From 9c81721c407ff41ef9dce2c33e26ac477355cf1f Mon Sep 17 00:00:00 2001 From: Andrew Baxter Date: Wed, 5 Jun 2019 23:43:56 +0900 Subject: [PATCH] Add tests for private method name mangling --- scrapy/utils/reqser.py | 18 +++++++++++------- tests/test_utils_reqser.py | 16 +++++++++++++++- 2 files changed, 26 insertions(+), 8 deletions(-) diff --git a/scrapy/utils/reqser.py b/scrapy/utils/reqser.py index d1f472e6e..3c463cfed 100644 --- a/scrapy/utils/reqser.py +++ b/scrapy/utils/reqser.py @@ -71,6 +71,16 @@ def _is_private_method(name): return name.startswith('__') and not name.endswith('__') +def _mangle_private_name(obj, func, name): + qualname = getattr(func, '__qualname__', None) + if qualname is None: + classname = obj.__class__.__name__.lstrip('_') + return '_%s%s' % (classname, name) + else: + splits = qualname.split('.') + return '_%s%s' % (splits[-2], splits[-1]) + + def _find_method(obj, func): if obj: try: @@ -81,13 +91,7 @@ def _find_method(obj, func): if func_self is obj: name = six.get_method_function(func).__name__ if _is_private_method(name): - qualname = getattr(func, '__qualname__', None) - if qualname is None: - classname = obj.__class__.__name__.lstrip('_') - name = '_%s%s' % (classname, name) - else: - splits = qualname.split('.') - name = '_%s%s' % (splits[-2], splits[-1]) + return _mangle_private_name(obj, func, name) return name raise ValueError("Function %s is not a method of: %s" % (func, obj)) diff --git a/tests/test_utils_reqser.py b/tests/test_utils_reqser.py index 31577bc8c..7f9e31daa 100644 --- a/tests/test_utils_reqser.py +++ b/tests/test_utils_reqser.py @@ -2,9 +2,11 @@ import unittest import sys +import six + from scrapy.http import Request, FormRequest from scrapy.spiders import Spider -from scrapy.utils.reqser import request_to_dict, request_from_dict, _is_private_method +from scrapy.utils.reqser import request_to_dict, request_from_dict, _is_private_method, _mangle_private_name class RequestSerializationTest(unittest.TestCase): @@ -105,6 +107,18 @@ class RequestSerializationTest(unittest.TestCase): self.assertFalse(_is_private_method('___')) self.assertFalse(_is_private_method('____')) + def _assert_mangles_to(self, obj, name): + self.assertEqual( + _mangle_private_name(obj, getattr(obj, name), name), + name + ) + + def test_private_name_mangling(self): + self._assert_mangles_to( + self.spider, '_TestSpider__parse_item_private') + self._assert_mangles_to( + self.spider, '_TestSpiderMixin__mixin_callback') + def test_unserializable_callback1(self): r = Request("http://www.example.com", callback=lambda x: x) self.assertRaises(ValueError, request_to_dict, r)