• 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

37.04
/src/python/pants/engine/internals/defaults.py
1
# Copyright 2022 Pants project contributors (see CONTRIBUTORS.md).
2
# Licensed under the Apache License, Version 2.0 (see LICENSE).
3
"""The `BuildFileDefaultsParserState.set_defaults` is used by the pants.engine.internals.Parser,
4
exposed as the `__defaults__` BUILD file symbol.
5

6
When parsing a BUILD (from the rule `pants.engine.internals.build_files.parse_address_family`) the
7
defaults from the closest parent BUILD file is passed as input to the parser, and the new defaults
8
resulting after the BUILD file have been parsed is returned in the `AddressFamily`.
9

10
These defaults are then applied when creating the `TargetAdaptor` targets by the `Registrar` in the
11
parser.
12
"""
13

14
from __future__ import annotations
1✔
15

16
from collections.abc import Callable, Iterable, Mapping
1✔
17
from dataclasses import dataclass
1✔
18
from typing import Any, Union
1✔
19

20
from pants.engine.addresses import Address
1✔
21
from pants.engine.internals.parametrize import Parametrize
1✔
22
from pants.engine.target import (
1✔
23
    Field,
24
    ImmutableValue,
25
    InvalidFieldException,
26
    RegisteredTargetTypes,
27
    Target,
28
    TargetGenerator,
29
)
30
from pants.engine.unions import UnionMembership
1✔
31
from pants.util.frozendict import FrozenDict
1✔
32

33
SetDefaultsValueT = Mapping[str, Any]
1✔
34
SetDefaultsKeyT = Union[str, tuple[str, ...]]
1✔
35
SetDefaultsT = Mapping[SetDefaultsKeyT, SetDefaultsValueT]
1✔
36

37

38
class BuildFileDefaults(FrozenDict[str, FrozenDict[str, ImmutableValue]]):
1✔
39
    """Map target types to default field values."""
40

41

42
class ParametrizeDefault(Parametrize):
1✔
43
    """Parametrize for default field values.
44

45
    This is to have eager validation on the field values rather than erroring first when applied on
46
    an actual target.
47
    """
48

49
    @classmethod
1✔
50
    def create(
1✔
51
        cls, freeze: Callable[[Any], ImmutableValue], parametrize: Parametrize
52
    ) -> ParametrizeDefault:
UNCOV
53
        return cls(
×
54
            *map(freeze, parametrize.args),
55
            **{kw: freeze(arg) for kw, arg in parametrize.kwargs.items()},
56
        ).to_weak()
57

58

59
@dataclass
1✔
60
class BuildFileDefaultsParserState:
1✔
61
    address: Address
1✔
62
    defaults: dict[str, Mapping[str, Any]]
1✔
63
    registered_target_types: RegisteredTargetTypes
1✔
64
    union_membership: UnionMembership
1✔
65

66
    @classmethod
1✔
67
    def create(
1✔
68
        cls,
69
        path: str,
70
        defaults: BuildFileDefaults,
71
        registered_target_types: RegisteredTargetTypes,
72
        union_membership: UnionMembership,
73
    ) -> BuildFileDefaultsParserState:
UNCOV
74
        return cls(
×
75
            address=Address(path, generated_name="__defaults__"),
76
            defaults=dict(defaults),
77
            registered_target_types=registered_target_types,
78
            union_membership=union_membership,
79
        )
80

81
    def _freeze_field_value(self, field_type: type[Field], value: Any) -> ImmutableValue:
1✔
UNCOV
82
        if isinstance(value, ParametrizeDefault):
×
83
            return value
×
UNCOV
84
        elif isinstance(value, Parametrize):
×
85

UNCOV
86
            def freeze(v: Any) -> ImmutableValue:
×
UNCOV
87
                return self._freeze_field_value(field_type, v)
×
88

UNCOV
89
            return ParametrizeDefault.create(freeze, value)
×
90
        else:
UNCOV
91
            return field_type.compute_value(raw_value=value, address=self.address)
×
92

93
    def get_frozen_defaults(self) -> BuildFileDefaults:
1✔
UNCOV
94
        types = self.registered_target_types.aliases_to_types
×
UNCOV
95
        return BuildFileDefaults(
×
96
            {
97
                target_alias: FrozenDict(
98
                    {
99
                        **{
100
                            field_type.alias: self._freeze_field_value(field_type, default)
101
                            for field_alias, default in fields.items()
102
                            for field_type in self._target_type_field_types(types[target_alias])
103
                            if field_alias in (field_type.alias, field_type.deprecated_alias)
104
                        },
105
                        **{
106
                            key: ParametrizeDefault(
107
                                parametrize.group_name,
108
                                **{
109
                                    field_type.alias: self._freeze_field_value(field_type, default)
110
                                    for field_alias, default in parametrize.kwargs.items()
111
                                    for field_type in self._target_type_field_types(
112
                                        types[target_alias]
113
                                    )
114
                                    if field_alias
115
                                    in (field_type.alias, field_type.deprecated_alias)
116
                                },
117
                            )
118
                            .to_weak()
119
                            .to_group()
120
                            for key, parametrize in fields.items()
121
                            if isinstance(parametrize, Parametrize) and parametrize.is_group
122
                        },
123
                    }
124
                )
125
                for target_alias, fields in self.defaults.items()
126
            }
127
        )
