PageRenderTime 44ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/likeProjects_examples/qtile-0.10.1/trollius-2.0-py2.7.egg/trollius/coroutines.py

https://bitbucket.org/hackersgame/lavinder-prototype
Python | 440 lines | 344 code | 35 blank | 61 comment | 62 complexity | 90d259373e3cb26db16ed4e62f8aedce MD5 | raw file
Possible License(s): GPL-2.0
  1. __all__ = ['coroutine',
  2. 'iscoroutinefunction', 'iscoroutine',
  3. 'From', 'Return']
  4. import functools
  5. import inspect
  6. import opcode
  7. import os
  8. import sys
  9. import traceback
  10. import types
  11. from . import compat
  12. from . import events
  13. from . import futures
  14. from .log import logger
  15. # Opcode of "yield from" instruction
  16. _YIELD_FROM = opcode.opmap.get('YIELD_FROM', None)
  17. # If you set _DEBUG to true, @coroutine will wrap the resulting
  18. # generator objects in a CoroWrapper instance (defined below). That
  19. # instance will log a message when the generator is never iterated
  20. # over, which may happen when you forget to use "yield from" with a
  21. # coroutine call. Note that the value of the _DEBUG flag is taken
  22. # when the decorator is used, so to be of any use it must be set
  23. # before you define your coroutines. A downside of using this feature
  24. # is that tracebacks show entries for the CoroWrapper.__next__ method
  25. # when _DEBUG is true.
  26. _DEBUG = bool(os.environ.get('TROLLIUSDEBUG'))
  27. try:
  28. _types_coroutine = types.coroutine
  29. except AttributeError:
  30. _types_coroutine = None
  31. try:
  32. _inspect_iscoroutinefunction = inspect.iscoroutinefunction
  33. except AttributeError:
  34. _inspect_iscoroutinefunction = lambda func: False
  35. try:
  36. from collections.abc import Coroutine as _CoroutineABC, \
  37. Awaitable as _AwaitableABC
  38. except ImportError:
  39. _CoroutineABC = _AwaitableABC = None
  40. if _YIELD_FROM is not None:
  41. # Check for CPython issue #21209
  42. exec('''if 1:
  43. def has_yield_from_bug():
  44. class MyGen:
  45. def __init__(self):
  46. self.send_args = None
  47. def __iter__(self):
  48. return self
  49. def __next__(self):
  50. return 42
  51. def send(self, *what):
  52. self.send_args = what
  53. return None
  54. def yield_from_gen(gen):
  55. yield from gen
  56. value = (1, 2, 3)
  57. gen = MyGen()
  58. coro = yield_from_gen(gen)
  59. next(coro)
  60. coro.send(value)
  61. return gen.send_args != (value,)
  62. ''')
  63. _YIELD_FROM_BUG = has_yield_from_bug()
  64. del has_yield_from_bug
  65. else:
  66. _YIELD_FROM_BUG = False
  67. if compat.PY33:
  68. # Don't use the Return class on Python 3.3 and later to support asyncio
  69. # coroutines (to avoid the warning emited in Return destructor).
  70. #
  71. # The problem is that Return inherits from StopIteration. "yield from
  72. # trollius_coroutine". Task._step() does not receive the Return exception,
  73. # because "yield from" handles it internally. So it's not possible to set
  74. # the raised attribute to True to avoid the warning in Return destructor.
  75. def Return(*args):
  76. if not args:
  77. value = None
  78. elif len(args) == 1:
  79. value = args[0]
  80. else:
  81. value = args
  82. return StopIteration(value)
  83. else:
  84. class Return(StopIteration):
  85. def __init__(self, *args):
  86. StopIteration.__init__(self)
  87. if not args:
  88. self.value = None
  89. elif len(args) == 1:
  90. self.value = args[0]
  91. else:
  92. self.value = args
  93. self.raised = False
  94. if _DEBUG:
  95. frame = sys._getframe(1)
  96. self._source_traceback = traceback.extract_stack(frame)
  97. # explicitly clear the reference to avoid reference cycles
  98. frame = None
  99. else:
  100. self._source_traceback = None
  101. def __del__(self):
  102. if self.raised:
  103. return
  104. fmt = 'Return(%r) used without raise'
  105. if self._source_traceback:
  106. fmt += '\nReturn created at (most recent call last):\n'
  107. tb = ''.join(traceback.format_list(self._source_traceback))
  108. fmt += tb.rstrip()
  109. logger.error(fmt, self.value)
  110. def debug_wrapper(gen):
  111. # This function is called from 'sys.set_coroutine_wrapper'.
  112. # We only wrap here coroutines defined via 'async def' syntax.
  113. # Generator-based coroutines are wrapped in @coroutine
  114. # decorator.
  115. return CoroWrapper(gen, None)
  116. def _coroutine_at_yield_from(coro):
  117. """Test if the last instruction of a coroutine is "yield from".
  118. Return False if the coroutine completed.
  119. """
  120. frame = coro.gi_frame
  121. if frame is None:
  122. return False
  123. code = coro.gi_code
  124. assert frame.f_lasti >= 0
  125. offset = frame.f_lasti + 1
  126. instr = code.co_code[offset]
  127. return (instr == _YIELD_FROM)
  128. class CoroWrapper:
  129. # Wrapper for coroutine object in _DEBUG mode.
  130. def __init__(self, gen, func=None):
  131. assert inspect.isgenerator(gen) or inspect.iscoroutine(gen), gen
  132. self.gen = gen
  133. self.func = func # Used to unwrap @coroutine decorator
  134. self._source_traceback = traceback.extract_stack(sys._getframe(1))
  135. self.__name__ = getattr(gen, '__name__', None)
  136. self.__qualname__ = getattr(gen, '__qualname__', None)
  137. def __repr__(self):
  138. coro_repr = _format_coroutine(self)
  139. if self._source_traceback:
  140. frame = self._source_traceback[-1]
  141. coro_repr += ', created at %s:%s' % (frame[0], frame[1])
  142. return '<%s %s>' % (self.__class__.__name__, coro_repr)
  143. def __iter__(self):
  144. return self
  145. def __next__(self):
  146. return next(self.gen)
  147. next = __next__
  148. if _YIELD_FROM_BUG:
  149. # For for CPython issue #21209: using "yield from" and a custom
  150. # generator, generator.send(tuple) unpacks the tuple instead of passing
  151. # the tuple unchanged. Check if the caller is a generator using "yield
  152. # from" to decide if the parameter should be unpacked or not.
  153. def send(self, *value):
  154. frame = sys._getframe()
  155. caller = frame.f_back
  156. assert caller.f_lasti >= 0
  157. if caller.f_code.co_code[caller.f_lasti] != _YIELD_FROM:
  158. value = value[0]
  159. return self.gen.send(value)
  160. else:
  161. def send(self, value):
  162. return self.gen.send(value)
  163. def throw(self, exc):
  164. return self.gen.throw(exc)
  165. def close(self):
  166. return self.gen.close()
  167. @property
  168. def gi_frame(self):
  169. return self.gen.gi_frame
  170. @property
  171. def gi_running(self):
  172. return self.gen.gi_running
  173. @property
  174. def gi_code(self):
  175. return self.gen.gi_code
  176. if compat.PY35:
  177. __await__ = __iter__ # make compatible with 'await' expression
  178. @property
  179. def gi_yieldfrom(self):
  180. return self.gen.gi_yieldfrom
  181. @property
  182. def cr_await(self):
  183. return self.gen.cr_await
  184. @property
  185. def cr_running(self):
  186. return self.gen.cr_running
  187. @property
  188. def cr_code(self):
  189. return self.gen.cr_code
  190. @property
  191. def cr_frame(self):
  192. return self.gen.cr_frame
  193. def __del__(self):
  194. # Be careful accessing self.gen.frame -- self.gen might not exist.
  195. gen = getattr(self, 'gen', None)
  196. frame = getattr(gen, 'gi_frame', None)
  197. if frame is None:
  198. frame = getattr(gen, 'cr_frame', None)
  199. if frame is not None and frame.f_lasti == -1:
  200. msg = '%r was never yielded from' % self
  201. tb = getattr(self, '_source_traceback', ())
  202. if tb:
  203. tb = ''.join(traceback.format_list(tb))
  204. msg += ('\nCoroutine object created at '
  205. '(most recent call last):\n')
  206. msg += tb.rstrip()
  207. logger.error(msg)
  208. if not compat.PY34:
  209. # Backport functools.update_wrapper() from Python 3.4:
  210. # - Python 2.7 fails if assigned attributes don't exist
  211. # - Python 2.7 and 3.1 don't set the __wrapped__ attribute
  212. # - Python 3.2 and 3.3 set __wrapped__ before updating __dict__
  213. def _update_wrapper(wrapper,
  214. wrapped,
  215. assigned = functools.WRAPPER_ASSIGNMENTS,
  216. updated = functools.WRAPPER_UPDATES):
  217. """Update a wrapper function to look like the wrapped function
  218. wrapper is the function to be updated
  219. wrapped is the original function
  220. assigned is a tuple naming the attributes assigned directly
  221. from the wrapped function to the wrapper function (defaults to
  222. functools.WRAPPER_ASSIGNMENTS)
  223. updated is a tuple naming the attributes of the wrapper that
  224. are updated with the corresponding attribute from the wrapped
  225. function (defaults to functools.WRAPPER_UPDATES)
  226. """
  227. for attr in assigned:
  228. try:
  229. value = getattr(wrapped, attr)
  230. except AttributeError:
  231. pass
  232. else:
  233. setattr(wrapper, attr, value)
  234. for attr in updated:
  235. getattr(wrapper, attr).update(getattr(wrapped, attr, {}))
  236. # Issue #17482: set __wrapped__ last so we don't inadvertently copy it
  237. # from the wrapped function when updating __dict__
  238. wrapper.__wrapped__ = wrapped
  239. # Return the wrapper so this can be used as a decorator via partial()
  240. return wrapper
  241. def _wraps(wrapped,
  242. assigned = functools.WRAPPER_ASSIGNMENTS,
  243. updated = functools.WRAPPER_UPDATES):
  244. """Decorator factory to apply update_wrapper() to a wrapper function
  245. Returns a decorator that invokes update_wrapper() with the decorated
  246. function as the wrapper argument and the arguments to wraps() as the
  247. remaining arguments. Default arguments are as for update_wrapper().
  248. This is a convenience function to simplify applying partial() to
  249. update_wrapper().
  250. """
  251. return functools.partial(_update_wrapper, wrapped=wrapped,
  252. assigned=assigned, updated=updated)
  253. else:
  254. _wraps = functools.wraps
  255. def coroutine(func):
  256. """Decorator to mark coroutines.
  257. If the coroutine is not yielded from before it is destroyed,
  258. an error message is logged.
  259. """
  260. if _inspect_iscoroutinefunction(func):
  261. # In Python 3.5 that's all we need to do for coroutines
  262. # defiend with "async def".
  263. # Wrapping in CoroWrapper will happen via
  264. # 'sys.set_coroutine_wrapper' function.
  265. return func
  266. if inspect.isgeneratorfunction(func):
  267. coro = func
  268. else:
  269. @_wraps(func)
  270. def coro(*args, **kw):
  271. res = func(*args, **kw)
  272. if (isinstance(res, futures._FUTURE_CLASSES)
  273. or inspect.isgenerator(res)):
  274. res = yield From(res)
  275. elif _AwaitableABC is not None:
  276. # If 'func' returns an Awaitable (new in 3.5) we
  277. # want to run it.
  278. try:
  279. await_meth = res.__await__
  280. except AttributeError:
  281. pass
  282. else:
  283. if isinstance(res, _AwaitableABC):
  284. res = yield From(await_meth())
  285. raise Return(res)
  286. if not _DEBUG:
  287. if _types_coroutine is None:
  288. wrapper = coro
  289. else:
  290. wrapper = _types_coroutine(coro)
  291. else:
  292. @_wraps(func)
  293. def wrapper(*args, **kwds):
  294. w = CoroWrapper(coro(*args, **kwds), func=func)
  295. if w._source_traceback:
  296. del w._source_traceback[-1]
  297. # Python < 3.5 does not implement __qualname__
  298. # on generator objects, so we set it manually.
  299. # We use getattr as some callables (such as
  300. # functools.partial may lack __qualname__).
  301. w.__name__ = getattr(func, '__name__', None)
  302. w.__qualname__ = getattr(func, '__qualname__', None)
  303. return w
  304. wrapper._is_coroutine = True # For iscoroutinefunction().
  305. return wrapper
  306. def iscoroutinefunction(func):
  307. """Return True if func is a decorated coroutine function."""
  308. return (getattr(func, '_is_coroutine', False) or
  309. _inspect_iscoroutinefunction(func))
  310. _COROUTINE_TYPES = (types.GeneratorType, CoroWrapper)
  311. if _CoroutineABC is not None:
  312. _COROUTINE_TYPES += (_CoroutineABC,)
  313. if events.asyncio is not None:
  314. # Accept also asyncio CoroWrapper for interoperability
  315. if hasattr(events.asyncio, 'coroutines'):
  316. _COROUTINE_TYPES += (events.asyncio.coroutines.CoroWrapper,)
  317. else:
  318. # old asyncio/Python versions
  319. _COROUTINE_TYPES += (events.asyncio.tasks.CoroWrapper,)
  320. def iscoroutine(obj):
  321. """Return True if obj is a coroutine object."""
  322. return isinstance(obj, _COROUTINE_TYPES)
  323. def _format_coroutine(coro):
  324. assert iscoroutine(coro)
  325. coro_name = None
  326. if isinstance(coro, CoroWrapper):
  327. func = coro.func
  328. coro_name = coro.__qualname__
  329. if coro_name is not None:
  330. coro_name = '{0}()'.format(coro_name)
  331. else:
  332. func = coro
  333. if coro_name is None:
  334. coro_name = events._format_callback(func, ())
  335. try:
  336. coro_code = coro.gi_code
  337. except AttributeError:
  338. coro_code = coro.cr_code
  339. try:
  340. coro_frame = coro.gi_frame
  341. except AttributeError:
  342. coro_frame = coro.cr_frame
  343. filename = coro_code.co_filename
  344. if (isinstance(coro, CoroWrapper)
  345. and not inspect.isgeneratorfunction(coro.func)
  346. and coro.func is not None):
  347. filename, lineno = events._get_function_source(coro.func)
  348. if coro_frame is None:
  349. coro_repr = ('%s done, defined at %s:%s'
  350. % (coro_name, filename, lineno))
  351. else:
  352. coro_repr = ('%s running, defined at %s:%s'
  353. % (coro_name, filename, lineno))
  354. elif coro_frame is not None:
  355. lineno = coro_frame.f_lineno
  356. coro_repr = ('%s running at %s:%s'
  357. % (coro_name, filename, lineno))
  358. else:
  359. lineno = coro_code.co_firstlineno
  360. coro_repr = ('%s done, defined at %s:%s'
  361. % (coro_name, filename, lineno))
  362. return coro_repr
  363. class FromWrapper(object):
  364. __slots__ = ('obj',)
  365. def __init__(self, obj):
  366. if isinstance(obj, FromWrapper):
  367. obj = obj.obj
  368. assert not isinstance(obj, FromWrapper)
  369. self.obj = obj
  370. def From(obj):
  371. if not _DEBUG:
  372. return obj
  373. else:
  374. return FromWrapper(obj)