def test_filter_field_sets(rule_runner: RuleRunner) -> None: @dataclass(frozen=True) class MockFieldSet(FieldSet): sources: Sources # Another field to demo that we will preserve the whole FieldSet data structure. tags: Tags rule_runner.create_file("f1.txt") valid_addr = Address("", target_name="valid") valid_field_set = MockFieldSet(valid_addr, Sources(["f1.txt"], address=valid_addr), Tags(None, address=valid_addr)) empty_addr = Address("", target_name="empty") empty_field_set = MockFieldSet(empty_addr, Sources(None, address=empty_addr), Tags(None, address=empty_addr)) result = rule_runner.request_product( FieldSetsWithSources, [ FieldSetsWithSourcesRequest([valid_field_set, empty_field_set]), create_options_bootstrapper(), ], ) assert tuple(result) == (valid_field_set, )
async def restrict_conflicting_sources( ptgt: PutativeTarget) -> DisjointSourcePutativeTarget: source_paths = await Get( Paths, PathGlobs( Sources.prefix_glob_with_dirpath(ptgt.path, glob) for glob in ptgt.owned_sources), ) source_path_set = set(source_paths.files) source_dirs = {os.path.dirname(path) for path in source_path_set} possible_owners = await Get( UnexpandedTargets, AddressSpecs(AscendantAddresses(d) for d in source_dirs)) possible_owners_sources = await MultiGet( Get(SourcesPaths, SourcesPathsRequest(t.get(Sources))) for t in possible_owners) conflicting_targets = [] for tgt, sources in zip(possible_owners, possible_owners_sources): if source_path_set.intersection(sources.files): conflicting_targets.append(tgt) if conflicting_targets: conflicting_addrs = sorted(tgt.address.spec for tgt in conflicting_targets) explicit_srcs_str = ", ".join(ptgt.kwargs.get("sources") or []) # type: ignore[arg-type] orig_sources_str = (f"[{explicit_srcs_str}]" if explicit_srcs_str else f"the default for {ptgt.type_alias}") ptgt = ptgt.restrict_sources().add_comments([ f"# NOTE: Sources restricted from {orig_sources_str} due to conflict with" ] + [f"# - {caddr}" for caddr in conflicting_addrs]) return DisjointSourcePutativeTarget(ptgt)
def test_unmatched_globs(self) -> None: self.create_files("", files=["f1.f95"]) sources = Sources(["non_existent.f95"], address=Address.parse(":lib")) with pytest.raises(ExecutionError) as exc: self.request_single_product(HydratedSources, HydrateSourcesRequest(sources)) assert "Unmatched glob" in str(exc.value) assert "//:lib" in str(exc.value) assert "non_existent.f95" in str(exc.value)
def test_filter_field_sets(self) -> None: @dataclass(frozen=True) class MockFieldSet(FieldSet): sources: Sources # Another field to demo that we will preserve the whole FieldSet data structure. tags: Tags self.create_file("f1.txt") valid_addr = Address.parse(":valid") valid_field_set = MockFieldSet( valid_addr, Sources(["f1.txt"], address=valid_addr), Tags(None, address=valid_addr) ) empty_addr = Address.parse(":empty") empty_field_set = MockFieldSet( empty_addr, Sources(None, address=empty_addr), Tags(None, address=empty_addr) ) result = self.request_single_product( FieldSetsWithSources, FieldSetsWithSourcesRequest([valid_field_set, empty_field_set]), ) assert tuple(result) == (valid_field_set,)
def test_normal_hydration(self) -> None: addr = Address.parse("src/fortran:lib") self.create_files("src/fortran", files=["f1.f95", "f2.f95", "f1.f03", "ignored.f03"]) sources = Sources(["f1.f95", "*.f03", "!ignored.f03", "!**/ignore*"], address=addr) hydrated_sources = self.request_single_product( HydratedSources, HydrateSourcesRequest(sources) ) assert hydrated_sources.snapshot.files == ("src/fortran/f1.f03", "src/fortran/f1.f95") # Also test that the Filespec is correct. This does not need hydration to be calculated. assert sources.filespec == { "globs": ["src/fortran/*.f03", "src/fortran/f1.f95"], "exclude": [{"globs": ["src/fortran/**/ignore*", "src/fortran/ignored.f03"]}], }
def test_filter_configurations(self) -> None: @dataclass(frozen=True) class MockConfiguration(Configuration): sources: Sources # Another field to demo that we will preserve the whole Configuration data structure. tags: Tags self.create_file("f1.txt") valid_addr = Address.parse(":valid") valid_config = MockConfiguration( valid_addr, Sources(["f1.txt"], address=valid_addr), Tags(None, address=valid_addr) ) empty_addr = Address.parse(":empty") empty_config = MockConfiguration( empty_addr, Sources(None, address=empty_addr), Tags(None, address=empty_addr) ) result = self.request_single_product( ConfigurationsWithSources, ConfigurationsWithSourcesRequest([valid_config, empty_config]), ) assert tuple(result) == (valid_config,)
def test_output_type(self) -> None: class SourcesSubclass(Sources): pass addr = Address.parse(":lib") self.create_files("", files=["f1.f95"]) valid_sources = SourcesSubclass(["*"], address=addr) hydrated_valid_sources = self.request_single_product( HydratedSources, HydrateSourcesRequest(valid_sources, for_sources_types=[SourcesSubclass]), ) assert hydrated_valid_sources.snapshot.files == ("f1.f95",) assert hydrated_valid_sources.sources_type == SourcesSubclass invalid_sources = Sources(["*"], address=addr) hydrated_invalid_sources = self.request_single_product( HydratedSources, HydrateSourcesRequest(invalid_sources, for_sources_types=[SourcesSubclass]), ) assert hydrated_invalid_sources.snapshot.files == () assert hydrated_invalid_sources.sources_type is None
def assert_invalid_type(raw_value: Any) -> None: with pytest.raises(InvalidFieldTypeException): Sources(raw_value, address=addr) with pytest.raises(InvalidFieldTypeException): Dependencies(raw_value, address=addr)
def assert_flexible_constructor(raw_value: Iterable[str]) -> None: assert Sources(raw_value, address=addr).sanitized_raw_value == tuple(raw_value) assert Dependencies( raw_value, address=addr).sanitized_raw_value == tuple(raw_value)