There is a regression in comparing recursive dataclasses for equality in Python 3.13.0 from the first alpha until at least a4.
>>> from dataclasses import dataclass
>>> @dataclass
... class C:
... recursive: object = ...
...
>>> c1 = C()
>>> c1.recursive = c1
>>> c1 == c1
True
>>> from dataclasses import dataclass
>>> @dataclass
... class C:
... recursive: object = ...
...
>>> c1 = C()
>>> c1.recursive = c1
>>> c1 == c1
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
c1 == c1
File "<string>", line 4, in __eq__
File "<string>", line 4, in __eq__
File "<string>", line 4, in __eq__
[Previous line repeated 996 more times]
RecursionError: maximum recursion depth exceeded
This breaks sip-build; hence, we cannot build pyqt5 or pyqt6 in Fedora with Python 3.13 to test the entire stack. For details, see this Fedora bugzilla.
sip-build: An internal error occurred...
Traceback (most recent call last):
File "/usr/bin/sip-build", line 8, in <module>
sys.exit(main())
^^^^^^
File "/usr/lib64/python3.13/site-packages/sipbuild/tools/build.py", line 37, in main
handle_exception(e)
File "/usr/lib64/python3.13/site-packages/sipbuild/exceptions.py", line 81, in handle_exception
raise e
File "/usr/lib64/python3.13/site-packages/sipbuild/tools/build.py", line 34, in main
project.build()
File "/usr/lib64/python3.13/site-packages/sipbuild/project.py", line 245, in build
self.builder.build()
File "/usr/lib64/python3.13/site-packages/sipbuild/builder.py", line 48, in build
self._generate_bindings()
File "/usr/lib64/python3.13/site-packages/sipbuild/builder.py", line 280, in _generate_bindings
buildable = bindings.generate()
^^^^^^^^^^^^^^^^^^^
File "/builddir/build/BUILD/PyQt5-5.15.9/project.py", line 619, in generate
buildable = super().generate()
^^^^^^^^^^^^^^^^^^
File "/usr/lib64/python3.13/site-packages/sipbuild/bindings.py", line 214, in generate
output_pyi(spec, project, pyi_path)
File "/usr/lib64/python3.13/site-packages/sipbuild/generator/outputs/pyi.py", line 53, in output_pyi
_module(pf, spec, module)
File "/usr/lib64/python3.13/site-packages/sipbuild/generator/outputs/pyi.py", line 132, in _module
_class(pf, spec, module, klass, defined)
File "/usr/lib64/python3.13/site-packages/sipbuild/generator/outputs/pyi.py", line 267, in _class
_class(pf, spec, module, nested, defined, indent)
File "/usr/lib64/python3.13/site-packages/sipbuild/generator/outputs/pyi.py", line 289, in _class
_callable(pf, spec, module, member, klass.overloads,
File "/usr/lib64/python3.13/site-packages/sipbuild/generator/outputs/pyi.py", line 485, in _callable
_overload(pf, spec, module, overload, overloaded, first_overload,
File "/usr/lib64/python3.13/site-packages/sipbuild/generator/outputs/pyi.py", line 575, in _overload
signature = _python_signature(spec, module, py_signature, defined,
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib64/python3.13/site-packages/sipbuild/generator/outputs/pyi.py", line 599, in _python_signature
as_str = _argument(spec, module, arg, defined, arg_nr=arg_nr)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib64/python3.13/site-packages/sipbuild/generator/outputs/pyi.py", line 676, in _argument
s += _type(spec, module, arg, defined, out=out)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib64/python3.13/site-packages/sipbuild/generator/outputs/pyi.py", line 710, in _type
return ArgumentFormatter(spec, arg).as_type_hint(module, out, defined)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib64/python3.13/site-packages/sipbuild/generator/outputs/formatters/argument.py", line 327, in as_type_hint
s += TypeHintManager(self.spec).as_type_hint(hint, out, context,
^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib64/python3.13/site-packages/sipbuild/generator/outputs/type_hints.py", line 107, in __new__
manager = cls._spec_manager_map[spec]
~~~~~~~~~~~~~~~~~~~~~^^^^^^
File "/usr/lib64/python3.13/weakref.py", line 415, in __getitem__
return self.data[ref(key)]
~~~~~~~~~^^^^^^^^^^
File "<string>", line 4, in __eq__
File "<string>", line 4, in __eq__
File "<string>", line 4, in __eq__
[Previous line repeated 495 more times]
RecursionError: maximum recursion depth exceeded in comparison
Bug report
Bug description:
There is a regression in comparing recursive dataclasses for equality in Python 3.13.0 from the first alpha until at least a4.
Python 3.12
Python 3.13
This has started happening since 18cfc1e.
Previously, tuples were compared via
==, which skips calling__eq__for items with the same identity. Now it skips the identity check and compares items directly with__eq__, causingRecursionError.This breaks sip-build; hence, we cannot build pyqt5 or pyqt6 in Fedora with Python 3.13 to test the entire stack. For details, see this Fedora bugzilla.
cc @rhettinger @ericvsmith
Thanks to @swt2c for bisecting the problem. Thanks to @encukou who gave me a hint of what to look for when finding the smaller reproducer.
CPython versions tested on:
3.13
Operating systems tested on:
Linux
Linked PRs