Esempio n. 1
0
    def test_async_def(self):
        # Test that types.coroutine passes 'async def' coroutines
        # without modification

        async def foo():
            pass

        foo_code = foo.__code__
        foo_flags = foo.__code__.co_flags
        decorated_foo = types.coroutine(foo)
        self.assertIs(foo, decorated_foo)
        self.assertEqual(foo.__code__.co_flags, foo_flags)
        self.assertIs(decorated_foo.__code__, foo_code)

        foo_coro = foo()

        def bar():
            return foo_coro

        for _ in range(2):
            bar = types.coroutine(bar)
            coro = bar()
            self.assertIs(foo_coro, coro)
            self.assertEqual(coro.cr_code.co_flags, foo_flags)
            coro.close()
Esempio n. 2
0
def test_convert_generator_to_coroutine():
    def gen():
        yield 100

    assert not inspect.isawaitable(gen())

    coroutine(gen)
    assert inspect.isawaitable(gen())
Esempio n. 3
0
    def test_wrong_args(self):
        class Foo:
            def __call__(self):
                pass
        def bar(): pass

        samples = [Foo, Foo(), bar, None, int, 1]
        for sample in samples:
            with self.assertRaisesRegex(TypeError, 'expects a generator'):
                types.coroutine(sample)
Esempio n. 4
0
    def test_wrong_args(self):
        class Foo:
            def __call__(self):
                pass
        def bar(): pass

        samples = [None, 1, object()]
        for sample in samples:
            with self.assertRaisesRegex(TypeError,
                                        'types.coroutine.*expects a callable'):
                types.coroutine(sample)
Esempio n. 5
0
    def test_wrong_args(self):
        class Foo:
            def __call__(self):
                pass

        def bar():
            pass

        samples = [None, 1, object()]
        for sample in samples:
            with self.assertRaisesRegex(TypeError,
                                        'types.coroutine.*expects a callable'):
                types.coroutine(sample)
Esempio n. 6
0
    def test_genfunc(self):
        def gen(): yield
        self.assertIs(types.coroutine(gen), gen)
        self.assertIs(types.coroutine(types.coroutine(gen)), gen)

        self.assertTrue(gen.__code__.co_flags & inspect.CO_ITERABLE_COROUTINE)
        self.assertFalse(gen.__code__.co_flags & inspect.CO_COROUTINE)

        g = gen()
        self.assertTrue(g.gi_code.co_flags & inspect.CO_ITERABLE_COROUTINE)
        self.assertFalse(g.gi_code.co_flags & inspect.CO_COROUTINE)

        self.assertIs(types.coroutine(gen), gen)
Esempio n. 7
0
    def test_genfunc(self):
        def gen():
            yield

        self.assertIs(types.coroutine(gen), gen)
        self.assertIs(types.coroutine(types.coroutine(gen)), gen)

        self.assertTrue(gen.__code__.co_flags & inspect.CO_ITERABLE_COROUTINE)
        self.assertFalse(gen.__code__.co_flags & inspect.CO_COROUTINE)

        g = gen()
        self.assertTrue(g.gi_code.co_flags & inspect.CO_ITERABLE_COROUTINE)
        self.assertFalse(g.gi_code.co_flags & inspect.CO_COROUTINE)

        self.assertIs(types.coroutine(gen), gen)
Esempio n. 8
0
 async def aiorun():
     if not async_target:
         core = types.coroutine(threading.Thread(target=target, args=args))
         await core.start()
     else:
         core = threading.Thread(target=target, args=args)
         core.start()
