Merge pull request #1846 from pijyoi/import_hygiene

reduce pollution of pg namespace
This commit is contained in:
Ogi Moore 2021-06-25 23:26:26 -07:00 committed by GitHub
commit 93fa8664cb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
30 changed files with 115 additions and 147 deletions

View File

View File

View File

View File

@ -12,7 +12,7 @@ This module exists to smooth out some of the differences between PySide and PyQt
import os, sys, re, time, subprocess, warnings
from .python2_3 import asUnicode
from ..python2_3 import asUnicode
PYSIDE = 'PySide'
PYSIDE2 = 'PySide2'
@ -130,10 +130,29 @@ def _loadUiType(uiFile):
return form_class, base_class
# For historical reasons, pyqtgraph maintains a Qt4-ish interface back when
# there wasn't a QtWidgets module. This _was_ done by monkey-patching all of
# QtWidgets into the QtGui module. This monkey-patching modifies QtGui at a
# global level.
# To avoid this, we now maintain a local "mirror" of QtCore, QtGui and QtWidgets.
# Thus, when monkey-patching happens later on in this file, they will only affect
# the local modules and not the global modules.
def _copy_attrs(src, dst):
for o in dir(src):
if not hasattr(dst, o):
setattr(dst, o, getattr(src, o))
from . import QtCore, QtGui, QtWidgets
if QT_LIB == PYQT5:
# We're using PyQt5 which has a different structure so we're going to use a shim to
# recreate the Qt4 structure for Qt5
from PyQt5 import QtGui, QtCore, QtWidgets, sip, uic
import PyQt5.QtCore, PyQt5.QtGui, PyQt5.QtWidgets
_copy_attrs(PyQt5.QtCore, QtCore)
_copy_attrs(PyQt5.QtGui, QtGui)
_copy_attrs(PyQt5.QtWidgets, QtWidgets)
from PyQt5 import sip, uic
try:
from PyQt5 import QtSvg
@ -147,7 +166,12 @@ if QT_LIB == PYQT5:
VERSION_INFO = 'PyQt5 ' + QtCore.PYQT_VERSION_STR + ' Qt ' + QtCore.QT_VERSION_STR
elif QT_LIB == PYQT6:
from PyQt6 import QtGui, QtCore, QtWidgets, sip, uic
import PyQt6.QtCore, PyQt6.QtGui, PyQt6.QtWidgets
_copy_attrs(PyQt6.QtCore, QtCore)
_copy_attrs(PyQt6.QtGui, QtGui)
_copy_attrs(PyQt6.QtWidgets, QtWidgets)
from PyQt6 import sip, uic
try:
from PyQt6 import QtSvg
@ -165,7 +189,10 @@ elif QT_LIB == PYQT6:
VERSION_INFO = 'PyQt6 ' + QtCore.PYQT_VERSION_STR + ' Qt ' + QtCore.QT_VERSION_STR
elif QT_LIB == PYSIDE2:
from PySide2 import QtGui, QtCore, QtWidgets
import PySide2.QtCore, PySide2.QtGui, PySide2.QtWidgets
_copy_attrs(PySide2.QtCore, QtCore)
_copy_attrs(PySide2.QtGui, QtGui)
_copy_attrs(PySide2.QtWidgets, QtWidgets)
try:
from PySide2 import QtSvg
@ -182,7 +209,10 @@ elif QT_LIB == PYSIDE2:
VERSION_INFO = 'PySide2 ' + PySide2.__version__ + ' Qt ' + QtCore.__version__
elif QT_LIB == PYSIDE6:
from PySide6 import QtGui, QtCore, QtWidgets
import PySide6.QtCore, PySide6.QtGui, PySide6.QtWidgets
_copy_attrs(PySide6.QtCore, QtCore)
_copy_attrs(PySide6.QtGui, QtGui)
_copy_attrs(PySide6.QtWidgets, QtWidgets)
try:
from PySide6 import QtSvg

View File

