base_futures.py 2.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980
  1. __all__ = ()
  2. import reprlib
  3. from _thread import get_ident
  4. from . import format_helpers
  5. # States for Future.
  6. _PENDING = 'PENDING'
  7. _CANCELLED = 'CANCELLED'
  8. _FINISHED = 'FINISHED'
  9. def isfuture(obj):
  10. """Check for a Future.
  11. This returns True when obj is a Future instance or is advertising
  12. itself as duck-type compatible by setting _asyncio_future_blocking.
  13. See comment in Future for more details.
  14. """
  15. return (hasattr(obj.__class__, '_asyncio_future_blocking') and
  16. obj._asyncio_future_blocking is not None)
  17. def _format_callbacks(cb):
  18. """helper function for Future.__repr__"""
  19. size = len(cb)
  20. if not size:
  21. cb = ''
  22. def format_cb(callback):
  23. return format_helpers._format_callback_source(callback, ())
  24. if size == 1:
  25. cb = format_cb(cb[0][0])
  26. elif size == 2:
  27. cb = '{}, {}'.format(format_cb(cb[0][0]), format_cb(cb[1][0]))
  28. elif size > 2:
  29. cb = '{}, <{} more>, {}'.format(format_cb(cb[0][0]),
  30. size - 2,
  31. format_cb(cb[-1][0]))
  32. return f'cb=[{cb}]'
  33. # bpo-42183: _repr_running is needed for repr protection
  34. # when a Future or Task result contains itself directly or indirectly.
  35. # The logic is borrowed from @reprlib.recursive_repr decorator.
  36. # Unfortunately, the direct decorator usage is impossible because of
  37. # AttributeError: '_asyncio.Task' object has no attribute '__module__' error.
  38. #
  39. # After fixing this thing we can return to the decorator based approach.
  40. _repr_running = set()
  41. def _future_repr_info(future):
  42. # (Future) -> str
  43. """helper function for Future.__repr__"""
  44. info = [future._state.lower()]
  45. if future._state == _FINISHED:
  46. if future._exception is not None:
  47. info.append(f'exception={future._exception!r}')
  48. else:
  49. key = id(future), get_ident()
  50. if key in _repr_running:
  51. result = '...'
  52. else:
  53. _repr_running.add(key)
  54. try:
  55. # use reprlib to limit the length of the output, especially
  56. # for very long strings
  57. result = reprlib.repr(future._result)
  58. finally:
  59. _repr_running.discard(key)
  60. info.append(f'result={result}')
  61. if future._callbacks:
  62. info.append(_format_callbacks(future._callbacks))
  63. if future._source_traceback:
  64. frame = future._source_traceback[-1]
  65. info.append(f'created at {frame[0]}:{frame[1]}')
  66. return info