Commit ca9d0ed1 authored by Luke Campagnola's avatar Luke Campagnola
Browse files

Added preliminary support for python 2.6

Fixed setup.py to automatically search for all sub-packages
parent c022f3a1
......@@ -15,8 +15,8 @@ import os, sys
## check python version
## Allow anything >= 2.7
if sys.version_info[0] < 2 or (sys.version_info[0] == 2 and sys.version_info[1] < 7):
raise Exception("Pyqtgraph requires Python version 2.7 (this is %d.%d)" % (sys.version_info[0], sys.version_info[1]))
if sys.version_info[0] < 2 or (sys.version_info[0] == 2 and sys.version_info[1] < 6):
raise Exception("Pyqtgraph requires Python version 2.6 or greater (this is %d.%d)" % (sys.version_info[0], sys.version_info[1]))
## helpers for 2/3 compatibility
from . import python2_3
......
......@@ -10,7 +10,7 @@ as it can be converted to/from a string using repr and eval.
"""
import re, os, sys
from collections import OrderedDict
from pgcollections import OrderedDict
GLOBAL_PATH = None # so not thread safe.
from . import units
from .python2_3 import asUnicode
......
......@@ -9,7 +9,7 @@ else:
from exampleLoaderTemplate_pyqt import Ui_Form
import os, sys
from collections import OrderedDict
from pyqtgraph.pgcollections import OrderedDict
examples = OrderedDict([
('Command-line usage', 'CLIexample.py'),
......
......@@ -14,7 +14,6 @@ import pyqtgraph as pg
from pyqtgraph.Qt import QtCore, QtGui
import collections
app = QtGui.QApplication([])
import pyqtgraph.parametertree.parameterTypes as pTypes
from pyqtgraph.parametertree import Parameter, ParameterTree, ParameterItem, registerParameterType
......
# -*- coding: utf-8 -*-
from pyqtgraph.Qt import QtCore, QtGui, USE_PYSIDE
from .Node import *
from collections import OrderedDict
from pyqtgraph.pgcollections import OrderedDict
from pyqtgraph.widgets.TreeWidget import *
## pyside and pyqt use incompatible ui files.
......
......@@ -3,7 +3,7 @@ from pyqtgraph.Qt import QtCore, QtGui
from pyqtgraph.graphicsItems.GraphicsObject import GraphicsObject
import pyqtgraph.functions as fn
from .Terminal import *
from collections import OrderedDict
from pyqtgraph.pgcollections import OrderedDict
from pyqtgraph.debug import *
import numpy as np
from .eq import *
......
# -*- coding: utf-8 -*-
from collections import OrderedDict
from pyqtgraph.pgcollections import OrderedDict
import os, types
from pyqtgraph.debug import printExc
from ..Node import Node
......
......@@ -42,7 +42,7 @@ class ArrowItem(QtGui.QGraphicsPathItem):
def setStyle(self, **opts):
self.opts = opts
opt = {k:self.opts[k] for k in ['headLen', 'tipAngle', 'baseAngle', 'tailLen', 'tailWidth']}
opt = dict([(k,self.opts[k]) for k in ['headLen', 'tipAngle', 'baseAngle', 'tailLen', 'tailWidth']])
self.path = fn.makeArrowPath(**opt)
self.setPath(self.path)
......
......@@ -3,13 +3,14 @@ from pyqtgraph.python2_3 import sortList
import pyqtgraph.functions as fn
from .GraphicsObject import GraphicsObject
from .GraphicsWidget import GraphicsWidget
import weakref, collections
import weakref
from pyqtgraph.pgcollections import OrderedDict
import numpy as np
__all__ = ['TickSliderItem', 'GradientEditorItem']
Gradients = collections.OrderedDict([
Gradients = OrderedDict([
('thermal', {'ticks': [(0.3333, (185, 0, 0, 255)), (0.6666, (255, 220, 0, 255)), (1, (255, 255, 255, 255)), (0, (0, 0, 0, 255))], 'mode': 'rgb'}),
('flame', {'ticks': [(0.2, (7, 0, 220, 255)), (0.5, (236, 0, 134, 255)), (0.8, (246, 246, 0, 255)), (1.0, (255, 255, 255, 255)), (0.0, (0, 0, 0, 255))], 'mode': 'rgb'}),
('yellowy', {'ticks': [(0.0, (0, 0, 0, 255)), (0.2328863796753704, (32, 0, 129, 255)), (0.8362738179251941, (255, 255, 0, 255)), (0.5257586450247, (115, 15, 255, 255)), (1.0, (255, 255, 255, 255))], 'mode': 'rgb'} ),
......
......@@ -35,7 +35,6 @@ from .. LabelItem import LabelItem
from .. GraphicsWidget import GraphicsWidget
from .. ButtonItem import ButtonItem
from pyqtgraph.WidgetGroup import WidgetGroup
import collections
__all__ = ['PlotItem']
......
......@@ -7,7 +7,7 @@ import numpy as np
import scipy.stats
import weakref
import pyqtgraph.debug as debug
from collections import OrderedDict
from pyqtgraph.pgcollections import OrderedDict
#import pyqtgraph as pg
__all__ = ['ScatterPlotItem', 'SpotItem']
......
......@@ -9,7 +9,6 @@ from pyqtgraph.GraphicsScene import GraphicsScene
import pyqtgraph
import weakref
from copy import deepcopy
import collections
__all__ = ['ViewBox']
......@@ -111,12 +110,6 @@ class ViewBox(GraphicsWidget):
}
#self.exportMethods = collections.OrderedDict([
#('SVG', self.saveSvg),
#('Image', self.saveImage),
#('Print', self.savePrint),
#])
self.setFlag(self.ItemClipsChildrenToShape)
self.setFlag(self.ItemIsFocusable, True) ## so we can receive key presses
......
from pyqtgraph.Qt import QtGui, QtCore
import collections, os, weakref, re
import os, weakref, re
from pyqtgraph.pgcollections import OrderedDict
from .ParameterItem import ParameterItem
PARAM_TYPES = {}
......@@ -216,7 +217,7 @@ class Parameter(QtCore.QObject):
def getValues(self):
"""Return a tree of all values that are children of this parameter"""
vals = collections.OrderedDict()
vals = OrderedDict()
for ch in self:
vals[ch.name()] = (ch.value(), ch.getValues())
return vals
......@@ -227,7 +228,7 @@ class Parameter(QtCore.QObject):
The tree state may be restored from this structure using restoreState()
"""
state = self.opts.copy()
state['children'] = collections.OrderedDict([(ch.name(), ch.saveState()) for ch in self])
state['children'] = OrderedDict([(ch.name(), ch.saveState()) for ch in self])
if state['type'] is None:
global PARAM_NAMES
state['type'] = PARAM_NAMES.get(type(self), None)
......@@ -363,7 +364,7 @@ class Parameter(QtCore.QObject):
most parameters will accept a common set of options: value, name, limits,
default, readonly, removable, renamable, visible, and enabled.
"""
changed = collections.OrderedDict()
changed = OrderedDict()
for k in opts:
if k == 'value':
self.setValue(opts[k])
......
from pyqtgraph.Qt import QtGui, QtCore
import collections, os, weakref, re
import os, weakref, re
class ParameterItem(QtGui.QTreeWidgetItem):
"""
......
from pyqtgraph.Qt import QtCore, QtGui
from pyqtgraph.widgets.TreeWidget import TreeWidget
import collections, os, weakref, re
import os, weakref, re
#import functions as fn
......
......@@ -5,7 +5,8 @@ from .ParameterItem import ParameterItem
from pyqtgraph.widgets.SpinBox import SpinBox
from pyqtgraph.widgets.ColorButton import ColorButton
import pyqtgraph as pg
import os, collections
import os
from pyqtgraph.pgcollections import OrderedDict
class WidgetParameterItem(ParameterItem):
"""
......@@ -481,8 +482,6 @@ class ListParameterItem(WidgetParameterItem):
def limitsChanged(self, param, limits):
# set up forward / reverse mappings for name:value
#self.forward = collections.OrderedDict([('', None)]) ## name: value
#self.reverse = collections.OrderedDict([(None, '')]) ## value: name
if len(limits) == 0:
limits = [''] ## Can never have an empty list--there is always at least a singhe blank item.
......@@ -507,8 +506,8 @@ class ListParameter(Parameter):
itemClass = ListParameterItem
def __init__(self, **opts):
self.forward = collections.OrderedDict() ## name: value
self.reverse = collections.OrderedDict() ## value: name
self.forward = OrderedDict() ## name: value
self.reverse = OrderedDict() ## value: name
## Parameter uses 'limits' option to define the set of allowed values
if 'values' in opts:
......@@ -528,8 +527,8 @@ class ListParameter(Parameter):
@staticmethod
def mapping(limits):
## Return forward and reverse mapping dictionaries given a limit specification
forward = collections.OrderedDict() ## name: value
reverse = collections.OrderedDict() ## value: name
forward = OrderedDict() ## name: value
reverse = OrderedDict() ## value: name
if isinstance(limits, dict):
for k, v in limits.items():
forward[k] = v
......
# -*- coding: utf-8 -*-
"""
advancedTypes.py - Basic data structures not included with python
Copyright 2010 Luke Campagnola
Distributed under MIT/X11 license. See license.txt for more infomation.
Includes:
- OrderedDict - Dictionary which preserves the order of its elements
- BiDict, ReverseDict - Bi-directional dictionaries
- ThreadsafeDict, ThreadsafeList - Self-mutexed data structures
"""
import threading, sys, copy, collections
#from debug import *
try:
from collections import OrderedDict
except:
# Deprecated; this class is now present in Python 2.7 as collections.OrderedDict
# 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)
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:
d = BiDict({'x': 1, 'y': 2})
d['x']
1
d[[2]]
'y'
"""
def __init__(self, data=None):
if data is None:
data = {}
self.reverse = {}
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]]
else:
return dict.__getitem__(self, item)
def __setitem__(self, item, value):
self.reverse[value] = item
dict.__setitem__(self, item, value)
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."""
def __init__(self, data=None):
if data is None:
data = {}
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")
class ThreadsafeDict(dict):
"""Extends dict so that getitem, setitem, and contains are all thread-safe.
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)
for k in self:
if type(self[k]) is dict:
self[k] = ThreadsafeDict(self[k])
def __getitem__(self, attr):
self.lock()
try:
val = dict.__getitem__(self, attr)
finally:
self.unlock()
return val
def __setitem__(self, attr, val):
if type(val) is dict:
val = ThreadsafeDict(val)
self.lock()
try:
dict.__setitem__(self, attr, val)
finally:
self.unlock()
def __contains__(self, attr):
self.lock()
try:
val = dict.__contains__(self, attr)
finally:
self.unlock()
return val
def __len__(self):
self.lock()
try:
val = dict.__len__(self)
finally:
self.unlock()
return val
def clear(self):
self.lock()
try:
dict.clear(self)
finally:
self.unlock()
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)
for k in self:
self[k] = mkThreadsafe(self[k])
def __getitem__(self, attr):
self.lock()
try:
val = list.__getitem__(self, attr)
finally:
self.unlock()
return val
def __setitem__(self, attr, val):
val = makeThreadsafe(val)
self.lock()
try:
list.__setitem__(self, attr, val)
finally:
self.unlock()
def __contains__(self, attr):
self.lock()
try:
val = list.__contains__(self, attr)
finally:
self.unlock()
return val
def __len__(self):
self.lock()
try:
val = list.__len__(self)
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)
elif type(obj) is list:
return ThreadsafeList(obj)
elif type(obj) in [str, int, float, bool, tuple]:
return obj
else:
raise Exception("Not sure how to make object of type %s thread-safe" % str(type(obj)))
class Locker:
def __init__(self, lock):
self.lock = lock
self.lock.acquire()
def __del__(self):
try:
self.lock.release()
except:
pass
class CaselessDict(OrderedDict):
"""Case-insensitive dict. Values can be set and retrieved using keys of any case.
Note that when iterating, the original case is returned for each key."""
def __init__(self, *args):
OrderedDict.__init__(self, {}) ## requirement for the empty {} here seems to be a python bug?
self.keyMap = OrderedDict([(k.lower(), k) for k in OrderedDict.keys(self)])
if len(args) == 0:
return
elif len(args) == 1 and isinstance(args[0], dict):
for k in args[0]:
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:
OrderedDict.__setitem__(self, self.keyMap[kl], val)
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")
def clear(self):
OrderedDict.clear(self)
self.keyMap.clear()
class ProtectedDict(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
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
for methodName in wrapMethods:
locals()[methodName] = wrapMethod(methodName)
## Wrap some methods from _data_ with the results converted to protected objects
for methodName in protectMethods:
locals()[methodName] = protectMethod(methodName)
## Disable any methods that could change data in the list
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):