Skip to content

Commit

Permalink
Recursive operations by field
Browse files Browse the repository at this point in the history
  • Loading branch information
Toni Marqués committed Jun 13, 2014
1 parent 533c30f commit 46cfcff
Show file tree
Hide file tree
Showing 4 changed files with 230 additions and 1 deletion.
50 changes: 50 additions & 0 deletions dirty_models/model_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -347,3 +347,53 @@ def _update_read_only(self):
value.set_read_only(self.get_read_only())
except AttributeError:
pass

def delete_field_value(self, index):
"""
Function for deleting an element from the list
"""
self.pop(index)

def reset_field_value(self, index):
"""
Function for restoring the old value of an element in the list
"""
if self._modified_data:
self._modified_data[index] = self._original_data[index]
if self._modified_data == self._original_data:
self._modified_data.clear()

def perform_function_by_path(self, field, function):
"""
Function to perform a function to the field specified.
:param field: Field structure as following:
*.subfield_2 would apply the function to the every subfield_2 of the elements
1.subfield_2 would apply the function to the subfield_2 of the element 1
* would apply the function to every element
1 would apply the function to element 1
:field function: string containing the function in the class to be applied to the field
"""
try:
field, next_field = field.split('.', 1)
except ValueError:
next_field = ''

if (field == '*'):
if next_field:
for item in self:
try:
item.perform_function_by_path(next_field, function)
except AttributeError:
return
else:
self.clear()
elif field.isnumeric():
try:
index = int(field)
item = self[index]
except IndexError:
return
try:
item.perform_function_by_path(next_field, function)
except AttributeError:
getattr(self, function)(index)
35 changes: 35 additions & 0 deletions dirty_models/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -384,6 +384,41 @@ def __str__(self):
def get_field_obj(cls, name):
return getattr(cls, name, None)

def perform_function_by_path(self, field, function):
"""
Function to perform a function to the field specified.
:param field: Field structure as following:
field_1.*.subfield_2 would apply a the function to the every subfield_2 of the elements in field_1
field_1.1.subfield_2 would apply a the function to the subfield_2 of the element 1 in field_1
:field function: string containing the function in the class to be applied to the field
"""
try:
field, next_field = field.split('.', 1)
except ValueError:
next_field = ''

obj = self.get_field_value(field)
if isinstance(obj, (ListModel, BaseModel)):
if next_field:
obj.perform_function_by_path(next_field, function)
else:
if not next_field:
getattr(self, function)(field)

def delete_attr_by_path(self, field):
"""
Function for deleting a field specifying the path in the whole model as described
in :func:`dirty:models.models.BaseModel.perform_function_by_path`
"""
self.perform_function_by_path(field, 'delete_field_value')

def reset_attr_by_path(self, field):
"""
Function for restoring a field specifying the path in the whole model as described
in :func:`dirty:models.models.BaseModel.perform_function_by_path`
"""
self.perform_function_by_path(field, 'reset_field_value')


class DynamicModel(BaseModel):

Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
name='dirty-models',
url='https://github.com/alfred82santa/dirty-models',
author='alfred82santa',
version='0.2.14',
version='0.2.15',
author_email='alfred82santa@gmail.com',
classifiers=[
'Intended Audience :: Developers',
Expand Down
144 changes: 144 additions & 0 deletions tests/dirty_models/tests_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -495,6 +495,150 @@ class FakeModel(BaseModel):

self.assertIsInstance(test_field_obj, BaseField)

def test_delete_attr_by_path(self):

class FakeBaseModel(BaseModel):
testBaseField1 = BaseField()
testBaseField2 = IntegerField()

class FakeModel(BaseModel):
testField1 = ModelField(model_class=FakeBaseModel)
testField2 = IntegerField()

data = {'testBaseField1': 'Value1', 'testBaseField2': 19}
model_base_object = FakeBaseModel(data)

data = {'testField1': model_base_object, 'testField2': 11}
model_object = FakeModel(data)

self.assertIsNotNone(model_object.testField1.testBaseField2)
model_object.delete_attr_by_path('testField1.testBaseField2')
self.assertIsNone(model_object.testField1.testBaseField2)

def test_delete_attr_by_path_with_list_model(self):

class EvenMoreFakeBaseModel(BaseModel):
bruceWayneField = IntegerField()

class FakeBaseModel(BaseModel):
testBaseField1 = BaseField()
testBaseField2 = IntegerField()
testBaseField3 = ArrayField(field_type=IntegerField())
testBaseField4 = ArrayField(field_type=ModelField(model_class=EvenMoreFakeBaseModel))

class FakeModel(BaseModel):
testField1 = ModelField(model_class=FakeBaseModel)
testField2 = IntegerField()

data = {'bruceWayneField': 45}
model_1 = EvenMoreFakeBaseModel(data)

data = {'testBaseField1': 'Value1', 'testBaseField2': 19, 'testBaseField3': [11, 12, 14, 'paco'],
'testBaseField4': [model_1]}
model_2 = FakeBaseModel(data)

data = {'testField1': model_2, 'testField2': 11}
model_object = FakeModel(data)
self.assertIsNotNone(model_object.testField1.testBaseField2)
self.assertIsNotNone(model_object.testField1.testBaseField3[2])
self.assertIsNotNone(model_object.testField1.testBaseField4[0].bruceWayneField)
model_object.delete_attr_by_path('testField1.testBaseField2')
model_object.delete_attr_by_path('testField1.testBaseField3.2')
model_object.delete_attr_by_path('testField1.testBaseField4.*.bruceWayneField')
model_object.delete_attr_by_path('testField1.testBaseField3.*.nonExistingField')
self.assertIsNone(model_object.testField1.testBaseField2)
self.assertRaises(IndexError, model_object.testField1.testBaseField3.__getitem__, 2)
self.assertIsNone(model_object.testField1.testBaseField4[0].bruceWayneField)

def test_delete_attr_by_path_whole_list(self):
class EvenMoreFakeBaseModel(BaseModel):
bruceWayneField = IntegerField()

class FakeBaseModel(BaseModel):
testBaseField1 = BaseField()
testBaseField2 = IntegerField()
testBaseField3 = ArrayField(field_type=IntegerField())
testBaseField4 = ArrayField(field_type=ModelField(model_class=EvenMoreFakeBaseModel))

class FakeModel(BaseModel):
testField1 = ModelField(model_class=FakeBaseModel)
testField2 = IntegerField()

data = {'bruceWayneField': 45}
model_1 = EvenMoreFakeBaseModel(data)

data = {'testBaseField1': 'Value1', 'testBaseField2': 19, 'testBaseField3': [11, 12, 14, 'paco'],
'testBaseField4': [model_1]}
model_2 = FakeBaseModel(data)

data = {'testField1': model_2, 'testField2': 11}
model_object = FakeModel(data)
self.assertIsNotNone(model_object.testField1.testBaseField3[2])
self.assertIsNotNone(model_object.testField1.testBaseField4[0].bruceWayneField)
model_object.delete_attr_by_path('testField1.testBaseField3.*')
model_object.delete_attr_by_path('testField1.testBaseField4.0.bruceWayneField')
model_object.delete_attr_by_path('testField1.testBaseField4.3.bruceWayneField')
self.assertEqual(list(model_object.testField1.testBaseField3), [])
self.assertIsNone(model_object.testField1.testBaseField4[0].bruceWayneField)

def test_reset_attr_by_path_with_lists(self):
class EvenMoreFakeBaseModel(BaseModel):
bruceWayneField = IntegerField()

class FakeBaseModel(BaseModel):
testBaseField1 = BaseField()
testBaseField2 = IntegerField()
testBaseField3 = ArrayField(field_type=IntegerField())
testBaseField4 = ArrayField(field_type=ModelField(model_class=EvenMoreFakeBaseModel))

class FakeModel(BaseModel):
testField1 = ModelField(model_class=FakeBaseModel)
testField2 = IntegerField()

data = {'bruceWayneField': 45}
model_1 = EvenMoreFakeBaseModel(data)

data = {'testBaseField1': 'Value1', 'testBaseField2': 19, 'testBaseField3': [11, 12, 14, 'paco'],
'testBaseField4': [model_1]}
model_2 = FakeBaseModel(data)

data = {'testField1': model_2, 'testField2': 11}
model_object = FakeModel(data)

model_object.flat_data()

model_object.testField1.testBaseField3[2] = 25
model_object.testField1.testBaseField4[0].bruceWayneField = 22
self.assertEqual(model_object.testField1.testBaseField3[2], 25)
self.assertEqual(model_object.testField1.testBaseField4[0].bruceWayneField, 22)
model_object.reset_attr_by_path('testField1.testBaseField4.*.bruceWayneField')
model_object.reset_attr_by_path('testField1.testBaseField3.2')
self.assertEqual(model_object.testField1.testBaseField3[2], 14)
self.assertEqual(model_object.testField1.testBaseField4[0].bruceWayneField, 45)

def test_reset_attr_by_path(self):

class FakeBaseModel(BaseModel):
testBaseField1 = BaseField()
testBaseField2 = IntegerField()

class FakeModel(BaseModel):
testField1 = ModelField(model_class=FakeBaseModel)
testField2 = IntegerField()

data = {'testBaseField1': 'Value1', 'testBaseField2': 19}
model_base_object = FakeBaseModel(data)

data = {'testField1': model_base_object, 'testField2': 11}
model_object = FakeModel(data)
model_object.flat_data()

model_object.testField1.testBaseField2 = 22

self.assertEqual(model_object.testField1.testBaseField2, 22)
model_object.reset_attr_by_path('testField1.testBaseField2')
self.assertEqual(model_object.testField1.testBaseField2, 19)


class ModelReadOnly(BaseModel):
testField1 = BaseField()
Expand Down

0 comments on commit 46cfcff

Please sign in to comment.