Skip to content
Snippets Groups Projects
Commit 6a4517e5 authored by Rodrigo Cortes Mejia's avatar Rodrigo Cortes Mejia
Browse files

Merge branch '357-compatibility-to-old-data-schemas' into 'master'

Resolve "Compatibility to old data schemas"

Closes #357

See merge request !275
parents a7f0b295 a2570901
No related branches found
No related tags found
1 merge request!275Resolve "Compatibility to old data schemas"
Pipeline #381957 passed
......@@ -9,6 +9,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/)
## [ 0.5.3] - 2024-11-15
### Added
- **utilities**: add a data schema version compatibility layer ([#357](https://gitlab.kit.edu/kit/virtmat-tools/vre-language/-/issues/357))
- **logos**: add logos for textS and textM ([#353](https://gitlab.kit.edu/kit/virtmat-tools/vre-language/-/issues/353))
- **docs**: add support contact ([#346](https://gitlab.kit.edu/kit/virtmat-tools/vre-language/-/issues/346))
- **amml**: implement NEB and Dimer algorithms ([#302](https://gitlab.kit.edu/kit/virtmat-tools/vre-language/-/issues/302))
......
......@@ -3,7 +3,7 @@ import re
from virtmat.language.utilities.logging import get_logger
versions = {'grammar': [14, 15, 16, 17, 18, 19, 20, 21, 22],
'data_schema': [6]}
'data_schema': [6, 7]}
class CompatibilityError(Exception):
......
......@@ -16,7 +16,31 @@ from .errors import RuntimeTypeError
from .units import ureg
from .lists import list_flatten
DATA_SCHEMA_VERSION = 6
DATA_SCHEMA_VERSION = 7
def versioned_deserialize(func):
"""func must be a *from_dict* method"""
def decorator(cls, dct):
assert isinstance(cls, type) and issubclass(cls, FWSerializable)
assert dct.pop('_fw_name') == getattr(cls, '_fw_name')
assert isinstance(dct, dict)
version = dct.pop('_version', None)
if version == DATA_SCHEMA_VERSION:
return func(cls, dct) # current version
if version is None: # non-tagged is implicitly version 6, to be depricated
return func(cls, dct)
return getattr(cls, f'from_dict_{version}')(cls, dct)
return decorator
def versioned_serialize(func):
"""func must be a *to_dict* method"""
def decorator(*args, **kwargs):
dct = func(*args, **kwargs)
dct['_version'] = DATA_SCHEMA_VERSION
return dct
return decorator
@dataclass
......@@ -29,6 +53,7 @@ class FWDataObject(FWSerializable):
@serialize_fw
@recursive_serialize
@versioned_serialize
def to_dict(self):
if self.datastore is None:
logger = get_fw_logger(__name__)
......@@ -49,8 +74,8 @@ class FWDataObject(FWSerializable):
@classmethod
@recursive_deserialize
@versioned_deserialize
def from_dict(cls, m_dict):
assert cls._fw_name == m_dict['_fw_name']
if 'datastore' in m_dict and m_dict['datastore'] is not None:
if m_dict['datastore']['type'] is None:
return cls(m_dict['value'], m_dict['datastore'])
......@@ -75,13 +100,14 @@ class FWDataFrame(pandas.DataFrame, FWSerializable):
@serialize_fw
@recursive_serialize
def to_dict(self):
@versioned_serialize
def to_dict(self): # pylint: disable=arguments-differ
return {'data': [get_serializable(self[c]) for c in self.columns]}
@classmethod
@recursive_deserialize
def from_dict(cls, m_dict):
assert cls._fw_name == m_dict['_fw_name']
@versioned_deserialize
def from_dict(cls, m_dict): # pylint: disable=arguments-differ
if len(m_dict['data']) == 0:
return cls()
return cls(pandas.concat(m_dict['data'], axis=1))
......@@ -105,7 +131,8 @@ class FWSeries(pandas.Series, FWSerializable):
@serialize_fw
@recursive_serialize
def to_dict(self):
@versioned_serialize
def to_dict(self): # pylint: disable=arguments-differ
if not isinstance(self.dtype, pint_pandas.PintType):
return {'name': self.name, 'data': get_serializable(self.tolist()),
'datatype': str(self.dtype)}
......@@ -119,8 +146,8 @@ class FWSeries(pandas.Series, FWSerializable):
@classmethod
@recursive_deserialize
@versioned_deserialize
def from_dict(cls, m_dict):
assert cls._fw_name == m_dict['_fw_name']
datatype = m_dict['datatype']
if datatype in ('int', 'float'):
dtype = pint_pandas.PintType(m_dict.get('units', 'dimensionless'))
......@@ -138,14 +165,15 @@ class FWQuantity(FWSerializable, ureg.Quantity):
@serialize_fw
@recursive_serialize
@versioned_serialize
def to_dict(self):
mag, unit = self.to_tuple()
return {'data': (get_serializable(mag), unit)}
@classmethod
@recursive_deserialize
@versioned_deserialize
def from_dict(cls, m_dict):
assert m_dict['_fw_name'] == cls._fw_name
assert isinstance(m_dict['data'], (list, tuple))
mag, unit = m_dict['data']
if isinstance(mag, (int, float)):
......@@ -170,13 +198,14 @@ class FWBoolArray(numpy.ndarray, FWSerializable):
@serialize_fw
@recursive_serialize
@versioned_serialize
def to_dict(self):
return {'data': self.tolist()}
@classmethod
@recursive_deserialize
@versioned_deserialize
def from_dict(cls, m_dict):
assert m_dict['_fw_name'] == cls._fw_name
assert isinstance(m_dict['data'], list)
assert all(isinstance(e, bool) for e in list_flatten(m_dict['data']))
return cls(m_dict['data'])
......@@ -191,13 +220,14 @@ class FWStrArray(numpy.ndarray, FWSerializable):
@serialize_fw
@recursive_serialize
@versioned_serialize
def to_dict(self):
return {'data': self.tolist()}
@classmethod
@recursive_deserialize
@versioned_deserialize
def from_dict(cls, m_dict):
assert m_dict['_fw_name'] == cls._fw_name
assert isinstance(m_dict['data'], list)
assert all(isinstance(e, str) for e in list_flatten(m_dict['data']))
return cls(m_dict['data'])
......@@ -209,6 +239,7 @@ class FWNumArray(FWSerializable, ureg.Quantity):
@serialize_fw
@recursive_serialize
@versioned_serialize
def to_dict(self):
tpl = self.to_tuple()
return {'data': (tpl[0].tolist(), tpl[1]),
......@@ -216,8 +247,8 @@ class FWNumArray(FWSerializable, ureg.Quantity):
@classmethod
@recursive_deserialize
@versioned_deserialize
def from_dict(cls, m_dict):
assert m_dict['_fw_name'] == cls._fw_name
array = numpy.array(m_dict['data'][0], dtype=m_dict['dtype'])
return super().from_tuple((array, m_dict['data'][1]))
......@@ -233,13 +264,14 @@ class FWAMMLStructure(amml.AMMLStructure, FWSerializable):
@serialize_fw
@recursive_serialize
@versioned_serialize
def to_dict(self):
return {'data': get_serializable(self.tab), 'name': self.name}
@classmethod
@recursive_deserialize
@versioned_deserialize
def from_dict(cls, m_dict):
assert m_dict['_fw_name'] == cls._fw_name
return cls(m_dict['data'], m_dict['name'])
@classmethod
......@@ -255,13 +287,14 @@ class FWCalculator(amml.Calculator, FWSerializable):
@serialize_fw
@recursive_serialize
@versioned_serialize
def to_dict(self):
return {k: get_serializable(getattr(self, k)) for k in self._keys}
@classmethod
@recursive_deserialize
@versioned_deserialize
def from_dict(cls, m_dict):
assert cls._fw_name == m_dict.pop('_fw_name')
return cls(**m_dict)
@classmethod
......@@ -277,13 +310,14 @@ class FWAlgorithm(amml.Algorithm, FWSerializable):
@serialize_fw
@recursive_serialize
@versioned_serialize
def to_dict(self):
return {k: get_serializable(getattr(self, k)) for k in self._keys}
@classmethod
@recursive_deserialize
@versioned_deserialize
def from_dict(cls, m_dict):
assert cls._fw_name == m_dict.pop('_fw_name')
return cls(**m_dict)
@classmethod
......@@ -299,13 +333,14 @@ class FWProperty(amml.Property, FWSerializable):
@serialize_fw
@recursive_serialize
@versioned_serialize
def to_dict(self):
return {k: get_serializable(getattr(self, k)) for k in self._keys}
@classmethod
@recursive_deserialize
@versioned_deserialize
def from_dict(cls, m_dict):
assert cls._fw_name == m_dict.pop('_fw_name')
return cls(**m_dict)
@classmethod
......@@ -321,14 +356,15 @@ class FWConstraint(amml.Constraint, FWSerializable):
@serialize_fw
@recursive_serialize
@versioned_serialize
def to_dict(self):
ser_kwargs = {k: get_serializable(v) for k, v in self.kwargs.items()}
return {'name': self.name, **ser_kwargs}
@classmethod
@recursive_deserialize
@versioned_deserialize
def from_dict(cls, m_dict):
assert cls._fw_name == m_dict.pop('_fw_name')
return cls(**m_dict)
@classmethod
......@@ -344,13 +380,14 @@ class FWTrajectory(amml.Trajectory, FWSerializable):
@serialize_fw
@recursive_serialize
@versioned_serialize
def to_dict(self):
return {k: get_serializable(getattr(self, k)) for k in self._keys}
@classmethod
@recursive_deserialize
@versioned_deserialize
def from_dict(cls, m_dict):
assert cls._fw_name == m_dict.pop('_fw_name')
return cls(**m_dict)
@classmethod
......@@ -367,13 +404,14 @@ class FWChemSpecies(chemistry.ChemSpecies, FWSerializable):
@serialize_fw
@recursive_serialize
@versioned_serialize
def to_dict(self):
return {k: get_serializable(getattr(self, k)) for k in self._keys}
@classmethod
@recursive_deserialize
@versioned_deserialize
def from_dict(cls, m_dict):
assert cls._fw_name == m_dict.pop('_fw_name')
return cls(**m_dict)
@classmethod
......@@ -390,13 +428,14 @@ class FWChemReaction(chemistry.ChemReaction, FWSerializable):
@serialize_fw
@recursive_serialize
@versioned_serialize
def to_dict(self):
return {k: get_serializable(getattr(self, k)) for k in self._keys}
@classmethod
@recursive_deserialize
@versioned_deserialize
def from_dict(cls, m_dict):
assert cls._fw_name == m_dict.pop('_fw_name')
return cls(**m_dict)
@classmethod
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment