Skip to content

Commit 314a5a9

Browse files
committed
DOC: first additions to docs about pyside6, also add tag for parts of codebase where we do pyqt5/pyside6 specific things.
1 parent 9ff9dbf commit 314a5a9

17 files changed

+77
-3
lines changed

docs/source/development/development.rst

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,3 +139,28 @@ should look like this:
139139
working on that branch. The rebasing process re-writes the commit history so
140140
any other checkout of the same branch referring to the old history will
141141
create duplicates of all the commits.
142+
143+
Qt Wrapper Dependent Code
144+
===========================
145+
PyDM runs using python wrappers around the Qt library,
146+
and there are two choices for python wrappers currently supported: PyQt (Qt5) and PySide6 (Qt6). Note: atm functionality
147+
of PyDM should be the same regardless of if PyQt5 of PySide6 is used.
148+
149+
Furthermore, PyDM runs ontop an abstraction layer called "qtpy" (https://github.com/spyder-ide/qtpy), which is used to handle differences
150+
between PyQt and PySide6 with one set of code.
151+
152+
But ends up that there are still some places in the PyDM codebase where we needed to implement
153+
wrapper-specific or Qt version specific code, either b/c qtpy was lacking a specific abstraction we needed
154+
or b/c we had gone around the abstraction layer in the past and now it's now difficult to change these sections.
155+
156+
Also, in the future PyDM may add the option to use Qt6 specific features, and these sections of code will only run on PySide6.
157+
158+
These wrapper-specific sections are noted in the codebase by the ``@QT_WRAPPER_SPECIFIC`` string. There are also comments in
159+
these sections explaining what differences there are between the PyQt and Pyside6 implementations.
160+
161+
When changing code marked with ``@QT_WRAPPER_SPECIFIC``, developers should make sure their changes work on both PyQt and PySide6.
162+
Automated testing on GitHub will ultimately run changes on both wrappers before any code gets merged,
163+
but if you are changing a ``@QT_WRAPPER_SPECIFIC`` section it's recommended to have two separate conda environments setup
164+
(one with PyQt and the other PySide6) so you can test PyDM with both wrappers.
165+
166+
Also, if new PySide6/Qt6 only features are implemented, these sections will also get denoted with the ``@QT_WRAPPER_SPECIFIC`` string.

docs/source/installation.rst

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,21 @@ from scratch is probably using the Conda system. We recommended using Conda from
99
python environment, and want to install PyDM for use with that, you can do that
1010
with pip.
1111

12+
PyDM runs using python bindings ontop of Qt, and works with either PyQt5 (to run on Qt5) or PySide6 (to run on Qt6). For now, PyQt5 is the recommended choice to run with,
13+
whereas PySide6 provides future-proofing and the potential for new Qt6 specific features.
14+
(Note: currently functionality is the same between PyQt and PySide6)
15+
16+
In general, running PyDm with a chosen python binding is as simple as follows:
17+
loading a conda environment that has installed PyDM and PyQt5 or PySide6 (along with the other required packages),
18+
and then setting the QT_API environment variable accordingly ("pyqt5" or "pyside6".)
19+
Then when you run PyDM it will automatically use your selected binding.
20+
(Note: It's not recommended to try installing both PyQt5 and PySide6 into the same conda environment, as this might cause issues with the underlying Qt libraries.)
21+
22+
Instructions for setting up conda environments for PyQt5 and for PySide6 are provided later on this page.
23+
1224
Please note, this guide is written with Unix in mind, so there are probably some differences when installing on Windows.
1325

14-
Installing PyDM and Prerequisites with Conda
26+
Installing PyDM and Prerequisites with Conda (PyQt5)
1527
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1628

1729
.. warning::
@@ -48,7 +60,24 @@ Now, you can use 'open' to open Designer.app::
4860

4961
$ export QT_MAC_WANTS_LAYER=1
5062

51-
Installing Manually, Without Anaconda
63+
Installing PyDM and Prerequisites with Conda (PySide6)
64+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
65+
66+
After installing Miniforge (see https://conda-forge.org/download/), create a new
67+
environment for PyDM::
68+
69+
.. note::
70+
Pyside6 is installed with into the conda environment with pip b/c the conda install doesn't provide the pyside6-designer bin currently.
71+
72+
$ conda create -n pydm-environment-pyside python pip numpy scipy six psutil pyqtgraph pydm -c conda-forge
73+
$ source activate pydm-environment
74+
$ pip install PySide6
75+
76+
Once you've installed and activated the environment, you should be able to run 'pydm' to launch PyDM, or run 'pyside6-designer' to launch Qt Designer.
77+
78+
MacOS and Windows instructions coming soon...
79+
80+
Installing Manually, Without Anaconda (PyQt5)
5281
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
5382
This alternate installation method is only recommended for large 'site' installations that want to avoid using Anaconda.
5483

@@ -78,6 +107,10 @@ and extract the archive. Follow `the provided instructions <http://pyqt.sourcef
78107
build and install it. Note that you may need to manually set the '--qmake' option to point to the
79108
qmake binary you created when you built Qt5.
80109

110+
Installing Manually, Without Anaconda (PySide6)
111+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
112+
Coming soon...
113+
81114
Installing PyDM with PIP
82115
++++++++++++++++++++++++
83116

pydm/display.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ def _compile_ui_file(uifile: str) -> Tuple[str, str]:
9898
-------
9999
Tuple[str, str] - The first element is the compiled ui file, the second is the name of the class (e.g. Ui_Form)
100100
"""
101+
# @QT_WRAPPER_SPECIFIC
101102
if ACTIVE_QT_WRAPPER == QtWrapperTypes.PYQT5:
102103
code_string = StringIO()
103104
uic.compileUi(uifile, code_string)
@@ -126,6 +127,7 @@ def _compile_ui_file(uifile: str) -> Tuple[str, str]:
126127

127128

128129
def _load_ui_into_display(uifile, display):
130+
# @QT_WRAPPER_SPECIFIC
129131
if ACTIVE_QT_WRAPPER == QtWrapperTypes.PYQT5:
130132
klass, _ = uic.loadUiType(uifile)
131133
else: # pyside6

pydm/tests/test_display.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ def ui_filename(self):
4848
qtbot.addWidget(my_display)
4949

5050

51+
# @QT_WRAPPER_SPECIFIC
5152
if ACTIVE_QT_WRAPPER == QtWrapperTypes.PYQT5:
5253

5354
def test_nonexistent_ui_file_raises_pyqt5(qtbot):

pydm/tests/test_main_window.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
# The path to the .ui file for creating a main window
1212
test_ui_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), "test_data", "test.ui")
1313

14+
# @QT_WRAPPER_SPECIFIC
1415
if ACTIVE_QT_WRAPPER == QtWrapperTypes.PYQT5:
1516

1617
@patch("qtpy.uic.compileUi", wraps=uic.compileUi)

pydm/widgets/baseplot.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,7 @@ def __init__(
110110
if lineWidth is not None:
111111
self._pen.setWidth(lineWidth)
112112
if lineStyle is not None:
113+
# @QT_WRAPPER_SPECIFIC
113114
# The type hint for 'Optional' for lineStyle arg, which has allowed for some screens to
114115
# pass int value for lineStyle. pyqt5 doesn't mind the int, but pyside6 complains so lets
115116
# convert any ints here to the proper Qt.PenStyle enums. The int values get converted to enums

pydm/widgets/channel.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,7 @@ def __eq__(self, other):
187187

188188
value_signal_matched = self.value_signal is None and other.value_signal is None
189189
if self.value_signal and other.value_signal:
190+
# @QT_WRAPPER_SPECIFIC
190191
if ACTIVE_QT_WRAPPER == QtWrapperTypes.PYQT5:
191192
value_signal_matched = self.value_signal.signal == other.value_signal.signal
192193
else:

pydm/widgets/colormaps.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1080,6 +1080,7 @@ class PyDMColorMap(object):
10801080
Hot = 6
10811081

10821082

1083+
# @QT_WRAPPER_SPECIFIC
10831084
if ACTIVE_QT_WRAPPER == QtWrapperTypes.PYSIDE6:
10841085
from PySide6.QtCore import QEnum
10851086
from enum import Enum

pydm/widgets/datetime.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ class TimeBase(object):
1717
Seconds = 1
1818

1919

20+
# @QT_WRAPPER_SPECIFIC
2021
if ACTIVE_QT_WRAPPER == QtWrapperTypes.PYSIDE6:
2122
from PySide6.QtCore import QEnum
2223
from enum import Enum

pydm/widgets/display_format.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ class DisplayFormat(object):
2626
Binary = 5
2727

2828

29+
# @QT_WRAPPER_SPECIFIC
2930
if ACTIVE_QT_WRAPPER == QtWrapperTypes.PYSIDE6:
3031
from PySide6.QtCore import QEnum
3132
from enum import Enum

0 commit comments

Comments
 (0)