Skip to content
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

__class__ not set defining 'X' as <class '__main__.X'> #85795

Open
zzzeek mannequin opened this issue Aug 24, 2020 · 6 comments
Open

__class__ not set defining 'X' as <class '__main__.X'> #85795

zzzeek mannequin opened this issue Aug 24, 2020 · 6 comments
Labels
3.8 only security fixes 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']

@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 upset 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 only security fixes 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
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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
3.8 only security fixes interpreter-core (Objects, Python, Grammar, and Parser dirs)
Projects
None yet
Development

No branches or pull requests

3 participants