Skip to content

Deprecate QtWidgets accessed through QtGui#1915

Merged
j9ac9k merged 8 commits intopyqtgraph:masterfrom
outofculture:widget-not-gui
Nov 13, 2021
Merged

Deprecate QtWidgets accessed through QtGui#1915
j9ac9k merged 8 commits intopyqtgraph:masterfrom
outofculture:widget-not-gui

Conversation

@outofculture
Copy link
Copy Markdown
Contributor

@outofculture outofculture commented Jul 18, 2021

This adds the deprecation warning ( thanks @ntjess ) to the first attempted access, then migrates all our code to no longer use QtGui. The migration was semi-automated, using the following process:

  1. Get a list of all the widgets python -c 'from PyQt6 import QtWidgets; print("\n".join([m for m in dir(QtWidgets) if m[0] == "Q"]))' > widget-names
  2. Replace the access to use the appropriate module: for m in $(cat widget-names); do for f in $(find tests/ examples/ pyqtgraph/ -name '*.py'); do sed -i "s/QtGui\.$m/QtWidgets.$m/g" $f; done; done
  3. Add an import everywhere:
  • sed -E -i 's/from pyqtgraph.Qt import .*QtGui/\0, QtWidgets/' $(find pyqtgraph/examples/ tests/ -name '*.py')
  • sed -E -i 's/from \.+Qt import .*QtGui/\0, QtWidgets/' $(find pyqtgraph/ -name '*.py')

This can hang out as a draft until the backlog is cleaned up a bit, and we can re-run the migration from scratch to avoid conflicts. We should also run isort on all our files someday, as this adds a bunch of unused imports, but it's not too important.

@pijyoi
Copy link
Copy Markdown
Contributor

pijyoi commented Jul 19, 2021

What should be done about Qt5.QtWidgets.QAction vs Qt6.QtGui.QAction?

@outofculture
Copy link
Copy Markdown
Contributor Author

What should be done about Qt5.QtWidgets.QAction vs Qt6.QtGui.QAction?

Ah, yeah, if so, then that's going to shout deprecation warnings at some users. I used PyQt6 for my list of widget names, so it didn't get converted. It looks like our code uses QtGui.QAction everywhere, so we're safe, otherwise.

We could whitelist QAction in the QtGui.__getattr__ we overwrite to not give a warning. Would any other strategy work better? Maybe we want to establish something like from .Qt.compatibility import QAction to make this all explicit? I don't know if that's easier for users to maintain, seeing as whatever documentation they're reading for Qt will only tell them to use one of the standard modules.

@outofculture outofculture marked this pull request as ready for review September 7, 2021 18:38
@outofculture outofculture force-pushed the widget-not-gui branch 3 times, most recently from dc43b68 to 908c4bd Compare September 8, 2021 06:30
- id: mixed-line-ending
args: [ --fix=lf ]
- repo: https://github.com/pycqa/isort
rev: 5.6.4
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

any reason we don't use the current version (5.9.3?)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no, I just copied what they had in their documentation.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pre-commit autoupdate will fix that right up

should we also add the trailing-whitespace hook from the main pre-commit default repo? that will get rid of quite a bit of our style errs.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm good w/ adding that; but I'm not convinced it should happen in this PR given the size of it (also our code quality issues look like they're going to go up by ~70 :( )

args: [ '--maxkb=100' ]
- id: check-case-conflict
- id: end-of-file-fixer
- id: fix-encoding-pragma
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Relaying a comment from @pijyoi but this should likely be

    - id: fix-encoding-pragma
      args: ['--remove']

As we no longer support py2, so we should be nuking those, not adding more of them

@j9ac9k
Copy link
Copy Markdown
Member

j9ac9k commented Sep 9, 2021

I'm glad this is being done, it's going to be painful to address the remaining open PRs, but it will be manageable.

I think we should take the opportunity to remove the unused imports; at the very least the ones in the examples, CodeQL looks to have registered 70ish new issues so hopefully that will cut down on that number a fair amount.

@j9ac9k
Copy link
Copy Markdown
Member

j9ac9k commented Sep 26, 2021

I was playing around on this branch; and ran into an issue. If we run isort on the entire repo; there are two problems.

  1. pyqtgraph/util/colorama/win23.py - since this directory is just the sources of an old colorama release, I think we can exclude this directory from isort (probably should update it though, as it appears to be a pretty ancient version)
  2. pyqtgraph/parametertree/__init__.py- this one is a bit more serious:

after isort runs on that file, it converts the file to the following contents:

# -*- coding: utf-8 -*-
from . import parameterTypes as types
from .Parameter import Parameter, registerParameterItemType, registerParameterType
from .ParameterItem import ParameterItem
from .ParameterSystem import ParameterSystem, SystemSolver
from .ParameterTree import ParameterTree

Unfortunately after the change, running pytest generates the following error:

ImportError while loading conftest '/Users/ogi/Developer/pyqtgraph/tests/conftest.py'.
tests/__init__.py:2: in <module>
    from .image_testing import assertImageApproved, TransposedImageItem
tests/image_testing.py:29: in <module>
    from pyqtgraph import GraphicsLayoutWidget, ImageItem, TextItem
pyqtgraph/__init__.py:259: in <module>
    from .widgets.ColorMapWidget import *
pyqtgraph/widgets/ColorMapWidget.py:7: in <module>
    from .. import parametertree as ptree
