Handle NotConfigured in add-ons.

This commit is contained in:
Andrey Rakhmatullin 2023-07-31 21:09:18 +04:00
parent b67a81b81d
commit 41a4a163e3
4 changed files with 29 additions and 17 deletions

View File

@ -77,6 +77,10 @@ modify :setting:`ITEM_PIPELINES`::
if settings.getbool("MYADDON_ENABLE_PIPELINE"):
settings["ITEM_PIPELINES"]["path.to.mypipeline"] = 200
If the ``update_settings`` method raises
:exc:`scrapy.exceptions.NotConfigured`, the add-on will not be skipped. This
makes it easy to enable an add-on only when some conditions are met.
Fallbacks
---------
@ -130,7 +134,7 @@ Check dependencies:
try:
import boto
except ImportError:
raise RuntimeError("MyAddon requires the boto library")
raise NotConfigured("MyAddon requires the boto library")
...
Access the crawler instance:

View File

@ -1,6 +1,8 @@
import logging
from typing import TYPE_CHECKING, Any, List
from scrapy.exceptions import NotConfigured
from scrapy.settings import Settings
from scrapy.utils.conf import build_component_list
from scrapy.utils.misc import create_instance, load_object
@ -17,19 +19,23 @@ class AddonManager:
self.crawler: "Crawler" = crawler
self.addons: List[Any] = []
def _add(self, addon: Any) -> None:
def _add(self, addon: Any, settings: Settings) -> None:
"""Store an add-on."""
if isinstance(addon, (type, str)):
addon = load_object(addon)
if isinstance(addon, type):
addon = create_instance(addon, settings=None, crawler=self.crawler)
self.addons.append(addon)
try:
addon.update_settings(settings)
self.addons.append(addon)
except NotConfigured:
pass
def load_settings(self, settings) -> None:
def load_settings(self, settings: Settings) -> None:
"""Load add-ons and configurations from a settings object.
This will load the add-on for every add-on path in the
``ADDONS`` setting.
``ADDONS`` setting and execute their ``update_settings`` methods.
:param settings: The :class:`~scrapy.settings.Settings` object from \
which to read the add-on configuration
@ -37,7 +43,7 @@ class AddonManager:
"""
addons = build_component_list(settings["ADDONS"])
for addon in build_component_list(settings["ADDONS"]):
self._add(addon)
self._add(addon, settings)
logger.info(
"Enabled addons:\n%(addons)s",
{
@ -45,13 +51,3 @@ class AddonManager:
},
extra={"crawler": self.crawler},
)
def update_settings(self, settings) -> None:
"""Call ``update_settings()`` of all held add-ons.
:param settings: The :class:`~scrapy.settings.Settings` object to be \
updated
:type settings: :class:`~scrapy.settings.Settings`
"""
for addon in self.addons:
addon.update_settings(settings)

View File

@ -71,7 +71,6 @@ class Crawler:
self.addons: AddonManager = AddonManager(self)
self.addons.load_settings(self.settings)
self.addons.update_settings(self.settings)
self.signals: SignalManager = SignalManager(self)

View File

@ -4,6 +4,7 @@ from typing import Any, Dict
from scrapy import Spider
from scrapy.crawler import Crawler, CrawlerRunner
from scrapy.exceptions import NotConfigured
from scrapy.settings import BaseSettings, Settings
from scrapy.utils.test import get_crawler
@ -57,6 +58,18 @@ class AddonManagerTest(unittest.TestCase):
manager = crawler.addons
self.assertIsInstance(manager.addons[0], SimpleAddon)
def test_notconfigured(self):
class NotConfiguredAddon:
def update_settings(self, settings):
raise NotConfigured()
settings_dict = {
"ADDONS": {NotConfiguredAddon: 0},
}
crawler = get_crawler(settings_dict=settings_dict)
manager = crawler.addons
self.assertFalse(manager.addons)
def test_load_settings_order(self):
# Get three addons with different settings
addonlist = []