Source code for cis_interface.metaschema.datatypes.JSONArrayMetaschemaType
import numpy as np
import pandas as pd
from cis_interface.metaschema.datatypes import register_type
from cis_interface.metaschema.datatypes.ContainerMetaschemaType import (
ContainerMetaschemaType)
[docs]@register_type
class JSONArrayMetaschemaType(ContainerMetaschemaType):
r"""Type associated with a set of subtypes."""
name = 'array'
description = 'A container of ordered values.'
properties = ContainerMetaschemaType.properties + ['items']
definition_properties = ContainerMetaschemaType.definition_properties
metadata_properties = ContainerMetaschemaType.metadata_properties + ['items']
extract_properties = ContainerMetaschemaType.extract_properties + ['items']
python_types = (list, tuple, np.ndarray, pd.DataFrame)
_replaces_existing = True
_container_type = list
_json_type = 'array'
_json_property = 'items'
_empty_msg = []
[docs] @classmethod
def validate(cls, obj, raise_errors=False):
r"""Validate an object to check if it could be of this type.
Args:
obj (object): Object to validate.
raise_errors (bool, optional): If True, errors will be raised when
the object fails to be validated. Defaults to False.
Returns:
bool: True if the object could be of this type, False otherwise.
"""
out = super(JSONArrayMetaschemaType, cls).validate(
obj, raise_errors=raise_errors)
if out and isinstance(obj, np.ndarray):
out = (len(obj.dtype) > 0)
if (not out) and raise_errors:
raise ValueError("Array dosn't have a structured data type.")
return out
[docs] @classmethod
def normalize(cls, obj):
r"""Normalize an object, if possible, to conform to this type.
Args:
obj (object): Object to normalize.
Returns:
object: Normalized object.
"""
if isinstance(obj, str):
obj = [v.strip() for v in obj.split(',')]
return obj
[docs] @classmethod
def coerce_type(cls, obj, typedef=None, key_order=None, **kwargs):
r"""Coerce objects of specific types to match the data type.
Args:
obj (object): Object to be coerced.
typedef (dict, optional): Type defintion that object should be
coerced to. Defaults to None.
key_order (list, optional): Order that keys from a dictionary should
be used to compose an array. Defaults to None.
**kwargs: Additional keyword arguments are metadata entries that may
aid in coercing the type.
Returns:
object: Coerced object.
Raises:
RuntimeError: If obj is a dictionary, but key_order is not provided.
"""
from cis_interface.serialize import pandas2list, numpy2list, dict2list
if isinstance(obj, pd.DataFrame):
obj = pandas2list(obj)
elif isinstance(obj, np.ndarray) and (len(obj.dtype) > 0):
obj = numpy2list(obj)
elif isinstance(obj, dict):
if (key_order is not None) or (len(obj) == 1):
obj = dict2list(obj, order=key_order)
elif isinstance(typedef, dict) and (len(typedef.get('items', [])) == 1):
typedef_validated = kwargs.get('typedef_validated', False)
if cls.check_decoded([obj], typedef,
typedef_validated=typedef_validated):
obj = [obj]
return obj
@classmethod
def _iterate(cls, container):
r"""Iterate over the contents of the container. Each element returned
should be a tuple including an index and a value.
Args:
container (obj): Object to be iterated over.
Returns:
iterator: Iterator over elements in the container.
"""
for k, v in enumerate(container):
yield (k, v)
@classmethod
def _assign(cls, container, index, value):
r"""Assign an element in the container to the specified value.
Args:
container (obj): Object that element will be assigned to.
index (obj): Index in the container object where element will be
assigned.
value (obj): Value that will be assigned to the element in the
container object.
"""
if len(container) > index:
container[index] = value
elif len(container) == index:
container.append(value)
else:
raise RuntimeError("The container has %s elements and the index is %s"
% (len(container), index))
@classmethod
def _has_element(cls, container, index):
r"""Check to see if an index is in the container.
Args:
container (obj): Object that should be checked for index.
index (obj): Index that should be checked for.
Returns:
bool: True if the index is in the container.
"""
return (len(container) > index)
@classmethod
def _get_element(cls, container, index, default):
r"""Get an element from the container if it exists, otherwise return
the default.
Args:
container (obj): Object that should be returned from.
index (obj): Index of element that should be returned.
default (obj): Default that should be returned if the index is not
in the container.
Returns:
object: Container contents at specified element.
"""
if isinstance(container, dict):
assert('type' in container)
return container
return super(JSONArrayMetaschemaType, cls)._get_element(
container, index, default)