Edit File by line
/home/barbar84/public_h.../wp-conte.../plugins/sujqvwi/ShExBy/shex_roo.../lib64/python3..../asyncio
File: futures.py
"""A Future class similar to the one in PEP 3148."""
[0] Fix | Delete
[1] Fix | Delete
__all__ = ['CancelledError', 'TimeoutError', 'InvalidStateError',
[2] Fix | Delete
'Future', 'wrap_future', 'isfuture']
[3] Fix | Delete
[4] Fix | Delete
import concurrent.futures
[5] Fix | Delete
import logging
[6] Fix | Delete
import sys
[7] Fix | Delete
import traceback
[8] Fix | Delete
[9] Fix | Delete
from . import base_futures
[10] Fix | Delete
from . import compat
[11] Fix | Delete
from . import events
[12] Fix | Delete
[13] Fix | Delete
[14] Fix | Delete
CancelledError = base_futures.CancelledError
[15] Fix | Delete
InvalidStateError = base_futures.InvalidStateError
[16] Fix | Delete
TimeoutError = base_futures.TimeoutError
[17] Fix | Delete
isfuture = base_futures.isfuture
[18] Fix | Delete
[19] Fix | Delete
[20] Fix | Delete
_PENDING = base_futures._PENDING
[21] Fix | Delete
_CANCELLED = base_futures._CANCELLED
[22] Fix | Delete
_FINISHED = base_futures._FINISHED
[23] Fix | Delete
[24] Fix | Delete
[25] Fix | Delete
STACK_DEBUG = logging.DEBUG - 1 # heavy-duty debugging
[26] Fix | Delete
[27] Fix | Delete
[28] Fix | Delete
class _TracebackLogger:
[29] Fix | Delete
"""Helper to log a traceback upon destruction if not cleared.
[30] Fix | Delete
[31] Fix | Delete
This solves a nasty problem with Futures and Tasks that have an
[32] Fix | Delete
exception set: if nobody asks for the exception, the exception is
[33] Fix | Delete
never logged. This violates the Zen of Python: 'Errors should
[34] Fix | Delete
never pass silently. Unless explicitly silenced.'
[35] Fix | Delete
[36] Fix | Delete
However, we don't want to log the exception as soon as
[37] Fix | Delete
set_exception() is called: if the calling code is written
[38] Fix | Delete
properly, it will get the exception and handle it properly. But
[39] Fix | Delete
we *do* want to log it if result() or exception() was never called
[40] Fix | Delete
-- otherwise developers waste a lot of time wondering why their
[41] Fix | Delete
buggy code fails silently.
[42] Fix | Delete
[43] Fix | Delete
An earlier attempt added a __del__() method to the Future class
[44] Fix | Delete
itself, but this backfired because the presence of __del__()
[45] Fix | Delete
prevents garbage collection from breaking cycles. A way out of
[46] Fix | Delete
this catch-22 is to avoid having a __del__() method on the Future
[47] Fix | Delete
class itself, but instead to have a reference to a helper object
[48] Fix | Delete
with a __del__() method that logs the traceback, where we ensure
[49] Fix | Delete
that the helper object doesn't participate in cycles, and only the
[50] Fix | Delete
Future has a reference to it.
[51] Fix | Delete
[52] Fix | Delete
The helper object is added when set_exception() is called. When
[53] Fix | Delete
the Future is collected, and the helper is present, the helper
[54] Fix | Delete
object is also collected, and its __del__() method will log the
[55] Fix | Delete
traceback. When the Future's result() or exception() method is
[56] Fix | Delete
called (and a helper object is present), it removes the helper
[57] Fix | Delete
object, after calling its clear() method to prevent it from
[58] Fix | Delete
logging.
[59] Fix | Delete
[60] Fix | Delete
One downside is that we do a fair amount of work to extract the
[61] Fix | Delete
traceback from the exception, even when it is never logged. It
[62] Fix | Delete
would seem cheaper to just store the exception object, but that
[63] Fix | Delete
references the traceback, which references stack frames, which may
[64] Fix | Delete
reference the Future, which references the _TracebackLogger, and
[65] Fix | Delete
then the _TracebackLogger would be included in a cycle, which is
[66] Fix | Delete
what we're trying to avoid! As an optimization, we don't
[67] Fix | Delete
immediately format the exception; we only do the work when
[68] Fix | Delete
activate() is called, which call is delayed until after all the
[69] Fix | Delete
Future's callbacks have run. Since usually a Future has at least
[70] Fix | Delete
one callback (typically set by 'yield from') and usually that
[71] Fix | Delete
callback extracts the callback, thereby removing the need to
[72] Fix | Delete
format the exception.
[73] Fix | Delete
[74] Fix | Delete
PS. I don't claim credit for this solution. I first heard of it
[75] Fix | Delete
in a discussion about closing files when they are collected.
[76] Fix | Delete
"""
[77] Fix | Delete
[78] Fix | Delete
__slots__ = ('loop', 'source_traceback', 'exc', 'tb')
[79] Fix | Delete
[80] Fix | Delete
def __init__(self, future, exc):
[81] Fix | Delete
self.loop = future._loop
[82] Fix | Delete
self.source_traceback = future._source_traceback
[83] Fix | Delete
self.exc = exc
[84] Fix | Delete
self.tb = None
[85] Fix | Delete
[86] Fix | Delete
def activate(self):
[87] Fix | Delete
exc = self.exc
[88] Fix | Delete
if exc is not None:
[89] Fix | Delete
self.exc = None
[90] Fix | Delete
self.tb = traceback.format_exception(exc.__class__, exc,
[91] Fix | Delete
exc.__traceback__)
[92] Fix | Delete
[93] Fix | Delete
def clear(self):
[94] Fix | Delete
self.exc = None
[95] Fix | Delete
self.tb = None
[96] Fix | Delete
[97] Fix | Delete
def __del__(self):
[98] Fix | Delete
if self.tb:
[99] Fix | Delete
msg = 'Future/Task exception was never retrieved\n'
[100] Fix | Delete
if self.source_traceback:
[101] Fix | Delete
src = ''.join(traceback.format_list(self.source_traceback))
[102] Fix | Delete
msg += 'Future/Task created at (most recent call last):\n'
[103] Fix | Delete
msg += '%s\n' % src.rstrip()
[104] Fix | Delete
msg += ''.join(self.tb).rstrip()
[105] Fix | Delete
self.loop.call_exception_handler({'message': msg})
[106] Fix | Delete
[107] Fix | Delete
[108] Fix | Delete
class Future:
[109] Fix | Delete
"""This class is *almost* compatible with concurrent.futures.Future.
[110] Fix | Delete
[111] Fix | Delete
Differences:
[112] Fix | Delete
[113] Fix | Delete
- This class is not thread-safe.
[114] Fix | Delete
[115] Fix | Delete
- result() and exception() do not take a timeout argument and
[116] Fix | Delete
raise an exception when the future isn't done yet.
[117] Fix | Delete
[118] Fix | Delete
- Callbacks registered with add_done_callback() are always called
[119] Fix | Delete
via the event loop's call_soon().
[120] Fix | Delete
[121] Fix | Delete
- This class is not compatible with the wait() and as_completed()
[122] Fix | Delete
methods in the concurrent.futures package.
[123] Fix | Delete
[124] Fix | Delete
(In Python 3.4 or later we may be able to unify the implementations.)
[125] Fix | Delete
"""
[126] Fix | Delete
[127] Fix | Delete
# Class variables serving as defaults for instance variables.
[128] Fix | Delete
_state = _PENDING
[129] Fix | Delete
_result = None
[130] Fix | Delete
_exception = None
[131] Fix | Delete
_loop = None
[132] Fix | Delete
_source_traceback = None
[133] Fix | Delete
[134] Fix | Delete
# This field is used for a dual purpose:
[135] Fix | Delete
# - Its presence is a marker to declare that a class implements
[136] Fix | Delete
# the Future protocol (i.e. is intended to be duck-type compatible).
[137] Fix | Delete
# The value must also be not-None, to enable a subclass to declare
[138] Fix | Delete
# that it is not compatible by setting this to None.
[139] Fix | Delete
# - It is set by __iter__() below so that Task._step() can tell
[140] Fix | Delete
# the difference between `yield from Future()` (correct) vs.
[141] Fix | Delete
# `yield Future()` (incorrect).
[142] Fix | Delete
_asyncio_future_blocking = False
[143] Fix | Delete
[144] Fix | Delete
_log_traceback = False
[145] Fix | Delete
[146] Fix | Delete
def __init__(self, *, loop=None):
[147] Fix | Delete
"""Initialize the future.
[148] Fix | Delete
[149] Fix | Delete
The optional event_loop argument allows explicitly setting the event
[150] Fix | Delete
loop object used by the future. If it's not provided, the future uses
[151] Fix | Delete
the default event loop.
[152] Fix | Delete
"""
[153] Fix | Delete
if loop is None:
[154] Fix | Delete
self._loop = events.get_event_loop()
[155] Fix | Delete
else:
[156] Fix | Delete
self._loop = loop
[157] Fix | Delete
self._callbacks = []
[158] Fix | Delete
if self._loop.get_debug():
[159] Fix | Delete
self._source_traceback = events.extract_stack(sys._getframe(1))
[160] Fix | Delete
[161] Fix | Delete
_repr_info = base_futures._future_repr_info
[162] Fix | Delete
[163] Fix | Delete
def __repr__(self):
[164] Fix | Delete
return '<%s %s>' % (self.__class__.__name__, ' '.join(self._repr_info()))
[165] Fix | Delete
[166] Fix | Delete
# On Python 3.3 and older, objects with a destructor part of a reference
[167] Fix | Delete
# cycle are never destroyed. It's not more the case on Python 3.4 thanks
[168] Fix | Delete
# to the PEP 442.
[169] Fix | Delete
if compat.PY34:
[170] Fix | Delete
def __del__(self):
[171] Fix | Delete
if not self._log_traceback:
[172] Fix | Delete
# set_exception() was not called, or result() or exception()
[173] Fix | Delete
# has consumed the exception
[174] Fix | Delete
return
[175] Fix | Delete
exc = self._exception
[176] Fix | Delete
context = {
[177] Fix | Delete
'message': ('%s exception was never retrieved'
[178] Fix | Delete
% self.__class__.__name__),
[179] Fix | Delete
'exception': exc,
[180] Fix | Delete
'future': self,
[181] Fix | Delete
}
[182] Fix | Delete
if self._source_traceback:
[183] Fix | Delete
context['source_traceback'] = self._source_traceback
[184] Fix | Delete
self._loop.call_exception_handler(context)
[185] Fix | Delete
[186] Fix | Delete
def cancel(self):
[187] Fix | Delete
"""Cancel the future and schedule callbacks.
[188] Fix | Delete
[189] Fix | Delete
If the future is already done or cancelled, return False. Otherwise,
[190] Fix | Delete
change the future's state to cancelled, schedule the callbacks and
[191] Fix | Delete
return True.
[192] Fix | Delete
"""
[193] Fix | Delete
self._log_traceback = False
[194] Fix | Delete
if self._state != _PENDING:
[195] Fix | Delete
return False
[196] Fix | Delete
self._state = _CANCELLED
[197] Fix | Delete
self._schedule_callbacks()
[198] Fix | Delete
return True
[199] Fix | Delete
[200] Fix | Delete
def _schedule_callbacks(self):
[201] Fix | Delete
"""Internal: Ask the event loop to call all callbacks.
[202] Fix | Delete
[203] Fix | Delete
The callbacks are scheduled to be called as soon as possible. Also
[204] Fix | Delete
clears the callback list.
[205] Fix | Delete
"""
[206] Fix | Delete
callbacks = self._callbacks[:]
[207] Fix | Delete
if not callbacks:
[208] Fix | Delete
return
[209] Fix | Delete
[210] Fix | Delete
self._callbacks[:] = []
[211] Fix | Delete
for callback in callbacks:
[212] Fix | Delete
self._loop.call_soon(callback, self)
[213] Fix | Delete
[214] Fix | Delete
def cancelled(self):
[215] Fix | Delete
"""Return True if the future was cancelled."""
[216] Fix | Delete
return self._state == _CANCELLED
[217] Fix | Delete
[218] Fix | Delete
# Don't implement running(); see http://bugs.python.org/issue18699
[219] Fix | Delete
[220] Fix | Delete
def done(self):
[221] Fix | Delete
"""Return True if the future is done.
[222] Fix | Delete
[223] Fix | Delete
Done means either that a result / exception are available, or that the
[224] Fix | Delete
future was cancelled.
[225] Fix | Delete
"""
[226] Fix | Delete
return self._state != _PENDING
[227] Fix | Delete
[228] Fix | Delete
def result(self):
[229] Fix | Delete
"""Return the result this future represents.
[230] Fix | Delete
[231] Fix | Delete
If the future has been cancelled, raises CancelledError. If the
[232] Fix | Delete
future's result isn't yet available, raises InvalidStateError. If
[233] Fix | Delete
the future is done and has an exception set, this exception is raised.
[234] Fix | Delete
"""
[235] Fix | Delete
if self._state == _CANCELLED:
[236] Fix | Delete
raise CancelledError
[237] Fix | Delete
if self._state != _FINISHED:
[238] Fix | Delete
raise InvalidStateError('Result is not ready.')
[239] Fix | Delete
self._log_traceback = False
[240] Fix | Delete
if self._exception is not None:
[241] Fix | Delete
raise self._exception
[242] Fix | Delete
return self._result
[243] Fix | Delete
[244] Fix | Delete
def exception(self):
[245] Fix | Delete
"""Return the exception that was set on this future.
[246] Fix | Delete
[247] Fix | Delete
The exception (or None if no exception was set) is returned only if
[248] Fix | Delete
the future is done. If the future has been cancelled, raises
[249] Fix | Delete
CancelledError. If the future isn't done yet, raises
[250] Fix | Delete
InvalidStateError.
[251] Fix | Delete
"""
[252] Fix | Delete
if self._state == _CANCELLED:
[253] Fix | Delete
raise CancelledError
[254] Fix | Delete
if self._state != _FINISHED:
[255] Fix | Delete
raise InvalidStateError('Exception is not set.')
[256] Fix | Delete
self._log_traceback = False
[257] Fix | Delete
return self._exception
[258] Fix | Delete
[259] Fix | Delete
def add_done_callback(self, fn):
[260] Fix | Delete
"""Add a callback to be run when the future becomes done.
[261] Fix | Delete
[262] Fix | Delete
The callback is called with a single argument - the future object. If
[263] Fix | Delete
the future is already done when this is called, the callback is
[264] Fix | Delete
scheduled with call_soon.
[265] Fix | Delete
"""
[266] Fix | Delete
if self._state != _PENDING:
[267] Fix | Delete
self._loop.call_soon(fn, self)
[268] Fix | Delete
else:
[269] Fix | Delete
self._callbacks.append(fn)
[270] Fix | Delete
[271] Fix | Delete
# New method not in PEP 3148.
[272] Fix | Delete
[273] Fix | Delete
def remove_done_callback(self, fn):
[274] Fix | Delete
"""Remove all instances of a callback from the "call when done" list.
[275] Fix | Delete
[276] Fix | Delete
Returns the number of callbacks removed.
[277] Fix | Delete
"""
[278] Fix | Delete
filtered_callbacks = [f for f in self._callbacks if f != fn]
[279] Fix | Delete
removed_count = len(self._callbacks) - len(filtered_callbacks)
[280] Fix | Delete
if removed_count:
[281] Fix | Delete
self._callbacks[:] = filtered_callbacks
[282] Fix | Delete
return removed_count
[283] Fix | Delete
[284] Fix | Delete
# So-called internal methods (note: no set_running_or_notify_cancel()).
[285] Fix | Delete
[286] Fix | Delete
def set_result(self, result):
[287] Fix | Delete
"""Mark the future done and set its result.
[288] Fix | Delete
[289] Fix | Delete
If the future is already done when this method is called, raises
[290] Fix | Delete
InvalidStateError.
[291] Fix | Delete
"""
[292] Fix | Delete
if self._state != _PENDING:
[293] Fix | Delete
raise InvalidStateError('{}: {!r}'.format(self._state, self))
[294] Fix | Delete
self._result = result
[295] Fix | Delete
self._state = _FINISHED
[296] Fix | Delete
self._schedule_callbacks()
[297] Fix | Delete
[298] Fix | Delete
def set_exception(self, exception):
[299] Fix | Delete
"""Mark the future done and set an exception.
[300] Fix | Delete
[301] Fix | Delete
If the future is already done when this method is called, raises
[302] Fix | Delete
InvalidStateError.
[303] Fix | Delete
"""
[304] Fix | Delete
if self._state != _PENDING:
[305] Fix | Delete
raise InvalidStateError('{}: {!r}'.format(self._state, self))
[306] Fix | Delete
if isinstance(exception, type):
[307] Fix | Delete
exception = exception()
[308] Fix | Delete
if type(exception) is StopIteration:
[309] Fix | Delete
raise TypeError("StopIteration interacts badly with generators "
[310] Fix | Delete
"and cannot be raised into a Future")
[311] Fix | Delete
self._exception = exception
[312] Fix | Delete
self._state = _FINISHED
[313] Fix | Delete
self._schedule_callbacks()
[314] Fix | Delete
if compat.PY34:
[315] Fix | Delete
self._log_traceback = True
[316] Fix | Delete
else:
[317] Fix | Delete
self._tb_logger = _TracebackLogger(self, exception)
[318] Fix | Delete
# Arrange for the logger to be activated after all callbacks
[319] Fix | Delete
# have had a chance to call result() or exception().
[320] Fix | Delete
self._loop.call_soon(self._tb_logger.activate)
[321] Fix | Delete
[322] Fix | Delete
def __iter__(self):
[323] Fix | Delete
if not self.done():
[324] Fix | Delete
self._asyncio_future_blocking = True
[325] Fix | Delete
yield self # This tells Task to wait for completion.
[326] Fix | Delete
assert self.done(), "yield from wasn't used with future"
[327] Fix | Delete
return self.result() # May raise too.
[328] Fix | Delete
[329] Fix | Delete
if compat.PY35:
[330] Fix | Delete
__await__ = __iter__ # make compatible with 'await' expression
[331] Fix | Delete
[332] Fix | Delete
[333] Fix | Delete
# Needed for testing purposes.
[334] Fix | Delete
_PyFuture = Future
[335] Fix | Delete
[336] Fix | Delete
[337] Fix | Delete
def _set_result_unless_cancelled(fut, result):
[338] Fix | Delete
"""Helper setting the result only if the future was not cancelled."""
[339] Fix | Delete
if fut.cancelled():
[340] Fix | Delete
return
[341] Fix | Delete
fut.set_result(result)
[342] Fix | Delete
[343] Fix | Delete
[344] Fix | Delete
def _set_concurrent_future_state(concurrent, source):
[345] Fix | Delete
"""Copy state from a future to a concurrent.futures.Future."""
[346] Fix | Delete
assert source.done()
[347] Fix | Delete
if source.cancelled():
[348] Fix | Delete
concurrent.cancel()
[349] Fix | Delete
if not concurrent.set_running_or_notify_cancel():
[350] Fix | Delete
return
[351] Fix | Delete
exception = source.exception()
[352] Fix | Delete
if exception is not None:
[353] Fix | Delete
concurrent.set_exception(exception)
[354] Fix | Delete
else:
[355] Fix | Delete
result = source.result()
[356] Fix | Delete
concurrent.set_result(result)
[357] Fix | Delete
[358] Fix | Delete
[359] Fix | Delete
def _copy_future_state(source, dest):
[360] Fix | Delete
"""Internal helper to copy state from another Future.
[361] Fix | Delete
[362] Fix | Delete
The other Future may be a concurrent.futures.Future.
[363] Fix | Delete
"""
[364] Fix | Delete
assert source.done()
[365] Fix | Delete
if dest.cancelled():
[366] Fix | Delete
return
[367] Fix | Delete
assert not dest.done()
[368] Fix | Delete
if source.cancelled():
[369] Fix | Delete
dest.cancel()
[370] Fix | Delete
else:
[371] Fix | Delete
exception = source.exception()
[372] Fix | Delete
if exception is not None:
[373] Fix | Delete
dest.set_exception(exception)
[374] Fix | Delete
else:
[375] Fix | Delete
result = source.result()
[376] Fix | Delete
dest.set_result(result)
[377] Fix | Delete
[378] Fix | Delete
[379] Fix | Delete
def _chain_future(source, destination):
[380] Fix | Delete
"""Chain two futures so that when one completes, so does the other.
[381] Fix | Delete
[382] Fix | Delete
The result (or exception) of source will be copied to destination.
[383] Fix | Delete
If destination is cancelled, source gets cancelled too.
[384] Fix | Delete
Compatible with both asyncio.Future and concurrent.futures.Future.
[385] Fix | Delete
"""
[386] Fix | Delete
if not isfuture(source) and not isinstance(source,
[387] Fix | Delete
concurrent.futures.Future):
[388] Fix | Delete
raise TypeError('A future is required for source argument')
[389] Fix | Delete
if not isfuture(destination) and not isinstance(destination,
[390] Fix | Delete
concurrent.futures.Future):
[391] Fix | Delete
raise TypeError('A future is required for destination argument')
[392] Fix | Delete
source_loop = source._loop if isfuture(source) else None
[393] Fix | Delete
dest_loop = destination._loop if isfuture(destination) else None
[394] Fix | Delete
[395] Fix | Delete
def _set_state(future, other):
[396] Fix | Delete
if isfuture(future):
[397] Fix | Delete
_copy_future_state(other, future)
[398] Fix | Delete
else:
[399] Fix | Delete
_set_concurrent_future_state(future, other)
[400] Fix | Delete
[401] Fix | Delete
def _call_check_cancel(destination):
[402] Fix | Delete
if destination.cancelled():
[403] Fix | Delete
if source_loop is None or source_loop is dest_loop:
[404] Fix | Delete
source.cancel()
[405] Fix | Delete
else:
[406] Fix | Delete
source_loop.call_soon_threadsafe(source.cancel)
[407] Fix | Delete
[408] Fix | Delete
def _call_set_state(source):
[409] Fix | Delete
if (destination.cancelled() and
[410] Fix | Delete
dest_loop is not None and dest_loop.is_closed()):
[411] Fix | Delete
return
[412] Fix | Delete
if dest_loop is None or dest_loop is source_loop:
[413] Fix | Delete
_set_state(destination, source)
[414] Fix | Delete
else:
[415] Fix | Delete
dest_loop.call_soon_threadsafe(_set_state, destination, source)
[416] Fix | Delete
[417] Fix | Delete
destination.add_done_callback(_call_check_cancel)
[418] Fix | Delete
source.add_done_callback(_call_set_state)
[419] Fix | Delete
[420] Fix | Delete
[421] Fix | Delete
def wrap_future(future, *, loop=None):
[422] Fix | Delete
"""Wrap concurrent.futures.Future object."""
[423] Fix | Delete
if isfuture(future):
[424] Fix | Delete
return future
[425] Fix | Delete
assert isinstance(future, concurrent.futures.Future), \
[426] Fix | Delete
'concurrent.futures.Future is expected, got {!r}'.format(future)
[427] Fix | Delete
if loop is None:
[428] Fix | Delete
loop = events.get_event_loop()
[429] Fix | Delete
new_future = loop.create_future()
[430] Fix | Delete
_chain_future(future, new_future)
[431] Fix | Delete
return new_future
[432] Fix | Delete
[433] Fix | Delete
[434] Fix | Delete
try:
[435] Fix | Delete
import _asyncio
[436] Fix | Delete
except ImportError:
[437] Fix | Delete
pass
[438] Fix | Delete
else:
[439] Fix | Delete
# _CFuture is needed for tests.
[440] Fix | Delete
Future = _CFuture = _asyncio.Future
[441] Fix | Delete
[442] Fix | Delete
It is recommended that you Edit text format, this type of Fix handles quite a lot in one request
Function