Skip to content

Objects in NamedTuple class namespaces don't have __set_name__ called on them #111874

@AlexWaygood

Description

@AlexWaygood

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:

cpython/Lib/typing.py

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:

cpython/Lib/typing.py

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

Linked PRs

Metadata

Metadata

Assignees

Labels

3.13bugs and security fixesstdlibPython modules in the Lib dirtopic-typingtype-bugAn unexpected behavior, bug, or error

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions