mirror of https://github.com/scrapy/scrapy.git
Item multi inherit fixed
This commit is contained in:
parent
0a5bbbaed3
commit
7871acd665
|
|
@ -24,18 +24,21 @@ class Field(dict):
|
|||
class ItemMeta(ABCMeta):
|
||||
|
||||
def __new__(mcs, class_name, bases, attrs):
|
||||
new_bases = tuple(base._class for base in bases if hasattr(base, '_class'))
|
||||
_class = super(ItemMeta, mcs).__new__(mcs, 'x_' + class_name, new_bases, attrs)
|
||||
|
||||
fields = {}
|
||||
new_attrs = {}
|
||||
for n, v in six.iteritems(attrs):
|
||||
for n in dir(_class):
|
||||
v = getattr(_class, n)
|
||||
if isinstance(v, Field):
|
||||
fields[n] = v
|
||||
else:
|
||||
new_attrs[n] = v
|
||||
elif n in attrs:
|
||||
new_attrs[n] = attrs[n]
|
||||
|
||||
cls = super(ItemMeta, mcs).__new__(mcs, class_name, bases, new_attrs)
|
||||
cls.fields = cls.fields.copy()
|
||||
cls.fields.update(fields)
|
||||
return cls
|
||||
new_attrs['fields'] = fields
|
||||
new_attrs['_class'] = _class
|
||||
return super(ItemMeta, mcs).__new__(mcs, class_name, bases, new_attrs)
|
||||
|
||||
|
||||
class DictItem(MutableMapping, BaseItem):
|
||||
|
|
|
|||
|
|
@ -134,6 +134,76 @@ class ItemTest(unittest.TestCase):
|
|||
self.assertEqual(list(i.keys()), ['keys'])
|
||||
self.assertEqual(list(i.values()), [3])
|
||||
|
||||
def test_metaclass_multiple_inheritance_simple(self):
|
||||
class A(Item):
|
||||
save = Field(default='A')
|
||||
|
||||
class B(A): pass
|
||||
|
||||
class C(Item):
|
||||
save = Field(default='C')
|
||||
|
||||
class D(B, C): pass
|
||||
|
||||
self.assertEqual(D(save='X')['save'], 'X')
|
||||
self.assertEqual(D.fields, {'save': {'default': 'A'}})
|
||||
|
||||
# D class inverted
|
||||
class E(C, B): pass
|
||||
|
||||
self.assertEqual(E(save='X')['save'], 'X')
|
||||
self.assertEqual(E.fields, {'save': {'default': 'C'}})
|
||||
|
||||
def test_metaclass_multiple_inheritance_diamond(self):
|
||||
class A(Item):
|
||||
save = Field(default='A')
|
||||
load = Field(default='A')
|
||||
|
||||
class B(A): pass
|
||||
|
||||
class C(A):
|
||||
save = Field(default='C')
|
||||
|
||||
class D(B, C):
|
||||
load = Field(default='D')
|
||||
|
||||
self.assertEqual(D(save='X')['save'], 'X')
|
||||
self.assertEqual(D(load='X')['load'], 'X')
|
||||
self.assertEqual(D.fields, {'save': {'default': 'C'},
|
||||
'load': {'default': 'D'}})
|
||||
|
||||
# D class inverted
|
||||
class E(C, B):
|
||||
load = Field(default='E')
|
||||
|
||||
self.assertEqual(E(save='X')['save'], 'X')
|
||||
self.assertEqual(E(load='X')['load'], 'X')
|
||||
self.assertEqual(E.fields, {'save': {'default': 'C'},
|
||||
'load': {'default': 'E'}})
|
||||
|
||||
def test_metaclass_multiple_inheritance_without_metaclass(self):
|
||||
class A(Item):
|
||||
save = Field(default='A')
|
||||
|
||||
class B(A): pass
|
||||
|
||||
class C(object):
|
||||
not_allowed = Field(default='not_allowed')
|
||||
save = Field(default='C')
|
||||
|
||||
class D(B, C): pass
|
||||
|
||||
self.assertRaises(KeyError, D, not_allowed='value')
|
||||
self.assertEqual(D(save='X')['save'], 'X')
|
||||
self.assertEqual(D.fields, {'save': {'default': 'A'}})
|
||||
|
||||
# D class inverted
|
||||
class E(C, B): pass
|
||||
|
||||
self.assertRaises(KeyError, E, not_allowed='value')
|
||||
self.assertEqual(E(save='X')['save'], 'X')
|
||||
self.assertEqual(E.fields, {'save': {'default': 'A'}})
|
||||
|
||||
def test_to_dict(self):
|
||||
class TestItem(Item):
|
||||
name = Field()
|
||||
|
|
|
|||
Loading…
Reference in New Issue