Skip to content

Commit

Permalink
pythongh-91126: Docs and tests for slotted dataclasses with `__init_s…
Browse files Browse the repository at this point in the history
…ubclass__` (python#123342)
  • Loading branch information
sobolevn committed Sep 1, 2024
1 parent d9439a2 commit 75e7282
Show file tree
Hide file tree
Showing 2 changed files with 47 additions and 4 deletions.
19 changes: 15 additions & 4 deletions Doc/library/dataclasses.rst
Original file line number Diff line number Diff line change
Expand Up @@ -185,10 +185,21 @@ Module contents
- *slots*: If true (the default is ``False``), :attr:`~object.__slots__` attribute
will be generated and new class will be returned instead of the original one.
If :attr:`!__slots__` is already defined in the class, then :exc:`TypeError`
is raised. Calling no-arg :func:`super` in dataclasses using ``slots=True`` will result in
the following exception being raised:
``TypeError: super(type, obj): obj must be an instance or subtype of type``.
The two-arg :func:`super` is a valid workaround. See :gh:`90562` for full details.
is raised.

.. warning::
Calling no-arg :func:`super` in dataclasses using ``slots=True``
will result in the following exception being raised:
``TypeError: super(type, obj): obj must be an instance or subtype of type``.
The two-arg :func:`super` is a valid workaround.
See :gh:`90562` for full details.

.. warning::
Passing parameters to a base class :meth:`~object.__init_subclass__`
when using ``slots=True`` will result in a :exc:`TypeError`.
Either use ``__init_subclass__`` with no parameters
or use default values as a workaround.
See :gh:`91126` for full details.

.. versionadded:: 3.10

Expand Down
32 changes: 32 additions & 0 deletions Lib/test/test_dataclasses/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3664,6 +3664,38 @@ class A(WithDictSlot): ...
self.assertEqual(A().__dict__, {})
A()

@support.cpython_only
def test_slots_with_wrong_init_subclass(self):
# TODO: This test is for a kinda-buggy behavior.
# Ideally, it should be fixed and `__init_subclass__`
# should be fully supported in the future versions.
# See https://github.com/python/cpython/issues/91126
class WrongSuper:
def __init_subclass__(cls, arg):
pass

with self.assertRaisesRegex(
TypeError,
"missing 1 required positional argument: 'arg'",
):
@dataclass(slots=True)
class WithWrongSuper(WrongSuper, arg=1):
pass

class CorrectSuper:
args = []
def __init_subclass__(cls, arg="default"):
cls.args.append(arg)

@dataclass(slots=True)
class WithCorrectSuper(CorrectSuper):
pass

# __init_subclass__ is called twice: once for `WithCorrectSuper`
# and once for `WithCorrectSuper__slots__` new class
# that we create internally.
self.assertEqual(CorrectSuper.args, ["default", "default"])


class TestDescriptors(unittest.TestCase):
def test_set_name(self):
Expand Down

0 comments on commit 75e7282

Please sign in to comment.