mirror of
https://github.com/python/cpython.git
synced 2025-08-04 08:59:19 +00:00
gh-90104: avoid RecursionError on recursive dataclass field repr (gh-100756)
Avoid RecursionError on recursive dataclass field repr
This commit is contained in:
parent
cc8748712e
commit
0a7936a38f
3 changed files with 40 additions and 21 deletions
|
@ -223,6 +223,26 @@ _POST_INIT_NAME = '__post_init__'
|
|||
# https://bugs.python.org/issue33453 for details.
|
||||
_MODULE_IDENTIFIER_RE = re.compile(r'^(?:\s*(\w+)\s*\.)?\s*(\w+)')
|
||||
|
||||
# This function's logic is copied from "recursive_repr" function in
|
||||
# reprlib module to avoid dependency.
|
||||
def _recursive_repr(user_function):
|
||||
# Decorator to make a repr function return "..." for a recursive
|
||||
# call.
|
||||
repr_running = set()
|
||||
|
||||
@functools.wraps(user_function)
|
||||
def wrapper(self):
|
||||
key = id(self), _thread.get_ident()
|
||||
if key in repr_running:
|
||||
return '...'
|
||||
repr_running.add(key)
|
||||
try:
|
||||
result = user_function(self)
|
||||
finally:
|
||||
repr_running.discard(key)
|
||||
return result
|
||||
return wrapper
|
||||
|
||||
class InitVar:
|
||||
__slots__ = ('type', )
|
||||
|
||||
|
@ -280,6 +300,7 @@ class Field:
|
|||
self.kw_only = kw_only
|
||||
self._field_type = None
|
||||
|
||||
@_recursive_repr
|
||||
def __repr__(self):
|
||||
return ('Field('
|
||||
f'name={self.name!r},'
|
||||
|
@ -403,27 +424,6 @@ def _tuple_str(obj_name, fields):
|
|||
return f'({",".join([f"{obj_name}.{f.name}" for f in fields])},)'
|
||||
|
||||
|
||||
# This function's logic is copied from "recursive_repr" function in
|
||||
# reprlib module to avoid dependency.
|
||||
def _recursive_repr(user_function):
|
||||
# Decorator to make a repr function return "..." for a recursive
|
||||
# call.
|
||||
repr_running = set()
|
||||
|
||||
@functools.wraps(user_function)
|
||||
def wrapper(self):
|
||||
key = id(self), _thread.get_ident()
|
||||
if key in repr_running:
|
||||
return '...'
|
||||
repr_running.add(key)
|
||||
try:
|
||||
result = user_function(self)
|
||||
finally:
|
||||
repr_running.discard(key)
|
||||
return result
|
||||
return wrapper
|
||||
|
||||
|
||||
def _create_fn(name, args, body, *, globals=None, locals=None,
|
||||
return_type=MISSING):
|
||||
# Note that we may mutate locals. Callers beware!
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue