-
-
Notifications
You must be signed in to change notification settings - Fork 33.2k
Description
Bug report
Bug description:
Generally speaking, any objects present in the namespace of a class Foo that define the special __set_name__ method will have that method called on them as part of the creation of the class Foo. (__set_name__ is generally only used for descriptors, but can be defined on any class.)
For example:
Python 3.12.0 (tags/v3.12.0:0fb18b0, Oct 2 2023, 13:03:39) [MSC v.1935 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> class Annoying:
... def __set_name__(self, owner, name):
... raise Exception('no')
...
>>> class Foo:
... attr = Annoying()
...
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 3, in __set_name__
Exception: no
Error calling __set_name__ on 'Annoying' instance 'attr' in 'Foo'Descriptors inside typing.NamedTuple namespaces generally work the same way as in other class namespaces...
>>> from typing import NamedTuple
>>> class Foo(NamedTuple):
... bar = property(lambda self: 42)
...
>>> Foo().bar
42...but with one notable exception: they don't have __set_name__ called on them!
>>> class Annoying:
... def __set_name__(self, owner, name):
... raise Exception('no')
...
>>> from typing import NamedTuple
>>> class Foo(NamedTuple):
... bar = Annoying() # this should cause the creation of the `Foo` class to fail...
...
>>> # ...but it didn't!Why does this happen?
__set_name__ would normally be called on all members of a class dictionary during the class's creation. But the NamedTuple class Foo is created here:
Lines 2721 to 2723 in 97c4c06
| nm_tpl = _make_nmtuple(typename, types.items(), | |
| defaults=[ns[n] for n in default_names], | |
| module=ns['__module__']) |
And the bar attribute is only monkey-patched onto the Foo class after the class has actually been created. This happens a few lines lower down in typing.py, here:
Lines 2732 to 2733 in 97c4c06
| elif key not in _special and key not in nm_tpl._fields: | |
| setattr(nm_tpl, key, ns[key]) |
__set_name__ isn't called on Foo.bar as part of the creation of the Foo class, because the Foo class doesn't have a bar attribute at the point in time when it's actually being created.
CPython versions tested on:
3.8, 3.11, 3.12, CPython main branch
Operating systems tested on:
Windows