mirror of https://github.com/scrapy/scrapy.git
More docs about Deferred<->Future interoperability. (#6734)
This commit is contained in:
parent
fc566a7ff9
commit
9057bf4e1e
|
|
@ -72,24 +72,32 @@ those imports happen.
|
|||
|
||||
.. _asyncio-await-dfd:
|
||||
|
||||
Awaiting on Deferreds
|
||||
=====================
|
||||
Integrating Deferred code and asyncio code
|
||||
==========================================
|
||||
|
||||
When the asyncio reactor isn't installed, you can await on Deferreds in the
|
||||
coroutines directly. When it is installed, this is not possible anymore, due to
|
||||
specifics of the Scrapy coroutine integration (the coroutines are wrapped into
|
||||
:class:`asyncio.Future` objects, not into
|
||||
:class:`~twisted.internet.defer.Deferred` directly), and you need to wrap them into
|
||||
Futures. Scrapy provides two helpers for this:
|
||||
Coroutine functions can await on Deferreds by wrapping them into
|
||||
:class:`asyncio.Future` objects. Scrapy provides two helpers for this:
|
||||
|
||||
.. autofunction:: scrapy.utils.defer.deferred_to_future
|
||||
.. autofunction:: scrapy.utils.defer.maybe_deferred_to_future
|
||||
|
||||
.. tip:: If you don't need to support reactors other than the default
|
||||
:class:`~twisted.internet.asyncioreactor.AsyncioSelectorReactor`, you
|
||||
can use :func:`~scrapy.utils.defer.deferred_to_future`, otherwise you
|
||||
should use :func:`~scrapy.utils.defer.maybe_deferred_to_future`.
|
||||
|
||||
.. tip:: If you need to use these functions in code that aims to be compatible
|
||||
with lower versions of Scrapy that do not provide these functions,
|
||||
down to Scrapy 2.0 (earlier versions do not support
|
||||
:mod:`asyncio`), you can copy the implementation of these functions
|
||||
into your own code.
|
||||
|
||||
Coroutines and futures can be wrapped into Deferreds (for example, when a
|
||||
Scrapy API requires passing a Deferred to it) using the following helpers:
|
||||
|
||||
.. autofunction:: scrapy.utils.defer.deferred_from_coro
|
||||
.. autofunction:: scrapy.utils.defer.deferred_f_from_coro_f
|
||||
|
||||
|
||||
.. _enforce-asyncio-requirement:
|
||||
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ Coroutines
|
|||
Scrapy has :ref:`partial support <coroutine-support>` for the
|
||||
:ref:`coroutine syntax <async>`.
|
||||
|
||||
|
||||
.. _coroutine-support:
|
||||
|
||||
Supported callables
|
||||
|
|
@ -51,6 +52,29 @@ hence use coroutine syntax (e.g. ``await``, ``async for``, ``async with``):
|
|||
|
||||
.. versionadded:: 2.7
|
||||
|
||||
|
||||
.. _coroutine-deferred-apis:
|
||||
|
||||
Using Deferred-based APIs
|
||||
=========================
|
||||
|
||||
In addition to native coroutine APIs Scrapy has some APIs that return a
|
||||
:class:`~twisted.internet.defer.Deferred` object or take a user-supplied
|
||||
function that returns a :class:`~twisted.internet.defer.Deferred` object. These
|
||||
APIs are also asynchronous but don't yet support native ``async def`` syntax.
|
||||
For example:
|
||||
|
||||
- The :meth:`ExecutionEngine.download` method returns a
|
||||
:class:`~twisted.internet.defer.Deferred` object.
|
||||
- A custom download handler needs to define a ``download_request()`` method that
|
||||
returns a :class:`~twisted.internet.defer.Deferred` object.
|
||||
|
||||
In most cases you can use these APIs in code that otherwise uses coroutines, by
|
||||
wrapping a :class:`~twisted.internet.defer.Deferred` object into a
|
||||
:class:`~asyncio.Future` object or vice versa. See :ref:`asyncio-await-dfd` for
|
||||
more information about this.
|
||||
|
||||
|
||||
General usage
|
||||
=============
|
||||
|
||||
|
|
|
|||
|
|
@ -362,7 +362,8 @@ def deferred_from_coro(o: _T) -> _T: ...
|
|||
|
||||
|
||||
def deferred_from_coro(o: _T) -> Deferred | _T:
|
||||
"""Converts a coroutine into a Deferred, or returns the object as is if it isn't a coroutine"""
|
||||
"""Converts a coroutine or other awaitable object into a Deferred,
|
||||
or returns the object as is if it isn't a coroutine."""
|
||||
if isinstance(o, Deferred):
|
||||
return o
|
||||
if asyncio.isfuture(o) or inspect.isawaitable(o):
|
||||
|
|
@ -442,12 +443,12 @@ def maybe_deferred_to_future(d: Deferred[_T]) -> Deferred[_T] | Future[_T]:
|
|||
What you can await in Scrapy callables defined as coroutines depends on the
|
||||
value of :setting:`TWISTED_REACTOR`:
|
||||
|
||||
- When not using the asyncio reactor, you can only await on
|
||||
:class:`~twisted.internet.defer.Deferred` objects.
|
||||
|
||||
- When :ref:`using the asyncio reactor <install-asyncio>`, you can only
|
||||
await on :class:`asyncio.Future` objects.
|
||||
|
||||
- When not using the asyncio reactor, you can only await on
|
||||
:class:`~twisted.internet.defer.Deferred` objects.
|
||||
|
||||
If you want to write code that uses ``Deferred`` objects but works with any
|
||||
reactor, use this function on all ``Deferred`` objects::
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue