Ordereddict exploses with python2.6 ...

Use the official backport
This commit is contained in:
Jerome Kieffer 2013-10-17 20:19:30 +02:00
parent f6ed67fc33
commit 4052c3e9d1
2 changed files with 208 additions and 147 deletions

127
pyqtgraph/ordereddict.py Normal file
View File

@ -0,0 +1,127 @@
# 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
class OrderedDict(dict, DictMixin):
def __init__(self, *args, **kwds):
if len(args) > 1:
raise TypeError('expected at most 1 arguments, got %d' % len(args))
try:
self.__end
except AttributeError:
self.clear()
self.update(*args, **kwds)
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)
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)
def __delitem__(self, key):
dict.__delitem__(self, key)
key, prev, next = self.__map.pop(key)
prev[2] = next
next[1] = prev
def __iter__(self):
end = self.__end
curr = end[2]
while curr is not end:
yield curr[0]
curr = curr[2]
def __reversed__(self):
end = self.__end
curr = end[1]
while curr is not end:
yield curr[0]
curr = curr[1]
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
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,)
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
def __repr__(self):
if not self:
return '%s()' % (self.__class__.__name__,)
return '%s(%r)' % (self.__class__.__name__, self.items())
def copy(self):
return self.__class__(self)
@classmethod
def fromkeys(cls, iterable, value=None):
d = cls()
for key in iterable:
d[key] = value
return d
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)
def __ne__(self, other):
return not self == other

View File