Esempio n. 9
0
    def test_gen(self):
        def gen_func():
            yield 1
            return (yield 2)
        gen = gen_func()
        @types.coroutine
        def foo(): return gen
        wrapper = foo()
        self.assertIsInstance(wrapper, types._GeneratorWrapper)
        self.assertIs(wrapper.__await__(), gen)

        for name in ('__name__', 'gi_code',
                     'gi_running', 'gi_frame'):
            self.assertIs(getattr(foo(), name),
                          getattr(gen, name))
        self.assertIs(foo().cr_code, gen.gi_code)

        self.assertEqual(next(wrapper), 1)
        self.assertEqual(wrapper.send(None), 2)
        with self.assertRaisesRegexp(StopIteration, 'spam'):
            wrapper.send('spam')

        gen = gen_func()
        wrapper = foo()
        wrapper.send(None)
        with self.assertRaisesRegexp(Exception, 'ham'):
            wrapper.throw(Exception, Exception('ham'))

        # decorate foo second time
        foo = types.coroutine(foo)
        self.assertIs(foo().__await__(), gen)
Esempio n. 10
0
    def test_gen(self):
        def gen_func():
            yield 1
            return (yield 2)

        gen = gen_func()

        @types.coroutine
        def foo():
            return gen

        wrapper = foo()
        self.assertIsInstance(wrapper, types._GeneratorWrapper)
        self.assertIs(wrapper.__await__(), gen)

        for name in ('__name__', 'gi_code', 'gi_running', 'gi_frame'):
            self.assertIs(getattr(foo(), name), getattr(gen, name))
        self.assertIs(foo().cr_code, gen.gi_code)

        self.assertEqual(next(wrapper), 1)
        self.assertEqual(wrapper.send(None), 2)
        with self.assertRaisesRegexp(StopIteration, 'spam'):
            wrapper.send('spam')

        gen = gen_func()
        wrapper = foo()
        wrapper.send(None)
        with self.assertRaisesRegexp(Exception, 'ham'):
            wrapper.throw(Exception, Exception('ham'))

        # decorate foo second time
        foo = types.coroutine(foo)
        self.assertIs(foo().__await__(), gen)
Esempio n. 11
0
 def __init__(
     self,
     coro: Callable[..., Awaitable[None]],
     args: Tuple[Any, ...],
     kwargs: Dict[str, Any],
 ) -> None:
     self.coro = types.coroutine(coro)
     self.args = args
     self.kwargs = kwargs
def coroutine(func):
    """Decorator to mark coroutines.

    If the coroutine is not yielded from before it is destroyed,
    an error message is logged.
    """
    warnings.warn(
        '"@coroutine" decorator is deprecated since Python 3.8, use "async def" instead',
        DeprecationWarning,
        stacklevel=2)
    if inspect.iscoroutinefunction(func):
        # In Python 3.5 that's all we need to do for coroutines
        # defined with "async def".
        return func

    if inspect.isgeneratorfunction(func):
        coro = func
    else:

        @functools.wraps(func)
        def coro(*args, **kw):
            res = func(*args, **kw)
            if (base_futures.isfuture(res) or inspect.isgenerator(res)
                    or isinstance(res, CoroWrapper)):
                res = yield from res
            else:
                # If 'res' is an awaitable, run it.
                try:
                    await_meth = res.__await__
                except AttributeError:
                    pass
                else:
                    if isinstance(res, collections.abc.Awaitable):
                        res = yield from await_meth()
            return res

    coro = types.coroutine(coro)
    if not _DEBUG:
        wrapper = coro
    else:

        @functools.wraps(func)
        def wrapper(*args, **kwds):
            w = CoroWrapper(coro(*args, **kwds), func=func)
            if w._source_traceback:
                del w._source_traceback[-1]
            # Python < 3.5 does not implement __qualname__
            # on generator objects, so we set it manually.
            # We use getattr as some callables (such as
            # functools.partial may lack __qualname__).
            w.__name__ = getattr(func, '__name__', None)
            w.__qualname__ = getattr(func, '__qualname__', None)
            return w

    wrapper._is_coroutine = _is_coroutine  # For iscoroutinefunction().
    return wrapper
Esempio n. 13
0
def add_route(app, fn):
    method = getattr(fn, '__method__', None)   # 获取method
    path = getattr(fn, '__route__', None)       # 获取路径
    if path is None or method is None:
        raise ValueError('@get or @post not defined in %s.' % str(fn))
    if not asyncio.iscoroutinefunction(fn) and not inspect.isgeneratorfunction(fn):  # 如果fn视图函数不是协程
        # fn = asyncio.coroutine(fn)  #python3.8弃用?
        fn = types.coroutine(fn)
    logging.info('add route %s %s => %s(%s)' % (method, path, fn.__name__, ', '.join(inspect.signature(fn).parameters.keys())))
    app.router.add_route(method, path, RequestHandler(app, fn))
Esempio n. 14
0
async def setup_redis(loop, stop_app):
    rd = redis.StrictRedis(decode_responses=True)
    ps = rd.pubsub(ignore_subscribe_messages=True)
    ps.subscribe('video:new')
    listen = types.coroutine(ps.listen)
    while not stop_app.is_set():
        msg = ps.get_message()
        if msg:
            new_video_handler(msg)
        await asyncio.sleep(0.01)
Esempio n. 15
0
File: _traps.py Progetto: zed/trio
def asyncfunction(fn):
    # Set the coroutine flag
    fn = types.coroutine(fn)
    # Then wrap it in an 'async def', to enable the "coroutine was not
    # awaited" warning
    @wraps(fn)
    async def wrapper(*args, **kwargs):
        return await fn(*args, **kwargs)

    return wrapper
Esempio n. 16
0
def coroutine(func):
    """Decorator to mark coroutines.

    If the coroutine is not yielded from before it is destroyed,
    an error message is logged.
    """
    is_coroutine = _iscoroutinefunction(func)
    if is_coroutine and _is_native_coro_code(func.__code__):
        # In Python 3.5 that's all we need to do for coroutines
        # defiend with "async def".
        # Wrapping in CoroWrapper will happen via
        # 'sys.set_coroutine_wrapper' function.
        return func

    if inspect.isgeneratorfunction(func):
        coro = func
    else:
        @functools.wraps(func)
        def coro(*args, **kw):
            res = func(*args, **kw)
            if isinstance(res, futures.Future) or inspect.isgenerator(res):
                res = yield from res
            elif AwaitableABC is not None:
                # If 'func' returns an Awaitable (new in 3.5) we
                # want to run it.
                try:
                    await_meth = res.__await__
                except AttributeError:
                    pass
                else:
                    if isinstance(res, AwaitableABC):
                        res = yield from await_meth()
            return res

    if not _DEBUG:
        if native_coroutine_support:
            wrapper = types.coroutine(coro)
        else:
            wrapper = coro
    else:
        @functools.wraps(func)
        def wrapper(*args, **kwds):
            w = CoroWrapper(coro(*args, **kwds), func=func)
            if w._source_traceback:
                del w._source_traceback[-1]
            # Python < 3.5 does not implement __qualname__
            # on generator objects, so we set it manually.
            # We use getattr as some callables (such as
            # functools.partial may lack __qualname__).
            w.__name__ = getattr(func, '__name__', None)
            w.__qualname__ = getattr(func, '__qualname__', None)
            return w

    wrapper._is_coroutine = True  # For iscoroutinefunction().
    return wrapper
Esempio n. 17
0
    def test_async_def(self):
        # Test that types.coroutine passes 'async def' coroutines
        # without modification

        async def foo(): pass
        foo_code = foo.__code__
        foo_flags = foo.__code__.co_flags
        decorated_foo = types.coroutine(foo)
        self.assertIs(foo, decorated_foo)
        self.assertEqual(foo.__code__.co_flags, foo_flags)
        self.assertIs(decorated_foo.__code__, foo_code)

        foo_coro = foo()
        def bar(): return foo_coro
        for _ in range(2):
            bar = types.coroutine(bar)
            coro = bar()
            self.assertIs(foo_coro, coro)
            self.assertEqual(coro.cr_code.co_flags, foo_flags)
            coro.close()
Esempio n. 18
0
def m_make_coroutine_wrapper(func, replace_callback=True):
    if hasattr(types, 'm_coroutine'):
        func = types.coroutine(func)

#    ipdb.set_trace()
    def wrapper(*args, **kwargs):
        ipdb.set_trace()
        future = TracebackFuture()
        if replace_callback and 'callback' in kwargs:
            callback = kwargs.pop('callback')
            IOLoop.current().add_future(future, lambda future: callback(future.result()))

        try:
            result = func(*args, **kwargs)
        except (Return, StopIteration) as e:
#            ipdb.set_trace()
            result = gen._value_from_stopiteration(e)
        except Exception:
#            ipdb.set_trace()
            future.set_exc_info(sys.exc_info())
            return future
        else:
#            ipdb.set_trace()
            if isinstance(result, GeneratorType):
                try:
                    orig_stack_contexts = stack_context._state.contexts
                    yielded = next(result)
                    if stack_context._state.contexts is not orig_stack_contexts:
                        yielded = TracebackFuture()
                        yielded.set_exception(stack_context.StackContextInconsistentError('stack_context inconsistency (probably caused'))
                except (StopIteration, Return) as e:
                    future.set_result(gen._value_from_stopiteration(e))
                except Exception:
                    future.set_exc_info(sys.exc_info())
                else:
                    try:
                        result.send(yielded.result()) 
                    except (StopIteration, Return) as e:
                        ipdb.set_trace()
                        future.set_result(gen._value_from_stopiteration(e))
                        
#                    gen.Runner(result, future, yielded)
                try:
                    return future
                finally:
                    future = None

        future.set_result(result)
        return future
    return wrapper
Esempio n. 19
0
def coroutine(func):
    """Decorator to mark coroutines.

    If the coroutine is not yielded from before it is destroyed,
    an error message is logged.
    """
    if inspect.iscoroutinefunction(func):
        # In Python 3.5 that's all we need to do for coroutines
        # defined with "async def".
        return func

    if inspect.isgeneratorfunction(func):
        coro = func
    else:
        @functools.wraps(func)
        def coro(*args, **kw):
            res = func(*args, **kw)
            if (base_futures.isfuture(res) or inspect.isgenerator(res) or
                    isinstance(res, CoroWrapper)):
                res = yield from res
            else:
                # If 'res' is an awaitable, run it.
                try:
                    await_meth = res.__await__
                except AttributeError:
                    pass
                else:
                    if isinstance(res, collections.abc.Awaitable):
                        res = yield from await_meth()
            return res

    coro = types.coroutine(coro)
    if not _DEBUG:
        wrapper = coro
    else:
        @functools.wraps(func)
        def wrapper(*args, **kwds):
            w = CoroWrapper(coro(*args, **kwds), func=func)
            if w._source_traceback:
                del w._source_traceback[-1]
            # Python < 3.5 does not implement __qualname__
            # on generator objects, so we set it manually.
            # We use getattr as some callables (such as
            # functools.partial may lack __qualname__).
            w.__name__ = getattr(func, '__name__', None)
            w.__qualname__ = getattr(func, '__qualname__', None)
            return w

    wrapper._is_coroutine = _is_coroutine  # For iscoroutinefunction().
    return wrapper
Esempio n. 20
0
    def test_genfunc(self):
        def gen():
            yield

        self.assertFalse(isinstance(gen(), collections.abc.Coroutine))
        self.assertFalse(isinstance(gen(), collections.abc.Awaitable))

        gen_code = gen.__code__
        decorated_gen = types.coroutine(gen)
        self.assertIs(decorated_gen, gen)
        self.assertIsNot(decorated_gen.__code__, gen_code)

        decorated_gen2 = types.coroutine(decorated_gen)
        self.assertIs(decorated_gen2.__code__, decorated_gen.__code__)

        self.assertTrue(gen.__code__.co_flags & inspect.CO_ITERABLE_COROUTINE)
        self.assertFalse(gen.__code__.co_flags & inspect.CO_COROUTINE)

        g = gen()
        self.assertTrue(g.gi_code.co_flags & inspect.CO_ITERABLE_COROUTINE)
        self.assertFalse(g.gi_code.co_flags & inspect.CO_COROUTINE)
        self.assertTrue(isinstance(g, collections.abc.Coroutine))
        self.assertTrue(isinstance(g, collections.abc.Awaitable))
        g.close() # silence warning
def primed_coroutine(function: Callable[..., Generator]) -> Callable:
    """
    Primes a coroutine at creation.

    :param function: A coroutine function.
    :return: The coroutine function wrapped to prime the coroutine at creation.
    """
    function = types.coroutine(function)

    def inner(*args: Any, **kwargs: Any) -> Generator:
        output = function(*args, **kwargs)
        next(output)
        return output

    return inner
Esempio n. 22
0
    def test_returning_itercoro(self):
        @types.coroutine
        def gen():
            yield

        gencoro = gen()

        @types.coroutine
        def foo():
            return gencoro

        self.assertIs(foo(), gencoro)

        # decorate foo second time
        foo = types.coroutine(foo)
        self.assertIs(foo(), gencoro)
Esempio n. 23
0
def add_route(app, fn):
    method = getattr(fn, '__method__', None)
    path = getattr(fn, '__route__', None)
    if path is None or method is None:
        raise ValueError('@get or @post not defined in %s.' % str(fn))
    # asyncio.coroutine已经不支持了,这里删除好像对代码没有影响
    # 尝试了自定义一个toCoroutine,在其中async def,但是会造成runtime error: index was never awaited
    # 最终尝试types.coroutine,这个在官方文档中也能看见是把一个生成器函数转换为一个协程函数
    # if not asyncio.iscoroutinefunction(fn) and not inspect.isgeneratorfunction(fn):
    #     fn = asyncio.coroutine(fn)

    if not asyncio.iscoroutinefunction(fn) and not inspect.isgeneratorfunction(fn):
        fn = types.coroutine(fn)

    logging.info('add route %s %s => %s(%s)' % (method, path, fn.__name__, ', '.join(inspect.signature(fn).parameters.keys())))
    app.router.add_route(method, path, RequestHandler(app, fn))
Esempio n. 24
0
    def test_returning_itercoro(self):
        @types.coroutine
        def gen():
            yield

        gencoro = gen()

        @types.coroutine
        def foo():
            return gencoro

        self.assertIs(foo(), gencoro)

        # decorate foo second time
        foo = types.coroutine(foo)
        self.assertIs(foo(), gencoro)
Esempio n. 25
0
    def test_non_gen_values(self):
        @types.coroutine
        def foo():
            return 'spam'
        self.assertEqual(foo(), 'spam')

        class Awaitable:
            def __await__(self):
                return ()
        aw = Awaitable()
        @types.coroutine
        def foo():
            return aw
        self.assertIs(aw, foo())

        # decorate foo second time
        foo = types.coroutine(foo)
        self.assertIs(aw, foo())
Esempio n. 26
0
    def test_genfunc(self):
        def gen():
            yield

        self.assertFalse(isinstance(gen(), collections.abc.Coroutine))
        self.assertFalse(isinstance(gen(), collections.abc.Awaitable))

        self.assertIs(types.coroutine(gen), gen)

        self.assertTrue(gen.__code__.co_flags & inspect.CO_ITERABLE_COROUTINE)
        self.assertFalse(gen.__code__.co_flags & inspect.CO_COROUTINE)

        g = gen()
        self.assertTrue(g.gi_code.co_flags & inspect.CO_ITERABLE_COROUTINE)
        self.assertFalse(g.gi_code.co_flags & inspect.CO_COROUTINE)
        self.assertTrue(isinstance(g, collections.abc.Coroutine))
        self.assertTrue(isinstance(g, collections.abc.Awaitable))
        g.close()  # silence warning
    def test_generator_coroutine(self):
        module = self.import_extension('test_gen',
                                       [('is_coroutine', 'METH_O', '''
             if (!PyGen_CheckExact(args))
                Py_RETURN_NONE;
             PyObject* co = ((PyGenObject*)args)->gi_code;
             if (((PyCodeObject*)co)->co_flags & CO_ITERABLE_COROUTINE)
                Py_RETURN_TRUE;
             else
                Py_RETURN_FALSE;
             ''')])

        def it():
            yield 42

        print(module.is_coroutine(it()))
        assert module.is_coroutine(it()) is False
        self.debug_collect()  # don't crash while deallocating
        from types import coroutine
        assert module.is_coroutine(coroutine(it)()) is True
Esempio n. 28
0
def coroutine(func: Callable[..., Any]) -> Callable[..., Awaitable[Any]]:
    """Decorator to apply to methods to convert them to ESPHome coroutines."""
    if getattr(func, "_esphome_coroutine", False):
        # If func is already a coroutine, do not re-wrap it (performance)
        return func
    if inspect.isasyncgenfunction(func):
        # Trade-off: In ESPHome, there's not really a use-case for async generators.
        # and during the transition to new-style syntax it will happen that a `yield`
        # is not replaced properly, so don't accept async generators.
        raise ValueError(
            f"Async generator functions are not allowed. "
            f"Please check whether you've replaced all yields with awaits/returns. "
            f"See {func} in {func.__module__}"
        )
    if inspect.iscoroutinefunction(func):
        # A new-style async-def coroutine function, no conversion needed.
        return func

    if inspect.isgeneratorfunction(func):

        @functools.wraps(func)
        def coro(*args, **kwargs):
            gen = func(*args, **kwargs)
            ret = yield from _flatten_generator(gen)
            return ret

    else:
        # A "normal" function with no `yield` statements, convert to generator
        # that includes a yield just so it's also a generator function
        @functools.wraps(func)
        def coro(*args, **kwargs):
            res = func(*args, **kwargs)
            yield
            return res

    # Add coroutine internal python flag so that it can be awaited from new-style coroutines.
    coro = types.coroutine(coro)
    # pylint: disable=protected-access
    coro._esphome_coroutine = True
    return coro
Esempio n. 29
0
    def test_non_gen_values(self):
        @types.coroutine
        def foo():
            return 'spam'

        self.assertEqual(foo(), 'spam')

        class Awaitable:
            def __await__(self):
                return ()

        aw = Awaitable()

        @types.coroutine
        def foo():
            return aw

        self.assertIs(aw, foo())

        # decorate foo second time
        foo = types.coroutine(foo)
        self.assertIs(aw, foo())
Esempio n. 30
0
def futurize(func: PromiseCoroutineFunction[T],
             *,
             spawn=True) -> Callable[..., AbstractFuture[T]]:
    """
    Makes this coroutine a function that returns a Future instead of a
    coroutine-object.

    :param func:  The function to convert.
    :param spawn: If true, this function will spawn a new thread to execute the functions.
    :return: The function that returns a future.
    """
    func = coroutine(func)

    async def wrapped(coro):
        if spawn:
            await sleep(0)
        return await coro

    @functools.wraps(func)
    def _wrapper(*args, **kwargs) -> Callable[..., AbstractFuture[T]]:
        c = func(*args, **kwargs)
        return run_coroutine(wrapped(c))

    return _wrapper
