def test_collection_single(self): collection_constraint = TypedCollection(Exactly(self.A)) self.assertTrue(collection_constraint.satisfied_by([self.A()])) self.assertFalse( collection_constraint.satisfied_by([self.A(), self.B()])) self.assertTrue( collection_constraint.satisfied_by([self.A(), self.A()]))
def test_no_complex_sub_constraint(self): sub_collection = TypedCollection(Exactly(self.A)) with self.assertRaisesWithMessage( TypeError, "constraint for collection must be a TypeOnlyConstraint! was: {}" .format(sub_collection)): TypedCollection(sub_collection)
class TaskInvocationResult(datatype([ 'context', ('before_tasks', TypedCollection(SubclassesOf(Task))), ('this_task', SubclassesOf(Task)), ('after_tasks', TypedCollection(SubclassesOf(Task))), ])): pass def invoke_tasks(self, target_closure=None, **context_kwargs):
def test_collection_multiple(self): collection_constraint = TypedCollection( SubclassesOf(self.B, self.BPrime)) self.assertTrue( collection_constraint.satisfied_by( [self.B(), self.C(), self.BPrime()])) self.assertFalse( collection_constraint.satisfied_by([self.B(), self.A()]))
class TaskInvocationResult( datatype([ 'context', ('before_tasks', TypedCollection(SubclassesOf(Task))), ('this_task', SubclassesOf(Task)), ('after_tasks', TypedCollection(SubclassesOf(Task))), ])): pass
def test_str_and_repr(self): collection_of_exactly_b = TypedCollection(Exactly(self.B)) self.assertEqual("TypedCollection(Exactly(B))", str(collection_of_exactly_b)) self.assertEqual("TypedCollection(Exactly(B))", repr(collection_of_exactly_b)) collection_of_multiple_subclasses = TypedCollection( SubclassesOf(self.A, self.B)) self.assertEqual("TypedCollection(SubclassesOf(A or B))", str(collection_of_multiple_subclasses)) self.assertEqual("TypedCollection(SubclassesOf(A, B))", repr(collection_of_multiple_subclasses))
class PexBuildEnvironment(datatype([ ('cpp_flags', TypedCollection(string_type)), ('ld_flags', TypedCollection(string_type)), ])): @property def invocation_environment_dict(self): return { 'CPPFLAGS': safe_shlex_join(self.cpp_flags), 'LDFLAGS': safe_shlex_join(self.ld_flags), }
class MultiPlatformExecuteProcessRequest(datatype([ ('platform_constraints', hashable_string_list), ('execute_process_requests', TypedCollection(Exactly(ExecuteProcessRequest))), ])): # args collects a set of tuples representing platform constraints mapped to a req, just like a dict constructor can. def __new__(cls, request_dict): if len(request_dict) == 0: raise cls.make_type_error("At least one platform constrained ExecuteProcessRequest must be passed.") # validate the platform constraints using the platforms enum an flatten the keys. validated_constraints = tuple( constraint.value for pair in request_dict.keys() for constraint in pair if PlatformConstraint(constraint.value) ) if len({req.description for req in request_dict.values()}) != 1: raise ValueError(f"The `description` of all execute_process_requests in a {cls.__name__} must be identical.") return super().__new__( cls, validated_constraints, tuple(request_dict.values()) ) @property def product_description(self): # we can safely extract the first description because we guarantee that at # least one request exists and that all of their descriptions are the same # in __new__ return ProductDescription(self.execute_process_requests[0].description)
def test_complex_sub_constraint(self): sub_collection = TypedCollection(Exactly(self.A)) nested_collection = TypedCollection(sub_collection) self.assertTrue(nested_collection.satisfied_by(())) self.assertTrue(nested_collection.satisfied_by([])) self.assertTrue(nested_collection.satisfied_by([[]])) self.assertTrue(nested_collection.satisfied_by([[self.A()]])) self.assertFalse(nested_collection.satisfied_by([[self.B()]]))
def test_validate(self): collection_exactly_a_or_b = TypedCollection(Exactly(self.A, self.B)) self.assertEqual([self.A()], collection_exactly_a_or_b.validate_satisfied_by([self.A()])) self.assertEqual([self.B()], collection_exactly_a_or_b.validate_satisfied_by([self.B()])) with self.assertRaisesWithMessage(TypeConstraintError, dedent("""\ in wrapped constraint TypedCollection(Exactly(A or B)): value A() (with type 'A') must satisfy this type constraint: SubclassesOf(Iterable). Note that objects matching {} are not considered iterable.""") .format(TypedCollection.exclude_iterable_constraint)): collection_exactly_a_or_b.validate_satisfied_by(self.A()) with self.assertRaisesWithMessage(TypeConstraintError, dedent("""\ in wrapped constraint TypedCollection(Exactly(A or B)) matching iterable object [C()]: value C() (with type 'C') must satisfy this type constraint: Exactly(A or B).""")): collection_exactly_a_or_b.validate_satisfied_by([self.C()])
def of(cls, *element_types): union = '|'.join(element_type.__name__ for element_type in element_types) type_name = '{}.of({})'.format(cls.__name__, union) 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. ('dependencies', TypedCollection(Exactly(*element_types))) ], superclass_name=cls.__name__) supertypes = (cls, type_checked_collection_class) properties = {'element_types': element_types} collection_of_type = type(type_name, supertypes, properties) # Expose the custom class type at the module level to be pickle compatible. setattr(sys.modules[cls.__module__], type_name, collection_of_type) return collection_of_type
def test_validate(self): collection_exactly_a_or_b = TypedCollection(Exactly(self.A, self.B)) self.assertEqual([self.A()], collection_exactly_a_or_b.validate_satisfied_by( [self.A()])) self.assertEqual([self.B()], collection_exactly_a_or_b.validate_satisfied_by( [self.B()])) with self.assertRaisesWithMessage( TypeConstraintError, "in wrapped constraint TypedCollection(Exactly(A or B)): value A() (with type 'A') must satisfy this type constraint: SubclassesOf(Iterable)." ): collection_exactly_a_or_b.validate_satisfied_by(self.A()) with self.assertRaisesWithMessage( TypeConstraintError, "in wrapped constraint TypedCollection(Exactly(A or B)) matching iterable object [C()]: value C() (with type 'C') must satisfy this type constraint: Exactly(A or B)." ): collection_exactly_a_or_b.validate_satisfied_by([self.C()])
def test_validate(self): collection_exactly_a_or_b = TypedCollection(Exactly(self.A, self.B)) self.assertEqual([self.A()], collection_exactly_a_or_b.validate_satisfied_by([self.A()])) self.assertEqual([self.B()], collection_exactly_a_or_b.validate_satisfied_by([self.B()])) with self.assertRaisesWithMessage(TypeConstraintError, dedent("""\ in wrapped constraint TypedCollection(Exactly(A or B)): value A() (with type 'A') must satisfy this type constraint: SubclassesOf(Iterable). Note that objects matching {} are not considered iterable.""") .format(_string_type_constraint)): collection_exactly_a_or_b.validate_satisfied_by(self.A()) with self.assertRaisesWithMessage(TypeConstraintError, dedent("""\ in wrapped constraint TypedCollection(Exactly(A or B)) matching iterable object [C()]: value C() (with type 'C') must satisfy this type constraint: Exactly(A or B).""")): collection_exactly_a_or_b.validate_satisfied_by([self.C()])
class TaskRule(datatype([ ('output_type', _type_field), ('input_selectors', TypedCollection(SubclassesOf(type))), ('input_gets', tuple), 'func', ('dependency_rules', tuple), ('dependency_optionables', tuple), ('cacheable', bool), ]), Rule): """A Rule that runs a task function when all of its input selectors are satisfied. NB: This API is experimental, and not meant for direct consumption. To create a `TaskRule` you should always prefer the `@rule` constructor, and in cases where that is too constraining (likely due to #4535) please bump or open a ticket to explain the usecase. """ def __new__(cls, output_type, input_selectors, func, input_gets, dependency_optionables=None, dependency_rules=None, cacheable=True): # Create. return super().__new__( cls, output_type, input_selectors, input_gets, func, dependency_rules or tuple(), dependency_optionables or tuple(), cacheable, ) def __str__(self): return ('({}, {!r}, {}, gets={}, opts={})' .format(self.output_type.__name__, self.input_selectors, self.func.__name__, self.input_gets, self.dependency_optionables))
class WithCollectionTypeConstraint( datatype([ ('dependencies', TypedCollection(Exactly(int))), ])): pass
class StringCollectionField( datatype([('hello_strings', TypedCollection(Exactly(str)))])): pass
def test_collection_single(self): collection_constraint = TypedCollection(Exactly(self.A)) self.assertTrue(collection_constraint.satisfied_by([self.A()])) self.assertFalse(collection_constraint.satisfied_by([self.A(), self.B()])) self.assertTrue(collection_constraint.satisfied_by([self.A(), self.A()]))
def test_collection_multiple(self): collection_constraint = TypedCollection(SubclassesOf(self.B, self.BPrime)) self.assertTrue(collection_constraint.satisfied_by([self.B(), self.C(), self.BPrime()])) self.assertFalse(collection_constraint.satisfied_by([self.B(), self.A()]))