diff options
author | Andrew Svetlov <andrew.svetlov@gmail.com> | 2022-03-17 01:03:09 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-03-17 01:03:09 (GMT) |
commit | 30b5d41fabad04f9f34d603f1ce2249452c18c71 (patch) | |
tree | 7eed9b2cc60f96768193498b051583dd733e2a40 /Lib/asyncio | |
parent | a7c54148322781cb0f332d440a3454d550ef6414 (diff) | |
download | cpython-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.py | 30 | ||||
-rw-r--r-- | Lib/asyncio/base_tasks.py | 7 | ||||
-rw-r--r-- | Lib/asyncio/futures.py | 5 | ||||
-rw-r--r-- | Lib/asyncio/tasks.py | 4 |
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 |