@ -1,6 +1,8 @@
# -*- coding: utf-8 -*-
from .Qt import QtCore, QtGui
__all__ = ['ThreadsafeTimer']
class ThreadsafeTimer(QtCore.QObject):
"""
Thread-safe replacement for QTimer.

View File

@ -10,7 +10,7 @@ __version__ = '0.12.1'
## 'Qt' is a local module; it is intended mainly to cover up the differences
## between PyQt4 and PySide.
from .Qt import QtGui, mkQApp
from .Qt import QtCore, QtGui, mkQApp
from .Qt import exec_ as exec
## not really safe--If we accidentally create another QApplication, the process hangs (and it is very difficult to trace the cause)
@ -280,6 +280,15 @@ from .ptime import time
from .Qt import isQObjectAlive
from .ThreadsafeTimer import *
# indirect imports used within library
from .GraphicsScene import GraphicsScene
from .python2_3 import asUnicode
from .util.cupy_helper import getCupy
# indirect imports known to be used outside of the library
from .metaarray import MetaArray
from .ordereddict import OrderedDict
##############################################################
## PyQt and PySide both are prone to crashing on exit.

View File

@ -26,6 +26,31 @@ from .metaarray import MetaArray
from collections import OrderedDict
from .python2_3 import asUnicode, basestring
# in order of appearance in this file.
# add new functions to this list only if they are to reside in pg namespace.
__all__ = [
'siScale', 'siFormat', 'siParse', 'siEval', 'siApply',
'Color', 'mkColor', 'mkBrush', 'mkPen', 'hsvColor',
'CIELabColor', 'colorCIELab', 'colorDistance',
'colorTuple', 'colorStr', 'intColor', 'glColor',
'makeArrowPath', 'eq',
'affineSliceCoords', 'affineSlice',
'interweaveArrays', 'interpolateArray', 'subArray',
'transformToArray', 'transformCoordinates',
'solve3DTransform', 'solveBilinearTransform',
'clip_scalar', 'clip_array', 'rescaleData', 'applyLookupTable',
'makeRGBA', 'makeARGB',
# 'try_fastpath_argb', 'ndarray_to_qimage',
'makeQImage',
# 'qimage_to_ndarray',
'imageToArray', 'colorToAlpha',
'gaussianFilter', 'downsample', 'arrayToQPath',
# 'ndarray_from_qpolygonf', 'create_qpolygonf', 'arrayToQPolygonF',
'isocurve', 'traceImage', 'isosurface',
'invertQTransform',
'pseudoScatter', 'toposort', 'disconnect', 'SignalBlock']
Colors = {
'b': QtGui.QColor(0,0,255,255),
'g': QtGui.QColor(0,255,0,255),

View File

@ -3,6 +3,8 @@ from .. import functions as fn
from .PlotDataItem import PlotDataItem
from .PlotCurveItem import PlotCurveItem
__all__ = ['FillBetweenItem']
class FillBetweenItem(QtGui.QGraphicsPathItem):
"""
GraphicsItem filling the space between two PlotDataItems.

View File

@ -9,6 +9,7 @@ from .. import functions as fn
import weakref
import operator
__all__ = ['GraphicsItem']
# Recipe from https://docs.python.org/3.8/library/collections.html#collections.OrderedDict
# slightly adapted for Python 3.7 compatibility

View File

@ -1,6 +1,7 @@
from ..Qt import QtGui, QtCore
from ..Point import Point
__all__ = ['GraphicsWidgetAnchor']
class GraphicsWidgetAnchor(object):
"""

View File

@ -12,6 +12,7 @@ from .ViewBox import *
from .GradientEditorItem import *
from .LinearRegionItem import *
from .PlotDataItem import *
from .PlotCurveItem import *
from .AxisItem import *
from .GridItem import *
from ..Point import Point

View File

@ -3,6 +3,7 @@ from .GraphicsObject import *
from .. import functions as fn
from ..Qt import QtGui, QtCore
__all__ = ['IsocurveItem']
class IsocurveItem(GraphicsObject):
"""

View File

@ -6,6 +6,7 @@ from .GraphicsObject import GraphicsObject
from .. import mkBrush, mkPen
from .. import functions as fn
__all__ = ['NonUniformImage']
class NonUniformImage(GraphicsObject):
"""

View File

@ -11,6 +11,7 @@ from .. import functions as fn
from .. import debug as debug
from .. import getConfigOption
__all__ = ['PlotDataItem']
class PlotDataItem(GraphicsObject):
"""

View File

@ -14,9 +14,11 @@ from ..InfiniteLine import InfiniteLine
from ..LabelItem import LabelItem
from ..LegendItem import LegendItem
from ..PlotDataItem import PlotDataItem
from ..PlotCurveItem import PlotCurveItem
from ..ScatterPlotItem import ScatterPlotItem
from ..ViewBox import ViewBox
from ... import functions as fn
from ... import icons, PlotCurveItem, ScatterPlotItem
from ... import icons
from ...Qt import QtGui, QtCore, QT_LIB
from ...WidgetGroup import WidgetGroup
from ...python2_3 import basestring

View File

@ -1 +1,3 @@
from .PlotItem import PlotItem
__all__ = ['PlotItem']

View File

@ -10,6 +10,7 @@ from .ViewBox import ViewBox
import string
import warnings
__all__ = ['TargetItem', 'TargetLabel']
class TargetItem(UIGraphicsItem):
"""Draws a draggable target symbol (circle plus crosshair).

View File

@ -4,6 +4,7 @@ from ..Point import Point
from .. import functions as fn
from .GraphicsObject import GraphicsObject
__all__ = ['TextItem']
class TextItem(GraphicsObject):
"""

