blob: c28de95a46b25293b3cb7f6a5035de248665e9b1 [file] [log] [blame]
Victor Stinnerf951d282014-06-29 00:46:45 +02001__all__ = ['coroutine',
2 'iscoroutinefunction', 'iscoroutine']
3
4import functools
5import inspect
Victor Stinnerb75380f2014-06-30 14:39:11 +02006import opcode
Victor Stinnerf951d282014-06-29 00:46:45 +02007import os
8import sys
9import traceback
Victor Stinnerb75380f2014-06-30 14:39:11 +020010import types
Victor Stinnerf951d282014-06-29 00:46:45 +020011
12from . import events
13from . import futures
14from .log import logger
15
Victor Stinnerb75380f2014-06-30 14:39:11 +020016
17# Opcode of "yield from" instruction
18_YIELD_FROM = opcode.opmap['YIELD_FROM']
19
Victor Stinnerf951d282014-06-29 00:46:45 +020020# If you set _DEBUG to true, @coroutine will wrap the resulting
21# generator objects in a CoroWrapper instance (defined below). That
22# instance will log a message when the generator is never iterated
23# over, which may happen when you forget to use "yield from" with a
24# coroutine call. Note that the value of the _DEBUG flag is taken
25# when the decorator is used, so to be of any use it must be set
26# before you define your coroutines. A downside of using this feature
27# is that tracebacks show entries for the CoroWrapper.__next__ method
28# when _DEBUG is true.
29_DEBUG = (not sys.flags.ignore_environment
30 and bool(os.environ.get('PYTHONASYNCIODEBUG')))
31
Victor Stinnerb75380f2014-06-30 14:39:11 +020032
33# Check for CPython issue #21209
34def has_yield_from_bug():
35 class MyGen:
36 def __init__(self):
37 self.send_args = None
38 def __iter__(self):
39 return self
40 def __next__(self):
41 return 42
42 def send(self, *what):
43 self.send_args = what
44 return None
45 def yield_from_gen(gen):
46 yield from gen
47 value = (1, 2, 3)
48 gen = MyGen()
49 coro = yield_from_gen(gen)
50 next(coro)
51 coro.send(value)
52 return gen.send_args != (value,)
53_YIELD_FROM_BUG = has_yield_from_bug()
54del has_yield_from_bug
55
56
Victor Stinnerf951d282014-06-29 00:46:45 +020057class CoroWrapper:
Victor Stinnerc39ba7d2014-07-11 00:21:27 +020058 # Wrapper for coroutine object in _DEBUG mode.
Victor Stinnerf951d282014-06-29 00:46:45 +020059
60 def __init__(self, gen, func):
61 assert inspect.isgenerator(gen), gen
62 self.gen = gen
63 self.func = func
64 self._source_traceback = traceback.extract_stack(sys._getframe(1))
Victor Stinnera9acbe82014-07-05 15:29:41 +020065 # __name__, __qualname__, __doc__ attributes are set by the coroutine()
66 # decorator
67
68 def __repr__(self):
Victor Stinnerc39ba7d2014-07-11 00:21:27 +020069 coro_repr = _format_coroutine(self)
70 if self._source_traceback:
71 frame = self._source_traceback[-1]
72 coro_repr += ', created at %s:%s' % (frame[0], frame[1])
73 return '<%s %s>' % (self.__class__.__name__, coro_repr)
Victor Stinnerf951d282014-06-29 00:46:45 +020074
75 def __iter__(self):
76 return self
77
78 def __next__(self):
79 return next(self.gen)
80
Victor Stinnerb75380f2014-06-30 14:39:11 +020081 if _YIELD_FROM_BUG:
82 # For for CPython issue #21209: using "yield from" and a custom
83 # generator, generator.send(tuple) unpacks the tuple instead of passing
84 # the tuple unchanged. Check if the caller is a generator using "yield
85 # from" to decide if the parameter should be unpacked or not.
86 def send(self, *value):
87 frame = sys._getframe()
88 caller = frame.f_back
89 assert caller.f_lasti >= 0
90 if caller.f_code.co_code[caller.f_lasti] != _YIELD_FROM:
91 value = value[0]
92 return self.gen.send(value)
93 else:
94 def send(self, value):
95 return self.gen.send(value)
Victor Stinnerf951d282014-06-29 00:46:45 +020096
97 def throw(self, exc):
98 return self.gen.throw(exc)
99
100 def close(self):
101 return self.gen.close()
102
103 @property
104 def gi_frame(self):
105 return self.gen.gi_frame
106
107 @property
108 def gi_running(self):
109 return self.gen.gi_running
110
111 @property
112 def gi_code(self):
113 return self.gen.gi_code
114
115 def __del__(self):
116 # Be careful accessing self.gen.frame -- self.gen might not exist.
117 gen = getattr(self, 'gen', None)
118 frame = getattr(gen, 'gi_frame', None)
119 if frame is not None and frame.f_lasti == -1:
Victor Stinner737c34f2014-07-11 01:04:16 +0200120 msg = '%r was never yielded from' % self
Victor Stinner2dba23a2014-07-03 00:59:00 +0200121 tb = getattr(self, '_source_traceback', ())
122 if tb:
123 tb = ''.join(traceback.format_list(tb))
124 msg += ('\nCoroutine object created at '
125 '(most recent call last):\n')
126 msg += tb.rstrip()
127 logger.error(msg)
Victor Stinnerf951d282014-06-29 00:46:45 +0200128
129
130def coroutine(func):
131 """Decorator to mark coroutines.
132
133 If the coroutine is not yielded from before it is destroyed,
134 an error message is logged.
135 """
136 if inspect.isgeneratorfunction(func):
137 coro = func
138 else:
139 @functools.wraps(func)
140 def coro(*args, **kw):
141 res = func(*args, **kw)
142 if isinstance(res, futures.Future) or inspect.isgenerator(res):
143 res = yield from res
144 return res
145
146 if not _DEBUG:
147 wrapper = coro
148 else:
149 @functools.wraps(func)
150 def wrapper(*args, **kwds):
151 w = CoroWrapper(coro(*args, **kwds), func)
152 if w._source_traceback:
153 del w._source_traceback[-1]
154 w.__name__ = func.__name__
Victor Stinner737c34f2014-07-11 01:04:16 +0200155 if hasattr(func, '__qualname__'):
Victor Stinnerf951d282014-06-29 00:46:45 +0200156 w.__qualname__ = func.__qualname__
157 w.__doc__ = func.__doc__
158 return w
159
160 wrapper._is_coroutine = True # For iscoroutinefunction().
161 return wrapper
162
163
164def iscoroutinefunction(func):
165 """Return True if func is a decorated coroutine function."""
166 return getattr(func, '_is_coroutine', False)
167
168
Victor Stinner1a870c92014-07-07 17:26:54 +0200169_COROUTINE_TYPES = (types.GeneratorType, CoroWrapper)
Victor Stinnerb75380f2014-06-30 14:39:11 +0200170
Victor Stinnerf951d282014-06-29 00:46:45 +0200171def iscoroutine(obj):
172 """Return True if obj is a coroutine object."""
Victor Stinner1a870c92014-07-07 17:26:54 +0200173 return isinstance(obj, _COROUTINE_TYPES)
Victor Stinnerf951d282014-06-29 00:46:45 +0200174
175
176def _format_coroutine(coro):
177 assert iscoroutine(coro)
Victor Stinner737c34f2014-07-11 01:04:16 +0200178 coro_name = getattr(coro, '__qualname__', coro.__name__)
Victor Stinnerf951d282014-06-29 00:46:45 +0200179
180 filename = coro.gi_code.co_filename
Victor Stinnerc39ba7d2014-07-11 00:21:27 +0200181 if (isinstance(coro, CoroWrapper)
182 and not inspect.isgeneratorfunction(coro.func)):
183 filename, lineno = events._get_function_source(coro.func)
184 if coro.gi_frame is None:
185 coro_repr = '%s() done, defined at %s:%s' % (coro_name, filename, lineno)
186 else:
187 coro_repr = '%s() running, defined at %s:%s' % (coro_name, filename, lineno)
188 elif coro.gi_frame is not None:
Victor Stinnerf951d282014-06-29 00:46:45 +0200189 lineno = coro.gi_frame.f_lineno
Victor Stinnerc39ba7d2014-07-11 00:21:27 +0200190 coro_repr = '%s() running at %s:%s' % (coro_name, filename, lineno)
Victor Stinnerf951d282014-06-29 00:46:45 +0200191 else:
192 lineno = coro.gi_code.co_firstlineno
Victor Stinnerc39ba7d2014-07-11 00:21:27 +0200193 coro_repr = '%s() done, defined at %s:%s' % (coro_name, filename, lineno)
194
195 return coro_repr