@@ -561,8 +561,7 @@ def __annotate__(format, /):
561561 case _:
562562 raise NotImplementedError (format )
563563
564- # This is a flag for _add_slots to know it needs to regenerate this method
565- # In order to remove references to the original class when it is replaced
564+ # Mark the function as generated by dataclasses, for introspection.
566565 __annotate__ .__generated_by_dataclasses__ = True
567566 __annotate__ .__qualname__ = f"{ __class__ .__qualname__ } .{ method_name } .__annotate__"
568567
@@ -1118,6 +1117,16 @@ def _process_class(cls, init, repr, eq, order, unsafe_hash, frozen,
11181117 # also marks this class as being a dataclass.
11191118 setattr (cls , _FIELDS , fields )
11201119
1120+ # It's an error to specify weakref_slot if slots is False.
1121+ if weakref_slot and not slots :
1122+ raise TypeError ('weakref_slot is True but slots is False' )
1123+ if slots :
1124+ # Create the slotted class before generating any methods, so that
1125+ # the generated methods are bound to the final class from the start
1126+ # and the __class__ cell fix-up in _add_slots only has to look at
1127+ # user-defined methods.
1128+ cls = _add_slots (cls , frozen , weakref_slot , fields )
1129+
11211130 # Was this class defined with an explicit __hash__? Note that if
11221131 # __eq__ is defined in this class, then python will automatically
11231132 # set __hash__ to None. This is a heuristic, as it's possible
@@ -1235,12 +1244,6 @@ def _process_class(cls, init, repr, eq, order, unsafe_hash, frozen,
12351244 _set_new_attribute (cls , '__match_args__' ,
12361245 tuple (f .name for f in std_init_fields ))
12371246
1238- # It's an error to specify weakref_slot if slots is False.
1239- if weakref_slot and not slots :
1240- raise TypeError ('weakref_slot is True but slots is False' )
1241- if slots :
1242- cls = _add_slots (cls , frozen , weakref_slot , fields )
1243-
12441247 abc .update_abstractmethods (cls )
12451248
12461249 return cls
@@ -1284,23 +1287,6 @@ def _get_slots(cls):
12841287 raise TypeError (f"Slots of '{ cls .__name__ } ' cannot be determined" )
12851288
12861289
1287- def _unwrap (func ):
1288- # A copy of `inspect.unwrap()`, to avoid importing `inspect` module.
1289- # Keep this in sync with the original.
1290- f = func # remember the original func for error reporting
1291- # Memoise by id to tolerate non-hashable objects, but store objects to
1292- # ensure they aren't destroyed, which would allow their IDs to be reused.
1293- memo = {id (f ): f }
1294- recursion_limit = sys .getrecursionlimit ()
1295- while not isinstance (func , type ) and hasattr (func , '__wrapped__' ):
1296- func = func .__wrapped__
1297- id_func = id (func )
1298- if (id_func in memo ) or (len (memo ) >= recursion_limit ):
1299- raise ValueError (f'wrapper loop when unwrapping { f !r} ' )
1300- memo [id_func ] = func
1301- return func
1302-
1303-
13041290def _update_func_cell_for__class__ (f , oldcls , newcls ):
13051291 # Returns True if we update a cell, else False.
13061292 if f is None :
@@ -1409,7 +1395,8 @@ def _add_slots(cls, is_frozen, weakref_slot, defined_fields):
14091395
14101396 # If this is a wrapped function, unwrap it.
14111397 if not isinstance (member , type ) and hasattr (member , '__wrapped__' ):
1412- member = _unwrap (member )
1398+ import inspect
1399+ member = inspect .unwrap (member )
14131400
14141401 if isinstance (member , types .FunctionType ):
14151402 if _update_func_cell_for__class__ (member , cls , newcls ):
@@ -1434,12 +1421,6 @@ def _add_slots(cls, is_frozen, weakref_slot, defined_fields):
14341421 else :
14351422 f .type = ann
14361423
1437- # Fix the class reference in the __annotate__ method
1438- init = newcls .__init__
1439- if init_annotate := getattr (init , "__annotate__" , None ):
1440- if getattr (init_annotate , "__generated_by_dataclasses__" , False ):
1441- _update_func_cell_for__class__ (init_annotate , cls , newcls )
1442-
14431424 return newcls
14441425
14451426
0 commit comments