• 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/framework/stevedore/python_target_dependencies.py
1
# Copyright 2023 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
from collections import defaultdict
×
UNCOV
7
from collections.abc import Iterable, Mapping
×
UNCOV
8
from dataclasses import dataclass
×
9

UNCOV
10
from pants.backend.python.framework.stevedore.target_types import (
×
11
    AllStevedoreExtensionTargets,
12
    StevedoreExtensionTargets,
13
    StevedoreNamespace,
14
    StevedoreNamespacesField,
15
    StevedoreNamespacesProviderTargetsRequest,
16
)
UNCOV
17
from pants.backend.python.target_types import (
×
18
    PythonDistribution,
19
    PythonDistributionEntryPointsField,
20
    PythonTestsDependenciesField,
21
    PythonTestsGeneratorTarget,
22
    PythonTestTarget,
23
)
UNCOV
24
from pants.backend.python.util_rules.entry_points import (
×
25
    GetEntryPointDependenciesRequest,
26
    get_filtered_entry_point_dependencies,
27
)
UNCOV
28
from pants.engine.rules import Rule, collect_rules, implicitly, rule
×
UNCOV
29
from pants.engine.target import (
×
30
    AllTargets,
31
    FieldSet,
32
    InferDependenciesRequest,
33
    InferredDependencies,
34
    Target,
35
)
UNCOV
36
from pants.engine.unions import UnionRule
×
UNCOV
37
from pants.util.frozendict import FrozenDict
×
UNCOV
38
from pants.util.logging import LogLevel
×
39

40
# -----------------------------------------------------------------------------------------------
41
# Utility rules to analyze all StevedoreNamespace entry_points
42
# -----------------------------------------------------------------------------------------------
43

44

UNCOV
45
@rule(
×
46
    desc=f"Find all `{PythonDistribution.alias}` targets with `{StevedoreNamespace.alias}` entry_points",
47
    level=LogLevel.DEBUG,
48
)
UNCOV
49
async def find_all_python_distributions_with_any_stevedore_entry_points(
×
50
    targets: AllTargets,
51
) -> AllStevedoreExtensionTargets:
52
    # This only supports specifying stevedore_namespace entry points in the
53
    # `entry_points` field of a `python_distribution`, not the `provides` field.
54
    # Use this: `python_distribution(entry_points={...})`
55
    # NOT this: `python_distribution(provides=python_artifact(entry_points={...}))`
56
    return AllStevedoreExtensionTargets(
×
57
        tgt
58
        for tgt in targets
59
        if tgt.has_field(PythonDistributionEntryPointsField)
60
        and any(
61
            # namespace aka category aka group
62
            isinstance(namespace, StevedoreNamespace)
63
            for namespace in (tgt[PythonDistributionEntryPointsField].value or {}).keys()
64
        )
65
    )
66

67

UNCOV
68
@dataclass(frozen=True)
×
UNCOV
69
class StevedoreExtensions:
×
70
    """A mapping of stevedore namespaces to a list of targets that provide them.
71

72
    Effectively, the targets are StevedoreExtension targets.
73
    """
74

UNCOV
75
    mapping: FrozenDict[StevedoreNamespace, tuple[Target, ...]]
×
76

77

UNCOV
78
@rule(
×
79
    desc=f"Create map of `{StevedoreNamespace.alias}` to `{PythonDistribution.alias}` targets",
80
    level=LogLevel.DEBUG,
81
)
UNCOV
82
async def map_stevedore_extensions(
×
83
    stevedore_extensions: AllStevedoreExtensionTargets,
84
) -> StevedoreExtensions:
85
    mapping: Mapping[StevedoreNamespace, list[Target]] = defaultdict(list)
×
86
    for tgt in stevedore_extensions:
×
87
        # namespace aka category aka group
88
        for namespace in (tgt[PythonDistributionEntryPointsField].value or {}).keys():
×
89
            if isinstance(namespace, StevedoreNamespace):
×
90
                mapping[namespace].append(tgt)
×
91
    return StevedoreExtensions(
×
92
        FrozenDict((k, tuple(sorted(v))) for k, v in sorted(mapping.items()))
93
    )
94

95

UNCOV
96
@rule(
×
97
    desc=f"Find `{PythonDistribution.alias}` targets with entry_points in selected `{StevedoreNamespace.alias}`s",
98
    level=LogLevel.DEBUG,
99
)
UNCOV
100
async def find_python_distributions_with_entry_points_in_stevedore_namespaces(
×
101
    request: StevedoreNamespacesProviderTargetsRequest,
102
    stevedore_extensions: StevedoreExtensions,
103
) -> StevedoreExtensionTargets:
104
    namespaces: StevedoreNamespacesField = request.stevedore_namespaces
×
105
    if namespaces.value is None:
×
106
        return StevedoreExtensionTargets(())
×
107

108
    return StevedoreExtensionTargets(
×
109
        {
110
            tgt
111
            for namespace in namespaces.value
112
            for tgt in stevedore_extensions.mapping.get(StevedoreNamespace(namespace), ())
113
        }
114
    )
115

116

117
# -----------------------------------------------------------------------------------------------
118
# Dependencies for `python_test` and `python_tests` targets
119
# -----------------------------------------------------------------------------------------------
120

121

UNCOV
122
@dataclass(frozen=True)
×
UNCOV
123
class PythonTestsStevedoreNamespaceInferenceFieldSet(FieldSet):
×
UNCOV
124
    required_fields = (PythonTestsDependenciesField, StevedoreNamespacesField)
×
125

UNCOV
126
    stevedore_namespaces: StevedoreNamespacesField
×
127

128

UNCOV
129
class InferStevedoreNamespacesDependencies(InferDependenciesRequest):
×
UNCOV
130
    infer_from = PythonTestsStevedoreNamespaceInferenceFieldSet
×
131

132

UNCOV
133
@rule(
×
134
    desc=f"Infer dependencies based on `{StevedoreNamespacesField.alias}` field.",
135
    level=LogLevel.DEBUG,
136
)
UNCOV
137
async def infer_stevedore_namespaces_dependencies(
×
138
    request: InferStevedoreNamespacesDependencies,
139
) -> InferredDependencies:
140
    requested_namespaces: StevedoreNamespacesField = request.field_set.stevedore_namespaces
×
141
    if requested_namespaces.value is None:
×
142
        return InferredDependencies(())
×
143

144
    targets = await find_python_distributions_with_entry_points_in_stevedore_namespaces(
×
145
        StevedoreNamespacesProviderTargetsRequest(requested_namespaces), **implicitly()
146
    )
147

148
    requested_namespaces_value = requested_namespaces.value
×
149
    entry_point_dependencies = await get_filtered_entry_point_dependencies(
×
150
        GetEntryPointDependenciesRequest(
151
            targets,
152
            lambda tgt, ns: ns in requested_namespaces_value,
153
            lambda tgt, ns, ep_name: True,
154
        )
155
    )
156

157
    return InferredDependencies(entry_point_dependencies.addresses)
×
158

159

UNCOV
160
def rules() -> Iterable[Rule | UnionRule]:
×
UNCOV
161
    return (
×
162
        *collect_rules(),
163
        PythonTestsGeneratorTarget.register_plugin_field(StevedoreNamespacesField),
164
        PythonTestTarget.register_plugin_field(StevedoreNamespacesField),
165
        UnionRule(InferDependenciesRequest, InferStevedoreNamespacesDependencies),
166
    )
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