Source code for yggdrasil.communication.transforms.MapTransform
import copy
import numpy as np
from yggdrasil import rapidjson
from yggdrasil.communication.transforms.TransformBase import TransformBase
[docs]class MapTransform(TransformBase):
r"""Class for transforming an object into a dictionary.
Args:
field_names (list, optional): A list of field names that should
be used for array object. If not provided, names will be
generated according to 'f0', 'f1', 'f2', etc.
"""
_transformtype = 'map'
_schema_subtype_description = "Convert an object into a dictionary."
_schema_properties = {'field_names': {'type': 'array',
'items': {'type': 'string'}}}
def _get_field_names(self, N):
if self.field_names:
return self.field_names
elif (self.original_datatype
and self.original_datatype['type'] == 'array'
and isinstance(self.original_datatype['items'], list)):
out = [x.get('title', False) for x in
self.original_datatype['items']]
if all(out):
return out
return [f'f{i}' for i in range(N)]
[docs] def transform_datatype(self, datatype):
r"""Determine the datatype that will result from applying the
transform to the supplied datatype.
Args:
datatype (dict): Datatype to transform.
Returns:
dict: Transformed datatype.
"""
out = {'type': 'object'}
if datatype.get('type', None) == 'array':
if isinstance(datatype.get('items', None), list):
field_names = self._get_field_names(
len(datatype['items']))
out['properties'] = {}
for i, x in enumerate(datatype['items']):
out['properties'][x.get('title', field_names[i])] = (
copy.deepcopy(x))
elif isinstance(datatype.get('items', None), dict):
out['additionalProperties'] = copy.deepcopy(
datatype['items'])
elif datatype.get('type', None) in ['object', 'schema']:
out = copy.deepcopy(datatype)
elif datatype.get('type', None) in ['any', 'ply', 'obj']:
pass
else:
field_names = self._get_field_names(1)
out['properties'] = {field_names[0]: copy.deepcopy(datatype)}
return out
[docs] def evaluate_transform(self, x, no_copy=False):
r"""Call transform on the provided message.
Args:
x (object): Message object to transform.
no_copy (bool, optional): If True, the transformation occurs in
place. Otherwise a copy is created and transformed. Defaults
to False.
Returns:
object: The transformed message.
"""
out = x
if isinstance(x, dict):
out = x
elif isinstance(x, (list, tuple)):
field_names = self._get_field_names(len(x))
out = {k: v for k, v in zip(field_names, x)}
elif isinstance(x, np.ndarray):
field_names = list(x.dtype.names)
out = {k: x[k] for k in field_names}
elif isinstance(x, (rapidjson.geometry.Ply,
rapidjson.geometry.ObjWavefront)):
out = x.as_dict()
else:
field_names = self._get_field_names(1)
out = {field_names[0]: x}
return out
[docs] @classmethod
def get_testing_options(cls, **kwargs):
r"""Get testing options for the transform class.
Returns:
list: Multiple dictionaries of keywords and messages before/after
pairs that will result from the transform created by the provided
keywords.
"""
return [{'kwargs': {},
'in/out': [(dict(zip('abc', range(3))),
dict(zip('abc', range(3))))],
'in/out_t': [
({'type': 'object',
'properties': {
x: {'type': 'int'} for x in 'abc'}},
{'type': 'object',
'properties': {
x: {'type': 'int'} for x in 'abc'}})]},
{'kwargs': {'field_names': ['a', 'b', 'c']},
'in/out': [([0, 1, 2], dict(zip('abc', range(3))))],
'in/out_t': [
({'type': 'array',
'items': [{'type': 'int', 'title': x}
for x in 'abc']},
{'type': 'object',
'properties': {
x: {'type': 'int', 'title': x}
for x in 'abc'}}),
({'type': 'array',
'items': {'type': 'int'}},
{'type': 'object',
'additionalProperties': {'type': 'int'}})]},
{'kwargs': {},
'in/out': [(1, {'f0': 1})],
'in/out_t': [
({'type': 'int'},
{'type': 'object',
'properties': {'f0': {'type': 'int'}}})]},
{'kwargs': {},
'in/out': [(np.zeros(3, np.dtype({'names': ['a', 'b', 'c'],
'formats': ['i4', 'i4', 'i4']})),
{k: np.zeros(3) for k in 'abc'})]},
{'kwargs': {},
'in/out': [
(rapidjson.generate_data({'type': 'ply'}),
rapidjson.generate_data({'type': 'ply'}).as_dict())],
'in/out_t': [
({'type': 'ply'},
{'type': 'object'})]}]