Esempio n. 31
0
def _make_coroutine_wrapper(func, replace_callback):
    """The inner workings of ``@gen.coroutine`` and ``@gen.engine``.

    The two decorators differ in their treatment of the ``callback``
    argument, so we cannot simply implement ``@engine`` in terms of
    ``@coroutine``.
    """
    # On Python 3.5, set the coroutine flag on our generator, to allow it
    # to be used with 'await'.
    if hasattr(types, 'coroutine'):
        func = types.coroutine(func)

    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        # 这个 future 对象是用来存储 coroutine 执行完毕后的结果的。结果通常有
        # 两种来源,一个是在 coroutine 中 yield Return 对象,另一种则是
        # coroutine 作为 generator 执行完毕后 raise
        # StopIteration,并有结果数据存储在 StopIteration 这个异常对象中。
        future = TracebackFuture()

        if replace_callback and 'callback' in kwargs:
            callback = kwargs.pop('callback')
            IOLoop.current().add_future(
                future, lambda future: callback(future.result()))

        try:
            result = func(*args, **kwargs)
        except (Return, StopIteration) as e:
            result = _value_from_stopiteration(e)
        except Exception:
            future.set_exc_info(sys.exc_info())
            return future
        else:
            if isinstance(result, GeneratorType):
                # Inline the first iteration of Runner.run.  This lets us
                # avoid the cost of creating a Runner when the coroutine
                # never actually yields, which in turn allows us to
                # use "optional" coroutines in critical path code without
                # performance penalty for the synchronous case.
                try:
                    orig_stack_contexts = stack_context._state.contexts
                    yielded = next(result)
                    if stack_context._state.contexts is \
                            not orig_stack_contexts:
                        yielded = TracebackFuture()
                        yielded.set_exception(
                            stack_context.StackContextInconsistentError(
                                'stack_context inconsistency (probably caused '
                                'by yield within a "with StackContext" block)')
                        )
                except (StopIteration, Return) as e:
                    future.set_result(_value_from_stopiteration(e))
                except Exception:
                    future.set_exc_info(sys.exc_info())
                else:
                    # Runner 负责执行一个 coroutine,如果 coroutine 中的异步
                    # 操作已经完成,则 future 会被填充该操作的结果,否则 future
                    # 会继续处于等待结果的状态,并紧接着在下一行代码返回给
                    # coroutine 的调用者。
                    Runner(result, future, yielded)
                try:
                    return future
                finally:
                    # Subtle memory optimization: if next() raised an
                    # exception, the future's exc_info contains a traceback
                    # which includes this stack frame.  This creates a cycle,
                    # which will be collected at the next full GC but has
                    # been shown to greatly increase memory usage of
                    # benchmarks (relative to the refcount-based scheme
                    # used in the absence of cycles).  We can avoid the
                    # cycle by clearing the local variable after we return it.
                    future = None
        future.set_result(result)
        return future

    return wrapper
Esempio n. 32
0
File: gen.py Progetto: heewa/tornado
def _make_coroutine_wrapper(func, replace_callback):
    """The inner workings of ``@gen.coroutine`` and ``@gen.engine``.

    The two decorators differ in their treatment of the ``callback``
    argument, so we cannot simply implement ``@engine`` in terms of
    ``@coroutine``.
    """
    # On Python 3.5, set the coroutine flag on our generator, to allow it
    # to be used with 'await'.
    wrapped = func
    if hasattr(types, 'coroutine'):
        func = types.coroutine(func)

    @functools.wraps(wrapped)
    def wrapper(*args, **kwargs):
        future = TracebackFuture()

        if replace_callback and 'callback' in kwargs:
            callback = kwargs.pop('callback')
            IOLoop.current().add_future(
                future, lambda future: callback(future.result()))

        try:
            result = func(*args, **kwargs)
        except (Return, StopIteration) as e:
            result = _value_from_stopiteration(e)
        except Exception:
            future.set_exc_info(sys.exc_info())
            return future
        else:
            if isinstance(result, GeneratorType):
                # Inline the first iteration of Runner.run.  This lets us
                # avoid the cost of creating a Runner when the coroutine
                # never actually yields, which in turn allows us to
                # use "optional" coroutines in critical path code without
                # performance penalty for the synchronous case.
                try:
                    orig_stack_contexts = stack_context._state.contexts
                    yielded = next(result)
                    if stack_context._state.contexts is not orig_stack_contexts:
                        yielded = TracebackFuture()
                        yielded.set_exception(
                            stack_context.StackContextInconsistentError(
                                'stack_context inconsistency (probably caused '
                                'by yield within a "with StackContext" block)'))
                except (StopIteration, Return) as e:
                    future.set_result(_value_from_stopiteration(e))
                except Exception:
                    future.set_exc_info(sys.exc_info())
                else:
                    _futures_to_runners[future] = Runner(result, future, yielded)
                try:
                    return future
                finally:
                    # Subtle memory optimization: if next() raised an exception,
                    # the future's exc_info contains a traceback which
                    # includes this stack frame.  This creates a cycle,
                    # which will be collected at the next full GC but has
                    # been shown to greatly increase memory usage of
                    # benchmarks (relative to the refcount-based scheme
                    # used in the absence of cycles).  We can avoid the
                    # cycle by clearing the local variable after we return it.
                    future = None
        future.set_result(result)
        return future

    wrapper.__wrapped__ = wrapped
    wrapper.__tornado_coroutine__ = True
    return wrapper
Esempio n. 33
0
def _make_coroutine_wrapper(func, replace_callback):
    """The inner workings of ``@gen.coroutine`` and ``@gen.engine``.

    The two decorators differ in their treatment of the ``callback``
    argument, so we cannot simply implement ``@engine`` in terms of
    ``@coroutine``.
    """
    # On Python 3.5, set the coroutine flag on our generator, to allow it
    # to be used with 'await'.
    wrapped = func
    if hasattr(types, 'coroutine'):
        func = types.coroutine(func)

    @functools.wraps(wrapped)
    def wrapper(*args, **kwargs):
        future = _create_future()

        if replace_callback and 'callback' in kwargs:
            callback = kwargs.pop('callback')
            IOLoop.current().add_future(
                future, lambda future: callback(future.result()))

        try:
            result = func(*args, **kwargs)
        except (Return, StopIteration) as e:
            result = _value_from_stopiteration(e)
        except Exception:
            future_set_exc_info(future, sys.exc_info())
            try:
                return future
            finally:
                # Avoid circular references
                future = None
        else:
            if isinstance(result, GeneratorType):
                # Inline the first iteration of Runner.run.  This lets us
                # avoid the cost of creating a Runner when the coroutine
                # never actually yields, which in turn allows us to
                # use "optional" coroutines in critical path code without
                # performance penalty for the synchronous case.
                try:
                    orig_stack_contexts = stack_context._state.contexts
                    yielded = next(result)
                    if stack_context._state.contexts is not orig_stack_contexts:
                        yielded = _create_future()
                        yielded.set_exception(
                            stack_context.StackContextInconsistentError(
                                'stack_context inconsistency (probably caused '
                                'by yield within a "with StackContext" block)')
                        )
                except (StopIteration, Return) as e:
                    future_set_result_unless_cancelled(
                        future, _value_from_stopiteration(e))
                except Exception:
                    future_set_exc_info(future, sys.exc_info())
                else:
                    _futures_to_runners[future] = Runner(
                        result, future, yielded)
                yielded = None
                try:
                    return future
                finally:
                    # Subtle memory optimization: if next() raised an exception,
                    # the future's exc_info contains a traceback which
                    # includes this stack frame.  This creates a cycle,
                    # which will be collected at the next full GC but has
                    # been shown to greatly increase memory usage of
                    # benchmarks (relative to the refcount-based scheme
                    # used in the absence of cycles).  We can avoid the
                    # cycle by clearing the local variable after we return it.
                    future = None
        future_set_result_unless_cancelled(future, result)
        return future

    wrapper.__wrapped__ = wrapped
    wrapper.__tornado_coroutine__ = True
    return wrapper
Esempio n. 34
0
def generator_hook(f):
    return functools.wraps(f)(coroutine_hook(types.coroutine(f)))
Esempio n. 35
0
 def test_wrong_args(self):
     samples = [None, 1, object()]
     for sample in samples:
         with self.assertRaisesRegexp(TypeError,
                                     'types.coroutine.*expects a callable'):
             types.coroutine(sample)
Esempio n. 36
0
 def update_event(self, inp=-1):
     self.set_output_val(0, types.coroutine(self.input(0)))
Esempio n. 37
0
 def test_wrong_args(self):
     samples = [None, 1, object()]
     for sample in samples:
         with self.assertRaisesRegexp(
                 TypeError, 'types.coroutine.*expects a callable'):
             types.coroutine(sample)