Skip to content

Port QtVCP from PyQt5 to QtPy#3881

Open
bgermann wants to merge 1 commit intoLinuxCNC:masterfrom
bgermann:qtpy
Open

Port QtVCP from PyQt5 to QtPy#3881
bgermann wants to merge 1 commit intoLinuxCNC:masterfrom
bgermann:qtpy

Conversation

@bgermann
Copy link
Copy Markdown

@bgermann bgermann commented Mar 27, 2026

Replace all PyQt5-specific imports and idioms with their QtPy equivalents, making the codebase compatible with PyQt5 and PyQt6.

Import changes:

  • Replace from PyQt5.XXX import with from qtpy.XXX import
  • Replace bare from PyQt5 import XXX with from qtpy import XXX
  • Replace pyqtSignal, pyqtSlot, pyqtProperty with the qtpy canonical names Signal, Slot, Property
  • Port PyQt5.QtDesigner imports to qtpy.QtDesigner
  • Port PyQt5.Qsci imports to qtpy.Qsci

PDFViewer: add QtPdf backend as Qt6 alternative to popplerqt5

  • Try qtpy.QtPdf.QPdfDocument first; fall back to popplerqt5
  • Use QPdfDocumentRenderOptions with Annotations flag for render quality matching the popplerqt5 Antialiasing/TextAntialiasing hints

sys_notify: make DBus main loop integration backend-agnostic

  • Try dbus.mainloop.pyqt5, then pyqt6.

qtplasmac handlers: replace find_spec("PyQt5.QtWebEngineWidgets")

  • Use a module-level _WEBENGINE_AVAILABLE flag set by try/import of qtpy.QtWebEngineWidgets in the qtplasmac handler

plugins/status_label_plugin: fix pyqtProperty descriptor check

  • Replace fragile 'PyQt5.QtCore.pyqtProperty' in str(...) with isinstance(..., Property) to work across all Qt bindings

@bgermann bgermann mentioned this pull request Mar 27, 2026
@andypugh andypugh requested a review from c-morley March 27, 2026 20:36
@andypugh
Copy link
Copy Markdown
Collaborator

@c-morley The description sounds like a good approach. What do you think?

@snowgoer540
Copy link
Copy Markdown
Contributor

Made some time to apply this to the project and test it out.

After installing the necessary pyqt dependency, I get these in the terminal window when running the qtplasmac GUI:

QSocketNotifier: Can only be used with threads started with QThread
QSocketNotifier: Can only be used with threads started with QThread
QSocketNotifier: Can only be used with threads started with QThread
QSocketNotifier: Can only be used with threads started with QThread

@bgermann
Copy link
Copy Markdown
Author

bgermann commented Mar 27, 2026

QSocketNotifier: Can only be used with threads started with QThread

I have removed the dbus.mainloop.glib fallback (which was added for PySide which we do not need to support) so this should be fixed.

@snowgoer540
Copy link
Copy Markdown
Contributor

It still gave the same QSocketNotifier message. In order to fix it, I had to change the order of the import test to prefer testing pyqt5 first.

From:
for _mod in ('dbus.mainloop.pyqt6', 'dbus.mainloop.pyqt5'):

To:
for _mod in ('dbus.mainloop.pyqt5', 'dbus.mainloop.pyqt6'):

Replace all PyQt5-specific imports and idioms with their QtPy
equivalents, making the codebase compatible with PyQt5 and PyQt6.

Import changes:
- Replace `from PyQt5.XXX import` with `from qtpy.XXX import`
- Replace bare `from PyQt5 import XXX` with `from qtpy import XXX`
- Replace `pyqtSignal`, `pyqtSlot`, `pyqtProperty` with the qtpy
  canonical names `Signal`, `Slot`, `Property`
- Port `PyQt5.QtDesigner` imports to `qtpy.QtDesigner`
- Port `PyQt5.Qsci` imports to `qtpy.Qsci`

PDFViewer: add QtPdf backend as Qt6 alternative to popplerqt5
- Try `qtpy.QtPdf.QPdfDocument` first; fall back to popplerqt5
- Use `QPdfDocumentRenderOptions` with Annotations flag for render
  quality matching the popplerqt5 Antialiasing/TextAntialiasing hints

sys_notify: make DBus main loop integration backend-agnostic
- Try dbus.mainloop.pyqt5, then dbus.mainloop.pyqt6.

qtplasmac handlers: replace `find_spec("PyQt5.QtWebEngineWidgets")`
- Use a module-level `_WEBENGINE_AVAILABLE` flag set by try/import
  of `qtpy.QtWebEngineWidgets` in the qtplasmac handler.

plugins/status_label_plugin: fix pyqtProperty descriptor check
- Replace fragile `'PyQt5.QtCore.pyqtProperty' in str(...)` with
  `isinstance(..., Property)` to work across all Qt bindings
@bgermann
Copy link
Copy Markdown
Author

It still gave the same QSocketNotifier message. In order to fix it, I had to change the order of the import test to prefer testing pyqt5 first.

Applied to the PR.

Copy link
Copy Markdown
Contributor

@snowgoer540 snowgoer540 left a comment

Choose a reason for hiding this comment

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

From a QtPlasmaC standpoint this seems ok to merge. It will require RIP users to install the python3-qtpy dependency.

Will require @c-morley 's review prior to merging, he is much much more familiar with all of the core qtvcp stuff, and has many more affected GUIs.

@c-morley
Copy link
Copy Markdown
Collaborator

hmm on my system I get:

from qtpy.Qsci import QsciScintilla

ModuleNotFoundError: No module named 'qtpy.Qsci'

@c-morley
Copy link
Copy Markdown
Collaborator

c-morley commented Mar 29, 2026

if in gcode_editor, I change to:

try:
from qtpy.Qsci import QsciScintilla, QsciLexerCustom, QsciLexerPython
except ImportError as e:
from PyQt5.Qsci import QsciScintilla, QsciLexerCustom, QsciLexerPython

then dragon runs.
More testing needed...

@bgermann
Copy link
Copy Markdown
Author

That is interesting because I have actually verified that module to work on Debian bookworm. Support for qtpy.Qsci was introduced in QtPy 2.3.0. So probably you are using an older version.

@snowgoer540
Copy link
Copy Markdown
Contributor

If the goal of this pull request is to allow Debian to drop python3-poppler-qt5, then I think we should limit the changes to only what is necessary to support the necessary updates in PDFViewer.py.

I understand and appreciate the groundwork being done with this commit to support our future conversion to pyqt6, but that introduces additional changes that require extensive testing and review. Given that our master branch is approaching a release state, this may not be the right time to include the broader refactoring.

At this point, I recommend we focus only on the changes necessary to remove poppler from the codebase so Debian can proceed with dropping the package from Forky. The rest can be handled by Chris and myself in a separate effort where the changes can be reviewed and tested thoroughly (after 2.10 is released).

Copy link
Copy Markdown
Contributor

@snowgoer540 snowgoer540 left a comment

Choose a reason for hiding this comment

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

After further consideration, I recommend changing this pull request to encompass only what is absolutely necessary to remove python3-poppler-qt5 from PDFViewer.py in support of dropping the package for Debian Forky.

@bgermann
Copy link
Copy Markdown
Author

That is okay. The Debian package can just drop the optional dependency. There is nothing in this PR that suggests to integrate it very soon.

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.

4 participants