gh-115775: Compiler adds __static_attributes__ field to classes (#115913)

This commit is contained in:
Irit Katriel 2024-03-26 15:18:17 +00:00 committed by GitHub
parent 70969d53a7
commit 79be75735c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
13 changed files with 136 additions and 11 deletions

View file

@ -2018,7 +2018,8 @@ def _test_simple_enum(checked_enum, simple_enum):
+ list(simple_enum._member_map_.keys())
)
for key in set(checked_keys + simple_keys):
if key in ('__module__', '_member_map_', '_value2member_map_', '__doc__'):
if key in ('__module__', '_member_map_', '_value2member_map_', '__doc__',
'__static_attributes__'):
# keys known to be different, or very long
continue
elif key in member_names:

View file

@ -313,7 +313,8 @@ def visiblename(name, all=None, obj=None):
if name in {'__author__', '__builtins__', '__cached__', '__credits__',
'__date__', '__doc__', '__file__', '__spec__',
'__loader__', '__module__', '__name__', '__package__',
'__path__', '__qualname__', '__slots__', '__version__'}:
'__path__', '__qualname__', '__slots__', '__version__',
'__static_attributes__'}:
return 0
# Private names are hidden, but special names are displayed.
if name.startswith('__') and name.endswith('__'): return 1

View file

@ -1960,6 +1960,64 @@ def test_load_super_attr(self):
)
class TestExpectedAttributes(unittest.TestCase):
def test_basic(self):
class C:
def f(self):
self.a = self.b = 42
self.assertIsInstance(C.__static_attributes__, tuple)
self.assertEqual(sorted(C.__static_attributes__), ['a', 'b'])
def test_nested_function(self):
class C:
def f(self):
self.x = 1
self.y = 2
self.x = 3 # check deduplication
def g(self, obj):
self.y = 4
self.z = 5
def h(self, a):
self.u = 6
self.v = 7
obj.self = 8
self.assertEqual(sorted(C.__static_attributes__), ['u', 'v', 'x', 'y', 'z'])
def test_nested_class(self):
class C:
def f(self):
self.x = 42
self.y = 42
class D:
def g(self):
self.y = 42
self.z = 42
self.assertEqual(sorted(C.__static_attributes__), ['x', 'y'])
self.assertEqual(sorted(C.D.__static_attributes__), ['y', 'z'])
def test_subclass(self):
class C:
def f(self):
self.x = 42
self.y = 42
class D(C):
def g(self):
self.y = 42
self.z = 42
self.assertEqual(sorted(C.__static_attributes__), ['x', 'y'])
self.assertEqual(sorted(D.__static_attributes__), ['y', 'z'])
class TestExpressionStackSize(unittest.TestCase):
# These tests check that the computed stack size for a code object
# stays within reasonable bounds (see issue #21523 for an example

View file

@ -5080,7 +5080,8 @@ def test_iter_keys(self):
keys = list(it)
keys.sort()
self.assertEqual(keys, ['__dict__', '__doc__', '__module__',
'__weakref__', 'meth'])
'__static_attributes__', '__weakref__',
'meth'])
@unittest.skipIf(hasattr(sys, 'gettrace') and sys.gettrace(),
'trace function introduces __local__')
@ -5089,7 +5090,7 @@ def test_iter_values(self):
it = self.C.__dict__.values()
self.assertNotIsInstance(it, list)
values = list(it)
self.assertEqual(len(values), 5)
self.assertEqual(len(values), 6)
@unittest.skipIf(hasattr(sys, 'gettrace') and sys.gettrace(),
'trace function introduces __local__')
@ -5100,7 +5101,8 @@ def test_iter_items(self):
keys = [item[0] for item in it]
keys.sort()
self.assertEqual(keys, ['__dict__', '__doc__', '__module__',
'__weakref__', 'meth'])
'__static_attributes__', '__weakref__',
'meth'])
def test_dict_type_with_metaclass(self):
# Testing type of __dict__ when metaclass set...

View file

@ -1160,7 +1160,7 @@ class APIMismatchTest(unittest.TestCase):
def test_RawIOBase_io_in_pyio_match(self):
"""Test that pyio RawIOBase class has all c RawIOBase methods"""
mismatch = support.detect_api_mismatch(pyio.RawIOBase, io.RawIOBase,
ignore=('__weakref__',))
ignore=('__weakref__', '__static_attributes__'))
self.assertEqual(mismatch, set(), msg='Python RawIOBase does not have all C RawIOBase methods')
def test_RawIOBase_pyio_in_io_match(self):

View file

@ -167,6 +167,7 @@
d['foo'] = 4
d['foo'] = 42
d['bar'] = 123
d['__static_attributes__'] = ()
>>>
Use a metaclass that doesn't derive from type.
@ -182,12 +183,12 @@
... b = 24
...
meta: C ()
ns: [('__module__', 'test.test_metaclass'), ('__qualname__', 'C'), ('a', 42), ('b', 24)]
ns: [('__module__', 'test.test_metaclass'), ('__qualname__', 'C'), ('__static_attributes__', ()), ('a', 42), ('b', 24)]
kw: []
>>> type(C) is dict
True
>>> print(sorted(C.items()))
[('__module__', 'test.test_metaclass'), ('__qualname__', 'C'), ('a', 42), ('b', 24)]
[('__module__', 'test.test_metaclass'), ('__qualname__', 'C'), ('__static_attributes__', ()), ('a', 42), ('b', 24)]
>>>
And again, with a __prepare__ attribute.
@ -208,8 +209,9 @@
d['a'] = 1
d['a'] = 2
d['b'] = 3
d['__static_attributes__'] = ()
meta: C ()
ns: [('__module__', 'test.test_metaclass'), ('__qualname__', 'C'), ('a', 2), ('b', 3)]
ns: [('__module__', 'test.test_metaclass'), ('__qualname__', 'C'), ('__static_attributes__', ()), ('a', 2), ('b', 3)]
kw: [('other', 'booh')]
>>>

View file

@ -1717,7 +1717,7 @@ class _TypingEllipsis:
'__abstractmethods__', '__annotations__', '__dict__', '__doc__',
'__init__', '__module__', '__new__', '__slots__',
'__subclasshook__', '__weakref__', '__class_getitem__',
'__match_args__',
'__match_args__', '__static_attributes__',
})
# These special attributes will be not collected as protocol members.