Source code for obspy.core.util.types

# -*- coding: utf-8 -*-
"""
Various types used in ObsPy.

:copyright:
    The ObsPy Development Team (devs@obspy.org)
:license:
    GNU Lesser General Public License, Version 3
    (http://www.gnu.org/copyleft/lesser.html)
"""

# try native OrderDict implementations first (Python >= 2.7.x)
try:
    from collections import OrderedDict
except ImportError:
    # Copyright (c) 2009 Raymond Hettinger
    #
    # Permission is hereby granted, free of charge, to any person
    # obtaining a copy of this software and associated documentation files
    # (the "Software"), to deal in the Software without restriction,
    # including without limitation the rights to use, copy, modify, merge,
    # publish, distribute, sublicense, and/or sell copies of the Software,
    # and to permit persons to whom the Software is furnished to do so,
    # subject to the following conditions:
    #
    #     The above copyright notice and this permission notice shall be
    #     included in all copies or substantial portions of the Software.
    #
    #     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
    #     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
    #     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
    #     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
    #     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
    #     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
    #     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
    #     OTHER DEALINGS IN THE SOFTWARE.
    from UserDict import DictMixin

[docs] class OrderedDict(dict, DictMixin): """ Dictionary that remembers insertion order. """
[docs] def __init__(self, *args, **kwds): if len(args) > 1: msg = 'expected at most 1 arguments, got %d' raise TypeError(msg % len(args)) try: self.__end except AttributeError: self.clear() self.update(*args, **kwds)
[docs] def clear(self): self.__end = end = [] end += [None, end, end] # sentinel node for doubly linked list self.__map = {} # key --> [key, prev, next] dict.clear(self)
[docs] def __setitem__(self, key, value): if key not in self: end = self.__end curr = end[1] curr[2] = end[1] = self.__map[key] = [key, curr, end] dict.__setitem__(self, key, value)
[docs] def __delitem__(self, key): dict.__delitem__(self, key) key, prev, next = self.__map.pop(key) prev[2] = next next[1] = prev
[docs] def __iter__(self): end = self.__end curr = end[2] while curr is not end: yield curr[0] curr = curr[2]
[docs] def __reversed__(self): end = self.__end curr = end[1] while curr is not end: yield curr[0] curr = curr[1]
[docs] def popitem(self, last=True): if not self: raise KeyError('dictionary is empty') if last: key = reversed(self).next() else: key = iter(self).next() value = self.pop(key) return key, value
[docs] def __reduce__(self): items = [[k, self[k]] for k in self] tmp = self.__map, self.__end del self.__map, self.__end inst_dict = vars(self).copy() self.__map, self.__end = tmp if inst_dict: return (self.__class__, (items,), inst_dict) return self.__class__, (items,)
[docs] def keys(self): return list(self)
setdefault = DictMixin.setdefault update = DictMixin.update pop = DictMixin.pop values = DictMixin.values items = DictMixin.items iterkeys = DictMixin.iterkeys itervalues = DictMixin.itervalues iteritems = DictMixin.iteritems
[docs] def __repr__(self): if not self: return '%s()' % (self.__class__.__name__,) return '%s(%r)' % (self.__class__.__name__, self.items())
[docs] def copy(self): return self.__class__(self)
@classmethod
[docs] def fromkeys(cls, iterable, value=None): d = cls() for key in iterable: d[key] = value return d
[docs] def __eq__(self, other): if isinstance(other, OrderedDict): if len(self) != len(other): return False for p, q in zip(self.items(), other.items()): if p != q: return False return True return dict.__eq__(self, other)
[docs] def __ne__(self, other): return not self == other
[docs]class Enum(object): """ Enumerated type (enum) implementation for Python. :type enums: list of str .. rubric:: Example >>> from obspy.core.util import Enum >>> units = Enum(["m", "s", "m/s", "m/(s*s)", "m*s", "other"]) There are different ways to access the correct enum values: >>> units.get('m/s') 'm/s' >>> units['S'] 's' >>> units.OTHER 'other' >>> units[3] 'm/(s*s)' >>> units.xxx # doctest: +ELLIPSIS Traceback (most recent call last): ... KeyError: 'xxx' Changing enum values will not work: >>> units.m = 5 # doctest: +ELLIPSIS Traceback (most recent call last): ... NotImplementedError >>> units['m'] = 'xxx' # doctest: +ELLIPSIS Traceback (most recent call last): ... NotImplementedError Calling with a value will either return the mapped enum value or ``None``: >>> units("M*s") 'm*s' >>> units('xxx') >>> units(5) 'other' """ # marker needed for for usage within ABC classes __isabstractmethod__ = False
[docs] def __init__(self, enums): self.__enums = OrderedDict(zip([str(e).lower() for e in enums], enums))
[docs] def __call__(self, enum): try: return self.get(enum) except: return None
[docs] def get(self, key): if isinstance(key, int): return self.__enums.values()[key] return self.__enums.__getitem__(key.lower())
__getattr__ = get __getitem__ = get
[docs] def set(self, name, value): if name == '_Enum__enums': self.__dict__[name] = value return raise NotImplementedError
__setattr__ = set __setitem__ = set
[docs] def __contains__(self, value): return value.lower() in self.__enums
[docs] def values(self): return self.__enums.values()
[docs] def keys(self): return self.__enums.keys()
[docs] def items(self): return self.__enums.items()
[docs] def iteritems(self): return self.__enums.iteritems()
[docs] def __str__(self): """ >>> enum = Enum(["c", "a", "b"]) >>> print enum Enum(["c", "a", "b"]) """ keys = self.__enums.keys() return "Enum([%s])" % ", ".join(['"%s"' % _i for _i in keys])
if __name__ == '__main__': import doctest doctest.testmod(exclude_empty=True)