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

pantsbuild / pants / 19015773527

02 Nov 2025 05:33PM UTC coverage: 17.872% (-62.4%) from 80.3%
19015773527

Pull #22816

github

web-flow
Merge a12d75757 into 6c024e162
Pull Request #22816: Update Pants internal Python to 3.14

4 of 5 new or added lines in 3 files covered. (80.0%)

28452 existing lines in 683 files now uncovered.

9831 of 55007 relevant lines covered (17.87%)

0.18 hits per line

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

0.0
/src/python/pants/backend/python/goals/debug_goals.py
1
# Copyright 2022 Pants project contributors (see CONTRIBUTORS.md).
2
# Licensed under the Apache License, Version 2.0 (see LICENSE).
3

UNCOV
4
from __future__ import annotations
×
5

UNCOV
6
import json
×
UNCOV
7
from dataclasses import dataclass
×
UNCOV
8
from enum import Enum
×
UNCOV
9
from typing import Any
×
10

UNCOV
11
from pants.backend.project_info.peek import _PeekJsonEncoder
×
UNCOV
12
from pants.backend.python.dependency_inference.module_mapper import ResolveName
×
UNCOV
13
from pants.backend.python.dependency_inference.parse_python_dependencies import (
×
14
    ParsedPythonDependencies,
15
    ParsedPythonImportInfo,
16
)
UNCOV
17
from pants.backend.python.dependency_inference.rules import (
×
18
    ImportResolveResult,
19
    PythonImportDependenciesInferenceFieldSet,
20
    ResolvedParsedPythonDependencies,
21
    ResolvedParsedPythonDependenciesRequest,
22
    UnownedImportsPossibleOwners,
23
    UnownedImportsPossibleOwnersRequest,
24
    _collect_imports_info,
25
    _exec_parse_deps,
26
    _find_other_owners_for_unowned_imports,
27
    import_rules,
28
    resolve_parsed_dependencies,
29
)
UNCOV
30
from pants.backend.python.goals.run_python_source import PythonSourceFieldSet
×
UNCOV
31
from pants.backend.python.subsystems.setup import PythonSetup
×
UNCOV
32
from pants.build_graph.address import Address
×
UNCOV
33
from pants.engine.console import Console
×
UNCOV
34
from pants.engine.goal import Goal, GoalSubsystem
×
UNCOV
35
from pants.engine.internals.selectors import concurrently
×
UNCOV
36
from pants.engine.rules import collect_rules, goal_rule, implicitly, rule
×
UNCOV
37
from pants.engine.target import Targets
×
UNCOV
38
from pants.option.option_types import EnumOption
×
UNCOV
39
from pants.util.strutil import softwrap
×
40

41

UNCOV
42
class AnalysisFlavor(Enum):
×
UNCOV
43
    raw_dependency_inference = "raw_dependency_inference"
×
UNCOV
44
    dependency_inference = "dependency_inference"
×
45

46

UNCOV
47
class DumpPythonSourceAnalysisSubsystem(GoalSubsystem):
×
UNCOV
48
    name = "python-dump-source-analysis"
×
UNCOV
49
    help = "Dump source analysis for python_source targets."
×
50

UNCOV
51
    flavor = EnumOption(
×
52
        "--analysis-flavor",
53
        default=AnalysisFlavor.dependency_inference,
54
        help=softwrap(
55
            f"""\
56
            The type of information that should be returned.\n
57
            * `{AnalysisFlavor.dependency_inference.value}`: The results of dependency inference, for every detected import in every file.\n
58
            * `{AnalysisFlavor.raw_dependency_inference.value}`: The raw intermediate results of the dependency inference process,
59
            at every stage they're available.
60
            Potentially useful for debugging the dependency inference process.\n
61
            """
62
        ),
63
    )
64

65

UNCOV
66
class DumpPythonSourceAnalysis(Goal):
×
UNCOV
67
    subsystem_cls = DumpPythonSourceAnalysisSubsystem
×
UNCOV
68
    environment_behavior = Goal.EnvironmentBehavior.LOCAL_ONLY  # TODO(#17129) — Migrate this.
×
69

70

UNCOV
71
@dataclass(frozen=True)
×
UNCOV
72
class PythonSourceAnalysis:
×
73
    """Information on the inferred imports for a Python file, including all raw intermediate
74
    results."""
75

UNCOV
76
    fs: PythonImportDependenciesInferenceFieldSet
×
UNCOV
77
    identified: ParsedPythonDependencies
