Skip to content

Commit

Permalink
Merge pull request #247 from rhunwicks/fix-140-attribute_inheritance
Browse files Browse the repository at this point in the history
Fix #140 attribute inheritance
  • Loading branch information
bmihelac committed Apr 22, 2015
2 parents 3cb8bc6 + 8b4c649 commit c2b59b4
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 13 deletions.
35 changes: 22 additions & 13 deletions import_export/resources.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -120,8 +124,13 @@ def __new__(cls, name, bases, attrs):
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

Expand Down
35 changes: 35 additions & 0 deletions tests/core/tests/resources_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,41 @@ def test_get_export_order(self):
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')
Expand Down

0 comments on commit c2b59b4

Please sign in to comment.