Source code for fdi.dataset.composite

# -*- coding: utf-8 -*-

from .datawrapper import DataContainer
from .odict import ODict
from .serializable import Serializable
from .invalid import INVALID

from collections import UserDict
from collections.abc import MutableMapping
import logging
# create logger
logger = logging.getLogger(__name__)
# logger.debug('level %d' %  (logger.getEffectiveLevel()))

# from .listener import DatasetEventSender, DatasetListener
# from .metadata import DataWrapperMapper

# order of Container, Sized, Iterator must be the same as in DataContaier!


# class Composite(DeepEqual, UserDictAdapter, Serializable):  # ):

[docs]class Composite(DataContainer, Serializable, MutableMapping): """ A container of named Datasets. This container can hold zero or more datasets, each of them stored against a unique name. The order of adding datasets to this Composite is important, that is: the keySet() method will return a set of labels of the datasets in the sequence as they were added. Note that replacing a dataset with the same name, will keep the order. :class:`DeepEqual` must stay to the left of :class:`MutableMapping` so its `__eq__` will get to run. `Serializable` becomes a parent for having `__setstate__`. :data: default `None` will init with a `dict`. """
[docs] def __init__(self, data=None, **kwds): """ Parameters ---------- Returns ------- """ # pass data to parent super().__init__({} if data is None else data, **kwds)
[docs] def containsKey(self, name): """ Returns true if this map contains a mapping for the specified name. Parameters ---------- Returns ------- """ return self.__contains__(name)
[docs] def get(self, name, default=INVALID): """ Returns the dataset to which this composite maps the specified name. If the attrbute does not exist and `default` unspecified, raise a KeyError. Parameters ---------- :default: assigne to None or anything for missing `name`. Returns ------- """ if name in self.data: return self.data[name] elif default is INVALID: raise KeyError(name + 'not found') else: return default
[docs] def set(self, name, dataset): """ Associates the specified dataset with the specified key in this map(optional operation). If the map previously contained a mapping for this key, the old dataset is replaced by the specified dataset. this composite does not permit null or empty keys. Parameters ---------- Returns ------- """ self._data[name] = dataset
def __getitem__(self, name): """ Parameters ---------- Returns ------- """ return self._data[name] def __delitem__(self, name): """ Parameters ---------- Returns ------- """ del self.data[name] def __setitem__(self, name, dataset): """ Parameters ---------- Returns ------- """ if 'refs' in self._data and name != 'refs' and not (name in self._data): refs = self._data.pop('refs') self._data[name] = dataset self._data['refs'] = refs else: # this must call `set` which can be overridden by subclasses self.set(name, dataset)
[docs] def getSets(self): """ Provide access to the Map < String, Dataset > . mh: api from CompositeDataset Parameters ---------- Returns ------- """ return self.data
[docs] def isEmpty(self): """ Returns true if this map contains no key - value mappings. Parameters ---------- Returns ------- """ return len(self.data) == 0
[docs] def keySet(self): """ Returns a list view of the keys contained in this composite. Parameters ---------- Returns ------- """ return list(self.data.keys())
# convenience method name. getDatasetNames = keySet
[docs] def remove(self, name): """ Removes the mapping for this name from this composite. mh: returns None if name is None or item does not exist. Parameters ---------- Returns ------- """ if name == '' or name is None or name not in self.data: logger.debug('Cannot remove non-exist item \'' + name + "'") return None del self._data[name]
[docs] def size(self): """ Returns the number of key - value mappings in this map. Parameters ---------- Returns ------- """ return len(self.data)
[docs] def getDefault(self): """ Convenience method that returns the first dataset \ belonging to this composite. """ ls = list(self.values()) return ls[0] if len(ls) > 0 else None
def __iter__(self): for i in self.data: yield i def __repr__(self): return self.__class__.__name__ + '(' + (self.data.__repr__() if hasattr(self, 'data') else 'None') + ')'
[docs] def toString(self, level=0, matprint=None, trans=True, **kwds): """ Parameters ---------- Returns ------- """ o = ODict(self.data) return self.__class__.__name__ + \ o.toString(level=level, matprint=matprint, trans=trans, **kwds)
string = toString txt = toString
[docs]class UserDictAdapter(UserDict): """ Adapter class to make UserDict cooperative to multiple inheritance and take data keyword arg. REf. https://rhettinger.wordpress.com/2011/05/26/super-considered-super/ """
[docs] def __init__(self, data=None, *args, **kwds): """ Parameters ---------- :data: initialize UserDict. Returns ------- """ # pass data to UserDict as the first positional arg super().__init__(data, *args, **kwds)