This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

classification
Title: Iterating over cls.__dict__ in classmethod causes RuntimeError when printing __annotations__
Type: behavior Stage:
Components: Versions: Python 3.11, Python 3.10
process
Status: open Resolution:
Dependencies: Superseder:
Assigned To: Nosy List: JelleZijlstra, PythonF, larry
Priority: normal Keywords:

Created on 2022-03-05 15:33 by PythonF, last changed 2022-04-11 14:59 by admin.

Messages (3)
msg414582 - (view) Author: Fabian Zills (PythonF) Date: 2022-03-05 15:33
When iterating over __dict__ inside a classmethod, accessing __annotations causses RuntimeError: dictionary changed size during iteration.
This only seems to affect Python 3.10.x on a Ubuntu system.

The following can be used to reproduce this issue:

class ExampleCls:
    @classmethod
    def iter_cls(cls):
        for name, val in cls.__dict__.items():
            print(cls.__annotations__)


This can be fixed for this Example by calling  _ = cls.__annotations__ before iterating over the __dict__
msg414583 - (view) Author: Jelle Zijlstra (JelleZijlstra) * (Python committer) Date: 2022-03-05 15:52
Can reproduce this:

>>> ExampleCls.__dict__
mappingproxy({'__module__': '__main__', 'iter_cls': <classmethod(<function ExampleCls.iter_cls at 0x7f1742669d80>)>, '__dict__': <attribute '__dict__' of 'ExampleCls' objects>, '__weakref__': <attribute '__weakref__' of 'ExampleCls' objects>, '__doc__': None})
>>> ExampleCls.iter_cls()
{}
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 4, in iter_cls
RuntimeError: dictionary changed size during iteration
>>> ExampleCls.__dict__
mappingproxy({'__module__': '__main__', 'iter_cls': <classmethod(<function ExampleCls.iter_cls at 0x7f1742669d80>)>, '__dict__': <attribute '__dict__' of 'ExampleCls' objects>, '__weakref__': <attribute '__weakref__' of 'ExampleCls' objects>, '__doc__': None, '__annotations__': {}})

The descriptor for type.__annotations__ writes a new attribute into the class's dict if it doesn't exist yet. This was done in bpo-43901 / GH-25263.

I don't see a way to fix this bug while preserving the behavior bpo-43901 was aiming for.
msg414639 - (view) Author: Larry Hastings (larry) * (Python committer) Date: 2022-03-07 06:42
When accessing __annotations__ *in a class without annotations*, and *for the first time*.  And your workaround seems reasonable.
History
Date User Action Args
2022-04-11 14:59:57adminsetgithub: 91086
2022-03-07 06:42:58larrysetmessages: + msg414639
2022-03-05 16:04:00AlexWaygoodsettype: crash -> behavior
versions: + Python 3.11
2022-03-05 15:52:43JelleZijlstrasetnosy: + larry, JelleZijlstra
messages: + msg414583
2022-03-05 15:33:42PythonFcreate