pyqtgraph/parametertree/__init__.py:2: in <module>
    from . import parameterTypes as types
pyqtgraph/parametertree/parameterTypes/__init__.py:3: in <module>
    from .action import ActionParameter, ActionParameterItem
pyqtgraph/parametertree/parameterTypes/action.py:6: in <module>
    class ActionParameterItem(ParameterItem):
E   TypeError: module() takes at most 2 arguments (3 given)

While we could mark the file for skip for isort purposes, we should probably try to resolve that issue whatever it may be.

@j9ac9k
Copy link
Copy Markdown
Member

j9ac9k commented Sep 27, 2021

After # isort:skip -ing the problematic line in parametertree/__init__.py, and re-running I sort, the test suite runs, but unfortunately we get some errors.

=================================================================== short test summary info ===================================================================
FAILED examples/test_examples.py::testExamples[ dockarea.py - PyQt5 ]
FAILED examples/test_examples.py::testExamples[ parametertree.py - PyQt5 ]
FAILED tests/dockarea/test_dockarea.py::test_dockarea - AttributeError: type object 'Dock' has no attribute 'Dock'
FAILED examples/test_examples.py::testExamples[ PlotSpeedTest.py - PyQt5 ]

More specifically:

  File "/Users/ogi/Developer/pyqtgraph/pyqtgraph/dockarea/Container.py", line 250, in _insertItem
    if not isinstance(item, Dock.Dock):
AttributeError: type object 'Dock' has no attribute 'Dock'
  File "/Users/ogi/Developer/pyqtgraph/pyqtgraph/parametertree/parameterTypes/pen.py", line 11, in __init__
    self.pdialog = PenSelectorDialog(fn.mkPen(param.pen))
  File "/Users/ogi/Developer/pyqtgraph/pyqtgraph/widgets/PenSelectorDialog.py", line 61, in __init__
    self.tree = ParameterTree(showHeader=False)
TypeError: 'module' object is not callable

I suspect it has to do with some confusion between objects and modules judging by the errors.

@pijyoi
Copy link
Copy Markdown
Contributor

pijyoi commented Sep 29, 2021

In pyqtgraph/parametertree/parameterTypes/actions.py, I think you need to change:

from .. import ParameterItem, Parameter

to

from ..ParameterItem import ParameterItem
from ..Parameter import Parameter

The former relies on pyqtgraph/parametertree/__init__.py having imported ParameterItem and Parameter into the namespace. Hence the breakage with isort.
Similar changes would need to be made to the other files within pyqtgraph/parametertree/parameterTypes/.

While browsing through that directory, I noticed that the following files were doing absolute instead of relative imports:

  1. bool.py
  2. str.py
from pyqtgraph.Qt import QtWidgets
from pyqtgraph.parametertree.parameterTypes import WidgetParameterItem

@j9ac9k
Copy link
Copy Markdown
Member

j9ac9k commented Sep 29, 2021

In pyqtgraph/parametertree/parameterTypes/actions.py, I think you need to change:

from .. import ParameterItem, Parameter

to

from ..ParameterItem import ParameterItem
from ..Parameter import Parameter

The former relies on pyqtgraph/parametertree/__init__.py having imported ParameterItem and Parameter into the namespace. Hence the breakage with isort. Similar changes would need to be made to the other files within pyqtgraph/parametertree/parameterTypes/.

While browsing through that directory, I noticed that the following files were doing absolute instead of relative imports:

  1. bool.py
  2. str.py
from pyqtgraph.Qt import QtWidgets
from pyqtgraph.parametertree.parameterTypes import WidgetParameterItem

Nice catch (on both the non-relative imports and the import of Parameter and ParameterItem)! That indeed fixed the issue w/ ParameterItems; still have the issue with Dock but I'm willing to bet it's something very similar.

EDIT: dock related error was even simpler to resolve... now that isort doesn't appear to cause breakages, moving onto pycln

EDIT 2: scratch that, some examples are failing.

EDIT 3: Fixed, just needed to update the import for PenSelectorDialog.py

@j9ac9k
Copy link
Copy Markdown
Member

j9ac9k commented Sep 29, 2021

I got isort and pycln to run over the entire repo, test suite runs and passes, but still getting lots of warnings such as:

 DeprecationWarning: Accessing QtWidgets through QtGui is deprecated and will be removed after Jan 2022. Use QtWidgets.QPushButton instead.

@outofculture do you know of a good way we can detect these uses in an automated fashion?

@j9ac9k
Copy link
Copy Markdown
Member

j9ac9k commented Oct 30, 2021

Was hoping to make more progress on this today; hopefully i'll make more of a go at it later tonight, the following are items available in PyQt5.QtWidgets but are not available in PyQt6.QtWidgets

QAction
QActionGroup
QDesktopWidget
QDirModel
QFileSystemModel
QKeyEventTransition
QMacCocoaViewContainer
QMouseEventTransition
QOpenGLWidget
QShortcut
QUndoCommand
QUndoGroup
QUndoStack

I found no items in PyQt6.QtWidgets that were not in PyQt5.QtWidgets

Will check out QtGui next for a more exhaustive listing.

@j9ac9k
Copy link
Copy Markdown
Member

j9ac9k commented Nov 13, 2021

Thanks @outofculture ! LGTM!

@j9ac9k j9ac9k merged commit 7f7c621 into pyqtgraph:master Nov 13, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants