Source code for larray.core.metadata

# -*- coding: utf8 -*-
from __future__ import absolute_import, division, print_function

from collections import OrderedDict
from larray.util.misc import PY2, basestring


if PY2:
    class AttributeDict(object):
        def __init__(self, *args, **kwargs):
            object.__setattr__(self, '__odict', OrderedDict(*args, **kwargs))

        def __getattr__(self, key):
            od = object.__getattribute__(self, '__odict')
            if hasattr(od, key):
                return getattr(od, key)
            else:
                try:
                    return od[key]
                except KeyError:
                    raise AttributeError(key)

        def __setattr__(self, key, value):
            od = object.__getattribute__(self, '__odict')
            od[key] = value

        def __delattr__(self, key):
            od = object.__getattribute__(self, '__odict')
            del od[key]

        def __reduce__(self):
            'Return state information for pickling'
            od = object.__getattribute__(self, '__odict')
            res = list(od.__reduce__())
            res[0] = self.__class__
            return tuple(res)

        def __dir__(self):
            od = object.__getattribute__(self, '__odict')
            return list(set(dir(self.__class__)) | set(self.__dict__.keys()) | set(od.keys()))

        def copy(self):
            od = object.__getattribute__(self, '__odict')
            return self.__class__(od)

        def method_factory(name):
            fullname = '__%s__' % name
            odict_method = getattr(OrderedDict, fullname)

            def method(self, *args, **kwargs):
                od = object.__getattribute__(self, '__odict')
                return odict_method(od, *args, **kwargs)
            return method

        __getitem__ = method_factory('getitem')
        __setitem__ = method_factory('setitem')
        __delitem__ = method_factory('delitem')
        __contains__ = method_factory('contains')

        __iter__ = method_factory('iter')
        __len__ = method_factory('len')

        __reversed__ = method_factory('reversed')

        __sizeof__ = method_factory('sizeof')

        def _binop(name):
            fullname = '__%s__' % name
            odict_method = getattr(OrderedDict, fullname)

            def opmethod(self, other):
                self_od = object.__getattribute__(self, '__odict')
                if not isinstance(other, AttributeDict):
                    return False
                other_od = object.__getattribute__(other, '__odict')
                return odict_method(self_od, other_od)
            opmethod.__name__ = fullname
            return opmethod

        __eq__ = _binop('eq')
        __ne__ = _binop('ne')
        __ge__ = _binop('ge')
        __gt__ = _binop('gt')
        __le__ = _binop('le')
        __lt__ = _binop('lt')

        def __repr__(self):
            return '\n'.join(['{}: {}'.format(k, v) for k, v in self.items()])

else:
    class AttributeDict(OrderedDict):
        def __getattr__(self, key):
            try:
                return self[key]
            except KeyError:
                raise AttributeError(key)

        def __setattr__(self, key, value):
            self[key] = value

        def __delattr__(self, key):
            del self[key]

        def __dir__(self):
            return list(set(super(AttributeDict, self).__dir__()) | set(self.keys()))

        def __repr__(self):
            return '\n'.join(['{}: {}'.format(k, v) for k, v in self.items()])


[docs]class Metadata(AttributeDict): """ An ordered dictionary allowing key-values accessibly using attribute notation (AttributeDict.attribute) instead of key notation (Dict["key"]). Examples -------- >>> from larray import ndtest >>> from datetime import datetime Add metadata at array initialization >>> # Python 2 or <= 3.5 >>> arr = ndtest((3, 3), meta=[('title', 'the title'), ('author', 'John Smith')]) >>> # Python 3.6+ >>> arr = ndtest((3, 3), meta=Metadata(title='the title', author='John Smith')) # doctest: +SKIP Add metadata after array initialization >>> arr.meta.creation_date = datetime(2017, 2, 10) Access to metadata >>> arr.meta.creation_date datetime.datetime(2017, 2, 10, 0, 0) Modify metadata >>> arr.meta.creation_date = datetime(2017, 2, 16) Delete metadata >>> del arr.meta.creation_date """ def __larray__(self): from larray.core.array import stack return stack(self.items(), axes='metadata') @classmethod def from_array(cls, array): from larray.core.array import aslarray array = aslarray(array) if array.ndim != 1: raise ValueError("Expected LArray object of dimension 1. Got array of dimension {}".format(array.ndim)) from pandas import to_numeric, to_datetime def _convert_value(value): value = to_numeric([value], errors='ignore')[0] if isinstance(value, basestring): value = to_datetime(value, errors='ignore', infer_datetime_format=True) return value return Metadata([(key, _convert_value(value)) for key, value in zip(array.axes.labels[0], array.data)]) # ---------- IO methods ---------- def to_hdf(self, hdfstore, key=None): if len(self): attrs = hdfstore.get_storer(key).attrs if key is not None else hdfstore.root._v_attrs attrs.metadata = self @classmethod def from_hdf(cls, hdfstore, key=None): attrs = hdfstore.get_storer(key).attrs if key is not None else hdfstore.root._v_attrs if 'metadata' in attrs: return attrs.metadata else: return None