from __future__ import print_function
from __future__ import absolute_import
from __future__ import division
import json
__all__ = ['DataDecoder', 'DataEncoder']
def cls_from_dtype(dtype):
"""Get the class object corresponding to a COMPAS data type specification.
Parameters
----------
dtype : str
The data type of the COMPAS object in the following format:
'{}/{}'.format(o.__class__.__module__, o.__class__.__name__).
Returns
-------
:class:`compas.base.Base`
Raises
------
ValueError
If the data type is not in the correct format.
ImportError
If the module can't be imported.
AttributeError
If the module doesn't contain the specified data type.
"""
mod_name, attr_name = dtype.split('/')
module = __import__(mod_name, fromlist=[attr_name])
return getattr(module, attr_name)
class DecoderError(Exception):
pass
[docs]class DataEncoder(json.JSONEncoder):
"""Data encoder for custom JSON serialisation with support for COMPAS data structures and geometric primitives.
Notes
-----
In the context of Remote Procedure Calls,
"""
[docs] def default(self, o):
try:
value = o.to_data()
except AttributeError:
pass
else:
return {
'dtype': "{}/{}".format(".".join(o.__class__.__module__.split(".")[:2]), o.__class__.__name__),
'value': value}
try:
import numpy as np
except ImportError:
pass
else:
if isinstance(o, np.ndarray):
return o.tolist()
if isinstance(o, (np.int32, np.int64)):
return int(o)
if isinstance(o, (np.float32, np.float64)):
return float(o)
elif isinstance(o, (np.int_, np.intc, np.intp, np.int8,
np.int16, np.int32, np.int64, np.uint8,
np.uint16, np.uint32, np.uint64)):
return int(o)
elif isinstance(o, (np.float_, np.float16, np.float32, np.float64)):
return float(o)
elif isinstance(o, np.bool_):
return bool(o)
elif isinstance(o, np.void):
return None
return super(DataEncoder, self).default(o)
[docs]class DataDecoder(json.JSONDecoder):
"""Data decoder for custom JSON serialisation with support for COMPAS data structures and geometric primitives."""
[docs] def __init__(self, *args, **kwargs):
super(DataDecoder, self).__init__(object_hook=self.object_hook, *args, **kwargs)
[docs] def object_hook(self, o):
if 'dtype' not in o:
return o
try:
cls = cls_from_dtype(o['dtype'])
except ValueError:
raise DecoderError("The data type of the object should be in the following format: '{}/{}'.format(o.__class__.__module__, o.__class__.__name__)")
except ImportError:
raise DecoderError("The module of the data type can't be found.")
except AttributeError:
raise DecoderError("The data type can't be found in the specified module.")
return cls.from_data(o['value'])
# ==============================================================================
# Main
# ==============================================================================
if __name__ == '__main__':
pass