Skip to content
This repository has been archived by the owner on Apr 23, 2021. It is now read-only.

Commit

Permalink
Merge pull request #335 from simphony/copying-data-container
Browse files Browse the repository at this point in the history
Copying data container
  • Loading branch information
mehdisadeghi committed Nov 2, 2016
2 parents a1e08ff + 862d083 commit 2b6e5f7
Show file tree
Hide file tree
Showing 104 changed files with 1,852 additions and 2,180 deletions.
64 changes: 40 additions & 24 deletions scripts/generate.py
Original file line number Diff line number Diff line change
Expand Up @@ -393,10 +393,20 @@ def parents(cls):
def populate_user_variable_code(self):
''' Populate code for user-defined attributes '''

for key, contents in chain(self.inherited_required.items(),
self.required_user_defined.items(),
self.inherited_optional.items(),
self.optional_user_defined.items()):
# populate them in reverse, because we want the root base class
# attributes filled at the very end. This is to prevent
# data to be overwritten by the defaults
for key, contents in chain(
reversed(list(chain(
self.inherited_required.items(),
self.required_user_defined.items()
))
),
reversed(list(chain(
self.inherited_optional.items(),
self.optional_user_defined.items()
)),
)):
if hasattr(self, 'populate_'+key):
getattr(self, 'populate_'+key)(contents)
continue
Expand Down Expand Up @@ -489,12 +499,20 @@ def populate_setter(self, key, check_statements=()):
# If the key is a CUBA key, store it in the DataContainer
cuba_key = 'CUBA.'+key.upper()
if cuba_key in self.class_data:
target = 'self.data[{cuba_key}]'.format(cuba_key=cuba_key)
self.methods.append('''
@{key}.setter
def {key}(self, value):
{validation_code}
data = self.data
data[{cuba_key}] = value
self.data = data'''.format(key=key,
cuba_key=cuba_key,
validation_code=validation_code))
else:
target = 'self._{key}'.format(key=key)

# default property setter
self.methods.append('''
# default property setter
self.methods.append('''
@{key}.setter
def {key}(self, value):
{validation_code}
Expand Down Expand Up @@ -628,7 +646,10 @@ def populate_data(self, contents):
self.imports.append(IMPORT_PATHS['DataContainer'])

self.init_body.append('''if data:
self.data = data''')
internal_data = self.data
internal_data.update(data)
self.data = internal_data
''')

self.methods.append('''
@property
Expand All @@ -637,22 +658,16 @@ def data(self):
data_container = self._data
except AttributeError:
self._data = DataContainer()
return self._data
else:
# One more check in case the
# property setter is by-passed
if not isinstance(data_container, DataContainer):
raise TypeError("data is not a DataContainer. "
"data.setter is by-passed.")
return data_container''')
data_container = self._data
return DataContainer(data_container)
''')

self.methods.append('''
@data.setter
def data(self, new_data):
if isinstance(new_data, DataContainer):
self._data = new_data
else:
self._data = DataContainer(new_data)''')
self._data = DataContainer(new_data)
''')

def collect_parents_to_mro(self, generators):
''' Recursively collect all the inherited into CodeGenerator.mro
Expand Down Expand Up @@ -713,7 +728,7 @@ def collect_attributes_from_parents(self, generators):
'inherited_optional': 'optional_user_defined',
'inherited_sys_vars': 'system_variables'}

for parent_name in self.mro:
for parent_name in reversed(self.mro):
parent = generators[parent_name]

