Source code for fsleyes_props.serialise

#!/usr/bin/env python
#
# serialise.py - Functions for serialising/deserialising property values.
#
# Author: Paul McCarthy <pauldmccarthy@gmail.com>
#
"""This module provides functions for serialising and deserialising the values
of most ``fsleyes_props`` property types (which are defined in
:mod:`.properties_types`).


This module only contains logic for those property types that the default
python conversion routines would not be able to handle. For example, an
:class:`.Int` property value can be serialised with ``str``, and deserialised
with ``int``. Such logic is already built into the ``Int`` class, so there
is no need for this module to duplicate it.


An example of where specific serialisation/deserialisation logic is useful is
the :class:`.Boolean` property. Passing a boolean value,``True`` or ``False``
to the ``str`` function will result in a string ``'True'`` or
``'False'``. However, passing a string ``'True'`` or ``'False'`` to the
``bool`` function will result in ``True`` in both cases.


The logic needed to safely serialise/deserialise :class:`.Boolean` values, and
other property types for which it is needed, is provided by this module.
"""

import sys
import logging

import numpy as np


log = logging.getLogger(__name__)


DELIMITER = '#'
"""Delimiter string used to join multi-valued properties. """


[docs] def serialise(hasProps, propName): """Get the value of the named property from the given :class:`.HasProperties` instance, serialise it, and return the serialised string. """ propObj = hasProps.getProp(propName) val = getattr(hasProps, propName) propType = type(propObj).__name__ sfunc = getattr(sys.modules[__name__], '_serialise_{}'.format(propType), None) def defaultSfunc(s, *a): return str(s) if sfunc is None: sfunc = defaultSfunc sval = sfunc(val, hasProps, propObj) log.debug('Serialised {}.{}: {} -> "{}"'.format( type(hasProps).__name__, propName, val, sval)) return sval
[docs] def deserialise(hasProps, propName, string): """Deserialise the given string, under the assumption that it is a serialised value of the named property from the given :class:`.HasProperties` instance. """ propObj = hasProps.getProp(propName) propType = type(propObj).__name__ dfunc = getattr(sys.modules[__name__], '_deserialise_{}'.format(propType), None) def defaultDfunc(s, *a): return s if dfunc is None: dfunc = defaultDfunc dval = dfunc(string, hasProps, propObj) log.debug('Deserialised {}.{}: "{}" -> {}'.format( type(hasProps).__name__, propName, string, dval)) return dval
# The type specific conversions are performed by the # functions below. They must accept the following # arguments: # # - The value to be serialised/deserialised # - The HasProperties instance # - The PropertyBase instance def _serialise_Boolean(value, *a): return str(value) def _deserialise_Boolean(value, *a): # Special case - a string containig 'false' # (case insensitive) evaluates to False. if isinstance(value, str): value = value.lower() if value == 'false': value = '' # For anything else, we # rely on default conversion. return bool(value) def _serialise_Choice(value, *a): return str(value) def _deserialise_Choice(value, hasProps, propObj): choices = propObj.getChoices(hasProps) # This is a bit hacky - Choice properties can store # any type, so we can't figure out precisely how # to serialise/deserialise those types. So we check # to see if all the choices are numeric and, if not, # fall back to using str for deserialisation. if all([isinstance(c, float) for c in choices]): cType = float elif any([isinstance(c, float) for c in choices]): cType = float elif all([isinstance(c, int) for c in choices]): cType = int else: cType = str return cType(value) def _serialise_Colour(value, *a): # Colour values should be in the range [0, 1] r, g, b, a = [int(v * 255) for v in value] hexstr = '#{:02x}{:02x}{:02x}{:02x}'.format(r, g, b, a) return hexstr def _deserialise_Colour(value, *a): r = value[1:3] g = value[3:5] b = value[5:7] a = value[7:9] r, g, b, a = [int(v, base=16) for v in (r, g, b, a)] r, g, b, a = [v / 255.0 for v in (r, g, b, a)] return [r, g, b, a] def _serialise_ColourMap(value, *a): return value.name def _deserialise_ColourMap(value, *a): import matplotlib as mpl return mpl.colormaps[value] def _serialise_Bounds(value, *a): value = map(str, value) return DELIMITER.join(value) def _deserialise_Bounds(value, *a): value = value.split(DELIMITER) return map(float, value) def _serialise_Point(value, *a): value = map(str, value) return DELIMITER.join(value) def _deserialise_Point(value, *a): value = value.split(DELIMITER) return map(float, value) def _serialise_Array(value, *a): ndim = str(value.ndim) shape = [str(s) for s in value.shape] value = [str(v) for v in value.flat[:]] return DELIMITER.join([ndim] + shape + value) def _deserialise_Array(value, *a): value = value.split(DELIMITER) ndim = int(value[0]) shape = [int( v) for v in value[1:ndim + 1]] value = [float(v) for v in value[ ndim + 1:]] return np.array(value).reshape(shape)