View File

@ -1 +1,3 @@
from .ViewBox import ViewBox
__all__ = ['ViewBox']

View File

@ -6,6 +6,8 @@ it is possible to place any widget into its own window by simply calling its
show() method.
"""
__all__ = ['GraphicsWindow', 'TabWindow', 'PlotWindow', 'ImageWindow']
from .Qt import QtCore, QtGui, mkQApp
from .widgets.PlotWidget import *
from .imageview import *

View File

@ -4,3 +4,5 @@ Includes ROI plotting over time and image normalization.
"""
from .ImageView import ImageView
__all__ = ['ImageView']

View File

@ -1,137 +1,12 @@
# 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.
import collections
import warnings
warnings.warn(
"OrderedDict is in the standard library for supported versions of Python. Will be removed in 0.13",
DeprecationWarning, stacklevel=2
)
import sys
if sys.version[0] > '2':
from collections import OrderedDict
else:
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
class OrderedDict(collections.OrderedDict):
def __init__(self, *args, **kwds):
warnings.warn(
"OrderedDict is in the standard library for supported versions of Python. Will be removed in 0.13",
DeprecationWarning,
stacklevel=2,
)
super().__init__(*args, **kwds)

View File

@ -4,6 +4,7 @@ from ..SignalProxy import SignalProxy
from collections import OrderedDict
from ..python2_3 import asUnicode, basestring
__all__ = ['ComboBox']
class ComboBox(QtGui.QComboBox):
"""Extends QComboBox to add extra functionality.

View File

@ -2,6 +2,7 @@ from ..Qt import QtGui, QtCore
from .PathButton import PathButton
from ..python2_3 import basestring
__all__ = ['GroupBox']
class GroupBox(QtGui.QGroupBox):
"""Subclass of QGroupBox that implements collapse handle.

View File

@ -6,6 +6,8 @@ from matplotlib.backends.backend_qt5agg import NavigationToolbar2QT as Navigatio
from matplotlib.figure import Figure
__all__ = ['MatplotlibWidget']
class MatplotlibWidget(QtGui.QWidget):
"""
Implements a Matplotlib figure inside a QWidget.

View File

@ -18,6 +18,7 @@ except (ImportError, AttributeError):
# AttributeError upon import
HAVE_OPENGL = False
__all__ = ['RawImageWidget']
class RawImageWidget(QtGui.QWidget):
"""
@ -78,6 +79,7 @@ class RawImageWidget(QtGui.QWidget):
if HAVE_OPENGL:
__all__.append('RawImageGLWidget')
class RawImageGLWidget(QOpenGLWidget):
"""
Similar to RawImageWidget, but uses a GL widget to do all drawing.

View File

@ -2,6 +2,7 @@
CSV export test
"""
from __future__ import division, print_function, absolute_import
import numpy as np
import pyqtgraph as pg
import csv
import tempfile
@ -19,11 +20,11 @@ def test_CSVExporter():
plt.plot(y=y1, name='myPlot')
y2 = [3,4,6,1,2,4,2,3,5,3,5,1,3]
x2 = pg.np.linspace(0, 1.0, len(y2))
x2 = np.linspace(0, 1.0, len(y2))
plt.plot(x=x2, y=y2)
y3 = [1,5,2,3,4,6,1,2,4,2,3,5,3]
x3 = pg.np.linspace(0, 1.0, len(y3)+1)
x3 = np.linspace(0, 1.0, len(y3)+1)
plt.plot(x=x3, y=y3, stepMode="center")
ex = pg.exporters.CSVExporter(plt.plotItem)

View File

@ -7,7 +7,7 @@ pytest.importorskip("matplotlib")
app = pg.mkQApp()
skip_qt6 = pytest.mark.skipif(
pg.QT_LIB in ["PySide6", "PyQt6"],
pg.Qt.QT_LIB in ["PySide6", "PyQt6"],
reason= (
"Matplotlib has no Qt6 support yet, "
"see https://github.com/matplotlib/matplotlib/pull/19255"

View File

@ -229,7 +229,7 @@ def test_setRect():
def test_dividebyzero():
im = pg.image(pg.np.random.normal(size=(100,100)))
im = pg.image(np.random.normal(size=(100,100)))
im.imageItem.setAutoDownsample(True)
im.view.setRange(xRange=[-5+25, 5e+25],yRange=[-5e+25, 5e+25])
app.processEvents()

View File

@ -37,7 +37,7 @@ def test_PlotWidget():
with warnings.catch_warnings():
warnings.simplefilter("ignore")
w = pg.PlotWidget(*args, **kwds)
data = pg.np.array([1,5,2,4,3])
data = np.array([1,5,2,4,3])
c = w.plot(data, name='stuff')
w.addLegend()