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

pantsbuild / pants / 19849046701

02 Dec 2025 06:08AM UTC coverage: 92.707% (+12.4%) from 80.291%
19849046701

Pull #22816

github

web-flow
Merge f39d8c531 into 565e13a24
Pull Request #22816: Update Pants internal Python to 3.14

45 of 45 new or added lines in 8 files covered. (100.0%)

4 existing lines in 3 files now uncovered.

90036 of 97119 relevant lines covered (92.71%)

4.06 hits per line

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

99.16
/src/python/pants/util/meta_test.py
1
# Copyright 2015 Pants project contributors (see CONTRIBUTORS.md).
2
# Licensed under the Apache License, Version 2.0 (see LICENSE).
3

4
from abc import ABC, abstractmethod
1✔
5

6
import pytest
1✔
7

8
from pants.util.meta import SingletonMetaclass, classproperty
1✔
9
from pants.util.strutil import softwrap
1✔
10

11

12
def test_singleton() -> None:
1✔
13
    class One(metaclass=SingletonMetaclass):
1✔
14
        pass
1✔
15

16
    assert One() is One()
1✔
17

18

19
class WithProp:
1✔
20
    _value = "val0"
1✔
21

22
    @classproperty
1✔
23
    def class_property(cls):
1✔
24
        """class_property docs."""
25
        return cls._value
1✔
26

27
    @classmethod
1✔
28
    def class_method(cls):
1✔
29
        return cls._value
1✔
30

31
    @staticmethod
1✔
32
    def static_method():
1✔
33
        return "static_method"
1✔
34

35

36
class OverridingValueField(WithProp):
1✔
37
    _value = "val1"
1✔
38

39

40
class OverridingValueInit(WithProp):
1✔
41
    """Override the class-level `_value` with an instance-level `_value` from a constructor.
42

43
    The class-level methods should still return the class-level `_value`, but the new instance
44
    methods should return the value from the constructor.
45
    """
46

47
    def __init__(self, v):
1✔
48
        # This will be ignored when accessed as a class method.
49
        self._value = v
1✔
50

51
    @property
1✔
52
    def instance_property(self):
1✔
53
        return self._value
1✔
54

55
    def instance_method(self):
1✔
56
        return self._value
1✔
57

58

59
class WithShadowingInstanceMethod(OverridingValueInit):
1✔
60
    """Override the class-level property and method with instance versions.
61

62
    The instance-level methods should return the instance-level `_value` (the constructor argument)
63
    instead of the class-level `_value` (defined in :class:`WithProp`).
64
    """
65

66
    @property
1✔
67
    def class_property(self):
1✔
68
        return self._value
1✔
69

70
    def class_method(self):
1✔
71
        return self._value
1✔
72

73

74
class OverridingMethodDefSuper(WithProp):
1✔
75
    _other_value = "o0"
1✔
76

77
    @classproperty
1✔
78
    def class_property(cls):
1✔
79
        return super().class_property + cls._other_value
1✔
80

81

82
def test_access() -> None:
1✔
83
    assert "val0" == WithProp.class_property
1✔
84
    assert "val0" == WithProp().class_property
1✔
85

86
    assert "val0" == WithProp.class_method()
1✔
87
    assert "val0" == WithProp().class_method()
1✔
88

89
    assert "static_method" == WithProp.static_method()
1✔
90
    assert "static_method" == WithProp().static_method()
1✔
91

92

93
def test_has_attr() -> None:
1✔
94
    assert hasattr(WithProp, "class_property") is True
1✔
95
    assert hasattr(WithProp(), "class_property") is True
1✔
96

97

98
def test_docstring() -> None:
1✔
99
    assert "class_property docs." == WithProp.__dict__["class_property"].__doc__
1✔
100

101

102
def test_override_value() -> None:
1✔
103
    assert "val1" == OverridingValueField.class_property
1✔
104
    assert "val1" == OverridingValueField().class_property
1✔
105

106

107
def test_override_inst_value() -> None:
1✔
108
    obj = OverridingValueInit("v1")
