mirror of https://github.com/scrapy/scrapy.git
Merge pull request #4872 from elacuesta/asyncio_get_event_loop
Call asyncio.get_event_loop when installing the asyncio reactor
This commit is contained in:
commit
27b07c692c
|
|
@ -249,19 +249,25 @@ ASYNCIO_EVENT_LOOP
|
|||
|
||||
Default: ``None``
|
||||
|
||||
Import path of a given asyncio event loop class.
|
||||
Import path of a given ``asyncio`` event loop class.
|
||||
|
||||
If the asyncio reactor is enabled (see :setting:`TWISTED_REACTOR`) this setting can be used to specify the
|
||||
asyncio event loop to be used with it. Set the setting to the import path of the
|
||||
If the asyncio reactor is enabled (see :setting:`TWISTED_REACTOR`) this setting can be used to specify the
|
||||
asyncio event loop to be used with it. Set the setting to the import path of the
|
||||
desired asyncio event loop class. If the setting is set to ``None`` the default asyncio
|
||||
event loop will be used.
|
||||
|
||||
If you are installing the asyncio reactor manually using the :func:`~scrapy.utils.reactor.install_reactor`
|
||||
function, you can use the ``event_loop_path`` parameter to indicate the import path of the event loop
|
||||
class to be used.
|
||||
function, you can use the ``event_loop_path`` parameter to indicate the import path of the event loop
|
||||
class to be used.
|
||||
|
||||
Note that the event loop class must inherit from :class:`asyncio.AbstractEventLoop`.
|
||||
|
||||
.. caution:: Please be aware that, when using a non-default event loop
|
||||
(either defined via :setting:`ASYNCIO_EVENT_LOOP` or installed with
|
||||
:func:`~scrapy.utils.reactor.install_reactor`), Scrapy will call
|
||||
:func:`asyncio.set_event_loop`, which will set the specified event loop
|
||||
as the current loop for the current OS thread.
|
||||
|
||||
.. setting:: BOT_NAME
|
||||
|
||||
BOT_NAME
|
||||
|
|
|
|||
|
|
@ -60,8 +60,9 @@ def install_reactor(reactor_path, event_loop_path=None):
|
|||
if event_loop_path is not None:
|
||||
event_loop_class = load_object(event_loop_path)
|
||||
event_loop = event_loop_class()
|
||||
asyncio.set_event_loop(event_loop)
|
||||
else:
|
||||
event_loop = asyncio.new_event_loop()
|
||||
event_loop = asyncio.get_event_loop()
|
||||
asyncioreactor.install(eventloop=event_loop)
|
||||
else:
|
||||
*module, _ = reactor_path.split(".")
|
||||
|
|
|
|||
|
|
@ -0,0 +1,44 @@
|
|||
import asyncio
|
||||
import sys
|
||||
|
||||
from scrapy import Spider
|
||||
from scrapy.crawler import CrawlerProcess
|
||||
from scrapy.utils.defer import deferred_from_coro
|
||||
from twisted.internet.defer import Deferred
|
||||
|
||||
|
||||
class UppercasePipeline:
|
||||
async def _open_spider(self, spider):
|
||||
spider.logger.info("async pipeline opened!")
|
||||
await asyncio.sleep(0.1)
|
||||
|
||||
def open_spider(self, spider):
|
||||
return deferred_from_coro(self._open_spider(spider))
|
||||
|
||||
def process_item(self, item, spider):
|
||||
return {"url": item["url"].upper()}
|
||||
|
||||
|
||||
class UrlSpider(Spider):
|
||||
name = "url_spider"
|
||||
start_urls = ["data:,"]
|
||||
custom_settings = {
|
||||
"ITEM_PIPELINES": {UppercasePipeline: 100},
|
||||
}
|
||||
|
||||
def parse(self, response):
|
||||
yield {"url": response.url}
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
try:
|
||||
ASYNCIO_EVENT_LOOP = sys.argv[1]
|
||||
except IndexError:
|
||||
ASYNCIO_EVENT_LOOP = None
|
||||
|
||||
process = CrawlerProcess(settings={
|
||||
"TWISTED_REACTOR": "twisted.internet.asyncioreactor.AsyncioSelectorReactor",
|
||||
"ASYNCIO_EVENT_LOOP": ASYNCIO_EVENT_LOOP,
|
||||
})
|
||||
process.crawl(UrlSpider)
|
||||
process.start()
|
||||
|
|
@ -364,6 +364,25 @@ class CrawlerProcessSubprocess(ScriptRunnerMixin, unittest.TestCase):
|
|||
self.assertIn("Using reactor: twisted.internet.asyncioreactor.AsyncioSelectorReactor", log)
|
||||
self.assertIn("Using asyncio event loop: uvloop.Loop", log)
|
||||
|
||||
@mark.skipif(sys.implementation.name == "pypy", reason="uvloop does not support pypy properly")
|
||||
@mark.skipif(platform.system() == "Windows", reason="uvloop does not support Windows")
|
||||
def test_custom_loop_asyncio_deferred_signal(self):
|
||||
log = self.run_script("asyncio_deferred_signal.py", "uvloop.Loop")
|
||||
self.assertIn("Spider closed (finished)", log)
|
||||
self.assertIn("Using reactor: twisted.internet.asyncioreactor.AsyncioSelectorReactor", log)
|
||||
self.assertIn("Using asyncio event loop: uvloop.Loop", log)
|
||||
self.assertIn("async pipeline opened!", log)
|
||||
|
||||
# https://twistedmatrix.com/trac/ticket/9766
|
||||
@skipIf(platform.system() == 'Windows' and sys.version_info >= (3, 8),
|
||||
"the asyncio reactor is broken on Windows when running Python ≥ 3.8")
|
||||
def test_default_loop_asyncio_deferred_signal(self):
|
||||
log = self.run_script("asyncio_deferred_signal.py")
|
||||
self.assertIn("Spider closed (finished)", log)
|
||||
self.assertIn("Using reactor: twisted.internet.asyncioreactor.AsyncioSelectorReactor", log)
|
||||
self.assertNotIn("Using asyncio event loop: uvloop.Loop", log)
|
||||
self.assertIn("async pipeline opened!", log)
|
||||
|
||||
|
||||
class CrawlerRunnerSubprocess(ScriptRunnerMixin, unittest.TestCase):
|
||||
script_dir = os.path.join(os.path.abspath(os.path.dirname(__file__)), 'CrawlerRunner')
|
||||
|
|
|
|||
Loading…
Reference in New Issue