Ejemplo n.º 1
0
def assert_imports_parsed(
    rule_runner: RuleRunner,
    content: str | None,
    *,
    expected: list[str],
    filename: str = "project/foo.py",
    constraints: str = ">=3.6",
    string_imports: bool = True,
) -> None:
    rule_runner.set_options([], env_inherit={"PATH", "PYENV_ROOT", "HOME"})
    files = {"project/BUILD": "python_library(sources=['**/*.py'])"}
    if content is not None:
        files[filename] = content
    rule_runner.write_files(files)  # type: ignore[arg-type]
    tgt = rule_runner.get_target(Address("project"))
    imports = rule_runner.request(
        ParsedPythonImports,
        [
            ParsePythonImportsRequest(
                tgt[PythonSources],
                InterpreterConstraints([constraints]),
                string_imports=string_imports,
            )
        ],
    )
    assert list(imports) == sorted(expected)
Ejemplo n.º 2
0
async def infer_python_dependencies_via_imports(
    request: InferPythonImportDependencies,
    python_infer_subsystem: PythonInferSubsystem,
    python_setup: PythonSetup,
) -> InferredDependencies:
    if not python_infer_subsystem.imports:
        return InferredDependencies([], sibling_dependencies_inferrable=False)

    wrapped_tgt = await Get(WrappedTarget, Address,
                            request.sources_field.address)
    detected_imports = await Get(
        ParsedPythonImports,
        ParsePythonImportsRequest(
            request.sources_field,
            PexInterpreterConstraints.create_from_targets([wrapped_tgt.target],
                                                          python_setup),
        ),
    )
    relevant_imports = (detected_imports.all_imports
                        if python_infer_subsystem.string_imports else
                        detected_imports.explicit_imports)

    owners_per_import = await MultiGet(
        Get(PythonModuleOwners, PythonModule(imported_module))
        for imported_module in relevant_imports
        if imported_module not in combined_stdlib)
    merged_result = sorted(
        set(itertools.chain.from_iterable(owners_per_import)))
    return InferredDependencies(merged_result,
                                sibling_dependencies_inferrable=True)
Ejemplo n.º 3
0
def assert_imports_parsed(
    rule_runner: RuleRunner,
    content: str,
    *,
    expected: list[str],
    filename: str = "project/foo.py",
    constraints: str = ">=3.6",
    string_imports: bool = True,
    string_imports_min_dots: int = 2,
) -> None:
    rule_runner.set_options([], env_inherit={"PATH", "PYENV_ROOT", "HOME"})
    rule_runner.write_files({
        "BUILD": f"python_source(name='t', source={repr(filename)})",
        filename: content,
    })
    tgt = rule_runner.get_target(Address("", target_name="t"))
    imports = rule_runner.request(
        ParsedPythonImports,
        [
            ParsePythonImportsRequest(
                tgt[PythonSourceField],
                InterpreterConstraints([constraints]),
                string_imports=string_imports,
                string_imports_min_dots=string_imports_min_dots,
            )
        ],
    )
    assert list(imports) == sorted(expected)
Ejemplo n.º 4
0
async def infer_python_dependencies_via_imports(
    request: InferPythonImportDependencies,
    python_infer_subsystem: PythonInferSubsystem,
    python_setup: PythonSetup,
) -> InferredDependencies:
    if not python_infer_subsystem.imports:
        return InferredDependencies([], sibling_dependencies_inferrable=False)

    wrapped_tgt = await Get(WrappedTarget, Address,
                            request.sources_field.address)
    explicitly_provided_deps, detected_imports = await MultiGet(
        Get(ExplicitlyProvidedDependencies,
            DependenciesRequest(wrapped_tgt.target[Dependencies])),
        Get(
            ParsedPythonImports,
            ParsePythonImportsRequest(
                request.sources_field,
                PexInterpreterConstraints.create_from_targets(
                    [wrapped_tgt.target], python_setup),
            ),
        ),
    )

    relevant_imports = tuple(
        imp for imp in (detected_imports.all_imports if python_infer_subsystem.
                        string_imports else detected_imports.explicit_imports)
        if imp not in combined_stdlib)

    owners_per_import = await MultiGet(
        Get(PythonModuleOwners, PythonModule(imported_module))
        for imported_module in relevant_imports)
    merged_result: set[Address] = set()
    for owners, imp in zip(owners_per_import, relevant_imports):
        merged_result.update(owners.unambiguous)
        address = wrapped_tgt.target.address
        explicitly_provided_deps.maybe_warn_of_ambiguous_dependency_inference(
            owners.ambiguous,
            address,
            import_reference="module",
            context=f"The target {address} imports `{imp}`",
        )
        maybe_disambiguated = explicitly_provided_deps.disambiguated_via_ignores(
            owners.ambiguous)
        if maybe_disambiguated:
            merged_result.add(maybe_disambiguated)

    return InferredDependencies(sorted(merged_result),
                                sibling_dependencies_inferrable=True)
Ejemplo n.º 5
0
def assert_imports_parsed(
    rule_runner: RuleRunner,
    content: Optional[str],
    *,
    expected_explicit: List[str],
    expected_string: List[str],
    filename: str = "project/foo.py",
    constraints: str = ">=3.6",
):
    if content:
        rule_runner.create_file(filename, content)
    rule_runner.set_options([], env_inherit={"PATH", "PYENV_ROOT", "HOME"})
    rule_runner.add_to_build_file("project",
                                  "python_library(sources=['**/*.py'])")
    tgt = rule_runner.get_target(Address("project"))
    imports = rule_runner.request(
        ParsedPythonImports,
        [
            ParsePythonImportsRequest(tgt[PythonSources],
                                      PexInterpreterConstraints([constraints]))
        ],
    )
    assert set(imports.explicit_imports) == set(expected_explicit)
    assert set(imports.string_imports) == set(expected_string)
Ejemplo n.º 6
0
async def infer_python_dependencies_via_imports(
    request: InferPythonImportDependencies,
    python_infer_subsystem: PythonInferSubsystem,
    python_setup: PythonSetup,
) -> InferredDependencies:
    if not python_infer_subsystem.imports:
        return InferredDependencies([])

    wrapped_tgt = await Get(WrappedTarget, Address,
                            request.sources_field.address)
    explicitly_provided_deps, detected_imports = await MultiGet(
        Get(ExplicitlyProvidedDependencies,
            DependenciesRequest(wrapped_tgt.target[Dependencies])),
        Get(
            ParsedPythonImports,
            ParsePythonImportsRequest(
                cast(PythonSourceField, request.sources_field),
                InterpreterConstraints.create_from_targets(
                    [wrapped_tgt.target], python_setup),
                string_imports=python_infer_subsystem.string_imports,
                string_imports_min_dots=python_infer_subsystem.
                string_imports_min_dots,
            ),
        ),
    )

    owners_per_import = await MultiGet(
        Get(PythonModuleOwners, PythonModule(imported_module))
        for imported_module in detected_imports)

    merged_result: set[Address] = set()
    unowned_imports: set[str] = set()
    address = wrapped_tgt.target.address
    for owners, imp in zip(owners_per_import, detected_imports):
        merged_result.update(owners.unambiguous)
        explicitly_provided_deps.maybe_warn_of_ambiguous_dependency_inference(
            owners.ambiguous,
            address,
            import_reference="module",
            context=f"The target {address} imports `{imp}`",
        )
        maybe_disambiguated = explicitly_provided_deps.disambiguated(
            owners.ambiguous)
        if maybe_disambiguated:
            merged_result.add(maybe_disambiguated)

        if not owners.unambiguous and imp.split(
                ".")[0] not in DEFAULT_UNOWNED_DEPENDENCIES:
            unowned_imports.add(imp)

    unowned_dependency_behavior = python_infer_subsystem.unowned_dependency_behavior
    if unowned_imports and unowned_dependency_behavior is not UnownedDependencyUsage.DoNothing:
        raise_error = unowned_dependency_behavior is UnownedDependencyUsage.RaiseError
        log = logger.error if raise_error else logger.warning
        log(f"The following imports in {address} have no owners:\n\n{bullet_list(unowned_imports)}\n\n"
            "If you are expecting this import to be provided by your own firstparty code, ensure that it is contained within a source root. "
            "Otherwise if you are using a requirements file, consider adding the relevant package.\n"
            "Otherwise consider declaring a `python_requirement_library` target, which can then be inferred.\n"
            f"See {doc_url('python-third-party-dependencies')}")

        if raise_error:
            raise UnownedDependencyError(
                "One or more unowned dependencies detected. Check logs for more details."
            )

    return InferredDependencies(sorted(merged_result))