• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

pantsbuild / pants / 20632486505

01 Jan 2026 04:21AM UTC coverage: 43.231% (-37.1%) from 80.281%
20632486505

Pull #22962

github

web-flow
Merge 08d5c63b0 into f52ab6675
Pull Request #22962: Bump the gha-deps group across 1 directory with 6 updates

26122 of 60424 relevant lines covered (43.23%)

0.86 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/src/python/pants/backend/java/dependency_inference/rules.py
1
# Copyright 2021 Pants project contributors (see CONTRIBUTORS.md).
2
# Licensed under the Apache License, Version 2.0 (see LICENSE).
3
from __future__ import annotations
×
4

5
from collections import defaultdict
×
6
from dataclasses import dataclass
×
7

8
from pants.backend.java.dependency_inference import symbol_mapper
×
9
from pants.backend.java.dependency_inference.java_parser import (
×
10
    JavaSourceDependencyAnalysisRequest,
11
    resolve_fallible_result_to_analysis,
12
)
13
from pants.backend.java.dependency_inference.java_parser import rules as java_parser_rules
×
14
from pants.backend.java.dependency_inference.types import JavaImport
×
15
from pants.backend.java.subsystems.java_infer import JavaInferSubsystem
×
16
from pants.backend.java.target_types import JavaSourceField
×
17
from pants.core.util_rules.source_files import SourceFilesRequest, determine_source_files
×
18
from pants.core.util_rules.source_files import rules as source_files_rules
×
19
from pants.engine.addresses import Address
×
20
from pants.engine.internals.graph import determine_explicitly_provided_dependencies, resolve_target
×
21
from pants.engine.rules import collect_rules, concurrently, implicitly, rule
×
22
from pants.engine.target import (
×
23
    Dependencies,
24
    DependenciesRequest,
25
    FieldSet,
26
    InferDependenciesRequest,
27
    InferredDependencies,
28
    SourcesField,
29
    WrappedTargetRequest,
30
)
31
from pants.engine.unions import UnionRule
×
32
from pants.jvm.dependency_inference import artifact_mapper
×
33
from pants.jvm.dependency_inference.symbol_mapper import SymbolMapping
×
34
from pants.jvm.subsystems import JvmSubsystem
×
35
from pants.jvm.target_types import JvmResolveField
×
36
from pants.util.ordered_set import FrozenOrderedSet, OrderedSet
×
37

38

39
@dataclass(frozen=True)
×
40
class JavaSourceDependenciesInferenceFieldSet(FieldSet):
×
41
    required_fields = (JavaSourceField,)
×
42

43
    source: JavaSourceField
×
44

45

46
class InferJavaSourceDependencies(InferDependenciesRequest):
×
47
    infer_from = JavaSourceDependenciesInferenceFieldSet
×
48

49

50
@dataclass(frozen=True)
×
51
class JavaInferredDependencies:
×
52
    dependencies: FrozenOrderedSet[Address]
×
53
    exports: FrozenOrderedSet[Address]
×
54

55

56
@dataclass(frozen=True)
×
57
class JavaInferredDependenciesAndExportsRequest:
×
58
    source: SourcesField
×
59

60

61
@rule(desc="Inferring Java dependencies and exports by source analysis")
×
62
async def infer_java_dependencies_and_exports_via_source_analysis(
×
63
    request: JavaInferredDependenciesAndExportsRequest,
64
    java_infer_subsystem: JavaInferSubsystem,
65
    jvm: JvmSubsystem,
66
    symbol_mapping: SymbolMapping,
67
) -> JavaInferredDependencies:
68
    if not java_infer_subsystem.imports and not java_infer_subsystem.consumed_types:
×
69
        return JavaInferredDependencies(FrozenOrderedSet([]), FrozenOrderedSet([]))
×
70

71
    address = request.source.address
×
72

73
    wrapped_tgt = await resolve_target(
×
74
        WrappedTargetRequest(address, description_of_origin="<infallible>"), **implicitly()
75
    )
76
    tgt = wrapped_tgt.target
×
77
    source_files = await determine_source_files(SourceFilesRequest([tgt[JavaSourceField]]))
×
78

79
    explicitly_provided_deps, analysis = await concurrently(
×
80
        determine_explicitly_provided_dependencies(
81
            **implicitly(DependenciesRequest(tgt[Dependencies]))
82
        ),
83
        resolve_fallible_result_to_analysis(
84
            **implicitly(JavaSourceDependencyAnalysisRequest(source_files=source_files))
85
        ),
86
    )
87

88
    types: OrderedSet[str] = OrderedSet()
×
89
    if java_infer_subsystem.imports:
×
90
        types.update(dependency_name(imp) for imp in analysis.imports)
×
91
    if java_infer_subsystem.consumed_types:
×
92
        package = analysis.declared_package
×
93

94
        for consumed_type in analysis.consumed_types:
×
95
            if "." not in consumed_type:
×
96
                # Simple unqualified type - add package prefix
97
                types.add(f"{package}.{consumed_type}" if package else consumed_type)
×
98
            else:
99
                # Has dots and might already be fully qualified
100
                types.add(consumed_type)
×
101

102
                # Might be an inner class in the same package as the current class
103
                first_part = consumed_type.split(".")[0]
×
104
                types.add(f"{package}.{first_part}" if package else first_part)
×
105

106
    # Resolve the export types into (probable) types:
107
    # First produce a map of known consumed unqualified types to possible qualified names
108
    consumed_type_mapping: dict[str, set[str]] = defaultdict(set)
×
109
    for typ in types:
×
110
        unqualified = typ.rpartition(".")[2]  # `"org.foo.Java"` -> `("org.foo", ".", "Java")`
×
111
        consumed_type_mapping[unqualified].add(typ)
×
112

113
    # Now take the list of unqualified export types and convert them to possible
114
    # qualified names based on the guesses we made for consumed types
115
    export_types = {
×
116
        i for typ in analysis.export_types for i in consumed_type_mapping.get(typ, set())
117
    }
118
    # Finally, if there's a `.` in the name, it's probably fully qualified,
119
    # so just add it unaltered
120
    export_types.update(typ for typ in analysis.export_types if "." in typ)
×
121

122
    resolve = tgt[JvmResolveField].normalized_value(jvm)
×
123

124
    dependencies: OrderedSet[Address] = OrderedSet()
×
125
    exports: OrderedSet[Address] = OrderedSet()
×
126
    for typ in types:
×
127
        for matches in symbol_mapping.addresses_for_symbol(typ, resolve).values():
×
128
            explicitly_provided_deps.maybe_warn_of_ambiguous_dependency_inference(
×
129
                matches,
130
                address,
131
                import_reference="type",
132
                context=f"The target {address} imports `{typ}`",
133
            )
134
            maybe_disambiguated = explicitly_provided_deps.disambiguated(matches)
×
135

136
            if maybe_disambiguated:
×
137
                dependencies.add(maybe_disambiguated)
×
138
                if typ in export_types:
×
139
                    exports.add(maybe_disambiguated)
×
140
            else:
141
                # Exports from explicitly provided dependencies:
142
                explicitly_provided_exports = set(matches) & set(explicitly_provided_deps.includes)
×
143
                exports.update(explicitly_provided_exports)
×
144

145
    # Files do not export themselves. Don't be silly.
146
    if address in exports:
×
147
        exports.remove(address)
×
148

149
    return JavaInferredDependencies(FrozenOrderedSet(dependencies), FrozenOrderedSet(exports))
×
150

151

152
@rule(desc="Inferring Java dependencies by source analysis")
×
153
async def infer_java_dependencies_via_source_analysis(
×
154
    request: InferJavaSourceDependencies,
155
) -> InferredDependencies:
156
    jids = await infer_java_dependencies_and_exports_via_source_analysis(
×
157
        JavaInferredDependenciesAndExportsRequest(request.field_set.source), **implicitly()
158
    )
159
    return InferredDependencies(jids.dependencies)
×
160

161

162
def dependency_name(imp: JavaImport):
×
163
    if imp.is_static and not imp.is_asterisk:
×
164
        return imp.name.rsplit(".", maxsplit=1)[0]
×
165
    else:
166
        return imp.name
×
167

168

169
def rules():
×
170
    return [
×
171
        *collect_rules(),
172
        *artifact_mapper.rules(),
173
        *java_parser_rules(),
174
        *symbol_mapper.rules(),
175
        *source_files_rules(),
176
        UnionRule(InferDependenciesRequest, InferJavaSourceDependencies),
177
    ]
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc