StopDownload: store response in the exception instead of the failure

This commit is contained in:
Eugenio Lacuesta 2020-05-27 10:45:07 -03:00
parent 634ad5ebca
commit 492197e477
No known key found for this signature in database
GPG Key ID: DA3EF2D0913E9810
4 changed files with 16 additions and 21 deletions

View File

@ -91,9 +91,12 @@ indicate that no further bytes should be downloaded for a response.
The ``fail`` boolean parameter controls which method will handle the resulting
response:
* If ``fail=True``, the request errback is called. The response object is
available as the ``response`` attribute of the received
:class:`~twisted.python.failure.Failure` object. This is the default behaviour.
* If ``fail=True`` (default), the request errback is called. The response object is
available as the ``response`` attribute of the ``StopDownload`` exception,
which is in turn stored as the ``value`` attribute of the received
:class:`~twisted.python.failure.Failure` object. This means that in an errback
defined as ``def errback(self, failure)``, the response can be accessed though
``failure.value.response``.
* If ``fail=False``, the request callback is called instead.

View File

@ -442,12 +442,8 @@ class ScrapyAgent:
ip_address=result["ip_address"],
)
if result.get("failure"):
# This failure is not the same object that will reach the errback,
# so we need to temporarily store the response in the exception.
# It will be moved to the failure in core/scraper.py
failure = result["failure"]
failure.value.response = response
return failure
result["failure"].value.response = response
return result["failure"]
return response

View File

@ -11,7 +11,7 @@ from scrapy.utils.defer import defer_result, defer_succeed, parallel, iter_errba
from scrapy.utils.spider import iterate_spider_output
from scrapy.utils.misc import load_object, warn_on_generator_with_return_value
from scrapy.utils.log import logformatter_adapter, failure_to_exc_info
from scrapy.exceptions import CloseSpider, DropItem, IgnoreRequest, StopDownload
from scrapy.exceptions import CloseSpider, DropItem, IgnoreRequest
from scrapy import signals
from scrapy.http import Request, Response
from scrapy.item import _BaseItem
@ -147,14 +147,6 @@ class Scraper:
def call_spider(self, result, request, spider):
result.request = request
# StopDownload exceptions: make the partial response an attribute of the failure
if (
isinstance(result, Failure)
and isinstance(result.value, StopDownload)
and hasattr(result.value, "response")
):
result.response = result.value.response
delattr(result.value, "response")
dfd = defer_result(result)
callback = request.callback or spider.parse
warn_on_generator_with_return_value(spider, callback)

View File

@ -488,6 +488,10 @@ with multiples lines
self.assertIsNone(crawler.spider.meta.get("response"))
self.assertIsInstance(crawler.spider.meta["failure"], Failure)
self.assertIsInstance(crawler.spider.meta["failure"].value, StopDownload)
self.assertIsInstance(crawler.spider.meta["failure"].response, Response)
self.assertEqual(crawler.spider.meta["failure"].response.body, crawler.spider.meta.get("bytes_received"))
self.assertLess(len(crawler.spider.meta["failure"].response.body), crawler.spider.full_response_length)
self.assertIsInstance(crawler.spider.meta["failure"].value.response, Response)
self.assertEqual(
crawler.spider.meta["failure"].value.response.body,
crawler.spider.meta.get("bytes_received"))
self.assertLess(
len(crawler.spider.meta["failure"].value.response.body),
crawler.spider.full_response_length)