128

129
    def get(self, target_alias: str) -> Mapping[str, Any]:
1✔
130
        # Used by `pants.engine.internals.parser.Parser._generate_symbols.Registrar.__call__`
UNCOV
131
        return self.defaults.get(target_alias, {})
×
132

133
    def set_defaults(
1✔
134
        self,
135
        *args: SetDefaultsT,
136
        all: SetDefaultsValueT | None = None,
137
        extend: bool = False,
138
        ignore_unknown_fields: bool = False,
139
        ignore_unknown_targets: bool = False,
140
    ) -> None:
UNCOV
141
        defaults: dict[str, dict[str, Any]] = (
×
142
            {} if not extend else {k: dict(v) for k, v in self.defaults.items()}
143
        )
144

UNCOV
145
        if all is not None:
×
UNCOV
146
            self._process_defaults(
×
147
                defaults,
148
                {tuple(self.registered_target_types.aliases): all},
149
                ignore_unknown_fields=True,
150
                ignore_unknown_targets=ignore_unknown_targets,
151
            )
152

UNCOV
153
        for arg in args:
×
UNCOV
154
            self._process_defaults(
×
155
                defaults,
156
                arg,
157
                ignore_unknown_fields=ignore_unknown_fields,
158
                ignore_unknown_targets=ignore_unknown_targets,
159
            )
160

161
        # Update with new defaults, dropping targets without any default values.
UNCOV
162
        for tgt, default in defaults.items():
×
UNCOV
163
            if not default:
×
UNCOV
164
                self.defaults.pop(tgt, None)
×
165
            else:
UNCOV
166
                self.defaults[tgt] = default
×
167

168
    def _target_type_field_types(self, target_type: type[Target]) -> tuple[type[Field], ...]:
1✔
UNCOV
169
        return (
×
170
            *target_type.class_field_types(self.union_membership),
171
            *(target_type.moved_fields if issubclass(target_type, TargetGenerator) else ()),
172
        )
173

174
    def _process_defaults(
1✔
175
        self,
176
        defaults: dict[str, dict[str, Any]],
177
        targets_defaults: SetDefaultsT,
178
        ignore_unknown_fields: bool = False,
179
        ignore_unknown_targets: bool = False,
180
    ):
UNCOV
181
        if not isinstance(targets_defaults, dict):
×
UNCOV
182
            raise ValueError(
×
183
                f"Expected dictionary mapping targets to default field values for {self.address} "
184
                f"but got: {type(targets_defaults).__name__}."
185
            )
186

UNCOV
187
        types = self.registered_target_types.aliases_to_types
×
UNCOV
188
        for target, default in targets_defaults.items():
×
UNCOV
189
            if not isinstance(default, dict):
×
UNCOV
190
                raise ValueError(
×
191
                    f"Invalid default field values in {self.address} for target type {target}, "
192
                    f"must be an `dict` but was {default!r} with type `{type(default).__name__}`."
193
                )
194

195
            targets: Iterable[str]
UNCOV
196
            targets = target if isinstance(target, tuple) else (target,)
×
UNCOV
197
            for target_alias in map(str, targets):
×
UNCOV
198
                if target_alias in types:
×
UNCOV
199
                    target_type = types[target_alias]
×
UNCOV
200
                elif ignore_unknown_targets:
×
UNCOV
201
                    continue
×
202
                else:
UNCOV
203
                    raise ValueError(f"Unrecognized target type {target_alias} in {self.address}.")
×
204

205
                # Copy default dict if we may mutate it.
UNCOV
206
                raw_values = dict(default) if ignore_unknown_fields else default
×
207

208
                # Validate that field exists on target
UNCOV
209
                valid_field_aliases = set(
×
210
                    target_type._get_field_aliases_to_field_types(
211
                        self._target_type_field_types(target_type)
212
                    ).keys()
213
                )
214

UNCOV
215
                def _check_field_alias(field_alias: str) -> None:
×
UNCOV
216
                    if field_alias in valid_field_aliases:
×
UNCOV
217
                        return
×
UNCOV
218
                    if not ignore_unknown_fields:
×
UNCOV
219
                        raise InvalidFieldException(
×
220
                            f"Unrecognized field `{field_alias}` for target {target_type.alias}. "
221
                            f"Valid fields are: {', '.join(sorted(valid_field_aliases))}.",
222
                        )
UNCOV
223
                    elif field_alias in raw_values:
×
UNCOV
224
                        del raw_values[field_alias]
×
225

UNCOV
226
                for field_alias, field_value in default.items():
×
UNCOV
227
                    if isinstance(field_value, Parametrize) and field_value.is_group:
×
UNCOV
228
                        field_value.to_weak()
×
UNCOV
229
                        for parametrize_field_alias in field_value.kwargs.keys():
×
UNCOV
230
                            _check_field_alias(parametrize_field_alias)
×
231
                    else:
UNCOV
232
                        _check_field_alias(field_alias)
×
233

234
                # Merge all provided defaults for this call.
UNCOV
235
                defaults.setdefault(target_type.alias, {}).update(raw_values)
×
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