1✔
109
    assert "val0" == obj.class_property
1✔
110
    assert "val0" == obj.class_method()
1✔
111
    assert "v1" == obj.instance_property
1✔
112
    assert "v1" == obj.instance_method()
1✔
113

114

115
def test_override_inst_method() -> None:
1✔
116
    obj = WithShadowingInstanceMethod("v1")
1✔
117
    assert "v1" == obj.class_property
1✔
118
    assert "v1" == obj.class_method()
1✔
119

120

121
def test_override_method_super() -> None:
1✔
122
    assert "val0o0" == OverridingMethodDefSuper.class_property
1✔
123
    assert "val0o0" == OverridingMethodDefSuper().class_property
1✔
124

125

126
def test_modify_class_value() -> None:
1✔
127
    class WithFieldToModify:
1✔
128
        _z = "z0"
1✔
129

130
        @classproperty
1✔
131
        def class_property(cls):
1✔
132
            return cls._z
1✔
133

134
    assert "z0" == WithFieldToModify.class_property
1✔
135

136
    # The classproperty reflects the change in state (is not cached by python or something else
137
    # weird we might do).
138
    WithFieldToModify._z = "z1"
1✔
139
    assert "z1" == WithFieldToModify.class_property
1✔
140

141

142
def test_set_attr():
1✔
143
    class SetValue:
1✔
144
        _x = "x0"
1✔
145

146
        @classproperty
1✔
147
        def class_property(cls):
1✔
148
            return cls._x
1✔
149

150
    assert "x0" == SetValue.class_property
1✔
151

152
    # The @classproperty is gone, this is just a regular property now.
153
    SetValue.class_property = "x1"
1✔
154
    assert "x1" == SetValue.class_property
1✔
155
    # The source field is unmodified.
156
    assert "x0" == SetValue._x
1✔
157

158

159
def test_delete_attr():
1✔
160
    class DeleteValue:
1✔
161
        _y = "y0"
1✔
162

163
        @classproperty
1✔
164
        def class_property(cls):
1✔
165
            return cls._y
1✔
166

167
    assert "y0" == DeleteValue.class_property
1✔
168

169
    # The @classproperty is gone, but the source field is still alive.
170
    del DeleteValue.class_property
1✔
171
    assert hasattr(DeleteValue, "class_property") is False
1✔
172
    assert hasattr(DeleteValue, "_y") is True
1✔
173

174

175
def test_abstract_classproperty():
1✔
176
    class Abstract(ABC):
1✔
177
        @classproperty
1✔
178
        @property
1✔
179
        @abstractmethod
1✔
180
        def f(cls):
1✔
UNCOV
181
            pass
×
182

183
    with pytest.raises(TypeError) as exc:
1✔
184
        Abstract.f
1✔
185
    assert str(exc.value) == softwrap(
1✔
186
        """
187
        The classproperty 'f' in type 'Abstract' was an abstractproperty, meaning that type
188
        Abstract must override it by setting it as a variable in the class body or defining a
189
        method with an @classproperty decorator.
190
        """
191
    )
192

193
    class WithoutOverriding(Abstract):
1✔
194
        """Show that subclasses failing to override the abstract classproperty will raise."""
195

196
    with pytest.raises(TypeError) as exc:
1✔
197
        WithoutOverriding.f
1✔
198
    assert str(exc.value) == softwrap(
1✔
199
        """
200
        The classproperty 'f' in type 'WithoutOverriding' was an abstractproperty, meaning that
201
        type WithoutOverriding must override it by setting it as a variable in the class body or
202
        defining a method with an @classproperty decorator.
203
        """
204
    )
205

206
    class Concrete(Abstract):
1✔
207
        f = 3
1✔
208

209
    assert Concrete.f == 3
1✔
210

211
    class Concrete2(Abstract):
1✔
212
        @classproperty
1✔
213
        def f(cls):
1✔
214
            return "hello"
1✔
215

216
    assert Concrete2.f == "hello"
1✔
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