From 4d388ee633fd7ac0322ed306ce79cd64acdc5a35 Mon Sep 17 00:00:00 2001 From: Ogi Moore Date: Sun, 25 Apr 2021 17:05:05 -0700 Subject: [PATCH 1/5] Use open context-manager instead of file.open() Static code checker identified multiple places where a file is opened but is not necessarily closed. This commit addressed that with the exception of RemoteGraphicsView.py --- examples/ExampleApp.py | 3 ++- pyqtgraph/tests/test_reload.py | 47 +++++++++------------------------- setup.py | 6 +++-- tools/generateChangelog.py | 23 +++++++++-------- tools/setupHelpers.py | 28 ++++++++++---------- 5 files changed, 44 insertions(+), 63 deletions(-) diff --git a/examples/ExampleApp.py b/examples/ExampleApp.py index d5535a3b..01d00567 100644 --- a/examples/ExampleApp.py +++ b/examples/ExampleApp.py @@ -369,7 +369,8 @@ class ExampleLoader(QtGui.QMainWindow): return if os.path.isdir(fn): fn = os.path.join(fn, '__main__.py') - text = open(fn).read() + with open(fn, "r") as currentFile: + text = currentFile.read() self.ui.codeView.setPlainText(text) self.ui.loadedFileLabel.setText(fn) self.codeBtn.hide() diff --git a/pyqtgraph/tests/test_reload.py b/pyqtgraph/tests/test_reload.py index 193f17a6..9dbba885 100644 --- a/pyqtgraph/tests/test_reload.py +++ b/pyqtgraph/tests/test_reload.py @@ -56,7 +56,8 @@ def test_reload(): # write a module mod = os.path.join(path, 'reload_test_mod.py') print("\nRELOAD FILE:", mod) - open(mod, 'w').write(code.format(path_repr=pgpath_repr, msg="C.fn() Version1")) + with open(mod, "w") as file_: + file_.write(code.format(path_repr=pgpath_repr, msg="C.fn() Version1")) # import the new module import reload_test_mod @@ -64,61 +65,37 @@ def test_reload(): c = reload_test_mod.C() c.sig.connect(c.fn) - if py3: - v1 = (reload_test_mod.C, reload_test_mod.C.sig, reload_test_mod.C.fn, c.sig, c.fn, c.fn.__func__) - else: - v1 = (reload_test_mod.C, reload_test_mod.C.sig, reload_test_mod.C.fn, reload_test_mod.C.fn.__func__, c.sig, c.fn, c.fn.__func__) - + v1 = (reload_test_mod.C, reload_test_mod.C.sig, reload_test_mod.C.fn, c.sig, c.fn, c.fn.__func__) # write again and reload - open(mod, 'w').write(code.format(path_repr=pgpath_repr, msg="C.fn() Version2")) + with open(mod, "w") as file_: + file_.write(code.format(path_repr=pgpath_repr, msg="C.fn() Version 2")) time.sleep(1.1) #remove_cache(mod) result1 = pg.reload.reloadAll(path, debug=True) - if py3: - v2 = (reload_test_mod.C, reload_test_mod.C.sig, reload_test_mod.C.fn, c.sig, c.fn, c.fn.__func__) - else: - v2 = (reload_test_mod.C, reload_test_mod.C.sig, reload_test_mod.C.fn, reload_test_mod.C.fn.__func__, c.sig, c.fn, c.fn.__func__) + v2 = (reload_test_mod.C, reload_test_mod.C.sig, reload_test_mod.C.fn, c.sig, c.fn, c.fn.__func__) - if not py3: - assert c.fn.im_class is v2[0] oldcfn = pg.reload.getPreviousVersion(c.fn) if oldcfn is None: # Function did not reload; are we using pytest's assertion rewriting? raise Exception("Function did not reload. (This can happen when using py.test" " with assertion rewriting; use --assert=plain for this test.)") - if py3: - assert oldcfn.__func__ is v1[2] - else: - assert oldcfn.im_class is v1[0] - assert oldcfn.__func__ is v1[2].__func__ + assert oldcfn.__func__ is v1[2] assert oldcfn.__self__ is c - # write again and reload - open(mod, 'w').write(code.format(path_repr=pgpath_repr, msg="C.fn() Version2")) + with open(mod, "w") as file_: + file_.write(code.format(path_repr=pgpath_repr, msg="C.fn() Version2")) time.sleep(1.1) # remove_cache(mod) result2 = pg.reload.reloadAll(path, debug=True) - if py3: - v3 = (reload_test_mod.C, reload_test_mod.C.sig, reload_test_mod.C.fn, c.sig, c.fn, c.fn.__func__) - else: - v3 = (reload_test_mod.C, reload_test_mod.C.sig, reload_test_mod.C.fn, reload_test_mod.C.fn.__func__, c.sig, c.fn, c.fn.__func__) - - #for i in range(len(old)): - #print id(old[i]), id(new1[i]), id(new2[i]), old[i], new1[i] + v3 = (reload_test_mod.C, reload_test_mod.C.sig, reload_test_mod.C.fn, c.sig, c.fn, c.fn.__func__) cfn1 = pg.reload.getPreviousVersion(c.fn) cfn2 = pg.reload.getPreviousVersion(cfn1) - if py3: - assert cfn1.__func__ is v2[2] - assert cfn2.__func__ is v1[2] - else: - assert cfn1.__func__ is v2[2].__func__ - assert cfn2.__func__ is v1[2].__func__ - assert cfn1.im_class is v2[0] - assert cfn2.im_class is v1[0] + assert cfn1.__func__ is v2[2] + assert cfn2.__func__ is v1[2] assert cfn1.__self__ is c assert cfn2.__self__ is c diff --git a/setup.py b/setup.py index ec945968..730523f6 100644 --- a/setup.py +++ b/setup.py @@ -110,8 +110,10 @@ class Install(install.install): try: initfile = os.path.join(path, '__init__.py') - data = open(initfile, 'r').read() - open(initfile, 'w').write(re.sub(r"__version__ = .*", "__version__ = '%s'" % version, data)) + with open(initfile, "r") as file_: + data = file_.read() + with open(initfile, "w") as file_: + file_.write(re.sub(r"__version__ = .*", "__version__ = '%s'" % version, data)) installVersion = version except: sys.stderr.write("Warning: Error occurred while setting version string in build path. " diff --git a/tools/generateChangelog.py b/tools/generateChangelog.py index 3dcd692d..f003c263 100644 --- a/tools/generateChangelog.py +++ b/tools/generateChangelog.py @@ -28,17 +28,18 @@ def generateDebianChangelog(package, logFile, version, maintainer): current_version = None current_log = None current_date = None - for line in open(logFile).readlines(): - match = re.match(package+r'-(\d+\.\d+\.\d+(\.\d+)?)\s*(\d+-\d+-\d+)\s*$', line) - if match is None: - if current_log is not None: - current_log.append(line) - else: - if current_log is not None: - releases.append((current_version, current_log, current_date)) - current_version, current_date = match.groups()[0], match.groups()[2] - #sys.stderr.write("Found release %s\n" % current_version) - current_log = [] + with open(logFile) as file_: + for line in file_.readlines(): + match = re.match(package+r'-(\d+\.\d+\.\d+(\.\d+)?)\s*(\d+-\d+-\d+)\s*$', line) + if match is None: + if current_log is not None: + current_log.append(line) + else: + if current_log is not None: + releases.append((current_version, current_log, current_date)) + current_version, current_date = match.groups()[0], match.groups()[2] + #sys.stderr.write("Found release %s\n" % current_version) + current_log = [] if releases[0][0] != version: raise Exception("Latest release in changelog (%s) does not match current release (%s)\n" % (releases[0][0], version)) diff --git a/tools/setupHelpers.py b/tools/setupHelpers.py index 420a27b2..1a78bdb8 100644 --- a/tools/setupHelpers.py +++ b/tools/setupHelpers.py @@ -149,20 +149,20 @@ def checkStyle(): if os.path.splitext(f)[1] not in ('.py', '.rst'): continue filename = os.path.join(path, f) - fh = open(filename, 'U') - _ = fh.readlines() - endings = set( - fh.newlines - if isinstance(fh.newlines, tuple) - else (fh.newlines,) - ) - endings -= allowedEndings - if len(endings) > 0: - print("\033[0;31m" - + "File has invalid line endings: " - + "%s" % filename + "\033[0m") - ret = ret | 2 - count += 1 + with open(filename, 'U') as fh: + _ = fh.readlines() + endings = set( + fh.newlines + if isinstance(fh.newlines, tuple) + else (fh.newlines,) + ) + endings -= allowedEndings + if len(endings) > 0: + print("\033[0;31m" + + "File has invalid line endings: " + + "%s" % filename + "\033[0m") + ret = ret | 2 + count += 1 print('checked line endings in %d files' % count) From 00a0ddb0d43a80b349e71fa757b4d4cb229cb38c Mon Sep 17 00:00:00 2001 From: Ogi Moore Date: Sun, 25 Apr 2021 20:08:47 -0700 Subject: [PATCH 2/5] Do not import value of mutable attribute This was brought to the attention via the stack type checker, Easy fix so it is being implemented. --- tools/setupHelpers.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/tools/setupHelpers.py b/tools/setupHelpers.py index 1a78bdb8..097fec76 100644 --- a/tools/setupHelpers.py +++ b/tools/setupHelpers.py @@ -7,7 +7,7 @@ import re import shutil import subprocess import sys -from distutils.core import Command +from distutils import core from typing import Dict, Any from generateChangelog import generateDebianChangelog @@ -503,7 +503,7 @@ DEFAULT_ASV: Dict[str, Any] = { } -class ASVConfigCommand(Command): +class ASVConfigCommand(core.Command): description = "Setup the ASV benchmarking config for this system" user_options = [] @@ -526,7 +526,7 @@ class ASVConfigCommand(Command): conf_file.write(json.dumps(config, indent=2)) -class DebCommand(Command): +class DebCommand(core.Command): description = "build .deb package using `debuild -us -uc`" maintainer = "Luke Campagnola " debTemplate = "debian" @@ -584,7 +584,7 @@ class DebCommand(Command): raise Exception("Error during debuild.") -class DebugCommand(Command): +class DebugCommand(core.Command): """Just for learning about distutils.""" description = "" user_options = [] @@ -599,7 +599,7 @@ class DebugCommand(Command): print(self.distribution.version) -class TestCommand(Command): +class TestCommand(core.Command): description = "Run all package tests and exit immediately with ", \ "informative return code." user_options = [] @@ -614,7 +614,7 @@ class TestCommand(Command): pass -class StyleCommand(Command): +class StyleCommand(core.Command): description = "Check all code for style, exit immediately with ", \ "informative return code." user_options = [] @@ -629,7 +629,7 @@ class StyleCommand(Command): pass -class MergeTestCommand(Command): +class MergeTestCommand(core.Command): description = "Run all tests needed to determine whether the current ",\ "code is suitable for merge." user_options = [] From 38dccf8642214b34e3937f4d23ff577286cbe47a Mon Sep 17 00:00:00 2001 From: Ogi Moore Date: Sun, 25 Apr 2021 20:10:54 -0700 Subject: [PATCH 3/5] Fix indentation bug with flowchart --- pyqtgraph/flowchart/library/Data.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pyqtgraph/flowchart/library/Data.py b/pyqtgraph/flowchart/library/Data.py index 6edd3a80..b4d229ba 100644 --- a/pyqtgraph/flowchart/library/Data.py +++ b/pyqtgraph/flowchart/library/Data.py @@ -160,10 +160,9 @@ class RegionSelectNode(CtrlNode): sliced = data[0:s['start']:s['stop']] else: mask = (data['time'] >= s['start']) * (data['time'] < s['stop']) - sliced = data[mask] + sliced = data[mask] else: sliced = None - return {'selected': sliced, 'widget': self.items, 'region': region} From 7c48233bfa961cbfb5ed3948b2f1128793dbf15e Mon Sep 17 00:00:00 2001 From: Ogi Moore Date: Sun, 25 Apr 2021 20:25:58 -0700 Subject: [PATCH 4/5] Remove unreachable code --- pyqtgraph/exporters/SVGExporter.py | 1 - pyqtgraph/graphicsItems/FillBetweenItem.py | 5 +---- .../ViewBox/tests/test_ViewBoxZoom.py | 5 ----- pyqtgraph/reload.py | 6 +----- pyqtgraph/tests/test_Vector.py | 6 ++++++ pyqtgraph/tests/test_functions.py | 17 ++--------------- pyqtgraph/tests/test_reload.py | 15 --------------- pyqtgraph/widgets/ColorMapWidget.py | 4 +--- setup.py | 2 +- 9 files changed, 12 insertions(+), 49 deletions(-) diff --git a/pyqtgraph/exporters/SVGExporter.py b/pyqtgraph/exporters/SVGExporter.py index 465c4526..b904ed15 100644 --- a/pyqtgraph/exporters/SVGExporter.py +++ b/pyqtgraph/exporters/SVGExporter.py @@ -172,7 +172,6 @@ def _generateItemSvg(item, nodes=None, root=None, options={}): ## Generate SVG text for just this item (exclude its children; we'll handle them later) - tr = QtGui.QTransform() if isinstance(item, QtGui.QGraphicsScene): xmlStr = "\n\n" doc = xml.parseString(xmlStr) diff --git a/pyqtgraph/graphicsItems/FillBetweenItem.py b/pyqtgraph/graphicsItems/FillBetweenItem.py index b16be853..02c5feca 100644 --- a/pyqtgraph/graphicsItems/FillBetweenItem.py +++ b/pyqtgraph/graphicsItems/FillBetweenItem.py @@ -21,6 +21,7 @@ class FillBetweenItem(QtGui.QGraphicsPathItem): self.updatePath() def setBrush(self, *args, **kwds): + """Change the fill brush. Acceps the same arguments as pg.mkBrush()""" QtGui.QGraphicsPathItem.setBrush(self, fn.mkBrush(*args, **kwds)) def setPen(self, *args, **kwds): @@ -50,10 +51,6 @@ class FillBetweenItem(QtGui.QGraphicsPathItem): self.setZValue(min(curve1.zValue(), curve2.zValue())-1) self.curveChanged() - def setBrush(self, *args, **kwds): - """Change the fill brush. Acceps the same arguments as pg.mkBrush()""" - QtGui.QGraphicsPathItem.setBrush(self, fn.mkBrush(*args, **kwds)) - def curveChanged(self): self.updatePath() diff --git a/pyqtgraph/graphicsItems/ViewBox/tests/test_ViewBoxZoom.py b/pyqtgraph/graphicsItems/ViewBox/tests/test_ViewBoxZoom.py index 4bad9ee1..5a8aa65b 100644 --- a/pyqtgraph/graphicsItems/ViewBox/tests/test_ViewBoxZoom.py +++ b/pyqtgraph/graphicsItems/ViewBox/tests/test_ViewBoxZoom.py @@ -193,8 +193,3 @@ def test_zoom_ratio_with_limits_out_of_range(): assert viewRange[1][0] >= -5 assert viewRange[1][1] <= 5 assert viewWidth == 2 * viewHeight - - -if __name__ == "__main__": - setup_module(None) - test_zoom_ratio() diff --git a/pyqtgraph/reload.py b/pyqtgraph/reload.py index 05ef8f0f..83d78046 100644 --- a/pyqtgraph/reload.py +++ b/pyqtgraph/reload.py @@ -45,7 +45,7 @@ def reloadAll(prefix=None, debug=False): failed = [] changed = [] ret = {} - for modName, mod in list(sys.modules.items()): ## don't use iteritems; size may change during reload + for modName, mod in list(sys.modules.items()): if not inspect.ismodule(mod): ret[modName] = (False, 'not a module') continue @@ -331,10 +331,6 @@ if __name__ == '__main__': btn = Btn() except: raise - print("Error; skipping Qt tests") - doQtTest = False - - import os if not os.path.isdir('test1'): diff --git a/pyqtgraph/tests/test_Vector.py b/pyqtgraph/tests/test_Vector.py index dcae6f9d..3b608f83 100644 --- a/pyqtgraph/tests/test_Vector.py +++ b/pyqtgraph/tests/test_Vector.py @@ -15,7 +15,13 @@ def test_Vector_init(): # separate values with 3 args v = pg.Vector(0, 1, 2) + assert v.x() == 0 + assert v.y() == 1 + assert v.z() == 2 v = pg.Vector(0.0, 1.0, 2.0) + assert v.x() == 0 + assert v.y() == 1 + assert v.z() == 2 # all in a list v = pg.Vector([0, 1]) diff --git a/pyqtgraph/tests/test_functions.py b/pyqtgraph/tests/test_functions.py index 2338461b..6f90567c 100644 --- a/pyqtgraph/tests/test_functions.py +++ b/pyqtgraph/tests/test_functions.py @@ -97,21 +97,8 @@ def check_interpolateArray(order): #[ 82.5 , 110. , 165. ]]) assert_array_almost_equal(r1, r2) - -def test_subArray(): - a = np.array([0, 0, 111, 112, 113, 0, 121, 122, 123, 0, 0, 0, 211, 212, 213, 0, 221, 222, 223, 0, 0, 0, 0]) - b = pg.subArray(a, offset=2, shape=(2,2,3), stride=(10,4,1)) - c = np.array([[[111,112,113], [121,122,123]], [[211,212,213], [221,222,223]]]) - assert np.all(b == c) - - # operate over first axis; broadcast over the rest - aa = np.vstack([a, a/100.]).T - cc = np.empty(c.shape + (2,)) - cc[..., 0] = c - cc[..., 1] = c / 100. - bb = pg.subArray(aa, offset=2, shape=(2,2,3), stride=(10,4,1)) - assert np.all(bb == cc) - + + def test_subArray(): a = np.array([0, 0, 111, 112, 113, 0, 121, 122, 123, 0, 0, 0, 211, 212, 213, 0, 221, 222, 223, 0, 0, 0, 0]) b = pg.subArray(a, offset=2, shape=(2,2,3), stride=(10,4,1)) diff --git a/pyqtgraph/tests/test_reload.py b/pyqtgraph/tests/test_reload.py index 9dbba885..fe2f2eb9 100644 --- a/pyqtgraph/tests/test_reload.py +++ b/pyqtgraph/tests/test_reload.py @@ -7,21 +7,6 @@ import pytest pgpath = os.path.join(os.path.dirname(pg.__file__), '..') pgpath_repr = repr(pgpath) -# make temporary directory to write module code -path = None - -def setup_module(): - # make temporary directory to write module code - global path - path = tempfile.mkdtemp() - sys.path.insert(0, path) - -def teardown_module(): - global path - shutil.rmtree(path) - sys.path.remove(path) - - code = """ import sys sys.path.append({path_repr}) diff --git a/pyqtgraph/widgets/ColorMapWidget.py b/pyqtgraph/widgets/ColorMapWidget.py index 9f2fafe8..ee153423 100644 --- a/pyqtgraph/widgets/ColorMapWidget.py +++ b/pyqtgraph/widgets/ColorMapWidget.py @@ -228,9 +228,7 @@ class EnumColorMapItem(ptree.types.GroupParameter): self.fieldName = name vals = opts.get('values', []) if isinstance(vals, list): - vals = OrderedDict([(v,str(v)) for v in vals]) - childs = [{'name': v, 'type': 'color'} for v in vals] - + vals = OrderedDict([(v,str(v)) for v in vals]) childs = [] for val,vname in vals.items(): ch = ptree.Parameter.create(name=vname, type='color') diff --git a/setup.py b/setup.py index 730523f6..6068ceba 100644 --- a/setup.py +++ b/setup.py @@ -81,7 +81,7 @@ class Build(build.build): if os.path.isdir(buildPath): distutils.dir_util.remove_tree(buildPath) - ret = build.build.run(self) + build.build.run(self) class Install(install.install): From 2d8d1d6d32ce7fbe901ddeeb49417da0d0458af9 Mon Sep 17 00:00:00 2001 From: Ogi Moore Date: Sun, 25 Apr 2021 20:53:50 -0700 Subject: [PATCH 5/5] Add tmp_module fixture for test_reload --- pyqtgraph/tests/conftest.py | 10 ++++++++++ pyqtgraph/tests/test_reload.py | 15 +++++++-------- 2 files changed, 17 insertions(+), 8 deletions(-) create mode 100644 pyqtgraph/tests/conftest.py diff --git a/pyqtgraph/tests/conftest.py b/pyqtgraph/tests/conftest.py new file mode 100644 index 00000000..01b08995 --- /dev/null +++ b/pyqtgraph/tests/conftest.py @@ -0,0 +1,10 @@ +import pytest +import os +import sys + +@pytest.fixture +def tmp_module(tmp_path): + module_path = os.fsdecode(tmp_path) + sys.path.insert(0, module_path) + yield module_path + sys.path.remove(module_path) diff --git a/pyqtgraph/tests/test_reload.py b/pyqtgraph/tests/test_reload.py index fe2f2eb9..495a3f9d 100644 --- a/pyqtgraph/tests/test_reload.py +++ b/pyqtgraph/tests/test_reload.py @@ -1,4 +1,4 @@ -import tempfile, os, sys, shutil, time +import os, sys, shutil, time import pyqtgraph as pg import pyqtgraph.reload import pytest @@ -35,11 +35,10 @@ def remove_cache(mod): or (sys.version_info >= (3, 10)), reason="Unknown Issue" ) -def test_reload(): - py3 = sys.version_info >= (3,) - +@pytest.mark.usefixtures("tmp_module") +def test_reload(tmp_module): # write a module - mod = os.path.join(path, 'reload_test_mod.py') + mod = os.path.join(tmp_module, 'reload_test_mod.py') print("\nRELOAD FILE:", mod) with open(mod, "w") as file_: file_.write(code.format(path_repr=pgpath_repr, msg="C.fn() Version1")) @@ -57,7 +56,7 @@ def test_reload(): file_.write(code.format(path_repr=pgpath_repr, msg="C.fn() Version 2")) time.sleep(1.1) #remove_cache(mod) - result1 = pg.reload.reloadAll(path, debug=True) + _ = pg.reload.reloadAll(tmp_module, debug=True) v2 = (reload_test_mod.C, reload_test_mod.C.sig, reload_test_mod.C.fn, c.sig, c.fn, c.fn.__func__) oldcfn = pg.reload.getPreviousVersion(c.fn) @@ -73,8 +72,8 @@ def test_reload(): file_.write(code.format(path_repr=pgpath_repr, msg="C.fn() Version2")) time.sleep(1.1) # remove_cache(mod) - result2 = pg.reload.reloadAll(path, debug=True) - v3 = (reload_test_mod.C, reload_test_mod.C.sig, reload_test_mod.C.fn, c.sig, c.fn, c.fn.__func__) + _ = pg.reload.reloadAll(tmp_module, debug=True) + _ = (reload_test_mod.C, reload_test_mod.C.sig, reload_test_mod.C.fn, c.sig, c.fn, c.fn.__func__) cfn1 = pg.reload.getPreviousVersion(c.fn) cfn2 = pg.reload.getPreviousVersion(cfn1)