8000 __class__ not set in typing.NamedTuple · Issue #85795 · python/cpython · GitHub
[go: up one dir, main page]

Skip to content

__class__ not set in typing.NamedTuple #85795

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
zzzeek mannequin opened this issue Aug 24, 2020 · 8 comments · Fixed by #130082
Closed

__class__ not set in typing.NamedTuple #85795

zzzeek mannequin opened this issue Aug 24, 2020 · 8 comments · Fixed by #130082
Labels
3.8 (EOL) end of life interpreter-core (Objects, Python, Grammar, and Parser dirs)

Comments

@zzzeek
Copy link
Mannequin
zzzeek mannequin commented Aug 24, 2020
BPO 41629
Nosy @conqp, @tirkarthi, @cdce8p

Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.

Show more details

GitHub fields:

assignee = None
closed_at = None
created_at = <Date 2020-08-24.23:32:59.688>
labels = ['interpreter-core', '3.8']
title = "__class__ not set defining 'X' as <class '__main__.X'>"
updated_at = <Date 2021-09-23.12:36:30.132>
user = 'https://bugs.python.org/zzzeek'

bugs.python.org fields:

activity = <Date 2021-09-23.12:36:30.132>
actor = 'cdce8p'
assignee = 'none'
closed = False
closed_date = None
closer = None
components = ['Interpreter Core']
creation = <Date 2020-08-24.23:32:59.688>
creator = 'zzzeek'
dependencies = []
files = []
hgrepos = []
issue_num = 41629
keywords = []
message_count = 4.0
messages = ['375863', '375879', '375880', '384490']
nosy_count = 4.0
nosy_names = ['zzzeek', 'conqp', 'xtreak', 'cdce8p']
pr_nums = []
priority = 'normal'
resolution = None
stage = None
status = 'open'
superseder = None
type = None
url = 'https://bugs.python.org/issue41629'
versions = ['Python 3.8']

Linked PRs

@zzzeek
Copy link
Mannequin Author
zzzeek mannequin commented Aug 24, 2020

This is likely related or a dupe of https://bugs.python.org/issue29270, but the error message is different. I'm posting this to confirm it's the same issue, or not, and to at least provide a google result for people who also see this error as 29270 seems to imply this might not be fixable.

Like 29270, it involves the fact that the interpreter seems to be looking at my super() call inside of a method without actually calling it, and then getting ups 8000 et about __classcell__:

from typing import NamedTuple


class X(NamedTuple):
    a: str
    b: str

    # comment this out to remove the issue
    def foo(self):
        return super(X, self)

and that's it! on my interpreter:

Python 3.8.3 (default, May 23 2020, 16:34:37)
[GCC 9.3.1 20200408 (Red Hat 9.3.1-2)] on linux

I get:

$ python test3.py 
Traceback (most recent call last):
  File "test3.py", line 4, in <module>
    class X(NamedTuple):
RuntimeError: __class__ not set defining 'X' as <class '__main__.X'>. Was __classcell__ propagated to type.__new__?

The most surprising thing is that this seems extremely basic and google is not finding this error message for me.

@zzzeek zzzeek mannequin added 3.8 (EOL) end of life interpreter-core (Objects, Python, Grammar, and Parser dirs) labels Aug 24, 2020
@tirkarthi
Copy link
Member

The example used to raise deprecation warning in python 3.7

python3.7 -Wall ../backups/bpo41629.py
../backups/bpo41629.py:4: DeprecationWarning: __class__ not set defining 'X' as <class '__main__.X'>. Was __classcell__ propagated to type.__new__?
class X(NamedTuple):

It was converted into RuntimeError in f5e7b19 . Related https://bugs.python.org/issue23722

@terryjreedy terryjreedy changed the title __class__ not set defining 'X' as <class '__main__.X'>. Was __classcell__ propagated to type.__new__? __class__ not set defining 'X' as <class '__main__.X'> Aug 29, 2020
@terryjreedy terryjreedy changed the title __class__ not set defining 'X' as <class '__main__.X'>. Was __classcell__ propagated to type.__new__? __class__ not set defining 'X' as <class '__main__.X'> Aug 29, 2020
@coNQP
8000
Copy link
Mannequin
coNQP mannequin commented Jan 6, 2021

