Skip to content

Commit

Permalink
break my own heart and remove wrapper_type
Browse files Browse the repository at this point in the history
  • Loading branch information
cosmicexplorer committed Jan 28, 2019
1 parent 320de41 commit 25824f6
Show file tree
Hide file tree
Showing 3 changed files with 17 additions and 49 deletions.
7 changes: 2 additions & 5 deletions src/python/pants/engine/objects.py
Original file line number Diff line number Diff line change
Expand Up @@ -171,11 +171,8 @@ def of(cls, *element_types):
type_name = type_name.encode('utf-8')
type_checked_collection_class = datatype([
# Create a datatype with a single field 'dependencies' which is type-checked on construction
# to be a collection containing elements of only the exact `element_types` specified, and
# which is converted into a tuple upon construction. A tuple `wrapper_type` is required for
# the resulting datatype to be hashable, so we set it explicitly here although it is the
# default.
('dependencies', TypedCollection(Exactly(*element_types), wrapper_type=tuple))
# to be a collection containing elements of only the exact `element_types` specified.
('dependencies', TypedCollection(Exactly(*element_types)))
], superclass_name=cls.__name__)
supertypes = (cls, type_checked_collection_class)
properties = {'element_types': element_types}
Expand Down
22 changes: 5 additions & 17 deletions src/python/pants/util/objects.py
Original file line number Diff line number Diff line change
Expand Up @@ -276,7 +276,7 @@ class TypeConstraint(AbstractClass):
:class:`SubclassesOf`.
"""

def __init__(self, variance_symbol, wrapper_type, description):
def __init__(self, variance_symbol, description):
"""Creates a type constraint centered around the given types.
The type constraint is satisfied as a whole if satisfied for at least one of the given types.
Expand All @@ -285,12 +285,7 @@ def __init__(self, variance_symbol, wrapper_type, description):
:param str description: A description for this constraint if the list of types is too long.
"""
assert(variance_symbol)
if wrapper_type is not None:
if not isinstance(wrapper_type, type):
raise TypeError("wrapper_type must be a type! was: {} (type '{}')"
.format(wrapper_type, type(wrapper_type).__name__))
self._variance_symbol = variance_symbol
self._wrapper_type = wrapper_type
self._description = description

@abstractmethod
Expand All @@ -309,8 +304,6 @@ def validate_satisfied_by(self, obj):
"""

if self.satisfied_by(obj):
if self._wrapper_type:
return self._wrapper_type(obj)
return obj

raise TypeConstraintError(
Expand Down Expand Up @@ -355,7 +348,6 @@ def __init__(self, *types):

super(BasicTypeConstraint, self).__init__(
variance_symbol=self._variance_symbol,
wrapper_type=None,
description=constrained_type)

# NB: This is made into a tuple so that we can use self._types in issubclass() and others!
Expand Down Expand Up @@ -430,14 +422,12 @@ class TypedCollection(TypeConstraint):
def _generate_variance_symbol(cls, constraint):
return '[{}]'.format(constraint._variance_symbol)

def __init__(self, constraint, wrapper_type=tuple):
def __init__(self, constraint):
"""Create a TypeConstraint which validates each member of a collection with `constraint`.
:param BasicTypeConstraint constraint: the TypeConstraint to apply to each element. This is
currently required to be a BasicTypeConstraint to avoid
complex prototypal type relationships.
:param type wrapper_type: the type of the returned collection when invoking
validate_satisfied_by().
"""

if not isinstance(constraint, BasicTypeConstraint):
Expand All @@ -447,7 +437,6 @@ def __init__(self, constraint, wrapper_type=tuple):

super(TypedCollection, self).__init__(
variance_symbol=self._generate_variance_symbol(constraint),
wrapper_type=wrapper_type,
description=constraint._description)

def satisfied_by(self, obj):
Expand All @@ -456,13 +445,12 @@ def satisfied_by(self, obj):
return False

def __hash__(self):
return hash((type(self), self._constraint, self._wrapper_type))
return hash((type(self), self._constraint))

def __eq__(self, other):
return type(self) == type(other) and self._constraint == other._constraint

def __repr__(self):
return ('{type_constraint_type}({constraint!r}, wrapper_type={wrapper_type})'
return ('{type_constraint_type}({constraint!r})'
.format(type_constraint_type=type(self).__name__,
constraint=self._constraint,
wrapper_type=self._wrapper_type.__name__))
constraint=self._constraint))
37 changes: 10 additions & 27 deletions tests/python/pants_test/util/test_objects.py
Original file line number Diff line number Diff line change
Expand Up @@ -130,21 +130,16 @@ def test_multiple(self):


class TypedCollectionTest(TypeConstraintTestBase):
def test_construction_errors(self):
with self.assertRaisesRegexp(TypeError, re.escape(
"wrapper_type must be a type! was: 3 (type 'int')")):
TypedCollection(Exactly(self.B), wrapper_type=3)

def test_str_and_repr(self):
collection_of_exactly_b = TypedCollection(Exactly(self.B))
self.assertEqual("[=]B", str(collection_of_exactly_b))
self.assertEqual("TypedCollection(Exactly(B), wrapper_type=tuple)",
self.assertEqual("TypedCollection(Exactly(B))",
repr(collection_of_exactly_b))

collection_of_multiple_subclasses = TypedCollection(
SubclassesOf(self.A, self.B), wrapper_type=list)
SubclassesOf(self.A, self.B))
self.assertEqual("[+](A, B)", str(collection_of_multiple_subclasses))
self.assertEqual("TypedCollection(SubclassesOf(A, B), wrapper_type=list)",
self.assertEqual("TypedCollection(SubclassesOf(A, B))",
repr(collection_of_multiple_subclasses))

def test_collection_single(self):
Expand All @@ -158,28 +153,15 @@ def test_collection_multiple(self):
self.assertTrue(collection_constraint.satisfied_by([self.B(), self.C(), self.BPrime()]))
self.assertFalse(collection_constraint.satisfied_by([self.B(), self.A()]))

def test_collection_converts_wrapper_type(self):
collection_constraint = TypedCollection(Exactly(self.A, self.C))
self.assertEquals(
# Defaults to converting to tuple.
(self.A(), self.C(), self.A()),
collection_constraint.validate_satisfied_by([self.A(), self.C(), self.A()]))

def collection_generator():
yield self.A()
yield self.C()
yield self.A()

# Test conversion to a different wrapper type.
collection_constraint = TypedCollection(Exactly(self.A, self.C), wrapper_type=list)
collection_constraint = TypedCollection(Exactly(self.A, self.C))
self.assertEquals(
[self.A(), self.C(), self.A()],
(self.A(), self.C(), self.A()),
collection_constraint.validate_satisfied_by(tuple(collection_generator())))
# NB: For now, passing a generator without wrapping it in a concrete collection means it gets
# consumed. This makes sense (how else would you type check all its elements?).
self.assertEquals(
[],
collection_constraint.validate_satisfied_by(collection_generator()))

def test_construction(self):
with self.assertRaisesRegexp(TypeError, re.escape(
Expand Down Expand Up @@ -539,10 +521,11 @@ def compare_str(unicode_type_name):
self.assertEqual(obj_with_mixin.stripped(), 'asdf')

def test_instance_with_collection_construction_str_repr(self):
# TODO: convert the type of the input collection using a `wrapper_type` argument!
obj_with_collection = WithCollectionTypeConstraint([3])
self.assertEqual("WithCollectionTypeConstraint(dependencies<[=]int>=(3,))",
self.assertEqual("WithCollectionTypeConstraint(dependencies<[=]int>=[3])",
str(obj_with_collection))
self.assertEqual("WithCollectionTypeConstraint(dependencies=(3,))",
self.assertEqual("WithCollectionTypeConstraint(dependencies=[3])",
repr(obj_with_collection))

def test_instance_construction_errors(self):
Expand Down Expand Up @@ -655,14 +638,14 @@ def compare_str(unicode_type_name, include_unicode=False):
WithCollectionTypeConstraint(3)
expected_msg = """\
error: in constructor of type WithCollectionTypeConstraint: type check error:
field 'dependencies' was invalid: value 3 (with type 'int') must satisfy this type constraint: TypedCollection(Exactly(int), wrapper_type=tuple)."""
field 'dependencies' was invalid: value 3 (with type 'int') must satisfy this type constraint: TypedCollection(Exactly(int))."""
self.assertEqual(str(cm.exception), expected_msg)

with self.assertRaises(TypeCheckError) as cm:
WithCollectionTypeConstraint([3, "asdf"])
expected_msg = """\
error: in constructor of type WithCollectionTypeConstraint: type check error:
field 'dependencies' was invalid: value [3, {}'asdf'] (with type 'list') must satisfy this type constraint: TypedCollection(Exactly(int), wrapper_type=tuple).""".format('u' if PY2 else '')
field 'dependencies' was invalid: value [3, {}'asdf'] (with type 'list') must satisfy this type constraint: TypedCollection(Exactly(int)).""".format('u' if PY2 else '')
self.assertEqual(str(cm.exception), expected_msg)

def test_copy(self):
Expand Down

0 comments on commit 25824f6

Please sign in to comment.