commit
a63fd24442
@ -17,16 +17,20 @@ class Container(object):
|
||||
|
||||
def containerChanged(self, c):
|
||||
self._container = c
|
||||
if c is None:
|
||||
self.area = None
|
||||
else:
|
||||
self.area = c.area
|
||||
|
||||
def type(self):
|
||||
return None
|
||||
|
||||
def insert(self, new, pos=None, neighbor=None):
|
||||
# remove from existing parent first
|
||||
new.setParent(None)
|
||||
|
||||
if not isinstance(new, list):
|
||||
new = [new]
|
||||
for n in new:
|
||||
# remove from existing parent first
|
||||
n.setParent(None)
|
||||
if neighbor is None:
|
||||
if pos == 'before':
|
||||
index = 0
|
||||
@ -40,34 +44,37 @@ class Container(object):
|
||||
index += 1
|
||||
|
||||
for n in new:
|
||||
#print "change container", n, " -> ", self
|
||||
n.containerChanged(self)
|
||||
#print "insert", n, " -> ", self, index
|
||||
self._insertItem(n, index)
|
||||
#print "change container", n, " -> ", self
|
||||
n.containerChanged(self)
|
||||
index += 1
|
||||
n.sigStretchChanged.connect(self.childStretchChanged)
|
||||
#print "child added", self
|
||||
self.updateStretch()
|
||||
|
||||
def apoptose(self, propagate=True):
|
||||
##if there is only one (or zero) item in this container, disappear.
|
||||
# if there is only one (or zero) item in this container, disappear.
|
||||
# if propagate is True, then also attempt to apoptose parent containers.
|
||||
cont = self._container
|
||||
c = self.count()
|
||||
if c > 1:
|
||||
return
|
||||
if self.count() == 1: ## if there is one item, give it to the parent container (unless this is the top)
|
||||
if self is self.area.topContainer:
|
||||
if c == 1: ## if there is one item, give it to the parent container (unless this is the top)
|
||||
ch = self.widget(0)
|
||||
if (self.area is not None and self is self.area.topContainer and not isinstance(ch, Container)) or self.container() is None:
|
||||
return
|
||||
self.container().insert(self.widget(0), 'before', self)
|
||||
self.container().insert(ch, 'before', self)
|
||||
#print "apoptose:", self
|
||||
self.close()
|
||||
if propagate and cont is not None:
|
||||
cont.apoptose()
|
||||
|
||||
|
||||
def close(self):
|
||||
self.area = None
|
||||
self._container = None
|
||||
self.setParent(None)
|
||||
if self.area is not None and self.area.topContainer is self:
|
||||
self.area.topContainer = None
|
||||
self.containerChanged(None)
|
||||
|
||||
def childEvent(self, ev):
|
||||
ch = ev.child()
|
||||
@ -92,7 +99,6 @@ class Container(object):
|
||||
###Set the stretch values for this container to reflect its contents
|
||||
pass
|
||||
|
||||
|
||||
def stretch(self):
|
||||
"""Return the stretch factors for this container"""
|
||||
return self._stretch
|
||||
|
@ -36,6 +36,7 @@ class Dock(QtGui.QWidget, DockDrop):
|
||||
self.widgetArea.setLayout(self.layout)
|
||||
self.widgetArea.setSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding)
|
||||
self.widgets = []
|
||||
self._container = None
|
||||
self.currentRow = 0
|
||||
#self.titlePos = 'top'
|
||||
self.raiseOverlay()
|
||||
@ -187,9 +188,6 @@ class Dock(QtGui.QWidget, DockDrop):
|
||||
def name(self):
|
||||
return self._name
|
||||
|
||||
def container(self):
|
||||
return self._container
|
||||
|
||||
def addWidget(self, widget, row=None, col=0, rowspan=1, colspan=1):
|
||||
"""
|
||||
Add a new widget to the interior of this Dock.
|
||||
@ -202,7 +200,6 @@ class Dock(QtGui.QWidget, DockDrop):
|
||||
self.layout.addWidget(widget, row, col, rowspan, colspan)
|
||||
self.raiseOverlay()
|
||||
|
||||
|
||||
def startDrag(self):
|
||||
self.drag = QtGui.QDrag(self)
|
||||
mime = QtCore.QMimeData()
|
||||
@ -216,21 +213,30 @@ class Dock(QtGui.QWidget, DockDrop):
|
||||
def float(self):
|
||||
self.area.floatDock(self)
|
||||
|
||||
def container(self):
|
||||
return self._container
|
||||
|
||||
def containerChanged(self, c):
|
||||
if self._container is not None:
|
||||
# ask old container to close itself if it is no longer needed
|
||||
self._container.apoptose()
|
||||
#print self.name(), "container changed"
|
||||
self._container = c
|
||||
if c.type() != 'tab':
|
||||
self.moveLabel = True
|
||||
self.label.setDim(False)
|
||||
if c is None:
|
||||
self.area = None
|
||||
else:
|
||||
self.moveLabel = False
|
||||
|
||||
self.setOrientation(force=True)
|
||||
|
||||
self.area = c.area
|
||||
if c.type() != 'tab':
|
||||
self.moveLabel = True
|
||||
self.label.setDim(False)
|
||||
else:
|
||||
self.moveLabel = False
|
||||
|
||||
self.setOrientation(force=True)
|
||||
|
||||
def raiseDock(self):
|
||||
"""If this Dock is stacked underneath others, raise it to the top."""
|
||||
self.container().raiseDock(self)
|
||||
|
||||
|
||||
def close(self):
|
||||
"""Remove this dock from the DockArea it lives inside."""
|
||||
|
@ -61,6 +61,8 @@ class DockArea(Container, QtGui.QWidget, DockDrop):
|
||||
if isinstance(relativeTo, basestring):
|
||||
relativeTo = self.docks[relativeTo]
|
||||
container = self.getContainer(relativeTo)
|
||||
if container is None:
|
||||
raise TypeError("Dock %s is not contained in a DockArea; cannot add another dock relative to it." % relativeTo)
|
||||
neighbor = relativeTo
|
||||
|
||||
## what container type do we need?
|
||||
@ -98,7 +100,6 @@ class DockArea(Container, QtGui.QWidget, DockDrop):
|
||||
#print "request insert", dock, insertPos, neighbor
|
||||
old = dock.container()
|
||||
container.insert(dock, insertPos, neighbor)
|
||||
dock.area = self
|
||||
self.docks[dock.name()] = dock
|
||||
if old is not None:
|
||||
old.apoptose()
|
||||
@ -142,23 +143,19 @@ class DockArea(Container, QtGui.QWidget, DockDrop):
|
||||
|
||||
def insert(self, new, pos=None, neighbor=None):
|
||||
if self.topContainer is not None:
|
||||
# Adding new top-level container; addContainer() should
|
||||
# take care of giving the old top container a new home.
|
||||
self.topContainer.containerChanged(None)
|
||||
self.layout.addWidget(new)
|
||||
new.containerChanged(self)
|
||||
self.topContainer = new
|
||||
#print self, "set top:", new
|
||||
new._container = self
|
||||
self.raiseOverlay()
|
||||
#print "Insert top:", new
|
||||
|
||||
def count(self):
|
||||
if self.topContainer is None:
|
||||
return 0
|
||||
return 1
|
||||
|
||||
|
||||
#def paintEvent(self, ev):
|
||||
#self.drawDockOverlay()
|
||||
|
||||
def resizeEvent(self, ev):
|
||||
self.resizeOverlay(self.size())
|
||||
|
||||
@ -180,7 +177,6 @@ class DockArea(Container, QtGui.QWidget, DockDrop):
|
||||
area.win.resize(dock.size())
|
||||
area.moveDock(dock, 'top', None)
|
||||
|
||||
|
||||
def removeTempArea(self, area):
|
||||
self.tempAreas.remove(area)
|
||||
#print "close window", area.window()
|
||||
@ -212,14 +208,20 @@ class DockArea(Container, QtGui.QWidget, DockDrop):
|
||||
childs.append(self.childState(obj.widget(i)))
|
||||
return (obj.type(), childs, obj.saveState())
|
||||
|
||||
|
||||
def restoreState(self, state):
|
||||
def restoreState(self, state, missing='error', extra='bottom'):
|
||||
"""
|
||||
Restore Dock configuration as generated by saveState.
|
||||
|
||||
Note that this function does not create any Docks--it will only
|
||||
This function does not create any Docks--it will only
|
||||
restore the arrangement of an existing set of Docks.
|
||||
|
||||
By default, docks that are described in *state* but do not exist
|
||||
in the dock area will cause an exception to be raised. This behavior
|
||||
can be changed by setting *missing* to 'ignore' or 'create'.
|
||||
|
||||
Extra docks that are in the dockarea but that are not mentioned in
|
||||
*state* will be added to the bottom of the dockarea, unless otherwise
|
||||
specified by the *extra* argument.
|
||||
"""
|
||||
|
||||
## 1) make dict of all docks and list of existing containers
|
||||
@ -229,17 +231,22 @@ class DockArea(Container, QtGui.QWidget, DockDrop):
|
||||
|
||||
## 2) create container structure, move docks into new containers
|
||||
if state['main'] is not None:
|
||||
self.buildFromState(state['main'], docks, self)
|
||||
self.buildFromState(state['main'], docks, self, missing=missing)
|
||||
|
||||
## 3) create floating areas, populate
|
||||
for s in state['float']:
|
||||
a = self.addTempArea()
|
||||
a.buildFromState(s[0]['main'], docks, a)
|
||||
a.buildFromState(s[0]['main'], docks, a, missing=missing)
|
||||
a.win.setGeometry(*s[1])
|
||||
a.apoptose() # ask temp area to close itself if it is empty
|
||||
|
||||
## 4) Add any remaining docks to the bottom
|
||||
## 4) Add any remaining docks to a float
|
||||
for d in docks.values():
|
||||
self.moveDock(d, 'below', None)
|
||||
if extra == 'float':
|
||||
a = self.addTempArea()
|
||||
a.addDock(d, 'below')
|
||||
else:
|
||||
self.moveDock(d, extra, None)
|
||||
|
||||
#print "\nKill old containers:"
|
||||
## 5) kill old containers
|
||||
@ -248,8 +255,7 @@ class DockArea(Container, QtGui.QWidget, DockDrop):
|
||||
for a in oldTemps:
|
||||
a.apoptose()
|
||||
|
||||
|
||||
def buildFromState(self, state, docks, root, depth=0):
|
||||
def buildFromState(self, state, docks, root, depth=0, missing='error'):
|
||||
typ, contents, state = state
|
||||
pfx = " " * depth
|
||||
if typ == 'dock':
|
||||
@ -257,7 +263,15 @@ class DockArea(Container, QtGui.QWidget, DockDrop):
|
||||
obj = docks[contents]
|
||||
del docks[contents]
|
||||
except KeyError:
|
||||
raise Exception('Cannot restore dock state; no dock with name "%s"' % contents)
|
||||
if missing == 'error':
|
||||
raise Exception('Cannot restore dock state; no dock with name "%s"' % contents)
|
||||
elif missing == 'create':
|
||||
obj = Dock(name=contents)
|
||||
elif missing == 'ignore':
|
||||
return
|
||||
else:
|
||||
raise ValueError('"missing" argument must be one of "error", "create", or "ignore".')
|
||||
|
||||
else:
|
||||
obj = self.makeContainer(typ)
|
||||
|
||||
@ -266,10 +280,11 @@ class DockArea(Container, QtGui.QWidget, DockDrop):
|
||||
|
||||
if typ != 'dock':
|
||||
for o in contents:
|
||||
self.buildFromState(o, docks, obj, depth+1)
|
||||
self.buildFromState(o, docks, obj, depth+1, missing=missing)
|
||||
# remove this container if possible. (there are valid situations when a restore will
|
||||
# generate empty containers, such as when using missing='ignore')
|
||||
obj.apoptose(propagate=False)
|
||||
obj.restoreState(state) ## this has to be done later?
|
||||
|
||||
obj.restoreState(state) ## this has to be done later?
|
||||
|
||||
def findAll(self, obj=None, c=None, d=None):
|
||||
if obj is None:
|
||||
@ -295,14 +310,15 @@ class DockArea(Container, QtGui.QWidget, DockDrop):
|
||||
d.update(d2)
|
||||
return (c, d)
|
||||
|
||||
def apoptose(self):
|
||||
def apoptose(self, propagate=True):
|
||||
# remove top container if possible, close this area if it is temporary.
|
||||
#print "apoptose area:", self.temporary, self.topContainer, self.topContainer.count()
|
||||
if self.topContainer.count() == 0:
|
||||
if self.topContainer is None or self.topContainer.count() == 0:
|
||||
self.topContainer = None
|
||||
if self.temporary:
|
||||
self.home.removeTempArea(self)
|
||||
#self.close()
|
||||
|
||||
|
||||
def clear(self):
|
||||
docks = self.findAll()[1]
|
||||
for dock in docks.values():
|
||||
@ -322,12 +338,38 @@ class DockArea(Container, QtGui.QWidget, DockDrop):
|
||||
def dropEvent(self, *args):
|
||||
DockDrop.dropEvent(self, *args)
|
||||
|
||||
def printState(self, state=None, name='Main'):
|
||||
# for debugging
|
||||
if state is None:
|
||||
state = self.saveState()
|
||||
print("=== %s dock area ===" % name)
|
||||
if state['main'] is None:
|
||||
print(" (empty)")
|
||||
else:
|
||||
self._printAreaState(state['main'])
|
||||
for i, float in enumerate(state['float']):
|
||||
self.printState(float[0], name='float %d' % i)
|
||||
|
||||
class TempAreaWindow(QtGui.QMainWindow):
|
||||
def _printAreaState(self, area, indent=0):
|
||||
if area[0] == 'dock':
|
||||
print(" " * indent + area[0] + " " + str(area[1:]))
|
||||
return
|
||||
else:
|
||||
print(" " * indent + area[0])
|
||||
for ch in area[1]:
|
||||
self._printAreaState(ch, indent+1)
|
||||
|
||||
|
||||
|
||||
class TempAreaWindow(QtGui.QWidget):
|
||||
def __init__(self, area, **kwargs):
|
||||
QtGui.QMainWindow.__init__(self, **kwargs)
|
||||
self.setCentralWidget(area)
|
||||
QtGui.QWidget.__init__(self, **kwargs)
|
||||
self.layout = QtGui.QGridLayout()
|
||||
self.setLayout(self.layout)
|
||||
self.layout.setContentsMargins(0, 0, 0, 0)
|
||||
self.dockarea = area
|
||||
self.layout.addWidget(area)
|
||||
|
||||
def closeEvent(self, *args, **kwargs):
|
||||
self.centralWidget().clear()
|
||||
QtGui.QMainWindow.closeEvent(self, *args, **kwargs)
|
||||
def closeEvent(self, *args):
|
||||
self.dockarea.clear()
|
||||
QtGui.QWidget.closeEvent(self, *args)
|
||||
|
189
pyqtgraph/dockarea/tests/test_dockarea.py
Normal file
189
pyqtgraph/dockarea/tests/test_dockarea.py
Normal file
@ -0,0 +1,189 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import pytest
|
||||
import pyqtgraph as pg
|
||||
from pyqtgraph.ordereddict import OrderedDict
|
||||
pg.mkQApp()
|
||||
|
||||
import pyqtgraph.dockarea as da
|
||||
|
||||
def test_dockarea():
|
||||
a = da.DockArea()
|
||||
d1 = da.Dock("dock 1")
|
||||
a.addDock(d1, 'left')
|
||||
|
||||
assert a.topContainer is d1.container()
|
||||
assert d1.container().container() is a
|
||||
assert d1.area is a
|
||||
assert a.topContainer.widget(0) is d1
|
||||
|
||||
d2 = da.Dock("dock 2")
|
||||
a.addDock(d2, 'right')
|
||||
|
||||
assert a.topContainer is d1.container()
|
||||
assert a.topContainer is d2.container()
|
||||
assert d1.container().container() is a
|
||||
assert d2.container().container() is a
|
||||
assert d2.area is a
|
||||
assert a.topContainer.widget(0) is d1
|
||||
assert a.topContainer.widget(1) is d2
|
||||
|
||||
d3 = da.Dock("dock 3")
|
||||
a.addDock(d3, 'bottom')
|
||||
|
||||
assert a.topContainer is d3.container()
|
||||
assert d2.container().container() is d3.container()
|
||||
assert d1.container().container() is d3.container()
|
||||
assert d1.container().container().container() is a
|
||||
assert d2.container().container().container() is a
|
||||
assert d3.container().container() is a
|
||||
assert d3.area is a
|
||||
assert d2.area is a
|
||||
assert a.topContainer.widget(0) is d1.container()
|
||||
assert a.topContainer.widget(1) is d3
|
||||
|
||||
d4 = da.Dock("dock 4")
|
||||
a.addDock(d4, 'below', d3)
|
||||
|
||||
assert d4.container().type() == 'tab'
|
||||
assert d4.container() is d3.container()
|
||||
assert d3.container().container() is d2.container().container()
|
||||
assert d4.area is a
|
||||
a.printState()
|
||||
|
||||
# layout now looks like:
|
||||
# vcontainer
|
||||
# hcontainer
|
||||
# dock 1
|
||||
# dock 2
|
||||
# tcontainer
|
||||
# dock 3
|
||||
# dock 4
|
||||
|
||||
# test save/restore state
|
||||
state = a.saveState()
|
||||
a2 = da.DockArea()
|
||||
# default behavior is to raise exception if docks are missing
|
||||
with pytest.raises(Exception):
|
||||
a2.restoreState(state)
|
||||
|
||||
# test restore with ignore missing
|
||||
a2.restoreState(state, missing='ignore')
|
||||
assert a2.topContainer is None
|
||||
|
||||
# test restore with auto-create
|
||||
a2.restoreState(state, missing='create')
|
||||
assert a2.saveState() == state
|
||||
a2.printState()
|
||||
|
||||
# double-check that state actually matches the output of saveState()
|
||||
c1 = a2.topContainer
|
||||
assert c1.type() == 'vertical'
|
||||
c2 = c1.widget(0)
|
||||
c3 = c1.widget(1)
|
||||
assert c2.type() == 'horizontal'
|
||||
assert c2.widget(0).name() == 'dock 1'
|
||||
assert c2.widget(1).name() == 'dock 2'
|
||||
assert c3.type() == 'tab'
|
||||
assert c3.widget(0).name() == 'dock 3'
|
||||
assert c3.widget(1).name() == 'dock 4'
|
||||
|
||||
# test restore with docks already present
|
||||
a3 = da.DockArea()
|
||||
a3docks = []
|
||||
for i in range(1, 5):
|
||||
dock = da.Dock('dock %d' % i)
|
||||
a3docks.append(dock)
|
||||
a3.addDock(dock, 'right')
|
||||
a3.restoreState(state)
|
||||
assert a3.saveState() == state
|
||||
|
||||
# test restore with extra docks present
|
||||
a3 = da.DockArea()
|
||||
a3docks = []
|
||||
for i in [1, 2, 5, 4, 3]:
|
||||
dock = da.Dock('dock %d' % i)
|
||||
a3docks.append(dock)
|
||||
a3.addDock(dock, 'left')
|
||||
a3.restoreState(state)
|
||||
a3.printState()
|
||||
|
||||
|
||||
# test a more complex restore
|
||||
a4 = da.DockArea()
|
||||
state1 = {'float': [], 'main':
|
||||
('horizontal', [
|
||||
('vertical', [
|
||||
('horizontal', [
|
||||
('tab', [
|
||||
('dock', 'dock1', {}),
|
||||
('dock', 'dock2', {}),
|
||||
('dock', 'dock3', {}),
|
||||
('dock', 'dock4', {})
|
||||
], {'index': 1}),
|
||||
('vertical', [
|
||||
('dock', 'dock5', {}),
|
||||
('horizontal', [
|
||||
('dock', 'dock6', {}),
|
||||
('dock', 'dock7', {})
|
||||
], {'sizes': [184, 363]})
|
||||
], {'sizes': [355, 120]})
|
||||
], {'sizes': [9, 552]})
|
||||
], {'sizes': [480]}),
|
||||
('dock', 'dock8', {})
|
||||
], {'sizes': [566, 69]})
|
||||
}
|
||||
|
||||
state2 = {'float': [], 'main':
|
||||
('horizontal', [
|
||||
('vertical', [
|
||||
('horizontal', [
|
||||
('dock', 'dock2', {}),
|
||||
('vertical', [
|
||||
('dock', 'dock5', {}),
|
||||
('horizontal', [
|
||||
('dock', 'dock6', {}),
|
||||
('dock', 'dock7', {})
|
||||
], {'sizes': [492, 485]})
|
||||
], {'sizes': [936, 0]})
|
||||
], {'sizes': [172, 982]})
|
||||
], {'sizes': [941]}),
|
||||
('vertical', [
|
||||
('dock', 'dock8', {}),
|
||||
('dock', 'dock4', {}),
|
||||
('dock', 'dock1', {})
|
||||
], {'sizes': [681, 225, 25]})
|
||||
], {'sizes': [1159, 116]})}
|
||||
|
||||
a4.restoreState(state1, missing='create')
|
||||
# dock3 not mentioned in restored state; stays in dockarea by default
|
||||
c, d = a4.findAll()
|
||||
assert d['dock3'].area is a4
|
||||
|
||||
a4.restoreState(state2, missing='ignore', extra='float')
|
||||
a4.printState()
|
||||
|
||||
c, d = a4.findAll()
|
||||
# dock3 not mentioned in restored state; goes to float due to `extra` argument
|
||||
assert d['dock3'].area is not a4
|
||||
assert d['dock1'].container() is d['dock4'].container() is d['dock8'].container()
|
||||
assert d['dock6'].container() is d['dock7'].container()
|
||||
assert a4 is d['dock2'].area is d['dock2'].container().container().container()
|
||||
assert a4 is d['dock5'].area is d['dock5'].container().container().container().container()
|
||||
|
||||
# States should be the same with two exceptions:
|
||||
# dock3 is in a float because it does not appear in state2
|
||||
# a superfluous vertical splitter in state2 has been removed
|
||||
state4 = a4.saveState()
|
||||
state4['main'][1][0] = state4['main'][1][0][1][0]
|
||||
assert clean_state(state4['main']) == clean_state(state2['main'])
|
||||
|
||||
|
||||
def clean_state(state):
|
||||
# return state dict with sizes removed
|
||||
ch = [clean_state(x) for x in state[1]] if isinstance(state[1], list) else state[1]
|
||||
state = (state[0], ch, {})
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
test_dockarea()
|
@ -20,108 +20,112 @@
|
||||
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
# OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
from UserDict import DictMixin
|
||||
import sys
|
||||
if sys.version[0] > '2':
|
||||
from collections import OrderedDict
|
||||
else:
|
||||
from UserDict import DictMixin
|
||||
|
||||
class OrderedDict(dict, 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 __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 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:
|
||||
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]
|
||||
curr[2] = end[1] = self.__map[key] = [key, curr, end]
|
||||
dict.__setitem__(self, key, value)
|
||||
while curr is not end:
|
||||
yield curr[0]
|
||||
curr = curr[1]
|
||||
|
||||
def __delitem__(self, key):
|
||||
dict.__delitem__(self, key)
|
||||
key, prev, next = self.__map.pop(key)
|
||||
prev[2] = next
|
||||
next[1] = prev
|
||||
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 __iter__(self):
|
||||
end = self.__end
|
||||
curr = end[2]
|
||||
while curr is not end:
|
||||
yield curr[0]
|
||||
curr = curr[2]
|
||||
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 __reversed__(self):
|
||||
end = self.__end
|
||||
curr = end[1]
|
||||
while curr is not end:
|
||||
yield curr[0]
|
||||
curr = curr[1]
|
||||
def keys(self):
|
||||
return list(self)
|
||||
|
||||
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
|
||||
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 __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 __repr__(self):
|
||||
if not self:
|
||||
return '%s()' % (self.__class__.__name__,)
|
||||
return '%s(%r)' % (self.__class__.__name__, self.items())
|
||||
|
||||
def keys(self):
|
||||
return list(self)
|
||||
def copy(self):
|
||||
return self.__class__(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
|
||||
@classmethod
|
||||
def fromkeys(cls, iterable, value=None):
|
||||
d = cls()
|
||||
for key in iterable:
|
||||
d[key] = value
|
||||
return d
|
||||
|
||||
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:
|
||||
def __eq__(self, other):
|
||||
if isinstance(other, OrderedDict):
|
||||
if len(self) != len(other):
|
||||
return False
|
||||
return True
|
||||
return dict.__eq__(self, other)
|
||||
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
|
||||
def __ne__(self, other):
|
||||
return not self == other
|
||||
|
24
test.py
Normal file
24
test.py
Normal file
@ -0,0 +1,24 @@
|
||||
"""
|
||||
Script for invoking pytest with options to select Qt library
|
||||
"""
|
||||
|
||||
import sys
|
||||
import pytest
|
||||
|
||||
args = sys.argv[1:]
|
||||
if '--pyside' in args:
|
||||
args.remove('--pyside')
|
||||
import PySide
|
||||
elif '--pyqt4' in args:
|
||||
args.remove('--pyqt4')
|
||||
import PyQt4
|
||||
elif '--pyqt5' in args:
|
||||
args.remove('--pyqt5')
|
||||
import PyQt5
|
||||
|
||||
import pyqtgraph as pg
|
||||
pg.systemInfo()
|
||||
|
||||
pytest.main(args)
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user