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