serialize requests with callback references as spider attribute

You could define a spider attribute that references a callback method
but if this method has a different name than your spider attribute,
the request serializer is not able to find it on the spider class.

With this commit we're fixing this behavior as we're searching for
callback references in the spider object itself instead of looking
for attributes with the same function's name, that could be different.
This commit is contained in:
Victor Torres 2020-04-15 19:57:34 -03:00
parent 36abe9235c
commit 47a992615a
No known key found for this signature in database
GPG Key ID: 5A646C47A34D7752
2 changed files with 48 additions and 4 deletions

View File

@ -1,6 +1,8 @@
"""
Helper functions for serializing (and deserializing) requests.
"""
import inspect
from scrapy.http import Request
from scrapy.utils.python import to_unicode
from scrapy.utils.misc import load_object
@ -90,10 +92,12 @@ def _find_method(obj, func):
pass
else:
if func_self is obj:
name = func.__func__.__name__
if _is_private_method(name):
return _mangle_private_name(obj, func, name)
return name
members = inspect.getmembers(obj, predicate=inspect.ismethod)
for name, obj_func in members:
if obj_func.__func__ is func.__func__:
if _is_private_method(name):
return _mangle_private_name(obj, func, name)
return name
raise ValueError("Function %s is not a method of: %s" % (func, obj))

View File

@ -69,6 +69,26 @@ class RequestSerializationTest(unittest.TestCase):
errback=self.spider.handle_error)
self._assert_serializes_ok(r, spider=self.spider)
def test_reference_callback_serialization(self):
r = Request("http://www.example.com",
callback=self.spider.parse_item_reference,
errback=self.spider.handle_error_reference)
self._assert_serializes_ok(r, spider=self.spider)
request_dict = request_to_dict(r, self.spider)
self.assertEqual(request_dict['callback'], 'parse_item_reference')
self.assertEqual(request_dict['errback'], 'handle_error_reference')
def test_private_reference_callback_serialization(self):
r = Request("http://www.example.com",
callback=self.spider._TestSpider__parse_item_reference,
errback=self.spider._TestSpider__handle_error_reference)
self._assert_serializes_ok(r, spider=self.spider)
request_dict = request_to_dict(r, self.spider)
self.assertEqual(request_dict['callback'],
'_TestSpider__parse_item_reference')
self.assertEqual(request_dict['errback'],
'_TestSpider__handle_error_reference')
def test_private_callback_serialization(self):
r = Request("http://www.example.com",
callback=self.spider._TestSpider__parse_item_private,
@ -131,8 +151,28 @@ class TestSpiderMixin:
pass
def parse_item(response):
pass
def handle_error(failure):
pass
def private_parse_item(response):
pass
def private_handle_error(failure):
pass
class TestSpider(Spider, TestSpiderMixin):
name = 'test'
parse_item_reference = parse_item
handle_error_reference = handle_error
__parse_item_reference = private_parse_item
__handle_error_reference = private_handle_error
def parse_item(self, response):
pass