I just stumbled across this issue trying to resolve this: https://bugs.python.org/issue42765?

While this fails:

from typing import NamedTuple


class Spamm(NamedTuple):
foo: int
bar: str
    def __getitem__(self, index_or_key):
        """Returns the respective item."""
        if isinstance(index_or_key, str):
            try:
                return getattr(self, index_or_key)
            except AttributeError:
                raise IndexError(index_or_key) from None

        return super().__getitem__(index_or_key)

    def keys(self):
        return self._fields


def main():

    spamm = Spamm(12, 'hello')
    print(dir(spamm))
    print(spamm._fields)
    d = dict(spamm)
    print(d)


if __name__ == '__main__':
    main()

with

Traceback (most recent call last):
  File "/home/neumann/test.py", line 4, in <module>
    class Spamm(NamedTuple):
RuntimeError: __class__ not set defining 'Spamm' as <class '__main__.Spamm'>. Was __classcell__ propagated to type.__new__?

The following works:

from typing import NamedTuple


def _getitem(instance, index_or_key):
    """Returns the respective item."""

    if isinstance(index_or_key, str):
        try:
            return getattr(instance, index_or_key)
        except AttributeError:
            raise IndexError(index_or_key) from None

    return super().__getitem__(index_or_key)


def dicttuple(cls: tuple):
    """Extends a tuple class with methods for the dict constructor."""

    cls.keys = lambda self: self._fields
    cls.__getitem__ = _getitem
    return cls


@dicttuple
class Spamm(NamedTuple):
foo: int
bar: str
def main():

    spamm = Spamm(12, 'hello')
    print(dir(spamm))
    print(spamm._fields)
    d = dict(spamm)
    print(d)


if __name__ == '__main__':
    main()

And produces:

['__add__', '__annotations__', '__class__', '__class_getitem__', '__contains__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getnewargs__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__module__', '__mul__', '__ne__', '__new__', '__orig_bases__', '__reduce__', '__reduce_ex__', '__repr__', '__rmul__', '__setattr__', '__sizeof__', '__slots__', '__str__', '__subclasshook__', '_asdict', '_field_defaults', '_fields', '_make', '_replace', 'bar', 'count', 'foo', 'index', 'keys']
('foo', 'bar')
{'foo': 12, 'bar': 'hello'}

I am a bit baffled, why it works when the method is injected via a decorator.

@ezio-melotti ezio-melotti transferred this issue from another repository Apr 10, 2022
@Prometheus3375
Copy link
Contributor

I met this issue in Python 3.10 too.

@BirdLogics
Copy link

This issue is still present in Python 3.11.2. The super function cannot be used within a named tuple or a RuntimeError will occur.

@bswck
Copy link
Contributor
bswck commented Feb 13, 2025

In gh-129352, we drew a conclusion that it is unnecessary for typed named tuples to support super(). We'll add code to dynamically check for the presence of __classcell__ and raise a navigable error if it's present.

It may be a good idea to detect and prevent the use of super() in that context in type checkers. WDYT @JelleZijlstra @AlexWaygood? (FWIW, I just reproduced this issue in pypy. It's super unlikely other implementations will support super() in typed namedtuples or that they already support it.)

@JelleZijlstra JelleZijlstra changed the title __class__ not set defining 'X' as <class '__main__.X'> __class__ not set in typing.NamedTuple Feb 14, 2025
@JelleZijlstra
Copy link
Member

Sure, type checkers (or linters: detecting this issue doesn't really need a full type checker) could detect this. I don't think it's especially common, but tool maintainers may be willing to entertain contributions.

JelleZijlstra pushed a commit that referenced this issue Mar 6, 2025
seehwan pushed a commit to seehwan/cpython that referenced this issue Apr 16, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
3.8 (EOL) end of life interpreter-core (Objects, Python, Grammar, and Parser dirs)
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants
0