summaryrefslogtreecommitdiffstats
path: root/Lib/dataclasses.py
diff options
context:
space:
mode:
authorCarl Meyer <carl@oddbird.net>2023-01-06 00:19:40 (GMT)
committerGitHub <noreply@github.com>2023-01-06 00:19:40 (GMT)
commit0a7936a38f0bab1619ee9fe257880a51c9d839d5 (patch)
treed80b3a2e48200408d41b415beacd59a1f4b2b0c5 /Lib/dataclasses.py
parentcc8748712e78805c5be4a0a3f98cfb5c35026d0e (diff)
downloadcpython-0a7936a38f0bab1619ee9fe257880a51c9d839d5.zip
cpython-0a7936a38f0bab1619ee9fe257880a51c9d839d5.tar.gz
cpython-0a7936a38f0bab1619ee9fe257880a51c9d839d5.tar.bz2
gh-90104: avoid RecursionError on recursive dataclass field repr (gh-100756)
Avoid RecursionError on recursive dataclass field repr
Diffstat (limited to 'Lib/dataclasses.py')
-rw-r--r--Lib/dataclasses.py42
1 files changed, 21 insertions, 21 deletions
diff --git a/Lib/dataclasses.py b/Lib/dataclasses.py
index b54e169..5c0257e 100644
--- a/Lib/dataclasses.py
+++ b/Lib/dataclasses.py
@@ -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!