|
3 | 3 | import asyncio |
4 | 4 | from typing import TYPE_CHECKING |
5 | 5 |
|
6 | | -from twisted.internet.defer import Deferred, ensureDeferred |
7 | | -from twisted.internet.task import react |
8 | | - |
9 | 6 | if TYPE_CHECKING: |
10 | 7 | from collections.abc import Coroutine |
11 | 8 |
|
12 | 9 |
|
13 | | -async def _run_coro_as_deferred(coro: Coroutine) -> None: |
14 | | - """Wrap the given asyncio coroutine in a Task and await its result as a Twisted Deferred.""" |
15 | | - task = asyncio.ensure_future(coro) |
16 | | - await Deferred.fromFuture(task) |
17 | | - |
18 | | - |
19 | 10 | def run_scrapy_actor(coro: Coroutine) -> None: |
20 | 11 | """Start Twisted's reactor and execute the provided Actor coroutine. |
21 | 12 |
|
22 | | - This function initiates the Twisted reactor and runs the given asyncio coroutine (typically the |
23 | | - Actor's main) by converting it to a Deferred. This bridges the asyncio and Twisted event loops, |
24 | | - enabling the Apify and Scrapy integration to work together. |
| 13 | + This function installs Twisted's asyncio-compatible reactor, then initiates it and runs the given asyncio |
| 14 | + coroutine (typically the Actor's main) by converting it to a Deferred. This bridges the asyncio and Twisted |
| 15 | + event loops, enabling the Apify and Scrapy integration to work together. |
25 | 16 | """ |
26 | | - react(lambda _: ensureDeferred(_run_coro_as_deferred(coro))) |
| 17 | + from scrapy.utils.reactor import install_reactor # noqa: PLC0415 |
| 18 | + from twisted.internet.error import ReactorAlreadyInstalledError # noqa: PLC0415 |
| 19 | + |
| 20 | + try: |
| 21 | + install_reactor('twisted.internet.asyncioreactor.AsyncioSelectorReactor') |
| 22 | + except ReactorAlreadyInstalledError: |
| 23 | + from twisted.internet import reactor as installed_reactor # noqa: PLC0415 |
| 24 | + |
| 25 | + reactor_cls = type(installed_reactor) |
| 26 | + if ( |
| 27 | + reactor_cls.__module__ != 'twisted.internet.asyncioreactor' |
| 28 | + or reactor_cls.__name__ != 'AsyncioSelectorReactor' |
| 29 | + ): |
| 30 | + raise RuntimeError( |
| 31 | + 'A Twisted reactor is already installed and it is not AsyncioSelectorReactor. ' |
| 32 | + 'Make sure that run_scrapy_actor() is called before importing any Scrapy or Twisted ' |
| 33 | + 'modules that install a reactor (e.g. scrapy.crawler).' |
| 34 | + ) from None |
| 35 | + |
| 36 | + from twisted.internet.defer import Deferred # noqa: PLC0415 |
| 37 | + from twisted.internet.task import react # noqa: PLC0415 |
| 38 | + |
| 39 | + react(lambda _reactor: Deferred.fromFuture(asyncio.ensure_future(coro))) |
0 commit comments