diff --git a/scrapy/item.py b/scrapy/item.py index ff1c7363d..ec41b212d 100644 --- a/scrapy/item.py +++ b/scrapy/item.py @@ -5,7 +5,8 @@ See documentation in docs/topics/item.rst """ from pprint import pformat -from UserDict import DictMixin +from collections import MutableMapping +from abc import ABCMeta import six from scrapy.utils.trackref import object_ref @@ -20,7 +21,7 @@ class Field(dict): """Container of field metadata""" -class ItemMeta(type): +class ItemMeta(ABCMeta): def __new__(mcs, class_name, bases, attrs): fields = {} @@ -37,7 +38,7 @@ class ItemMeta(type): return cls -class DictItem(DictMixin, BaseItem): +class DictItem(MutableMapping, BaseItem): fields = {} @@ -71,6 +72,19 @@ class DictItem(DictMixin, BaseItem): (name, value)) super(DictItem, self).__setattr__(name, value) + def __len__(self): + return len(self._values) + + def __iter__(self): + for i in getattr(self, "_values", ()): + yield i + + def __hash__(self): + if hasattr(self, "_values"): + return hash(frozenset(self._values.items())) + else: + return 1 + def keys(self): return self._values.keys() @@ -81,6 +95,5 @@ class DictItem(DictMixin, BaseItem): return self.__class__(self) -class Item(DictItem): - - __metaclass__ = ItemMeta +class Item(six.with_metaclass(ItemMeta, DictItem)): + pass diff --git a/scrapy/tests/test_item.py b/scrapy/tests/test_item.py index 2a24fddca..5de77d22e 100644 --- a/scrapy/tests/test_item.py +++ b/scrapy/tests/test_item.py @@ -1,6 +1,7 @@ import unittest from scrapy.item import Item, Field +import six class ItemTest(unittest.TestCase): @@ -52,8 +53,13 @@ class ItemTest(unittest.TestCase): i['name'] = u'John Doe' i['number'] = 123 itemrepr = repr(i) - self.assertEqual(itemrepr, - "{'name': u'John Doe', 'number': 123}") + + if six.PY2: + self.assertEqual(itemrepr, + "{'name': u'John Doe', 'number': 123}") + else: + self.assertEqual(itemrepr, + "{'name': 'John Doe', 'number': 123}") i2 = eval(itemrepr) self.assertEqual(i2['name'], 'John Doe') @@ -106,13 +112,13 @@ class ItemTest(unittest.TestCase): i = TestItem() i['name'] = u'John' - self.assertEqual(i.keys(), ['name']) - self.assertEqual(i.values(), ['John']) + self.assertEqual(list(i.keys()), ['name']) + self.assertEqual(list(i.values()), ['John']) i['keys'] = u'Keys' i['values'] = u'Values' - self.assertSortedEqual(i.keys(), ['keys', 'values', 'name']) - self.assertSortedEqual(i.values(), [u'Keys', u'Values', u'John']) + self.assertSortedEqual(list(i.keys()), ['keys', 'values', 'name']) + self.assertSortedEqual(list(i.values()), [u'Keys', u'Values', u'John']) def test_metaclass_inheritance(self): class BaseItem(Item): @@ -125,8 +131,8 @@ class ItemTest(unittest.TestCase): i = TestItem() i['keys'] = 3 - self.assertEqual(i.keys(), ['keys']) - self.assertEqual(i.values(), [3]) + self.assertEqual(list(i.keys()), ['keys']) + self.assertEqual(list(i.values()), [3]) def test_to_dict(self): class TestItem(Item):