# Update the known attribute
Expand Down Expand Up @@ -814,8 +829,10 @@ def generate_initializer(self, file_out):
'''
# __init__ keyword arguments
kwargs = []
for key, content in chain(self.inherited_optional.items(),
self.optional_user_defined.items()):
for key, content in chain(
self.inherited_optional.items(),
self.optional_user_defined.items(),
):
# Since it is optional, it must have a default entry
# However if the default value is a CUBA key,
# we set it to None in the init
Expand Down Expand Up @@ -905,7 +922,6 @@ def meta_class(yaml_file, out_path, overwrite):
with make_temporary_directory() as temp_dir:

for key, class_data in yml_data['CUDS_KEYS'].items():

# Catch inconsistent definitions that would choke the generator
parent = class_data['parent']
if (parent and
Expand Down
37 changes: 37 additions & 0 deletions scripts/tests/test_meta_class.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import uuid

from simphony.api import CUBA
from simphony.core import DataContainer
from simphony.cuds.meta import api as meta_class


Expand Down Expand Up @@ -126,6 +127,17 @@ def test_all_inherit_cuds_item(self):
if errors:
self.fail('\n'.join(errors))

def test_initialization_with_data(self):
errors = []

for name, klass in self.no_required_args_classes:
meta_obj = klass(data=DataContainer(NAME="foobar"))
self.check_cuds_item(meta_obj)
self.assertEqual(meta_obj.data[CUBA.NAME], "foobar")

if errors:
self.fail('\n'.join(errors))

def test_cuds_components_properties(self):
''' Test the properties of CUDSComponent '''
for name, klass in self.no_required_args_classes:
Expand Down Expand Up @@ -325,6 +337,31 @@ def test_Box(self):
arr = box.vector == numpy.array([[0, 0, 0], [0, 0, 0], [0, 0, 0]])
self.assertTrue(arr.all())

def test_Berendsen(self):
material = meta_class.Material()
berendsen = meta_class.Berendsen(material=[material])

self.assertIsNotNone(berendsen.material)

def test_IntegrationStep(self):
integration_step = meta_class.IntegrationStep(10, 10)
self.assertIsNotNone(integration_step.data)

def test_TemperatureRescaling(self):
material = meta_class.Material()
temp_rescaling = meta_class.TemperatureRescaling([material])
self.assertIsNotNone(temp_rescaling.data)

def test_Thermostat(self):
material = meta_class.Material()
thermostat = meta_class.Thermostat([material])
self.assertIsNotNone(thermostat.data)

def test_NoseHooverBoundary(self):
material = meta_class.Material()
nose_hoover = meta_class.NoseHoover([material])
self.assertIsNotNone(nose_hoover.data)

def test_not_sharing_mutable(self):
box1 = meta_class.Box()
box2 = meta_class.Box()
Expand Down
23 changes: 0 additions & 23 deletions simphony/core/data_container.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,29 +33,6 @@ def __init__(self, *args, **kwargs):

self.update(*args, **kwargs)

@classmethod
def new_with_restricted_keys(cls, restricted_keys):
"""Instantiate a DataContainer with the given restricted keys
Parameters
----------
restricted_keys : sequence
CUBA IntEnum
Returns
-------
new instance of DataContainer.
"""
# Make sure all restricted keys are CUBA keys
if any(not isinstance(key, CUBA) for key in restricted_keys):
raise ValueError('All restricted keys should be CUBA IntEnum')

self = super(DataContainer, cls).__new__(cls)
self.restricted_keys = frozenset(restricted_keys)
self._restricted_mapping = {key.name: key for key in restricted_keys}

return self

def __setitem__(self, key, value):
""" Set/Update the key value only when the key is a CUBA key.
Expand Down
10 changes: 0 additions & 10 deletions simphony/core/tests/test_data_container.py
Original file line number Diff line number Diff line change
Expand Up @@ -147,16 +147,6 @@ def test_setitem_with_non_cuba_key(self):
with self.assertRaises(ValueError):
container[100] = 29

def test_new_with_restricted_keys(self):
restricted_keys = frozenset([CUBA.UUID, CUBA.NAME])
container = DataContainer.new_with_restricted_keys(restricted_keys)
self.assertEqual(container.restricted_keys, restricted_keys)

container[CUBA.NAME] = "foo"

with self.assertRaises(ValueError):
container[CUBA.DESCRIPTION] = "hello"


if __name__ == '__main__':
unittest.main()
47 changes: 22 additions & 25 deletions simphony/cuds/meta/atom.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,47 +11,44 @@ class Atom(Particle):

cuba_key = CUBA.ATOM

def __init__(self, position=None, data=None, mass=1.0):
def __init__(self, data=None, position=None, mass=1.0):

self.mass = mass
if position is None:
self.position = [0, 0, 0]
if data:
self.data = data
self.mass = mass
internal_data = self.data
internal_data.update(data)
self.data = internal_data

# This is a system-managed, read-only attribute
self._definition = 'An atom' # noqa

@property
def mass(self):
return self.data[CUBA.MASS]

@mass.setter
def mass(self, value):
value = validation.cast_data_type(value, 'mass')
validation.validate_cuba_keyword(value, 'mass')
data = self.data
data[CUBA.MASS] = value
self.data = data

@property
def data(self):
try:
data_container = self._data
except AttributeError:
self._data = DataContainer()
return self._data
else:
# One more check in case the
# property setter is by-passed
if not isinstance(data_container, DataContainer):
raise TypeError("data is not a DataContainer. "
"data.setter is by-passed.")
return data_container
data_container = self._data

return DataContainer(data_container)

@data.setter
def data(self, new_data):
if isinstance(new_data, DataContainer):
self._data = new_data
else:
self._data = DataContainer(new_data)

@property
def mass(self):
return self.data[CUBA.MASS]

@mass.setter
def mass(self, value):
value = validation.cast_data_type(value, 'mass')
validation.validate_cuba_keyword(value, 'mass')
self.data[CUBA.MASS] = value
self._data = DataContainer(new_data)

@property
def definition(self):
Expand Down
25 changes: 10 additions & 15 deletions simphony/cuds/meta/atomistic.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,15 @@ class Atomistic(ComputationalModel):

cuba_key = CUBA.ATOMISTIC

def __init__(self, description=None, name=None, data=None):
def __init__(self, data=None, description=None, name=None):

self.description = description
self.name = name
self.description = description
if data:
self.data = data
internal_data = self.data
internal_data.update(data)
self.data = internal_data

# This is a system-managed, read-only attribute
self._definition = 'Atomistic model category according to the RoMM' # noqa

Expand All @@ -25,21 +28,13 @@ def data(self):
data_container = self._data
except AttributeError:
self._data = DataContainer()
return self._data
else:
# One more check in case the
# property setter is by-passed
if not isinstance(data_container, DataContainer):
raise TypeError("data is not a DataContainer. "
"data.setter is by-passed.")
return data_container
data_container = self._data

return DataContainer(data_container)

@data.setter
def data(self, new_data):
if isinstance(new_data, DataContainer):
self._data = new_data
else:
self._data = DataContainer(new_data)
self._data = DataContainer(new_data)

@property
def definition(self):
Expand Down
27 changes: 11 additions & 16 deletions simphony/cuds/meta/base_centered_monoclinic_lattice.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,21 @@ class BaseCenteredMonoclinicLattice(BravaisLattice):

def __init__(self,
primitive_cell,
lattice_parameter=None,
data=None,
description=None,
name=None,
data=None):
lattice_parameter=None):

self.primitive_cell = primitive_cell
if lattice_parameter is None:
self.lattice_parameter = [1.0, 1.0, 1.0]
self.description = description
self.name = name
self.description = description
if data:
self.data = data
internal_data = self.data
internal_data.update(data)
self.data = internal_data

# This is a system-managed, read-only attribute
self._definition = 'A base centered monoclinic lattice' # noqa
# This is a system-managed, read-only attribute
Expand All @@ -37,21 +40,13 @@ def data(self):
data_container = self._data
except AttributeError:
self._data = DataContainer()
return self._data
else:
# One more check in case the
# property setter is by-passed
if not isinstance(data_container, DataContainer):
raise TypeError("data is not a DataContainer. "
"data.setter is by-passed.")
return data_container
data_container = self._data

return DataContainer(data_container)

@data.setter
def data(self, new_data):
if isinstance(new_data, DataContainer):
self._data = new_data
else:
self._data = DataContainer(new_data)
self._data = DataContainer(new_data)

@property
def definition(self):
Expand Down

0 comments on commit 2b6e5f7

Please sign in to comment.