From 67c77eb9f2e91a2fbda78e32f307aaa98d462851 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adri=C3=A1n=20Chaves?= Date: Thu, 21 Dec 2023 21:01:07 +0100 Subject: [PATCH] MediaPipeline: log media_to_download errors before stripping them (#5068) --- scrapy/pipelines/media.py | 10 +++++----- tests/test_pipeline_crawl.py | 24 ++++++++++++++++++++++++ 2 files changed, 29 insertions(+), 5 deletions(-) diff --git a/scrapy/pipelines/media.py b/scrapy/pipelines/media.py index 401029439..153047acf 100644 --- a/scrapy/pipelines/media.py +++ b/scrapy/pipelines/media.py @@ -118,14 +118,14 @@ class MediaPipeline: info.downloading.add(fp) dfd = mustbe_deferred(self.media_to_download, request, info, item=item) dfd.addCallback(self._check_media_to_download, request, info, item=item) + dfd.addErrback(self._log_exception) dfd.addBoth(self._cache_result_and_execute_waiters, fp, info) - dfd.addErrback( - lambda f: logger.error( - f.value, exc_info=failure_to_exc_info(f), extra={"spider": info.spider} - ) - ) return dfd.addBoth(lambda _: wad) # it must return wad at last + def _log_exception(self, result): + logger.exception(result) + return result + def _make_compatible(self): """Make overridable methods of MediaPipeline and subclasses backwards compatible""" methods = [ diff --git a/tests/test_pipeline_crawl.py b/tests/test_pipeline_crawl.py index cb9464949..caf7a537f 100644 --- a/tests/test_pipeline_crawl.py +++ b/tests/test_pipeline_crawl.py @@ -8,6 +8,7 @@ from w3lib.url import add_or_replace_parameter from scrapy import signals from scrapy.crawler import CrawlerRunner +from scrapy.utils.misc import load_object from tests.mockserver import MockServer from tests.spiders import SimpleSpider @@ -192,6 +193,29 @@ class FileDownloadCrawlTestCase(TestCase): crawler.stats.get_value("downloader/response_status_count/302"), 3 ) + @defer.inlineCallbacks + def test_download_media_file_path_error(self): + cls = load_object(self.pipeline_class) + + class ExceptionRaisingMediaPipeline(cls): + def file_path(self, request, response=None, info=None, *, item=None): + return 1 / 0 + + settings = { + **self.settings, + "ITEM_PIPELINES": {ExceptionRaisingMediaPipeline: 1}, + } + runner = CrawlerRunner(settings) + crawler = self._create_crawler(MediaDownloadSpider, runner=runner) + with LogCapture() as log: + yield crawler.crawl( + self.mockserver.url("/files/images/"), + media_key=self.media_key, + media_urls_key=self.media_urls_key, + mockserver=self.mockserver, + ) + self.assertIn("ZeroDivisionError", str(log)) + try: from PIL import Image # noqa: imported just to check for the import error