def synchronous(func):
"""Decorator to ensure that `func` never runs in the reactor thread.
If the wrapped function is called from the reactor thread, this will
raise a :class:`AssertionError`, implying that this is a programming
error. Calls from outside the reactor will proceed unaffected.
There is an asymmetry with the `asynchronous` decorator. The reason
is that it is essential to be aware when `deferToThread()` is being
used, so that in-reactor code knows to synchronise with it, to add a
callback to the :class:`Deferred` that it returns, for example. The
expectation with `asynchronous` is that the return value is always
important, and will be appropriate to the environment in which it is
utilised.
It is possible to programmatically determine if a function has been thusly
decorated by checking if `ISynchronous` is provided::
if ISynchronous.providedBy(a_function):
... # a_function has been decorated with @synchronous
This also serves a secondary documentation purpose; functions decorated
with this are readily identifiable as synchronous, or blocking.
:raises AssertionError: When called inside the reactor thread.
"""
try:
# A function or method; see PEP 3155.
func_name = func.__qualname__
except AttributeError:
# An instance with a __call__ method.
func_name = type(func).__qualname__
@wraps(func)
def wrapper(*args, **kwargs):
# isInIOThread() can return True if the reactor has previously been
# started but has now stopped, so don't test isInIOThread() until
# we've also checked if the reactor is running.
if reactor.running and isInIOThread():
raise AssertionError(
"Function %s(...) must not be called in the "
"reactor thread." % func.__name__)
else:
result = func(*args, **kwargs)
if isinstance(result, Deferred):
args_reprs = chain(
map(repr, args), starmap(
"{}={!r}".format, kwargs.items()))
raise TypeError(
"Synchronous call returned a Deferred: %s(%s)"
% (func_name, ", ".join(args_reprs)))
else:
return result
# This makes it possible to reliably determine programmatically if a
# function has been decorated with @synchronous.
interface.directlyProvides(wrapper, ISynchronous)
return wrapper
评论列表
文章目录