Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 18 additions & 2 deletions Lib/dataclasses.py
Original file line number Diff line number Diff line change
Expand Up @@ -1284,6 +1284,23 @@ def _get_slots(cls):
raise TypeError(f"Slots of '{cls.__name__}' cannot be determined")


def _unwrap(func):
# A copy of `inspect.unwrap()`, to avoid importing `inspect` module.
# Keep this in sync with the original.
f = func # remember the original func for error reporting
# Memoise by id to tolerate non-hashable objects, but store objects to
# ensure they aren't destroyed, which would allow their IDs to be reused.
memo = {id(f): f}
recursion_limit = sys.getrecursionlimit()
while not isinstance(func, type) and hasattr(func, '__wrapped__'):
func = func.__wrapped__
id_func = id(func)
if (id_func in memo) or (len(memo) >= recursion_limit):
raise ValueError(f'wrapper loop when unwrapping {f!r}')
memo[id_func] = func
return func


def _update_func_cell_for__class__(f, oldcls, newcls):
# Returns True if we update a cell, else False.
if f is None:
Expand Down Expand Up @@ -1392,8 +1409,7 @@ def _add_slots(cls, is_frozen, weakref_slot, defined_fields):

# If this is a wrapped function, unwrap it.
if not isinstance(member, type) and hasattr(member, '__wrapped__'):
import inspect
member = inspect.unwrap(member)
member = _unwrap(member)

if isinstance(member, types.FunctionType):
if _update_func_cell_for__class__(member, cls, newcls):
Expand Down
14 changes: 14 additions & 0 deletions Lib/test/test_dataclasses/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,20 @@ def test_lazy_import(self):
"dataclasses", {"inspect", "re", "copy"}
)

@cpython_only
def test_slots_does_not_import_inspect(self):
create_slotted_class = textwrap.dedent(
"""
@dataclasses.dataclass(slots=True)
class C:
x: int = 0
"""
)
import_helper.ensure_lazy_imports(
"dataclasses", {"inspect"},
additional_code=create_slotted_class,
)


class TestCase(unittest.TestCase):
def test_no_fields(self):
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Creating a :func:`~dataclasses.dataclass` with ``slots=True`` no longer
imports the :mod:`inspect` module.
Loading