blob: 2c01ac98e10fcaa4ac0b88a2f196dc6450769bf7 [file] [log] [blame]
Yury Selivanov6370f342017-12-10 18:36:12 -05001__all__ = ()
Yury Selivanova0c1ba62016-10-28 12:52:37 -04002
Yury Selivanova0c1ba62016-10-28 12:52:37 -04003import reprlib
Andrew Svetlov42d873c2020-11-10 15:58:31 +02004from _thread import get_ident
Yury Selivanova0c1ba62016-10-28 12:52:37 -04005
Andrew Svetlovf74ef452017-12-15 07:04:38 +02006from . import format_helpers
Yury Selivanova0c1ba62016-10-28 12:52:37 -04007
Yury Selivanova0c1ba62016-10-28 12:52:37 -04008# States for Future.
9_PENDING = 'PENDING'
10_CANCELLED = 'CANCELLED'
11_FINISHED = 'FINISHED'
12
13
14def isfuture(obj):
15 """Check for a Future.
16
17 This returns True when obj is a Future instance or is advertising
18 itself as duck-type compatible by setting _asyncio_future_blocking.
19 See comment in Future for more details.
20 """
Yury Selivanov6130c022016-11-07 16:07:30 -050021 return (hasattr(obj.__class__, '_asyncio_future_blocking') and
22 obj._asyncio_future_blocking is not None)
Yury Selivanova0c1ba62016-10-28 12:52:37 -040023
24
25def _format_callbacks(cb):
26 """helper function for Future.__repr__"""
27 size = len(cb)
28 if not size:
29 cb = ''
30
31 def format_cb(callback):
Andrew Svetlovf74ef452017-12-15 07:04:38 +020032 return format_helpers._format_callback_source(callback, ())
Yury Selivanova0c1ba62016-10-28 12:52:37 -040033
34 if size == 1:
Yury Selivanovf23746a2018-01-22 19:11:18 -050035 cb = format_cb(cb[0][0])
Yury Selivanova0c1ba62016-10-28 12:52:37 -040036 elif size == 2:
Yury Selivanovf23746a2018-01-22 19:11:18 -050037 cb = '{}, {}'.format(format_cb(cb[0][0]), format_cb(cb[1][0]))
Yury Selivanova0c1ba62016-10-28 12:52:37 -040038 elif size > 2:
Yury Selivanovf23746a2018-01-22 19:11:18 -050039 cb = '{}, <{} more>, {}'.format(format_cb(cb[0][0]),
Yury Selivanova0c1ba62016-10-28 12:52:37 -040040 size - 2,
Yury Selivanovf23746a2018-01-22 19:11:18 -050041 format_cb(cb[-1][0]))
Yury Selivanov6370f342017-12-10 18:36:12 -050042 return f'cb=[{cb}]'
Yury Selivanova0c1ba62016-10-28 12:52:37 -040043
44
Andrew Svetlov42d873c2020-11-10 15:58:31 +020045# bpo-42183: _repr_running is needed for repr protection
46# when a Future or Task result contains itself directly or indirectly.
47# The logic is borrowed from @reprlib.recursive_repr decorator.
48# Unfortunately, the direct decorator usage is impossible because of
49# AttributeError: '_asyncio.Task' object has no attribute '__module__' error.
50#
51# After fixing this thing we can return to the decorator based approach.
52_repr_running = set()
53
54
Yury Selivanova0c1ba62016-10-28 12:52:37 -040055def _future_repr_info(future):
56 # (Future) -> str
57 """helper function for Future.__repr__"""
58 info = [future._state.lower()]
59 if future._state == _FINISHED:
60 if future._exception is not None:
Yury Selivanov6370f342017-12-10 18:36:12 -050061 info.append(f'exception={future._exception!r}')
Yury Selivanova0c1ba62016-10-28 12:52:37 -040062 else:
Andrew Svetlov42d873c2020-11-10 15:58:31 +020063 key = id(future), get_ident()
64 if key in _repr_running:
65 result = '...'
66 else:
67 _repr_running.add(key)
68 try:
69 # use reprlib to limit the length of the output, especially
70 # for very long strings
71 result = reprlib.repr(future._result)
72 finally:
73 _repr_running.discard(key)
Yury Selivanov6370f342017-12-10 18:36:12 -050074 info.append(f'result={result}')
Yury Selivanova0c1ba62016-10-28 12:52:37 -040075 if future._callbacks:
76 info.append(_format_callbacks(future._callbacks))
77 if future._source_traceback:
78 frame = future._source_traceback[-1]
Yury Selivanov6370f342017-12-10 18:36:12 -050079 info.append(f'created at {frame[0]}:{frame[1]}')
Yury Selivanova0c1ba62016-10-28 12:52:37 -040080 return info