Source code for mdt.visualization.dict_conversion

from collections import Mapping, Sequence

__author__ = 'Robbert Harms'
__date__ = "2016-09-03"
__maintainer__ = "Robbert Harms"
__email__ = "robbert@xkls.nl"


[docs]class ConversionSpecification: def __init__(self): """Specifies how the content of an object is to be converted from and to a dictionary."""
[docs] def to_dict(self, obj): """Convert the given value to a dictionary. Args: obj : the value to convert to a dictionary Returns: dict: the resulting converted dictionary """
[docs] def from_dict(self, value): """Generate a result value from the given dictionary Args: value : the dictionary to convert back to a value Returns: object: the value represented by the dict. """
[docs]class OptionalConversionDecorator(ConversionSpecification): def __init__(self, conversion_specification): """Makes the conversion optional by testing against None. If the element to convert is None, we will return None as a conversion. If the element to convert is not None we will convert it according to the conversion specified. This holds for both to- and from- dict. Args: conversion_specification (ConversionSpecification): the conversion specification to use if the element to convert is not None. """ super().__init__() self._conversion_specification = conversion_specification
[docs] def to_dict(self, obj): if obj is None: return None return self._conversion_specification.to_dict(obj)
[docs] def from_dict(self, value): if value is None: return None return self._conversion_specification.from_dict(value)
[docs]class SimpleClassConversion(ConversionSpecification): def __init__(self, class_type, attribute_conversions): """Converts a dictionary to and from the specified class. Args: class_type (type): the type of class to convert to attribute_conversions (List[ConversionSpecification]) the list of conversion specification for the attributes """ super().__init__() self._class_type = class_type self._attribute_conversions = attribute_conversions
[docs] def to_dict(self, obj): result_dict = {} conversion_info = self._attribute_conversions for key, converter in conversion_info.items(): result_dict[key] = converter.to_dict(getattr(obj, key)) return result_dict
[docs] def from_dict(self, value): init_kwargs = {} for key, converter in self._attribute_conversions.items(): if key in value: init_kwargs[key] = converter.from_dict(value[key]) return self._class_type(**init_kwargs)
[docs]class ConvertDictElements(ConversionSpecification): def __init__(self, conversion_type): """Converts all the elements in the value (a dictionary) using the given conversion type.""" super().__init__() self._conversion_type = conversion_type
[docs] def to_dict(self, obj): return {key: self._conversion_type.to_dict(v) for key, v in obj.items()}
[docs] def from_dict(self, value): return {key: self._conversion_type.from_dict(v) for key, v in value.items()}
[docs]class ConvertListElements(ConversionSpecification): def __init__(self, conversion_type): """Converts all the elements in the value (a list) using the given conversion type.""" super().__init__() self._conversion_type = conversion_type
[docs] def to_dict(self, obj): return [self._conversion_type.to_dict(v) for v in obj]
[docs] def from_dict(self, value): return [self._conversion_type.from_dict(v) for v in value]
[docs]class ConvertDynamicFromModule(ConversionSpecification): def __init__(self, module): """Performs dynamic lookup by loading the class from the given module. This requires that the class we are dynamically loading has a get_conversion_info() class method that returns the conversion specification for that class. Args: module (module): the python module to use for loading the data from dict """ super().__init__() self._module = module
[docs] def to_dict(self, obj): return [obj.__class__.__name__, obj.get_conversion_info().to_dict(obj)]
[docs] def from_dict(self, value): try: cls = getattr(self._module, value[0]) except AttributeError: raise ValueError('The given class "{}" could not be found.'.format(value[0])) return cls.get_conversion_info().from_dict(value[1])
[docs]class SimpleFunctionConversion(ConversionSpecification): def __init__(self, conversion_func=None, allow_null=True, set_null_to_value=None): """Performs identity conversion between simple types. Args: conversion_func (Func): if not None we apply the given function before converting to and from the dictionary. Can also be a type like ``int``. allow_null (bool): if True we allow None during type casting set_null_to_value (obj): the value to set null entries to. If this is None and allow_null is False we raise an error. """ super().__init__() self._conversion_func = conversion_func self._allow_none = allow_null self._set_null_to_value = set_null_to_value
[docs] def to_dict(self, obj): if obj is None: if self._allow_none: return None else: if self._set_null_to_value is not None: return self._set_null_to_value raise ValueError('The object is supposed to be not None.') else: if self._conversion_func: return self._conversion_func(obj) return obj
[docs] def from_dict(self, value): if value is None: if self._allow_none: return None else: if self._set_null_to_value is not None: return self._set_null_to_value raise ValueError('The object is supposed to be not None.') else: if self._conversion_func: return self._conversion_func(value) return value
[docs]class SimpleDictConversion(SimpleFunctionConversion): def __init__(self, conversion_func=None, allow_null=True, set_null_to_value=None): """Converts all the objects in the given dict. Args: conversion_func (Func): if not None we cast the from_dict value to the given type allow_null (bool): if True we allow None during type casting set_null_to_value (obj): the value to set null entries to. If this is None and allow_null is False we raise an error. """ super().__init__( conversion_func=SimpleDictConversion._get_conversion_func(conversion_func), allow_null=allow_null, set_null_to_value=set_null_to_value) @staticmethod def _get_conversion_func(user_conversion_func): """Wraps the desired type into a Dict[user_conversion_func] function.""" if user_conversion_func is None: return None def conversion_wrapper(obj): if isinstance(obj, Mapping): return {key: user_conversion_func(v) for key, v in obj.items()} return obj return conversion_wrapper
[docs]class SimpleListConversion(SimpleFunctionConversion): def __init__(self, conversion_func=None, allow_null=True, set_null_to_value=None): """Converts all the objects in the given list. Args: conversion_func (Func): if not None we cast the from_dict value to the given type allow_null (bool): if True we allow None during type casting set_null_to_value (obj): the value to set null entries to. If this is None and allow_null is False we raise an error. """ super().__init__( conversion_func=SimpleListConversion._get_conversion_func(conversion_func), allow_null=allow_null, set_null_to_value=set_null_to_value) @staticmethod def _get_conversion_func(desired_type): """Wraps the desired type into a dict(desired_type) function.""" if desired_type is None: return None def conversion_wrapper(obj): if isinstance(obj, Sequence): return [desired_type(el) for el in obj] return obj return conversion_wrapper
[docs]class StringConversion(SimpleFunctionConversion): def __init__(self, allow_null=True): super().__init__(str, allow_null=allow_null)
[docs]class IntConversion(SimpleFunctionConversion): def __init__(self, allow_null=True): super().__init__(int, allow_null=allow_null)
[docs]class FloatConversion(SimpleFunctionConversion): def __init__(self, allow_null=True): super().__init__(float, allow_null=allow_null)
[docs]class BooleanConversion(SimpleFunctionConversion): def __init__(self, allow_null=True): super().__init__(bool, allow_null=allow_null)
[docs]class WhiteListConversion(ConversionSpecification): def __init__(self, white_list, default): """Allow only elements from the given white list. If the element is not one of them, revert to the default. Args: white_list (list of object): list of allowable objects default : the default fallback object """ super().__init__() self.white_list = white_list self.default = default
[docs] def to_dict(self, obj): if obj not in self.white_list: return self.default return obj
[docs] def from_dict(self, value): if value not in self.white_list: return self.default return value