summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBojan Mihelac <bmihelac@mihelac.org>2015-04-22 11:48:39 (GMT)
committerBojan Mihelac <bmihelac@mihelac.org>2015-04-22 11:48:39 (GMT)
commitc2b59b43637d726784c69955a46a441f0658ab7d (patch)
tree6d3254b6d1cf9db8fec55fe2b2e510615d26e3b2
parent3cb8bc6bae959cbd0f0bb28738dd23773a23abde (diff)
parent8b4c64904fbb91d47bc2879e1b95728c6ff9ee28 (diff)
downloaddjango-import-export-c2b59b43637d726784c69955a46a441f0658ab7d.zip
django-import-export-c2b59b43637d726784c69955a46a441f0658ab7d.tar.gz
django-import-export-c2b59b43637d726784c69955a46a441f0658ab7d.tar.bz2
Merge pull request #247 from rhunwicks/fix-140-attribute_inheritance
Fix #140 attribute inheritance
-rw-r--r--import_export/resources.py35
-rw-r--r--tests/core/tests/resources_tests.py35
2 files changed, 57 insertions, 13 deletions
diff --git a/import_export/resources.py b/import_export/resources.py
index 5836a7b..e0f8b6e 100644
--- a/import_export/resources.py
+++ b/import_export/resources.py
@@ -94,22 +94,26 @@ class ResourceOptions(object):
skip_unchanged = False
report_skipped = True
- def __new__(cls, meta=None):
- overrides = {}
-
- if meta:
- for override_name in dir(meta):
- if not override_name.startswith('_'):
- overrides[override_name] = getattr(meta, override_name)
-
- return object.__new__(type(str('ResourceOptions'), (cls,), overrides))
-
class DeclarativeMetaclass(type):
def __new__(cls, name, bases, attrs):
declared_fields = []
-
+ meta = ResourceOptions()
+
+ # If this class is subclassing another Resource, add that Resource's fields.
+ # Note that we loop over the bases in *reverse*. This is necessary in
+ # order to preserve the correct order of fields.
+ for base in bases[::-1]:
+ if hasattr(base, 'fields'):
+ declared_fields = list(six.iteritems(base.fields)) + declared_fields
+ # Collect the Meta options
+ options = getattr(base, 'Meta', None)
+ for option in [option for option in dir(options)
+ if not option.startswith('_')]:
+ setattr(meta, option, getattr(options, option))
+
+ # Add direct fields
for field_name, obj in attrs.copy().items():
if isinstance(obj, Field):
field = attrs.pop(field_name)
@@ -120,8 +124,13 @@ class DeclarativeMetaclass(type):
attrs['fields'] = OrderedDict(declared_fields)
new_class = super(DeclarativeMetaclass, cls).__new__(cls, name,
bases, attrs)
- opts = getattr(new_class, 'Meta', None)
- new_class._meta = ResourceOptions(opts)
+
+ # Add direct options
+ options = getattr(new_class, 'Meta', None)
+ for option in [option for option in dir(options)
+ if not option.startswith('_')]:
+ setattr(meta, option, getattr(options, option))
+ new_class._meta = meta
return new_class
diff --git a/tests/core/tests/resources_tests.py b/tests/core/tests/resources_tests.py
index 4481fde..7c74392 100644
--- a/tests/core/tests/resources_tests.py
+++ b/tests/core/tests/resources_tests.py
@@ -60,6 +60,41 @@ class ResourceTestCase(TestCase):
self.assertEqual(self.my_resource.get_export_headers(),
['email', 'name', 'extra'])
+ # Issue 140 Attributes aren't inherited by subclasses
+ def test_inheritance(self):
+ class A(MyResource):
+ inherited = fields.Field()
+
+ class Meta:
+ import_id_fields = ('email',)
+
+ class B(A):
+ local = fields.Field()
+
+ class Meta:
+ export_order = ('email', 'extra')
+
+ resource = B()
+ self.assertIn('name', resource.fields)
+ self.assertIn('inherited', resource.fields)
+ self.assertIn('local', resource.fields)
+ self.assertEqual(resource.get_export_headers(),
+ ['email', 'extra', 'name', 'inherited', 'local'])
+ self.assertEqual(resource._meta.import_id_fields, ('email',))
+
+ def test_inheritance_with_custom_attributes(self):
+ class A(MyResource):
+ inherited = fields.Field()
+
+ class Meta:
+ import_id_fields = ('email',)
+ custom_attribute = True
+
+ class B(A):
+ local = fields.Field()
+
+ resource = B()
+ self.assertEqual(resource._meta.custom_attribute, True)
class BookResource(resources.ModelResource):
published = fields.Field(column_name='published_date')