# HG changeset patch # Parent 44253ce374fc21402c15cbce9c2be0e184610882 diff -r 44253ce374fc Doc/glossary.rst --- a/Doc/glossary.rst Mon Jun 22 12:31:24 2015 -0400 +++ b/Doc/glossary.rst Tue Jun 23 12:20:11 2015 +0000 @@ -169,18 +169,19 @@ statement by defining :meth:`__enter__` and :meth:`__exit__` methods. See :pep:`343`. - coroutine function - A function which returns a :term:`coroutine` object. It is defined - with an :keyword:`async def` keyword, and may contain :keyword:`await`, - :keyword:`async for`, and :keyword:`async with` keywords. Introduced - by :pep:`492`. - coroutine Coroutines is a more generalized form of subroutines. Subroutines are - entered at one point and exited at another point. Coroutines, can be - entered, exited, and resumed at many different points. See - :keyword:`await` expressions, and :keyword:`async for` and - :keyword:`async with` statements. See also :pep:`492`. + entered at one point and exited at another point. Coroutines can be + entered, exited, and resumed at many different points. :dfn:`Native + coroutines` are implemented with the :keyword:`async def` statement. + See also :pep:`492`. + + coroutine function + A function which returns a :term:`coroutine` object. A :dfn:`native + coroutine function` is defined with the :keyword:`async def` statement, + and may contain :keyword:`await`, :keyword:`async for`, and + :keyword:`async with` keywords. Native coroutines were introduced + by :pep:`492`. CPython The canonical implementation of the Python programming language, as diff -r 44253ce374fc Doc/library/asyncio-task.rst --- a/Doc/library/asyncio-task.rst Mon Jun 22 12:31:24 2015 -0400 +++ b/Doc/library/asyncio-task.rst Tue Jun 23 12:20:11 2015 +0000 @@ -8,17 +8,22 @@ Coroutines ---------- -A coroutine is a generator that follows certain conventions. For -documentation purposes, all coroutines should be decorated with -``@asyncio.coroutine``, but this cannot be strictly enforced. +A coroutine is a native Python :term:`coroutine` or a :term:`generator` that +follows certain conventions. Native coroutines were added in Python 3.5, and +are recommended if there is no need to support older Python versions. -Coroutines use the ``yield from`` syntax introduced in :pep:`380`, +Generator-based coroutines should be decorated with +:func:`@asyncio.coroutine `. This is mainly +for documentation purposes and cannot be strictly enforced, but +it also enables them to call native coroutines. Generator-based +coroutines use the ``yield from`` syntax introduced in :pep:`380`, instead of the original ``yield`` syntax. The word "coroutine", like the word "generator", is used for two different (though related) concepts: -- The function that defines a coroutine (a function definition +- The function that defines a coroutine + (a function definition using :keyword:`async def` or decorated with ``@asyncio.coroutine``). If disambiguation is needed we will call this a *coroutine function* (:func:`iscoroutinefunction` returns ``True``). @@ -30,27 +35,28 @@ Things a coroutine can do: -- ``result = yield from future`` -- suspends the coroutine until the +- ``result = await future`` or ``result = yield from future`` -- + suspends the coroutine until the future is done, then returns the future's result, or raises an exception, which will be propagated. (If the future is cancelled, it will raise a ``CancelledError`` exception.) Note that tasks are futures, and everything said about futures also applies to tasks. -- ``result = yield from coroutine`` -- wait for another coroutine to +- ``result = await coroutine`` or ``result = yield from coroutine`` -- + wait for another coroutine to produce a result (or raise an exception, which will be propagated). The ``coroutine`` expression must be a *call* to another coroutine. - ``return expression`` -- produce a result to the coroutine that is - waiting for this one using ``yield from``. + waiting for this one using :keyword:`await` or ``yield from``. - ``raise exception`` -- raise an exception in the coroutine that is - waiting for this one using ``yield from``. + waiting for this one using :keyword:`await` or ``yield from``. -Calling a coroutine does not start its code running -- it is just a -generator, and the coroutine object returned by the call is really a -generator object, which doesn't do anything until you iterate over it. -In the case of a coroutine object, there are two basic ways to start -it running: call ``yield from coroutine`` from another coroutine +Calling a coroutine does not start its code running -- +the coroutine object returned by the call doesn't do anything until you +schedule its execution. There are two basic ways to start it running: +call ``await coroutine`` or ``yield from coroutine`` from another coroutine (assuming the other coroutine is already running!), or schedule its execution using the :func:`async` function or the :meth:`BaseEventLoop.create_task` method. @@ -60,7 +66,8 @@ .. decorator:: coroutine - Decorator to mark coroutines. + Decorator to mark generator-based coroutines. This also enables + the generator to call native coroutines. If the coroutine is not yielded from before it is destroyed, an error message is logged. See :ref:`Detect coroutines never scheduled @@ -84,8 +91,7 @@ import asyncio - @asyncio.coroutine - def hello_world(): + async def hello_world(): print("Hello World!") loop = asyncio.get_event_loop() @@ -111,14 +117,13 @@ import asyncio import datetime - @asyncio.coroutine - def display_date(loop): + async def display_date(loop): end_time = loop.time() + 5.0 while True: print(datetime.datetime.now()) if (loop.time() + 1.0) >= end_time: break - yield from asyncio.sleep(1) + await asyncio.sleep(1) loop = asyncio.get_event_loop() # Blocking call which returns when the display_date() coroutine is done @@ -550,12 +555,14 @@ .. function:: iscoroutine(obj) - Return ``True`` if *obj* is a :ref:`coroutine object `. + Return ``True`` if *obj* is a :ref:`coroutine object `, + which may be based on a generator or a native coroutine. -.. function:: iscoroutinefunction(obj) +.. function:: iscoroutinefunction(func) - Return ``True`` if *func* is a decorated :ref:`coroutine function - `. + Return ``True`` if *func* is determined to be a :ref:`coroutine function + `, which may be a decorated generator function or a native + coroutine function. .. coroutinefunction:: sleep(delay, result=None, \*, loop=None) diff -r 44253ce374fc Doc/library/collections.abc.rst --- a/Doc/library/collections.abc.rst Mon Jun 22 12:31:24 2015 -0400 +++ b/Doc/library/collections.abc.rst Tue Jun 23 12:20:11 2015 +0000 @@ -154,21 +154,22 @@ .. class:: Awaitable - ABC for classes that provide ``__await__`` method. Instances - of such classes can be used in ``await`` expression. + ABC for :term:`awaitable` objects, which can be used in :keyword:`await` + expressions. Custom implementations must provide the :meth:`__await__` + method. - :term:`coroutine` objects and instances of - :class:`~collections.abc.Coroutine` are too instances of this ABC. + :term:`Coroutine` objects and instances of + :class:`~collections.abc.Coroutine` are both instances of this ABC. .. versionadded:: 3.5 .. class:: Coroutine ABC for coroutine compatible classes that implement a subset of - generator methods defined in :pep:`342`, namely: - :meth:`~generator.send`, :meth:`~generator.throw`, - :meth:`~generator.close` methods. :meth:`__await__` must also be - implemented. All :class:`Coroutine` instances are also instances of + the generator methods defined in :pep:`342`, namely: + :meth:`~generator.send`, :meth:`~generator.throw`, and + :meth:`~generator.close`. Custom implementations must also implement + :meth:`__await__`. All :class:`Coroutine` instances are also instances of :class:`Awaitable`. See also the definition of :term:`coroutine`. .. versionadded:: 3.5 diff -r 44253ce374fc Doc/library/dis.rst --- a/Doc/library/dis.rst Mon Jun 22 12:31:24 2015 -0400 +++ b/Doc/library/dis.rst Tue Jun 23 12:20:11 2015 +0000 @@ -516,12 +516,14 @@ Implements ``del TOS1[TOS]``. -**Coroutines opcodes** +**Coroutine opcodes** .. opcode:: GET_AWAITABLE - Implements ``TOS = get_awaitable(TOS)``; where ``get_awaitable(o)`` - returns ``o`` if ``o`` is a coroutine object; or resolved ``o.__await__``. + Implements ``TOS = get_awaitable(TOS)``, where ``get_awaitable(o)`` + returns ``o`` if ``o`` is a native coroutine object or + one derived from :func:`types.coroutine`, or resolves + ``o.__await__``. .. opcode:: GET_AITER diff -r 44253ce374fc Doc/library/exceptions.rst --- a/Doc/library/exceptions.rst Mon Jun 22 12:31:24 2015 -0400 +++ b/Doc/library/exceptions.rst Tue Jun 23 12:20:11 2015 +0000 @@ -162,7 +162,8 @@ .. exception:: GeneratorExit - Raised when a :term:`generator`\'s :meth:`close` method is called. It + Raised when a :term:`generator` or :term:`coroutine` is closed; + see :meth:`generator.close` and :meth:`coroutine.close`. It directly inherits from :exc:`BaseException` instead of :exc:`Exception` since it is technically not an error. @@ -306,7 +307,8 @@ given as an argument when constructing the exception, and defaults to :const:`None`. - When a generator function returns, a new :exc:`StopIteration` instance is + When a :term:`generator` or :term:`coroutine` function + returns, a new :exc:`StopIteration` instance is raised, and the value returned by the function is used as the :attr:`value` parameter to the constructor of the exception. diff -r 44253ce374fc Doc/library/sys.rst --- a/Doc/library/sys.rst Mon Jun 22 12:31:24 2015 -0400 +++ b/Doc/library/sys.rst Tue Jun 23 12:20:11 2015 +0000 @@ -1080,7 +1080,7 @@ :func:`types.coroutine` or :func:`asyncio.coroutine` will not be intercepted). - *wrapper* must be either: + The *wrapper* argument must be either: * a callable that accepts one argument (a coroutine object); * ``None``, to reset the wrapper. @@ -1088,7 +1088,8 @@ If called twice, the new wrapper replaces the previous one. The function is thread-specific. - The *wrapper* callable cannot define new coroutines directly or indirectly:: + The *wrapper* callable cannot define new native coroutines directly or + indirectly:: def wrapper(coro): async def wrap(coro): @@ -1096,7 +1097,8 @@ return wrap(coro) sys.set_coroutine_wrapper(wrapper) - async def foo(): pass + async def foo(): + pass # The following line will fail with a RuntimeError, because # `wrapper` creates a `wrap(coro)` coroutine: diff -r 44253ce374fc Doc/library/types.rst --- a/Doc/library/types.rst Mon Jun 22 12:31:24 2015 -0400 +++ b/Doc/library/types.rst Tue Jun 23 12:20:11 2015 +0000 @@ -281,13 +281,16 @@ .. versionadded:: 3.4 -Coroutines Utility Functions ----------------------------- +Coroutine Utility Functions +--------------------------- .. function:: coroutine(gen_func) - The function transforms a generator function to a :term:`coroutine function`, - so that it returns a :term:`coroutine` object. + This function transforms a :term:`generator` function into a + :term:`coroutine function`. The object returned by the transformed + function is still a :term:`generator iterator`, but is also considered + to be a :term:`coroutine` object and is :term:`awaitable`, although + it may not necessarily implement the :meth:`__await__` method. *gen_func* is modified in-place, hence the function can be used as a decorator. diff -r 44253ce374fc Doc/reference/compound_stmts.rst --- a/Doc/reference/compound_stmts.rst Mon Jun 22 12:31:24 2015 -0400 +++ b/Doc/reference/compound_stmts.rst Tue Jun 23 12:20:11 2015 +0000 @@ -666,15 +666,9 @@ Coroutines ========== -.. index:: - statement: async def - statement: async for - statement: async with - keyword: async - keyword: await - .. versionadded:: 3.5 +.. index:: statement: async def .. _`async def`: Coroutine function definition @@ -683,14 +677,23 @@ .. productionlist:: async_funcdef: "async" `funcdef` +.. index:: + keyword: async + keyword: await + Execution of Python coroutines can be suspended and resumed at many points -(see :term:`coroutine`.) :keyword:`await` expressions, :keyword:`async for` -and :keyword:`async with` can only be used in their bodies. +(see :term:`coroutine`). In the body of a coroutine, any ``await`` and +``async`` identifiers become reserved keywords; :keyword:`await` expressions, +:keyword:`async for` and :keyword:`async with` can only be used in +coroutine bodies. However, to simplify the parser, these keywords cannot +be used on the same line as a function or coroutine (:keyword:`def` +statement) header. Functions defined with ``async def`` syntax are always coroutine functions, even if they do not contain ``await`` or ``async`` keywords. -It is a :exc:`SyntaxError` to use :keyword:`yield` expressions in coroutines. +It is a :exc:`SyntaxError` to use :keyword:`yield` expressions in native +coroutines. An example of a coroutine function:: @@ -699,6 +702,7 @@ await some_coroutine() +.. index:: statement: async for .. _`async for`: The :keyword:`async for` statement @@ -742,6 +746,7 @@ :keyword:`async def` function. +.. index:: statement: async with .. _`async with`: The :keyword:`async with` statement diff -r 44253ce374fc Doc/reference/datamodel.rst --- a/Doc/reference/datamodel.rst Mon Jun 22 12:31:24 2015 -0400 +++ b/Doc/reference/datamodel.rst Tue Jun 23 12:20:11 2015 +0000 @@ -616,15 +616,15 @@ exception is raised and the iterator will have reached the end of the set of values to be returned. - Coroutine functions + Native coroutine functions .. index:: single: coroutine; function A function or method which is defined using :keyword:`async def` is called - a :dfn:`coroutine function`. Such a function, when called, returns a - :term:`coroutine` object. It may contain :keyword:`await` expressions, + a :dfn:`native coroutine function`. Such a function, when called, returns a + native :term:`coroutine` object. It may contain :keyword:`await` expressions, as well as :keyword:`async with` and :keyword:`async for` statements. See - also :ref:`coroutines` section. + also the :ref:`coroutine-objects` section. Built-in functions .. index:: @@ -2264,26 +2264,21 @@ object itself in order to be consistently invoked by the interpreter). -.. _coroutines: +.. index:: + single: coroutine Coroutines ========== -.. index:: - single: coroutine - Awaitable Objects ----------------- -An *awaitable* object can be one of the following: - -* A :term:`coroutine` object returned from a :term:`coroutine function`. - -* A :term:`generator` decorated with :func:`types.coroutine` - (or :func:`asyncio.coroutine`) decorator. - -* An object that implements an ``__await__`` method. +An :term:`awaitable` object generally implements an :meth:`__await__` method. +Native :term:`coroutine` objects are awaitable. The :term:`generator +iterator` objects returned from generators decorated with +:func:`types.coroutine` or :func:`asyncio.coroutine` are also awaitable, +but they do not implement :meth:`__await__`. .. method:: object.__await__(self) @@ -2296,6 +2291,58 @@ .. seealso:: :pep:`492` for additional information about awaitable objects. +.. _coroutine-objects: + +Native Coroutine Objects +------------------------ + +Native :term:`coroutine` objects are :term:`awaitable` objects. +A coroutine's execution can be controlled by calling :meth:`__await__` and +iterating over the result. When the coroutine has finished executing and +returns, the iterator raises :exc:`StopIteration`, and the exception's +:attr:`~StopIteration.value` attribute holds the return value. If the +coroutine raises an exception, it is propagated by the iterator. Coroutines +should not directly raise unhandled :exc:`StopIteration` exceptions. + +Coroutines also have the methods listed below, which are analogous to +those of generators (see :ref:`generator-methods`). However, unlike +generators, coroutines do not directly support iteration. + +.. method:: coroutine.send(value) + + Starts or resumes execution of the coroutine. If *value* is ``None``, + this is equivalent to advancing the iterator returned by + :meth:`__await__`. If *value* is not ``None``, this method delegates + to the :meth:`~generator.send` method of the iterator that caused + the coroutine's suspension. The result (return value, + :exc:`StopIteration`, or other exception) is the same as when + iterating over the :meth:`__await__` return value, described above. + +.. method:: coroutine.throw(type[, value[, traceback]]) + + Raises the specified exception in the coroutine. This method delegates + to the :meth:`~generator.throw` method of the iterator that caused + the coroutine's suspension, if it has such a method. Otherwise, + the exception is raised at the suspension point. The result + (return value, :exc:`StopIteration`, or other exception) is the same as + when iterating over the :meth:`__await__` return value, described + above. If the exception is not caught in the coroutine, it propagates + back to the caller. + +.. method:: coroutine.close() + + Causes the coroutine to clean itself up and exit. If the coroutine + is suspended, this method first delegates to the :meth:`~generator.close` + method of the iterator that caused the coroutine's suspension, if it + has such a method. Then it raises :exc:`GeneratorExit` at the + suspension point, causing the coroutine to immediately clean itself up. + Finally, the coroutine is marked as having finished executing, even if + it was never started. + + Coroutine objects are automatically closed using the above process when + they are about to be destroyed. + + Asynchronous Iterators ---------------------- diff -r 44253ce374fc Doc/reference/expressions.rst --- a/Doc/reference/expressions.rst Mon Jun 22 12:31:24 2015 -0400 +++ b/Doc/reference/expressions.rst Tue Jun 23 12:20:11 2015 +0000 @@ -390,6 +390,7 @@ to sub-generators easy. .. index:: object: generator +.. _generator-methods: Generator-iterator methods ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -817,7 +818,7 @@ ================ Suspend the execution of :term:`coroutine` on an :term:`awaitable` object. -Can only be used inside a :term:`coroutine function`. +Can only be used inside a native :term:`coroutine function`. .. productionlist:: await: ["await"] `primary` diff -r 44253ce374fc Objects/genobject.c --- a/Objects/genobject.c Mon Jun 22 12:31:24 2015 -0400 +++ b/Objects/genobject.c Tue Jun 23 12:20:11 2015 +0000 @@ -793,11 +793,11 @@ PyDoc_STRVAR(coro_send_doc, "send(arg) -> send 'arg' into coroutine,\n\ -return next yielded value or raise StopIteration."); +return next iterated value or raise StopIteration."); PyDoc_STRVAR(coro_throw_doc, "throw(typ[,val[,tb]]) -> raise exception in coroutine,\n\ -return next yielded value or raise StopIteration."); +return next iterated value or raise StopIteration."); PyDoc_STRVAR(coro_close_doc, "close() -> raise GeneratorExit inside coroutine."); @@ -908,9 +908,9 @@ } static PyMethodDef coro_wrapper_methods[] = { - {"send",(PyCFunction)coro_wrapper_send, METH_O, send_doc}, - {"throw",(PyCFunction)coro_wrapper_throw, METH_VARARGS, throw_doc}, - {"close",(PyCFunction)coro_wrapper_close, METH_NOARGS, close_doc}, + {"send",(PyCFunction)coro_wrapper_send, METH_O, coro_send_doc}, + {"throw",(PyCFunction)coro_wrapper_throw, METH_VARARGS, coro_throw_doc}, + {"close",(PyCFunction)coro_wrapper_close, METH_NOARGS, coro_close_doc}, {NULL, NULL} /* Sentinel */ };