def test_configuration() -> None: class UnrelatedField(StringField): alias = "unrelated_field" default = "default" value: str class UnrelatedTarget(Target): alias = "unrelated_target" core_fields = (UnrelatedField, ) class NoFieldsTarget(Target): alias = "no_fields_target" core_fields = () @dataclass(frozen=True) class FortranConfiguration(Configuration): required_fields = (FortranSources, ) sources: FortranSources unrelated_field: UnrelatedField @dataclass(frozen=True) class UnrelatedFieldConfiguration(ConfigurationWithOrigin): required_fields = () unrelated_field: UnrelatedField fortran_addr = Address.parse(":fortran") fortran_tgt = FortranTarget({}, address=fortran_addr) unrelated_addr = Address.parse(":unrelated") unrelated_tgt = UnrelatedTarget({UnrelatedField.alias: "configured"}, address=unrelated_addr) no_fields_addr = Address.parse(":no_fields") no_fields_tgt = NoFieldsTarget({}, address=no_fields_addr) assert FortranConfiguration.is_valid(fortran_tgt) is True assert FortranConfiguration.is_valid(unrelated_tgt) is False assert FortranConfiguration.is_valid(no_fields_tgt) is False # When no fields are required, every target is valid. for tgt in [fortran_tgt, unrelated_tgt, no_fields_tgt]: assert UnrelatedFieldConfiguration.is_valid(tgt) is True valid_fortran_config = FortranConfiguration.create(fortran_tgt) assert valid_fortran_config.address == fortran_addr assert valid_fortran_config.unrelated_field.value == UnrelatedField.default with pytest.raises(KeyError): FortranConfiguration.create(unrelated_tgt) origin = FilesystemLiteralSpec("f.txt") assert (UnrelatedFieldConfiguration.create( TargetWithOrigin(fortran_tgt, origin)).origin == origin) assert (UnrelatedFieldConfiguration.create( TargetWithOrigin(unrelated_tgt, origin)).unrelated_field.value == "configured") assert (UnrelatedFieldConfiguration.create( TargetWithOrigin( no_fields_tgt, origin)).unrelated_field.value == UnrelatedField.default)
def make_target_with_origin( self, source_files: List[FileContent], *, name: str = "target", interpreter_constraints: Optional[str] = None, origin: Optional[OriginSpec] = None, dependencies: Optional[List[Address]] = None, ) -> TargetWithOrigin: for source_file in source_files: self.create_file(source_file.path, source_file.content.decode()) source_globs = [ PurePath(source_file.path).name for source_file in source_files ] self.create_library(path=self.source_root, target_type=PythonLibrary.alias, name=name, sources=source_globs) # We must re-write the files because `create_library` will have over-written the content. for source_file in source_files: self.create_file(source_file.path, source_file.content.decode()) target = PythonLibrary( { Sources.alias: source_globs, Dependencies.alias: dependencies, PythonInterpreterCompatibility.alias: interpreter_constraints, }, address=Address(self.source_root, name), ) if origin is None: origin = SingleAddress(directory=self.source_root, name=name) return TargetWithOrigin(target, origin)
def make_target_with_origin(address: Optional[Address] = None) -> TargetWithOrigin: if address is None: address = Address.parse(":tests") return TargetWithOrigin( MockTarget({}, address=address), origin=SingleAddress(directory=address.spec_path, name=address.target_name), )
def run_pytest( self, *, passthrough_args: Optional[str] = None, origin: Optional[OriginSpec] = None, ) -> TestResult: args = [ "--backend-packages2=pants.backend.python", # pin to lower versions so that we can run Python 2 tests "--pytest-version=pytest>=4.6.6,<4.7", "--pytest-pytest-plugins=['zipp==1.0.0']", ] if passthrough_args: args.append(f"--pytest-args='{passthrough_args}'") options_bootstrapper = create_options_bootstrapper(args=args) address = Address(self.source_root, "target") if origin is None: origin = SingleAddress(directory=address.spec_path, name=address.target_name) tgt = PythonTests({}, address=address) params = Params( PythonTestConfiguration.create(TargetWithOrigin(tgt, origin)), options_bootstrapper) test_result = self.request_single_product(TestResult, params) debug_request = self.request_single_product(TestDebugRequest, params) debug_result = InteractiveRunner( self.scheduler).run_local_interactive_process(debug_request.ipr) if test_result.status == Status.SUCCESS: assert debug_result.process_exit_code == 0 else: assert debug_result.process_exit_code != 0 return test_result
def make_target_with_origin( self, source_files: List[FileContent], *, package: Optional[str] = None, name: str = "target", ) -> TargetWithOrigin: if not package: package = self.package for source_file in source_files: self.create_file(source_file.path, source_file.content.decode()) source_globs = [ PurePath(source_file.path).name for source_file in source_files ] self.add_to_build_file( f"{package}", dedent(f"""\ python_library( name={repr(name)}, sources={source_globs}, ) """), ) target = self.request_single_product( WrappedTarget, Address(package, target_name=name)).target origin = SingleAddress(directory=package, name=name) return TargetWithOrigin(target, origin)
def make_target_with_origin( self, source_files: List[FileContent], *, name: str = "target", interpreter_constraints: Optional[str] = None, origin: Optional[OriginSpec] = None, dependencies: Optional[List[Address]] = None, ) -> TargetWithOrigin: for source_file in source_files: self.create_file(source_file.path, source_file.content.decode()) source_globs = [ PurePath(source_file.path).name for source_file in source_files ] self.add_to_build_file( self.source_root, f"python_library(name='{name}', sources={source_globs})\n") target = PythonLibrary( { Sources.alias: source_globs, Dependencies.alias: dependencies, PythonInterpreterCompatibility.alias: interpreter_constraints, }, address=Address(self.source_root, name), ) if origin is None: origin = SingleAddress(directory=self.source_root, name=name) return TargetWithOrigin(target, origin)
def make_target_with_origin( self, source_files: List[FileContent], *, name: str = "target", interpreter_constraints: Optional[str] = None, origin: Optional[OriginSpec] = None, dependencies: Optional[List[Address]] = None, ) -> TargetWithOrigin: for source_file in source_files: self.create_file(source_file.path, source_file.content.decode()) source_globs = [PurePath(source_file.path).name for source_file in source_files] self.add_to_build_file( self.source_root, dedent( f"""\ python_library( name={repr(name)}, sources={source_globs}, dependencies={[str(dep) for dep in dependencies or ()]}, compatibility={repr(interpreter_constraints)}, ) """ ), ) target = self.request_single_product(WrappedTarget, Address(self.source_root, name)).target if origin is None: origin = SingleAddress(directory=self.source_root, name=name) return TargetWithOrigin(target, origin)
def make_target_with_origin(address: Optional[Address] = None) -> TargetWithOrigin: if address is None: address = Address("", target_name="tests") return TargetWithOrigin( MockTarget({}, address=address), origin=AddressLiteralSpec(address.spec_path, address.target_name), )
async def resolve_targets_with_origins( addresses_with_origins: AddressesWithOrigins, ) -> TargetsWithOrigins: # TODO: See `resolve_targets`. targets_with_origins = await MultiGet( Get(TargetWithOrigin, AddressWithOrigin, address_with_origin) for address_with_origin in addresses_with_origins) # Split out and expand any base targets. # TODO: Should recursively expand alias targets here as well. other_targets_with_origins = [] base_targets_with_origins = [] for to in targets_with_origins: if to.target.address.is_base_target: base_targets_with_origins.append(to) else: other_targets_with_origins.append(to) base_targets_subtargets = await MultiGet( Get(Subtargets, Address, to.target.address) for to in base_targets_with_origins) # Zip the subtargets back to the base targets and replace them while maintaining origins. # NB: If a target had no subtargets, we use the base. expanded_targets_with_origins = set(other_targets_with_origins) expanded_targets_with_origins.update( TargetWithOrigin(target, bto.origin) for bto, subtargets in zip( base_targets_with_origins, base_targets_subtargets) for target in ( subtargets.subtargets if subtargets.subtargets else [bto.target])) return TargetsWithOrigins(expanded_targets_with_origins)
def make_target_with_origin( self, source_files: List[FileContent], *, origin: Optional[OriginSpec] = None, ) -> TargetWithOrigin: for source_file in source_files: self.create_file(f"{source_file.path}", source_file.content.decode()) target = PythonLibrary({}, address=Address.parse(":target")) if origin is None: origin = SingleAddress(directory="", name="target") return TargetWithOrigin(target, origin)
def make_target_with_origin( address: Optional[Address] = None, *, target_cls: Type[Target] = FortranTarget) -> TargetWithOrigin: if address is None: address = Address.parse(":tests") return TargetWithOrigin( target_cls({}, address=address), origin=SingleAddress(directory=address.spec_path, name=address.target_name), )
def single_target_run( self, *, console: MockConsole, program_text: bytes, address_spec: str, ) -> Run: workspace = Workspace(self.scheduler) interactive_runner = InteractiveRunner(self.scheduler) class TestBinaryConfiguration(BinaryConfiguration): required_fields = () class TestBinaryTarget(Target): alias = "binary" core_fields = () address = Address.parse(address_spec) origin = SingleAddress(address.spec_path, address.target_name) res = run_rule( run, rule_args=[ console, workspace, interactive_runner, BuildRoot(), TargetsWithOrigins([ TargetWithOrigin( target=TestBinaryTarget(unhydrated_values={}, address=address), origin=origin, ) ]), create_goal_subsystem(RunOptions, args=[]), create_subsystem(GlobalOptions, pants_workdir=self.pants_workdir), UnionMembership(union_rules={ BinaryConfiguration: OrderedSet([TestBinaryConfiguration]) }), RegisteredTargetTypes.create([TestBinaryTarget]), ], mock_gets=[ MockGet( product_type=CreatedBinary, subject_type=TestBinaryConfiguration, mock=lambda _: self.create_mock_binary(program_text), ), ], ) return cast(Run, res)
def single_target_run( self, *, console: MockConsole, program_text: bytes, address_spec: str, ) -> Run: workspace = Workspace(self.scheduler) interactive_runner = InteractiveRunner(self.scheduler) class TestRunFieldSet(RunFieldSet): required_fields = () class TestBinaryTarget(Target): alias = "binary" core_fields = () address = Address.parse(address_spec) target = TestBinaryTarget({}, address=address) target_with_origin = TargetWithOrigin( target, AddressLiteralSpec(address.spec_path, address.target_name)) field_set = TestRunFieldSet.create(target) res = run_rule_with_mocks( run, rule_args=[ create_goal_subsystem(RunSubsystem, args=[]), create_subsystem(GlobalOptions, pants_workdir=self.pants_workdir), console, interactive_runner, workspace, BuildRoot(), ], mock_gets=[ MockGet( product_type=TargetsToValidFieldSets, subject_type=TargetsToValidFieldSetsRequest, mock=lambda _: TargetsToValidFieldSets( {target_with_origin: [field_set]}), ), MockGet( product_type=RunRequest, subject_type=TestRunFieldSet, mock=lambda _: self.create_mock_run_request(program_text), ), ], ) return cast(Run, res)
def make_target_with_origin( self, source_files: List[FileContent], *, interpreter_constraints: Optional[str] = None, origin: Optional[OriginSpec] = None, ) -> TargetWithOrigin: for source_file in source_files: self.create_file(source_file.path, source_file.content.decode()) target = PythonLibrary( {PythonInterpreterCompatibility.alias: interpreter_constraints}, address=Address.parse(":target"), ) if origin is None: origin = SingleAddress(directory="", name="target") return TargetWithOrigin(target, origin)
def run_black_and_isort( self, source_files: List[FileContent], *, name: str, extra_args: Optional[List[str]] = None ) -> LanguageFmtResults: for source_file in source_files: self.create_file(source_file.path, source_file.content.decode()) target = PythonLibrary({}, address=Address.parse(f"test:{name}")) origin = SingleAddress(directory="test", name=name) targets = PythonFmtTargets(TargetsWithOrigins([TargetWithOrigin(target, origin)])) args = [ "--backend-packages2=['pants.backend.python.lint.black', 'pants.backend.python.lint.isort']", *(extra_args or []), ] results = self.request_single_product( LanguageFmtResults, Params(targets, create_options_bootstrapper(args=args)), ) return results
def single_target_run( self, *, console: MockConsole, program_text: bytes, address_spec: str, ) -> Run: workspace = Workspace(self.scheduler) interactive_runner = InteractiveRunner(self.scheduler) class TestBinaryConfiguration(BinaryConfiguration): required_fields = () class TestBinaryTarget(Target): alias = "binary" core_fields = () address = Address.parse(address_spec) target = TestBinaryTarget({}, address=address) target_with_origin = TargetWithOrigin( target, SingleAddress(address.spec_path, address.target_name) ) config = TestBinaryConfiguration.create(target) res = run_rule( run, rule_args=[ console, workspace, interactive_runner, BuildRoot(), create_goal_subsystem(RunOptions, args=[]), create_subsystem(GlobalOptions, pants_workdir=self.pants_workdir), ], mock_gets=[ MockGet( product_type=TargetsToValidConfigurations, subject_type=TargetsToValidConfigurationsRequest, mock=lambda _: TargetsToValidConfigurations({target_with_origin: [config]}), ), MockGet( product_type=CreatedBinary, subject_type=TestBinaryConfiguration, mock=lambda _: self.create_mock_binary(program_text), ), ], ) return cast(Run, res)
async def resolve_target_with_origin( address_with_origin: AddressWithOrigin) -> TargetWithOrigin: wrapped_target = await Get[WrappedTarget](Address, address_with_origin.address) return TargetWithOrigin(wrapped_target.target, address_with_origin.origin)
def test_find_valid_field_sets(self) -> None: origin = FilesystemLiteralSpec("f.txt") valid_tgt = FortranTarget({}, address=Address.parse(":valid")) valid_tgt_with_origin = TargetWithOrigin(valid_tgt, origin) invalid_tgt = self.InvalidTarget({}, address=Address.parse(":invalid")) invalid_tgt_with_origin = TargetWithOrigin(invalid_tgt, origin) def find_valid_field_sets( superclass: Type, targets_with_origins: Iterable[TargetWithOrigin], *, error_if_no_valid_targets: bool = False, expect_single_config: bool = False, ) -> TargetsToValidFieldSets: request = TargetsToValidFieldSetsRequest( superclass, goal_description="fake", error_if_no_valid_targets=error_if_no_valid_targets, expect_single_field_set=expect_single_config, ) return self.request_single_product( TargetsToValidFieldSets, Params(request, TargetsWithOrigins(targets_with_origins),), ) valid = find_valid_field_sets( self.FieldSetSuperclass, [valid_tgt_with_origin, invalid_tgt_with_origin] ) assert valid.targets == (valid_tgt,) assert valid.targets_with_origins == (valid_tgt_with_origin,) assert valid.field_sets == ( self.FieldSetSubclass1.create(valid_tgt), self.FieldSetSubclass2.create(valid_tgt), ) with pytest.raises(ExecutionError) as exc: find_valid_field_sets( self.FieldSetSuperclass, [valid_tgt_with_origin], expect_single_config=True ) assert AmbiguousImplementationsException.__name__ in str(exc.value) with pytest.raises(ExecutionError) as exc: find_valid_field_sets( self.FieldSetSuperclass, [ valid_tgt_with_origin, TargetWithOrigin(FortranTarget({}, address=Address.parse(":valid2")), origin), ], expect_single_config=True, ) assert TooManyTargetsException.__name__ in str(exc.value) no_valid_targets = find_valid_field_sets(self.FieldSetSuperclass, [invalid_tgt_with_origin]) assert no_valid_targets.targets == () assert no_valid_targets.targets_with_origins == () assert no_valid_targets.field_sets == () with pytest.raises(ExecutionError) as exc: find_valid_field_sets( self.FieldSetSuperclass, [invalid_tgt_with_origin], error_if_no_valid_targets=True ) assert NoValidTargetsException.__name__ in str(exc.value) valid_with_origin = find_valid_field_sets( self.FieldSetSuperclassWithOrigin, [valid_tgt_with_origin, invalid_tgt_with_origin] ) assert valid_with_origin.targets == (valid_tgt,) assert valid_with_origin.targets_with_origins == (valid_tgt_with_origin,) assert valid_with_origin.field_sets == ( self.FieldSetSubclassWithOrigin.create(valid_tgt_with_origin), )