summaryrefslogtreecommitdiffstats
path: root/Lib/asyncio
diff options
context:
space:
mode:
authorAndrew Svetlov <andrew.svetlov@gmail.com>2022-03-17 01:03:09 (GMT)
committerGitHub <noreply@github.com>2022-03-17 01:03:09 (GMT)
commit30b5d41fabad04f9f34d603f1ce2249452c18c71 (patch)
tree7eed9b2cc60f96768193498b051583dd733e2a40 /Lib/asyncio
parenta7c54148322781cb0f332d440a3454d550ef6414 (diff)
downloadcpython-30b5d41fabad04f9f34d603f1ce2249452c18c71.zip
cpython-30b5d41fabad04f9f34d603f1ce2249452c18c71.tar.gz
cpython-30b5d41fabad04f9f34d603f1ce2249452c18c71.tar.bz2
bpo-47039: Normalize repr() of asyncio future and task objects (GH-31950)
Diffstat (limited to 'Lib/asyncio')
-rw-r--r--Lib/asyncio/base_futures.py30
-rw-r--r--Lib/asyncio/base_tasks.py7
-rw-r--r--Lib/asyncio/futures.py5
-rw-r--r--Lib/asyncio/tasks.py4
4 files changed, 19 insertions, 27 deletions
diff --git a/Lib/asyncio/base_futures.py b/Lib/asyncio/base_futures.py
index 2c01ac9..cd811a7 100644
--- a/Lib/asyncio/base_futures.py
+++ b/Lib/asyncio/base_futures.py
@@ -42,16 +42,6 @@ def _format_callbacks(cb):
return f'cb=[{cb}]'
-# bpo-42183: _repr_running is needed for repr protection
-# when a Future or Task result contains itself directly or indirectly.
-# The logic is borrowed from @reprlib.recursive_repr decorator.
-# Unfortunately, the direct decorator usage is impossible because of
-# AttributeError: '_asyncio.Task' object has no attribute '__module__' error.
-#
-# After fixing this thing we can return to the decorator based approach.
-_repr_running = set()
-
-
def _future_repr_info(future):
# (Future) -> str
"""helper function for Future.__repr__"""
@@ -60,17 +50,9 @@ def _future_repr_info(future):
if future._exception is not None:
info.append(f'exception={future._exception!r}')
else:
- key = id(future), get_ident()
- if key in _repr_running:
- result = '...'
- else:
- _repr_running.add(key)
- try:
- # use reprlib to limit the length of the output, especially
- # for very long strings
- result = reprlib.repr(future._result)
- finally:
- _repr_running.discard(key)
+ # use reprlib to limit the length of the output, especially
+ # for very long strings
+ result = reprlib.repr(future._result)
info.append(f'result={result}')
if future._callbacks:
info.append(_format_callbacks(future._callbacks))
@@ -78,3 +60,9 @@ def _future_repr_info(future):
frame = future._source_traceback[-1]
info.append(f'created at {frame[0]}:{frame[1]}')
return info
+
+
+@reprlib.recursive_repr()
+def _future_repr(future):
+ info = ' '.join(_future_repr_info(future))
+ return f'<{future.__class__.__name__} {info}>'
diff --git a/Lib/asyncio/base_tasks.py b/Lib/asyncio/base_tasks.py
index 1d62389..26298e6 100644
--- a/Lib/asyncio/base_tasks.py
+++ b/Lib/asyncio/base_tasks.py
@@ -1,4 +1,5 @@
import linecache
+import reprlib
import traceback
from . import base_futures
@@ -22,6 +23,12 @@ def _task_repr_info(task):
return info
+@reprlib.recursive_repr()
+def _task_repr(task):
+ info = ' '.join(_task_repr_info(task))
+ return f'<{task.__class__.__name__} {info}>'
+
+
def _task_get_stack(task, limit):
frames = []
if hasattr(task._coro, 'cr_frame'):
diff --git a/Lib/asyncio/futures.py b/Lib/asyncio/futures.py
index 5a92f17..bfd4ee9 100644
--- a/Lib/asyncio/futures.py
+++ b/Lib/asyncio/futures.py
@@ -85,11 +85,8 @@ class Future:
self._source_traceback = format_helpers.extract_stack(
sys._getframe(1))
- _repr_info = base_futures._future_repr_info
-
def __repr__(self):
- return '<{} {}>'.format(self.__class__.__name__,
- ' '.join(self._repr_info()))
+ return base_futures._future_repr(self)
def __del__(self):
if not self.__log_traceback:
diff --git a/Lib/asyncio/tasks.py b/Lib/asyncio/tasks.py
index b4f1eed..0b5f322 100644
--- a/Lib/asyncio/tasks.py
+++ b/Lib/asyncio/tasks.py
@@ -133,8 +133,8 @@ class Task(futures._PyFuture): # Inherit Python Task implementation
__class_getitem__ = classmethod(GenericAlias)
- def _repr_info(self):
- return base_tasks._task_repr_info(self)
+ def __repr__(self):
+ return base_tasks._task_repr(self)
def get_coro(self):
return self._coro