×
UNCOV
78
    resolved: ResolvedParsedPythonDependencies
×
UNCOV
79
    possible_owners: UnownedImportsPossibleOwners
×
80

81

UNCOV
82
@rule
×
UNCOV
83
async def dump_python_source_analysis_single(
×
84
    fs: PythonImportDependenciesInferenceFieldSet,
85
    python_setup: PythonSetup,
86
) -> PythonSourceAnalysis:
87
    """Infer the dependencies for a single python fieldset, keeping all the intermediate results."""
88

89
    parsed_dependencies = await _exec_parse_deps(fs, python_setup)
×
90

91
    resolve = fs.resolve.normalized_value(python_setup)
×
92

93
    resolved_dependencies = await resolve_parsed_dependencies(
×
94
        ResolvedParsedPythonDependenciesRequest(fs, parsed_dependencies, resolve), **implicitly()
95
    )
96

97
    import_deps, unowned_imports = _collect_imports_info(resolved_dependencies.resolve_results)
×
98

99
    imports_to_other_owners = await _find_other_owners_for_unowned_imports(
×
100
        UnownedImportsPossibleOwnersRequest(unowned_imports, resolve),
101
    )
102

103
    return PythonSourceAnalysis(
×
104
        fs, parsed_dependencies, resolved_dependencies, imports_to_other_owners
105
    )
106

107

UNCOV
108
@dataclass(frozen=True)
×
UNCOV
109
class ImportAnalysis:
×
110
    """Information on the inferred imports for a Python file."""
111

UNCOV
112
    name: str
×
UNCOV
113
    reference: ParsedPythonImportInfo | str
×
UNCOV
114
    resolved: ImportResolveResult
×
UNCOV
115
    possible_resolve: list[tuple[Address, ResolveName]] | None
×
116

117

UNCOV
118
@dataclass(frozen=True)
×
UNCOV
119
class CollectedImportAnalysis:
×
120
    """Collected information on all Python files."""
121

UNCOV
122
    imports: list[ImportAnalysis]
×
UNCOV
123
    assets: list[ImportAnalysis]
×
124

125

UNCOV
126
def collect_analysis(raw: PythonSourceAnalysis) -> CollectedImportAnalysis:
×
127
    """Collect raw analysis and present it in a helpful per-import format."""
128
    imports = []
×
129

130
    resolved_results = raw.resolved.resolve_results
×
131

132
    for name, info in raw.identified.imports.items():
×
133
        possible_resolve = raw.possible_owners.value.get(name)
×
134

135
        imports.append(
×
136
            ImportAnalysis(
137
                name=name,
138
                reference=info,
139
                resolved=resolved_results[name],
140
                possible_resolve=possible_resolve,
141
            )
142
        )
143

144
    assets = []
×
145
    resolved_assets = raw.resolved.assets
×
146

147
    for name in raw.identified.assets:
×
148
        possible_resolve = raw.possible_owners.value.get(name)
×
149

150
        assets.append(
×
151
            ImportAnalysis(
152
                name=name,
153
                reference=name,  # currently assets don't keep track of their line numbers
154
                resolved=resolved_assets[name],
155
                possible_resolve=possible_resolve,
156
            )
157
        )
158

159
    return CollectedImportAnalysis(imports, assets)
×
160

161

UNCOV
162
@goal_rule
×
UNCOV
163
async def dump_python_source_analysis(
×
164
    request: DumpPythonSourceAnalysisSubsystem,
165
    targets: Targets,
166
    console: Console,
167
) -> DumpPythonSourceAnalysis:
168
    source_field_sets = [
×
169
        PythonImportDependenciesInferenceFieldSet.create(tgt)
170
        for tgt in targets
171
        if PythonSourceFieldSet.is_applicable(tgt)
172
    ]
173

174
    source_analysis = await concurrently(
×
175
        dump_python_source_analysis_single(fs, **implicitly()) for fs in source_field_sets
176
    )
177

178
    output: Any
179
    if request.flavor == AnalysisFlavor.raw_dependency_inference:
×
180
        output = source_analysis
×
181
    else:
182
        output = {str(a.fs.address): collect_analysis(a) for a in source_analysis}
×
183

184
    console.print_stdout(json.dumps(output, cls=_PeekJsonEncoder))
×
185
    return DumpPythonSourceAnalysis(exit_code=0)
×
186

187

UNCOV
188
def rules():
×
UNCOV
189
    return [
×
190
        *import_rules(),
191
        *collect_rules(),
192
    ]
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

© 2025 Coveralls, Inc