Example #1
0
def assert_injected(
    rule_runner: RuleRunner,
    *,
    source_roots: List[str],
    original_declared_files: List[str],
    original_undeclared_files: List[str],
    expected_discovered: List[str],
) -> None:
    rule_runner.set_options([f"--source-root-patterns={source_roots}"])
    for f in original_undeclared_files:
        rule_runner.create_file(f, "# undeclared")
    request = AncestorFilesRequest(
        "__init__.py",
        rule_runner.make_snapshot({fp: "# declared" for fp in original_declared_files}),
    )
    result = rule_runner.request(AncestorFiles, [request]).snapshot
    assert list(result.files) == sorted(expected_discovered)

    materialized_result = rule_runner.request(DigestContents, [result.digest])
    for file_content in materialized_result:
        path = file_content.path
        if not path.endswith("__init__.py"):
            continue
        assert path in original_declared_files or path in expected_discovered
        expected = b"# declared" if path in original_declared_files else b"# undeclared"
        assert file_content.content == expected
Example #2
0
async def infer_python_init_dependencies(
        request: InferInitDependencies,
        python_infer_subsystem: PythonInferSubsystem) -> InferredDependencies:
    if not python_infer_subsystem.inits:
        return InferredDependencies([])

    fp = request.sources_field.file_path
    assert fp is not None
    init_files = await Get(
        AncestorFiles,
        AncestorFilesRequest(input_files=(fp, ),
                             requested=("__init__.py", "__init__.pyi")),
    )
    owners = await MultiGet(
        Get(Owners, OwnersRequest((f, ))) for f in init_files.snapshot.files)
    return InferredDependencies(itertools.chain.from_iterable(owners))
Example #3
0
async def infer_python_init_dependencies(
    request: InferInitDependencies,
    python_infer_subsystem: PythonInferSubsystem,
    python_setup: PythonSetup,
) -> InferredDependencies:
    if (
        not python_infer_subsystem.options.is_default("inits") and not python_infer_subsystem.inits
    ) or python_infer_subsystem.init_files is InitFilesInference.never:
        return InferredDependencies([])

    ignore_empty_files = (
        python_infer_subsystem.options.is_default("inits")
        and python_infer_subsystem.init_files is InitFilesInference.content_only
    )
    fp = request.sources_field.file_path
    assert fp is not None
    init_files = await Get(
        AncestorFiles,
        AncestorFilesRequest(
            input_files=(fp,),
            requested=("__init__.py", "__init__.pyi"),
            ignore_empty_files=ignore_empty_files,
        ),
    )
    owners = await MultiGet(Get(Owners, OwnersRequest((f,))) for f in init_files.snapshot.files)

    original_tgt, owner_tgts = await MultiGet(
        Get(
            WrappedTarget,
            WrappedTargetRequest(
                request.sources_field.address, description_of_origin="<infallible>"
            ),
        ),
        Get(Targets, Addresses(itertools.chain.from_iterable(owners))),
    )
    resolve = original_tgt.target[PythonResolveField].normalized_value(python_setup)
    python_owners = [
        tgt.address
        for tgt in owner_tgts
        if (
            tgt.has_field(PythonSourceField)
            and tgt[PythonResolveField].normalized_value(python_setup) == resolve
        )
    ]
    return InferredDependencies(python_owners)
Example #4
0
async def infer_python_conftest_dependencies(
    request: InferConftestDependencies,
    python_infer_subsystem: PythonInferSubsystem,
) -> InferredDependencies:
    if not python_infer_subsystem.conftests:
        return InferredDependencies([])

    fp = request.sources_field.file_path
    assert fp is not None
    conftest_files = await Get(
        AncestorFiles,
        AncestorFilesRequest(input_files=(fp, ), requested=("conftest.py", )),
    )
    owners = await MultiGet(
        # NB: Because conftest.py files effectively always have content, we require an
        # owning target.
        Get(Owners, OwnersRequest((f, ), OwnersNotFoundBehavior.error))
        for f in conftest_files.snapshot.files)
    return InferredDependencies(itertools.chain.from_iterable(owners))
Example #5
0
async def infer_python_conftest_dependencies(
    request: InferConftestDependencies,
    python_infer_subsystem: PythonInferSubsystem,
) -> InferredDependencies:
    if not python_infer_subsystem.conftests:
        return InferredDependencies([])

    # Locate conftest.py files not already in the Snapshot.
    hydrated_sources = await Get(HydratedSources,
                                 HydrateSourcesRequest(request.sources_field))
    extra_conftest_files = await Get(
        AncestorFiles,
        AncestorFilesRequest("conftest.py", hydrated_sources.snapshot),
    )

    # And add dependencies on their owners.
    # NB: Because conftest.py files effectively always have content, we require an owning target.
    owners = await MultiGet(
        Get(Owners, OwnersRequest((f, ), OwnersNotFoundBehavior.error))
        for f in extra_conftest_files.snapshot.files)
    return InferredDependencies(itertools.chain.from_iterable(owners))
Example #6
0
async def infer_python_conftest_dependencies(
    request: InferConftestDependencies,
    python_infer_subsystem: PythonInferSubsystem,
    python_setup: PythonSetup,
) -> InferredDependencies:
    if not python_infer_subsystem.conftests:
        return InferredDependencies([])

    fp = request.sources_field.file_path
    assert fp is not None
    conftest_files = await Get(
        AncestorFiles,
        AncestorFilesRequest(input_files=(fp,), requested=("conftest.py",)),
    )
    owners = await MultiGet(
        # NB: Because conftest.py files effectively always have content, we require an
        # owning target.
        Get(Owners, OwnersRequest((f,), OwnersNotFoundBehavior.error))
        for f in conftest_files.snapshot.files
    )

    original_tgt, owner_tgts = await MultiGet(
        Get(
            WrappedTarget,
            WrappedTargetRequest(
                request.sources_field.address, description_of_origin="<infallible>"
            ),
        ),
        Get(Targets, Addresses(itertools.chain.from_iterable(owners))),
    )
    resolve = original_tgt.target[PythonResolveField].normalized_value(python_setup)
    python_owners = [
        tgt.address
        for tgt in owner_tgts
        if (
            tgt.has_field(PythonSourceField)
            and tgt[PythonResolveField].normalized_value(python_setup) == resolve
        )
    ]
    return InferredDependencies(python_owners)
Example #7
0
async def infer_python_init_dependencies(
        request: InferInitDependencies,
        python_infer_subsystem: PythonInferSubsystem) -> InferredDependencies:
    if not python_infer_subsystem.inits:
        return InferredDependencies([])

    # Locate __init__.py files not already in the Snapshot.
    hydrated_sources = await Get(HydratedSources,
                                 HydrateSourcesRequest(request.sources_field))
    extra_init_files = await Get(
        AncestorFiles,
        AncestorFilesRequest("__init__.py", hydrated_sources.snapshot),
    )

    # And add dependencies on their owners.
    # NB: Because the python_sources rules always locate __init__.py files, and will trigger an
    # error for files that have content but have not already been included via a dependency, we
    # don't need to error for unowned files here.
    owners = await MultiGet(
        Get(Owners, OwnersRequest((f, )))
        for f in extra_init_files.snapshot.files)
    return InferredDependencies(itertools.chain.from_iterable(owners))
Example #8
0
def assert_injected(
    rule_runner: RuleRunner,
    *,
    input_files: list[str],
    empty_files: list[str],
    nonempty_files: list[str],
    expected_discovered: list[str],
    ignore_empty_files: bool,
) -> None:
    rule_runner.write_files({
        **{f: ""
           for f in empty_files},
        **{f: "foo"
           for f in nonempty_files}
    })
    request = AncestorFilesRequest(
        requested=("__init__.py", ),
        input_files=tuple(input_files),
        ignore_empty_files=ignore_empty_files,
    )
    result = rule_runner.request(AncestorFiles, [request]).snapshot
    assert list(result.files) == sorted(expected_discovered)
