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:
|
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:
|
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
Linked PRs
Bug report
Bug description:
Generally speaking, any objects present in the namespace of a class
Foothat define the special__set_name__method will have that method called on them as part of the creation of the classFoo. (__set_name__is generally only used for descriptors, but can be defined on any class.)For example:
Descriptors inside
typing.NamedTuplenamespaces generally work the same way as in other class namespaces......but with one notable exception: they don't have
__set_name__called on them!Why does this happen?
__set_name__would normally be called on all members of a class dictionary during the class's creation. But theNamedTupleclassFoois created here:cpython/Lib/typing.py
Lines 2721 to 2723 in 97c4c06
And the
barattribute is only monkey-patched onto theFooclass after the class has actually been created. This happens a few lines lower down intyping.py, here:cpython/Lib/typing.py
Lines 2732 to 2733 in 97c4c06
__set_name__isn't called onFoo.baras part of the creation of theFooclass, because theFooclass doesn't have abarattribute 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
Linked PRs
__set_name__on objects that define the method inside atyping.NamedTupleclass dictionary as part of the creation of that class #111876