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

pantsbuild / pants / 18252174847

05 Oct 2025 01:36AM UTC coverage: 43.382% (-36.9%) from 80.261%
18252174847

push

github

web-flow
run tests on mac arm (#22717)

Just doing the minimal to pull forward the x86_64 pattern.

ref #20993

25776 of 59416 relevant lines covered (43.38%)

1.3 hits per line

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

63.24
/src/python/pants/option/option_value_container.py
1
# Copyright 2014 Pants project contributors (see CONTRIBUTORS.md).
2
# Licensed under the Apache License, Version 2.0 (see LICENSE).
3

4
from __future__ import annotations
3✔
5

6
import copy
3✔
7
from collections.abc import Iterator
3✔
8
from dataclasses import dataclass
3✔
9

10
from pants.option.ranked_value import Rank, RankedValue, Value
3✔
11

12
Key = str
3✔
13

14

15
class OptionValueContainerBuilder:
3✔
16
    def __init__(self, value_map: dict[Key, RankedValue] | None = None) -> None:
3✔
17
        self._value_map: dict[Key, RankedValue] = value_map if value_map else {}
3✔
18

19
    def update(self, other: OptionValueContainerBuilder) -> None:
3✔
20
        """Set other's values onto this object.
21

22
        For each key, highest ranked value wins. In a tie, other's value wins.
23
        """
24
        for k, v in other._value_map.items():
×
25
            self._set(k, v)
×
26

27
    def _set(self, key: Key, value: RankedValue) -> None:
3✔
28
        if not isinstance(value, RankedValue):
3✔
29
            raise AttributeError(f"Value must be of type RankedValue: {value}")
×
30

31
        existing_value = self._value_map.get(key)
3✔
32
        existing_rank = existing_value.rank if existing_value is not None else Rank.NONE
3✔
33
        if value.rank >= existing_rank:
3✔
34
            # We set values from outer scopes before values from inner scopes, so
35
            # in case of equal rank we overwrite. That way that the inner scope value wins.
36
            self._value_map[key] = value
3✔
37

38
    # Support attribute setting, e.g., opts.foo = RankedValue(Rank.HARDCODED, 42).
39
    def __setattr__(self, key: Key, value: RankedValue) -> None:
3✔
40
        if key == "_value_map":
3✔
41
            return super().__setattr__(key, value)
3✔
42
        self._set(key, value)
3✔
43

44
    def build(self) -> OptionValueContainer:
3✔
45
        return OptionValueContainer(copy.copy(self._value_map))
3✔
46

47

48
@dataclass(frozen=True)
3✔
49
class OptionValueContainer:
3✔
50
    """A container for option values.
51

52
    Implements "value ranking":
53

54
       Attribute values can be ranked, so that a given attribute's value can only be changed if
55
       the new value has at least as high a rank as the old value. This allows an option value in
56
       an outer scope to override that option's value in an inner scope, when the outer scope's
57
       value comes from a higher ranked source (e.g., the outer value comes from an env var and
58
       the inner one from config).
59

60
       See ranked_value.py for more details.
61
    """
62

63
    _value_map: dict[Key, RankedValue]
3✔
64

65
    def get_keys(self) -> set[Key]:
3✔
66
        return set(self._value_map.keys())
×
67

68
    def get_explicit_keys(self) -> list[Key]:
3✔
69
        """Returns the keys for any values that were set explicitly (via flag, config, or env
70
        var)."""
71
        ret = []
×
72
        for k, v in self._value_map.items():
×
73
            if v.rank > Rank.CONFIG_DEFAULT:
×
74
                ret.append(k)
×
75
        return ret
×
76

77
    def get_rank(self, key: Key) -> Rank:
3✔
78
        """Returns the rank of the value at the specified key.
79

80
        Returns one of the constants in Rank.
81
        """
82
        ranked_value = self._value_map.get(key)
×
83
        if ranked_value is None:
×
84
            raise AttributeError(key)
×
85
        return ranked_value.rank
×
86

87
    def is_flagged(self, key: Key) -> bool:
3✔
88
        """Returns `True` if the value for the specified key was supplied via a flag.
89

90
        A convenience equivalent to `get_rank(key) == Rank.FLAG`.
91

92
        This check can be useful to determine whether or not a user explicitly set an option for this
93
        run.  Although a user might also set an option explicitly via an environment variable, ie via:
94
        `ENV_VAR=value ./pants ...`, this is an ambiguous case since the environment variable could also
95
        be permanently set in the user's environment.
96

97
        :param string key: The name of the option to check.
98
        :returns: `True` if the option was explicitly flagged by the user from the command line.
99
        :rtype: bool
100
        """
101
        return self.get_rank(key) == Rank.FLAG
×
102

103
    def is_default(self, key: Key) -> bool:
3✔
104
        """Returns `True` if the value for the specified key was not supplied by the user.
105

106
        I.e. the option was NOT specified config files, on the cli, or in environment variables.
107

108
        :param string key: The name of the option to check.
109
        :returns: `True` if the user did not set the value for this option.
110
        :rtype: bool
111
        """
112
        return self.get_rank(key) in (Rank.NONE, Rank.HARDCODED)
×
113

114
    def get(self, key: Key, default: Value | None = None):
3✔
115
        # Support dict-like dynamic access.  See also __getitem__ below.
116
        if key not in self._value_map:
×
117
            return default
×
118
        return self._get_underlying_value(key)
×
119

120
    def as_dict(self) -> dict[Key, Value]:
3✔
121
        return {key: self.get(key) for key in self._value_map}
×
122

123
    def to_builder(self) -> OptionValueContainerBuilder:
3✔
124
        return OptionValueContainerBuilder(copy.copy(self._value_map))
×
125

126
    def _get_underlying_value(self, key: Key):
3✔
127
        # Note that the key may exist with a value of None, so we can't just
128
        # test self._value_map.get() for None.
129
        if key not in self._value_map:
3✔
130
            raise AttributeError(key)
×
131
        ranked_val = self._value_map[key]
3✔
132
        return ranked_val.value
3✔
133

134
    # Support natural dynamic access, e.g., opts[foo] is more idiomatic than getattr(opts, 'foo').
135
    def __getitem__(self, key: Key):
3✔
136
        return self.__getattr__(key)
×
137

138
    # Support attribute getting, e.g., foo = opts.foo.
139
    # Note: Called only if regular attribute lookup fails,
140
    # so method and member access will be handled the normal way.
141
    def __getattr__(self, key: Key):
3✔
142
        if key == "_value_map":
3✔
143
            # In case we get called in copy, which doesn't invoke the ctor.
144
            raise AttributeError(key)
×
145
        return self._get_underlying_value(key)
3✔
146

147
    def __contains__(self, key: Key):
3✔
148
        return key in self._value_map
×
149

150
    def __iter__(self) -> Iterator[Key]:
3✔
151
        """Returns an iterator over all option names, in lexicographical order."""
152
        yield from sorted(self._value_map.keys())
×
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