Example #9
0
async def prepare_python_sources(
        request: PythonSourceFilesRequest,
        union_membership: UnionMembership) -> PythonSourceFiles:
    sources = await Get(
        SourceFiles,
        SourceFilesRequest(
            (tgt.get(Sources) for tgt in request.targets),
            for_sources_types=request.valid_sources_types,
            enable_codegen=True,
        ),
    )

    missing_init_files = await Get(
        AncestorFiles,
        AncestorFilesRequest("__init__.py", sources.snapshot),
    )

    init_injected = await Get(
        Snapshot,
        MergeDigests(
            (sources.snapshot.digest, missing_init_files.snapshot.digest)),
    )

    source_root_objs = await MultiGet(
        Get(SourceRoot, SourceRootRequest, SourceRootRequest.for_target(tgt))
        for tgt in request.targets
        if (tgt.has_field(PythonSources) or tgt.has_field(ResourcesSources) or
            tgt.get(Sources).can_generate(PythonSources, union_membership) or
            tgt.get(Sources).can_generate(ResourcesSources, union_membership)))
    source_root_paths = {
        source_root_obj.path
        for source_root_obj in source_root_objs
    }
    return PythonSourceFiles(
        SourceFiles(init_injected, sources.unrooted_files),
        tuple(sorted(source_root_paths)))
Example #10
0
async def prepare_python_sources(
        request: PythonSourceFilesRequest,
        union_membership: UnionMembership) -> PythonSourceFiles:
    sources = await Get(
        SourceFiles,
        SourceFilesRequest(
            (tgt.get(SourcesField) for tgt in request.targets),
            for_sources_types=request.valid_sources_types,
            enable_codegen=True,
        ),
    )

    missing_init_files = await Get(
        AncestorFiles,
        AncestorFilesRequest(input_files=sources.snapshot.files,
                             requested=("__init__.py", "__init__.pyi")),
    )
    init_injected = await Get(
        Snapshot,
        MergeDigests(
            (sources.snapshot.digest, missing_init_files.snapshot.digest)))

    # Codegen is able to generate code in any arbitrary location, unlike sources normally being
    # rooted under the target definition. To determine source roots for these generated files, we
    # cannot use the normal `SourceRootRequest.for_target()` and we instead must determine
    # a source root for every individual generated file. So, we re-resolve the codegen sources here.
    python_and_resources_targets = []
    codegen_targets = []
    for tgt in request.targets:
        if tgt.has_field(PythonSourceField) or tgt.has_field(
                ResourceSourceField):
            python_and_resources_targets.append(tgt)
        elif tgt.get(SourcesField).can_generate(
                PythonSourceField,
                union_membership) or tgt.get(SourcesField).can_generate(
                    ResourceSourceField, union_membership):
            codegen_targets.append(tgt)
    codegen_sources = await MultiGet(
        Get(
            HydratedSources,
            HydrateSourcesRequest(
                tgt.get(SourcesField),
                for_sources_types=request.valid_sources_types,
                enable_codegen=True,
            ),
        ) for tgt in codegen_targets)
    source_root_requests = [
        *(SourceRootRequest.for_target(tgt)
          for tgt in python_and_resources_targets),
        *(SourceRootRequest.for_file(f) for sources in codegen_sources
          for f in sources.snapshot.files),
    ]

    source_root_objs = await MultiGet(
        Get(SourceRoot, SourceRootRequest, req)
        for req in source_root_requests)
    source_root_paths = {
        source_root_obj.path
        for source_root_obj in source_root_objs
    }
    return PythonSourceFiles(
        SourceFiles(init_injected, sources.unrooted_files),
        tuple(sorted(source_root_paths)))