From fbb411a805724fec50b786f369be79dc221c798e Mon Sep 17 00:00:00 2001 From: woxcab Date: Mon, 13 Mar 2017 14:16:39 +0300 Subject: [PATCH 1/2] Allowed passing objects of Mapping class or its subclass to the CaselessDict initializer --- scrapy/utils/datatypes.py | 4 ++-- tests/test_utils_datatypes.py | 43 +++++++++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+), 2 deletions(-) diff --git a/scrapy/utils/datatypes.py b/scrapy/utils/datatypes.py index e516185bd..eb373c501 100644 --- a/scrapy/utils/datatypes.py +++ b/scrapy/utils/datatypes.py @@ -8,7 +8,7 @@ This module must not depend on any module outside the Standard Library. import copy import six import warnings -from collections import OrderedDict +from collections import OrderedDict, Mapping from scrapy.exceptions import ScrapyDeprecationWarning @@ -224,7 +224,7 @@ class CaselessDict(dict): return dict.setdefault(self, self.normkey(key), self.normvalue(def_val)) def update(self, seq): - seq = seq.items() if isinstance(seq, dict) else seq + seq = seq.items() if isinstance(seq, Mapping) else seq iseq = ((self.normkey(k), self.normvalue(v)) for k, v in seq) super(CaselessDict, self).update(iseq) diff --git a/tests/test_utils_datatypes.py b/tests/test_utils_datatypes.py index 80f797227..3a4137942 100644 --- a/tests/test_utils_datatypes.py +++ b/tests/test_utils_datatypes.py @@ -1,5 +1,6 @@ import copy import unittest +from collections import Mapping, MutableMapping from scrapy.utils.datatypes import CaselessDict, SequenceExclude @@ -18,6 +19,48 @@ class CaselessDictTest(unittest.TestCase): self.assertEqual(d['red'], 1) self.assertEqual(d['black'], 3) + class MyMapping(Mapping): + def __init__(self, **kwargs): + self._d = kwargs + + def __getitem__(self, key): + return self._d[key] + + def __iter__(self): + return iter(self._d) + + def __len__(self): + return len(self._d) + + seq = MyMapping(red=1, black=3) + d = CaselessDict(seq) + self.assertEqual(d['red'], 1) + self.assertEqual(d['black'], 3) + + class MyMutableMapping(MutableMapping): + def __init__(self, **kwargs): + self._d = kwargs + + def __getitem__(self, key): + return self._d[key] + + def __setitem__(self, key, value): + self._d[key] = value + + def __delitem__(self, key): + del self._d[key] + + def __iter__(self): + return iter(self._d) + + def __len__(self): + return len(self._d) + + seq = MyMutableMapping(red=1, black=3) + d = CaselessDict(seq) + self.assertEqual(d['red'], 1) + self.assertEqual(d['black'], 3) + def test_caseless(self): d = CaselessDict() d['key_Lower'] = 1 From a84652e775fda1135fe959465b27cf6ed2c25e1d Mon Sep 17 00:00:00 2001 From: woxcab Date: Wed, 15 Mar 2017 12:39:48 +0300 Subject: [PATCH 2/2] Init tests are split by initializer' input --- tests/test_utils_datatypes.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/test_utils_datatypes.py b/tests/test_utils_datatypes.py index 3a4137942..49323f0ff 100644 --- a/tests/test_utils_datatypes.py +++ b/tests/test_utils_datatypes.py @@ -8,17 +8,19 @@ __doctests__ = ['scrapy.utils.datatypes'] class CaselessDictTest(unittest.TestCase): - def test_init(self): + def test_init_dict(self): seq = {'red': 1, 'black': 3} d = CaselessDict(seq) self.assertEqual(d['red'], 1) self.assertEqual(d['black'], 3) + def test_init_pair_sequence(self): seq = (('red', 1), ('black', 3)) d = CaselessDict(seq) self.assertEqual(d['red'], 1) self.assertEqual(d['black'], 3) + def test_init_mapping(self): class MyMapping(Mapping): def __init__(self, **kwargs): self._d = kwargs @@ -37,6 +39,7 @@ class CaselessDictTest(unittest.TestCase): self.assertEqual(d['red'], 1) self.assertEqual(d['black'], 3) + def test_init_mutable_mapping(self): class MyMutableMapping(MutableMapping): def __init__(self, **kwargs): self._d = kwargs