Don't install the reactor in is_asyncio_reactor_installed(). (#6732)

This commit is contained in:
Andrey Rakhmatullin 2025-03-14 23:46:17 +04:00 committed by GitHub
parent d0dabbc097
commit fc566a7ff9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 57 additions and 1 deletions

View File

@ -116,6 +116,8 @@ example:
f"of Scrapy for more information."
)
.. autofunction:: scrapy.utils.reactor.is_asyncio_reactor_installed
.. _asyncio-windows:

View File

@ -175,7 +175,20 @@ def verify_installed_asyncio_event_loop(loop_path: str) -> None:
)
def is_reactor_installed() -> bool:
return "twisted.internet.reactor" in sys.modules
def is_asyncio_reactor_installed() -> bool:
"""Check whether the installed reactor is :class:`~twisted.internet.asyncioreactor.AsyncioSelectorReactor`.
Raise a :exc:`RuntimeError` if no reactor is installed.
"""
if not is_reactor_installed():
raise RuntimeError(
"is_asyncio_reactor_installed() called without an installed reactor."
)
from twisted.internet import reactor
return isinstance(reactor, asyncioreactor.AsyncioSelectorReactor)

View File

@ -1,5 +1,12 @@
import scrapy
from scrapy.crawler import CrawlerProcess
from scrapy.utils.reactor import is_asyncio_reactor_installed
class ReactorCheckExtension:
def __init__(self):
if not is_asyncio_reactor_installed():
raise RuntimeError("ReactorCheckExtension requires the asyncio reactor.")
class NoRequestsSpider(scrapy.Spider):
@ -12,6 +19,7 @@ class NoRequestsSpider(scrapy.Spider):
process = CrawlerProcess(
settings={
"TWISTED_REACTOR": "twisted.internet.asyncioreactor.AsyncioSelectorReactor",
"EXTENSIONS": {ReactorCheckExtension: 0},
}
)
process.crawl(NoRequestsSpider)

View File

@ -1,9 +1,39 @@
import scrapy
from scrapy.crawler import CrawlerProcess
from scrapy.utils.reactor import install_reactor
from scrapy.utils.reactor import (
install_reactor,
is_asyncio_reactor_installed,
is_reactor_installed,
)
if is_reactor_installed():
raise RuntimeError(
"Reactor already installed before is_asyncio_reactor_installed()."
)
try:
is_asyncio_reactor_installed()
except RuntimeError:
pass
else:
raise RuntimeError("is_asyncio_reactor_installed() did not raise RuntimeError.")
if is_reactor_installed():
raise RuntimeError(
"Reactor already installed after is_asyncio_reactor_installed()."
)
install_reactor("twisted.internet.asyncioreactor.AsyncioSelectorReactor")
if not is_asyncio_reactor_installed():
raise RuntimeError("Wrong reactor installed after install_reactor().")
class ReactorCheckExtension:
def __init__(self):
if not is_asyncio_reactor_installed():
raise RuntimeError("ReactorCheckExtension requires the asyncio reactor.")
class NoRequestsSpider(scrapy.Spider):
name = "no_request"
@ -15,6 +45,7 @@ class NoRequestsSpider(scrapy.Spider):
process = CrawlerProcess(
settings={
"TWISTED_REACTOR": "twisted.internet.asyncioreactor.AsyncioSelectorReactor",
"EXTENSIONS": {ReactorCheckExtension: 0},
}
)
process.crawl(NoRequestsSpider)

View File

@ -747,6 +747,7 @@ class TestCrawlerProcessSubprocess(ScriptRunnerMixin, unittest.TestCase):
"Using reactor: twisted.internet.asyncioreactor.AsyncioSelectorReactor"
in log
)
assert "RuntimeError" not in log
def test_asyncio_enabled_reactor(self):
log = self.run_script("asyncio_enabled_reactor.py")
@ -755,6 +756,7 @@ class TestCrawlerProcessSubprocess(ScriptRunnerMixin, unittest.TestCase):
"Using reactor: twisted.internet.asyncioreactor.AsyncioSelectorReactor"
in log
)
assert "RuntimeError" not in log
@pytest.mark.skipif(
parse_version(w3lib_version) >= parse_version("2.0.0"),