Make deep copy of fileds from class attr to instance attr (#550)

* Make deep copy of fileds from class attr to instance attr

The fields resource class attribute is the *class-wide* definition of
fields. Because a particular *instance* of the class might want to
alter self.fields, we create self.fields here by copying cls.fields.
Instances should always modify self.fields; they should not modify
cls.fields.

* Update test for resource fields

Test checks that resource instance *fields* attr doesn't refer to attr *fields* of resource class
This commit is contained in:
Andrei Loskutov 2018-05-17 21:37:46 +07:00 committed by Bojan Mihelac
parent 8562268e0f
commit 7045e39425
2 changed files with 45 additions and 6 deletions

View File

@ -192,6 +192,14 @@ class Resource(six.with_metaclass(DeclarativeMetaclass)):
representations and handle importing and exporting data.
"""
def __init__(self):
# The fields class attribute is the *class-wide* definition of
# fields. Because a particular *instance* of the class might want to
# alter self.fields, we create self.fields here by copying cls.fields.
# Instances should always modify self.fields; they should not modify
# cls.fields.
self.fields = deepcopy(self.fields)
@classmethod
def get_result_class(self):
"""
@ -233,16 +241,15 @@ class Resource(six.with_metaclass(DeclarativeMetaclass)):
"""
return [self.fields[f] for f in self.get_export_order()]
@classmethod
def get_field_name(cls, field):
def get_field_name(self, field):
"""
Returns the field name for a given field.
"""
for field_name, f in cls.fields.items():
for field_name, f in self.fields.items():
if f == field:
return field_name
raise AttributeError("Field %s does not exists in %s resource" % (
field, cls))
field, self.__class__))
def init_instance(self, row=None):
raise NotImplementedError()

View File

@ -24,6 +24,11 @@ from ..models import (
WithFloatField,
)
try:
from collections import OrderedDict
except ImportError:
from django.utils.datastructures import SortedDict as OrderedDict
try:
from django.utils.encoding import force_text
except ImportError:
@ -45,8 +50,35 @@ class ResourceTestCase(TestCase):
self.my_resource = MyResource()
def test_fields(self):
fields = self.my_resource.fields
self.assertIn('name', fields)
"""Check that fields were determined correctly """
# check that our fields were determined
self.assertIn('name', self.my_resource.fields)
# check that resource instance fields attr isn't link to resource cls
# fields
self.assertFalse(
MyResource.fields is self.my_resource.fields
)
# dynamically add new resource field into resource instance
self.my_resource.fields.update(
OrderedDict([
('new_field', fields.Field()),
])
)
# check that new field in resource instance fields
self.assertIn(
'new_field',
self.my_resource.fields
)
# check that new field not in resource cls fields
self.assertNotIn(
'new_field',
MyResource.fields
)
def test_field_column_name(self):
field = self.my_resource.fields['name']