@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
"""
advancedTypes.py - Basic data structures not included with python
advancedTypes.py - Basic data structures not included with python
Copyright 2010 Luke Campagnola
Distributed under MIT/X11 license. See license.txt for more infomation.
@ -15,76 +15,10 @@ import threading, sys, copy, collections
try:
from collections import OrderedDict
except:
# Deprecated; this class is now present in Python 2.7 as collections.OrderedDict
except ImportError:
# Only keeping this around for python2.6 support.
class OrderedDict(dict):
"""extends dict so that elements are iterated in the order that they were added.
Since this class can not be instantiated with regular dict notation, it instead uses
a list of tuples:
od = OrderedDict([(key1, value1), (key2, value2), ...])
items set using __setattr__ are added to the end of the key list.
"""
def __init__(self, data=None):
self.order = []
if data is not None:
for i in data:
self[i[0]] = i[1]
def __setitem__(self, k, v):
if not self.has_key(k):
self.order.append(k)
dict.__setitem__(self, k, v)
def __delitem__(self, k):
self.order.remove(k)
dict.__delitem__(self, k)
from ordereddict import OrderedDict
def keys(self):
return self.order[:]
def items(self):
it = []
for k in self.keys():
it.append((k, self[k]))
return it
def values(self):
return [self[k] for k in self.order]
def remove(self, key):
del self[key]
#self.order.remove(key)
def __iter__(self):
for k in self.order:
yield k
def update(self, data):
"""Works like dict.update, but accepts list-of-tuples as well as dict."""
if isinstance(data, dict):
for k, v in data.iteritems():
self[k] = v
else:
for k,v in data:
self[k] = v
def copy(self):
return OrderedDict(self.items())
def itervalues(self):
for k in self.order:
yield self[k]
def iteritems(self):
for k in self.order:
yield (k, self[k])
def __deepcopy__(self, memo):
return OrderedDict([(k, copy.deepcopy(v, memo)) for k, v in self.iteritems()])
class ReverseDict(dict):
"""extends dict so that reverse lookups are possible by requesting the key as a list of length 1:
@ -101,7 +35,7 @@ class ReverseDict(dict):
for k in data:
self.reverse[data[k]] = k
dict.__init__(self, data)
def __getitem__(self, item):
if type(item) is list:
return self.reverse[item[0]]
@ -114,8 +48,8 @@ class ReverseDict(dict):
def __deepcopy__(self, memo):
raise Exception("deepcopy not implemented")
class BiDict(dict):
"""extends dict so that reverse lookups are possible by adding each reverse combination to the dict.
This only works if all values and keys are unique."""
@ -125,11 +59,11 @@ class BiDict(dict):
dict.__init__(self)
for k in data:
self[data[k]] = k
def __setitem__(self, item, value):
dict.__setitem__(self, item, value)
dict.__setitem__(self, value, item)
def __deepcopy__(self, memo):
raise Exception("deepcopy not implemented")
@ -138,7 +72,7 @@ class ThreadsafeDict(dict):
Also adds lock/unlock functions for extended exclusive operations
Converts all sub-dicts and lists to threadsafe as well.
"""
def __init__(self, *args, **kwargs):
self.mutex = threading.RLock()
dict.__init__(self, *args, **kwargs)
@ -162,7 +96,7 @@ class ThreadsafeDict(dict):
dict.__setitem__(self, attr, val)
finally:
self.unlock()
def __contains__(self, attr):
self.lock()
try:
@ -188,19 +122,19 @@ class ThreadsafeDict(dict):
def lock(self):
self.mutex.acquire()
def unlock(self):
self.mutex.release()
def __deepcopy__(self, memo):
raise Exception("deepcopy not implemented")
class ThreadsafeList(list):
"""Extends list so that getitem, setitem, and contains are all thread-safe.
Also adds lock/unlock functions for extended exclusive operations
Converts all sub-lists and dicts to threadsafe as well.
"""
def __init__(self, *args, **kwargs):
self.mutex = threading.RLock()
list.__init__(self, *args, **kwargs)
@ -222,7 +156,7 @@ class ThreadsafeList(list):
list.__setitem__(self, attr, val)
finally:
self.unlock()
def __contains__(self, attr):
self.lock()
try:
@ -238,17 +172,17 @@ class ThreadsafeList(list):
finally:
self.unlock()
return val
def lock(self):
self.mutex.acquire()
def unlock(self):
self.mutex.release()
def __deepcopy__(self, memo):
raise Exception("deepcopy not implemented")
def makeThreadsafe(obj):
if type(obj) is dict:
return ThreadsafeDict(obj)
@ -258,8 +192,8 @@ def makeThreadsafe(obj):
return obj
else:
raise Exception("Not sure how to make object of type %s thread-safe" % str(type(obj)))
class Locker(object):
def __init__(self, lock):
self.lock = lock
@ -283,10 +217,10 @@ class CaselessDict(OrderedDict):
self[k] = args[0][k]
else:
raise Exception("CaselessDict may only be instantiated with a single dict.")
#def keys(self):
#return self.keyMap.values()
def __setitem__(self, key, val):
kl = key.lower()
if kl in self.keyMap:
@ -294,30 +228,30 @@ class CaselessDict(OrderedDict):
else:
OrderedDict.__setitem__(self, key, val)
self.keyMap[kl] = key
def __getitem__(self, key):
kl = key.lower()
if kl not in self.keyMap:
raise KeyError(key)
return OrderedDict.__getitem__(self, self.keyMap[kl])
def __contains__(self, key):
return key.lower() in self.keyMap
def update(self, d):
for k, v in d.iteritems():
self[k] = v
def copy(self):
return CaselessDict(OrderedDict.copy(self))
def __delitem__(self, key):
kl = key.lower()
if kl not in self.keyMap:
raise KeyError(key)
OrderedDict.__delitem__(self, self.keyMap[kl])
del self.keyMap[kl]
def __deepcopy__(self, memo):
raise Exception("deepcopy not implemented")
@ -329,34 +263,34 @@ class CaselessDict(OrderedDict):
class ProtectedDict(dict):
"""
A class allowing read-only 'view' of a dict.
A class allowing read-only 'view' of a dict.
The object can be treated like a normal dict, but will never modify the original dict it points to.
Any values accessed from the dict will also be read-only.
"""
def __init__(self, data):
self._data_ = data
## List of methods to directly wrap from _data_
wrapMethods = ['_cmp_', '__contains__', '__eq__', '__format__', '__ge__', '__gt__', '__le__', '__len__', '__lt__', '__ne__', '__reduce__', '__reduce_ex__', '__repr__', '__str__', 'count', 'has_key', 'iterkeys', 'keys', ]
## List of methods which wrap from _data_ but return protected results
protectMethods = ['__getitem__', '__iter__', 'get', 'items', 'values']
## List of methods to disable
disableMethods = ['__delitem__', '__setitem__', 'clear', 'pop', 'popitem', 'setdefault', 'update']
## Template methods
# # Template methods
def wrapMethod(methodName):
return lambda self, *a, **k: getattr(self._data_, methodName)(*a, **k)
def protectMethod(methodName):
return lambda self, *a, **k: protect(getattr(self._data_, methodName)(*a, **k))
def error(self, *args, **kargs):
raise Exception("Can not modify read-only list.")
## Directly (and explicitly) wrap some methods from _data_
## Many of these methods can not be intercepted using __getattribute__, so they
## must be implemented explicitly
@ -371,33 +305,33 @@ class ProtectedDict(dict):
for methodName in disableMethods:
locals()[methodName] = error
## Add a few extra methods.
def copy(self):
raise Exception("It is not safe to copy protected dicts! (instead try deepcopy, but be careful.)")
def itervalues(self):
for v in self._data_.itervalues():
yield protect(v)
def iteritems(self):
for k, v in self._data_.iteritems():
yield (k, protect(v))
def deepcopy(self):
return copy.deepcopy(self._data_)
def __deepcopy__(self, memo):
return copy.deepcopy(self._data_, memo)
class ProtectedList(collections.Sequence):
"""
A class allowing read-only 'view' of a list or dict.
A class allowing read-only 'view' of a list or dict.
The object can be treated like a normal list, but will never modify the original list it points to.
Any values accessed from the list will also be read-only.
Note: It would be nice if we could inherit from list or tuple so that isinstance checks would work.
However, doing this causes tuple(obj) to return unprotected results (importantly, this means
unpacking into function arguments will also fail)
@ -405,28 +339,28 @@ class ProtectedList(collections.Sequence):
def __init__(self, data):
self._data_ = data
#self.__mro__ = (ProtectedList, object)
## List of methods to directly wrap from _data_
wrapMethods = ['__contains__', '__eq__', '__format__', '__ge__', '__gt__', '__le__', '__len__', '__lt__', '__ne__', '__reduce__', '__reduce_ex__', '__repr__', '__str__', 'count', 'index']
## List of methods which wrap from _data_ but return protected results
protectMethods = ['__getitem__', '__getslice__', '__mul__', '__reversed__', '__rmul__']
## List of methods to disable
disableMethods = ['__delitem__', '__delslice__', '__iadd__', '__imul__', '__setitem__', '__setslice__', 'append', 'extend', 'insert', 'pop', 'remove', 'reverse', 'sort']
## Template methods
# # Template methods
def wrapMethod(methodName):
return lambda self, *a, **k: getattr(self._data_, methodName)(*a, **k)
def protectMethod(methodName):
return lambda self, *a, **k: protect(getattr(self._data_, methodName)(*a, **k))
def error(self, *args, **kargs):
raise Exception("Can not modify read-only list.")
## Directly (and explicitly) wrap some methods from _data_
## Many of these methods can not be intercepted using __getattribute__, so they
## must be implemented explicitly
@ -441,13 +375,13 @@ class ProtectedList(collections.Sequence):
for methodName in disableMethods:
locals()[methodName] = error
## Add a few extra methods.
def __iter__(self):
for item in self._data_:
yield protect(item)
def __add__(self, op):
if isinstance(op, ProtectedList):
return protect(self._data_.__add__(op._data_))
@ -455,7 +389,7 @@ class ProtectedList(collections.Sequence):
return protect(self._data_.__add__(op))
else:
raise TypeError("Argument must be a list.")
def __radd__(self, op):
if isinstance(op, ProtectedList):
return protect(op._data_.__add__(self._data_))
@ -463,13 +397,13 @@ class ProtectedList(collections.Sequence):
return protect(op.__add__(self._data_))
else:
raise TypeError("Argument must be a list.")
def deepcopy(self):
return copy.deepcopy(self._data_)
def __deepcopy__(self, memo):
return copy.deepcopy(self._data_, memo)
def poop(self):
raise Exception("This is a list. It does not poop.")
@ -478,29 +412,29 @@ class ProtectedTuple(collections.Sequence):
"""
A class allowing read-only 'view' of a tuple.
The object can be treated like a normal tuple, but its contents will be returned as protected objects.
Note: It would be nice if we could inherit from list or tuple so that isinstance checks would work.
However, doing this causes tuple(obj) to return unprotected results (importantly, this means
unpacking into function arguments will also fail)
"""
def __init__(self, data):
self._data_ = data
## List of methods to directly wrap from _data_
wrapMethods = ['__contains__', '__eq__', '__format__', '__ge__', '__getnewargs__', '__gt__', '__hash__', '__le__', '__len__', '__lt__', '__ne__', '__reduce__', '__reduce_ex__', '__repr__', '__str__', 'count', 'index']
## List of methods which wrap from _data_ but return protected results
protectMethods = ['__getitem__', '__getslice__', '__iter__', '__add__', '__mul__', '__reversed__', '__rmul__']
## Template methods
# # Template methods
def wrapMethod(methodName):
return lambda self, *a, **k: getattr(self._data_, methodName)(*a, **k)
def protectMethod(methodName):
return lambda self, *a, **k: protect(getattr(self._data_, methodName)(*a, **k))
## Directly (and explicitly) wrap some methods from _data_
## Many of these methods can not be intercepted using __getattribute__, so they
## must be implemented explicitly
@ -511,14 +445,14 @@ class ProtectedTuple(collections.Sequence):
for methodName in protectMethods:
locals()[methodName] = protectMethod(methodName)
## Add a few extra methods.
def deepcopy(self):
return copy.deepcopy(self._data_)
def __deepcopy__(self, memo):
return copy.deepcopy(self._data_, memo)
def protect(obj):
@ -530,14 +464,14 @@ def protect(obj):
return ProtectedTuple(obj)
else:
return obj
if __name__ == '__main__':
d = {'x': 1, 'y': [1,2], 'z': ({'a': 2, 'b': [3,4], 'c': (5,6)}, 1, 2)}
dp = protect(d)
l = [1, 'x', ['a', 'b'], ('c', 'd'), {'x': 1, 'y': 2}]
lp = protect(l)
t = (1, 'x', ['a', 'b'], ('c', 'd'), {'x': 1, 'y': 2})
tp = protect(t)
tp = protect(t)