From d81477077f4b6f4eb7b7e322ae560dfe00ab6148 Mon Sep 17 00:00:00 2001 From: Giles Knap Date: Thu, 2 Feb 2023 12:49:40 +0000 Subject: [PATCH 01/36] attempt to pin DLS compatible pyqt --- Pipfile.lock | 92 ++++------------------------------------------------ setup.cfg | 2 +- 2 files changed, 7 insertions(+), 87 deletions(-) diff --git a/Pipfile.lock b/Pipfile.lock index 453fd73..5f67753 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -199,49 +199,9 @@ }, "pyqt5": { "hashes": [ - "sha256:08694f0a4c7d4f3d36b2311b1920e6283240ad3b7c09b515e08262e195dcdf37", - "sha256:1a793748c60d5aff3850b7abf84d47c1d41edb11231b7d7c16bef602c36be643", - "sha256:232fe5b135a095cbd024cf341d928fc672c963f88e6a52b0c605be8177c2fdb5", - "sha256:755121a52b3a08cb07275c10ebb96576d36e320e572591db16cfdbc558101594", - "sha256:e319c9d8639e0729235c1b09c99afdadad96fa3dbd8392ab561b5ab5946ee6ef" - ], - "version": "==5.15.7" - }, - "pyqt5-qt5": { - "hashes": [ - "sha256:1988f364ec8caf87a6ee5d5a3a5210d57539988bf8e84714c7d60972692e2f4a", - "sha256:750b78e4dba6bdf1607febedc08738e318ea09e9b10aea9ff0d73073f11f6962", - "sha256:76980cd3d7ae87e3c7a33bfebfaee84448fd650bad6840471d6cae199b56e154", - "sha256:9cc7a768b1921f4b982ebc00a318ccb38578e44e45316c7a4a850e953e1dd327" - ], - "version": "==5.15.2" - }, - "pyqt5-sip": { - "hashes": [ - "sha256:0bc81cb9e171d29302d393775f95cfa01b7a15f61b199ab1812976e5c4cb2cb9", - "sha256:19b06164793177146c7f7604fe8389f44221a7bde196f2182457eb3e4229fa88", - "sha256:3358c584832f0ac9fd1ad3623d8a346c705f43414df1fcd0cb285a6ef51fec08", - "sha256:3afb1d1c07adcfef5c8bb12356a2ec2ec094f324af4417735d43b1ecaf1bb1a4", - "sha256:4f0497e2f5eeaea9f5a67b0e55c501168efa86df4e53aace2a46498b87bc55c1", - "sha256:54dad6c2e5dab14e46f6822a889bbb1515bbd2061762273af10d26566d649bd9", - "sha256:5c152878443c3e951d5db7df53509d444708dc06a121c267b548146be06b87f8", - "sha256:6b1113538082a7dd63b908587f61ce28ba4c7b8341e801fdf305d53a50a878ab", - "sha256:7218f6a1cefeb0b2fc26b89f15011f841aa4cd77786ccd863bf9792347fa38a8", - "sha256:97d3fbda0f61edb1be6529ec2d5c7202ae83aee4353e4b264a159f8c9ada4369", - "sha256:9a6f9c058564d0ac573561036299f54c452ae78b7d2a65d7c2d01685e6dca50d", - "sha256:a40a39a6136a90e10c31510295c2be924564fc6260691501cdde669bdc5edea5", - "sha256:ac5f7ed06213d3bb203e33037f7c1a0716584c21f4f0922dcc044750e3659b80", - "sha256:b077fb4383536f51382f5516f0347328a4f338c6ccc4c268cc358643bef1b838", - "sha256:b355d56483edc79dcba30be947a6b700856bb74beb90539e14cc4d92b9bad152", - "sha256:b714f550ea6ddae94fd7acae531971e535f4a4e7277b62eb44e7c649cf3f03d0", - "sha256:bd935cc46dfdbb89c21042c1db2e46a71f25693af57272f146d6d9418e2934f1", - "sha256:d09b2586235deab7a5f2e28e4bde9a70c0b3730fa84f2590804a9932414136a3", - "sha256:dd163d9cffc4a56ebb9dd6908c0f0cb0caff8080294d41f4fb60fc3be63ca434", - "sha256:f9691c6f4d899ca762dd54442a1be158c3e52017f583183da6ef37d5bae86595", - "sha256:fc920c0e0d5050474d2d6282b478e4957548bf1dce58e1b0678914514dc70064" - ], - "markers": "python_version >= '3.7'", - "version": "==12.11.1" + "sha256:2c309db3035093ea85f08029711d6fbcccf89eded7f8e4f788695d933cfd80a5" + ], + "version": "==5.12.2+dls1" }, "pyserial": { "hashes": [ @@ -859,49 +819,9 @@ }, "pyqt5": { "hashes": [ - "sha256:08694f0a4c7d4f3d36b2311b1920e6283240ad3b7c09b515e08262e195dcdf37", - "sha256:1a793748c60d5aff3850b7abf84d47c1d41edb11231b7d7c16bef602c36be643", - "sha256:232fe5b135a095cbd024cf341d928fc672c963f88e6a52b0c605be8177c2fdb5", - "sha256:755121a52b3a08cb07275c10ebb96576d36e320e572591db16cfdbc558101594", - "sha256:e319c9d8639e0729235c1b09c99afdadad96fa3dbd8392ab561b5ab5946ee6ef" - ], - "version": "==5.15.7" - }, - "pyqt5-qt5": { - "hashes": [ - "sha256:1988f364ec8caf87a6ee5d5a3a5210d57539988bf8e84714c7d60972692e2f4a", - "sha256:750b78e4dba6bdf1607febedc08738e318ea09e9b10aea9ff0d73073f11f6962", - "sha256:76980cd3d7ae87e3c7a33bfebfaee84448fd650bad6840471d6cae199b56e154", - "sha256:9cc7a768b1921f4b982ebc00a318ccb38578e44e45316c7a4a850e953e1dd327" - ], - "version": "==5.15.2" - }, - "pyqt5-sip": { - "hashes": [ - "sha256:0bc81cb9e171d29302d393775f95cfa01b7a15f61b199ab1812976e5c4cb2cb9", - "sha256:19b06164793177146c7f7604fe8389f44221a7bde196f2182457eb3e4229fa88", - "sha256:3358c584832f0ac9fd1ad3623d8a346c705f43414df1fcd0cb285a6ef51fec08", - "sha256:3afb1d1c07adcfef5c8bb12356a2ec2ec094f324af4417735d43b1ecaf1bb1a4", - "sha256:4f0497e2f5eeaea9f5a67b0e55c501168efa86df4e53aace2a46498b87bc55c1", - "sha256:54dad6c2e5dab14e46f6822a889bbb1515bbd2061762273af10d26566d649bd9", - "sha256:5c152878443c3e951d5db7df53509d444708dc06a121c267b548146be06b87f8", - "sha256:6b1113538082a7dd63b908587f61ce28ba4c7b8341e801fdf305d53a50a878ab", - "sha256:7218f6a1cefeb0b2fc26b89f15011f841aa4cd77786ccd863bf9792347fa38a8", - "sha256:97d3fbda0f61edb1be6529ec2d5c7202ae83aee4353e4b264a159f8c9ada4369", - "sha256:9a6f9c058564d0ac573561036299f54c452ae78b7d2a65d7c2d01685e6dca50d", - "sha256:a40a39a6136a90e10c31510295c2be924564fc6260691501cdde669bdc5edea5", - "sha256:ac5f7ed06213d3bb203e33037f7c1a0716584c21f4f0922dcc044750e3659b80", - "sha256:b077fb4383536f51382f5516f0347328a4f338c6ccc4c268cc358643bef1b838", - "sha256:b355d56483edc79dcba30be947a6b700856bb74beb90539e14cc4d92b9bad152", - "sha256:b714f550ea6ddae94fd7acae531971e535f4a4e7277b62eb44e7c649cf3f03d0", - "sha256:bd935cc46dfdbb89c21042c1db2e46a71f25693af57272f146d6d9418e2934f1", - "sha256:d09b2586235deab7a5f2e28e4bde9a70c0b3730fa84f2590804a9932414136a3", - "sha256:dd163d9cffc4a56ebb9dd6908c0f0cb0caff8080294d41f4fb60fc3be63ca434", - "sha256:f9691c6f4d899ca762dd54442a1be158c3e52017f583183da6ef37d5bae86595", - "sha256:fc920c0e0d5050474d2d6282b478e4957548bf1dce58e1b0678914514dc70064" - ], - "markers": "python_version >= '3.7'", - "version": "==12.11.1" + "sha256:2c309db3035093ea85f08029711d6fbcccf89eded7f8e4f788695d933cfd80a5" + ], + "version": "==5.12.2+dls1" }, "pyserial": { "hashes": [ diff --git a/setup.cfg b/setup.cfg index 84848f1..19dafaa 100644 --- a/setup.cfg +++ b/setup.cfg @@ -33,7 +33,7 @@ install_requires = # dls-pmaclib @ https://github.com/DiamondLightSource/dls-pmac-lib/archive/refs/tags/3.0.0.zip dls-pmaclib >= 3.0.1-beta1 numpy - pyqt5 == 5.15.7 + pyqt5 == 5.12.2+dls1 pythonqwt mock From f5e86c61f3997a150a8827b11ae8d913a55241e8 Mon Sep 17 00:00:00 2001 From: James O'Hea Date: Thu, 3 Aug 2023 16:22:20 +0100 Subject: [PATCH 02/36] Add brick status requests to PowerPMAC cmd string and parse the response (see ticket BC-1450) --- src/dls_pmaccontrol/commsThread.py | 12 +++++++++++- src/dls_pmaccontrol/motor.py | 12 ++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/src/dls_pmaccontrol/commsThread.py b/src/dls_pmaccontrol/commsThread.py index a9b0d5c..d543205 100644 --- a/src/dls_pmaccontrol/commsThread.py +++ b/src/dls_pmaccontrol/commsThread.py @@ -146,7 +146,9 @@ def updateFunc(self): cmd = "i65???&%s??%%" % self.CSNum # Send a different command for the Power PMAC if isinstance(self.parent.pmac, PPmacSshInterface): - cmd = "i65?&%s?%%" % self.CSNum + # The %% is because % needs escaping - only one % is actually sent + # There has to be a space before the first BrickLV string to avoid its B being interpreted as a 'begin' command + cmd = "i65?&%s?%% BrickLV.BusUnderVoltage BrickLV.BusOverVoltage BrickLV.OverTemp" % self.CSNum elif isinstance(self.parent.pmac, PmacEthernetInterface): # Add the 7 segment display status query cmd = "i65???&%s??%%m%s90" % (self.CSNum, self.CSNum) @@ -197,6 +199,14 @@ def updateFunc(self): # fourth is 7 segment display status self.resultQueue.put([valueList[4], 0, 0, 0, "M90%s" % self.CSNum]) valueList = valueList[5:] + elif isinstance(self.parent.pmac, PPmacSshInterface): + # Brick Under Voltage Status + self.resultQueue.put([valueList[4], 0, 0, 0, "UVOL"]) + # Brick Over Voltage Status + self.resultQueue.put([valueList[5], 0, 0, 0, "OVOL"]) + # Brick Over Temperature Status + self.resultQueue.put([valueList[6], 0, 0, 0, "OTEMP"]) + valueList = valueList[7:] else: valueList = valueList[4:] cols = 4 diff --git a/src/dls_pmaccontrol/motor.py b/src/dls_pmaccontrol/motor.py index 9734d5c..62f069f 100755 --- a/src/dls_pmaccontrol/motor.py +++ b/src/dls_pmaccontrol/motor.py @@ -663,6 +663,18 @@ def updateMotors(self): if motorRow == "IDENT": self.updateIdentity(int(value[0])) continue + if motorRow == "UVOL": + if int(value[0]) != 0: + print("Under voltage!", str(value[0])) + continue + if motorRow == "OVOL": + if int(value[0]) != 0: + print("Over voltage!", str(value[0])) + continue + if motorRow == "OTEMP": + if int(value[0]) != 0: + print("Over temperature!", str(value[0])) + continue else: if motorRow == "G": self.GlobalStatusScreen.updateStatus(int(value[0], 16)) From 17becd911fc4d4f8b0574ec951d77fde6d191052 Mon Sep 17 00:00:00 2001 From: James O'Hea Date: Thu, 3 Aug 2023 16:58:19 +0100 Subject: [PATCH 03/36] Add motor amplifier status requests to PowerPMAC cmd string and parse the response (see ticket BC-1450) --- src/dls_pmaccontrol/commsThread.py | 14 +++++++++++--- src/dls_pmaccontrol/motor.py | 13 ++++++++++++- 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/src/dls_pmaccontrol/commsThread.py b/src/dls_pmaccontrol/commsThread.py index d543205..0bcdec7 100644 --- a/src/dls_pmaccontrol/commsThread.py +++ b/src/dls_pmaccontrol/commsThread.py @@ -153,8 +153,13 @@ def updateFunc(self): # Add the 7 segment display status query cmd = "i65???&%s??%%m%s90" % (self.CSNum, self.CSNum) axes = self.parent.pmac.getNumberOfAxes() + 1 - for motorNo in range(1, axes): - cmd = cmd + "#" + str(motorNo) + "?PVF" + if isinstance(self.parent.pmac, PPmacSshInterface): + # Number of axes is hard-coded for now until axes vs channels issue is resolved + for motorNo in range(0, 8): + cmd = cmd + "#" + str(motorNo) + "?PVF BrickLV.Chan[" + str(motorNo) + "].I2tFaultStatus BrickLV.Chan[" + str(motorNo) + "].OverCurrent" + else: + for motorNo in range(1, axes): + cmd = cmd + "#" + str(motorNo) + "?PVF" # send polling command (retStr, wasSuccessful) = self.parent.pmac.sendCommand(cmd) with self.lock: @@ -209,7 +214,10 @@ def updateFunc(self): valueList = valueList[7:] else: valueList = valueList[4:] - cols = 4 + if isinstance(self.parent.pmac, PPmacSshInterface): + cols = 6 + else: + cols = 4 for motorRow, i in enumerate(range(0, len(valueList), cols)): returnList = valueList[i : i + cols] returnList.append(motorRow) diff --git a/src/dls_pmaccontrol/motor.py b/src/dls_pmaccontrol/motor.py index 62f069f..91cb682 100755 --- a/src/dls_pmaccontrol/motor.py +++ b/src/dls_pmaccontrol/motor.py @@ -641,7 +641,10 @@ def updateMotors(self): return try: - motorRow = value[4] + if isinstance(self.pmac, PPmacSshInterface): + motorRow = value[6] + else: + motorRow = value[4] # check for special cases if type(motorRow) == str: if isinstance(self.pmac, PPmacSshInterface): @@ -696,6 +699,14 @@ def updateMotors(self): velocity = str(round(float(value[2]), 1)) folerr = str(round(float(value[3]), 1)) + if isinstance(self.pmac, PPmacSshInterface): + i2t_fault = str(round(float(value[4]), 1)) + over_current = str(round(float(value[5]), 1)) + if int(value[4]) != 0: + print("i2t_fault =", int(value[4])) + if int(value[5]) != 0: + print("over_current =", int(value[5])) + self.__item(motorRow, 0).setText(position) self.__item(motorRow, 1).setText(velocity) self.__item(motorRow, 2).setText(folerr) From 747b2a4dad1d85abedacda8b44180b5e2984155b Mon Sep 17 00:00:00 2001 From: James O'Hea Date: Fri, 4 Aug 2023 11:08:40 +0100 Subject: [PATCH 04/36] Add motor amplifier status requests to TurboPMAC cmd string (see ticket BC-1450) --- src/dls_pmaccontrol/commsThread.py | 8 +++++--- src/dls_pmaccontrol/motor.py | 2 +- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/dls_pmaccontrol/commsThread.py b/src/dls_pmaccontrol/commsThread.py index 0bcdec7..ac4722a 100644 --- a/src/dls_pmaccontrol/commsThread.py +++ b/src/dls_pmaccontrol/commsThread.py @@ -158,8 +158,9 @@ def updateFunc(self): for motorNo in range(0, 8): cmd = cmd + "#" + str(motorNo) + "?PVF BrickLV.Chan[" + str(motorNo) + "].I2tFaultStatus BrickLV.Chan[" + str(motorNo) + "].OverCurrent" else: - for motorNo in range(1, axes): - cmd = cmd + "#" + str(motorNo) + "?PVF" + for motorNo in range(1, 9): + cmd = cmd + "#" + str(motorNo) + "?PVFm" + str(motorNo) + "90" + # send polling command (retStr, wasSuccessful) = self.parent.pmac.sendCommand(cmd) with self.lock: @@ -217,7 +218,8 @@ def updateFunc(self): if isinstance(self.parent.pmac, PPmacSshInterface): cols = 6 else: - cols = 4 + cols = 5 + for motorRow, i in enumerate(range(0, len(valueList), cols)): returnList = valueList[i : i + cols] returnList.append(motorRow) diff --git a/src/dls_pmaccontrol/motor.py b/src/dls_pmaccontrol/motor.py index 91cb682..221a328 100755 --- a/src/dls_pmaccontrol/motor.py +++ b/src/dls_pmaccontrol/motor.py @@ -644,7 +644,7 @@ def updateMotors(self): if isinstance(self.pmac, PPmacSshInterface): motorRow = value[6] else: - motorRow = value[4] + motorRow = value[5] # check for special cases if type(motorRow) == str: if isinstance(self.pmac, PPmacSshInterface): From 7b982126dc1393214ea9d678b4e58086d3e64488 Mon Sep 17 00:00:00 2001 From: James O'Hea Date: Fri, 4 Aug 2023 11:11:01 +0100 Subject: [PATCH 05/36] Parse the amplifier status requests from both Turbo and Power PMACs (see ticket BC-1450) --- src/dls_pmaccontrol/motor.py | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/src/dls_pmaccontrol/motor.py b/src/dls_pmaccontrol/motor.py index 221a328..cae4956 100755 --- a/src/dls_pmaccontrol/motor.py +++ b/src/dls_pmaccontrol/motor.py @@ -699,13 +699,29 @@ def updateMotors(self): velocity = str(round(float(value[2]), 1)) folerr = str(round(float(value[3]), 1)) + i2t_fault = False + under_voltage = False + over_voltage = False + over_current = False + over_temperature = False + if isinstance(self.pmac, PPmacSshInterface): - i2t_fault = str(round(float(value[4]), 1)) - over_current = str(round(float(value[5]), 1)) - if int(value[4]) != 0: - print("i2t_fault =", int(value[4])) - if int(value[5]) != 0: - print("over_current =", int(value[5])) + if int(value[4]) > 0: + i2t_fault = True + if int(value[5]) > 0: + over_current = True + elif isinstance(self.pmac, PmacEthernetInterface): + amp_status = ((int(value[4])&448)>>6) + if amp_status == 2: + under_voltage = True + elif amp_status == 3: + over_temperature = True + elif amp_status == 4: + over_voltage = True + elif amp_status == 5: + i2t_fault = True + elif amp_status == 6: + over_current = True self.__item(motorRow, 0).setText(position) self.__item(motorRow, 1).setText(velocity) From 4554629e1d4d8c567553d601e18744c82609fabd Mon Sep 17 00:00:00 2001 From: James O'Hea Date: Fri, 4 Aug 2023 11:12:31 +0100 Subject: [PATCH 06/36] Add indicators for i2t and over current faults to the GUI and set them motor.py (see ticket BC-1450) --- src/dls_pmaccontrol/formControl.ui | 22 ++- src/dls_pmaccontrol/motor.py | 10 ++ src/dls_pmaccontrol/ui_formControl.py | 188 ++++++++++---------------- 3 files changed, 101 insertions(+), 119 deletions(-) diff --git a/src/dls_pmaccontrol/formControl.ui b/src/dls_pmaccontrol/formControl.ui index 8cb4178..84dd7b1 100644 --- a/src/dls_pmaccontrol/formControl.ui +++ b/src/dls_pmaccontrol/formControl.ui @@ -7,7 +7,7 @@ 0 0 675 - 750 + 805 @@ -1006,6 +1006,9 @@ 8 + + QAbstractScrollArea::AdjustToContents + QAbstractItemView::NoSelection @@ -1027,8 +1030,11 @@ true + + false + - 130 + 94 50 @@ -1061,6 +1067,16 @@ lo lim + + + i2t fault + + + + + over current + + @@ -1093,6 +1109,8 @@ p, li { white-space: pre-wrap; } <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:10pt;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;"><br /></span></p> diff --git a/src/dls_pmaccontrol/motor.py b/src/dls_pmaccontrol/motor.py index cae4956..9e2358e 100755 --- a/src/dls_pmaccontrol/motor.py +++ b/src/dls_pmaccontrol/motor.py @@ -757,6 +757,16 @@ def updateMotors(self): else: self.__item(motorRow, 4).setIcon(QIcon(self.redLedOff)) + # set amplifier status indicators in polling table + if i2t_fault: + self.__item(motorRow, 5).setIcon(QIcon(self.redLedOn)) + else: + self.__item(motorRow, 5).setIcon(QIcon(self.redLedOff)) + if over_current: + self.__item(motorRow, 6).setIcon(QIcon(self.redLedOn)) + else: + self.__item(motorRow, 6).setIcon(QIcon(self.redLedOff)) + # Update also the jog ribbon if motorRow + 1 == self.currentMotor: self.lblPosition.setText(position) diff --git a/src/dls_pmaccontrol/ui_formControl.py b/src/dls_pmaccontrol/ui_formControl.py index 8962936..6622508 100644 --- a/src/dls_pmaccontrol/ui_formControl.py +++ b/src/dls_pmaccontrol/ui_formControl.py @@ -2,11 +2,9 @@ # Form implementation generated from reading ui file 'dls_pmaccontrol/formControl.ui' # -# Created by: PyQt5 UI code generator 5.15.4 +# Created by: PyQt5 UI code generator 5.12.2 # -# WARNING: Any manual changes made to this file will be lost when pyuic5 is -# run again. Do not edit this file unless you know what you are doing. - +# WARNING! All changes made in this file will be lost! from PyQt5 import QtCore, QtGui, QtWidgets @@ -14,7 +12,7 @@ class Ui_ControlForm(object): def setupUi(self, ControlForm): ControlForm.setObjectName("ControlForm") - ControlForm.resize(675, 750) + ControlForm.resize(675, 805) font = QtGui.QFont() ControlForm.setFont(font) self.widget = QtWidgets.QWidget(ControlForm) @@ -24,9 +22,7 @@ def setupUi(self, ControlForm): self.gridLayout_2.setSpacing(6) self.gridLayout_2.setObjectName("gridLayout_2") self.grpJog = QtWidgets.QGroupBox(self.widget) - sizePolicy = QtWidgets.QSizePolicy( - QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed - ) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.grpJog.sizePolicy().hasHeightForWidth()) @@ -40,9 +36,7 @@ def setupUi(self, ControlForm): self.horizontalLayout.setSpacing(6) self.horizontalLayout.setObjectName("horizontalLayout") self.spnJogMotor = QtWidgets.QSpinBox(self.grpJog) - sizePolicy = QtWidgets.QSizePolicy( - QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed - ) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.spnJogMotor.sizePolicy().hasHeightForWidth()) @@ -98,9 +92,7 @@ def setupUi(self, ControlForm): self.lblPosition.setMinimumSize(QtCore.QSize(0, 28)) self.lblPosition.setFrameShape(QtWidgets.QFrame.Box) self.lblPosition.setFrameShadow(QtWidgets.QFrame.Sunken) - self.lblPosition.setAlignment( - QtCore.Qt.AlignRight | QtCore.Qt.AlignTrailing | QtCore.Qt.AlignVCenter - ) + self.lblPosition.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter) self.lblPosition.setWordWrap(False) self.lblPosition.setObjectName("lblPosition") self.gridLayout.addWidget(self.lblPosition, 3, 1, 1, 1) @@ -113,7 +105,7 @@ def setupUi(self, ControlForm): self.horizontalLayout_2.setObjectName("horizontalLayout_2") self.pixHiLim = QtWidgets.QLabel(self.grpJog) self.pixHiLim.setMaximumSize(QtCore.QSize(25, 25)) - self.pixHiLim.setPixmap(QtGui.QPixmap("dls_pmaccontrol/redLedOff.png")) + self.pixHiLim.setPixmap(QtGui.QPixmap("redLedOff.png")) self.pixHiLim.setWordWrap(False) self.pixHiLim.setObjectName("pixHiLim") self.horizontalLayout_2.addWidget(self.pixHiLim) @@ -130,9 +122,7 @@ def setupUi(self, ControlForm): self.lblVelo.setMinimumSize(QtCore.QSize(0, 28)) self.lblVelo.setFrameShape(QtWidgets.QFrame.Box) self.lblVelo.setFrameShadow(QtWidgets.QFrame.Sunken) - self.lblVelo.setAlignment( - QtCore.Qt.AlignRight | QtCore.Qt.AlignTrailing | QtCore.Qt.AlignVCenter - ) + self.lblVelo.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter) self.lblVelo.setWordWrap(False) self.lblVelo.setObjectName("lblVelo") self.gridLayout.addWidget(self.lblVelo, 4, 1, 1, 1) @@ -145,7 +135,7 @@ def setupUi(self, ControlForm): self.horizontalLayout_3.setObjectName("horizontalLayout_3") self.pixLoLim = QtWidgets.QLabel(self.grpJog) self.pixLoLim.setMaximumSize(QtCore.QSize(20, 20)) - self.pixLoLim.setPixmap(QtGui.QPixmap("dls_pmaccontrol/redLedOff.png")) + self.pixLoLim.setPixmap(QtGui.QPixmap("redLedOff.png")) self.pixLoLim.setWordWrap(False) self.pixLoLim.setObjectName("pixLoLim") self.horizontalLayout_3.addWidget(self.pixLoLim) @@ -162,9 +152,7 @@ def setupUi(self, ControlForm): self.lblFolErr.setMinimumSize(QtCore.QSize(0, 28)) self.lblFolErr.setFrameShape(QtWidgets.QFrame.Box) self.lblFolErr.setFrameShadow(QtWidgets.QFrame.Sunken) - self.lblFolErr.setAlignment( - QtCore.Qt.AlignRight | QtCore.Qt.AlignTrailing | QtCore.Qt.AlignVCenter - ) + self.lblFolErr.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter) self.lblFolErr.setWordWrap(False) self.lblFolErr.setObjectName("lblFolErr") self.gridLayout.addWidget(self.lblFolErr, 5, 1, 1, 1) @@ -197,9 +185,7 @@ def setupUi(self, ControlForm): self.gridLayout.addWidget(self.btnJogStop, 5, 3, 1, 1) self.lneJogDist = QtWidgets.QLineEdit(self.grpJog) self.lneJogDist.setEnabled(False) - sizePolicy = QtWidgets.QSizePolicy( - QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.Fixed - ) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.Fixed) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.lneJogDist.sizePolicy().hasHeightForWidth()) @@ -223,9 +209,7 @@ def setupUi(self, ControlForm): self.gridLayout.addWidget(self.textLabel3, 2, 0, 1, 1) self.lneJogTo = QtWidgets.QLineEdit(self.grpJog) self.lneJogTo.setEnabled(False) - sizePolicy = QtWidgets.QSizePolicy( - QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.Fixed - ) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.Fixed) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.lneJogTo.sizePolicy().hasHeightForWidth()) @@ -251,16 +235,12 @@ def setupUi(self, ControlForm): self.gridLayout.addWidget(self.btnKillMotor, 6, 3, 1, 1) self.gridLayout_2.addWidget(self.grpJog, 0, 1, 1, 1) self.groupBox1 = QtWidgets.QGroupBox(self.widget) - sizePolicy = QtWidgets.QSizePolicy( - QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Fixed - ) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Fixed) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.groupBox1.sizePolicy().hasHeightForWidth()) self.groupBox1.setSizePolicy(sizePolicy) - self.groupBox1.setAlignment( - QtCore.Qt.AlignLeading | QtCore.Qt.AlignLeft | QtCore.Qt.AlignTop - ) + self.groupBox1.setAlignment(QtCore.Qt.AlignLeading|QtCore.Qt.AlignLeft|QtCore.Qt.AlignTop) self.groupBox1.setObjectName("groupBox1") self.verticalLayout = QtWidgets.QVBoxLayout(self.groupBox1) self.verticalLayout.setContentsMargins(11, 11, 11, 11) @@ -274,23 +254,17 @@ def setupUi(self, ControlForm): self.gridLayout_3.setSpacing(6) self.gridLayout_3.setObjectName("gridLayout_3") self.rbUseTerminalServer = QtWidgets.QRadioButton(self.btnGroupProtocol) - sizePolicy = QtWidgets.QSizePolicy( - QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed - ) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth( - self.rbUseTerminalServer.sizePolicy().hasHeightForWidth() - ) + sizePolicy.setHeightForWidth(self.rbUseTerminalServer.sizePolicy().hasHeightForWidth()) self.rbUseTerminalServer.setSizePolicy(sizePolicy) self.rbUseTerminalServer.setChecked(False) self.rbUseTerminalServer.setObjectName("rbUseTerminalServer") self.gridLayout_3.addWidget(self.rbUseTerminalServer, 0, 0, 1, 1) self.rbUseSocket = QtWidgets.QRadioButton(self.btnGroupProtocol) self.rbUseSocket.setEnabled(True) - sizePolicy = QtWidgets.QSizePolicy( - QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed - ) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.rbUseSocket.sizePolicy().hasHeightForWidth()) @@ -298,9 +272,7 @@ def setupUi(self, ControlForm): self.rbUseSocket.setObjectName("rbUseSocket") self.gridLayout_3.addWidget(self.rbUseSocket, 1, 0, 1, 1) self.rbUseSerial = QtWidgets.QRadioButton(self.btnGroupProtocol) - sizePolicy = QtWidgets.QSizePolicy( - QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Expanding - ) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Expanding) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.rbUseSerial.sizePolicy().hasHeightForWidth()) @@ -310,9 +282,7 @@ def setupUi(self, ControlForm): self.gridLayout_3.addWidget(self.rbUseSerial, 2, 0, 1, 1) self.rbUseSsh = QtWidgets.QRadioButton(self.btnGroupProtocol) self.rbUseSsh.setEnabled(True) - sizePolicy = QtWidgets.QSizePolicy( - QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Expanding - ) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Expanding) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.rbUseSsh.sizePolicy().hasHeightForWidth()) @@ -354,9 +324,7 @@ def setupUi(self, ControlForm): self.hboxlayout.addWidget(self.btnDisconnect) self.verticalLayout.addLayout(self.hboxlayout) self.lblIdentity = QtWidgets.QLabel(self.groupBox1) - sizePolicy = QtWidgets.QSizePolicy( - QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Preferred - ) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Preferred) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.lblIdentity.sizePolicy().hasHeightForWidth()) @@ -383,9 +351,7 @@ def setupUi(self, ControlForm): self.hboxlayout1.addWidget(self.chkShowAll) self.gridLayout_2.addLayout(self.hboxlayout1, 4, 0, 1, 2) self.frame3 = QtWidgets.QFrame(self.widget) - sizePolicy = QtWidgets.QSizePolicy( - QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed - ) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.frame3.sizePolicy().hasHeightForWidth()) @@ -417,7 +383,7 @@ def setupUi(self, ControlForm): self.gridLayout_4.addWidget(self.lnePollRate, 2, 2, 1, 1) self.pixPolling = QtWidgets.QLabel(self.frame3) self.pixPolling.setMaximumSize(QtCore.QSize(25, 25)) - self.pixPolling.setPixmap(QtGui.QPixmap("dls_pmaccontrol/greenLedOff.png")) + self.pixPolling.setPixmap(QtGui.QPixmap("greenLedOff.png")) self.pixPolling.setWordWrap(False) self.pixPolling.setObjectName("pixPolling") self.gridLayout_4.addWidget(self.pixPolling, 2, 0, 1, 1) @@ -431,9 +397,7 @@ def setupUi(self, ControlForm): self.gridLayout_4.addWidget(self.btnGlobalStatus, 2, 6, 1, 1) self.btnKillAll = QtWidgets.QPushButton(self.frame3) self.btnKillAll.setEnabled(False) - sizePolicy = QtWidgets.QSizePolicy( - QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Minimum - ) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Minimum) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.btnKillAll.sizePolicy().hasHeightForWidth()) @@ -470,9 +434,7 @@ def setupUi(self, ControlForm): self.gridLayout_4.addWidget(self.btnWatches, 2, 4, 1, 1) self.gridLayout_2.addWidget(self.frame3, 2, 0, 1, 2) self.splitter = QtWidgets.QSplitter(self.widget) - sizePolicy = QtWidgets.QSizePolicy( - QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Expanding - ) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Expanding) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.splitter.sizePolicy().hasHeightForWidth()) @@ -480,9 +442,7 @@ def setupUi(self, ControlForm): self.splitter.setOrientation(QtCore.Qt.Vertical) self.splitter.setObjectName("splitter") self.table = QtWidgets.QTableWidget(self.splitter) - sizePolicy = QtWidgets.QSizePolicy( - QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding - ) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding) sizePolicy.setHorizontalStretch(1) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.table.sizePolicy().hasHeightForWidth()) @@ -491,6 +451,7 @@ def setupUi(self, ControlForm): font = QtGui.QFont() font.setPointSize(8) self.table.setFont(font) + self.table.setSizeAdjustPolicy(QtWidgets.QAbstractScrollArea.AdjustToContents) self.table.setSelectionMode(QtWidgets.QAbstractItemView.NoSelection) self.table.setProperty("dragAutoScroll", False) self.table.setProperty("numRows", 32) @@ -499,7 +460,7 @@ def setupUi(self, ControlForm): self.table.setProperty("columnMovingEnabled", False) self.table.setProperty("readOnly", True) self.table.setObjectName("table") - self.table.setColumnCount(5) + self.table.setColumnCount(7) self.table.setRowCount(0) item = QtWidgets.QTableWidgetItem() self.table.setHorizontalHeaderItem(0, item) @@ -511,14 +472,17 @@ def setupUi(self, ControlForm): self.table.setHorizontalHeaderItem(3, item) item = QtWidgets.QTableWidgetItem() self.table.setHorizontalHeaderItem(4, item) - self.table.horizontalHeader().setDefaultSectionSize(130) + item = QtWidgets.QTableWidgetItem() + self.table.setHorizontalHeaderItem(5, item) + item = QtWidgets.QTableWidgetItem() + self.table.setHorizontalHeaderItem(6, item) + self.table.horizontalHeader().setCascadingSectionResizes(False) + self.table.horizontalHeader().setDefaultSectionSize(94) self.table.horizontalHeader().setMinimumSectionSize(50) self.table.verticalHeader().setDefaultSectionSize(20) self.txtShell = QtWidgets.QTextEdit(self.splitter) self.txtShell.setEnabled(True) - sizePolicy = QtWidgets.QSizePolicy( - QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding - ) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding) sizePolicy.setHorizontalStretch(1) sizePolicy.setVerticalStretch(1) sizePolicy.setHeightForWidth(self.txtShell.sizePolicy().hasHeightForWidth()) @@ -533,7 +497,7 @@ def setupUi(self, ControlForm): ControlForm.setCentralWidget(self.widget) self.retranslateUi(ControlForm) - self.spnJogMotor.valueChanged["int"].connect(ControlForm.jogChangeMotor) + self.spnJogMotor.valueChanged['int'].connect(ControlForm.jogChangeMotor) self.btnJogPos.clicked.connect(ControlForm.jogPos) self.btnSend.clicked.connect(ControlForm.sendSingleCommand) self.lneSend.returnPressed.connect(ControlForm.sendSingleCommand) @@ -541,24 +505,20 @@ def setupUi(self, ControlForm): self.lneServer.returnPressed.connect(self.lnePort.selectAll) self.lneServer.returnPressed.connect(self.lnePort.setFocus) self.lnePort.returnPressed.connect(self.rbUseTerminalServer.setFocus) - self.rbUseTerminalServer.clicked.connect( - ControlForm.useTerminalServerConnection - ) + self.rbUseTerminalServer.clicked.connect(ControlForm.useTerminalServerConnection) self.rbUseSocket.clicked.connect(ControlForm.useSocketConnection) self.rbUseSsh.clicked.connect(ControlForm.useSshConnection) self.btnDisconnect.clicked.connect(ControlForm.remoteDisconnect) self.btnConnect.clicked.connect(ControlForm.remoteConnect) self.lnePort.returnPressed.connect(ControlForm.remoteConnect) self.btnKillMotor.clicked.connect(ControlForm.killMotor) - self.chkJogInc.toggled["bool"].connect(ControlForm.jogIncrementally) + self.chkJogInc.toggled['bool'].connect(ControlForm.jogIncrementally) self.btnJogStop.clicked.connect(ControlForm.jogStop) self.btnJogTo.clicked.connect(ControlForm.jogGoToPosition) self.btnSettings.clicked.connect(ControlForm.jogParameters) self.btnStatus.clicked.connect(ControlForm.statusScreen) self.btnJogNeg.clicked.connect(ControlForm.jogNeg) - self.table.cellDoubleClicked["int", "int"].connect( - ControlForm.chooseMotorFromTable - ) + self.table.cellDoubleClicked['int','int'].connect(ControlForm.chooseMotorFromTable) self.btnGather.clicked.connect(ControlForm.dataGather) self.btnWatches.clicked.connect(ControlForm.watches) self.btnPollingStatus.clicked.connect(ControlForm.pmacPollingStatus) @@ -600,13 +560,9 @@ def setupUi(self, ControlForm): def retranslateUi(self, ControlForm): _translate = QtCore.QCoreApplication.translate - ControlForm.setWindowTitle( - _translate("ControlForm", "Delta Tau motor controller") - ) + ControlForm.setWindowTitle(_translate("ControlForm", "Delta Tau motor controller")) self.grpJog.setTitle(_translate("ControlForm", "Jog ribbon")) - self.spnJogMotor.setToolTip( - _translate("ControlForm", "Choose the motor to jog") - ) + self.spnJogMotor.setToolTip(_translate("ControlForm", "Choose the motor to jog")) self.btnJogNeg.setText(_translate("ControlForm", "jog neg")) self.btnHome.setText(_translate("ControlForm", "home")) self.btnJogPos.setText(_translate("ControlForm", "jog pos")) @@ -652,12 +608,7 @@ def retranslateUi(self, ControlForm): self.lblPolling.setText(_translate("ControlForm", "Polling")) self.lblPollRate.setText(_translate("ControlForm", "Hz")) self.btnGlobalStatus.setText(_translate("ControlForm", "Global Status...")) - self.btnKillAll.setToolTip( - _translate( - "ControlForm", - "Kill All (CTRL-K) motion by opening servo loops and setting zero velocity", - ) - ) + self.btnKillAll.setToolTip(_translate("ControlForm", "Kill All (CTRL-K) motion by opening servo loops and setting zero velocity")) self.btnKillAll.setText(_translate("ControlForm", "KILL ALL!")) self.btnLoadFile.setText(_translate("ControlForm", "load pmc...")) self.btnPollingStatus.setText(_translate("ControlForm", "disable polling")) @@ -673,30 +624,33 @@ def retranslateUi(self, ControlForm): item.setText(_translate("ControlForm", "hi lim")) item = self.table.horizontalHeaderItem(4) item.setText(_translate("ControlForm", "lo lim")) - self.txtShell.setHtml( - _translate( - "ControlForm", - '\n' - '\n" - '\n' - "\n" - '
\n' - '


\n' - '


\n' - '


\n' - '


\n' - '


\n' - '


\n' - '


\n' - '


\n' - '


\n' - '


\n' - '


\n' - '


\n' - '


\n' - '


\n' - '


', - ) - ) + item = self.table.horizontalHeaderItem(5) + item.setText(_translate("ControlForm", "i2t fault")) + item = self.table.horizontalHeaderItem(6) + item.setText(_translate("ControlForm", "over current")) + self.txtShell.setHtml(_translate("ControlForm", "\n" +"\n" +"\n" +"\n" +"
\n" +"


\n" +"


\n" +"


\n" +"


\n" +"


\n" +"


\n" +"


\n" +"


\n" +"


\n" +"


\n" +"


\n" +"


\n" +"


\n" +"


\n" +"


\n" +"


\n" +"


")) + + From a4471d45dfb6dc19b4ca13b46de69f87028d6b53 Mon Sep 17 00:00:00 2001 From: James O'Hea Date: Fri, 4 Aug 2023 11:22:51 +0100 Subject: [PATCH 07/36] Correct typo on Axis Settings screens (see ticket CGP-232) --- src/dls_pmaccontrol/formAxisSettings.ui | 4 +- src/dls_pmaccontrol/formPpmacAxisSettings.ui | 2 +- src/dls_pmaccontrol/ui_formAxisSettings.py | 185 ++++--------- .../ui_formPpmacAxisSettings.py | 247 +++++------------- 4 files changed, 116 insertions(+), 322 deletions(-) diff --git a/src/dls_pmaccontrol/formAxisSettings.ui b/src/dls_pmaccontrol/formAxisSettings.ui index 21d2fbd..d722582 100644 --- a/src/dls_pmaccontrol/formAxisSettings.ui +++ b/src/dls_pmaccontrol/formAxisSettings.ui @@ -7,7 +7,7 @@ 0 0 508 - 451 + 548
@@ -29,7 +29,7 @@ - Note this screen does not update continously. + Note this screen does not update continuously. Hit the update button to read out the current values from pmac. Write demand values in the text fields and hit enter to send. diff --git a/src/dls_pmaccontrol/formPpmacAxisSettings.ui b/src/dls_pmaccontrol/formPpmacAxisSettings.ui index 92887e8..8173602 100644 --- a/src/dls_pmaccontrol/formPpmacAxisSettings.ui +++ b/src/dls_pmaccontrol/formPpmacAxisSettings.ui @@ -36,7 +36,7 @@ - Note this screen does not update continously. + Note this screen does not update continuously. Hit the update button to read out the current values from pmac. Write demand values in the text fields and hit enter to send. diff --git a/src/dls_pmaccontrol/ui_formAxisSettings.py b/src/dls_pmaccontrol/ui_formAxisSettings.py index bc76a53..fa155b0 100644 --- a/src/dls_pmaccontrol/ui_formAxisSettings.py +++ b/src/dls_pmaccontrol/ui_formAxisSettings.py @@ -2,11 +2,9 @@ # Form implementation generated from reading ui file 'dls_pmaccontrol/formAxisSettings.ui' # -# Created by: PyQt5 UI code generator 5.15.4 +# Created by: PyQt5 UI code generator 5.12.2 # -# WARNING: Any manual changes made to this file will be lost when pyuic5 is -# run again. Do not edit this file unless you know what you are doing. - +# WARNING! All changes made in this file will be lost! from PyQt5 import QtCore, QtGui, QtWidgets @@ -14,10 +12,8 @@ class Ui_formAxisSettings(object): def setupUi(self, formAxisSettings): formAxisSettings.setObjectName("formAxisSettings") - formAxisSettings.resize(508, 451) - sizePolicy = QtWidgets.QSizePolicy( - QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed - ) + formAxisSettings.resize(508, 548) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(formAxisSettings.sizePolicy().hasHeightForWidth()) @@ -57,9 +53,7 @@ def setupUi(self, formAxisSettings): self.textLabel2_2 = QtWidgets.QLabel(self.groupBox1) self.textLabel2_2.setWordWrap(False) self.textLabel2_2.setObjectName("textLabel2_2") - self.formLayout_2.setWidget( - 1, QtWidgets.QFormLayout.LabelRole, self.textLabel2_2 - ) + self.formLayout_2.setWidget(1, QtWidgets.QFormLayout.LabelRole, self.textLabel2_2) self.lneIx12 = QtWidgets.QLineEdit(self.groupBox1) self.lneIx12.setMinimumSize(QtCore.QSize(60, 0)) self.lneIx12.setMaximumSize(QtCore.QSize(31222, 32767)) @@ -68,9 +62,7 @@ def setupUi(self, formAxisSettings): self.textLabel2_3 = QtWidgets.QLabel(self.groupBox1) self.textLabel2_3.setWordWrap(False) self.textLabel2_3.setObjectName("textLabel2_3") - self.formLayout_2.setWidget( - 2, QtWidgets.QFormLayout.LabelRole, self.textLabel2_3 - ) + self.formLayout_2.setWidget(2, QtWidgets.QFormLayout.LabelRole, self.textLabel2_3) self.lneIx13 = QtWidgets.QLineEdit(self.groupBox1) self.lneIx13.setMinimumSize(QtCore.QSize(60, 0)) self.lneIx13.setMaximumSize(QtCore.QSize(31222, 32767)) @@ -79,9 +71,7 @@ def setupUi(self, formAxisSettings): self.textLabel2_4 = QtWidgets.QLabel(self.groupBox1) self.textLabel2_4.setWordWrap(False) self.textLabel2_4.setObjectName("textLabel2_4") - self.formLayout_2.setWidget( - 3, QtWidgets.QFormLayout.LabelRole, self.textLabel2_4 - ) + self.formLayout_2.setWidget(3, QtWidgets.QFormLayout.LabelRole, self.textLabel2_4) self.lneIx14 = QtWidgets.QLineEdit(self.groupBox1) self.lneIx14.setMinimumSize(QtCore.QSize(60, 0)) self.lneIx14.setMaximumSize(QtCore.QSize(31222, 32767)) @@ -90,9 +80,7 @@ def setupUi(self, formAxisSettings): self.textLabel2_5 = QtWidgets.QLabel(self.groupBox1) self.textLabel2_5.setWordWrap(False) self.textLabel2_5.setObjectName("textLabel2_5") - self.formLayout_2.setWidget( - 4, QtWidgets.QFormLayout.LabelRole, self.textLabel2_5 - ) + self.formLayout_2.setWidget(4, QtWidgets.QFormLayout.LabelRole, self.textLabel2_5) self.lneIx15 = QtWidgets.QLineEdit(self.groupBox1) self.lneIx15.setMinimumSize(QtCore.QSize(60, 0)) self.lneIx15.setMaximumSize(QtCore.QSize(31222, 32767)) @@ -101,9 +89,7 @@ def setupUi(self, formAxisSettings): self.textLabel2_6 = QtWidgets.QLabel(self.groupBox1) self.textLabel2_6.setWordWrap(False) self.textLabel2_6.setObjectName("textLabel2_6") - self.formLayout_2.setWidget( - 5, QtWidgets.QFormLayout.LabelRole, self.textLabel2_6 - ) + self.formLayout_2.setWidget(5, QtWidgets.QFormLayout.LabelRole, self.textLabel2_6) self.lneIx16 = QtWidgets.QLineEdit(self.groupBox1) self.lneIx16.setMinimumSize(QtCore.QSize(60, 0)) self.lneIx16.setMaximumSize(QtCore.QSize(31222, 32767)) @@ -112,9 +98,7 @@ def setupUi(self, formAxisSettings): self.textLabel2_7 = QtWidgets.QLabel(self.groupBox1) self.textLabel2_7.setWordWrap(False) self.textLabel2_7.setObjectName("textLabel2_7") - self.formLayout_2.setWidget( - 6, QtWidgets.QFormLayout.LabelRole, self.textLabel2_7 - ) + self.formLayout_2.setWidget(6, QtWidgets.QFormLayout.LabelRole, self.textLabel2_7) self.lneIx17 = QtWidgets.QLineEdit(self.groupBox1) self.lneIx17.setMinimumSize(QtCore.QSize(60, 0)) self.lneIx17.setMaximumSize(QtCore.QSize(31222, 32767)) @@ -123,9 +107,7 @@ def setupUi(self, formAxisSettings): self.textLabel2_8 = QtWidgets.QLabel(self.groupBox1) self.textLabel2_8.setWordWrap(False) self.textLabel2_8.setObjectName("textLabel2_8") - self.formLayout_2.setWidget( - 7, QtWidgets.QFormLayout.LabelRole, self.textLabel2_8 - ) + self.formLayout_2.setWidget(7, QtWidgets.QFormLayout.LabelRole, self.textLabel2_8) self.lneIx19 = QtWidgets.QLineEdit(self.groupBox1) self.lneIx19.setMinimumSize(QtCore.QSize(60, 0)) self.lneIx19.setMaximumSize(QtCore.QSize(31222, 32767)) @@ -143,9 +125,7 @@ def setupUi(self, formAxisSettings): self.textLabel2_9.setObjectName("textLabel2_9") self.formLayout.setWidget(0, QtWidgets.QFormLayout.LabelRole, self.textLabel2_9) self.lneIx20 = QtWidgets.QLineEdit(self.groupBox2) - sizePolicy = QtWidgets.QSizePolicy( - QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed - ) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.lneIx20.sizePolicy().hasHeightForWidth()) @@ -157,9 +137,7 @@ def setupUi(self, formAxisSettings): self.textLabel2_2_2 = QtWidgets.QLabel(self.groupBox2) self.textLabel2_2_2.setWordWrap(False) self.textLabel2_2_2.setObjectName("textLabel2_2_2") - self.formLayout.setWidget( - 1, QtWidgets.QFormLayout.LabelRole, self.textLabel2_2_2 - ) + self.formLayout.setWidget(1, QtWidgets.QFormLayout.LabelRole, self.textLabel2_2_2) self.lneIx21 = QtWidgets.QLineEdit(self.groupBox2) self.lneIx21.setMinimumSize(QtCore.QSize(60, 0)) self.lneIx21.setMaximumSize(QtCore.QSize(32222, 32767)) @@ -168,9 +146,7 @@ def setupUi(self, formAxisSettings): self.textLabel2_3_2 = QtWidgets.QLabel(self.groupBox2) self.textLabel2_3_2.setWordWrap(False) self.textLabel2_3_2.setObjectName("textLabel2_3_2") - self.formLayout.setWidget( - 2, QtWidgets.QFormLayout.LabelRole, self.textLabel2_3_2 - ) + self.formLayout.setWidget(2, QtWidgets.QFormLayout.LabelRole, self.textLabel2_3_2) self.lneIx22 = QtWidgets.QLineEdit(self.groupBox2) self.lneIx22.setMinimumSize(QtCore.QSize(60, 0)) self.lneIx22.setMaximumSize(QtCore.QSize(32222, 32767)) @@ -179,9 +155,7 @@ def setupUi(self, formAxisSettings): self.textLabel2_4_2 = QtWidgets.QLabel(self.groupBox2) self.textLabel2_4_2.setWordWrap(False) self.textLabel2_4_2.setObjectName("textLabel2_4_2") - self.formLayout.setWidget( - 3, QtWidgets.QFormLayout.LabelRole, self.textLabel2_4_2 - ) + self.formLayout.setWidget(3, QtWidgets.QFormLayout.LabelRole, self.textLabel2_4_2) self.lneIx23 = QtWidgets.QLineEdit(self.groupBox2) self.lneIx23.setMinimumSize(QtCore.QSize(60, 0)) self.lneIx23.setMaximumSize(QtCore.QSize(32222, 32767)) @@ -190,9 +164,7 @@ def setupUi(self, formAxisSettings): self.textLabel2_5_2 = QtWidgets.QLabel(self.groupBox2) self.textLabel2_5_2.setWordWrap(False) self.textLabel2_5_2.setObjectName("textLabel2_5_2") - self.formLayout.setWidget( - 4, QtWidgets.QFormLayout.LabelRole, self.textLabel2_5_2 - ) + self.formLayout.setWidget(4, QtWidgets.QFormLayout.LabelRole, self.textLabel2_5_2) self.lneIx24 = QtWidgets.QLineEdit(self.groupBox2) self.lneIx24.setMinimumSize(QtCore.QSize(60, 0)) self.lneIx24.setMaximumSize(QtCore.QSize(32222, 32767)) @@ -201,9 +173,7 @@ def setupUi(self, formAxisSettings): self.textLabel2_6_2 = QtWidgets.QLabel(self.groupBox2) self.textLabel2_6_2.setWordWrap(False) self.textLabel2_6_2.setObjectName("textLabel2_6_2") - self.formLayout.setWidget( - 5, QtWidgets.QFormLayout.LabelRole, self.textLabel2_6_2 - ) + self.formLayout.setWidget(5, QtWidgets.QFormLayout.LabelRole, self.textLabel2_6_2) self.lneIx25 = QtWidgets.QLineEdit(self.groupBox2) self.lneIx25.setMinimumSize(QtCore.QSize(60, 0)) self.lneIx25.setMaximumSize(QtCore.QSize(32222, 32767)) @@ -212,9 +182,7 @@ def setupUi(self, formAxisSettings): self.textLabel2_7_2 = QtWidgets.QLabel(self.groupBox2) self.textLabel2_7_2.setWordWrap(False) self.textLabel2_7_2.setObjectName("textLabel2_7_2") - self.formLayout.setWidget( - 6, QtWidgets.QFormLayout.LabelRole, self.textLabel2_7_2 - ) + self.formLayout.setWidget(6, QtWidgets.QFormLayout.LabelRole, self.textLabel2_7_2) self.lneIx26 = QtWidgets.QLineEdit(self.groupBox2) self.lneIx26.setMinimumSize(QtCore.QSize(0, 0)) self.lneIx26.setMaximumSize(QtCore.QSize(32222, 32767)) @@ -229,9 +197,7 @@ def setupUi(self, formAxisSettings): self.gridLayout.setSpacing(6) self.gridLayout.setObjectName("gridLayout") self.groupBox1_2 = QtWidgets.QGroupBox(self.tab1) - sizePolicy = QtWidgets.QSizePolicy( - QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed - ) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.groupBox1_2.sizePolicy().hasHeightForWidth()) @@ -244,9 +210,7 @@ def setupUi(self, formAxisSettings): self.textLabel2_10 = QtWidgets.QLabel(self.groupBox1_2) self.textLabel2_10.setWordWrap(False) self.textLabel2_10.setObjectName("textLabel2_10") - self.formLayout_3.setWidget( - 0, QtWidgets.QFormLayout.LabelRole, self.textLabel2_10 - ) + self.formLayout_3.setWidget(0, QtWidgets.QFormLayout.LabelRole, self.textLabel2_10) self.lneIx30 = QtWidgets.QLineEdit(self.groupBox1_2) self.lneIx30.setMinimumSize(QtCore.QSize(60, 0)) self.lneIx30.setMaximumSize(QtCore.QSize(32233, 32767)) @@ -255,9 +219,7 @@ def setupUi(self, formAxisSettings): self.textLabel2_2_3 = QtWidgets.QLabel(self.groupBox1_2) self.textLabel2_2_3.setWordWrap(False) self.textLabel2_2_3.setObjectName("textLabel2_2_3") - self.formLayout_3.setWidget( - 1, QtWidgets.QFormLayout.LabelRole, self.textLabel2_2_3 - ) + self.formLayout_3.setWidget(1, QtWidgets.QFormLayout.LabelRole, self.textLabel2_2_3) self.lneIx31 = QtWidgets.QLineEdit(self.groupBox1_2) self.lneIx31.setMinimumSize(QtCore.QSize(60, 0)) self.lneIx31.setMaximumSize(QtCore.QSize(32233, 32767)) @@ -266,9 +228,7 @@ def setupUi(self, formAxisSettings): self.textLabel2_3_3 = QtWidgets.QLabel(self.groupBox1_2) self.textLabel2_3_3.setWordWrap(False) self.textLabel2_3_3.setObjectName("textLabel2_3_3") - self.formLayout_3.setWidget( - 2, QtWidgets.QFormLayout.LabelRole, self.textLabel2_3_3 - ) + self.formLayout_3.setWidget(2, QtWidgets.QFormLayout.LabelRole, self.textLabel2_3_3) self.lneIx32 = QtWidgets.QLineEdit(self.groupBox1_2) self.lneIx32.setMinimumSize(QtCore.QSize(60, 0)) self.lneIx32.setMaximumSize(QtCore.QSize(32233, 32767)) @@ -277,9 +237,7 @@ def setupUi(self, formAxisSettings): self.textLabel2_4_3 = QtWidgets.QLabel(self.groupBox1_2) self.textLabel2_4_3.setWordWrap(False) self.textLabel2_4_3.setObjectName("textLabel2_4_3") - self.formLayout_3.setWidget( - 3, QtWidgets.QFormLayout.LabelRole, self.textLabel2_4_3 - ) + self.formLayout_3.setWidget(3, QtWidgets.QFormLayout.LabelRole, self.textLabel2_4_3) self.lneIx33 = QtWidgets.QLineEdit(self.groupBox1_2) self.lneIx33.setMinimumSize(QtCore.QSize(60, 0)) self.lneIx33.setMaximumSize(QtCore.QSize(32233, 32767)) @@ -288,9 +246,7 @@ def setupUi(self, formAxisSettings): self.textLabel2_5_3 = QtWidgets.QLabel(self.groupBox1_2) self.textLabel2_5_3.setWordWrap(False) self.textLabel2_5_3.setObjectName("textLabel2_5_3") - self.formLayout_3.setWidget( - 4, QtWidgets.QFormLayout.LabelRole, self.textLabel2_5_3 - ) + self.formLayout_3.setWidget(4, QtWidgets.QFormLayout.LabelRole, self.textLabel2_5_3) self.lneIx34 = QtWidgets.QLineEdit(self.groupBox1_2) self.lneIx34.setMinimumSize(QtCore.QSize(60, 0)) self.lneIx34.setMaximumSize(QtCore.QSize(32233, 32767)) @@ -299,9 +255,7 @@ def setupUi(self, formAxisSettings): self.textLabel2_10_2 = QtWidgets.QLabel(self.groupBox1_2) self.textLabel2_10_2.setWordWrap(False) self.textLabel2_10_2.setObjectName("textLabel2_10_2") - self.formLayout_3.setWidget( - 5, QtWidgets.QFormLayout.LabelRole, self.textLabel2_10_2 - ) + self.formLayout_3.setWidget(5, QtWidgets.QFormLayout.LabelRole, self.textLabel2_10_2) self.lneIx35 = QtWidgets.QLineEdit(self.groupBox1_2) self.lneIx35.setMinimumSize(QtCore.QSize(60, 0)) self.lneIx35.setMaximumSize(QtCore.QSize(32233, 32767)) @@ -310,9 +264,7 @@ def setupUi(self, formAxisSettings): self.textLabel2_10_2_2 = QtWidgets.QLabel(self.groupBox1_2) self.textLabel2_10_2_2.setWordWrap(False) self.textLabel2_10_2_2.setObjectName("textLabel2_10_2_2") - self.formLayout_3.setWidget( - 6, QtWidgets.QFormLayout.LabelRole, self.textLabel2_10_2_2 - ) + self.formLayout_3.setWidget(6, QtWidgets.QFormLayout.LabelRole, self.textLabel2_10_2_2) self.lneIx65 = QtWidgets.QLineEdit(self.groupBox1_2) self.lneIx65.setMinimumSize(QtCore.QSize(60, 0)) self.lneIx65.setMaximumSize(QtCore.QSize(32233, 32767)) @@ -320,36 +272,26 @@ def setupUi(self, formAxisSettings): self.formLayout_3.setWidget(6, QtWidgets.QFormLayout.FieldRole, self.lneIx65) self.gridLayout.addWidget(self.groupBox1_2, 0, 0, 2, 1) self.groupBox1_2_2 = QtWidgets.QGroupBox(self.tab1) - sizePolicy = QtWidgets.QSizePolicy( - QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed - ) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth( - self.groupBox1_2_2.sizePolicy().hasHeightForWidth() - ) + sizePolicy.setHeightForWidth(self.groupBox1_2_2.sizePolicy().hasHeightForWidth()) self.groupBox1_2_2.setSizePolicy(sizePolicy) self.groupBox1_2_2.setObjectName("groupBox1_2_2") self.formLayout_4 = QtWidgets.QFormLayout(self.groupBox1_2_2) - self.formLayout_4.setFieldGrowthPolicy( - QtWidgets.QFormLayout.AllNonFixedFieldsGrow - ) + self.formLayout_4.setFieldGrowthPolicy(QtWidgets.QFormLayout.AllNonFixedFieldsGrow) self.formLayout_4.setContentsMargins(11, 11, 11, 11) self.formLayout_4.setSpacing(6) self.formLayout_4.setObjectName("formLayout_4") self.lLoopSelect = QtWidgets.QLabel(self.groupBox1_2_2) self.lLoopSelect.setWordWrap(False) self.lLoopSelect.setObjectName("lLoopSelect") - self.formLayout_4.setWidget( - 0, QtWidgets.QFormLayout.LabelRole, self.lLoopSelect - ) + self.formLayout_4.setWidget(0, QtWidgets.QFormLayout.LabelRole, self.lLoopSelect) self.lneLoopSelect = QtWidgets.QLineEdit(self.groupBox1_2_2) self.lneLoopSelect.setMinimumSize(QtCore.QSize(60, 0)) self.lneLoopSelect.setMaximumSize(QtCore.QSize(32222, 32767)) self.lneLoopSelect.setObjectName("lneLoopSelect") - self.formLayout_4.setWidget( - 0, QtWidgets.QFormLayout.FieldRole, self.lneLoopSelect - ) + self.formLayout_4.setWidget(0, QtWidgets.QFormLayout.FieldRole, self.lneLoopSelect) self.lCaptureOn = QtWidgets.QLabel(self.groupBox1_2_2) self.lCaptureOn.setWordWrap(False) self.lCaptureOn.setObjectName("lCaptureOn") @@ -358,52 +300,36 @@ def setupUi(self, formAxisSettings): self.lneCaptureOn.setMinimumSize(QtCore.QSize(60, 0)) self.lneCaptureOn.setMaximumSize(QtCore.QSize(32222, 32767)) self.lneCaptureOn.setObjectName("lneCaptureOn") - self.formLayout_4.setWidget( - 1, QtWidgets.QFormLayout.FieldRole, self.lneCaptureOn - ) + self.formLayout_4.setWidget(1, QtWidgets.QFormLayout.FieldRole, self.lneCaptureOn) self.lCaptureFlag = QtWidgets.QLabel(self.groupBox1_2_2) self.lCaptureFlag.setWordWrap(False) self.lCaptureFlag.setObjectName("lCaptureFlag") - self.formLayout_4.setWidget( - 2, QtWidgets.QFormLayout.LabelRole, self.lCaptureFlag - ) + self.formLayout_4.setWidget(2, QtWidgets.QFormLayout.LabelRole, self.lCaptureFlag) self.lneCaptureFlag = QtWidgets.QLineEdit(self.groupBox1_2_2) self.lneCaptureFlag.setMinimumSize(QtCore.QSize(60, 0)) self.lneCaptureFlag.setMaximumSize(QtCore.QSize(32222, 32767)) self.lneCaptureFlag.setObjectName("lneCaptureFlag") - self.formLayout_4.setWidget( - 2, QtWidgets.QFormLayout.FieldRole, self.lneCaptureFlag - ) + self.formLayout_4.setWidget(2, QtWidgets.QFormLayout.FieldRole, self.lneCaptureFlag) self.lOutputMode = QtWidgets.QLabel(self.groupBox1_2_2) self.lOutputMode.setWordWrap(False) self.lOutputMode.setObjectName("lOutputMode") - self.formLayout_4.setWidget( - 3, QtWidgets.QFormLayout.LabelRole, self.lOutputMode - ) + self.formLayout_4.setWidget(3, QtWidgets.QFormLayout.LabelRole, self.lOutputMode) self.lneOutputMode = QtWidgets.QLineEdit(self.groupBox1_2_2) self.lneOutputMode.setMinimumSize(QtCore.QSize(60, 0)) self.lneOutputMode.setMaximumSize(QtCore.QSize(32222, 32767)) self.lneOutputMode.setObjectName("lneOutputMode") - self.formLayout_4.setWidget( - 3, QtWidgets.QFormLayout.FieldRole, self.lneOutputMode - ) + self.formLayout_4.setWidget(3, QtWidgets.QFormLayout.FieldRole, self.lneOutputMode) self.gridLayout.addWidget(self.groupBox1_2_2, 0, 1, 1, 1) - spacerItem = QtWidgets.QSpacerItem( - 20, 125, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding - ) + spacerItem = QtWidgets.QSpacerItem(20, 125, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) self.gridLayout.addItem(spacerItem, 1, 1, 2, 1) - spacerItem1 = QtWidgets.QSpacerItem( - 20, 26, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding - ) + spacerItem1 = QtWidgets.QSpacerItem(20, 26, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) self.gridLayout.addItem(spacerItem1, 2, 0, 1, 1) self.tabAxisSetup.addTab(self.tab1, "") self.gridLayout_3.addWidget(self.tabAxisSetup, 1, 0, 1, 3) self.btnUpdate = QtWidgets.QPushButton(formAxisSettings) self.btnUpdate.setObjectName("btnUpdate") self.gridLayout_3.addWidget(self.btnUpdate, 2, 0, 1, 1) - spacerItem2 = QtWidgets.QSpacerItem( - 185, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum - ) + spacerItem2 = QtWidgets.QSpacerItem(185, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) self.gridLayout_3.addItem(spacerItem2, 2, 1, 1, 1) self.btnClose = QtWidgets.QPushButton(formAxisSettings) self.btnClose.setObjectName("btnClose") @@ -439,7 +365,7 @@ def setupUi(self, formAxisSettings): self.lneCaptureOn.returnPressed.connect(formAxisSettings.sendCaptureOn) self.lneCaptureFlag.returnPressed.connect(formAxisSettings.sendCaptureFlag) self.lneOutputMode.returnPressed.connect(formAxisSettings.sendOutputMode) - self.tabAxisSetup.currentChanged["int"].connect(formAxisSettings.tabChange) + self.tabAxisSetup.currentChanged['int'].connect(formAxisSettings.tabChange) QtCore.QMetaObject.connectSlotsByName(formAxisSettings) formAxisSettings.setTabOrder(self.lneIx11, self.lneIx12) formAxisSettings.setTabOrder(self.lneIx12, self.lneIx13) @@ -461,17 +387,10 @@ def setupUi(self, formAxisSettings): def retranslateUi(self, formAxisSettings): _translate = QtCore.QCoreApplication.translate formAxisSettings.setWindowTitle(_translate("formAxisSettings", "Axis setup")) - self.textLabel1.setText( - _translate( - "formAxisSettings", - "Note this screen does not update continously.\n" - "Hit the update button to read out the current values from pmac.\n" - "Write demand values in the text fields and hit enter to send.", - ) - ) - self.groupBox1.setTitle( - _translate("formAxisSettings", "Definition I variables") - ) + self.textLabel1.setText(_translate("formAxisSettings", "Note this screen does not update continuously.\n" +"Hit the update button to read out the current values from pmac.\n" +"Write demand values in the text fields and hit enter to send.")) + self.groupBox1.setTitle(_translate("formAxisSettings", "Definition I variables")) self.textLabel2.setText(_translate("formAxisSettings", "Ix11:")) self.textLabel2_2.setText(_translate("formAxisSettings", "Ix12:")) self.textLabel2_3.setText(_translate("formAxisSettings", "Ix13:")) @@ -488,13 +407,8 @@ def retranslateUi(self, formAxisSettings): self.textLabel2_5_2.setText(_translate("formAxisSettings", "Ix24")) self.textLabel2_6_2.setText(_translate("formAxisSettings", "Ix25")) self.textLabel2_7_2.setText(_translate("formAxisSettings", "Ix26")) - self.tabAxisSetup.setTabText( - self.tabAxisSetup.indexOf(self.tab), - _translate("formAxisSettings", "definition and safety"), - ) - self.groupBox1_2.setTitle( - _translate("formAxisSettings", "PID tuning variables") - ) + self.tabAxisSetup.setTabText(self.tabAxisSetup.indexOf(self.tab), _translate("formAxisSettings", "definition and safety")) + self.groupBox1_2.setTitle(_translate("formAxisSettings", "PID tuning variables")) self.textLabel2_10.setText(_translate("formAxisSettings", "ix30:")) self.textLabel2_2_3.setText(_translate("formAxisSettings", "Ix31:")) self.textLabel2_3_3.setText(_translate("formAxisSettings", "Ix32:")) @@ -507,9 +421,8 @@ def retranslateUi(self, formAxisSettings): self.lCaptureOn.setText(_translate("formAxisSettings", "capture on:")) self.lCaptureFlag.setText(_translate("formAxisSettings", "capture flag:")) self.lOutputMode.setText(_translate("formAxisSettings", "output mode:")) - self.tabAxisSetup.setTabText( - self.tabAxisSetup.indexOf(self.tab1), - _translate("formAxisSettings", "PID and macro"), - ) + self.tabAxisSetup.setTabText(self.tabAxisSetup.indexOf(self.tab1), _translate("formAxisSettings", "PID and macro")) self.btnUpdate.setText(_translate("formAxisSettings", "update")) self.btnClose.setText(_translate("formAxisSettings", "close")) + + diff --git a/src/dls_pmaccontrol/ui_formPpmacAxisSettings.py b/src/dls_pmaccontrol/ui_formPpmacAxisSettings.py index f5b3f13..ff1ca51 100644 --- a/src/dls_pmaccontrol/ui_formPpmacAxisSettings.py +++ b/src/dls_pmaccontrol/ui_formPpmacAxisSettings.py @@ -2,11 +2,9 @@ # Form implementation generated from reading ui file 'dls_pmaccontrol/formPpmacAxisSettings.ui' # -# Created by: PyQt5 UI code generator 5.15.4 +# Created by: PyQt5 UI code generator 5.12.2 # -# WARNING: Any manual changes made to this file will be lost when pyuic5 is -# run again. Do not edit this file unless you know what you are doing. - +# WARNING! All changes made in this file will be lost! from PyQt5 import QtCore, QtGui, QtWidgets @@ -15,14 +13,10 @@ class Ui_formPpmacAxisSettings(object): def setupUi(self, formPpmacAxisSettings): formPpmacAxisSettings.setObjectName("formPpmacAxisSettings") formPpmacAxisSettings.resize(580, 688) - sizePolicy = QtWidgets.QSizePolicy( - QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed - ) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth( - formPpmacAxisSettings.sizePolicy().hasHeightForWidth() - ) + sizePolicy.setHeightForWidth(formPpmacAxisSettings.sizePolicy().hasHeightForWidth()) formPpmacAxisSettings.setSizePolicy(sizePolicy) formPpmacAxisSettings.setMaximumSize(QtCore.QSize(1024, 768)) self.gridLayout_3 = QtWidgets.QGridLayout(formPpmacAxisSettings) @@ -36,9 +30,7 @@ def setupUi(self, formPpmacAxisSettings): self.textLabel1.setWordWrap(False) self.textLabel1.setObjectName("textLabel1") self.gridLayout_3.addWidget(self.textLabel1, 0, 0, 1, 3) - spacerItem = QtWidgets.QSpacerItem( - 185, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum - ) + spacerItem = QtWidgets.QSpacerItem(185, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) self.gridLayout_3.addItem(spacerItem, 2, 1, 1, 1) self.btnClose = QtWidgets.QPushButton(formPpmacAxisSettings) self.btnClose.setObjectName("btnClose") @@ -65,37 +57,25 @@ def setupUi(self, formPpmacAxisSettings): self.textLabel2_2_2 = QtWidgets.QLabel(self.groupBox2) self.textLabel2_2_2.setWordWrap(False) self.textLabel2_2_2.setObjectName("textLabel2_2_2") - self.formLayout.setWidget( - 2, QtWidgets.QFormLayout.LabelRole, self.textLabel2_2_2 - ) + self.formLayout.setWidget(2, QtWidgets.QFormLayout.LabelRole, self.textLabel2_2_2) self.textLabel2_3_2 = QtWidgets.QLabel(self.groupBox2) self.textLabel2_3_2.setWordWrap(False) self.textLabel2_3_2.setObjectName("textLabel2_3_2") - self.formLayout.setWidget( - 4, QtWidgets.QFormLayout.LabelRole, self.textLabel2_3_2 - ) + self.formLayout.setWidget(4, QtWidgets.QFormLayout.LabelRole, self.textLabel2_3_2) self.textLabel2_4_2 = QtWidgets.QLabel(self.groupBox2) self.textLabel2_4_2.setWordWrap(False) self.textLabel2_4_2.setObjectName("textLabel2_4_2") - self.formLayout.setWidget( - 6, QtWidgets.QFormLayout.LabelRole, self.textLabel2_4_2 - ) + self.formLayout.setWidget(6, QtWidgets.QFormLayout.LabelRole, self.textLabel2_4_2) self.textLabel2_6_2 = QtWidgets.QLabel(self.groupBox2) self.textLabel2_6_2.setWordWrap(False) self.textLabel2_6_2.setObjectName("textLabel2_6_2") - self.formLayout.setWidget( - 8, QtWidgets.QFormLayout.LabelRole, self.textLabel2_6_2 - ) + self.formLayout.setWidget(8, QtWidgets.QFormLayout.LabelRole, self.textLabel2_6_2) self.textLabel2_7_2 = QtWidgets.QLabel(self.groupBox2) self.textLabel2_7_2.setWordWrap(False) self.textLabel2_7_2.setObjectName("textLabel2_7_2") - self.formLayout.setWidget( - 10, QtWidgets.QFormLayout.LabelRole, self.textLabel2_7_2 - ) + self.formLayout.setWidget(10, QtWidgets.QFormLayout.LabelRole, self.textLabel2_7_2) self.lneIx20 = QtWidgets.QLineEdit(self.groupBox2) - sizePolicy = QtWidgets.QSizePolicy( - QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed - ) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.lneIx20.sizePolicy().hasHeightForWidth()) @@ -163,21 +143,15 @@ def setupUi(self, formPpmacAxisSettings): self.textLabel2_2 = QtWidgets.QLabel(self.groupBox1) self.textLabel2_2.setWordWrap(False) self.textLabel2_2.setObjectName("textLabel2_2") - self.formLayout_2.setWidget( - 2, QtWidgets.QFormLayout.LabelRole, self.textLabel2_2 - ) + self.formLayout_2.setWidget(2, QtWidgets.QFormLayout.LabelRole, self.textLabel2_2) self.textLabel2_3 = QtWidgets.QLabel(self.groupBox1) self.textLabel2_3.setWordWrap(False) self.textLabel2_3.setObjectName("textLabel2_3") - self.formLayout_2.setWidget( - 4, QtWidgets.QFormLayout.LabelRole, self.textLabel2_3 - ) + self.formLayout_2.setWidget(4, QtWidgets.QFormLayout.LabelRole, self.textLabel2_3) self.textLabel2_4 = QtWidgets.QLabel(self.groupBox1) self.textLabel2_4.setWordWrap(False) self.textLabel2_4.setObjectName("textLabel2_4") - self.formLayout_2.setWidget( - 5, QtWidgets.QFormLayout.LabelRole, self.textLabel2_4 - ) + self.formLayout_2.setWidget(5, QtWidgets.QFormLayout.LabelRole, self.textLabel2_4) self.lneIx14 = QtWidgets.QLineEdit(self.groupBox1) self.lneIx14.setMinimumSize(QtCore.QSize(60, 0)) self.lneIx14.setMaximumSize(QtCore.QSize(31222, 32767)) @@ -186,15 +160,11 @@ def setupUi(self, formPpmacAxisSettings): self.textLabel2_5 = QtWidgets.QLabel(self.groupBox1) self.textLabel2_5.setWordWrap(False) self.textLabel2_5.setObjectName("textLabel2_5") - self.formLayout_2.setWidget( - 7, QtWidgets.QFormLayout.LabelRole, self.textLabel2_5 - ) + self.formLayout_2.setWidget(7, QtWidgets.QFormLayout.LabelRole, self.textLabel2_5) self.textLabel2_6 = QtWidgets.QLabel(self.groupBox1) self.textLabel2_6.setWordWrap(False) self.textLabel2_6.setObjectName("textLabel2_6") - self.formLayout_2.setWidget( - 8, QtWidgets.QFormLayout.LabelRole, self.textLabel2_6 - ) + self.formLayout_2.setWidget(8, QtWidgets.QFormLayout.LabelRole, self.textLabel2_6) self.lneIx16 = QtWidgets.QLineEdit(self.groupBox1) self.lneIx16.setMinimumSize(QtCore.QSize(60, 0)) self.lneIx16.setMaximumSize(QtCore.QSize(31222, 32767)) @@ -203,9 +173,7 @@ def setupUi(self, formPpmacAxisSettings): self.textLabel2_7 = QtWidgets.QLabel(self.groupBox1) self.textLabel2_7.setWordWrap(False) self.textLabel2_7.setObjectName("textLabel2_7") - self.formLayout_2.setWidget( - 9, QtWidgets.QFormLayout.LabelRole, self.textLabel2_7 - ) + self.formLayout_2.setWidget(9, QtWidgets.QFormLayout.LabelRole, self.textLabel2_7) self.lneIx17 = QtWidgets.QLineEdit(self.groupBox1) self.lneIx17.setMinimumSize(QtCore.QSize(60, 0)) self.lneIx17.setMaximumSize(QtCore.QSize(31222, 32767)) @@ -214,9 +182,7 @@ def setupUi(self, formPpmacAxisSettings): self.textLabel2_8 = QtWidgets.QLabel(self.groupBox1) self.textLabel2_8.setWordWrap(False) self.textLabel2_8.setObjectName("textLabel2_8") - self.formLayout_2.setWidget( - 10, QtWidgets.QFormLayout.LabelRole, self.textLabel2_8 - ) + self.formLayout_2.setWidget(10, QtWidgets.QFormLayout.LabelRole, self.textLabel2_8) self.lneIx19 = QtWidgets.QLineEdit(self.groupBox1) self.lneIx19.setMinimumSize(QtCore.QSize(60, 0)) self.lneIx19.setMaximumSize(QtCore.QSize(31222, 32767)) @@ -228,9 +194,7 @@ def setupUi(self, formPpmacAxisSettings): self.tab_2.setObjectName("tab_2") self.groupBox1_2 = QtWidgets.QGroupBox(self.tab_2) self.groupBox1_2.setGeometry(QtCore.QRect(10, 20, 271, 330)) - sizePolicy = QtWidgets.QSizePolicy( - QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed - ) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.groupBox1_2.sizePolicy().hasHeightForWidth()) @@ -243,9 +207,7 @@ def setupUi(self, formPpmacAxisSettings): self.textLabel2_10 = QtWidgets.QLabel(self.groupBox1_2) self.textLabel2_10.setWordWrap(False) self.textLabel2_10.setObjectName("textLabel2_10") - self.formLayout_3.setWidget( - 0, QtWidgets.QFormLayout.LabelRole, self.textLabel2_10 - ) + self.formLayout_3.setWidget(0, QtWidgets.QFormLayout.LabelRole, self.textLabel2_10) self.lneIx30 = QtWidgets.QLineEdit(self.groupBox1_2) self.lneIx30.setMinimumSize(QtCore.QSize(60, 0)) self.lneIx30.setMaximumSize(QtCore.QSize(32233, 32767)) @@ -254,9 +216,7 @@ def setupUi(self, formPpmacAxisSettings): self.textLabel2_2_3 = QtWidgets.QLabel(self.groupBox1_2) self.textLabel2_2_3.setWordWrap(False) self.textLabel2_2_3.setObjectName("textLabel2_2_3") - self.formLayout_3.setWidget( - 1, QtWidgets.QFormLayout.LabelRole, self.textLabel2_2_3 - ) + self.formLayout_3.setWidget(1, QtWidgets.QFormLayout.LabelRole, self.textLabel2_2_3) self.lneIx31 = QtWidgets.QLineEdit(self.groupBox1_2) self.lneIx31.setMinimumSize(QtCore.QSize(60, 0)) self.lneIx31.setMaximumSize(QtCore.QSize(32233, 32767)) @@ -265,22 +225,16 @@ def setupUi(self, formPpmacAxisSettings): self.textLabel2_3_3 = QtWidgets.QLabel(self.groupBox1_2) self.textLabel2_3_3.setWordWrap(False) self.textLabel2_3_3.setObjectName("textLabel2_3_3") - self.formLayout_3.setWidget( - 2, QtWidgets.QFormLayout.LabelRole, self.textLabel2_3_3 - ) + self.formLayout_3.setWidget(2, QtWidgets.QFormLayout.LabelRole, self.textLabel2_3_3) self.lneDerivative2 = QtWidgets.QLineEdit(self.groupBox1_2) self.lneDerivative2.setMinimumSize(QtCore.QSize(60, 0)) self.lneDerivative2.setMaximumSize(QtCore.QSize(32233, 32767)) self.lneDerivative2.setObjectName("lneDerivative2") - self.formLayout_3.setWidget( - 2, QtWidgets.QFormLayout.FieldRole, self.lneDerivative2 - ) + self.formLayout_3.setWidget(2, QtWidgets.QFormLayout.FieldRole, self.lneDerivative2) self.textLabel2_4_3 = QtWidgets.QLabel(self.groupBox1_2) self.textLabel2_4_3.setWordWrap(False) self.textLabel2_4_3.setObjectName("textLabel2_4_3") - self.formLayout_3.setWidget( - 3, QtWidgets.QFormLayout.LabelRole, self.textLabel2_4_3 - ) + self.formLayout_3.setWidget(3, QtWidgets.QFormLayout.LabelRole, self.textLabel2_4_3) self.lneIx33 = QtWidgets.QLineEdit(self.groupBox1_2) self.lneIx33.setMinimumSize(QtCore.QSize(60, 0)) self.lneIx33.setMaximumSize(QtCore.QSize(32233, 32767)) @@ -289,9 +243,7 @@ def setupUi(self, formPpmacAxisSettings): self.textLabel2_5_3 = QtWidgets.QLabel(self.groupBox1_2) self.textLabel2_5_3.setWordWrap(False) self.textLabel2_5_3.setObjectName("textLabel2_5_3") - self.formLayout_3.setWidget( - 4, QtWidgets.QFormLayout.LabelRole, self.textLabel2_5_3 - ) + self.formLayout_3.setWidget(4, QtWidgets.QFormLayout.LabelRole, self.textLabel2_5_3) self.lneIx32 = QtWidgets.QLineEdit(self.groupBox1_2) self.lneIx32.setMinimumSize(QtCore.QSize(60, 0)) self.lneIx32.setMaximumSize(QtCore.QSize(32233, 32767)) @@ -300,9 +252,7 @@ def setupUi(self, formPpmacAxisSettings): self.textLabel2_10_2 = QtWidgets.QLabel(self.groupBox1_2) self.textLabel2_10_2.setWordWrap(False) self.textLabel2_10_2.setObjectName("textLabel2_10_2") - self.formLayout_3.setWidget( - 5, QtWidgets.QFormLayout.LabelRole, self.textLabel2_10_2 - ) + self.formLayout_3.setWidget(5, QtWidgets.QFormLayout.LabelRole, self.textLabel2_10_2) self.lneVFF2 = QtWidgets.QLineEdit(self.groupBox1_2) self.lneVFF2.setMinimumSize(QtCore.QSize(60, 0)) self.lneVFF2.setMaximumSize(QtCore.QSize(32233, 32767)) @@ -311,9 +261,7 @@ def setupUi(self, formPpmacAxisSettings): self.textLabel2_10_2_2 = QtWidgets.QLabel(self.groupBox1_2) self.textLabel2_10_2_2.setWordWrap(False) self.textLabel2_10_2_2.setObjectName("textLabel2_10_2_2") - self.formLayout_3.setWidget( - 6, QtWidgets.QFormLayout.LabelRole, self.textLabel2_10_2_2 - ) + self.formLayout_3.setWidget(6, QtWidgets.QFormLayout.LabelRole, self.textLabel2_10_2_2) self.lneIx35 = QtWidgets.QLineEdit(self.groupBox1_2) self.lneIx35.setMinimumSize(QtCore.QSize(60, 0)) self.lneIx35.setMaximumSize(QtCore.QSize(32233, 32767)) @@ -321,37 +269,27 @@ def setupUi(self, formPpmacAxisSettings): self.formLayout_3.setWidget(6, QtWidgets.QFormLayout.FieldRole, self.lneIx35) self.groupBox1_2_2 = QtWidgets.QGroupBox(self.tab_2) self.groupBox1_2_2.setGeometry(QtCore.QRect(290, 20, 260, 81)) - sizePolicy = QtWidgets.QSizePolicy( - QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed - ) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth( - self.groupBox1_2_2.sizePolicy().hasHeightForWidth() - ) + sizePolicy.setHeightForWidth(self.groupBox1_2_2.sizePolicy().hasHeightForWidth()) self.groupBox1_2_2.setSizePolicy(sizePolicy) self.groupBox1_2_2.setObjectName("groupBox1_2_2") self.formLayout_4 = QtWidgets.QFormLayout(self.groupBox1_2_2) - self.formLayout_4.setFieldGrowthPolicy( - QtWidgets.QFormLayout.AllNonFixedFieldsGrow - ) + self.formLayout_4.setFieldGrowthPolicy(QtWidgets.QFormLayout.AllNonFixedFieldsGrow) self.formLayout_4.setContentsMargins(11, 11, 11, 11) self.formLayout_4.setSpacing(6) self.formLayout_4.setObjectName("formLayout_4") self.lLoopSelect = QtWidgets.QLabel(self.groupBox1_2_2) self.lLoopSelect.setWordWrap(False) self.lLoopSelect.setObjectName("lLoopSelect") - self.formLayout_4.setWidget( - 0, QtWidgets.QFormLayout.LabelRole, self.lLoopSelect - ) + self.formLayout_4.setWidget(0, QtWidgets.QFormLayout.LabelRole, self.lLoopSelect) self.lneIx34 = QtWidgets.QLineEdit(self.groupBox1_2_2) self.lneIx34.setMinimumSize(QtCore.QSize(60, 0)) self.lneIx34.setMaximumSize(QtCore.QSize(32222, 32767)) self.lneIx34.setObjectName("lneIx34") self.formLayout_4.setWidget(0, QtWidgets.QFormLayout.FieldRole, self.lneIx34) - spacerItem1 = QtWidgets.QSpacerItem( - 30, 0, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding - ) + spacerItem1 = QtWidgets.QSpacerItem(30, 0, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) self.formLayout_4.setItem(2, QtWidgets.QFormLayout.SpanningRole, spacerItem1) self.tabAxisSetup.addTab(self.tab_2, "") self.gridLayout_3.addWidget(self.tabAxisSetup, 1, 0, 1, 3) @@ -370,7 +308,7 @@ def setupUi(self, formPpmacAxisSettings): self.lneIx21.returnPressed.connect(formPpmacAxisSettings.sendIx21) self.lneIx22.returnPressed.connect(formPpmacAxisSettings.sendIx22) self.lneIx26.returnPressed.connect(formPpmacAxisSettings.sendIx26) - self.tabAxisSetup.currentChanged["int"].connect(formPpmacAxisSettings.tabChange) + self.tabAxisSetup.currentChanged['int'].connect(formPpmacAxisSettings.tabChange) self.lneIx11.returnPressed.connect(formPpmacAxisSettings.sendIx11) self.lneIx14.returnPressed.connect(formPpmacAxisSettings.sendIx14) self.lneIx25.returnPressed.connect(formPpmacAxisSettings.sendIx25) @@ -389,96 +327,39 @@ def setupUi(self, formPpmacAxisSettings): def retranslateUi(self, formPpmacAxisSettings): _translate = QtCore.QCoreApplication.translate - formPpmacAxisSettings.setWindowTitle( - _translate("formPpmacAxisSettings", "Axis setup") - ) + formPpmacAxisSettings.setWindowTitle(_translate("formPpmacAxisSettings", "Axis setup")) self.btnUpdate.setText(_translate("formPpmacAxisSettings", "update")) - self.textLabel1.setText( - _translate( - "formPpmacAxisSettings", - "Note this screen does not update continously.\n" - "Hit the update button to read out the current values from pmac.\n" - "Write demand values in the text fields and hit enter to send.", - ) - ) + self.textLabel1.setText(_translate("formPpmacAxisSettings", "Note this screen does not update continuously.\n" +"Hit the update button to read out the current values from pmac.\n" +"Write demand values in the text fields and hit enter to send.")) self.btnClose.setText(_translate("formPpmacAxisSettings", "close")) - self.groupBox2.setTitle( - _translate("formPpmacAxisSettings", "Safety I variables") - ) - self.textLabel2_9.setText( - _translate("formPpmacAxisSettings", "Motor[x].JogTa:") - ) - self.textLabel2_2_2.setText( - _translate("formPpmacAxisSettings", "Motor[x].JogTs:") - ) - self.textLabel2_3_2.setText( - _translate("formPpmacAxisSettings", "Motor[x].JogSpeed:") - ) - self.textLabel2_4_2.setText( - _translate("formPpmacAxisSettings", "Motor[x].HomeVel:") - ) - self.textLabel2_6_2.setText( - _translate("formPpmacAxisSettings", "Motor[x].pEncStatus:") - ) - self.textLabel2_7_2.setText( - _translate("formPpmacAxisSettings", "Motor[x].HomeOffset:") - ) - self.groupBox1.setTitle( - _translate("formPpmacAxisSettings", "Definition I variables") - ) - self.textLabel2.setText( - _translate("formPpmacAxisSettings", "Motor[x].FatalFeLimit:") - ) - self.textLabel2_2.setText( - _translate("formPpmacAxisSettings", "Motor[x].WarnFeLimit:") - ) - self.textLabel2_3.setText( - _translate("formPpmacAxisSettings", "Motor[x].MaxPos:") - ) - self.textLabel2_4.setText( - _translate("formPpmacAxisSettings", "Motor[x].MinPos:") - ) - self.textLabel2_5.setText( - _translate("formPpmacAxisSettings", "Motor[x].AbortTa:") - ) - self.textLabel2_6.setText( - _translate("formPpmacAxisSettings", "Motor[x].MaxSpeed:") - ) - self.textLabel2_7.setText( - _translate("formPpmacAxisSettings", "Motor[x].InvAmax:") - ) - self.textLabel2_8.setText( - _translate("formPpmacAxisSettings", "Motor[x].AbortTs:") - ) - self.tabAxisSetup.setTabText( - self.tabAxisSetup.indexOf(self.tab), - _translate("formPpmacAxisSettings", "definition and safety"), - ) + self.groupBox2.setTitle(_translate("formPpmacAxisSettings", "Safety I variables")) + self.textLabel2_9.setText(_translate("formPpmacAxisSettings", "Motor[x].JogTa:")) + self.textLabel2_2_2.setText(_translate("formPpmacAxisSettings", "Motor[x].JogTs:")) + self.textLabel2_3_2.setText(_translate("formPpmacAxisSettings", "Motor[x].JogSpeed:")) + self.textLabel2_4_2.setText(_translate("formPpmacAxisSettings", "Motor[x].HomeVel:")) + self.textLabel2_6_2.setText(_translate("formPpmacAxisSettings", "Motor[x].pEncStatus:")) + self.textLabel2_7_2.setText(_translate("formPpmacAxisSettings", "Motor[x].HomeOffset:")) + self.groupBox1.setTitle(_translate("formPpmacAxisSettings", "Definition I variables")) + self.textLabel2.setText(_translate("formPpmacAxisSettings", "Motor[x].FatalFeLimit:")) + self.textLabel2_2.setText(_translate("formPpmacAxisSettings", "Motor[x].WarnFeLimit:")) + self.textLabel2_3.setText(_translate("formPpmacAxisSettings", "Motor[x].MaxPos:")) + self.textLabel2_4.setText(_translate("formPpmacAxisSettings", "Motor[x].MinPos:")) + self.textLabel2_5.setText(_translate("formPpmacAxisSettings", "Motor[x].AbortTa:")) + self.textLabel2_6.setText(_translate("formPpmacAxisSettings", "Motor[x].MaxSpeed:")) + self.textLabel2_7.setText(_translate("formPpmacAxisSettings", "Motor[x].InvAmax:")) + self.textLabel2_8.setText(_translate("formPpmacAxisSettings", "Motor[x].AbortTs:")) + self.tabAxisSetup.setTabText(self.tabAxisSetup.indexOf(self.tab), _translate("formPpmacAxisSettings", "definition and safety")) self.groupBox1_2.setTitle(_translate("formPpmacAxisSettings", "Gains")) self.textLabel2_10.setText(_translate("formPpmacAxisSettings", "Proportional:")) - self.textLabel2_2_3.setText( - _translate("formPpmacAxisSettings", "Derivative 1:") - ) - self.textLabel2_3_3.setText( - _translate("formPpmacAxisSettings", "Derivative 2:") - ) + self.textLabel2_2_3.setText(_translate("formPpmacAxisSettings", "Derivative 1:")) + self.textLabel2_3_3.setText(_translate("formPpmacAxisSettings", "Derivative 2:")) self.textLabel2_4_3.setText(_translate("formPpmacAxisSettings", "Integral:")) - self.textLabel2_5_3.setText( - _translate("formPpmacAxisSettings", "Vel. Feedforward 1:") - ) - self.textLabel2_10_2.setText( - _translate("formPpmacAxisSettings", "Vel. Feedforward 2:") - ) - self.textLabel2_10_2_2.setText( - _translate("formPpmacAxisSettings", "Accel. Feedforward:") - ) - self.groupBox1_2_2.setTitle( - _translate("formPpmacAxisSettings", "Other Servo Settings") - ) - self.lLoopSelect.setText( - _translate("formPpmacAxisSettings", "Integrator Mode:") - ) - self.tabAxisSetup.setTabText( - self.tabAxisSetup.indexOf(self.tab_2), - _translate("formPpmacAxisSettings", "PID and macro"), - ) + self.textLabel2_5_3.setText(_translate("formPpmacAxisSettings", "Vel. Feedforward 1:")) + self.textLabel2_10_2.setText(_translate("formPpmacAxisSettings", "Vel. Feedforward 2:")) + self.textLabel2_10_2_2.setText(_translate("formPpmacAxisSettings", "Accel. Feedforward:")) + self.groupBox1_2_2.setTitle(_translate("formPpmacAxisSettings", "Other Servo Settings")) + self.lLoopSelect.setText(_translate("formPpmacAxisSettings", "Integrator Mode:")) + self.tabAxisSetup.setTabText(self.tabAxisSetup.indexOf(self.tab_2), _translate("formPpmacAxisSettings", "PID and macro")) + + From 0007e70b90519d0d2e4aa679a116ce3ebd07119f Mon Sep 17 00:00:00 2001 From: James O'Hea Date: Wed, 9 Aug 2023 16:44:05 +0100 Subject: [PATCH 08/36] The ?PVF check applies for all configured axes, but amplifier status checks only apply to the 8 axes of a brick. Use padding requests so that all request chunks have the same length --- src/dls_pmaccontrol/commsThread.py | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/src/dls_pmaccontrol/commsThread.py b/src/dls_pmaccontrol/commsThread.py index ac4722a..e3b36d7 100644 --- a/src/dls_pmaccontrol/commsThread.py +++ b/src/dls_pmaccontrol/commsThread.py @@ -153,13 +153,19 @@ def updateFunc(self): # Add the 7 segment display status query cmd = "i65???&%s??%%m%s90" % (self.CSNum, self.CSNum) axes = self.parent.pmac.getNumberOfAxes() + 1 - if isinstance(self.parent.pmac, PPmacSshInterface): - # Number of axes is hard-coded for now until axes vs channels issue is resolved - for motorNo in range(0, 8): - cmd = cmd + "#" + str(motorNo) + "?PVF BrickLV.Chan[" + str(motorNo) + "].I2tFaultStatus BrickLV.Chan[" + str(motorNo) + "].OverCurrent" - else: - for motorNo in range(1, 9): - cmd = cmd + "#" + str(motorNo) + "?PVFm" + str(motorNo) + "90" + for motorNo in range(1, axes): + cmd = cmd + "#" + str(motorNo) + "?PVF " + # Amplifier status checks only apply to the first 8 axes + if motorNo < 9: + if isinstance(self.parent.pmac, PPmacSshInterface): + # PowerBrick channels are zero-indexed + cmd = cmd + "BrickLV.Chan[" + str(motorNo - 1) + "].I2tFaultStatus BrickLV.Chan[" + str(motorNo - 1) + "].OverCurrent" + else: + # Add a dummy request to keep the request chunks the same length + cmd = cmd + "m" + str(motorNo) + "90 p70" + else: + # Use two dummy requests to keep the request chunks the same length + cmd = cmd + "p80 p81" # send polling command (retStr, wasSuccessful) = self.parent.pmac.sendCommand(cmd) From bf3fc32061cc5104e983a67d38715c184c575afd Mon Sep 17 00:00:00 2001 From: James O'Hea Date: Wed, 9 Aug 2023 16:46:02 +0100 Subject: [PATCH 09/36] Add zeroes as padding to the reponses to ensure the special requests are the same chunk size as axis requests --- src/dls_pmaccontrol/commsThread.py | 32 ++++++++++++++---------------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/src/dls_pmaccontrol/commsThread.py b/src/dls_pmaccontrol/commsThread.py index e3b36d7..6aec710 100644 --- a/src/dls_pmaccontrol/commsThread.py +++ b/src/dls_pmaccontrol/commsThread.py @@ -200,32 +200,30 @@ def updateFunc(self): print("Received malformed response to poll request: ", valueList) return - self.resultQueue.put([valueList[0], 0, 0, 0, "IDENT"]) - # first value is global status - self.resultQueue.put([valueList[1], 0, 0, 0, "G"]) - # second value is the CS - self.resultQueue.put([valueList[2], 0, 0, 0, "CS%s" % self.CSNum]) - # third is feedrate - self.resultQueue.put([valueList[3], 0, 0, 0, "FEED%s" % self.CSNum]) + # Identifier i65 + self.resultQueue.put([valueList[0], 0, 0, 0, 0, 0, "IDENT"]) + # Global status + self.resultQueue.put([valueList[1], 0, 0, 0, 0, 0, "G"]) + # CS status + self.resultQueue.put([valueList[2], 0, 0, 0, 0, 0, "CS%s" % self.CSNum]) + # Fedrate + self.resultQueue.put([valueList[3], 0, 0, 0, 0, 0, "FEED%s" % self.CSNum]) if isinstance(self.parent.pmac, PmacEthernetInterface): - # fourth is 7 segment display status - self.resultQueue.put([valueList[4], 0, 0, 0, "M90%s" % self.CSNum]) + # 7 segment display status + self.resultQueue.put([valueList[4], 0, 0, 0, 0, 0, "M90%s" % self.CSNum]) valueList = valueList[5:] elif isinstance(self.parent.pmac, PPmacSshInterface): # Brick Under Voltage Status - self.resultQueue.put([valueList[4], 0, 0, 0, "UVOL"]) + self.resultQueue.put([valueList[4], 0, 0, 0, 0, 0, "UVOL"]) # Brick Over Voltage Status - self.resultQueue.put([valueList[5], 0, 0, 0, "OVOL"]) + self.resultQueue.put([valueList[5], 0, 0, 0, 0, 0, "OVOL"]) # Brick Over Temperature Status - self.resultQueue.put([valueList[6], 0, 0, 0, "OTEMP"]) + self.resultQueue.put([valueList[6], 0, 0, 0, 0, 0, "OTEMP"]) valueList = valueList[7:] else: valueList = valueList[4:] - if isinstance(self.parent.pmac, PPmacSshInterface): - cols = 6 - else: - cols = 5 - + # All request chunks contain 7 elements + cols = 6 for motorRow, i in enumerate(range(0, len(valueList), cols)): returnList = valueList[i : i + cols] returnList.append(motorRow) From 5ffd924287804d0c94c99c5f5c49e179fc96526e Mon Sep 17 00:00:00 2001 From: James O'Hea Date: Wed, 9 Aug 2023 16:49:30 +0100 Subject: [PATCH 10/36] Add brick status indicators to main GUI (see ticket BC-1450) --- src/dls_pmaccontrol/formControl.ui | 130 +++++++++++++++++++++----- src/dls_pmaccontrol/ui_formControl.py | 67 ++++++++++--- 2 files changed, 157 insertions(+), 40 deletions(-) diff --git a/src/dls_pmaccontrol/formControl.ui b/src/dls_pmaccontrol/formControl.ui index 84dd7b1..612a8df 100644 --- a/src/dls_pmaccontrol/formControl.ui +++ b/src/dls_pmaccontrol/formControl.ui @@ -722,32 +722,10 @@ - - - - - 0 - 0 - - - - QFrame::Box - - - QFrame::Sunken - - - Test - - - false - - -
- + @@ -775,7 +753,7 @@ - + @@ -977,7 +955,7 @@ - + @@ -1111,6 +1089,7 @@ p, li { white-space: pre-wrap; } <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:10pt;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;"><br /></span></p> @@ -1126,6 +1105,107 @@ p, li { white-space: pre-wrap; } + + + + 10 + + + + + + 0 + 0 + + + + QFrame::Box + + + QFrame::Sunken + + + Test + + + false + + + + + + + + 25 + 25 + + + + greenLedOff.png + + + false + + + + + + + Under Voltage + + + true + + + + + + + + 25 + 25 + + + + greenLedOff.png + + + false + + + + + + + Over Voltage + + + + + + + + 25 + 25 + + + + greenLedOff.png + + + false + + + + + + + Over Temperature + + + + + diff --git a/src/dls_pmaccontrol/ui_formControl.py b/src/dls_pmaccontrol/ui_formControl.py index 6622508..eb4b2c3 100644 --- a/src/dls_pmaccontrol/ui_formControl.py +++ b/src/dls_pmaccontrol/ui_formControl.py @@ -323,17 +323,6 @@ def setupUi(self, ControlForm): self.btnDisconnect.setObjectName("btnDisconnect") self.hboxlayout.addWidget(self.btnDisconnect) self.verticalLayout.addLayout(self.hboxlayout) - self.lblIdentity = QtWidgets.QLabel(self.groupBox1) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Preferred) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.lblIdentity.sizePolicy().hasHeightForWidth()) - self.lblIdentity.setSizePolicy(sizePolicy) - self.lblIdentity.setFrameShape(QtWidgets.QFrame.Box) - self.lblIdentity.setFrameShadow(QtWidgets.QFrame.Sunken) - self.lblIdentity.setWordWrap(False) - self.lblIdentity.setObjectName("lblIdentity") - self.verticalLayout.addWidget(self.lblIdentity) self.gridLayout_2.addWidget(self.groupBox1, 0, 0, 1, 1) self.hboxlayout1 = QtWidgets.QHBoxLayout() self.hboxlayout1.setSpacing(6) @@ -349,7 +338,7 @@ def setupUi(self, ControlForm): self.chkShowAll = QtWidgets.QCheckBox(self.widget) self.chkShowAll.setObjectName("chkShowAll") self.hboxlayout1.addWidget(self.chkShowAll) - self.gridLayout_2.addLayout(self.hboxlayout1, 4, 0, 1, 2) + self.gridLayout_2.addLayout(self.hboxlayout1, 7, 0, 1, 2) self.frame3 = QtWidgets.QFrame(self.widget) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed) sizePolicy.setHorizontalStretch(0) @@ -432,7 +421,7 @@ def setupUi(self, ControlForm): self.btnWatches.setEnabled(False) self.btnWatches.setObjectName("btnWatches") self.gridLayout_4.addWidget(self.btnWatches, 2, 4, 1, 1) - self.gridLayout_2.addWidget(self.frame3, 2, 0, 1, 2) + self.gridLayout_2.addWidget(self.frame3, 5, 0, 1, 2) self.splitter = QtWidgets.QSplitter(self.widget) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Expanding) sizePolicy.setHorizontalStretch(0) @@ -493,7 +482,51 @@ def setupUi(self, ControlForm): self.txtShell.setFont(font) self.txtShell.setReadOnly(True) self.txtShell.setObjectName("txtShell") - self.gridLayout_2.addWidget(self.splitter, 3, 0, 1, 2) + self.gridLayout_2.addWidget(self.splitter, 6, 0, 1, 2) + self.horizontalLayout_6 = QtWidgets.QHBoxLayout() + self.horizontalLayout_6.setContentsMargins(-1, -1, -1, 10) + self.horizontalLayout_6.setSpacing(6) + self.horizontalLayout_6.setObjectName("horizontalLayout_6") + self.lblIdentity = QtWidgets.QLabel(self.widget) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.Preferred) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.lblIdentity.sizePolicy().hasHeightForWidth()) + self.lblIdentity.setSizePolicy(sizePolicy) + self.lblIdentity.setFrameShape(QtWidgets.QFrame.Box) + self.lblIdentity.setFrameShadow(QtWidgets.QFrame.Sunken) + self.lblIdentity.setWordWrap(False) + self.lblIdentity.setObjectName("lblIdentity") + self.horizontalLayout_6.addWidget(self.lblIdentity) + self.pixUnderVoltage = QtWidgets.QLabel(self.widget) + self.pixUnderVoltage.setMaximumSize(QtCore.QSize(25, 25)) + self.pixUnderVoltage.setPixmap(QtGui.QPixmap("greenLedOff.png")) + self.pixUnderVoltage.setWordWrap(False) + self.pixUnderVoltage.setObjectName("pixUnderVoltage") + self.horizontalLayout_6.addWidget(self.pixUnderVoltage) + self.lblUnderVoltage = QtWidgets.QLabel(self.widget) + self.lblUnderVoltage.setWordWrap(True) + self.lblUnderVoltage.setObjectName("lblUnderVoltage") + self.horizontalLayout_6.addWidget(self.lblUnderVoltage) + self.pixOverVoltage = QtWidgets.QLabel(self.widget) + self.pixOverVoltage.setMaximumSize(QtCore.QSize(25, 25)) + self.pixOverVoltage.setPixmap(QtGui.QPixmap("greenLedOff.png")) + self.pixOverVoltage.setWordWrap(False) + self.pixOverVoltage.setObjectName("pixOverVoltage") + self.horizontalLayout_6.addWidget(self.pixOverVoltage) + self.lblOverVoltage = QtWidgets.QLabel(self.widget) + self.lblOverVoltage.setObjectName("lblOverVoltage") + self.horizontalLayout_6.addWidget(self.lblOverVoltage) + self.pixOverTemperature = QtWidgets.QLabel(self.widget) + self.pixOverTemperature.setMaximumSize(QtCore.QSize(25, 25)) + self.pixOverTemperature.setPixmap(QtGui.QPixmap("greenLedOff.png")) + self.pixOverTemperature.setWordWrap(False) + self.pixOverTemperature.setObjectName("pixOverTemperature") + self.horizontalLayout_6.addWidget(self.pixOverTemperature) + self.lblOverTemperature = QtWidgets.QLabel(self.widget) + self.lblOverTemperature.setObjectName("lblOverTemperature") + self.horizontalLayout_6.addWidget(self.lblOverTemperature) + self.gridLayout_2.addLayout(self.horizontalLayout_6, 3, 0, 1, 2) ControlForm.setCentralWidget(self.widget) self.retranslateUi(ControlForm) @@ -600,7 +633,6 @@ def retranslateUi(self, ControlForm): self.textLabel2.setText(_translate("ControlForm", "port:")) self.btnConnect.setText(_translate("ControlForm", "connect")) self.btnDisconnect.setText(_translate("ControlForm", "disconnect")) - self.lblIdentity.setText(_translate("ControlForm", "Test")) self.btnSend.setText(_translate("ControlForm", "send")) self.chkShowAll.setText(_translate("ControlForm", "show all commands sent")) self.btnEnergise.setText(_translate("ControlForm", "energise...")) @@ -641,6 +673,7 @@ def retranslateUi(self, ControlForm): "


\n" "


\n" "


\n" +"


\n" "


\n" "


\n" "


\n" @@ -652,5 +685,9 @@ def retranslateUi(self, ControlForm): "


\n" "


\n" "


")) + self.lblIdentity.setText(_translate("ControlForm", "Test")) + self.lblUnderVoltage.setText(_translate("ControlForm", "Under Voltage")) + self.lblOverVoltage.setText(_translate("ControlForm", "Over Voltage")) + self.lblOverTemperature.setText(_translate("ControlForm", "Over Temperature")) From 84f00e32dae88a9b9f61368a3e80539644749be8 Mon Sep 17 00:00:00 2001 From: James O'Hea Date: Wed, 9 Aug 2023 16:51:16 +0100 Subject: [PATCH 11/36] Add flags for brick status. All responses are now the same length (see ticket BC-1450) --- src/dls_pmaccontrol/motor.py | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/dls_pmaccontrol/motor.py b/src/dls_pmaccontrol/motor.py index 9e2358e..ba1b064 100755 --- a/src/dls_pmaccontrol/motor.py +++ b/src/dls_pmaccontrol/motor.py @@ -633,6 +633,10 @@ def addToTxtShell(self, command, retStr=None, chkShowAll=True): # and the jog ribbon. def updateMotors(self): + under_voltage = False + over_voltage = False + over_temperature = False + self.commsThread.resultQueue.qsize() for queItem in range(0, self.commsThread.resultQueue.qsize()): try: @@ -641,10 +645,7 @@ def updateMotors(self): return try: - if isinstance(self.pmac, PPmacSshInterface): - motorRow = value[6] - else: - motorRow = value[5] + motorRow = value[6] # check for special cases if type(motorRow) == str: if isinstance(self.pmac, PPmacSshInterface): @@ -668,15 +669,15 @@ def updateMotors(self): continue if motorRow == "UVOL": if int(value[0]) != 0: - print("Under voltage!", str(value[0])) + under_voltage = True continue if motorRow == "OVOL": if int(value[0]) != 0: - print("Over voltage!", str(value[0])) + over_voltage = True continue if motorRow == "OTEMP": if int(value[0]) != 0: - print("Over temperature!", str(value[0])) + over_temperature = True continue else: if motorRow == "G": From 574e939bea9c4aa3af6f89c8dc2c2e1918c63cd8 Mon Sep 17 00:00:00 2001 From: James O'Hea Date: Wed, 9 Aug 2023 16:53:37 +0100 Subject: [PATCH 12/36] Update the GUI based on the amplifier status bits. Amplifier states can only be read from the first 8 axes, and the brick status can only be read from the first 4 axes of a Turbo PMAC (see ticket BC-1450) --- src/dls_pmaccontrol/motor.py | 179 +++++++++++++++++++---------------- 1 file changed, 97 insertions(+), 82 deletions(-) diff --git a/src/dls_pmaccontrol/motor.py b/src/dls_pmaccontrol/motor.py index ba1b064..c7f202c 100755 --- a/src/dls_pmaccontrol/motor.py +++ b/src/dls_pmaccontrol/motor.py @@ -696,97 +696,112 @@ def updateMotors(self): self.CSStatusScreen.updateAmpStatus(int(value[0]) & 448) continue - position = str(round(float(value[1]), 1)) - velocity = str(round(float(value[2]), 1)) - folerr = str(round(float(value[3]), 1)) - - i2t_fault = False - under_voltage = False - over_voltage = False - over_current = False - over_temperature = False - - if isinstance(self.pmac, PPmacSshInterface): - if int(value[4]) > 0: - i2t_fault = True - if int(value[5]) > 0: - over_current = True - elif isinstance(self.pmac, PmacEthernetInterface): - amp_status = ((int(value[4])&448)>>6) - if amp_status == 2: - under_voltage = True - elif amp_status == 3: - over_temperature = True - elif amp_status == 4: - over_voltage = True - elif amp_status == 5: - i2t_fault = True - elif amp_status == 6: - over_current = True - - self.__item(motorRow, 0).setText(position) - self.__item(motorRow, 1).setText(velocity) - self.__item(motorRow, 2).setText(folerr) - - statusWord = int(value[0].strip("$"), 16) - - # define high and low limits for power pmac - if isinstance(self.pmac, PPmacSshInterface): - loLim = bool(statusWord & 0x2000000000000000) # MinusLimit - hiLim = bool(statusWord & 0x1000000000000000) # PlusLimit - loLimSoft = bool(statusWord & 0x0080000000000000) # SoftMinusLimit - hiLimSoft = bool(statusWord & 0x0040000000000000) # SoftPlusLimit - - # define high and low limits for pmac else: - loLim = bool(statusWord & 0x400000000000) # negative end limit set - hiLim = bool(statusWord & 0x200000000000) # positive end limit set - loLimSoft = False - hiLimSoft = False - - # set limit indicators in polling table - if hiLim: - self.__item(motorRow, 3).setIcon(QIcon(self.redLedOn)) - elif hiLimSoft: - self.__item(motorRow, 3).setIcon(QIcon(self.amberLedOn)) - else: - self.__item(motorRow, 3).setIcon(QIcon(self.redLedOff)) - if loLim: - self.__item(motorRow, 4).setIcon(QIcon(self.redLedOn)) - elif loLimSoft: - self.__item(motorRow, 4).setIcon(QIcon(self.amberLedOn)) - else: - self.__item(motorRow, 4).setIcon(QIcon(self.redLedOff)) + position = str(round(float(value[1]), 1)) + velocity = str(round(float(value[2]), 1)) + folerr = str(round(float(value[3]), 1)) + + i2t_fault = False + over_current = False + + if motorRow < 8: + + if isinstance(self.pmac, PPmacSshInterface): + if int(value[4]) > 0: + i2t_fault = True + if int(value[5]) > 0: + over_current = True + elif isinstance(self.pmac, PmacEthernetInterface): + amp_status = ((int(value[4])&448)>>6) + if amp_status == 5: + i2t_fault = True + elif amp_status == 6: + over_current = True + if motorRow < 4: + if amp_status == 2: + under_voltage = True + elif amp_status == 3: + over_temperature = True + elif amp_status == 4: + over_voltage = True + + self.__item(motorRow, 0).setText(position) + self.__item(motorRow, 1).setText(velocity) + self.__item(motorRow, 2).setText(folerr) + + statusWord = int(value[0].strip("$"), 16) + + # define high and low limits for power pmac + if isinstance(self.pmac, PPmacSshInterface): + loLim = bool(statusWord & 0x2000000000000000) # MinusLimit + hiLim = bool(statusWord & 0x1000000000000000) # PlusLimit + loLimSoft = bool(statusWord & 0x0080000000000000) # SoftMinusLimit + hiLimSoft = bool(statusWord & 0x0040000000000000) # SoftPlusLimit - # set amplifier status indicators in polling table - if i2t_fault: - self.__item(motorRow, 5).setIcon(QIcon(self.redLedOn)) - else: - self.__item(motorRow, 5).setIcon(QIcon(self.redLedOff)) - if over_current: - self.__item(motorRow, 6).setIcon(QIcon(self.redLedOn)) - else: - self.__item(motorRow, 6).setIcon(QIcon(self.redLedOff)) + # define high and low limits for pmac + else: + loLim = bool(statusWord & 0x400000000000) # negative end limit set + hiLim = bool(statusWord & 0x200000000000) # positive end limit set + loLimSoft = False + hiLimSoft = False - # Update also the jog ribbon - if motorRow + 1 == self.currentMotor: - self.lblPosition.setText(position) - self.lblVelo.setText(velocity) - self.lblFolErr.setText(folerr) + # set limit indicators in polling table if hiLim: - self.pixHiLim.setPixmap(self.redLedOn) + self.__item(motorRow, 3).setIcon(QIcon(self.redLedOn)) elif hiLimSoft: - self.pixHiLim.setPixmap(self.amberLedOn) + self.__item(motorRow, 3).setIcon(QIcon(self.amberLedOn)) else: - self.pixHiLim.setPixmap(self.redLedOff) + self.__item(motorRow, 3).setIcon(QIcon(self.redLedOff)) if loLim: - self.pixLoLim.setPixmap(self.redLedOn) + self.__item(motorRow, 4).setIcon(QIcon(self.redLedOn)) elif loLimSoft: - self.pixLoLim.setPixmap(self.amberLedOn) + self.__item(motorRow, 4).setIcon(QIcon(self.amberLedOn)) else: - self.pixLoLim.setPixmap(self.redLedOff) - self.statusScreen.updateStatus(statusWord) - self.ppmacstatusScreen.updateStatus(statusWord) + self.__item(motorRow, 4).setIcon(QIcon(self.redLedOff)) + + # set amplifier status indicators in polling table + if i2t_fault: + self.__item(motorRow, 5).setIcon(QIcon(self.redLedOn)) + else: + self.__item(motorRow, 5).setIcon(QIcon(self.redLedOff)) + if over_current: + self.__item(motorRow, 6).setIcon(QIcon(self.redLedOn)) + else: + self.__item(motorRow, 6).setIcon(QIcon(self.redLedOff)) + + # Update also the jog ribbon + if motorRow + 1 == self.currentMotor: + self.lblPosition.setText(position) + self.lblVelo.setText(velocity) + self.lblFolErr.setText(folerr) + if hiLim: + self.pixHiLim.setPixmap(self.redLedOn) + elif hiLimSoft: + self.pixHiLim.setPixmap(self.amberLedOn) + else: + self.pixHiLim.setPixmap(self.redLedOff) + if loLim: + self.pixLoLim.setPixmap(self.redLedOn) + elif loLimSoft: + self.pixLoLim.setPixmap(self.amberLedOn) + else: + self.pixLoLim.setPixmap(self.redLedOff) + self.statusScreen.updateStatus(statusWord) + self.ppmacstatusScreen.updateStatus(statusWord) + + # set controller status indicators on main window + if under_voltage: + self.pixUnderVoltage.setPixmap(self.redLedOn) + else: + self.pixUnderVoltage.setPixmap(self.redLedOff) + if over_voltage: + self.pixOverVoltage.setPixmap(self.redLedOn) + else: + self.pixOverVoltage.setPixmap(self.redLedOff) + if over_temperature: + self.pixOverTemperature.setPixmap(self.redLedOn) + else: + self.pixOverTemperature.setPixmap(self.redLedOff) except (ValueError, IndexError): # Catch the exception and continue, since there may be other From eabb52f9bffdbf12da368c05f5399d661d5f6cda Mon Sep 17 00:00:00 2001 From: James O'Hea Date: Thu, 10 Aug 2023 09:04:45 +0100 Subject: [PATCH 13/36] Remove incorrect implementation of amplifier status check for Turbo PMAC (see ticket BC-1450) --- src/dls_pmaccontrol/commsThread.py | 9 +++------ src/dls_pmaccontrol/motor.py | 3 --- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/src/dls_pmaccontrol/commsThread.py b/src/dls_pmaccontrol/commsThread.py index 6aec710..b13f7c1 100644 --- a/src/dls_pmaccontrol/commsThread.py +++ b/src/dls_pmaccontrol/commsThread.py @@ -151,7 +151,7 @@ def updateFunc(self): cmd = "i65?&%s?%% BrickLV.BusUnderVoltage BrickLV.BusOverVoltage BrickLV.OverTemp" % self.CSNum elif isinstance(self.parent.pmac, PmacEthernetInterface): # Add the 7 segment display status query - cmd = "i65???&%s??%%m%s90" % (self.CSNum, self.CSNum) + cmd = "i65???&%s??%%" % self.CSNum axes = self.parent.pmac.getNumberOfAxes() + 1 for motorNo in range(1, axes): cmd = cmd + "#" + str(motorNo) + "?PVF " @@ -208,11 +208,8 @@ def updateFunc(self): self.resultQueue.put([valueList[2], 0, 0, 0, 0, 0, "CS%s" % self.CSNum]) # Fedrate self.resultQueue.put([valueList[3], 0, 0, 0, 0, 0, "FEED%s" % self.CSNum]) - if isinstance(self.parent.pmac, PmacEthernetInterface): - # 7 segment display status - self.resultQueue.put([valueList[4], 0, 0, 0, 0, 0, "M90%s" % self.CSNum]) - valueList = valueList[5:] - elif isinstance(self.parent.pmac, PPmacSshInterface): + + if isinstance(self.parent.pmac, PPmacSshInterface): # Brick Under Voltage Status self.resultQueue.put([valueList[4], 0, 0, 0, 0, 0, "UVOL"]) # Brick Over Voltage Status diff --git a/src/dls_pmaccontrol/motor.py b/src/dls_pmaccontrol/motor.py index c7f202c..aad6cff 100755 --- a/src/dls_pmaccontrol/motor.py +++ b/src/dls_pmaccontrol/motor.py @@ -692,9 +692,6 @@ def updateMotors(self): if motorRow == "IDENT": self.updateIdentity(int(value[0])) continue - if motorRow.startswith("M90"): - self.CSStatusScreen.updateAmpStatus(int(value[0]) & 448) - continue else: position = str(round(float(value[1]), 1)) From 83c7f0f9b9ac060a0a76e0b51f2d772949242a6f Mon Sep 17 00:00:00 2001 From: James O'Hea Date: Thu, 10 Aug 2023 09:07:57 +0100 Subject: [PATCH 14/36] Auto formatting of imports by vscode extensions --- src/dls_pmaccontrol/commsThread.py | 8 +++----- src/dls_pmaccontrol/motor.py | 30 +++++++++++------------------- 2 files changed, 14 insertions(+), 24 deletions(-) diff --git a/src/dls_pmaccontrol/commsThread.py b/src/dls_pmaccontrol/commsThread.py index b13f7c1..01c66dc 100644 --- a/src/dls_pmaccontrol/commsThread.py +++ b/src/dls_pmaccontrol/commsThread.py @@ -3,13 +3,11 @@ import traceback from queue import Empty, Queue -from dls_pmaclib.dls_pmacremote import ( - PmacEthernetInterface, - PmacSerialInterface, - PPmacSshInterface, -) from PyQt5.QtCore import QCoreApplication, QEvent +from dls_pmaclib.dls_pmacremote import (PmacEthernetInterface, + PmacSerialInterface, PPmacSshInterface) + class CustomEvent(QEvent): _data = None diff --git a/src/dls_pmaccontrol/motor.py b/src/dls_pmaccontrol/motor.py index aad6cff..ca5aba0 100755 --- a/src/dls_pmaccontrol/motor.py +++ b/src/dls_pmaccontrol/motor.py @@ -6,36 +6,28 @@ from os import path from queue import Empty -from dls_pmaclib.dls_pmacremote import ( - PmacEthernetInterface, - PmacSerialInterface, - PmacTelnetInterface, - PPmacSshInterface, -) -from dls_pmaclib.dls_pmcpreprocessor import ClsPmacParser from PyQt5.QtCore import QEvent, Qt, pyqtSlot from PyQt5.QtGui import QIcon, QPixmap -from PyQt5.QtWidgets import ( - QApplication, - QFileDialog, - QLineEdit, - QMainWindow, - QMessageBox, - QProgressDialog, - QTableWidgetItem, -) - -from dls_pmaccontrol.axissettings import Axissettingsform, PpmacAxissettingsform +from PyQt5.QtWidgets import (QApplication, QFileDialog, QLineEdit, QMainWindow, + QMessageBox, QProgressDialog, QTableWidgetItem) + +from dls_pmaccontrol.axissettings import (Axissettingsform, + PpmacAxissettingsform) from dls_pmaccontrol.commsThread import CommsThread from dls_pmaccontrol.CSstatus import CSStatusForm, PpmacCSStatusForm from dls_pmaccontrol.energise import Energiseform from dls_pmaccontrol.gather import PmacGatherform -from dls_pmaccontrol.GlobalStatus import GlobalStatusForm, PpmacGlobalStatusForm +from dls_pmaccontrol.GlobalStatus import (GlobalStatusForm, + PpmacGlobalStatusForm) from dls_pmaccontrol.login import Loginform from dls_pmaccontrol.ppmacgather import PpmacGatherform from dls_pmaccontrol.status import PpmacStatusform, Statusform from dls_pmaccontrol.ui_formControl import Ui_ControlForm from dls_pmaccontrol.watches import Watchesform +from dls_pmaclib.dls_pmacremote import (PmacEthernetInterface, + PmacSerialInterface, + PmacTelnetInterface, PPmacSshInterface) +from dls_pmaclib.dls_pmcpreprocessor import ClsPmacParser from . import __version__ From b290e809089745e86b8ed36cbd78e14e99ebdeec Mon Sep 17 00:00:00 2001 From: James O'Hea Date: Thu, 10 Aug 2023 10:21:44 +0100 Subject: [PATCH 15/36] Remove redundant 7 segment status from CS status screen and associated code (see ticket BC-1450) --- src/dls_pmaccontrol/CSstatus.py | 17 -------------- src/dls_pmaccontrol/formCSStatus.ui | 23 ------------------ src/dls_pmaccontrol/ui_formCSStatus.py | 32 +++++--------------------- 3 files changed, 6 insertions(+), 66 deletions(-) diff --git a/src/dls_pmaccontrol/CSstatus.py b/src/dls_pmaccontrol/CSstatus.py index 30d042b..4355f86 100755 --- a/src/dls_pmaccontrol/CSstatus.py +++ b/src/dls_pmaccontrol/CSstatus.py @@ -9,16 +9,6 @@ from dls_pmaccontrol.ui_formCSStatus import Ui_formCSStatus from dls_pmaccontrol.ui_formPpmacCSStatus import Ui_formPpmacCSStatus -AmpStatusBits = { - 0: "No Error, Not Ready", - 64: "No Error, Ready", - 128: "Bus Under-Voltage Warning", - 192: "Over-Temperature (>70°C)", - 256: "I\u00b2T Warning/Fault, Not Ready", - 320: "I\u00b2T Warning/Fault, Ready", - 384: "Over-Current Fault", -} - class CSStatusForm(QDialog, Ui_formCSStatus): def __init__(self, parent): @@ -600,13 +590,6 @@ def updateStatus(self, CSStatusHexWord): else: self.lstLeds[bit].setPixmap(self.greenLedOff) - def updateAmpStatus(self, value): - if value in AmpStatusBits: - strVal = AmpStatusBits[value] - else: - strVal = "Unknown status" - self.lneAmpStatus.setText(strVal) - class PpmacCSStatusForm(QDialog, Ui_formPpmacCSStatus): def __init__(self, parent): diff --git a/src/dls_pmaccontrol/formCSStatus.ui b/src/dls_pmaccontrol/formCSStatus.ui index 33bad84..3bb11a3 100644 --- a/src/dls_pmaccontrol/formCSStatus.ui +++ b/src/dls_pmaccontrol/formCSStatus.ui @@ -80,29 +80,6 @@
- - - - - - - Amp Status bits (7 Segment Display Status): - - - false - - - - - - - true - - - - - - diff --git a/src/dls_pmaccontrol/ui_formCSStatus.py b/src/dls_pmaccontrol/ui_formCSStatus.py index 401f0d8..c7317a3 100644 --- a/src/dls_pmaccontrol/ui_formCSStatus.py +++ b/src/dls_pmaccontrol/ui_formCSStatus.py @@ -1,12 +1,10 @@ # -*- coding: utf-8 -*- -# Form implementation generated from reading ui file 'dls_pmaccontrol/formCSStatus.ui' +# Form implementation generated from reading ui file 'src/dls_pmaccontrol/formCSStatus.ui' # -# Created by: PyQt5 UI code generator 5.15.4 +# Created by: PyQt5 UI code generator 5.12.2 # -# WARNING: Any manual changes made to this file will be lost when pyuic5 is -# run again. Do not edit this file unless you know what you are doing. - +# WARNING! All changes made in this file will be lost! from PyQt5 import QtCore, QtGui, QtWidgets @@ -46,9 +44,7 @@ def setupUi(self, formCSStatus): self.gridLayout.addWidget(self.csSpin, 0, 1, 1, 1) self.gridLayout_2.addWidget(self.ctrlGroup, 0, 0, 1, 1) self.ledGroup = QtWidgets.QGroupBox(formCSStatus) - sizePolicy = QtWidgets.QSizePolicy( - QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Expanding - ) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Expanding) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.ledGroup.sizePolicy().hasHeightForWidth()) @@ -59,21 +55,6 @@ def setupUi(self, formCSStatus): self.gridlayout.setSpacing(6) self.gridlayout.setObjectName("gridlayout") self.gridLayout_2.addWidget(self.ledGroup, 1, 0, 1, 1) - self.ctrlGroup1 = QtWidgets.QGroupBox(formCSStatus) - self.ctrlGroup1.setObjectName("ctrlGroup1") - self.gridLayout1 = QtWidgets.QGridLayout(self.ctrlGroup1) - self.gridLayout1.setContentsMargins(11, 11, 11, 11) - self.gridLayout1.setSpacing(6) - self.gridLayout1.setObjectName("gridLayout1") - self.textLabel1_21 = QtWidgets.QLabel(self.ctrlGroup1) - self.textLabel1_21.setWordWrap(False) - self.textLabel1_21.setObjectName("textLabel1_21") - self.gridLayout1.addWidget(self.textLabel1_21, 1, 0, 1, 1) - self.lneAmpStatus = QtWidgets.QLineEdit(self.ctrlGroup1) - self.lneAmpStatus.setReadOnly(True) - self.lneAmpStatus.setObjectName("lneAmpStatus") - self.gridLayout1.addWidget(self.lneAmpStatus, 1, 1, 1, 1) - self.gridLayout_2.addWidget(self.ctrlGroup1, 2, 0, 1, 1) self.retranslateUi(formCSStatus) QtCore.QMetaObject.connectSlotsByName(formCSStatus) @@ -85,6 +66,5 @@ def retranslateUi(self, formCSStatus): self.textLabel1.setText(_translate("formCSStatus", "CS Number:")) self.textLabel1_2.setText(_translate("formCSStatus", "Feed Rate:")) self.ledGroup.setTitle(_translate("formCSStatus", "CS Status")) - self.textLabel1_21.setText( - _translate("formCSStatus", "Amp Status bits (7 Segment Display Status):") - ) + + From 99294effb296f3d364bed7e65683b85001675cdf Mon Sep 17 00:00:00 2001 From: "O'Hea, James (DLSLtd,RAL,LSCI)" Date: Wed, 18 Oct 2023 10:45:14 +0000 Subject: [PATCH 16/36] setup.cfg: Try using pyqt5 == 5.12.2 instead of 5.12.2+dls1 From c611ca32283f2048404fbe0f80ea6d45c0d43659 Mon Sep 17 00:00:00 2001 From: "O'Hea, James (DLSLtd,RAL,LSCI)" Date: Wed, 18 Oct 2023 12:33:04 +0000 Subject: [PATCH 17/36] setup.cfg: Try using pyqt5 == 5.12.2 instead of 5.12.2+dls1 --- setup.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.cfg b/setup.cfg index 19dafaa..d6bb0f0 100644 --- a/setup.cfg +++ b/setup.cfg @@ -33,7 +33,7 @@ install_requires = # dls-pmaclib @ https://github.com/DiamondLightSource/dls-pmac-lib/archive/refs/tags/3.0.0.zip dls-pmaclib >= 3.0.1-beta1 numpy - pyqt5 == 5.12.2+dls1 + pyqt5 == 5.12.2 pythonqwt mock From 5aea5aa6b2e7128ae8cae7c2f05a9a65353682b2 Mon Sep 17 00:00:00 2001 From: James O'Hea Date: Tue, 16 Jan 2024 11:55:47 +0000 Subject: [PATCH 18/36] Add working launch.json --- .vscode/launch.json | 23 +++++++++-------------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/.vscode/launch.json b/.vscode/launch.json index f8fcdb4..8940e85 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -5,21 +5,16 @@ "version": "0.2.0", "configurations": [ { - "name": "Debug Unit Test", + "name": "dls_pmacontrol", "type": "python", "request": "launch", - "justMyCode": false, - "program": "${file}", - "purpose": [ - "debug-test" - ], - "console": "integratedTerminal", - "env": { - // The default config in setup.cfg's "[tool:pytest]" adds coverage. - // Cannot have coverage and debugging at the same time. - // https://github.com/microsoft/vscode-python/issues/693 - "PYTEST_ADDOPTS": "--no-cov" - }, - } + "module": "dls_pmaccontrol.motor", + "args": [ + "-v", + "--protocol=ssh", + "--server=172.23.59.7", + "--port=22", + ] + }, ] } \ No newline at end of file From d60ce8d951a817f720c7f103d6792b6de367a8cc Mon Sep 17 00:00:00 2001 From: James O'Hea Date: Tue, 16 Jan 2024 16:35:41 +0000 Subject: [PATCH 19/36] Use p99 as padding variable which should always return zero (see ticket BC-1450) --- src/dls_pmaccontrol/commsThread.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/dls_pmaccontrol/commsThread.py b/src/dls_pmaccontrol/commsThread.py index 01c66dc..f8e6153 100644 --- a/src/dls_pmaccontrol/commsThread.py +++ b/src/dls_pmaccontrol/commsThread.py @@ -159,11 +159,13 @@ def updateFunc(self): # PowerBrick channels are zero-indexed cmd = cmd + "BrickLV.Chan[" + str(motorNo - 1) + "].I2tFaultStatus BrickLV.Chan[" + str(motorNo - 1) + "].OverCurrent" else: - # Add a dummy request to keep the request chunks the same length - cmd = cmd + "m" + str(motorNo) + "90 p70" + # Add a dummy request to keep the request chunks + # the same length (p99 always returns zero) + cmd = cmd + "m" + str(motorNo) + "90 p99" else: - # Use two dummy requests to keep the request chunks the same length - cmd = cmd + "p80 p81" + # Use two dummy requests to keep the request chunks + # the same length (p99 always returns zero) + cmd = cmd + "p99 p99" # send polling command (retStr, wasSuccessful) = self.parent.pmac.sendCommand(cmd) From f22e9728f9b0f314d65d2f2fb9f81d1259c3adad Mon Sep 17 00:00:00 2001 From: Giles Knap Date: Sun, 11 Feb 2024 19:24:53 +0000 Subject: [PATCH 20/36] initial copier-template merge --- .copier-answers.yml | 15 +++ .devcontainer/devcontainer.json | 86 +++++------- .github/CONTRIBUTING.md | 27 ++++ .../actions/install_requirements/action.yml | 34 +++++ .github/dependabot.yml | 8 ++ .github/pages/make_switcher.py | 92 +++++++++++++ .github/workflows/_check.yml | 27 ++++ .github/workflows/_container.yml | 56 ++++++++ .github/workflows/_dist.yml | 36 +++++ .github/workflows/_docs.yml | 54 ++++++++ .github/workflows/_pypi.yml | 22 +++ .github/workflows/_release.yml | 32 +++++ .github/workflows/_test.yml | 62 +++++++++ .github/workflows/_tox.yml | 22 +++ .github/workflows/ci.yml | 68 ++++++++++ .github/workflows/periodic.yml | 13 ++ .gitignore | 6 +- .pre-commit-config.yaml | 18 +-- .vscode/extensions.json | 7 +- .vscode/launch.json | 17 ++- .vscode/settings.json | 15 +-- Dockerfile | 57 +++----- README.md | 20 +++ README.rst | 43 ------ catalog-info.yaml | 10 ++ docs/conf.py | 126 +++++++++++++----- docs/explanations.md | 10 ++ docs/explanations/decisions.md | 18 +++ .../0001-record-architecture-decisions.md | 18 +++ ...0002-switched-to-python-copier-template.md | 28 ++++ docs/genindex.md | 3 + docs/how-to.md | 10 ++ docs/how-to/contribute.md | 2 + docs/how-to/run-container.md | 14 ++ docs/index.md | 56 ++++++++ docs/reference.md | 11 ++ docs/reference/api.md | 17 +++ docs/tutorials.md | 10 ++ docs/tutorials/installation.md | 42 ++++++ pyproject.toml | 108 ++++++++++++++- src/dls_pmac_control/__init__.py | 3 + src/dls_pmac_control/__main__.py | 16 +++ tests/test_cli.py | 9 ++ 43 files changed, 1135 insertions(+), 213 deletions(-) create mode 100644 .copier-answers.yml create mode 100644 .github/CONTRIBUTING.md create mode 100644 .github/actions/install_requirements/action.yml create mode 100755 .github/pages/make_switcher.py create mode 100644 .github/workflows/_check.yml create mode 100644 .github/workflows/_container.yml create mode 100644 .github/workflows/_dist.yml create mode 100644 .github/workflows/_docs.yml create mode 100644 .github/workflows/_pypi.yml create mode 100644 .github/workflows/_release.yml create mode 100644 .github/workflows/_test.yml create mode 100644 .github/workflows/_tox.yml create mode 100644 .github/workflows/ci.yml create mode 100644 .github/workflows/periodic.yml create mode 100644 README.md delete mode 100644 README.rst create mode 100644 catalog-info.yaml create mode 100644 docs/explanations.md create mode 100644 docs/explanations/decisions.md create mode 100644 docs/explanations/decisions/0001-record-architecture-decisions.md create mode 100644 docs/explanations/decisions/0002-switched-to-python-copier-template.md create mode 100644 docs/genindex.md create mode 100644 docs/how-to.md create mode 100644 docs/how-to/contribute.md create mode 100644 docs/how-to/run-container.md create mode 100644 docs/index.md create mode 100644 docs/reference.md create mode 100644 docs/reference/api.md create mode 100644 docs/tutorials.md create mode 100644 docs/tutorials/installation.md create mode 100644 src/dls_pmac_control/__init__.py create mode 100644 src/dls_pmac_control/__main__.py create mode 100644 tests/test_cli.py diff --git a/.copier-answers.yml b/.copier-answers.yml new file mode 100644 index 0000000..863cf4b --- /dev/null +++ b/.copier-answers.yml @@ -0,0 +1,15 @@ +# Changes here will be overwritten by Copier +_commit: 1.0.2-87-g16b7b0e +_src_path: gh:DiamondLightSource/python-copier-template +author_email: giles.knap@diamond.ac.uk +author_name: Giles Knap +component_owner: group:default/sscc +description: GUI for low level control and monitoring of turbo pmac and power pmac + motion controllers +distribution_name: dls-pmac-control +docker: true +docs_type: sphinx +git_platform: github.com +github_org: DiamondLightSource +package_name: dls_pmac_control +repo_name: dls-pmac-control diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index af6666d..79b85ff 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -1,68 +1,46 @@ -// For format details, see https://aka.ms/devcontainer.json. For config options, see the README at: -// https://github.com/microsoft/vscode-dev-containers/tree/v0.231.6/containers/python-3 +// For format details, see https://containers.dev/implementors/json_reference/ { - "name": "Python 3", + "name": "Python 3 Developer Container", "build": { - "dockerfile": "Dockerfile", - "target": "developer", - "context": "..", - "args": {} + "dockerfile": "../Dockerfile", + "target": "developer" }, "remoteEnv": { + // Allow X11 apps to run inside the container "DISPLAY": "${localEnv:DISPLAY}" }, - // Set *default* container specific settings.json values on container create. - "settings": { - "python.defaultInterpreterPath": "/usr/local/bin/python", - "python.linting.enabled": true, - "python.linting.pylintEnabled": true, - "python.formatting.autopep8Path": "/usr/local/py-utils/bin/autopep8", - "python.formatting.blackPath": "/usr/local/py-utils/bin/black", - "python.formatting.yapfPath": "/usr/local/py-utils/bin/yapf", - "python.linting.banditPath": "/usr/local/py-utils/bin/bandit", - "python.linting.flake8Path": "/usr/local/py-utils/bin/flake8", - "python.linting.mypyPath": "/usr/local/py-utils/bin/mypy", - "python.linting.pycodestylePath": "/usr/local/py-utils/bin/pycodestyle", - "python.linting.pydocstylePath": "/usr/local/py-utils/bin/pydocstyle", - "python.linting.pylintPath": "/usr/local/py-utils/bin/pylint" + "customizations": { + "vscode": { + // Set *default* container specific settings.json values on container create. + "settings": { + "python.defaultInterpreterPath": "/venv/bin/python" + }, + // Add the IDs of extensions you want installed when the container is created. + "extensions": [ + "ms-python.python", + "github.vscode-github-actions", + "tamasfe.even-better-toml", + "redhat.vscode-yaml", + "ryanluker.vscode-coverage-gutters", + "charliermarsh.ruff", + "ms-azuretools.vscode-docker" + ] + } }, - // Add the IDs of extensions you want installed when the container is created. - "extensions": [ - "ms-python.python", - "ms-python.vscode-pylance", - "streetsidesoftware.code-spell-checker", - "ryanluker.vscode-coverage-gutters", - "mhutchie.git-graph", - "eamodio.gitlens", - "gruntfuggly.todo-tree", - "redhat.vscode-yaml", - "nsd.vscode-epics", - "alefragnani.bookmarks" - ], "features": { - //"docker-from-docker": "20.10", - "git": "os-provided" + // Some default things like git config + "ghcr.io/devcontainers/features/common-utils:2": { + "upgradePackages": false + } }, - // Use 'forwardPorts' to make a list of ports inside the container available locally. - // "forwardPorts": [], - // Comment out to connect as root instead. More info: https://aka.ms/vscode-remote/containers/non-root. - // "remoteUser": "vscode", - // Make sure the files we are mapping into the container exist on the host - "initializeCommand": "bash -c 'for i in $HOME/.inputrc $HOME/.bashrc_dev; do [ -f $i ] || touch $i; done'", "runArgs": [ - "--privileged", + // Allow the container to access the host X11 display and EPICS CA "--net=host", - "-v=${localEnv:HOME}/.ssh:/root/.ssh", - "-v=${localEnv:HOME}/.bashrc_dev:/root/.bashrc", - "-v=${localEnv:HOME}/.inputrc:/root/.inputrc" - ], - "mounts": [ - // map in home directory - not strictly necessary but may be useful - "source=${localEnv:HOME},target=${localEnv:HOME},type=bind,consistency=cached" + // Make sure SELinux does not disable with access to host filesystems like tmp + "--security-opt=label=disable" ], - "workspaceMount": "source=${localWorkspaceFolder},target=/workspace,type=bind", - "workspaceFolder": "/workspace", + // Mount the parent as /workspaces so we can pip install peers as editable + "workspaceMount": "source=${localWorkspaceFolder}/..,target=/workspaces,type=bind", // After the container is created, install the python project in editable form - // This installs into the system python of the container - "postCreateCommand": "pip install $([ -f requirements_dev.txt ] && echo -r requirements_dev.txt ) -e .[dev]" + "postCreateCommand": "pip install $([ -f dev-requirements.txt ] && echo '-c dev-requirements.txt') -e '.[dev]' && pre-commit install" } \ No newline at end of file diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md new file mode 100644 index 0000000..892c71e --- /dev/null +++ b/.github/CONTRIBUTING.md @@ -0,0 +1,27 @@ +# Contribute to the project + +Contributions and issues are most welcome! All issues and pull requests are +handled through [GitHub](https://github.com/DiamondLightSource/dls-pmac-control/issues). Also, please check for any existing issues before +filing a new one. If you have a great idea but it involves big changes, please +file a ticket before making a pull request! We want to make sure you don't spend +your time coding something that might not fit the scope of the project. + +## Issue or Discussion? + +Github also offers [discussions](https://github.com/DiamondLightSource/dls-pmac-control/discussions) as a place to ask questions and share ideas. If +your issue is open ended and it is not obvious when it can be "closed", please +raise it as a discussion instead. + +## Code Coverage + +While 100% code coverage does not make a library bug-free, it significantly +reduces the number of easily caught bugs! Please make sure coverage remains the +same or is improved by a pull request! + +## Developer Information + +It is recommended that developers use a [vscode devcontainer](https://code.visualstudio.com/docs/devcontainers/containers). This repository contains configuration to set up a containerized development environment that suits its own needs. + +This project was created using the [Diamond Light Source Copier Template](https://github.com/DiamondLightSource/python-copier-template) for Python projects. +The template's [Developer Guide](https://diamondlightsource.github.io/python-copier-template) contains detailed information on setting up a development environment, running the tests and what standards the code and documentation +should follow. diff --git a/.github/actions/install_requirements/action.yml b/.github/actions/install_requirements/action.yml new file mode 100644 index 0000000..d33e080 --- /dev/null +++ b/.github/actions/install_requirements/action.yml @@ -0,0 +1,34 @@ +name: Install requirements +description: Install a version of python then call pip install and report what was installed +inputs: + python-version: + description: Python version to install, default is from Dockerfile + default: "dev" + pip-install: + description: Parameters to pass to pip install + default: "$([ -f dev-requirements.txt ] && echo '-c dev-requirements.txt') -e .[dev]" + +runs: + using: composite + steps: + - name: Get version of python + run: | + PYTHON_VERSION="${{ inputs.python-version }}" + if [ $PYTHON_VERSION == "dev" ]; then + PYTHON_VERSION=$(sed -n "s/ARG PYTHON_VERSION=//p" Dockerfile) + fi + echo "PYTHON_VERSION=$PYTHON_VERSION" >> "$GITHUB_ENV" + shell: bash + + - name: Setup python + uses: actions/setup-python@v5 + with: + python-version: ${{ env.PYTHON_VERSION }} + + - name: Install packages + run: pip install ${{ inputs.pip-install }} + shell: bash + + - name: Report what was installed + run: pip freeze + shell: bash diff --git a/.github/dependabot.yml b/.github/dependabot.yml index fb7c6ee..184ba36 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -9,8 +9,16 @@ updates: directory: "/" schedule: interval: "weekly" + groups: + actions: + patterns: + - "*" - package-ecosystem: "pip" directory: "/" schedule: interval: "weekly" + groups: + dev-dependencies: + patterns: + - "*" diff --git a/.github/pages/make_switcher.py b/.github/pages/make_switcher.py new file mode 100755 index 0000000..e2c8e6f --- /dev/null +++ b/.github/pages/make_switcher.py @@ -0,0 +1,92 @@ +import json +import logging +from argparse import ArgumentParser +from pathlib import Path +from subprocess import CalledProcessError, check_output +from typing import List, Optional + + +def report_output(stdout: bytes, label: str) -> List[str]: + ret = stdout.decode().strip().split("\n") + print(f"{label}: {ret}") + return ret + + +def get_branch_contents(ref: str) -> List[str]: + """Get the list of directories in a branch.""" + stdout = check_output(["git", "ls-tree", "-d", "--name-only", ref]) + return report_output(stdout, "Branch contents") + + +def get_sorted_tags_list() -> List[str]: + """Get a list of sorted tags in descending order from the repository.""" + stdout = check_output(["git", "tag", "-l", "--sort=-v:refname"]) + return report_output(stdout, "Tags list") + + +def get_versions(ref: str, add: Optional[str]) -> List[str]: + """Generate the file containing the list of all GitHub Pages builds.""" + # Get the directories (i.e. builds) from the GitHub Pages branch + try: + builds = set(get_branch_contents(ref)) + except CalledProcessError: + builds = set() + logging.warning(f"Cannot get {ref} contents") + + # Add and remove from the list of builds + if add: + builds.add(add) + + # Get a sorted list of tags + tags = get_sorted_tags_list() + + # Make the sorted versions list from main branches and tags + versions: List[str] = [] + for version in ["master", "main"] + tags: + if version in builds: + versions.append(version) + builds.remove(version) + + # Add in anything that is left to the bottom + versions += sorted(builds) + print(f"Sorted versions: {versions}") + return versions + + +def write_json(path: Path, repository: str, versions: str): + org, repo_name = repository.split("/") + struct = [ + {"version": version, "url": f"https://{org}.github.io/{repo_name}/{version}/"} + for version in versions + ] + text = json.dumps(struct, indent=2) + print(f"JSON switcher:\n{text}") + path.write_text(text, encoding="utf-8") + + +def main(args=None): + parser = ArgumentParser( + description="Make a versions.json file from gh-pages directories" + ) + parser.add_argument( + "--add", + help="Add this directory to the list of existing directories", + ) + parser.add_argument( + "repository", + help="The GitHub org and repository name: ORG/REPO", + ) + parser.add_argument( + "output", + type=Path, + help="Path of write switcher.json to", + ) + args = parser.parse_args(args) + + # Write the versions file + versions = get_versions("origin/gh-pages", args.add) + write_json(args.output, args.repository, versions) + + +if __name__ == "__main__": + main() diff --git a/.github/workflows/_check.yml b/.github/workflows/_check.yml new file mode 100644 index 0000000..a6139c1 --- /dev/null +++ b/.github/workflows/_check.yml @@ -0,0 +1,27 @@ +on: + workflow_call: + outputs: + branch-pr: + description: The PR number if the branch is in one + value: ${{ jobs.pr.outputs.branch-pr }} + +jobs: + pr: + runs-on: "ubuntu-latest" + outputs: + branch-pr: ${{ steps.script.outputs.result }} + steps: + - uses: actions/github-script@v7 + id: script + if: github.event_name == 'push' + with: + script: | + const prs = await github.rest.pulls.list({ + owner: context.repo.owner, + repo: context.repo.repo, + head: context.repo.owner + ':${{ github.ref_name }}' + }) + if (prs.data.length) { + console.log(`::notice ::Skipping CI on branch push as it is already run in PR #${prs.data[0]["number"]}`) + return prs.data[0]["number"] + } diff --git a/.github/workflows/_container.yml b/.github/workflows/_container.yml new file mode 100644 index 0000000..4857ee9 --- /dev/null +++ b/.github/workflows/_container.yml @@ -0,0 +1,56 @@ +on: + workflow_call: + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + # Need this to get version number from last tag + fetch-depth: 0 + + - name: Set up Docker Buildx + id: buildx + uses: docker/setup-buildx-action@v3 + + - name: Log in to GitHub Docker Registry + if: github.event_name != 'pull_request' + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Build and export to Docker local cache + uses: docker/build-push-action@v5 + with: + context: . + # Need load and tags so we can test it below + load: true + tags: tag_for_testing + + - name: Test cli works in cached runtime image + run: docker run --rm tag_for_testing --version + + - name: Create tags for publishing image + id: meta + uses: docker/metadata-action@v5 + with: + images: ghcr.io/${{ github.repository }} + tags: | + type=ref,event=tag + type=raw,value=latest + + - name: Push cached image to container registry + if: github.ref_type == 'tag' + uses: docker/build-push-action@v5 + # This does not build the image again, it will find the image in the + # Docker cache and publish it + with: + context: . + push: true + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} diff --git a/.github/workflows/_dist.yml b/.github/workflows/_dist.yml new file mode 100644 index 0000000..b1c4c93 --- /dev/null +++ b/.github/workflows/_dist.yml @@ -0,0 +1,36 @@ +on: + workflow_call: + +jobs: + build: + runs-on: "ubuntu-latest" + + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + # Need this to get version number from last tag + fetch-depth: 0 + + - name: Build sdist and wheel + run: > + export SOURCE_DATE_EPOCH=$(git log -1 --pretty=%ct) && + pipx run build + + - name: Upload sdist and wheel as artifacts + uses: actions/upload-artifact@v4 + with: + name: dist + path: dist + + - name: Check for packaging errors + run: pipx run twine check --strict dist/* + + - name: Install produced wheel + uses: ./.github/actions/install_requirements + with: + pip-install: dist/*.whl + + - name: Test module --version works using the installed wheel + # If more than one module in src/ replace with module name to test + run: python -m $(ls --hide='*.egg-info' src | head -1) --version diff --git a/.github/workflows/_docs.yml b/.github/workflows/_docs.yml new file mode 100644 index 0000000..40446e3 --- /dev/null +++ b/.github/workflows/_docs.yml @@ -0,0 +1,54 @@ +on: + workflow_call: + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - name: Avoid git conflicts when tag and branch pushed at same time + if: github.ref_type == 'tag' + run: sleep 60 + + - name: Checkout + uses: actions/checkout@v4 + with: + # Need this to get version number from last tag + fetch-depth: 0 + + - name: Install system packages + run: sudo apt-get install graphviz + + - name: Install python packages + uses: ./.github/actions/install_requirements + + - name: Build docs + run: tox -e docs + + - name: Remove environment.pickle + run: rm build/html/.doctrees/environment.pickle + + - name: Upload built docs artifact + uses: actions/upload-artifact@v4 + with: + name: docs + path: build + + - name: Sanitize ref name for docs version + run: echo "DOCS_VERSION=${GITHUB_REF_NAME//[^A-Za-z0-9._-]/_}" >> $GITHUB_ENV + + - name: Move to versioned directory + run: mv build/html .github/pages/$DOCS_VERSION + + - name: Write switcher.json + run: python .github/pages/make_switcher.py --add $DOCS_VERSION ${{ github.repository }} .github/pages/switcher.json + + - name: Publish Docs to gh-pages + if: github.ref_type == 'tag' || github.ref_name == 'main' + # We pin to the SHA, not the tag, for security reasons. + # https://docs.github.com/en/actions/learn-github-actions/security-hardening-for-github-actions#using-third-party-actions + uses: peaceiris/actions-gh-pages@373f7f263a76c20808c831209c920827a82a2847 # v3.9.3 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + publish_dir: .github/pages + keep_files: true \ No newline at end of file diff --git a/.github/workflows/_pypi.yml b/.github/workflows/_pypi.yml new file mode 100644 index 0000000..f2ead1b --- /dev/null +++ b/.github/workflows/_pypi.yml @@ -0,0 +1,22 @@ +on: + workflow_call: + secrets: + PYPI_TOKEN: + required: true + +jobs: + upload: + runs-on: ubuntu-latest + environment: release + + steps: + - name: Download dist artifact + uses: actions/download-artifact@v4 + with: + name: dist + path: dist + + - name: Publish to PyPI using trusted publishing + uses: pypa/gh-action-pypi-publish@release/v1 + with: + password: ${{ secrets.PYPI_TOKEN }} diff --git a/.github/workflows/_release.yml b/.github/workflows/_release.yml new file mode 100644 index 0000000..b49fa7d --- /dev/null +++ b/.github/workflows/_release.yml @@ -0,0 +1,32 @@ +on: + workflow_call: + +jobs: + artifacts: + runs-on: ubuntu-latest + + steps: + - name: Download artifacts + uses: actions/download-artifact@v4 + with: + merge-multiple: true + + - name: Zip up docs + run: | + set -vxeuo pipefail + if [ -d html ]; then + mv html $GITHUB_REF_NAME + zip -r docs.zip $GITHUB_REF_NAME + rm -rf $GITHUB_REF_NAME + fi + + - name: Create GitHub Release + # We pin to the SHA, not the tag, for security reasons. + # https://docs.github.com/en/actions/learn-github-actions/security-hardening-for-github-actions#using-third-party-actions + uses: softprops/action-gh-release@de2c0eb89ae2a093876385947365aca7b0e5f844 # v0.1.15 + with: + prerelease: ${{ contains(github.ref_name, 'a') || contains(github.ref_name, 'b') || contains(github.ref_name, 'rc') }} + files: "*" + generate_release_notes: true + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/_test.yml b/.github/workflows/_test.yml new file mode 100644 index 0000000..9b1f21f --- /dev/null +++ b/.github/workflows/_test.yml @@ -0,0 +1,62 @@ +on: + workflow_call: + inputs: + python-version: + type: string + description: The version of python to install + required: true + runs-on: + type: string + description: The runner to run this job on + required: true + secrets: + CODECOV_TOKEN: + required: true + +env: + # https://github.com/pytest-dev/pytest/issues/2042 + PY_IGNORE_IMPORTMISMATCH: "1" + +jobs: + run: + runs-on: ${{ inputs.runs-on }} + + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + # Need this to get version number from last tag + fetch-depth: 0 + + - if: inputs.python-version == 'dev' + name: Install dev versions of python packages + uses: ./.github/actions/install_requirements + + - if: inputs.python-version == 'dev' + name: Write the requirements as an artifact + run: pip freeze --exclude-editable > /tmp/dev-requirements.txt + + - if: inputs.python-version == 'dev' + name: Upload dev-requirements.txt + uses: actions/upload-artifact@v4 + with: + name: dev-requirements + path: /tmp/dev-requirements.txt + + - if: inputs.python-version != 'dev' + name: Install latest versions of python packages + uses: ./.github/actions/install_requirements + with: + python-version: ${{ inputs.python-version }} + pip-install: ".[dev]" + + - name: Run tests + run: tox -e pytest + + - name: Upload coverage to Codecov + uses: codecov/codecov-action@v4 + with: + name: ${{ inputs.python-version }}/${{ inputs.runs-on }} + files: cov.xml + env: + CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} diff --git a/.github/workflows/_tox.yml b/.github/workflows/_tox.yml new file mode 100644 index 0000000..a13536d --- /dev/null +++ b/.github/workflows/_tox.yml @@ -0,0 +1,22 @@ +on: + workflow_call: + inputs: + tox: + type: string + description: What to run under tox + required: true + + +jobs: + run: + runs-on: "ubuntu-latest" + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Install python packages + uses: ./.github/actions/install_requirements + + - name: Run tox + run: tox -e ${{ inputs.tox }} diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..c5610dd --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,68 @@ +name: CI + +on: + push: + pull_request: + +jobs: + check: + uses: ./.github/workflows/_check.yml + + lint: + needs: check + if: needs.check.outputs.branch-pr == '' + uses: ./.github/workflows/_tox.yml + with: + tox: pre-commit,pyright + + test: + needs: check + if: needs.check.outputs.branch-pr == '' + strategy: + matrix: + runs-on: ["ubuntu-latest"] # can add windows-latest, macos-latest + python-version: ["3.8", "3.9", "3.10", "3.11"] + include: + # Include one that runs in the dev environment + - runs-on: "ubuntu-latest" + python-version: "dev" + fail-fast: false + uses: ./.github/workflows/_test.yml + with: + runs-on: ${{ matrix.runs-on }} + python-version: ${{ matrix.python-version }} + secrets: + CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} + + container: + needs: check + if: needs.check.outputs.branch-pr == '' + uses: ./.github/workflows/_container.yml + permissions: + packages: write + + docs: + needs: check + if: needs.check.outputs.branch-pr == '' + uses: ./.github/workflows/_docs.yml + + dist: + needs: check + if: needs.check.outputs.branch-pr == '' + uses: ./.github/workflows/_dist.yml + + pypi: + if: github.ref_type == 'tag' + needs: dist + uses: ./.github/workflows/_pypi.yml + permissions: + id-token: write + secrets: + PYPI_TOKEN: ${{ secrets.PYPI_TOKEN }} + + release: + if: github.ref_type == 'tag' + needs: [dist, docs] + uses: ./.github/workflows/_release.yml + permissions: + contents: write diff --git a/.github/workflows/periodic.yml b/.github/workflows/periodic.yml new file mode 100644 index 0000000..e2a0fd1 --- /dev/null +++ b/.github/workflows/periodic.yml @@ -0,0 +1,13 @@ +name: Periodic + +on: + workflow_dispatch: + schedule: + # Run weekly to check URL links still resolve + - cron: "0 8 * * WED" + +jobs: + linkcheck: + uses: ./.github/workflows/_tox.yml + with: + tox: docs build -- -b linkcheck diff --git a/.gitignore b/.gitignore index 2d7ea35..2593ec7 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,6 @@ # Byte-compiled / optimized / DLL files __pycache__/ *.py[cod] -*.class # C extensions *.so @@ -9,7 +8,6 @@ __pycache__/ # Distribution / packaging .Python env/ -.venv build/ develop-eggs/ dist/ @@ -65,4 +63,8 @@ target/ .venv* venv* +# further build artifacts +lockfiles/ +# ruff cache +.ruff_cache/ diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 5e270b0..5a4cbf7 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,6 +1,6 @@ repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v2.3.0 + rev: v4.5.0 hooks: - id: check-added-large-files - id: check-yaml @@ -8,16 +8,16 @@ repos: - repo: local hooks: - - id: black - name: Run black - stages: [commit] + - id: ruff + name: lint with ruff language: system - entry: black --check --diff + entry: ruff check --force-exclude types: [python] + require_serial: true - - id: flake8 - name: Run flake8 - stages: [commit] + - id: ruff-format + name: format with ruff language: system - entry: flake8 + entry: ruff format --force-exclude types: [python] + require_serial: true diff --git a/.vscode/extensions.json b/.vscode/extensions.json index d173f8d..66ad632 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -1,8 +1,5 @@ { "recommendations": [ - "ms-vscode-remote.remote-containers" - "ms-python.vscode-pylance", - "ms-python.python", - "ryanluker.vscode-coverage-gutters" + "ms-vscode-remote.remote-containers", ] -} +} \ No newline at end of file diff --git a/.vscode/launch.json b/.vscode/launch.json index 8940e85..fe2b6dc 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -5,16 +5,15 @@ "version": "0.2.0", "configurations": [ { - "name": "dls_pmacontrol", + "name": "Debug Unit Test", "type": "python", "request": "launch", - "module": "dls_pmaccontrol.motor", - "args": [ - "-v", - "--protocol=ssh", - "--server=172.23.59.7", - "--port=22", - ] - }, + "justMyCode": false, + "program": "${file}", + "purpose": [ + "debug-test" + ], + "console": "integratedTerminal", + } ] } \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json index 77fee85..c129d99 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,18 +1,11 @@ { - "python.linting.pylintEnabled": false, - "python.linting.flake8Enabled": true, - "python.linting.mypyEnabled": true, - "python.linting.enabled": true, - "python.testing.pytestArgs": [ - "tests" - ], "python.testing.unittestEnabled": false, "python.testing.pytestEnabled": true, - "python.formatting.provider": "black", - "python.languageServer": "Pylance", "editor.formatOnSave": true, "editor.codeActionsOnSave": { - "source.organizeImports": true + "source.organizeImports": "explicit" + }, + "[python]": { + "editor.defaultFormatter": "charliermarsh.ruff", }, - "esbonio.sphinx.confDir": "${workspaceFolder}/docs" } \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index 382f60f..6c754ac 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,53 +1,26 @@ -# This file is for use as a devcontainer and a runtime container -# -# The devcontainer should use the build target and run as root with podman +# The devcontainer should use the developer target and run as root with podman # or docker with user namespaces. -# -FROM python:3.10 as build +ARG PYTHON_VERSION=3.11 +FROM python:${PYTHON_VERSION} as developer # Add any system dependencies for the developer/build environment here -RUN apt-get update && apt-get upgrade -y && \ - apt-get install -y --no-install-recommends \ - build-essential \ - busybox \ - git \ - net-tools \ - vim \ - libqt5gui5 libxcb-xinerama0 \ - && rm -rf /var/lib/apt/lists/* \ - && busybox --install - -COPY . /project - -RUN cd /project && \ - pip install --upgrade pip build && \ - export SOURCE_DATE_EPOCH=$(git log -1 --pretty=%ct) && \ - python -m build --sdist --wheel && \ - touch requirements.txt +RUN apt-get update && apt-get install -y --no-install-recommends \ + graphviz \ + && rm -rf /var/lib/apt/lists/* +# Set up a virtual environment and put it in PATH RUN python -m venv /venv ENV PATH=/venv/bin:$PATH -# allow tests to run headless in the dev container -ENV QT_QPA_PLATFORM=offscreen - -RUN cd /project && \ - pip install --upgrade pip && \ - pip install -r requirements.txt dist/*.whl && \ - pip freeze > dist/requirements.txt && \ - # we don't want to include our own wheel in requirements - remove with sed - # and replace with a comment to avoid a zero length asset upload later - sed -i '/file:/s/^/# Requirements for /' dist/requirements.txt - -FROM python:3.10-slim as runtime -# things to make pyQt5 work -RUN apt-get update && export DEBIAN_FRONTEND=noninteractive && \ - apt-get install -y --no-install-recommends \ - libqt5gui5 libxcb-xinerama0 && \ - rm -rf /var/lib/apt/lists/* - -ENV XDG_RUNTIME_DIR=/tmp/runtime-vscode +# The build stage installs the context into the venv +FROM developer as build +COPY . /context +WORKDIR /context +RUN pip install . +# The runtime stage copies the built venv into a slim runtime container +FROM python:${PYTHON_VERSION}-slim as runtime +# Add apt-get system dependecies for runtime here if needed COPY --from=build /venv/ /venv/ ENV PATH=/venv/bin:$PATH diff --git a/README.md b/README.md new file mode 100644 index 0000000..92b0067 --- /dev/null +++ b/README.md @@ -0,0 +1,20 @@ +[![CI](https://github.com/DiamondLightSource/dls-pmac-control/actions/workflows/ci.yml/badge.svg)](https://github.com/DiamondLightSource/dls-pmac-control/actions/workflows/ci.yml) +[![Coverage](https://codecov.io/gh/DiamondLightSource/dls-pmac-control/branch/main/graph/badge.svg)](https://codecov.io/gh/DiamondLightSource/dls-pmac-control) +[![PyPI](https://img.shields.io/pypi/v/dls-pmac-control.svg)](https://pypi.org/project/dls-pmac-control) +[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) + +# dls_pmac_control + +The dls_pmaccontrol package is a python application which provides a GUI front +end to control the DeltaTau PMAC, Power PMAC and Geobrick motor control systems. + +Source | +:---: | :---: +PyPI | `pip install dls-pmac-control` +Documentation | +Releases | + + + + +See https://diamondlightsource.github.io/dls-pmac-control for more detailed documentation. diff --git a/README.rst b/README.rst deleted file mode 100644 index a4b0237..0000000 --- a/README.rst +++ /dev/null @@ -1,43 +0,0 @@ -dls-pmac-control -=========================== - -|code_ci| |docs_ci| |coverage| |pypi_version| |license| - -The dls_pmaccontrol package is a python application which provides a GUI front -end to control the DeltaTau PMAC, Power PMAC and Geobrick motor control systems. - - -============== ============================================================== -PyPI ``pip install dls-pmaccontrol`` -launch with ``dls-pmac-control`` -Source code https://github.com/DiamondLightSource/dls-pmac-control -Documentation https://DiamondLightSource.github.io/dls-pmac-control -Releases https://github.com/DiamondLightSource/dls-pmac-control/releases -============== ============================================================== - - -.. |code_ci| image:: https://github.com/DiamondLightSource/dls-pmac-control/workflows/Code%20CI/badge.svg?branch=master - :target: https://github.com/DiamondLightSource/dls-pmac-control/actions?query=workflow%3A%22Code+CI%22 - :alt: Code CI - -.. |docs_ci| image:: https://github.com/DiamondLightSource/dls-pmac-control/workflows/Docs%20CI/badge.svg?branch=master - :target: https://github.com/DiamondLightSource/dls-pmac-control/actions?query=workflow%3A%22Docs+CI%22 - :alt: Docs CI - -.. |coverage| image:: https://codecov.io/gh/DiamondLightSource/dls-pmac-control/branch/master/graph/badge.svg - :target: https://codecov.io/gh/DiamondLightSource/dls-pmac-control - :alt: Test Coverage - -.. |pypi_version| image:: https://img.shields.io/pypi/v/dls-pmaccontrol.svg - :target: https://pypi.org/project/dls-pmaccontrol - :alt: Latest PyPI version - -.. |license| image:: https://img.shields.io/badge/License-Apache%202.0-blue.svg - :target: https://opensource.org/licenses/Apache-2.0 - :alt: Apache License - -.. - Anything below this line is used when viewing README.rst and will be replaced - when included in index.rst - -See https://DiamondLightSource.github.io/dls-pmac-control for more detailed documentation. diff --git a/catalog-info.yaml b/catalog-info.yaml new file mode 100644 index 0000000..45a8ac5 --- /dev/null +++ b/catalog-info.yaml @@ -0,0 +1,10 @@ +apiVersion: backstage.io/v1alpha1 +kind: Component +metadata: + name: dls-pmac-control + title: dls-pmac-control + description: GUI for low level control and monitoring of turbo pmac and power pmac motion controllers +spec: + type: documentation + lifecycle: experimental + owner: group:default/sscc \ No newline at end of file diff --git a/docs/conf.py b/docs/conf.py index 0200027..f254507 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -4,22 +4,28 @@ # list see the documentation: # https://www.sphinx-doc.org/en/master/usage/configuration.html -import dls_pmaccontrol +import sys +from pathlib import Path +from subprocess import check_output + +import requests + +import dls_pmac_control # -- General configuration ------------------------------------------------ # General information about the project. -project = "DLS PMAC Control Application" -copyright = "2021, Diamond Light Source" -author = "Bonnie McCallion" +project = "dls-pmac-control" # The full version, including alpha/beta/rc tags. -release = dls_pmaccontrol.__version__ +release = dls_pmac_control.__version__ # The short X.Y version. if "+" in release: - # Not on a tag - version = "main" + # Not on a tag, use branch name + root = Path(__file__).absolute().parent.parent + git_branch = check_output("git branch --show-current".split(), cwd=root) + version = git_branch.decode().strip() else: version = release @@ -34,14 +40,21 @@ "sphinx.ext.viewcode", # Adds the inheritance-diagram generation directive "sphinx.ext.inheritance_diagram", + # Add a copy button to each code block + "sphinx_copybutton", + # For the card element + "sphinx_design", + # So we can write markdown files + "myst_parser", ] +# So we can use the ::: syntax +myst_enable_extensions = ["colon_fence"] + # If true, Sphinx will warn about all references where the target cannot # be found. nitpicky = True -numfig = True - # A list of (type, target) tuples (by default empty) that should be ignored when # generating warnings in "nitpicky mode". Note that type should include the # domain name if present. Example entries would be ('py:func', 'int') or @@ -54,7 +67,6 @@ ("py:class", "'bool'"), ("py:class", "'object'"), ("py:class", "'id'"), - ("py:class", "apischema.utils.UndefinedType"), ("py:class", "typing_extensions.Literal"), ] @@ -75,50 +87,95 @@ # role, that is, for text marked up `like this` default_role = "any" -# The suffix of source filenames. -source_suffix = ".rst" - # The master toctree document. master_doc = "index" # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. # These patterns also affect html_static_path and html_extra_path -exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"] +exclude_patterns = ["_build"] # The name of the Pygments (syntax highlighting) style to use. pygments_style = "sphinx" # This means you can link things like `str` and `asyncio` to the relevant # docs in the python documentation. -intersphinx_mapping = dict(python=("https://docs.python.org/3/", None)) +intersphinx_mapping = {"python": ("https://docs.python.org/3/", None)} # A dictionary of graphviz graph attributes for inheritance diagrams. -inheritance_graph_attrs = dict(rankdir="TB") +inheritance_graph_attrs = {"rankdir": "TB"} -# Common links that should be available on every page -rst_epilog = """ -.. _Diamond Light Source: - http://www.diamond.ac.uk -""" - -# Ignore localhost links for period check that links in docs are valid +# Ignore localhost links for periodic check that links in docs are valid linkcheck_ignore = [r"http://localhost:\d+/"] +# Set copy-button to ignore python and bash prompts +# https://sphinx-copybutton.readthedocs.io/en/latest/use.html#using-regexp-prompt-identifiers +copybutton_prompt_text = r">>> |\.\.\. |\$ |In \[\d*\]: | {2,5}\.\.\.: | {5,8}: " +copybutton_prompt_is_regexp = True + # -- Options for HTML output ------------------------------------------------- # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. # -html_theme = "sphinx_rtd_theme_github_versions" - -# Options for the sphinx rtd theme, use DLS blue -html_theme_options = dict(style_nav_header_background="rgb(7, 43, 93)") - -# Add any paths that contain custom static files (such as style sheets) here, -# relative to this directory. They are copied after the builtin static files, -# so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ["_static"] +html_theme = "pydata_sphinx_theme" +github_repo = "dls-pmac-control" +github_user = "DiamondLightSource" +switcher_json = f"https://{github_user}.github.io/{github_repo}/switcher.json" +switcher_exists = requests.get(switcher_json).ok +if not switcher_exists: + print( + "*** Can't read version switcher, is GitHub pages enabled? \n" + " Once Docs CI job has successfully run once, set the " + "Github pages source branch to be 'gh-pages' at:\n" + f" https://github.com/{github_user}/{github_repo}/settings/pages", + file=sys.stderr, + ) + +# Theme options for pydata_sphinx_theme +# We don't check switcher because there are 3 possible states for a repo: +# 1. New project, docs are not published so there is no switcher +# 2. Existing project with latest skeleton, switcher exists and works +# 3. Existing project with old skeleton that makes broken switcher, +# switcher exists but is broken +# Point 3 makes checking switcher difficult, because the updated skeleton +# will fix the switcher at the end of the docs workflow, but never gets a chance +# to complete as the docs build warns and fails. +html_theme_options = { + "logo": { + "text": project, + }, + "use_edit_page_button": True, + "github_url": f"https://github.com/{github_user}/{github_repo}", + "icon_links": [ + { + "name": "PyPI", + "url": f"https://pypi.org/project/{project}", + "icon": "fas fa-cube", + } + ], + "switcher": { + "json_url": switcher_json, + "version_match": version, + }, + "check_switcher": False, + "navbar_end": ["theme-switcher", "icon-links", "version-switcher"], + "external_links": [ + { + "name": "Release Notes", + "url": f"https://github.com/{github_user}/{github_repo}/releases", + } + ], + "navigation_with_keys": False, +} + +# A dictionary of values to pass into the template engine’s context for all pages +html_context = { + "github_user": github_user, + "github_repo": project, + "github_version": version, + "doc_path": "docs", +} # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. html_show_sphinx = False @@ -126,9 +183,6 @@ # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. html_show_copyright = False -# Add some CSS classes for columns and other tweaks in a custom css file -html_css_files = ["theme_overrides.css"] - # Logo html_logo = "images/dls-logo.svg" -html_favicon = "images/dls-favicon.ico" +html_favicon = html_logo diff --git a/docs/explanations.md b/docs/explanations.md new file mode 100644 index 0000000..73ab289 --- /dev/null +++ b/docs/explanations.md @@ -0,0 +1,10 @@ +# Explanations + +Explanations of how it works and why it works that way. + +```{toctree} +:maxdepth: 1 +:glob: + +explanations/* +``` diff --git a/docs/explanations/decisions.md b/docs/explanations/decisions.md new file mode 100644 index 0000000..f97c2f9 --- /dev/null +++ b/docs/explanations/decisions.md @@ -0,0 +1,18 @@ +% This Source Code Form is subject to the terms of the Mozilla Public + +% License, v. 2.0. If a copy of the MPL was not distributed with this + +% file, You can obtain one at http://mozilla.org/MPL/2.0/. + +# Architectural Decision Records + +We record major architectural decisions in Architecture Decision Records (ADRs), +as [described by Michael Nygard](http://thinkrelevance.com/blog/2011/11/15/documenting-architecture-decisions). +Below is the list of our current ADRs. + +```{toctree} +:glob: true +:maxdepth: 1 + +decisions/* +``` diff --git a/docs/explanations/decisions/0001-record-architecture-decisions.md b/docs/explanations/decisions/0001-record-architecture-decisions.md new file mode 100644 index 0000000..44d234e --- /dev/null +++ b/docs/explanations/decisions/0001-record-architecture-decisions.md @@ -0,0 +1,18 @@ +# 1. Record architecture decisions + +## Status + +Accepted + +## Context + +We need to record the architectural decisions made on this project. + +## Decision + +We will use Architecture Decision Records, as [described by Michael Nygard](http://thinkrelevance.com/blog/2011/11/15/documenting-architecture-decisions). + +## Consequences + +See Michael Nygard's article, linked above. To create new ADRs we will copy and +paste from existing ones. diff --git a/docs/explanations/decisions/0002-switched-to-python-copier-template.md b/docs/explanations/decisions/0002-switched-to-python-copier-template.md new file mode 100644 index 0000000..66fe5d8 --- /dev/null +++ b/docs/explanations/decisions/0002-switched-to-python-copier-template.md @@ -0,0 +1,28 @@ +# 2. Adopt python-copier-template for project structure + +## Status + +Accepted + +## Context + +We should use the following [python-copier-template](https://github.com/DiamondLightSource/python-copier-template). +The template will ensure consistency in developer +environments and package management. + +## Decision + +We have switched to using the template. + +## Consequences + +This module will use a fixed set of tools as developed in `python-copier-template` +and can pull from this template to update the packaging to the latest techniques. + +As such, the developer environment may have changed, the following could be +different: + +- linting +- formatting +- pip venv setup +- CI/CD diff --git a/docs/genindex.md b/docs/genindex.md new file mode 100644 index 0000000..73f1191 --- /dev/null +++ b/docs/genindex.md @@ -0,0 +1,3 @@ +# Index + + diff --git a/docs/how-to.md b/docs/how-to.md new file mode 100644 index 0000000..6b16141 --- /dev/null +++ b/docs/how-to.md @@ -0,0 +1,10 @@ +# How-to Guides + +Practical step-by-step guides for the more experienced user. + +```{toctree} +:maxdepth: 1 +:glob: + +how-to/* +``` diff --git a/docs/how-to/contribute.md b/docs/how-to/contribute.md new file mode 100644 index 0000000..f9c4ca1 --- /dev/null +++ b/docs/how-to/contribute.md @@ -0,0 +1,2 @@ +```{include} ../../.github/CONTRIBUTING.md +``` \ No newline at end of file diff --git a/docs/how-to/run-container.md b/docs/how-to/run-container.md new file mode 100644 index 0000000..8676b84 --- /dev/null +++ b/docs/how-to/run-container.md @@ -0,0 +1,14 @@ +# Run in a container + +Pre-built containers with {\{repo_name}} and its dependencies already +installed are available on [Github Container Registry](https://ghcr.io/DiamondLightSource/dls-pmac-control). + +## Starting the container + +To pull the container from github container registry and run: + +``` +$ docker run ghcr.io/DiamondLightSource/dls-pmac-control:main --version +``` + +To get a released version, use a numbered release instead of `main`. diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 0000000..730b3fd --- /dev/null +++ b/docs/index.md @@ -0,0 +1,56 @@ +--- +html_theme.sidebar_secondary.remove: true +--- + +```{include} ../README.md +:end-before: + +::::{grid} 2 +:gutter: 4 + +:::{grid-item-card} {material-regular}`directions_walk;2em` +```{toctree} +:maxdepth: 2 +tutorials +``` ++++ +Tutorials for installation and typical usage. New users start here. +::: + +:::{grid-item-card} {material-regular}`directions;2em` +```{toctree} +:maxdepth: 2 +how-to +``` ++++ +Practical step-by-step guides for the more experienced user. +::: + +:::{grid-item-card} {material-regular}`info;2em` +```{toctree} +:maxdepth: 2 +explanations +``` ++++ +Explanations of how it works and why it works that way. +::: + +:::{grid-item-card} {material-regular}`menu_book;2em` +```{toctree} +:maxdepth: 2 +reference +``` ++++ +Technical reference material including APIs and release notes. +::: + +:::: diff --git a/docs/reference.md b/docs/reference.md new file mode 100644 index 0000000..6a7d085 --- /dev/null +++ b/docs/reference.md @@ -0,0 +1,11 @@ +# Reference + +Technical reference material including APIs and release notes. + +```{toctree} +:maxdepth: 1 +:glob: + +reference/* +genindex +``` diff --git a/docs/reference/api.md b/docs/reference/api.md new file mode 100644 index 0000000..82732e9 --- /dev/null +++ b/docs/reference/api.md @@ -0,0 +1,17 @@ +# API + +```{eval-rst} +.. automodule:: dls_pmac_control + + ``dls_pmac_control`` + ----------------------------------- +``` + +This is the internal API reference for {\{package_name}} + +```{eval-rst} +.. data:: dls_pmac_control.__version__ + :type: str + + Version number as calculated by https://github.com/pypa/setuptools_scm +``` diff --git a/docs/tutorials.md b/docs/tutorials.md new file mode 100644 index 0000000..1fe66c5 --- /dev/null +++ b/docs/tutorials.md @@ -0,0 +1,10 @@ +# Tutorials + +Tutorials for installation and typical usage. New users start here. + +```{toctree} +:maxdepth: 1 +:glob: + +tutorials/* +``` diff --git a/docs/tutorials/installation.md b/docs/tutorials/installation.md new file mode 100644 index 0000000..836070d --- /dev/null +++ b/docs/tutorials/installation.md @@ -0,0 +1,42 @@ +# Installation + +## Check your version of python + +You will need python 3.8 or later. You can check your version of python by +typing into a terminal: + +``` +$ python3 --version +``` + +## Create a virtual environment + +It is recommended that you install into a “virtual environment” so this +installation will not interfere with any existing Python software: + +``` +$ python3 -m venv /path/to/venv +$ source /path/to/venv/bin/activate +``` + +## Installing the library + +You can now use `pip` to install the library and its dependencies: + +``` +$ python3 -m pip install dls-pmac-control +``` + +If you require a feature that is not currently released you can also install +from github: + +``` +$ python3 -m pip install git+https://github.com/DiamondLightSource/dls-pmac-control.git +``` + +The library should now be installed and the commandline interface on your path. +You can check the version that has been installed by typing: + +``` +$ dls-pmac-control --version +``` diff --git a/pyproject.toml b/pyproject.toml index 3ba51e7..5927ea7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,110 @@ [build-system] -requires = ["setuptools>=64", "setuptools_scm[toml]>=6.2", "wheel"] +requires = ["setuptools>=64", "setuptools_scm[toml]>=6.2"] build-backend = "setuptools.build_meta" +[project] +name = "dls-pmac-control" +classifiers = [ + "Development Status :: 3 - Alpha", + "License :: OSI Approved :: Apache Software License", + "Programming Language :: Python :: 3.7", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", +] +description = "GUI for low level control and monitoring of turbo pmac and power pmac motion controllers" +dependencies = [] # Add project dependencies here, e.g. ["click", "numpy"] +dynamic = ["version"] +license.file = "LICENSE" +readme = "README.md" +requires-python = ">=3.7" + +[project.optional-dependencies] +dev = [ + "copier", + "myst-parser", + "pipdeptree", + "pre-commit", + "pydata-sphinx-theme>=0.12", + "pyright", + "pytest", + "pytest-cov", + "ruff", + "sphinx-autobuild", + "sphinx-copybutton", + "sphinx-design", + "tox-direct", + "types-mock", +] + +[project.scripts] +dls-pmac-control = "dls_pmac_control.__main__:main" + +[project.urls] +GitHub = "https://github.com/DiamondLightSource/dls-pmac-control" + +[[project.authors]] # Further authors may be added by duplicating this section +email = "giles.knap@diamond.ac.uk" +name = "Giles Knap" + + [tool.setuptools_scm] -write_to = "src/dls_pmaccontrol/_version.py" +write_to = "src/dls_pmac_control/_version.py" + +[tool.pyright] +reportMissingImports = false # Ignore missing stubs in imported modules + +[tool.pytest.ini_options] +# Run pytest with all our checkers, and don't spam us with massive tracebacks on error +addopts = """ + --tb=native -vv --doctest-modules --doctest-glob="*.rst" + """ +# https://iscinumpy.gitlab.io/post/bound-version-constraints/#watch-for-warnings +filterwarnings = "error" +# Doctest python code in docs, python code in src docstrings, test functions in tests +testpaths = "docs src tests" + +[tool.coverage.run] +data_file = "/tmp/dls_pmac_control.coverage" + +[tool.coverage.paths] +# Tests are run from installed location, map back to the src directory +source = ["src", "**/site-packages/"] + +# tox must currently be configured via an embedded ini string +# See: https://github.com/tox-dev/tox/issues/999 +[tool.tox] +legacy_tox_ini = """ +[tox] +skipsdist=True + +[testenv:{pre-commit,pyright,pytest,docs}] +# Don't create a virtualenv for the command, requires tox-direct plugin +direct = True +passenv = * +allowlist_externals = + pytest + pre-commit + pyright + sphinx-build + sphinx-autobuild +commands = + pytest: pytest --cov=dls_pmac_control --cov-report term --cov-report xml:cov.xml {posargs} + pyright: pyright src tests {posargs} + pre-commit: pre-commit run --all-files {posargs} + docs: sphinx-{posargs:build -EW --keep-going} -T docs build/html +""" + +[tool.ruff] +src = ["src", "tests"] +line-length = 88 +lint.select = [ + "B", # flake8-bugbear - https://docs.astral.sh/ruff/rules/#flake8-bugbear-b + "C4", # flake8-comprehensions - https://docs.astral.sh/ruff/rules/#flake8-comprehensions-c4 + "E", # pycodestyle errors - https://docs.astral.sh/ruff/rules/#error-e + "F", # pyflakes rules - https://docs.astral.sh/ruff/rules/#pyflakes-f + "W", # pycodestyle warnings - https://docs.astral.sh/ruff/rules/#warning-w + "I", # isort - https://docs.astral.sh/ruff/rules/#isort-i + "UP", # pyupgrade - https://docs.astral.sh/ruff/rules/#pyupgrade-up +] diff --git a/src/dls_pmac_control/__init__.py b/src/dls_pmac_control/__init__.py new file mode 100644 index 0000000..26d23ba --- /dev/null +++ b/src/dls_pmac_control/__init__.py @@ -0,0 +1,3 @@ +from ._version import __version__ + +__all__ = ["__version__"] diff --git a/src/dls_pmac_control/__main__.py b/src/dls_pmac_control/__main__.py new file mode 100644 index 0000000..823f3b9 --- /dev/null +++ b/src/dls_pmac_control/__main__.py @@ -0,0 +1,16 @@ +from argparse import ArgumentParser + +from . import __version__ + +__all__ = ["main"] + + +def main(args=None): + parser = ArgumentParser() + parser.add_argument("-v", "--version", action="version", version=__version__) + args = parser.parse_args(args) + + +# test with: python -m dls_pmac_control +if __name__ == "__main__": + main() diff --git a/tests/test_cli.py b/tests/test_cli.py new file mode 100644 index 0000000..9d95020 --- /dev/null +++ b/tests/test_cli.py @@ -0,0 +1,9 @@ +import subprocess +import sys + +from dls_pmac_control import __version__ + + +def test_cli_version(): + cmd = [sys.executable, "-m", "dls_pmac_control", "--version"] + assert subprocess.check_output(cmd).decode().strip() == __version__ From 5dd667aa14d9896270238f417592a84ca8db1554 Mon Sep 17 00:00:00 2001 From: Giles Knap Date: Sun, 11 Feb 2024 20:16:19 +0000 Subject: [PATCH 21/36] move src to correct folder etc. --- .containerignore | 7 - .coveragerc | 9 - .github/workflows/ci.yml | 6 +- .github/workflows/code.yml | 179 --- .github/workflows/codeql-analysis.yml | 72 -- .github/workflows/container_tests.sh | 13 - .github/workflows/docs.yml | 59 - .github/workflows/docs_clean.yml | 41 - .github/workflows/linkcheck.yml | 34 - .github/workflows/periodic.yml | 13 - Pipfile | 13 - Pipfile.lock | 1088 ----------------- pyproject.toml | 7 +- setup.cfg | 141 --- setup.py | 3 - .../CSstatus.py | 0 .../GlobalStatus.py | 0 src/dls_pmac_control/__main__.py | 4 +- .../axissettings.py | 0 .../commsThread.py | 0 .../energise.py | 0 .../formAxisSettings.ui | 0 .../formCSStatus.ui | 0 .../formControl.ui | 0 .../formEnergise.ui | 0 .../formGather.ui | 0 .../formGlobalStatus.ui | 0 .../formLogin.ui | 0 .../formPpmacAxisSettings.ui | 0 .../formPpmacCSStatus.ui | 0 .../formStatus.ui | 0 .../formWatches.ui | 0 .../gather.py | 0 .../gatherchannel.py | 0 .../greenLedOff.png | Bin .../greenLedOn.png | Bin .../led-amber.png | Bin .../login.py | 0 .../motor.py | 0 .../ppmacgather.py | 0 .../redLedOff.png | Bin .../redLedOn.png | Bin .../status.py | 0 .../ui_formAxisSettings.py | 0 .../ui_formCSStatus.py | 0 .../ui_formControl.py | 0 .../ui_formEnergise.py | 0 .../ui_formGather.py | 0 .../ui_formGlobalStatus.py | 0 .../ui_formLogin.py | 0 .../ui_formPpmacAxisSettings.py | 0 .../ui_formPpmacCSStatus.py | 0 .../ui_formStatus.py | 0 .../ui_formWatches.py | 0 .../watches.py | 0 src/dls_pmaccontrol/__init__.py | 12 - src/dls_pmaccontrol/__main__.py | 16 - 57 files changed, 8 insertions(+), 1709 deletions(-) delete mode 100644 .containerignore delete mode 100644 .coveragerc delete mode 100644 .github/workflows/code.yml delete mode 100644 .github/workflows/codeql-analysis.yml delete mode 100644 .github/workflows/container_tests.sh delete mode 100644 .github/workflows/docs.yml delete mode 100644 .github/workflows/docs_clean.yml delete mode 100644 .github/workflows/linkcheck.yml delete mode 100644 .github/workflows/periodic.yml delete mode 100644 Pipfile delete mode 100644 Pipfile.lock delete mode 100644 setup.cfg delete mode 100644 setup.py rename src/{dls_pmaccontrol => dls_pmac_control}/CSstatus.py (100%) rename src/{dls_pmaccontrol => dls_pmac_control}/GlobalStatus.py (100%) rename src/{dls_pmaccontrol => dls_pmac_control}/axissettings.py (100%) rename src/{dls_pmaccontrol => dls_pmac_control}/commsThread.py (100%) rename src/{dls_pmaccontrol => dls_pmac_control}/energise.py (100%) rename src/{dls_pmaccontrol => dls_pmac_control}/formAxisSettings.ui (100%) rename src/{dls_pmaccontrol => dls_pmac_control}/formCSStatus.ui (100%) rename src/{dls_pmaccontrol => dls_pmac_control}/formControl.ui (100%) rename src/{dls_pmaccontrol => dls_pmac_control}/formEnergise.ui (100%) rename src/{dls_pmaccontrol => dls_pmac_control}/formGather.ui (100%) rename src/{dls_pmaccontrol => dls_pmac_control}/formGlobalStatus.ui (100%) rename src/{dls_pmaccontrol => dls_pmac_control}/formLogin.ui (100%) rename src/{dls_pmaccontrol => dls_pmac_control}/formPpmacAxisSettings.ui (100%) rename src/{dls_pmaccontrol => dls_pmac_control}/formPpmacCSStatus.ui (100%) rename src/{dls_pmaccontrol => dls_pmac_control}/formStatus.ui (100%) rename src/{dls_pmaccontrol => dls_pmac_control}/formWatches.ui (100%) rename src/{dls_pmaccontrol => dls_pmac_control}/gather.py (100%) rename src/{dls_pmaccontrol => dls_pmac_control}/gatherchannel.py (100%) rename src/{dls_pmaccontrol => dls_pmac_control}/greenLedOff.png (100%) rename src/{dls_pmaccontrol => dls_pmac_control}/greenLedOn.png (100%) rename src/{dls_pmaccontrol => dls_pmac_control}/led-amber.png (100%) rename src/{dls_pmaccontrol => dls_pmac_control}/login.py (100%) rename src/{dls_pmaccontrol => dls_pmac_control}/motor.py (100%) rename src/{dls_pmaccontrol => dls_pmac_control}/ppmacgather.py (100%) rename src/{dls_pmaccontrol => dls_pmac_control}/redLedOff.png (100%) rename src/{dls_pmaccontrol => dls_pmac_control}/redLedOn.png (100%) rename src/{dls_pmaccontrol => dls_pmac_control}/status.py (100%) rename src/{dls_pmaccontrol => dls_pmac_control}/ui_formAxisSettings.py (100%) rename src/{dls_pmaccontrol => dls_pmac_control}/ui_formCSStatus.py (100%) rename src/{dls_pmaccontrol => dls_pmac_control}/ui_formControl.py (100%) rename src/{dls_pmaccontrol => dls_pmac_control}/ui_formEnergise.py (100%) rename src/{dls_pmaccontrol => dls_pmac_control}/ui_formGather.py (100%) rename src/{dls_pmaccontrol => dls_pmac_control}/ui_formGlobalStatus.py (100%) rename src/{dls_pmaccontrol => dls_pmac_control}/ui_formLogin.py (100%) rename src/{dls_pmaccontrol => dls_pmac_control}/ui_formPpmacAxisSettings.py (100%) rename src/{dls_pmaccontrol => dls_pmac_control}/ui_formPpmacCSStatus.py (100%) rename src/{dls_pmaccontrol => dls_pmac_control}/ui_formStatus.py (100%) rename src/{dls_pmaccontrol => dls_pmac_control}/ui_formWatches.py (100%) rename src/{dls_pmaccontrol => dls_pmac_control}/watches.py (100%) delete mode 100644 src/dls_pmaccontrol/__init__.py delete mode 100644 src/dls_pmaccontrol/__main__.py diff --git a/.containerignore b/.containerignore deleted file mode 100644 index eb7d5ae..0000000 --- a/.containerignore +++ /dev/null @@ -1,7 +0,0 @@ -Dockerfile -build/ -dist/ -.mypy_cache -.tox -.venv* -venv* diff --git a/.coveragerc b/.coveragerc deleted file mode 100644 index 8911e16..0000000 --- a/.coveragerc +++ /dev/null @@ -1,9 +0,0 @@ -[run] -source = dls_pmaccontrol/ -omit = - */_version_git.py - */tests/* - */ui_form* - *__init__.py - *__main__.py - /setup.py diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c5610dd..1f69047 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -21,7 +21,7 @@ jobs: strategy: matrix: runs-on: ["ubuntu-latest"] # can add windows-latest, macos-latest - python-version: ["3.8", "3.9", "3.10", "3.11"] + python-version: ["3.9", "3.10", "3.11", "3.12"] include: # Include one that runs in the dev environment - runs-on: "ubuntu-latest" @@ -50,7 +50,7 @@ jobs: needs: check if: needs.check.outputs.branch-pr == '' uses: ./.github/workflows/_dist.yml - + pypi: if: github.ref_type == 'tag' needs: dist @@ -59,7 +59,7 @@ jobs: id-token: write secrets: PYPI_TOKEN: ${{ secrets.PYPI_TOKEN }} - + release: if: github.ref_type == 'tag' needs: [dist, docs] diff --git a/.github/workflows/code.yml b/.github/workflows/code.yml deleted file mode 100644 index 01e5ba7..0000000 --- a/.github/workflows/code.yml +++ /dev/null @@ -1,179 +0,0 @@ -name: Code CI - -on: - push: - pull_request: - schedule: - # Run every Monday at 8am to check latest versions of dependencies - - cron: "0 8 * * WED" - -jobs: - lint: - # pull requests are a duplicate of a branch push if within the same repo. - if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name != github.repository - runs-on: ubuntu-latest - - steps: - - name: Checkout - uses: actions/checkout@v3 - - - name: Setup python - uses: actions/setup-python@v4 - with: - python-version: "3.10" - - - name: Lint - run: | - touch requirements_dev.txt requirements.txt - pip install -r requirements.txt -r requirements_dev.txt -e .[dev] - tox -e pre-commit,mypy - - test: - if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name != github.repository - strategy: - fail-fast: false - matrix: - os: ["ubuntu-latest"] # can add windows-latest, macos-latest - python: ["3.8", "3.9", "3.10"] - - runs-on: ${{ matrix.os }} - env: - # https://github.com/pytest-dev/pytest/issues/2042 - PY_IGNORE_IMPORTMISMATCH: "1" - # enable QT tests with no X Display - QT_QPA_PLATFORM: "offscreen" - - steps: - - name: Checkout - uses: actions/checkout@v3 - with: - fetch-depth: 0 - - - name: Setup python ${{ matrix.python }} - uses: actions/setup-python@v4 - with: - python-version: ${{ matrix.python }} - - - name: Install with latest dependencies - run: pip install .[dev] - - - name: Run tests - run: pytest tests - - - name: Upload coverage to Codecov - uses: codecov/codecov-action@v3 - with: - name: ${{ matrix.python }}/${{ matrix.os }} - files: cov.xml - - container: - if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name != github.repository - runs-on: ubuntu-latest - permissions: - contents: read - packages: write - - steps: - - name: Checkout - uses: actions/checkout@v3 - with: - fetch-depth: 0 - - - name: Log in to GitHub Docker Registry - if: github.event_name != 'pull_request' - uses: docker/login-action@v2 - with: - registry: ghcr.io - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} - - - name: Docker meta - id: meta - uses: docker/metadata-action@v4 - with: - images: ghcr.io/${{ github.repository }} - tags: | - type=ref,event=branch - type=ref,event=tag - - - name: Set up Docker Buildx - id: buildx - uses: docker/setup-buildx-action@v2 - - - name: Build developer image for testing - uses: docker/build-push-action@v3 - with: - tags: build:latest - context: . - target: build - load: true - - - name: Run tests in the container locked with requirements_dev.txt - run: | - docker run --name test build bash /project/.github/workflows/container_tests.sh - docker cp test:/project/dist . - docker cp test:/project/cov.xml . - - - name: Upload coverage to Codecov - uses: codecov/codecov-action@v3 - with: - name: 3.10-locked/ubuntu-latest - files: cov.xml - - - name: Build runtime image - uses: docker/build-push-action@v3 - with: - push: ${{ github.event_name != 'pull_request' }} - tags: ${{ steps.meta.outputs.tags }} - context: . - labels: ${{ steps.meta.outputs.labels }} - - - name: Check runtime - run: for i in ${{ steps.meta.outputs.tags }}; do docker run ${i} --version; done - - - name: Upload build files - uses: actions/upload-artifact@v3 - with: - name: dist - path: dist/* - - sdist: - needs: container - runs-on: ubuntu-latest - - steps: - - uses: actions/download-artifact@v3 - - - name: Install sdist in a venv and check cli works - # ${GITHUB_REPOSITORY##*/} is the repo name without org - # Replace this with the cli command if different to the repo name - run: | - pip install dist/*.gz - ${GITHUB_REPOSITORY##*/} --version - - release: - # upload to PyPI and make a release on every tag - if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags') - needs: container - runs-on: ubuntu-latest - - steps: - - uses: actions/download-artifact@v3 - - - name: Github Release - # We pin to the SHA, not the tag, for security reasons. - # https://docs.github.com/en/actions/learn-github-actions/security-hardening-for-github-actions#using-third-party-actions - uses: softprops/action-gh-release@1e07f4398721186383de40550babbdf2b84acfc5 # v0.1.14 - with: - prerelease: ${{ contains(github.ref_name, 'a') || contains(github.ref_name, 'b') || contains(github.ref_name, 'rc') }} - files: | - dist/* - generate_release_notes: true - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - - name: Publish to PyPI - env: - TWINE_USERNAME: __token__ - TWINE_PASSWORD: ${{ secrets.PYPI_TOKEN }} - run: pipx run twine upload dist/*.whl dist/*.tar.gz diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml deleted file mode 100644 index c2d4a01..0000000 --- a/.github/workflows/codeql-analysis.yml +++ /dev/null @@ -1,72 +0,0 @@ -# For most projects, this workflow file will not need changing; you simply need -# to commit it to your repository. -# -# You may wish to alter this file to override the set of languages analyzed, -# or to provide custom queries or build logic. -# -# ******** NOTE ******** -# We have attempted to detect the languages in your repository. Please check -# the `language` matrix defined below to confirm you have the correct set of -# supported CodeQL languages. -# -name: "CodeQL" - -on: - push: - branches: [ master ] - pull_request: - # The branches below must be a subset of the branches above - branches: [ master ] - schedule: - - cron: '25 21 * * 3' - -jobs: - analyze: - name: Analyze - runs-on: ubuntu-latest - permissions: - actions: read - contents: read - security-events: write - - strategy: - fail-fast: false - matrix: - language: [ 'python' ] - # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ] - # Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support - - steps: - - name: Checkout repository - uses: actions/checkout@v3 - - # Initializes the CodeQL tools for scanning. - - name: Initialize CodeQL - uses: github/codeql-action/init@v2 - with: - languages: ${{ matrix.language }} - # If you wish to specify custom queries, you can do so here or in a config file. - # By default, queries listed here will override any specified in a config file. - # Prefix the list here with "+" to use these queries and those in the config file. - - # Details on CodeQL's query packs refer to : https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs - # queries: security-extended,security-and-quality - - - # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). - # If this step fails, then you should remove it and run the build manually (see below) - - name: Autobuild - uses: github/codeql-action/autobuild@v2 - - # ℹ️ Command-line programs to run using the OS shell. - # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun - - # If the Autobuild fails above, remove it and uncomment the following three lines. - # modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance. - - # - run: | - # echo "Run, Build Application using script" - # ./location_of_script_within_repo/buildscript.sh - - - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v2 diff --git a/.github/workflows/container_tests.sh b/.github/workflows/container_tests.sh deleted file mode 100644 index 5f92159..0000000 --- a/.github/workflows/container_tests.sh +++ /dev/null @@ -1,13 +0,0 @@ -#!/bin/bash -set -x - -cd /project -source /venv/bin/activate - -touch requirements_dev.txt -pip install -r requirements_dev.txt -e .[dev] -pip freeze --exclude-editable > dist/requirements_dev.txt - -pipdeptree - -pytest tests diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml deleted file mode 100644 index 09e6f3e..0000000 --- a/.github/workflows/docs.yml +++ /dev/null @@ -1,59 +0,0 @@ -name: Docs CI - -on: - push: - pull_request: - -jobs: - docs: - if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name != github.repository - strategy: - fail-fast: false - matrix: - python: ["3.10"] - - runs-on: ubuntu-latest - - steps: - - name: Avoid git conflicts when tag and branch pushed at same time - if: startsWith(github.ref, 'refs/tags') - run: sleep 60 - - - name: Install python version - uses: actions/setup-python@v4 - with: - python-version: ${{ matrix.python }} - - - name: Install Packages - # Can delete this if you don't use graphviz in your docs - run: sudo apt-get install graphviz - - - name: checkout - uses: actions/checkout@v3 - with: - fetch-depth: 0 - - - name: Install dependencies - run: | - touch requirements_dev.txt - pip install -r requirements_dev.txt -e .[dev] - - - name: Build docs - run: tox -e docs - - - name: Move to versioned directory - # e.g. main or 0.1.2 - run: mv build/html ".github/pages/${GITHUB_REF##*/}" - - - name: Write versions.txt - run: sphinx_rtd_theme_github_versions .github/pages - - - name: Publish Docs to gh-pages - if: github.event_name == 'push' - # We pin to the SHA, not the tag, for security reasons. - # https://docs.github.com/en/actions/learn-github-actions/security-hardening-for-github-actions#using-third-party-actions - uses: peaceiris/actions-gh-pages@068dc23d9710f1ba62e86896f84735d869951305 # v3.8.0 - with: - github_token: ${{ secrets.GITHUB_TOKEN }} - publish_dir: .github/pages - keep_files: true diff --git a/.github/workflows/docs_clean.yml b/.github/workflows/docs_clean.yml deleted file mode 100644 index f39519f..0000000 --- a/.github/workflows/docs_clean.yml +++ /dev/null @@ -1,41 +0,0 @@ -name: Docs Cleanup CI - -# delete branch documentation when a branch is deleted -# also allow manually deleting a documentation version -on: - delete: - workflow_dispatch: - inputs: - version: - description: "documentation version to DELETE" - required: true - type: string - -jobs: - remove: - if: github.event.ref_type == 'branch' || github.event_name == 'workflow_dispatch' - runs-on: ubuntu-latest - - steps: - - name: checkout - uses: actions/checkout@v3 - with: - ref: gh-pages - - - name: removing documentation for branch ${{ github.event.ref }} - if: ${{ github.event_name != 'workflow_dispatch' }} - run: echo "remove_me=${{ github.event.ref }}" >> $GITHUB_ENV - - - name: manually removing documentation version ${{ github.event.inputs.version }} - if: ${{ github.event_name == 'workflow_dispatch' }} - run: echo "remove_me=${{ github.event.inputs.version }}" >> $GITHUB_ENV - - - name: update index and push changes - run: | - echo removing redundant documentation version ${{ env.remove_me }} - rm -r ${{ env.remove_me }} - sed -i /${{ env.remove_me }}/d versions.txt - git config --global user.name 'GitHub Actions Docs Cleanup CI' - git config --global user.email 'gha@users.noreply.github.com' - git commit -am"removing redundant docs version ${{ env.remove_me }}" - git push diff --git a/.github/workflows/linkcheck.yml b/.github/workflows/linkcheck.yml deleted file mode 100644 index e683856..0000000 --- a/.github/workflows/linkcheck.yml +++ /dev/null @@ -1,34 +0,0 @@ -name: Link Check - -on: - schedule: - # Run every Monday at 8am to check URL links still resolve - - cron: "0 8 * * WED" - -jobs: - docs: - strategy: - fail-fast: false - matrix: - python: ["3.10"] - - runs-on: ubuntu-latest - - steps: - - name: Checkout - uses: actions/checkout@v3 - with: - fetch-depth: 0 - - - name: Install python version - uses: actions/setup-python@v4 - with: - python-version: ${{ matrix.python }} - - - name: Install dependencies - run: | - touch requirements_dev.txt - pip install -r requirements_dev.txt -e .[dev] - - - name: Check links - run: tox -e docs -- -b linkcheck diff --git a/.github/workflows/periodic.yml b/.github/workflows/periodic.yml deleted file mode 100644 index e2a0fd1..0000000 --- a/.github/workflows/periodic.yml +++ /dev/null @@ -1,13 +0,0 @@ -name: Periodic - -on: - workflow_dispatch: - schedule: - # Run weekly to check URL links still resolve - - cron: "0 8 * * WED" - -jobs: - linkcheck: - uses: ./.github/workflows/_tox.yml - with: - tox: docs build -- -b linkcheck diff --git a/Pipfile b/Pipfile deleted file mode 100644 index eeedcba..0000000 --- a/Pipfile +++ /dev/null @@ -1,13 +0,0 @@ -[[source]] -name = "pypi" -url = "https://pypi.org/simple" -verify_ssl = true - -[dev-packages] -dls_pmaccontrol = {editable = true, extras = ["dev"], path = "."} - -[packages] -dls_pmaccontrol = {editable = true, path = "."} - -[pipenv] -allow_prereleases = true diff --git a/Pipfile.lock b/Pipfile.lock deleted file mode 100644 index 5f67753..0000000 --- a/Pipfile.lock +++ /dev/null @@ -1,1088 +0,0 @@ -{ - "_meta": { - "hash": { - "sha256": "06a47c54d5fee7e5a97497b09909008c5d7f02040aaa231d1443871deb312043" - }, - "pipfile-spec": 6, - "requires": {}, - "sources": [ - { - "name": "pypi", - "url": "https://pypi.org/simple", - "verify_ssl": true - } - ] - }, - "default": { - "bcrypt": { - "hashes": [ - "sha256:5b93c1726e50a93a033c36e5ca7fdcd29a5c7395af50a6892f5d9e7c6cfbfb29", - "sha256:63d4e3ff96188e5898779b6057878fecf3f11cfe6ec3b313ea09955d587ec7a7", - "sha256:81fec756feff5b6818ea7ab031205e1d323d8943d237303baca2c5f9c7846f34", - "sha256:a67fb841b35c28a59cebed05fbd3e80eea26e6d75851f0574a9273c80f3e9b55", - "sha256:c95d4cbebffafcdd28bd28bb4e25b31c50f6da605c81ffd9ad8a3d1b2ab7b1b6", - "sha256:cd1ea2ff3038509ea95f687256c46b79f5fc382ad0aa3664d200047546d511d1", - "sha256:cdcdcb3972027f83fe24a48b1e90ea4b584d35f1cc279d76de6fc4b13376239d" - ], - "version": "==3.2.0" - }, - "cffi": { - "hashes": [ - "sha256:001bf3242a1bb04d985d63e138230802c6c8d4db3668fb545fb5005ddf5bb5ff", - "sha256:00789914be39dffba161cfc5be31b55775de5ba2235fe49aa28c148236c4e06b", - "sha256:028a579fc9aed3af38f4892bdcc7390508adabc30c6af4a6e4f611b0c680e6ac", - "sha256:14491a910663bf9f13ddf2bc8f60562d6bc5315c1f09c704937ef17293fb85b0", - "sha256:1cae98a7054b5c9391eb3249b86e0e99ab1e02bb0cc0575da191aedadbdf4384", - "sha256:2089ed025da3919d2e75a4d963d008330c96751127dd6f73c8dc0c65041b4c26", - "sha256:2d384f4a127a15ba701207f7639d94106693b6cd64173d6c8988e2c25f3ac2b6", - "sha256:337d448e5a725bba2d8293c48d9353fc68d0e9e4088d62a9571def317797522b", - "sha256:399aed636c7d3749bbed55bc907c3288cb43c65c4389964ad5ff849b6370603e", - "sha256:3b911c2dbd4f423b4c4fcca138cadde747abdb20d196c4a48708b8a2d32b16dd", - "sha256:3d311bcc4a41408cf5854f06ef2c5cab88f9fded37a3b95936c9879c1640d4c2", - "sha256:62ae9af2d069ea2698bf536dcfe1e4eed9090211dbaafeeedf5cb6c41b352f66", - "sha256:66e41db66b47d0d8672d8ed2708ba91b2f2524ece3dee48b5dfb36be8c2f21dc", - "sha256:675686925a9fb403edba0114db74e741d8181683dcf216be697d208857e04ca8", - "sha256:7e63cbcf2429a8dbfe48dcc2322d5f2220b77b2e17b7ba023d6166d84655da55", - "sha256:8a6c688fefb4e1cd56feb6c511984a6c4f7ec7d2a1ff31a10254f3c817054ae4", - "sha256:8c0ffc886aea5df6a1762d0019e9cb05f825d0eec1f520c51be9d198701daee5", - "sha256:95cd16d3dee553f882540c1ffe331d085c9e629499ceadfbda4d4fde635f4b7d", - "sha256:99f748a7e71ff382613b4e1acc0ac83bf7ad167fb3802e35e90d9763daba4d78", - "sha256:b8c78301cefcf5fd914aad35d3c04c2b21ce8629b5e4f4e45ae6812e461910fa", - "sha256:c420917b188a5582a56d8b93bdd8e0f6eca08c84ff623a4c16e809152cd35793", - "sha256:c43866529f2f06fe0edc6246eb4faa34f03fe88b64a0a9a942561c8e22f4b71f", - "sha256:cab50b8c2250b46fe738c77dbd25ce017d5e6fb35d3407606e7a4180656a5a6a", - "sha256:cef128cb4d5e0b3493f058f10ce32365972c554572ff821e175dbc6f8ff6924f", - "sha256:cf16e3cf6c0a5fdd9bc10c21687e19d29ad1fe863372b5543deaec1039581a30", - "sha256:e56c744aa6ff427a607763346e4170629caf7e48ead6921745986db3692f987f", - "sha256:e577934fc5f8779c554639376beeaa5657d54349096ef24abe8c74c5d9c117c3", - "sha256:f2b0fa0c01d8a0c7483afd9f31d7ecf2d71760ca24499c8697aeb5ca37dc090c" - ], - "version": "==1.14.0" - }, - "cryptography": { - "hashes": [ - "sha256:07bb7fbfb5de0980590ddfc7f13081520def06dc9ed214000ad4372fb4e3c7f6", - "sha256:18d90f4711bf63e2fb21e8c8e51ed8189438e6b35a6d996201ebd98a26abbbe6", - "sha256:1ed82abf16df40a60942a8c211251ae72858b25b7421ce2497c2eb7a1cee817c", - "sha256:22a38e96118a4ce3b97509443feace1d1011d0571fae81fc3ad35f25ba3ea999", - "sha256:2d69645f535f4b2c722cfb07a8eab916265545b3475fdb34e0be2f4ee8b0b15e", - "sha256:4a2d0e0acc20ede0f06ef7aa58546eee96d2592c00f450c9acb89c5879b61992", - "sha256:54b2605e5475944e2213258e0ab8696f4f357a31371e538ef21e8d61c843c28d", - "sha256:7075b304cd567694dc692ffc9747f3e9cb393cc4aa4fb7b9f3abd6f5c4e43588", - "sha256:7b7ceeff114c31f285528ba8b390d3e9cfa2da17b56f11d366769a807f17cbaa", - "sha256:7eba2cebca600a7806b893cb1d541a6e910afa87e97acf2021a22b32da1df52d", - "sha256:928185a6d1ccdb816e883f56ebe92e975a262d31cc536429041921f8cb5a62fd", - "sha256:9933f28f70d0517686bd7de36166dda42094eac49415459d9bdf5e7df3e0086d", - "sha256:a688ebcd08250eab5bb5bca318cc05a8c66de5e4171a65ca51db6bd753ff8953", - "sha256:abb5a361d2585bb95012a19ed9b2c8f412c5d723a9836418fab7aaa0243e67d2", - "sha256:c10c797ac89c746e488d2ee92bd4abd593615694ee17b2500578b63cad6b93a8", - "sha256:ced40344e811d6abba00295ced98c01aecf0c2de39481792d87af4fa58b7b4d6", - "sha256:d57e0cdc1b44b6cdf8af1d01807db06886f10177469312fbde8f44ccbb284bc9", - "sha256:d99915d6ab265c22873f1b4d6ea5ef462ef797b4140be4c9d8b179915e0985c6", - "sha256:eb80e8a1f91e4b7ef8b33041591e6d89b2b8e122d787e87eeb2b08da71bb16ad", - "sha256:ebeddd119f526bcf323a89f853afb12e225902a24d29b55fe18dd6fcb2838a76" - ], - "version": "==35.0.0" - }, - "dls-pmaccontrol": { - "editable": true, - "path": "." - }, - "dls-pmaclib": { - "hashes": [ - "sha256:21592edab35fa61c6ea9823bd410d7dca2e070cdbbece37ea69c73c70fe3e699", - "sha256:bf464a268fa4141e0f3a203413af9f22db5d782b1adac579b306efae6daf250a" - ], - "version": "==3.0.2" - }, - "importlib-metadata": { - "hashes": [ - "sha256:d5059f9f1e8e41f80e9c56c2ee58811450c31984dfa625329ffd7c0dad88a73b", - "sha256:d84d17e21670ec07990e1044a99efe8d615d860fd176fc29ef5c306068fda313" - ], - "markers": "python_version < '3.8'", - "version": "==5.1.0" - }, - "mock": { - "hashes": [ - "sha256:122fcb64ee37cfad5b3f48d7a7d51875d7031aaf3d8be7c42e2bee25044eee62", - "sha256:7d3fbbde18228f4ff2f1f119a45cdffa458b4c0dee32eb4d2bb2f82554bac7bc" - ], - "version": "==4.0.3" - }, - "numpy": { - "hashes": [ - "sha256:1dbe1c91269f880e364526649a52eff93ac30035507ae980d2fed33aaee633ac", - "sha256:357768c2e4451ac241465157a3e929b265dfac85d9214074985b1786244f2ef3", - "sha256:3820724272f9913b597ccd13a467cc492a0da6b05df26ea09e78b171a0bb9da6", - "sha256:4391bd07606be175aafd267ef9bea87cf1b8210c787666ce82073b05f202add1", - "sha256:4aa48afdce4660b0076a00d80afa54e8a97cd49f457d68a4342d188a09451c1a", - "sha256:58459d3bad03343ac4b1b42ed14d571b8743dc80ccbf27444f266729df1d6f5b", - "sha256:5c3c8def4230e1b959671eb959083661b4a0d2e9af93ee339c7dada6759a9470", - "sha256:5f30427731561ce75d7048ac254dbe47a2ba576229250fb60f0fb74db96501a1", - "sha256:643843bcc1c50526b3a71cd2ee561cf0d8773f062c8cbaf9ffac9fdf573f83ab", - "sha256:67c261d6c0a9981820c3a149d255a76918278a6b03b6a036800359aba1256d46", - "sha256:67f21981ba2f9d7ba9ade60c9e8cbaa8cf8e9ae51673934480e45cf55e953673", - "sha256:6aaf96c7f8cebc220cdfc03f1d5a31952f027dda050e5a703a0d1c396075e3e7", - "sha256:7c4068a8c44014b2d55f3c3f574c376b2494ca9cc73d2f1bd692382b6dffe3db", - "sha256:7c7e5fa88d9ff656e067876e4736379cc962d185d5cd808014a8a928d529ef4e", - "sha256:7f5ae4f304257569ef3b948810816bc87c9146e8c446053539947eedeaa32786", - "sha256:82691fda7c3f77c90e62da69ae60b5ac08e87e775b09813559f8901a88266552", - "sha256:8737609c3bbdd48e380d463134a35ffad3b22dc56295eff6f79fd85bd0eeeb25", - "sha256:9f411b2c3f3d76bba0865b35a425157c5dcf54937f82bbeb3d3c180789dd66a6", - "sha256:a6be4cb0ef3b8c9250c19cc122267263093eee7edd4e3fa75395dfda8c17a8e2", - "sha256:bcb238c9c96c00d3085b264e5c1a1207672577b93fa666c3b14a45240b14123a", - "sha256:bf2ec4b75d0e9356edea834d1de42b31fe11f726a81dfb2c2112bc1eaa508fcf", - "sha256:d136337ae3cc69aa5e447e78d8e1514be8c3ec9b54264e680cf0b4bd9011574f", - "sha256:d4bf4d43077db55589ffc9009c0ba0a94fa4908b9586d6ccce2e0b164c86303c", - "sha256:d6a96eef20f639e6a97d23e57dd0c1b1069a7b4fd7027482a4c5c451cd7732f4", - "sha256:d9caa9d5e682102453d96a0ee10c7241b72859b01a941a397fd965f23b3e016b", - "sha256:dd1c8f6bd65d07d3810b90d02eba7997e32abbdf1277a481d698969e921a3be0", - "sha256:e31f0bb5928b793169b87e3d1e070f2342b22d5245c755e2b81caa29756246c3", - "sha256:ecb55251139706669fdec2ff073c98ef8e9a84473e51e716211b41aa0f18e656", - "sha256:ee5ec40fdd06d62fe5d4084bef4fd50fd4bb6bfd2bf519365f569dc470163ab0", - "sha256:f17e562de9edf691a42ddb1eb4a5541c20dd3f9e65b09ded2beb0799c0cf29bb", - "sha256:fdffbfb6832cd0b300995a2b08b8f6fa9f6e856d562800fea9182316d99c4e8e" - ], - "version": "==1.21.6" - }, - "packaging": { - "hashes": [ - "sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb", - "sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522" - ], - "version": "==21.3" - }, - "paramiko": { - "hashes": [ - "sha256:4f3e316fef2ac628b05097a637af35685183111d4bc1b5979bd397c2ab7b5898", - "sha256:7f36f4ba2c0d81d219f4595e35f70d56cc94f9ac40a6acdf51d6ca210ce65035" - ], - "version": "==2.7.2" - }, - "pycparser": { - "hashes": [ - "sha256:2d475327684562c3a96cc71adf7dc8c4f0565175cf86b6d7a404ff4c771f15f0", - "sha256:7582ad22678f0fcd81102833f60ef8d0e57288b6b5fb00323d101be910e35705" - ], - "version": "==2.20" - }, - "pynacl": { - "hashes": [ - "sha256:06cbb4d9b2c4bd3c8dc0d267416aaed79906e7b33f114ddbf0911969794b1cc4", - "sha256:11335f09060af52c97137d4ac54285bcb7df0cef29014a1a4efe64ac065434c4", - "sha256:2fe0fc5a2480361dcaf4e6e7cea00e078fcda07ba45f811b167e3f99e8cff574", - "sha256:30f9b96db44e09b3304f9ea95079b1b7316b2b4f3744fe3aaecccd95d547063d", - "sha256:4e10569f8cbed81cb7526ae137049759d2a8d57726d52c1a000a3ce366779634", - "sha256:511d269ee845037b95c9781aa702f90ccc36036f95d0f31373a6a79bd8242e25", - "sha256:537a7ccbea22905a0ab36ea58577b39d1fa9b1884869d173b5cf111f006f689f", - "sha256:54e9a2c849c742006516ad56a88f5c74bf2ce92c9f67435187c3c5953b346505", - "sha256:757250ddb3bff1eecd7e41e65f7f833a8405fede0194319f87899690624f2122", - "sha256:7757ae33dae81c300487591c68790dfb5145c7d03324000433d9a2c141f82af7", - "sha256:7c6092102219f59ff29788860ccb021e80fffd953920c4a8653889c029b2d420", - "sha256:8122ba5f2a2169ca5da936b2e5a511740ffb73979381b4229d9188f6dcb22f1f", - "sha256:9c4a7ea4fb81536c1b1f5cc44d54a296f96ae78c1ebd2311bd0b60be45a48d96", - "sha256:c914f78da4953b33d4685e3cdc7ce63401247a21425c16a39760e282075ac4a6", - "sha256:cd401ccbc2a249a47a3a1724c2918fcd04be1f7b54eb2a5a71ff915db0ac51c6", - "sha256:d452a6746f0a7e11121e64625109bc4468fc3100452817001dbe018bb8b08514", - "sha256:ea6841bc3a76fa4942ce00f3bda7d436fda21e2d91602b9e21b7ca9ecab8f3ff", - "sha256:f8851ab9041756003119368c1e6cd0b9c631f46d686b3904b18c0139f4419f80" - ], - "version": "==1.4.0" - }, - "pyparsing": { - "hashes": [ - "sha256:2b020ecf7d21b687f219b71ecad3631f644a47f01403fa1d1036b0c6416d70fb", - "sha256:5026bae9a10eeaefb61dab2f09052b9f4307d44aee4eda64b309723d8d206bbc" - ], - "version": "==3.0.9" - }, - "pyqt5": { - "hashes": [ - "sha256:2c309db3035093ea85f08029711d6fbcccf89eded7f8e4f788695d933cfd80a5" - ], - "version": "==5.12.2+dls1" - }, - "pyserial": { - "hashes": [ - "sha256:3c77e014170dfffbd816e6ffc205e9842efb10be9f58ec16d3e8675b4925cddb", - "sha256:c4451db6ba391ca6ca299fb3ec7bae67a5c55dde170964c7a14ceefec02f2cf0" - ], - "version": "==3.5" - }, - "pythonqwt": { - "hashes": [ - "sha256:1f13cc8b555a57f8fe0f806d6c2f6d847050e4d837649503932b81316d12788a", - "sha256:806d109a0f163ee37259516b498f9b2a711682efbb0dd60dff3c31f25007cbef" - ], - "version": "==0.5.5" - }, - "setuptools-scm": { - "extras": [ - "toml" - ], - "hashes": [ - "sha256:031e13af771d6f892b941adb6ea04545bbf91ebc5ce68c78aaf3fff6e1fb4844", - "sha256:7930f720905e03ccd1e1d821db521bff7ec2ac9cf0ceb6552dd73d24a45d3b02" - ], - "version": "==7.0.5" - }, - "six": { - "hashes": [ - "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926", - "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254" - ], - "version": "==1.16.0" - }, - "tomli": { - "hashes": [ - "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc", - "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f" - ], - "version": "==2.0.1" - }, - "typing-extensions": { - "hashes": [ - "sha256:1511434bb92bf8dd198c12b1cc812e800d4181cfcb867674e0f8279cc93087aa", - "sha256:16fa4864408f655d35ec496218b85f79b3437c829e93320c7c9215ccfd92489e" - ], - "markers": "python_version < '3.8'", - "version": "==4.4.0" - }, - "zipp": { - "hashes": [ - "sha256:3a7af91c3db40ec72dd9d154ae18e008c69efe8ca88dde4f9a731bb82fe2f9eb", - "sha256:972cfa31bc2fedd3fa838a51e9bc7e64b7fb725a8c00e7431554311f180e9980" - ], - "version": "==3.9.0" - } - }, - "develop": { - "alabaster": { - "hashes": [ - "sha256:446438bdcca0e05bd45ea2de1668c1d9b032e1a9154c2c259092d77031ddd359", - "sha256:a661d72d58e6ea8a57f7a86e37d86716863ee5e92788398526d58b26a4e4dc02" - ], - "version": "==0.7.12" - }, - "attrs": { - "hashes": [ - "sha256:29adc2665447e5191d0e7c568fde78b21f9672d344281d0c6e1ab085429b22b6", - "sha256:86efa402f67bf2df34f51a335487cf46b1ec130d02b8d39fd248abfd30da551c" - ], - "version": "==22.1.0" - }, - "babel": { - "hashes": [ - "sha256:1ad3eca1c885218f6dce2ab67291178944f810a10a9b5f3cb8382a5a232b64fe", - "sha256:5ef4b3226b0180dedded4229651c8b0e1a3a6a2837d45a073272f313e4cf97f6" - ], - "version": "==2.11.0" - }, - "bcrypt": { - "hashes": [ - "sha256:5b93c1726e50a93a033c36e5ca7fdcd29a5c7395af50a6892f5d9e7c6cfbfb29", - "sha256:63d4e3ff96188e5898779b6057878fecf3f11cfe6ec3b313ea09955d587ec7a7", - "sha256:81fec756feff5b6818ea7ab031205e1d323d8943d237303baca2c5f9c7846f34", - "sha256:a67fb841b35c28a59cebed05fbd3e80eea26e6d75851f0574a9273c80f3e9b55", - "sha256:c95d4cbebffafcdd28bd28bb4e25b31c50f6da605c81ffd9ad8a3d1b2ab7b1b6", - "sha256:cd1ea2ff3038509ea95f687256c46b79f5fc382ad0aa3664d200047546d511d1", - "sha256:cdcdcb3972027f83fe24a48b1e90ea4b584d35f1cc279d76de6fc4b13376239d" - ], - "version": "==3.2.0" - }, - "black": { - "hashes": [ - "sha256:0a12e4e1353819af41df998b02c6742643cfef58282915f781d0e4dd7a200411", - "sha256:0ad827325a3a634bae88ae7747db1a395d5ee02cf05d9aa7a9bd77dfb10e940c", - "sha256:32a4b17f644fc288c6ee2bafdf5e3b045f4eff84693ac069d87b1a347d861497", - "sha256:3b2c25f8dea5e8444bdc6788a2f543e1fb01494e144480bc17f806178378005e", - "sha256:4a098a69a02596e1f2a58a2a1c8d5a05d5a74461af552b371e82f9fa4ada8342", - "sha256:5107ea36b2b61917956d018bd25129baf9ad1125e39324a9b18248d362156a27", - "sha256:53198e28a1fb865e9fe97f88220da2e44df6da82b18833b588b1883b16bb5d41", - "sha256:5594efbdc35426e35a7defa1ea1a1cb97c7dbd34c0e49af7fb593a36bd45edab", - "sha256:5b879eb439094751185d1cfdca43023bc6786bd3c60372462b6f051efa6281a5", - "sha256:78dd85caaab7c3153054756b9fe8c611efa63d9e7aecfa33e533060cb14b6d16", - "sha256:792f7eb540ba9a17e8656538701d3eb1afcb134e3b45b71f20b25c77a8db7e6e", - "sha256:8ce13ffed7e66dda0da3e0b2eb1bdfc83f5812f66e09aca2b0978593ed636b6c", - "sha256:a05da0430bd5ced89176db098567973be52ce175a55677436a271102d7eaa3fe", - "sha256:a983526af1bea1e4cf6768e649990f28ee4f4137266921c2c3cee8116ae42ec3", - "sha256:bc4d4123830a2d190e9cc42a2e43570f82ace35c3aeb26a512a2102bce5af7ec", - "sha256:c3a73f66b6d5ba7288cd5d6dad9b4c9b43f4e8a4b789a94bf5abfb878c663eb3", - "sha256:ce957f1d6b78a8a231b18e0dd2d94a33d2ba738cd88a7fe64f53f659eea49fdd", - "sha256:cea1b2542d4e2c02c332e83150e41e3ca80dc0fb8de20df3c5e98e242156222c", - "sha256:d2c21d439b2baf7aa80d6dd4e3659259be64c6f49dfd0f32091063db0e006db4", - "sha256:d839150f61d09e7217f52917259831fe2b689f5c8e5e32611736351b89bb2a90", - "sha256:dd82842bb272297503cbec1a2600b6bfb338dae017186f8f215c8958f8acf869", - "sha256:e8166b7bfe5dcb56d325385bd1d1e0f635f24aae14b3ae437102dedc0c186747", - "sha256:e981e20ec152dfb3e77418fb616077937378b322d7b26aa1ff87717fb18b4875" - ], - "version": "==22.8.0" - }, - "certifi": { - "hashes": [ - "sha256:35824b4c3a97115964b408844d64aa14db1cc518f6562e8d7261699d1350a9e3", - "sha256:4ad3232f5e926d6718ec31cfc1fcadfde020920e278684144551c91769c7bc18" - ], - "version": "==2022.12.7" - }, - "cffi": { - "hashes": [ - "sha256:001bf3242a1bb04d985d63e138230802c6c8d4db3668fb545fb5005ddf5bb5ff", - "sha256:00789914be39dffba161cfc5be31b55775de5ba2235fe49aa28c148236c4e06b", - "sha256:028a579fc9aed3af38f4892bdcc7390508adabc30c6af4a6e4f611b0c680e6ac", - "sha256:14491a910663bf9f13ddf2bc8f60562d6bc5315c1f09c704937ef17293fb85b0", - "sha256:1cae98a7054b5c9391eb3249b86e0e99ab1e02bb0cc0575da191aedadbdf4384", - "sha256:2089ed025da3919d2e75a4d963d008330c96751127dd6f73c8dc0c65041b4c26", - "sha256:2d384f4a127a15ba701207f7639d94106693b6cd64173d6c8988e2c25f3ac2b6", - "sha256:337d448e5a725bba2d8293c48d9353fc68d0e9e4088d62a9571def317797522b", - "sha256:399aed636c7d3749bbed55bc907c3288cb43c65c4389964ad5ff849b6370603e", - "sha256:3b911c2dbd4f423b4c4fcca138cadde747abdb20d196c4a48708b8a2d32b16dd", - "sha256:3d311bcc4a41408cf5854f06ef2c5cab88f9fded37a3b95936c9879c1640d4c2", - "sha256:62ae9af2d069ea2698bf536dcfe1e4eed9090211dbaafeeedf5cb6c41b352f66", - "sha256:66e41db66b47d0d8672d8ed2708ba91b2f2524ece3dee48b5dfb36be8c2f21dc", - "sha256:675686925a9fb403edba0114db74e741d8181683dcf216be697d208857e04ca8", - "sha256:7e63cbcf2429a8dbfe48dcc2322d5f2220b77b2e17b7ba023d6166d84655da55", - "sha256:8a6c688fefb4e1cd56feb6c511984a6c4f7ec7d2a1ff31a10254f3c817054ae4", - "sha256:8c0ffc886aea5df6a1762d0019e9cb05f825d0eec1f520c51be9d198701daee5", - "sha256:95cd16d3dee553f882540c1ffe331d085c9e629499ceadfbda4d4fde635f4b7d", - "sha256:99f748a7e71ff382613b4e1acc0ac83bf7ad167fb3802e35e90d9763daba4d78", - "sha256:b8c78301cefcf5fd914aad35d3c04c2b21ce8629b5e4f4e45ae6812e461910fa", - "sha256:c420917b188a5582a56d8b93bdd8e0f6eca08c84ff623a4c16e809152cd35793", - "sha256:c43866529f2f06fe0edc6246eb4faa34f03fe88b64a0a9a942561c8e22f4b71f", - "sha256:cab50b8c2250b46fe738c77dbd25ce017d5e6fb35d3407606e7a4180656a5a6a", - "sha256:cef128cb4d5e0b3493f058f10ce32365972c554572ff821e175dbc6f8ff6924f", - "sha256:cf16e3cf6c0a5fdd9bc10c21687e19d29ad1fe863372b5543deaec1039581a30", - "sha256:e56c744aa6ff427a607763346e4170629caf7e48ead6921745986db3692f987f", - "sha256:e577934fc5f8779c554639376beeaa5657d54349096ef24abe8c74c5d9c117c3", - "sha256:f2b0fa0c01d8a0c7483afd9f31d7ecf2d71760ca24499c8697aeb5ca37dc090c" - ], - "version": "==1.14.0" - }, - "cfgv": { - "hashes": [ - "sha256:c6a0883f3917a037485059700b9e75da2464e6c27051014ad85ba6aaa5884426", - "sha256:f5a830efb9ce7a445376bb66ec94c638a9787422f96264c98edc6bdeed8ab736" - ], - "version": "==3.3.1" - }, - "charset-normalizer": { - "hashes": [ - "sha256:5a3d016c7c547f69d6f81fb0db9449ce888b418b5b9952cc5e6e66843e9dd845", - "sha256:83e9a75d1911279afd89352c68b45348559d1fc0506b054b346651b5e7fee29f" - ], - "version": "==2.1.1" - }, - "click": { - "hashes": [ - "sha256:7682dc8afb30297001674575ea00d1814d808d6a36af415a82bd481d37ba7b8e", - "sha256:bb4d8133cb15a609f44e8213d9b391b0809795062913b383c62be0ee95b1db48" - ], - "version": "==8.1.3" - }, - "coverage": { - "extras": [ - "toml" - ], - "hashes": [ - "sha256:027018943386e7b942fa832372ebc120155fd970837489896099f5cfa2890f79", - "sha256:11b990d520ea75e7ee8dcab5bc908072aaada194a794db9f6d7d5cfd19661e5a", - "sha256:12adf310e4aafddc58afdb04d686795f33f4d7a6fa67a7a9d4ce7d6ae24d949f", - "sha256:1431986dac3923c5945271f169f59c45b8802a114c8f548d611f2015133df77a", - "sha256:1ef221513e6f68b69ee9e159506d583d31aa3567e0ae84eaad9d6ec1107dddaa", - "sha256:20c8ac5386253717e5ccc827caad43ed66fea0efe255727b1053a8154d952398", - "sha256:2198ea6fc548de52adc826f62cb18554caedfb1d26548c1b7c88d8f7faa8f6ba", - "sha256:255758a1e3b61db372ec2736c8e2a1fdfaf563977eedbdf131de003ca5779b7d", - "sha256:265de0fa6778d07de30bcf4d9dc471c3dc4314a23a3c6603d356a3c9abc2dfcf", - "sha256:33a7da4376d5977fbf0a8ed91c4dffaaa8dbf0ddbf4c8eea500a2486d8bc4d7b", - "sha256:42eafe6778551cf006a7c43153af1211c3aaab658d4d66fa5fcc021613d02518", - "sha256:4433b90fae13f86fafff0b326453dd42fc9a639a0d9e4eec4d366436d1a41b6d", - "sha256:4a5375e28c5191ac38cca59b38edd33ef4cc914732c916f2929029b4bfb50795", - "sha256:4a8dbc1f0fbb2ae3de73eb0bdbb914180c7abfbf258e90b311dcd4f585d44bd2", - "sha256:59f53f1dc5b656cafb1badd0feb428c1e7bc19b867479ff72f7a9dd9b479f10e", - "sha256:5dbec3b9095749390c09ab7c89d314727f18800060d8d24e87f01fb9cfb40b32", - "sha256:633713d70ad6bfc49b34ead4060531658dc6dfc9b3eb7d8a716d5873377ab745", - "sha256:6b07130585d54fe8dff3d97b93b0e20290de974dc8177c320aeaf23459219c0b", - "sha256:6c4459b3de97b75e3bd6b7d4b7f0db13f17f504f3d13e2a7c623786289dd670e", - "sha256:6d4817234349a80dbf03640cec6109cd90cba068330703fa65ddf56b60223a6d", - "sha256:723e8130d4ecc8f56e9a611e73b31219595baa3bb252d539206f7bbbab6ffc1f", - "sha256:784f53ebc9f3fd0e2a3f6a78b2be1bd1f5575d7863e10c6e12504f240fd06660", - "sha256:7b6be138d61e458e18d8e6ddcddd36dd96215edfe5f1168de0b1b32635839b62", - "sha256:7ccf362abd726b0410bf8911c31fbf97f09f8f1061f8c1cf03dfc4b6372848f6", - "sha256:83516205e254a0cb77d2d7bb3632ee019d93d9f4005de31dca0a8c3667d5bc04", - "sha256:851cf4ff24062c6aec510a454b2584f6e998cada52d4cb58c5e233d07172e50c", - "sha256:8f830ed581b45b82451a40faabb89c84e1a998124ee4212d440e9c6cf70083e5", - "sha256:94e2565443291bd778421856bc975d351738963071e9b8839ca1fc08b42d4bef", - "sha256:95203854f974e07af96358c0b261f1048d8e1083f2de9b1c565e1be4a3a48cfc", - "sha256:97117225cdd992a9c2a5515db1f66b59db634f59d0679ca1fa3fe8da32749cae", - "sha256:98e8a10b7a314f454d9eff4216a9a94d143a7ee65018dd12442e898ee2310578", - "sha256:a1170fa54185845505fbfa672f1c1ab175446c887cce8212c44149581cf2d466", - "sha256:a6b7d95969b8845250586f269e81e5dfdd8ff828ddeb8567a4a2eaa7313460c4", - "sha256:a8fb6cf131ac4070c9c5a3e21de0f7dc5a0fbe8bc77c9456ced896c12fcdad91", - "sha256:af4fffaffc4067232253715065e30c5a7ec6faac36f8fc8d6f64263b15f74db0", - "sha256:b4a5be1748d538a710f87542f22c2cad22f80545a847ad91ce45e77417293eb4", - "sha256:b5604380f3415ba69de87a289a2b56687faa4fe04dbee0754bfcae433489316b", - "sha256:b9023e237f4c02ff739581ef35969c3739445fb059b060ca51771e69101efffe", - "sha256:bc8ef5e043a2af066fa8cbfc6e708d58017024dc4345a1f9757b329a249f041b", - "sha256:c4ed2820d919351f4167e52425e096af41bfabacb1857186c1ea32ff9983ed75", - "sha256:cca4435eebea7962a52bdb216dec27215d0df64cf27fc1dd538415f5d2b9da6b", - "sha256:d900bb429fdfd7f511f868cedd03a6bbb142f3f9118c09b99ef8dc9bf9643c3c", - "sha256:d9ecf0829c6a62b9b573c7bb6d4dcd6ba8b6f80be9ba4fc7ed50bf4ac9aecd72", - "sha256:dbdb91cd8c048c2b09eb17713b0c12a54fbd587d79adcebad543bc0cd9a3410b", - "sha256:de3001a203182842a4630e7b8d1a2c7c07ec1b45d3084a83d5d227a3806f530f", - "sha256:e07f4a4a9b41583d6eabec04f8b68076ab3cd44c20bd29332c6572dda36f372e", - "sha256:ef8674b0ee8cc11e2d574e3e2998aea5df5ab242e012286824ea3c6970580e53", - "sha256:f4f05d88d9a80ad3cac6244d36dd89a3c00abc16371769f1340101d3cb899fc3", - "sha256:f642e90754ee3e06b0e7e51bce3379590e76b7f76b708e1a71ff043f87025c84", - "sha256:fc2af30ed0d5ae0b1abdb4ebdce598eafd5b35397d4d75deb341a614d333d987" - ], - "version": "==6.5.0" - }, - "cryptography": { - "hashes": [ - "sha256:07bb7fbfb5de0980590ddfc7f13081520def06dc9ed214000ad4372fb4e3c7f6", - "sha256:18d90f4711bf63e2fb21e8c8e51ed8189438e6b35a6d996201ebd98a26abbbe6", - "sha256:1ed82abf16df40a60942a8c211251ae72858b25b7421ce2497c2eb7a1cee817c", - "sha256:22a38e96118a4ce3b97509443feace1d1011d0571fae81fc3ad35f25ba3ea999", - "sha256:2d69645f535f4b2c722cfb07a8eab916265545b3475fdb34e0be2f4ee8b0b15e", - "sha256:4a2d0e0acc20ede0f06ef7aa58546eee96d2592c00f450c9acb89c5879b61992", - "sha256:54b2605e5475944e2213258e0ab8696f4f357a31371e538ef21e8d61c843c28d", - "sha256:7075b304cd567694dc692ffc9747f3e9cb393cc4aa4fb7b9f3abd6f5c4e43588", - "sha256:7b7ceeff114c31f285528ba8b390d3e9cfa2da17b56f11d366769a807f17cbaa", - "sha256:7eba2cebca600a7806b893cb1d541a6e910afa87e97acf2021a22b32da1df52d", - "sha256:928185a6d1ccdb816e883f56ebe92e975a262d31cc536429041921f8cb5a62fd", - "sha256:9933f28f70d0517686bd7de36166dda42094eac49415459d9bdf5e7df3e0086d", - "sha256:a688ebcd08250eab5bb5bca318cc05a8c66de5e4171a65ca51db6bd753ff8953", - "sha256:abb5a361d2585bb95012a19ed9b2c8f412c5d723a9836418fab7aaa0243e67d2", - "sha256:c10c797ac89c746e488d2ee92bd4abd593615694ee17b2500578b63cad6b93a8", - "sha256:ced40344e811d6abba00295ced98c01aecf0c2de39481792d87af4fa58b7b4d6", - "sha256:d57e0cdc1b44b6cdf8af1d01807db06886f10177469312fbde8f44ccbb284bc9", - "sha256:d99915d6ab265c22873f1b4d6ea5ef462ef797b4140be4c9d8b179915e0985c6", - "sha256:eb80e8a1f91e4b7ef8b33041591e6d89b2b8e122d787e87eeb2b08da71bb16ad", - "sha256:ebeddd119f526bcf323a89f853afb12e225902a24d29b55fe18dd6fcb2838a76" - ], - "version": "==35.0.0" - }, - "distlib": { - "hashes": [ - "sha256:14bad2d9b04d3a36127ac97f30b12a19268f211063d8f8ee4f47108896e11b46", - "sha256:f35c4b692542ca110de7ef0bea44d73981caeb34ca0b9b6b2e6d7790dda8f80e" - ], - "version": "==0.3.6" - }, - "dls-pmaccontrol": { - "editable": true, - "path": "." - }, - "dls-pmaclib": { - "hashes": [ - "sha256:21592edab35fa61c6ea9823bd410d7dca2e070cdbbece37ea69c73c70fe3e699", - "sha256:bf464a268fa4141e0f3a203413af9f22db5d782b1adac579b306efae6daf250a" - ], - "version": "==3.0.2" - }, - "docutils": { - "hashes": [ - "sha256:686577d2e4c32380bb50cbb22f575ed742d58168cee37e99117a854bcd88f125", - "sha256:cf316c8370a737a022b72b56874f6602acf974a37a9fba42ec2876387549fc61" - ], - "version": "==0.17.1" - }, - "filelock": { - "hashes": [ - "sha256:7565f628ea56bfcd8e54e42bdc55da899c85c1abfe1b5bcfd147e9188cebb3b2", - "sha256:8df285554452285f79c035efb0c861eb33a4bcfa5b7a137016e32e6a90f9792c" - ], - "version": "==3.8.2" - }, - "flake8": { - "hashes": [ - "sha256:07528381786f2a6237b061f6e96610a4167b226cb926e2aa2b6b1d78057c576b", - "sha256:bf8fd333346d844f616e8d47905ef3a3384edae6b4e9beb0c5101e25e3110907" - ], - "version": "==3.9.2" - }, - "flake8-isort": { - "hashes": [ - "sha256:0951398c343c67f4933407adbbfb495d4df7c038650c5d05753a006efcfeb390", - "sha256:8c4ab431d87780d0c8336e9614e50ef11201bc848ef64ca017532dec39d4bf49" - ], - "version": "==5.0.3" - }, - "identify": { - "hashes": [ - "sha256:dce9e31fee7dbc45fea36a9e855c316b8fbf807e65a862f160840bb5a2bf5dfd", - "sha256:fb7c2feaeca6976a3ffa31ec3236a6911fbc51aec9acc111de2aed99f244ade2" - ], - "version": "==2.5.10" - }, - "idna": { - "hashes": [ - "sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4", - "sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2" - ], - "version": "==3.4" - }, - "imagesize": { - "hashes": [ - "sha256:0d8d18d08f840c19d0ee7ca1fd82490fdc3729b7ac93f49870406ddde8ef8d8b", - "sha256:69150444affb9cb0d5cc5a92b3676f0b2fb7cd9ae39e947a5e11a36b4497cd4a" - ], - "version": "==1.4.1" - }, - "importlib-metadata": { - "hashes": [ - "sha256:d5059f9f1e8e41f80e9c56c2ee58811450c31984dfa625329ffd7c0dad88a73b", - "sha256:d84d17e21670ec07990e1044a99efe8d615d860fd176fc29ef5c306068fda313" - ], - "markers": "python_version < '3.8'", - "version": "==5.1.0" - }, - "iniconfig": { - "hashes": [ - "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3", - "sha256:bc3af051d7d14b2ee5ef9969666def0cd1a000e121eaea580d4a313df4b37f32" - ], - "version": "==1.1.1" - }, - "isort": { - "hashes": [ - "sha256:dd8bbc5c0990f2a095d754e50360915f73b4c26fc82733eb5bfc6b48396af4d2", - "sha256:e486966fba83f25b8045f8dd7455b0a0d1e4de481e1d7ce4669902d9fb85e622" - ], - "version": "==5.11.2" - }, - "jinja2": { - "hashes": [ - "sha256:31351a702a408a9e7595a8fc6150fc3f43bb6bf7e319770cbc0db9df9437e852", - "sha256:6088930bfe239f0e6710546ab9c19c9ef35e29792895fed6e6e31a023a182a61" - ], - "version": "==3.1.2" - }, - "markupsafe": { - "hashes": [ - "sha256:0212a68688482dc52b2d45013df70d169f542b7394fc744c02a57374a4207003", - "sha256:089cf3dbf0cd6c100f02945abeb18484bd1ee57a079aefd52cffd17fba910b88", - "sha256:10c1bfff05d95783da83491be968e8fe789263689c02724e0c691933c52994f5", - "sha256:33b74d289bd2f5e527beadcaa3f401e0df0a89927c1559c8566c066fa4248ab7", - "sha256:3799351e2336dc91ea70b034983ee71cf2f9533cdff7c14c90ea126bfd95d65a", - "sha256:3ce11ee3f23f79dbd06fb3d63e2f6af7b12db1d46932fe7bd8afa259a5996603", - "sha256:421be9fbf0ffe9ffd7a378aafebbf6f4602d564d34be190fc19a193232fd12b1", - "sha256:43093fb83d8343aac0b1baa75516da6092f58f41200907ef92448ecab8825135", - "sha256:46d00d6cfecdde84d40e572d63735ef81423ad31184100411e6e3388d405e247", - "sha256:4a33dea2b688b3190ee12bd7cfa29d39c9ed176bda40bfa11099a3ce5d3a7ac6", - "sha256:4b9fe39a2ccc108a4accc2676e77da025ce383c108593d65cc909add5c3bd601", - "sha256:56442863ed2b06d19c37f94d999035e15ee982988920e12a5b4ba29b62ad1f77", - "sha256:671cd1187ed5e62818414afe79ed29da836dde67166a9fac6d435873c44fdd02", - "sha256:694deca8d702d5db21ec83983ce0bb4b26a578e71fbdbd4fdcd387daa90e4d5e", - "sha256:6a074d34ee7a5ce3effbc526b7083ec9731bb3cbf921bbe1d3005d4d2bdb3a63", - "sha256:6d0072fea50feec76a4c418096652f2c3238eaa014b2f94aeb1d56a66b41403f", - "sha256:6fbf47b5d3728c6aea2abb0589b5d30459e369baa772e0f37a0320185e87c980", - "sha256:7f91197cc9e48f989d12e4e6fbc46495c446636dfc81b9ccf50bb0ec74b91d4b", - "sha256:86b1f75c4e7c2ac2ccdaec2b9022845dbb81880ca318bb7a0a01fbf7813e3812", - "sha256:8dc1c72a69aa7e082593c4a203dcf94ddb74bb5c8a731e4e1eb68d031e8498ff", - "sha256:8e3dcf21f367459434c18e71b2a9532d96547aef8a871872a5bd69a715c15f96", - "sha256:8e576a51ad59e4bfaac456023a78f6b5e6e7651dcd383bcc3e18d06f9b55d6d1", - "sha256:96e37a3dc86e80bf81758c152fe66dbf60ed5eca3d26305edf01892257049925", - "sha256:97a68e6ada378df82bc9f16b800ab77cbf4b2fada0081794318520138c088e4a", - "sha256:99a2a507ed3ac881b975a2976d59f38c19386d128e7a9a18b7df6fff1fd4c1d6", - "sha256:a49907dd8420c5685cfa064a1335b6754b74541bbb3706c259c02ed65b644b3e", - "sha256:b09bf97215625a311f669476f44b8b318b075847b49316d3e28c08e41a7a573f", - "sha256:b7bd98b796e2b6553da7225aeb61f447f80a1ca64f41d83612e6139ca5213aa4", - "sha256:b87db4360013327109564f0e591bd2a3b318547bcef31b468a92ee504d07ae4f", - "sha256:bcb3ed405ed3222f9904899563d6fc492ff75cce56cba05e32eff40e6acbeaa3", - "sha256:d4306c36ca495956b6d568d276ac11fdd9c30a36f1b6eb928070dc5360b22e1c", - "sha256:d5ee4f386140395a2c818d149221149c54849dfcfcb9f1debfe07a8b8bd63f9a", - "sha256:dda30ba7e87fbbb7eab1ec9f58678558fd9a6b8b853530e176eabd064da81417", - "sha256:e04e26803c9c3851c931eac40c695602c6295b8d432cbe78609649ad9bd2da8a", - "sha256:e1c0b87e09fa55a220f058d1d49d3fb8df88fbfab58558f1198e08c1e1de842a", - "sha256:e72591e9ecd94d7feb70c1cbd7be7b3ebea3f548870aa91e2732960fa4d57a37", - "sha256:e8c843bbcda3a2f1e3c2ab25913c80a3c5376cd00c6e8c4a86a89a28c8dc5452", - "sha256:efc1913fd2ca4f334418481c7e595c00aad186563bbc1ec76067848c7ca0a933", - "sha256:f121a1420d4e173a5d96e47e9a0c0dcff965afdf1626d28de1460815f7c4ee7a", - "sha256:fc7b548b17d238737688817ab67deebb30e8073c95749d55538ed473130ec0c7" - ], - "version": "==2.1.1" - }, - "mccabe": { - "hashes": [ - "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42", - "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f" - ], - "version": "==0.6.1" - }, - "mock": { - "hashes": [ - "sha256:122fcb64ee37cfad5b3f48d7a7d51875d7031aaf3d8be7c42e2bee25044eee62", - "sha256:7d3fbbde18228f4ff2f1f119a45cdffa458b4c0dee32eb4d2bb2f82554bac7bc" - ], - "version": "==4.0.3" - }, - "mypy": { - "hashes": [ - "sha256:0714258640194d75677e86c786e80ccf294972cc76885d3ebbb560f11db0003d", - "sha256:0c8f3be99e8a8bd403caa8c03be619544bc2c77a7093685dcf308c6b109426c6", - "sha256:0cca5adf694af539aeaa6ac633a7afe9bbd760df9d31be55ab780b77ab5ae8bf", - "sha256:1c8cd4fb70e8584ca1ed5805cbc7c017a3d1a29fb450621089ffed3e99d1857f", - "sha256:1f7d1a520373e2272b10796c3ff721ea1a0712288cafaa95931e66aa15798813", - "sha256:209ee89fbb0deed518605edddd234af80506aec932ad28d73c08f1400ef80a33", - "sha256:26efb2fcc6b67e4d5a55561f39176821d2adf88f2745ddc72751b7890f3194ad", - "sha256:37bd02ebf9d10e05b00d71302d2c2e6ca333e6c2a8584a98c00e038db8121f05", - "sha256:3a700330b567114b673cf8ee7388e949f843b356a73b5ab22dd7cff4742a5297", - "sha256:3c0165ba8f354a6d9881809ef29f1a9318a236a6d81c690094c5df32107bde06", - "sha256:3d80e36b7d7a9259b740be6d8d906221789b0d836201af4234093cae89ced0cd", - "sha256:4175593dc25d9da12f7de8de873a33f9b2b8bdb4e827a7cae952e5b1a342e243", - "sha256:4307270436fd7694b41f913eb09210faff27ea4979ecbcd849e57d2da2f65305", - "sha256:5e80e758243b97b618cdf22004beb09e8a2de1af481382e4d84bc52152d1c476", - "sha256:641411733b127c3e0dab94c45af15fea99e4468f99ac88b39efb1ad677da5711", - "sha256:652b651d42f155033a1967739788c436491b577b6a44e4c39fb340d0ee7f0d70", - "sha256:6d7464bac72a85cb3491c7e92b5b62f3dcccb8af26826257760a552a5e244aa5", - "sha256:74e259b5c19f70d35fcc1ad3d56499065c601dfe94ff67ae48b85596b9ec1461", - "sha256:7d17e0a9707d0772f4a7b878f04b4fd11f6f5bcb9b3813975a9b13c9332153ab", - "sha256:901c2c269c616e6cb0998b33d4adbb4a6af0ac4ce5cd078afd7bc95830e62c1c", - "sha256:98e781cd35c0acf33eb0295e8b9c55cdbef64fcb35f6d3aa2186f289bed6e80d", - "sha256:a12c56bf73cdab116df96e4ff39610b92a348cc99a1307e1da3c3768bbb5b135", - "sha256:ac6e503823143464538efda0e8e356d871557ef60ccd38f8824a4257acc18d93", - "sha256:b8472f736a5bfb159a5e36740847808f6f5b659960115ff29c7cecec1741c648", - "sha256:b86ce2c1866a748c0f6faca5232059f881cda6dda2a893b9a8373353cfe3715a", - "sha256:bc9ec663ed6c8f15f4ae9d3c04c989b744436c16d26580eaa760ae9dd5d662eb", - "sha256:c9166b3f81a10cdf9b49f2d594b21b31adadb3d5e9db9b834866c3258b695be3", - "sha256:d13674f3fb73805ba0c45eb6c0c3053d218aa1f7abead6e446d474529aafc372", - "sha256:de32edc9b0a7e67c2775e574cb061a537660e51210fbf6006b0b36ea695ae9bb", - "sha256:e62ebaad93be3ad1a828a11e90f0e76f15449371ffeecca4a0a0b9adc99abcef" - ], - "version": "==0.991" - }, - "mypy-extensions": { - "hashes": [ - "sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d", - "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8" - ], - "version": "==0.4.3" - }, - "nodeenv": { - "hashes": [ - "sha256:27083a7b96a25f2f5e1d8cb4b6317ee8aeda3bdd121394e5ac54e498028a042e", - "sha256:e0e7f7dfb85fc5394c6fe1e8fa98131a2473e04311a45afb6508f7cf1836fa2b" - ], - "version": "==1.7.0" - }, - "numpy": { - "hashes": [ - "sha256:1dbe1c91269f880e364526649a52eff93ac30035507ae980d2fed33aaee633ac", - "sha256:357768c2e4451ac241465157a3e929b265dfac85d9214074985b1786244f2ef3", - "sha256:3820724272f9913b597ccd13a467cc492a0da6b05df26ea09e78b171a0bb9da6", - "sha256:4391bd07606be175aafd267ef9bea87cf1b8210c787666ce82073b05f202add1", - "sha256:4aa48afdce4660b0076a00d80afa54e8a97cd49f457d68a4342d188a09451c1a", - "sha256:58459d3bad03343ac4b1b42ed14d571b8743dc80ccbf27444f266729df1d6f5b", - "sha256:5c3c8def4230e1b959671eb959083661b4a0d2e9af93ee339c7dada6759a9470", - "sha256:5f30427731561ce75d7048ac254dbe47a2ba576229250fb60f0fb74db96501a1", - "sha256:643843bcc1c50526b3a71cd2ee561cf0d8773f062c8cbaf9ffac9fdf573f83ab", - "sha256:67c261d6c0a9981820c3a149d255a76918278a6b03b6a036800359aba1256d46", - "sha256:67f21981ba2f9d7ba9ade60c9e8cbaa8cf8e9ae51673934480e45cf55e953673", - "sha256:6aaf96c7f8cebc220cdfc03f1d5a31952f027dda050e5a703a0d1c396075e3e7", - "sha256:7c4068a8c44014b2d55f3c3f574c376b2494ca9cc73d2f1bd692382b6dffe3db", - "sha256:7c7e5fa88d9ff656e067876e4736379cc962d185d5cd808014a8a928d529ef4e", - "sha256:7f5ae4f304257569ef3b948810816bc87c9146e8c446053539947eedeaa32786", - "sha256:82691fda7c3f77c90e62da69ae60b5ac08e87e775b09813559f8901a88266552", - "sha256:8737609c3bbdd48e380d463134a35ffad3b22dc56295eff6f79fd85bd0eeeb25", - "sha256:9f411b2c3f3d76bba0865b35a425157c5dcf54937f82bbeb3d3c180789dd66a6", - "sha256:a6be4cb0ef3b8c9250c19cc122267263093eee7edd4e3fa75395dfda8c17a8e2", - "sha256:bcb238c9c96c00d3085b264e5c1a1207672577b93fa666c3b14a45240b14123a", - "sha256:bf2ec4b75d0e9356edea834d1de42b31fe11f726a81dfb2c2112bc1eaa508fcf", - "sha256:d136337ae3cc69aa5e447e78d8e1514be8c3ec9b54264e680cf0b4bd9011574f", - "sha256:d4bf4d43077db55589ffc9009c0ba0a94fa4908b9586d6ccce2e0b164c86303c", - "sha256:d6a96eef20f639e6a97d23e57dd0c1b1069a7b4fd7027482a4c5c451cd7732f4", - "sha256:d9caa9d5e682102453d96a0ee10c7241b72859b01a941a397fd965f23b3e016b", - "sha256:dd1c8f6bd65d07d3810b90d02eba7997e32abbdf1277a481d698969e921a3be0", - "sha256:e31f0bb5928b793169b87e3d1e070f2342b22d5245c755e2b81caa29756246c3", - "sha256:ecb55251139706669fdec2ff073c98ef8e9a84473e51e716211b41aa0f18e656", - "sha256:ee5ec40fdd06d62fe5d4084bef4fd50fd4bb6bfd2bf519365f569dc470163ab0", - "sha256:f17e562de9edf691a42ddb1eb4a5541c20dd3f9e65b09ded2beb0799c0cf29bb", - "sha256:fdffbfb6832cd0b300995a2b08b8f6fa9f6e856d562800fea9182316d99c4e8e" - ], - "version": "==1.21.6" - }, - "packaging": { - "hashes": [ - "sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb", - "sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522" - ], - "version": "==21.3" - }, - "paramiko": { - "hashes": [ - "sha256:4f3e316fef2ac628b05097a637af35685183111d4bc1b5979bd397c2ab7b5898", - "sha256:7f36f4ba2c0d81d219f4595e35f70d56cc94f9ac40a6acdf51d6ca210ce65035" - ], - "version": "==2.7.2" - }, - "pathspec": { - "hashes": [ - "sha256:46846318467efc4556ccfd27816e004270a9eeeeb4d062ce5e6fc7a87c573f93", - "sha256:7ace6161b621d31e7902eb6b5ae148d12cfd23f4a249b9ffb6b9fee12084323d" - ], - "version": "==0.10.1" - }, - "pipdeptree": { - "hashes": [ - "sha256:30699521e1c5861b08d29d92398f67e9a5d7f613092257fff2a8bde3c948e05b", - "sha256:fc0ffc6fd69f6f19e68bfd7722e5b4f66cc2b49a1be42ac7a3e8b4fd9f469370" - ], - "version": "==2.3.1" - }, - "platformdirs": { - "hashes": [ - "sha256:027d8e83a2d7de06bbac4e5ef7e023c02b863d7ea5d079477e722bb41ab25788", - "sha256:58c8abb07dcb441e6ee4b11d8df0ac856038f944ab98b7be6b27b2a3c7feef19" - ], - "version": "==2.5.2" - }, - "pluggy": { - "hashes": [ - "sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159", - "sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3" - ], - "version": "==1.0.0" - }, - "pre-commit": { - "hashes": [ - "sha256:51a5ba7c480ae8072ecdb6933df22d2f812dc897d5fe848778116129a681aac7", - "sha256:a978dac7bc9ec0bcee55c18a277d553b0f419d259dadb4b9418ff2d00eb43959" - ], - "version": "==2.20.0" - }, - "py": { - "hashes": [ - "sha256:51c75c4126074b472f746a24399ad32f6053d1b34b68d2fa41e558e6f4a98719", - "sha256:607c53218732647dff4acdfcd50cb62615cedf612e72d1724fb1a0cc6405b378" - ], - "version": "==1.11.0" - }, - "pycodestyle": { - "hashes": [ - "sha256:514f76d918fcc0b55c6680472f0a37970994e07bbb80725808c17089be302068", - "sha256:c389c1d06bf7904078ca03399a4816f974a1d590090fecea0c63ec26ebaf1cef" - ], - "version": "==2.7.0" - }, - "pycparser": { - "hashes": [ - "sha256:2d475327684562c3a96cc71adf7dc8c4f0565175cf86b6d7a404ff4c771f15f0", - "sha256:7582ad22678f0fcd81102833f60ef8d0e57288b6b5fb00323d101be910e35705" - ], - "version": "==2.20" - }, - "pyflakes": { - "hashes": [ - "sha256:7893783d01b8a89811dd72d7dfd4d84ff098e5eed95cfa8905b22bbffe52efc3", - "sha256:f5bc8ecabc05bb9d291eb5203d6810b49040f6ff446a756326104746cc00c1db" - ], - "version": "==2.3.1" - }, - "pygments": { - "hashes": [ - "sha256:56a8508ae95f98e2b9bdf93a6be5ae3f7d8af858b43e02c5a2ff083726be40c1", - "sha256:f643f331ab57ba3c9d89212ee4a2dabc6e94f117cf4eefde99a0574720d14c42" - ], - "version": "==2.13.0" - }, - "pynacl": { - "hashes": [ - "sha256:06cbb4d9b2c4bd3c8dc0d267416aaed79906e7b33f114ddbf0911969794b1cc4", - "sha256:11335f09060af52c97137d4ac54285bcb7df0cef29014a1a4efe64ac065434c4", - "sha256:2fe0fc5a2480361dcaf4e6e7cea00e078fcda07ba45f811b167e3f99e8cff574", - "sha256:30f9b96db44e09b3304f9ea95079b1b7316b2b4f3744fe3aaecccd95d547063d", - "sha256:4e10569f8cbed81cb7526ae137049759d2a8d57726d52c1a000a3ce366779634", - "sha256:511d269ee845037b95c9781aa702f90ccc36036f95d0f31373a6a79bd8242e25", - "sha256:537a7ccbea22905a0ab36ea58577b39d1fa9b1884869d173b5cf111f006f689f", - "sha256:54e9a2c849c742006516ad56a88f5c74bf2ce92c9f67435187c3c5953b346505", - "sha256:757250ddb3bff1eecd7e41e65f7f833a8405fede0194319f87899690624f2122", - "sha256:7757ae33dae81c300487591c68790dfb5145c7d03324000433d9a2c141f82af7", - "sha256:7c6092102219f59ff29788860ccb021e80fffd953920c4a8653889c029b2d420", - "sha256:8122ba5f2a2169ca5da936b2e5a511740ffb73979381b4229d9188f6dcb22f1f", - "sha256:9c4a7ea4fb81536c1b1f5cc44d54a296f96ae78c1ebd2311bd0b60be45a48d96", - "sha256:c914f78da4953b33d4685e3cdc7ce63401247a21425c16a39760e282075ac4a6", - "sha256:cd401ccbc2a249a47a3a1724c2918fcd04be1f7b54eb2a5a71ff915db0ac51c6", - "sha256:d452a6746f0a7e11121e64625109bc4468fc3100452817001dbe018bb8b08514", - "sha256:ea6841bc3a76fa4942ce00f3bda7d436fda21e2d91602b9e21b7ca9ecab8f3ff", - "sha256:f8851ab9041756003119368c1e6cd0b9c631f46d686b3904b18c0139f4419f80" - ], - "version": "==1.4.0" - }, - "pyparsing": { - "hashes": [ - "sha256:2b020ecf7d21b687f219b71ecad3631f644a47f01403fa1d1036b0c6416d70fb", - "sha256:5026bae9a10eeaefb61dab2f09052b9f4307d44aee4eda64b309723d8d206bbc" - ], - "version": "==3.0.9" - }, - "pyqt5": { - "hashes": [ - "sha256:2c309db3035093ea85f08029711d6fbcccf89eded7f8e4f788695d933cfd80a5" - ], - "version": "==5.12.2+dls1" - }, - "pyserial": { - "hashes": [ - "sha256:3c77e014170dfffbd816e6ffc205e9842efb10be9f58ec16d3e8675b4925cddb", - "sha256:c4451db6ba391ca6ca299fb3ec7bae67a5c55dde170964c7a14ceefec02f2cf0" - ], - "version": "==3.5" - }, - "pytest": { - "hashes": [ - "sha256:1377bda3466d70b55e3f5cecfa55bb7cfcf219c7964629b967c37cf0bda818b7", - "sha256:4f365fec2dff9c1162f834d9f18af1ba13062db0c708bf7b946f8a5c76180c39" - ], - "version": "==7.1.3" - }, - "pytest-cov": { - "hashes": [ - "sha256:2feb1b751d66a8bd934e5edfa2e961d11309dc37b73b0eabe73b5945fee20f6b", - "sha256:996b79efde6433cdbd0088872dbc5fb3ed7fe1578b68cdbba634f14bb8dd0470" - ], - "version": "==4.0.0" - }, - "pythonqwt": { - "hashes": [ - "sha256:1f13cc8b555a57f8fe0f806d6c2f6d847050e4d837649503932b81316d12788a", - "sha256:806d109a0f163ee37259516b498f9b2a711682efbb0dd60dff3c31f25007cbef" - ], - "version": "==0.5.5" - }, - "pytz": { - "hashes": [ - "sha256:2c0784747071402c6e99f0bafdb7da0fa22645f06554c7ae06bf6358897e9c91", - "sha256:48ce799d83b6f8aab2020e369b627446696619e79645419610b9facd909b3174" - ], - "version": "==2022.4" - }, - "pyyaml": { - "hashes": [ - "sha256:01b45c0191e6d66c470b6cf1b9531a771a83c1c4208272ead47a3ae4f2f603bf", - "sha256:0283c35a6a9fbf047493e3a0ce8d79ef5030852c51e9d911a27badfde0605293", - "sha256:055d937d65826939cb044fc8c9b08889e8c743fdc6a32b33e2390f66013e449b", - "sha256:07751360502caac1c067a8132d150cf3d61339af5691fe9e87803040dbc5db57", - "sha256:0b4624f379dab24d3725ffde76559cff63d9ec94e1736b556dacdfebe5ab6d4b", - "sha256:0ce82d761c532fe4ec3f87fc45688bdd3a4c1dc5e0b4a19814b9009a29baefd4", - "sha256:1e4747bc279b4f613a09eb64bba2ba602d8a6664c6ce6396a4d0cd413a50ce07", - "sha256:213c60cd50106436cc818accf5baa1aba61c0189ff610f64f4a3e8c6726218ba", - "sha256:231710d57adfd809ef5d34183b8ed1eeae3f76459c18fb4a0b373ad56bedcdd9", - "sha256:277a0ef2981ca40581a47093e9e2d13b3f1fbbeffae064c1d21bfceba2030287", - "sha256:2cd5df3de48857ed0544b34e2d40e9fac445930039f3cfe4bcc592a1f836d513", - "sha256:40527857252b61eacd1d9af500c3337ba8deb8fc298940291486c465c8b46ec0", - "sha256:432557aa2c09802be39460360ddffd48156e30721f5e8d917f01d31694216782", - "sha256:473f9edb243cb1935ab5a084eb238d842fb8f404ed2193a915d1784b5a6b5fc0", - "sha256:48c346915c114f5fdb3ead70312bd042a953a8ce5c7106d5bfb1a5254e47da92", - "sha256:50602afada6d6cbfad699b0c7bb50d5ccffa7e46a3d738092afddc1f9758427f", - "sha256:68fb519c14306fec9720a2a5b45bc9f0c8d1b9c72adf45c37baedfcd949c35a2", - "sha256:77f396e6ef4c73fdc33a9157446466f1cff553d979bd00ecb64385760c6babdc", - "sha256:81957921f441d50af23654aa6c5e5eaf9b06aba7f0a19c18a538dc7ef291c5a1", - "sha256:819b3830a1543db06c4d4b865e70ded25be52a2e0631ccd2f6a47a2822f2fd7c", - "sha256:897b80890765f037df3403d22bab41627ca8811ae55e9a722fd0392850ec4d86", - "sha256:98c4d36e99714e55cfbaaee6dd5badbc9a1ec339ebfc3b1f52e293aee6bb71a4", - "sha256:9df7ed3b3d2e0ecfe09e14741b857df43adb5a3ddadc919a2d94fbdf78fea53c", - "sha256:9fa600030013c4de8165339db93d182b9431076eb98eb40ee068700c9c813e34", - "sha256:a80a78046a72361de73f8f395f1f1e49f956c6be882eed58505a15f3e430962b", - "sha256:afa17f5bc4d1b10afd4466fd3a44dc0e245382deca5b3c353d8b757f9e3ecb8d", - "sha256:b3d267842bf12586ba6c734f89d1f5b871df0273157918b0ccefa29deb05c21c", - "sha256:b5b9eccad747aabaaffbc6064800670f0c297e52c12754eb1d976c57e4f74dcb", - "sha256:bfaef573a63ba8923503d27530362590ff4f576c626d86a9fed95822a8255fd7", - "sha256:c5687b8d43cf58545ade1fe3e055f70eac7a5a1a0bf42824308d868289a95737", - "sha256:cba8c411ef271aa037d7357a2bc8f9ee8b58b9965831d9e51baf703280dc73d3", - "sha256:d15a181d1ecd0d4270dc32edb46f7cb7733c7c508857278d3d378d14d606db2d", - "sha256:d4b0ba9512519522b118090257be113b9468d804b19d63c71dbcf4a48fa32358", - "sha256:d4db7c7aef085872ef65a8fd7d6d09a14ae91f691dec3e87ee5ee0539d516f53", - "sha256:d4eccecf9adf6fbcc6861a38015c2a64f38b9d94838ac1810a9023a0609e1b78", - "sha256:d67d839ede4ed1b28a4e8909735fc992a923cdb84e618544973d7dfc71540803", - "sha256:daf496c58a8c52083df09b80c860005194014c3698698d1a57cbcfa182142a3a", - "sha256:dbad0e9d368bb989f4515da330b88a057617d16b6a8245084f1b05400f24609f", - "sha256:e61ceaab6f49fb8bdfaa0f92c4b57bcfbea54c09277b1b4f7ac376bfb7a7c174", - "sha256:f84fbc98b019fef2ee9a1cb3ce93e3187a6df0b2538a651bfb890254ba9f90b5" - ], - "version": "==6.0" - }, - "requests": { - "hashes": [ - "sha256:7c5599b102feddaa661c826c56ab4fee28bfd17f5abca1ebbe3e7f19d7c97983", - "sha256:8fefa2a1a1365bf5520aac41836fbee479da67864514bdb821f31ce07ce65349" - ], - "version": "==2.28.1" - }, - "setuptools-scm": { - "extras": [ - "toml" - ], - "hashes": [ - "sha256:031e13af771d6f892b941adb6ea04545bbf91ebc5ce68c78aaf3fff6e1fb4844", - "sha256:7930f720905e03ccd1e1d821db521bff7ec2ac9cf0ceb6552dd73d24a45d3b02" - ], - "version": "==7.0.5" - }, - "six": { - "hashes": [ - "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926", - "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254" - ], - "version": "==1.16.0" - }, - "snowballstemmer": { - "hashes": [ - "sha256:09b16deb8547d3412ad7b590689584cd0fe25ec8db3be37788be3810cbf19cb1", - "sha256:c8e1716e83cc398ae16824e5572ae04e0d9fc2c6b985fb0f900f5f0c96ecba1a" - ], - "version": "==2.2.0" - }, - "sphinx": { - "hashes": [ - "sha256:7bf8ca9637a4ee15af412d1a1d9689fec70523a68ca9bb9127c2f3eeb344e2e6", - "sha256:ebf612653238bcc8f4359627a9b7ce44ede6fdd75d9d30f68255c7383d3a6226" - ], - "version": "==4.5.0" - }, - "sphinx-rtd-theme": { - "hashes": [ - "sha256:4d35a56f4508cfee4c4fb604373ede6feae2a306731d533f409ef5c3496fdbd8", - "sha256:eec6d497e4c2195fa0e8b2016b337532b8a699a68bcb22a512870e16925c6a5c" - ], - "version": "==1.0.0" - }, - "sphinx-rtd-theme-github-versions": { - "hashes": [ - "sha256:0df27ae9a9cd902468c808dbee5a43f4db8ce43cbcf2ecc78d2fe47698bb0ded", - "sha256:23018e51a5d27ef4f69dd86314f73b19088f2cfd91c74a24db1517832233dc07" - ], - "version": "==1.1" - }, - "sphinxcontrib-applehelp": { - "hashes": [ - "sha256:806111e5e962be97c29ec4c1e7fe277bfd19e9652fb1a4392105b43e01af885a", - "sha256:a072735ec80e7675e3f432fcae8610ecf509c5f1869d17e2eecff44389cdbc58" - ], - "version": "==1.0.2" - }, - "sphinxcontrib-devhelp": { - "hashes": [ - "sha256:8165223f9a335cc1af7ffe1ed31d2871f325254c0423bc0c4c7cd1c1e4734a2e", - "sha256:ff7f1afa7b9642e7060379360a67e9c41e8f3121f2ce9164266f61b9f4b338e4" - ], - "version": "==1.0.2" - }, - "sphinxcontrib-htmlhelp": { - "hashes": [ - "sha256:d412243dfb797ae3ec2b59eca0e52dac12e75a241bf0e4eb861e450d06c6ed07", - "sha256:f5f8bb2d0d629f398bf47d0d69c07bc13b65f75a81ad9e2f71a63d4b7a2f6db2" - ], - "version": "==2.0.0" - }, - "sphinxcontrib-jsmath": { - "hashes": [ - "sha256:2ec2eaebfb78f3f2078e73666b1415417a116cc848b72e5172e596c871103178", - "sha256:a9925e4a4587247ed2191a22df5f6970656cb8ca2bd6284309578f2153e0c4b8" - ], - "version": "==1.0.1" - }, - "sphinxcontrib-qthelp": { - "hashes": [ - "sha256:4c33767ee058b70dba89a6fc5c1892c0d57a54be67ddd3e7875a18d14cba5a72", - "sha256:bd9fc24bcb748a8d51fd4ecaade681350aa63009a347a8c14e637895444dfab6" - ], - "version": "==1.0.3" - }, - "sphinxcontrib-serializinghtml": { - "hashes": [ - "sha256:352a9a00ae864471d3a7ead8d7d79f5fc0b57e8b3f95e9867eb9eb28999b92fd", - "sha256:aa5f6de5dfdf809ef505c4895e51ef5c9eac17d0f287933eb49ec495280b6952" - ], - "version": "==1.1.5" - }, - "toml": { - "hashes": [ - "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b", - "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f" - ], - "version": "==0.10.2" - }, - "tomli": { - "hashes": [ - "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc", - "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f" - ], - "version": "==2.0.1" - }, - "tox": { - "hashes": [ - "sha256:44f3c347c68c2c68799d7d44f1808f9d396fc8a1a500cbc624253375c7ae107e", - "sha256:bf037662d7c740d15c9924ba23bb3e587df20598697bb985ac2b49bdc2d847f6" - ], - "version": "==3.26.0" - }, - "typed-ast": { - "hashes": [ - "sha256:0261195c2062caf107831e92a76764c81227dae162c4f75192c0d489faf751a2", - "sha256:0fdbcf2fef0ca421a3f5912555804296f0b0960f0418c440f5d6d3abb549f3e1", - "sha256:183afdf0ec5b1b211724dfef3d2cad2d767cbefac291f24d69b00546c1837fb6", - "sha256:211260621ab1cd7324e0798d6be953d00b74e0428382991adfddb352252f1d62", - "sha256:267e3f78697a6c00c689c03db4876dd1efdfea2f251a5ad6555e82a26847b4ac", - "sha256:2efae9db7a8c05ad5547d522e7dbe62c83d838d3906a3716d1478b6c1d61388d", - "sha256:370788a63915e82fd6f212865a596a0fefcbb7d408bbbb13dea723d971ed8bdc", - "sha256:39e21ceb7388e4bb37f4c679d72707ed46c2fbf2a5609b8b8ebc4b067d977df2", - "sha256:3e123d878ba170397916557d31c8f589951e353cc95fb7f24f6bb69adc1a8a97", - "sha256:4879da6c9b73443f97e731b617184a596ac1235fe91f98d279a7af36c796da35", - "sha256:4e964b4ff86550a7a7d56345c7864b18f403f5bd7380edf44a3c1fb4ee7ac6c6", - "sha256:639c5f0b21776605dd6c9dbe592d5228f021404dafd377e2b7ac046b0349b1a1", - "sha256:669dd0c4167f6f2cd9f57041e03c3c2ebf9063d0757dc89f79ba1daa2bfca9d4", - "sha256:6778e1b2f81dfc7bc58e4b259363b83d2e509a65198e85d5700dfae4c6c8ff1c", - "sha256:683407d92dc953c8a7347119596f0b0e6c55eb98ebebd9b23437501b28dcbb8e", - "sha256:79b1e0869db7c830ba6a981d58711c88b6677506e648496b1f64ac7d15633aec", - "sha256:7d5d014b7daa8b0bf2eaef684295acae12b036d79f54178b92a2b6a56f92278f", - "sha256:98f80dee3c03455e92796b58b98ff6ca0b2a6f652120c263efdba4d6c5e58f72", - "sha256:a94d55d142c9265f4ea46fab70977a1944ecae359ae867397757d836ea5a3f47", - "sha256:a9916d2bb8865f973824fb47436fa45e1ebf2efd920f2b9f99342cb7fab93f72", - "sha256:c542eeda69212fa10a7ada75e668876fdec5f856cd3d06829e6aa64ad17c8dfe", - "sha256:cf4afcfac006ece570e32d6fa90ab74a17245b83dfd6655a6f68568098345ff6", - "sha256:ebd9d7f80ccf7a82ac5f88c521115cc55d84e35bf8b446fcd7836eb6b98929a3", - "sha256:ed855bbe3eb3715fca349c80174cfcfd699c2f9de574d40527b8429acae23a66" - ], - "markers": "python_version < '3.8' and implementation_name == 'cpython'", - "version": "==1.5.4" - }, - "types-mock": { - "hashes": [ - "sha256:4535fbb3912b88a247d43cdb41db0c8b2e187138986f6f01a989717e56105848", - "sha256:a849bc2d966063f4946013bf404822ee2b96f77a8dccda4174b70ab61c5293fe" - ], - "version": "==4.0.15" - }, - "typing-extensions": { - "hashes": [ - "sha256:1511434bb92bf8dd198c12b1cc812e800d4181cfcb867674e0f8279cc93087aa", - "sha256:16fa4864408f655d35ec496218b85f79b3437c829e93320c7c9215ccfd92489e" - ], - "markers": "python_version < '3.8'", - "version": "==4.4.0" - }, - "urllib3": { - "hashes": [ - "sha256:3fa96cf423e6987997fc326ae8df396db2a8b7c667747d47ddd8ecba91f4a74e", - "sha256:b930dd878d5a8afb066a637fbb35144fe7901e3b209d1cd4f524bd0e9deee997" - ], - "version": "==1.26.12" - }, - "virtualenv": { - "hashes": [ - "sha256:0ef5be6d07181946891f5abc8047fda8bc2f0b4b9bf222c64e6e8963baee76db", - "sha256:635b272a8e2f77cb051946f46c60a54ace3cb5e25568228bd6b57fc70eca9ff3" - ], - "version": "==20.16.2" - }, - "zipp": { - "hashes": [ - "sha256:3a7af91c3db40ec72dd9d154ae18e008c69efe8ca88dde4f9a731bb82fe2f9eb", - "sha256:972cfa31bc2fedd3fa838a51e9bc7e64b7fb725a8c00e7431554311f180e9980" - ], - "version": "==3.9.0" - } - } -} diff --git a/pyproject.toml b/pyproject.toml index 5927ea7..4f707d9 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -7,18 +7,17 @@ name = "dls-pmac-control" classifiers = [ "Development Status :: 3 - Alpha", "License :: OSI Approved :: Apache Software License", - "Programming Language :: Python :: 3.7", - "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", ] description = "GUI for low level control and monitoring of turbo pmac and power pmac motion controllers" -dependencies = [] # Add project dependencies here, e.g. ["click", "numpy"] +dependencies = ["dls-pmaclib >= 3.0.1", "numpy", "pyqt5 <6.0", "pythonqwt"] dynamic = ["version"] license.file = "LICENSE" readme = "README.md" -requires-python = ">=3.7" +requires-python = ">=3.9" [project.optional-dependencies] dev = [ diff --git a/setup.cfg b/setup.cfg deleted file mode 100644 index d6bb0f0..0000000 --- a/setup.cfg +++ /dev/null @@ -1,141 +0,0 @@ -[metadata] - -name = dls_pmaccontrol -description = Delta Tau pmac control utility -url = https://github.com/DiamondLightSource/dls-pmac-control -author = Ulrik Kofoed Pederson -maintainer = Giles Knap -author_email = giles.knap@diamond.ac.uk -license = Apache License 2.0 -long_description = file: README.rst -long_description_content_type = text/x-rst -classifiers = - License :: OSI Approved :: Apache Software License - Programming Language :: Python :: 3.8 - Programming Language :: Python :: 3.9 - Programming Language :: Python :: 3.10 - -[options] -python_requires = >=3.7 -packages = find: -# =src is interpreted as {"": "src"} -# as per recommendation here https://hynek.me/articles/testing-packaging/ -package_dir = - =src - -setup_requires = - setuptools_scm[toml]>=6.2 - -# Specify any package dependencies below. -include_package_data = True -install_requires = - # dls-pmaclib @ git+https://github.com/DiamondLightSource/dls-pmac-lib.git@5b6acbfb1ec71ac50957c37e761d76529b16380f - # dls-pmaclib @ https://github.com/DiamondLightSource/dls-pmac-lib/archive/refs/tags/3.0.0.zip - dls-pmaclib >= 3.0.1-beta1 - numpy - pyqt5 == 5.12.2 - pythonqwt - mock - -[options.extras_require] -# For development tests/docs -dev = - black==22.8.0 - flake8 <= 3.9.2 - flake8-isort - isort>5.0 - mypy - pipdeptree - pre-commit - pytest-cov - setuptools_scm[toml]>=6.2 - sphinx-rtd-theme-github-versions - tox - types-mock - -[options.packages.find] -where = src -# Don't include our tests directory in the distribution -exclude = tests - -# Specify any package data to be included in the wheel below. -# [options.package_data] -# dls_pmaccontrol = -# subpackage/*.yaml - -[options.entry_points] -# Include a command line script -console_scripts = - dls-pmac-control = dls_pmaccontrol.motor:main - -[mypy] -# Ignore missing stubs for modules we use -ignore_missing_imports = True - -[isort] -known_third_party=dls_pmaclib -profile=black -float_to_top=true - -[flake8] -# Make flake8 respect black's line length (default 88), -max-line-length = 88 -extend-ignore = - E203, - # See https://github.com/PyCQA/pycodestyle/issues/373 - F811, - # support typing.overload decorator - F722, - # allow Annotated[typ, some_func("some string")] -exclude = - ui_* - .tox - .venv - -[tool:pytest] -# Run pytest with all our checkers, and don't spam us with massive tracebacks on error -addopts = - --tb=native -vv --doctest-modules --doctest-glob="*.rst" - --cov=dls_pmaccontrol --cov-report term --cov-report xml:cov.xml -# https://iscinumpy.gitlab.io/post/bound-version-constraints/#watch-for-warnings -# removed warnings as error since qt5 gets 'DeprecationWarning: Using or importing the ABCs from 'collections' instead of from 'collections.abc' is deprecated, and in 3.8 it will stop working' -# restore when we move to qt6? -# filterwarnings = error -# Doctest python code in docs, python code in src docstrings, test functions in tests -testpaths = - docs src tests - -[coverage:run] -data_file = /tmp/dls_pmaccontrol.coverage - -[coverage:paths] -# Tests are run from installed location, map back to the src directory -source = - src - **/site-packages/ - -# Use tox to provide parallel linting and testing -# NOTE that we pre-install all tools in the dev dependencies (including tox). -# Hence the use of allowlist_externals instead of using the tox virtualenvs. -# This ensures a match between developer time tools in the IDE and tox tools. -[tox:tox] -minversion = 3.7 -skipsdist=true -skipinstall=true - -[testenv:{pre-commit,mypy,pytest,docs}] -passenv = - PYTHONPATH - HOME -setenv = - QT_QPA_PLATFORM = offscreen -allowlist_externals = - pytest - pre-commit - mypy - sphinx-build -commands = - pytest: pytest tests {posargs} - mypy: mypy src tests {posargs} - pre-commit: pre-commit run --all-files {posargs} - docs: sphinx-build -EWT --keep-going docs build/html {posargs} diff --git a/setup.py b/setup.py deleted file mode 100644 index 6068493..0000000 --- a/setup.py +++ /dev/null @@ -1,3 +0,0 @@ -from setuptools import setup - -setup() diff --git a/src/dls_pmaccontrol/CSstatus.py b/src/dls_pmac_control/CSstatus.py similarity index 100% rename from src/dls_pmaccontrol/CSstatus.py rename to src/dls_pmac_control/CSstatus.py diff --git a/src/dls_pmaccontrol/GlobalStatus.py b/src/dls_pmac_control/GlobalStatus.py similarity index 100% rename from src/dls_pmaccontrol/GlobalStatus.py rename to src/dls_pmac_control/GlobalStatus.py diff --git a/src/dls_pmac_control/__main__.py b/src/dls_pmac_control/__main__.py index 823f3b9..fca6ad4 100644 --- a/src/dls_pmac_control/__main__.py +++ b/src/dls_pmac_control/__main__.py @@ -7,10 +7,10 @@ def main(args=None): parser = ArgumentParser() - parser.add_argument("-v", "--version", action="version", version=__version__) + parser.add_argument("--version", action="version", version=__version__) args = parser.parse_args(args) -# test with: python -m dls_pmac_control +# test with: pipenv run python -m dls_pmaccontrol if __name__ == "__main__": main() diff --git a/src/dls_pmaccontrol/axissettings.py b/src/dls_pmac_control/axissettings.py similarity index 100% rename from src/dls_pmaccontrol/axissettings.py rename to src/dls_pmac_control/axissettings.py diff --git a/src/dls_pmaccontrol/commsThread.py b/src/dls_pmac_control/commsThread.py similarity index 100% rename from src/dls_pmaccontrol/commsThread.py rename to src/dls_pmac_control/commsThread.py diff --git a/src/dls_pmaccontrol/energise.py b/src/dls_pmac_control/energise.py similarity index 100% rename from src/dls_pmaccontrol/energise.py rename to src/dls_pmac_control/energise.py diff --git a/src/dls_pmaccontrol/formAxisSettings.ui b/src/dls_pmac_control/formAxisSettings.ui similarity index 100% rename from src/dls_pmaccontrol/formAxisSettings.ui rename to src/dls_pmac_control/formAxisSettings.ui diff --git a/src/dls_pmaccontrol/formCSStatus.ui b/src/dls_pmac_control/formCSStatus.ui similarity index 100% rename from src/dls_pmaccontrol/formCSStatus.ui rename to src/dls_pmac_control/formCSStatus.ui diff --git a/src/dls_pmaccontrol/formControl.ui b/src/dls_pmac_control/formControl.ui similarity index 100% rename from src/dls_pmaccontrol/formControl.ui rename to src/dls_pmac_control/formControl.ui diff --git a/src/dls_pmaccontrol/formEnergise.ui b/src/dls_pmac_control/formEnergise.ui similarity index 100% rename from src/dls_pmaccontrol/formEnergise.ui rename to src/dls_pmac_control/formEnergise.ui diff --git a/src/dls_pmaccontrol/formGather.ui b/src/dls_pmac_control/formGather.ui similarity index 100% rename from src/dls_pmaccontrol/formGather.ui rename to src/dls_pmac_control/formGather.ui diff --git a/src/dls_pmaccontrol/formGlobalStatus.ui b/src/dls_pmac_control/formGlobalStatus.ui similarity index 100% rename from src/dls_pmaccontrol/formGlobalStatus.ui rename to src/dls_pmac_control/formGlobalStatus.ui diff --git a/src/dls_pmaccontrol/formLogin.ui b/src/dls_pmac_control/formLogin.ui similarity index 100% rename from src/dls_pmaccontrol/formLogin.ui rename to src/dls_pmac_control/formLogin.ui diff --git a/src/dls_pmaccontrol/formPpmacAxisSettings.ui b/src/dls_pmac_control/formPpmacAxisSettings.ui similarity index 100% rename from src/dls_pmaccontrol/formPpmacAxisSettings.ui rename to src/dls_pmac_control/formPpmacAxisSettings.ui diff --git a/src/dls_pmaccontrol/formPpmacCSStatus.ui b/src/dls_pmac_control/formPpmacCSStatus.ui similarity index 100% rename from src/dls_pmaccontrol/formPpmacCSStatus.ui rename to src/dls_pmac_control/formPpmacCSStatus.ui diff --git a/src/dls_pmaccontrol/formStatus.ui b/src/dls_pmac_control/formStatus.ui similarity index 100% rename from src/dls_pmaccontrol/formStatus.ui rename to src/dls_pmac_control/formStatus.ui diff --git a/src/dls_pmaccontrol/formWatches.ui b/src/dls_pmac_control/formWatches.ui similarity index 100% rename from src/dls_pmaccontrol/formWatches.ui rename to src/dls_pmac_control/formWatches.ui diff --git a/src/dls_pmaccontrol/gather.py b/src/dls_pmac_control/gather.py similarity index 100% rename from src/dls_pmaccontrol/gather.py rename to src/dls_pmac_control/gather.py diff --git a/src/dls_pmaccontrol/gatherchannel.py b/src/dls_pmac_control/gatherchannel.py similarity index 100% rename from src/dls_pmaccontrol/gatherchannel.py rename to src/dls_pmac_control/gatherchannel.py diff --git a/src/dls_pmaccontrol/greenLedOff.png b/src/dls_pmac_control/greenLedOff.png similarity index 100% rename from src/dls_pmaccontrol/greenLedOff.png rename to src/dls_pmac_control/greenLedOff.png diff --git a/src/dls_pmaccontrol/greenLedOn.png b/src/dls_pmac_control/greenLedOn.png similarity index 100% rename from src/dls_pmaccontrol/greenLedOn.png rename to src/dls_pmac_control/greenLedOn.png diff --git a/src/dls_pmaccontrol/led-amber.png b/src/dls_pmac_control/led-amber.png similarity index 100% rename from src/dls_pmaccontrol/led-amber.png rename to src/dls_pmac_control/led-amber.png diff --git a/src/dls_pmaccontrol/login.py b/src/dls_pmac_control/login.py similarity index 100% rename from src/dls_pmaccontrol/login.py rename to src/dls_pmac_control/login.py diff --git a/src/dls_pmaccontrol/motor.py b/src/dls_pmac_control/motor.py similarity index 100% rename from src/dls_pmaccontrol/motor.py rename to src/dls_pmac_control/motor.py diff --git a/src/dls_pmaccontrol/ppmacgather.py b/src/dls_pmac_control/ppmacgather.py similarity index 100% rename from src/dls_pmaccontrol/ppmacgather.py rename to src/dls_pmac_control/ppmacgather.py diff --git a/src/dls_pmaccontrol/redLedOff.png b/src/dls_pmac_control/redLedOff.png similarity index 100% rename from src/dls_pmaccontrol/redLedOff.png rename to src/dls_pmac_control/redLedOff.png diff --git a/src/dls_pmaccontrol/redLedOn.png b/src/dls_pmac_control/redLedOn.png similarity index 100% rename from src/dls_pmaccontrol/redLedOn.png rename to src/dls_pmac_control/redLedOn.png diff --git a/src/dls_pmaccontrol/status.py b/src/dls_pmac_control/status.py similarity index 100% rename from src/dls_pmaccontrol/status.py rename to src/dls_pmac_control/status.py diff --git a/src/dls_pmaccontrol/ui_formAxisSettings.py b/src/dls_pmac_control/ui_formAxisSettings.py similarity index 100% rename from src/dls_pmaccontrol/ui_formAxisSettings.py rename to src/dls_pmac_control/ui_formAxisSettings.py diff --git a/src/dls_pmaccontrol/ui_formCSStatus.py b/src/dls_pmac_control/ui_formCSStatus.py similarity index 100% rename from src/dls_pmaccontrol/ui_formCSStatus.py rename to src/dls_pmac_control/ui_formCSStatus.py diff --git a/src/dls_pmaccontrol/ui_formControl.py b/src/dls_pmac_control/ui_formControl.py similarity index 100% rename from src/dls_pmaccontrol/ui_formControl.py rename to src/dls_pmac_control/ui_formControl.py diff --git a/src/dls_pmaccontrol/ui_formEnergise.py b/src/dls_pmac_control/ui_formEnergise.py similarity index 100% rename from src/dls_pmaccontrol/ui_formEnergise.py rename to src/dls_pmac_control/ui_formEnergise.py diff --git a/src/dls_pmaccontrol/ui_formGather.py b/src/dls_pmac_control/ui_formGather.py similarity index 100% rename from src/dls_pmaccontrol/ui_formGather.py rename to src/dls_pmac_control/ui_formGather.py diff --git a/src/dls_pmaccontrol/ui_formGlobalStatus.py b/src/dls_pmac_control/ui_formGlobalStatus.py similarity index 100% rename from src/dls_pmaccontrol/ui_formGlobalStatus.py rename to src/dls_pmac_control/ui_formGlobalStatus.py diff --git a/src/dls_pmaccontrol/ui_formLogin.py b/src/dls_pmac_control/ui_formLogin.py similarity index 100% rename from src/dls_pmaccontrol/ui_formLogin.py rename to src/dls_pmac_control/ui_formLogin.py diff --git a/src/dls_pmaccontrol/ui_formPpmacAxisSettings.py b/src/dls_pmac_control/ui_formPpmacAxisSettings.py similarity index 100% rename from src/dls_pmaccontrol/ui_formPpmacAxisSettings.py rename to src/dls_pmac_control/ui_formPpmacAxisSettings.py diff --git a/src/dls_pmaccontrol/ui_formPpmacCSStatus.py b/src/dls_pmac_control/ui_formPpmacCSStatus.py similarity index 100% rename from src/dls_pmaccontrol/ui_formPpmacCSStatus.py rename to src/dls_pmac_control/ui_formPpmacCSStatus.py diff --git a/src/dls_pmaccontrol/ui_formStatus.py b/src/dls_pmac_control/ui_formStatus.py similarity index 100% rename from src/dls_pmaccontrol/ui_formStatus.py rename to src/dls_pmac_control/ui_formStatus.py diff --git a/src/dls_pmaccontrol/ui_formWatches.py b/src/dls_pmac_control/ui_formWatches.py similarity index 100% rename from src/dls_pmaccontrol/ui_formWatches.py rename to src/dls_pmac_control/ui_formWatches.py diff --git a/src/dls_pmaccontrol/watches.py b/src/dls_pmac_control/watches.py similarity index 100% rename from src/dls_pmaccontrol/watches.py rename to src/dls_pmac_control/watches.py diff --git a/src/dls_pmaccontrol/__init__.py b/src/dls_pmaccontrol/__init__.py deleted file mode 100644 index 0fe6655..0000000 --- a/src/dls_pmaccontrol/__init__.py +++ /dev/null @@ -1,12 +0,0 @@ -try: - # Use live version from git - from setuptools_scm import get_version - - # Warning: If the install is nested to the same depth, this will always succeed - __version__ = get_version(root="../../", relative_to=__file__) - del get_version -except (ImportError, LookupError): - # Use installed version - from ._version import __version__ - -__all__ = ["__version__"] diff --git a/src/dls_pmaccontrol/__main__.py b/src/dls_pmaccontrol/__main__.py deleted file mode 100644 index fca6ad4..0000000 --- a/src/dls_pmaccontrol/__main__.py +++ /dev/null @@ -1,16 +0,0 @@ -from argparse import ArgumentParser - -from . import __version__ - -__all__ = ["main"] - - -def main(args=None): - parser = ArgumentParser() - parser.add_argument("--version", action="version", version=__version__) - args = parser.parse_args(args) - - -# test with: pipenv run python -m dls_pmaccontrol -if __name__ == "__main__": - main() From bb2e63a8b673469d40349ad6e639654a91aa676d Mon Sep 17 00:00:00 2001 From: Giles Knap Date: Sun, 11 Feb 2024 20:23:07 +0000 Subject: [PATCH 22/36] fix docs --- docs/conf.py | 2 + docs/explanations.rst | 11 --- docs/explanations/decisions.rst | 17 ----- .../0001-record-architecture-decisions.rst | 26 ------- docs/how-to.rst | 11 --- docs/{ => how-to}/gather.rst | 0 docs/{ => how-to}/gui.rst | 0 docs/{ => how-to}/gui_images/amber-hi-lim.png | Bin .../gui_images/annotated-gui-main.png | Bin docs/{ => how-to}/gui_images/connected.png | Bin .../gui_images/connection-error.png | Bin .../gui_images/data-gather-config.png | Bin docs/{ => how-to}/gui_images/data-gather.png | Bin docs/{ => how-to}/gui_images/login.png | Bin .../gui_images/main-window-startup.png | Bin docs/{ => how-to}/gui_images/main.png | Bin .../gui_images/plot-data-gather.png | Bin .../gui_images/pmac-axis-settings.png | Bin .../gui_images/pmac-axis-settings2.png | Bin .../gui_images/pmac-connected.png | Bin .../gui_images/pmac-cs-status.png | Bin .../gui_images/pmac-global-status.png | Bin docs/{ => how-to}/gui_images/pmac-status.png | Bin .../gui_images/power-pmac-axis-settings.png | Bin .../gui_images/power-pmac-connected.png | Bin .../gui_images/power-pmac-cs-status.png | Bin .../gui_images/power-pmac-global-status.png | Bin .../gui_images/power-pmac-status.png | Bin docs/{ => how-to}/gui_images/red-hi-lim.png | Bin .../gui_images/refused-connection.png | Bin .../gui_images/watch-window-edit.png | Bin docs/{ => how-to}/gui_images/watch-window.png | Bin docs/{ => how-to}/watches.rst | 0 docs/index.rst | 18 ----- docs/installation.rst | 68 ------------------ docs/introduction.rst | 6 -- docs/reference.rst | 16 ----- docs/tutorials.rst | 11 --- docs/tutorials/installation.rst | 45 ------------ 39 files changed, 2 insertions(+), 229 deletions(-) delete mode 100644 docs/explanations.rst delete mode 100644 docs/explanations/decisions.rst delete mode 100644 docs/explanations/decisions/0001-record-architecture-decisions.rst delete mode 100644 docs/how-to.rst rename docs/{ => how-to}/gather.rst (100%) rename docs/{ => how-to}/gui.rst (100%) rename docs/{ => how-to}/gui_images/amber-hi-lim.png (100%) rename docs/{ => how-to}/gui_images/annotated-gui-main.png (100%) rename docs/{ => how-to}/gui_images/connected.png (100%) rename docs/{ => how-to}/gui_images/connection-error.png (100%) rename docs/{ => how-to}/gui_images/data-gather-config.png (100%) rename docs/{ => how-to}/gui_images/data-gather.png (100%) rename docs/{ => how-to}/gui_images/login.png (100%) rename docs/{ => how-to}/gui_images/main-window-startup.png (100%) rename docs/{ => how-to}/gui_images/main.png (100%) rename docs/{ => how-to}/gui_images/plot-data-gather.png (100%) rename docs/{ => how-to}/gui_images/pmac-axis-settings.png (100%) rename docs/{ => how-to}/gui_images/pmac-axis-settings2.png (100%) rename docs/{ => how-to}/gui_images/pmac-connected.png (100%) rename docs/{ => how-to}/gui_images/pmac-cs-status.png (100%) rename docs/{ => how-to}/gui_images/pmac-global-status.png (100%) rename docs/{ => how-to}/gui_images/pmac-status.png (100%) rename docs/{ => how-to}/gui_images/power-pmac-axis-settings.png (100%) rename docs/{ => how-to}/gui_images/power-pmac-connected.png (100%) rename docs/{ => how-to}/gui_images/power-pmac-cs-status.png (100%) rename docs/{ => how-to}/gui_images/power-pmac-global-status.png (100%) rename docs/{ => how-to}/gui_images/power-pmac-status.png (100%) rename docs/{ => how-to}/gui_images/red-hi-lim.png (100%) rename docs/{ => how-to}/gui_images/refused-connection.png (100%) rename docs/{ => how-to}/gui_images/watch-window-edit.png (100%) rename docs/{ => how-to}/gui_images/watch-window.png (100%) rename docs/{ => how-to}/watches.rst (100%) delete mode 100644 docs/index.rst delete mode 100644 docs/installation.rst delete mode 100644 docs/introduction.rst delete mode 100644 docs/reference.rst delete mode 100644 docs/tutorials.rst delete mode 100644 docs/tutorials/installation.rst diff --git a/docs/conf.py b/docs/conf.py index f254507..ae2aa88 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -186,3 +186,5 @@ # Logo html_logo = "images/dls-logo.svg" html_favicon = html_logo + +numfig = True \ No newline at end of file diff --git a/docs/explanations.rst b/docs/explanations.rst deleted file mode 100644 index 1e32967..0000000 --- a/docs/explanations.rst +++ /dev/null @@ -1,11 +0,0 @@ -:orphan: - -Explanations -============ - -Explanation of how the library works and why it works that way. - -.. toctree:: - :caption: Explanations - - explanations/decisions diff --git a/docs/explanations/decisions.rst b/docs/explanations/decisions.rst deleted file mode 100644 index 5841e6e..0000000 --- a/docs/explanations/decisions.rst +++ /dev/null @@ -1,17 +0,0 @@ -.. This Source Code Form is subject to the terms of the Mozilla Public -.. License, v. 2.0. If a copy of the MPL was not distributed with this -.. file, You can obtain one at http://mozilla.org/MPL/2.0/. - -Architectural Decision Records -============================== - -We record major architectural decisions in Architecture Decision Records (ADRs), -as `described by Michael Nygard -`_. -Below is the list of our current ADRs. - -.. toctree:: - :maxdepth: 1 - :glob: - - decisions/* \ No newline at end of file diff --git a/docs/explanations/decisions/0001-record-architecture-decisions.rst b/docs/explanations/decisions/0001-record-architecture-decisions.rst deleted file mode 100644 index b2d3d0f..0000000 --- a/docs/explanations/decisions/0001-record-architecture-decisions.rst +++ /dev/null @@ -1,26 +0,0 @@ -1. Record architecture decisions -================================ - -Date: 2022-02-18 - -Status ------- - -Accepted - -Context -------- - -We need to record the architectural decisions made on this project. - -Decision --------- - -We will use Architecture Decision Records, as `described by Michael Nygard -`_. - -Consequences ------------- - -See Michael Nygard's article, linked above. To create new ADRs we will copy and -paste from existing ones. diff --git a/docs/how-to.rst b/docs/how-to.rst deleted file mode 100644 index 700797c..0000000 --- a/docs/how-to.rst +++ /dev/null @@ -1,11 +0,0 @@ -:orphan: - -How-to Guides -============= - -Practical step-by-step guides for the more experienced user. - -.. toctree:: - :caption: How-to Guides - - how-to/contributing diff --git a/docs/gather.rst b/docs/how-to/gather.rst similarity index 100% rename from docs/gather.rst rename to docs/how-to/gather.rst diff --git a/docs/gui.rst b/docs/how-to/gui.rst similarity index 100% rename from docs/gui.rst rename to docs/how-to/gui.rst diff --git a/docs/gui_images/amber-hi-lim.png b/docs/how-to/gui_images/amber-hi-lim.png similarity index 100% rename from docs/gui_images/amber-hi-lim.png rename to docs/how-to/gui_images/amber-hi-lim.png diff --git a/docs/gui_images/annotated-gui-main.png b/docs/how-to/gui_images/annotated-gui-main.png similarity index 100% rename from docs/gui_images/annotated-gui-main.png rename to docs/how-to/gui_images/annotated-gui-main.png diff --git a/docs/gui_images/connected.png b/docs/how-to/gui_images/connected.png similarity index 100% rename from docs/gui_images/connected.png rename to docs/how-to/gui_images/connected.png diff --git a/docs/gui_images/connection-error.png b/docs/how-to/gui_images/connection-error.png similarity index 100% rename from docs/gui_images/connection-error.png rename to docs/how-to/gui_images/connection-error.png diff --git a/docs/gui_images/data-gather-config.png b/docs/how-to/gui_images/data-gather-config.png similarity index 100% rename from docs/gui_images/data-gather-config.png rename to docs/how-to/gui_images/data-gather-config.png diff --git a/docs/gui_images/data-gather.png b/docs/how-to/gui_images/data-gather.png similarity index 100% rename from docs/gui_images/data-gather.png rename to docs/how-to/gui_images/data-gather.png diff --git a/docs/gui_images/login.png b/docs/how-to/gui_images/login.png similarity index 100% rename from docs/gui_images/login.png rename to docs/how-to/gui_images/login.png diff --git a/docs/gui_images/main-window-startup.png b/docs/how-to/gui_images/main-window-startup.png similarity index 100% rename from docs/gui_images/main-window-startup.png rename to docs/how-to/gui_images/main-window-startup.png diff --git a/docs/gui_images/main.png b/docs/how-to/gui_images/main.png similarity index 100% rename from docs/gui_images/main.png rename to docs/how-to/gui_images/main.png diff --git a/docs/gui_images/plot-data-gather.png b/docs/how-to/gui_images/plot-data-gather.png similarity index 100% rename from docs/gui_images/plot-data-gather.png rename to docs/how-to/gui_images/plot-data-gather.png diff --git a/docs/gui_images/pmac-axis-settings.png b/docs/how-to/gui_images/pmac-axis-settings.png similarity index 100% rename from docs/gui_images/pmac-axis-settings.png rename to docs/how-to/gui_images/pmac-axis-settings.png diff --git a/docs/gui_images/pmac-axis-settings2.png b/docs/how-to/gui_images/pmac-axis-settings2.png similarity index 100% rename from docs/gui_images/pmac-axis-settings2.png rename to docs/how-to/gui_images/pmac-axis-settings2.png diff --git a/docs/gui_images/pmac-connected.png b/docs/how-to/gui_images/pmac-connected.png similarity index 100% rename from docs/gui_images/pmac-connected.png rename to docs/how-to/gui_images/pmac-connected.png diff --git a/docs/gui_images/pmac-cs-status.png b/docs/how-to/gui_images/pmac-cs-status.png similarity index 100% rename from docs/gui_images/pmac-cs-status.png rename to docs/how-to/gui_images/pmac-cs-status.png diff --git a/docs/gui_images/pmac-global-status.png b/docs/how-to/gui_images/pmac-global-status.png similarity index 100% rename from docs/gui_images/pmac-global-status.png rename to docs/how-to/gui_images/pmac-global-status.png diff --git a/docs/gui_images/pmac-status.png b/docs/how-to/gui_images/pmac-status.png similarity index 100% rename from docs/gui_images/pmac-status.png rename to docs/how-to/gui_images/pmac-status.png diff --git a/docs/gui_images/power-pmac-axis-settings.png b/docs/how-to/gui_images/power-pmac-axis-settings.png similarity index 100% rename from docs/gui_images/power-pmac-axis-settings.png rename to docs/how-to/gui_images/power-pmac-axis-settings.png diff --git a/docs/gui_images/power-pmac-connected.png b/docs/how-to/gui_images/power-pmac-connected.png similarity index 100% rename from docs/gui_images/power-pmac-connected.png rename to docs/how-to/gui_images/power-pmac-connected.png diff --git a/docs/gui_images/power-pmac-cs-status.png b/docs/how-to/gui_images/power-pmac-cs-status.png similarity index 100% rename from docs/gui_images/power-pmac-cs-status.png rename to docs/how-to/gui_images/power-pmac-cs-status.png diff --git a/docs/gui_images/power-pmac-global-status.png b/docs/how-to/gui_images/power-pmac-global-status.png similarity index 100% rename from docs/gui_images/power-pmac-global-status.png rename to docs/how-to/gui_images/power-pmac-global-status.png diff --git a/docs/gui_images/power-pmac-status.png b/docs/how-to/gui_images/power-pmac-status.png similarity index 100% rename from docs/gui_images/power-pmac-status.png rename to docs/how-to/gui_images/power-pmac-status.png diff --git a/docs/gui_images/red-hi-lim.png b/docs/how-to/gui_images/red-hi-lim.png similarity index 100% rename from docs/gui_images/red-hi-lim.png rename to docs/how-to/gui_images/red-hi-lim.png diff --git a/docs/gui_images/refused-connection.png b/docs/how-to/gui_images/refused-connection.png similarity index 100% rename from docs/gui_images/refused-connection.png rename to docs/how-to/gui_images/refused-connection.png diff --git a/docs/gui_images/watch-window-edit.png b/docs/how-to/gui_images/watch-window-edit.png similarity index 100% rename from docs/gui_images/watch-window-edit.png rename to docs/how-to/gui_images/watch-window-edit.png diff --git a/docs/gui_images/watch-window.png b/docs/how-to/gui_images/watch-window.png similarity index 100% rename from docs/gui_images/watch-window.png rename to docs/how-to/gui_images/watch-window.png diff --git a/docs/watches.rst b/docs/how-to/watches.rst similarity index 100% rename from docs/watches.rst rename to docs/how-to/watches.rst diff --git a/docs/index.rst b/docs/index.rst deleted file mode 100644 index 1d57778..0000000 --- a/docs/index.rst +++ /dev/null @@ -1,18 +0,0 @@ -.. DLS PMAC Control Application documentation master file, created by - sphinx-quickstart on Thu Nov 4 10:17:36 2021. - You can adapt this file completely to your liking, but it should at least - contain the root `toctree` directive. - -DLS PMAC Control Application -======================================================== - -.. toctree:: - :maxdepth: 2 - :caption: Contents: - - introduction - installation - gui - watches - gather - diff --git a/docs/installation.rst b/docs/installation.rst deleted file mode 100644 index dcb5866..0000000 --- a/docs/installation.rst +++ /dev/null @@ -1,68 +0,0 @@ -Installation Guide -================== - -1. Clone the 2 repos: - -* dls-pmac-control.git - -* dls-pmac-lib.git - -2. Create & activate a Python3 virtual environment: - -.. code-block:: console - - dls-python3 -m venv - - source venv/bin/activate - -3. Make sure to have an up-to-date version of pip and setuptools: - -.. code-block:: console - - pip install --upgrade pip - - pip install --upgrade setuptools - -4. Build the dls-pmac-lib module: - -.. code-block:: console - - cd dls-pmac-lib - - dls-python3 setup.py clean - - dls-python3 setup.py build - - dls-python3 setup.py install - -5. Install pyqt5: - -.. code-block:: console - - cd dls-pmac-control - - pip install pyqt5-tools - -6. Make the screens: - -.. code-block:: console - - make clean - - make - -7. Build the dls-pmac-control module: - -.. code-block:: console - - dls-python3 setup.py clean - - dls-python3 setup.py build - - dls-python3 setup.py install - -8. Run the application from within the virtual environment: - -.. code-block:: console - - dls-pmac-control diff --git a/docs/introduction.rst b/docs/introduction.rst deleted file mode 100644 index 57c9a6c..0000000 --- a/docs/introduction.rst +++ /dev/null @@ -1,6 +0,0 @@ -Introduction -============ - -The dls_pmaccontrol module is a Python application which provides a GUI to interact with the Delta Tau PMAC controller. The dls_pmaccontrol module requires the dls_pmaclib module for communication with the hardware. - - diff --git a/docs/reference.rst b/docs/reference.rst deleted file mode 100644 index b71098e..0000000 --- a/docs/reference.rst +++ /dev/null @@ -1,16 +0,0 @@ -:orphan: - -Reference -========= - -Technical reference material including APIs and release notes. - -.. toctree:: - :caption: Reference - - Releases - Index - -.. - Index link above is a hack to make genindex.html a relative link - https://stackoverflow.com/a/31820846 diff --git a/docs/tutorials.rst b/docs/tutorials.rst deleted file mode 100644 index dfdef50..0000000 --- a/docs/tutorials.rst +++ /dev/null @@ -1,11 +0,0 @@ -:orphan: - -Tutorials -========= - -Tutorials for installation, library and commandline usage. New users start here. - -.. toctree:: - :caption: Tutorials - - tutorials/installation diff --git a/docs/tutorials/installation.rst b/docs/tutorials/installation.rst deleted file mode 100644 index 118e31e..0000000 --- a/docs/tutorials/installation.rst +++ /dev/null @@ -1,45 +0,0 @@ -Installation -============ - -Check your version of python ----------------------------- - -You will need python 3.8 or later. You can check your version of python by -typing into a terminal:: - - python3 --version - - -Create a virtual environment ----------------------------- - -It is recommended that you install into a “virtual environment” so this -installation will not interfere with any existing Python software:: - - python3 -m venv /path/to/venv - source /path/to/venv/bin/activate - - -Installing the library ----------------------- - -You can now use ``pip`` to install the library:: - - python3 -m pip install dls-pmac-control - -If you require a feature that is not currently released you can also install -from github:: - - python3 -m pip install git+https://github.com/DiamondLightSource/dls-pmac-control.git - -The library should now be installed and the commandline interface on your path. -You can check the version that has been installed by typing:: - - dls-pmac-control --version - -Running in a container ----------------------- - -To pull the container from github container registry and run:: - - docker run ghcr.io/DiamondLightSource/dls-pmac-control:main --version From 509426208959ad4e703414b926b6cea33a6baa74 Mon Sep 17 00:00:00 2001 From: Giles Knap Date: Sun, 11 Feb 2024 20:42:06 +0000 Subject: [PATCH 23/36] rename dls_pmaccontrol to dls_pmac_control --- Makefile | 4 +- README.md | 2 +- documentation/config.cfg | 6 +- documentation/manual.src | 6 +- pyproject.toml | 1 + src/dls_pmac_control/CSstatus.py | 4 +- src/dls_pmac_control/GlobalStatus.py | 2 +- src/dls_pmac_control/__main__.py | 2 +- src/dls_pmac_control/axissettings.py | 4 +- src/dls_pmac_control/energise.py | 2 +- src/dls_pmac_control/gather.py | 4 +- src/dls_pmac_control/login.py | 2 +- src/dls_pmac_control/motor.py | 22 +-- src/dls_pmac_control/ppmacgather.py | 4 +- src/dls_pmac_control/status.py | 2 +- src/dls_pmac_control/ui_formAxisSettings.py | 2 +- src/dls_pmac_control/ui_formCSStatus.py | 2 +- src/dls_pmac_control/ui_formControl.py | 2 +- src/dls_pmac_control/ui_formEnergise.py | 2 +- src/dls_pmac_control/ui_formGather.py | 2 +- src/dls_pmac_control/ui_formGlobalStatus.py | 2 +- src/dls_pmac_control/ui_formLogin.py | 2 +- .../ui_formPpmacAxisSettings.py | 2 +- src/dls_pmac_control/ui_formPpmacCSStatus.py | 2 +- src/dls_pmac_control/ui_formStatus.py | 2 +- src/dls_pmac_control/ui_formWatches.py | 2 +- src/dls_pmac_control/watches.py | 2 +- tests/test_axissettings.py | 22 +-- tests/test_commsthread.py | 12 +- tests/test_csstatus.py | 2 +- tests/test_dls_pmaccontrol.py | 4 +- tests/test_energise.py | 18 +-- tests/test_gather.py | 22 +-- tests/test_gatherchannel.py | 2 +- tests/test_globalstatus.py | 2 +- tests/test_login.py | 6 +- tests/test_motor.py | 146 +++++++++--------- tests/test_status.py | 2 +- tests/test_watches.py | 14 +- 39 files changed, 172 insertions(+), 171 deletions(-) diff --git a/Makefile b/Makefile index 3329574..dc15531 100644 --- a/Makefile +++ b/Makefile @@ -1,9 +1,9 @@ ###### EDIT ##################### #Directory with ui and resource files -RESOURCE_DIR = dls_pmaccontrol +RESOURCE_DIR = dls_pmac_control #Directory for compiled resources -COMPILED_DIR = dls_pmaccontrol +COMPILED_DIR = dls_pmac_control #UI files to compile UI_FILES = formAxisSettings.ui formControl.ui formCSStatus.ui formEnergise.ui formGather.ui formGlobalStatus.ui formStatus.ui formWatches.ui formPpmacAxisSettings.ui formLogin.ui formPpmacCSStatus.ui diff --git a/README.md b/README.md index 92b0067..9be2f1d 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ # dls_pmac_control -The dls_pmaccontrol package is a python application which provides a GUI front +The dls_pmac_control package is a python application which provides a GUI front end to control the DeltaTau PMAC, Power PMAC and Geobrick motor control systems. Source | diff --git a/documentation/config.cfg b/documentation/config.cfg index a9c0aba..fa84410 100644 --- a/documentation/config.cfg +++ b/documentation/config.cfg @@ -1,12 +1,12 @@ # info about project -PROJECT_NAME = dls_pmaccontrol -PROJECT_NUMBER = +PROJECT_NAME = dls_pmac_control +PROJECT_NUMBER = # use . instead of :: OPTIMIZE_OUTPUT_JAVA = YES # need this to get all function/variable docs SHOW_NAMESPACES = YES # add the input dir -INPUT += ../dls_pmaccontrol . +INPUT += ../dls_pmac_control . # add some examples # EXAMPLE_PATH = examples # add the extensions diff --git a/documentation/manual.src b/documentation/manual.src index f7f0c3e..e655728 100644 --- a/documentation/manual.src +++ b/documentation/manual.src @@ -1,10 +1,10 @@ /** -\mainpage dls_pmaccontrol Python Module +\mainpage dls_pmac_control Python Module \section intro_sec Introduction -The dls_pmaccontrol package is a python application which provides a GUI front end to control the DeltaTau PMAC and Geobrick motor control systems. +The dls_pmac_control package is a python application which provides a GUI front end to control the DeltaTau PMAC and Geobrick motor control systems. \section Installation -dls_pmaccontrol is developed and tested on Python 2.6. Qt4, PyQt and Qwt5 are used to render the graphical user interface. These packages must be pre-installed on the system before building and running dls_pmaccontrol. The module uses make and python setuptools/distribute to build and output a python egg. +dls_pmac_control is developed and tested on Python 2.6. Qt4, PyQt and Qwt5 are used to render the graphical user interface. These packages must be pre-installed on the system before building and running dls_pmac_control. The module uses make and python setuptools/distribute to build and output a python egg. The dls_pmaclib package is also required for this application. This package is also available on the Diamond Control Downloads page. For Mac OS X the following MacPorts provide the necessary dependencies: diff --git a/pyproject.toml b/pyproject.toml index 4f707d9..3638cd0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -22,6 +22,7 @@ requires-python = ">=3.9" [project.optional-dependencies] dev = [ "copier", + "mock", "myst-parser", "pipdeptree", "pre-commit", diff --git a/src/dls_pmac_control/CSstatus.py b/src/dls_pmac_control/CSstatus.py index 4355f86..d209778 100755 --- a/src/dls_pmac_control/CSstatus.py +++ b/src/dls_pmac_control/CSstatus.py @@ -6,8 +6,8 @@ from PyQt5.QtCore import QObject, Qt, pyqtSignal, pyqtSlot from PyQt5.QtWidgets import QApplication, QDialog, QLabel -from dls_pmaccontrol.ui_formCSStatus import Ui_formCSStatus -from dls_pmaccontrol.ui_formPpmacCSStatus import Ui_formPpmacCSStatus +from dls_pmac_control.ui_formCSStatus import Ui_formCSStatus +from dls_pmac_control.ui_formPpmacCSStatus import Ui_formPpmacCSStatus class CSStatusForm(QDialog, Ui_formCSStatus): diff --git a/src/dls_pmac_control/GlobalStatus.py b/src/dls_pmac_control/GlobalStatus.py index 40c60c4..b18c373 100644 --- a/src/dls_pmac_control/GlobalStatus.py +++ b/src/dls_pmac_control/GlobalStatus.py @@ -4,7 +4,7 @@ from PyQt5.QtCore import QObject, Qt, pyqtSignal, pyqtSlot from PyQt5.QtWidgets import QApplication, QDialog, QLabel -from dls_pmaccontrol.ui_formGlobalStatus import Ui_formGlobalStatus +from dls_pmac_control.ui_formGlobalStatus import Ui_formGlobalStatus class GlobalStatusForm(QDialog, Ui_formGlobalStatus): diff --git a/src/dls_pmac_control/__main__.py b/src/dls_pmac_control/__main__.py index fca6ad4..cd2a93e 100644 --- a/src/dls_pmac_control/__main__.py +++ b/src/dls_pmac_control/__main__.py @@ -11,6 +11,6 @@ def main(args=None): args = parser.parse_args(args) -# test with: pipenv run python -m dls_pmaccontrol +# test with: pipenv run python -m dls_pmac_control if __name__ == "__main__": main() diff --git a/src/dls_pmac_control/axissettings.py b/src/dls_pmac_control/axissettings.py index fb06dcf..0271e2a 100644 --- a/src/dls_pmac_control/axissettings.py +++ b/src/dls_pmac_control/axissettings.py @@ -2,8 +2,8 @@ from PyQt5.QtWidgets import QDialog, QMessageBox -from dls_pmaccontrol.ui_formAxisSettings import Ui_formAxisSettings -from dls_pmaccontrol.ui_formPpmacAxisSettings import Ui_formPpmacAxisSettings +from dls_pmac_control.ui_formAxisSettings import Ui_formAxisSettings +from dls_pmac_control.ui_formPpmacAxisSettings import Ui_formPpmacAxisSettings # Power PMAC I-Variable Equivalents PpmacVars = { diff --git a/src/dls_pmac_control/energise.py b/src/dls_pmac_control/energise.py index 13b4b19..0472b64 100644 --- a/src/dls_pmac_control/energise.py +++ b/src/dls_pmac_control/energise.py @@ -6,7 +6,7 @@ from PyQt5.QtCore import QObject, Qt, pyqtSignal, pyqtSlot from PyQt5.QtWidgets import QApplication, QCheckBox, QDialog, QMessageBox -from dls_pmaccontrol.ui_formEnergise import Ui_formEnergise +from dls_pmac_control.ui_formEnergise import Ui_formEnergise class PmacIOError(IOError): diff --git a/src/dls_pmac_control/gather.py b/src/dls_pmac_control/gather.py index 81306d0..d6ebac6 100644 --- a/src/dls_pmac_control/gather.py +++ b/src/dls_pmac_control/gather.py @@ -8,14 +8,14 @@ from PyQt5.QtWidgets import QDialog, QFileDialog, QMessageBox from qwt import QwtPlotCurve -from dls_pmaccontrol.gatherchannel import ( +from dls_pmac_control.gatherchannel import ( LONGWORD, WORD, PmacGatherChannel, motorBaseAddrs, pmacDataSources, ) -from dls_pmaccontrol.ui_formGather import Ui_formGather +from dls_pmac_control.ui_formGather import Ui_formGather # TODO - this needs the logic decoupled from the GUI and moved into pmaclib # work has started in pmaclib but currently duplicates code in this module diff --git a/src/dls_pmac_control/login.py b/src/dls_pmac_control/login.py index 671dc07..c0f158a 100644 --- a/src/dls_pmac_control/login.py +++ b/src/dls_pmac_control/login.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- from PyQt5.QtWidgets import QDialog -from dls_pmaccontrol.ui_formLogin import Ui_Login +from dls_pmac_control.ui_formLogin import Ui_Login class Loginform(QDialog, Ui_Login): diff --git a/src/dls_pmac_control/motor.py b/src/dls_pmac_control/motor.py index ca5aba0..8fb8b2b 100755 --- a/src/dls_pmac_control/motor.py +++ b/src/dls_pmac_control/motor.py @@ -11,19 +11,19 @@ from PyQt5.QtWidgets import (QApplication, QFileDialog, QLineEdit, QMainWindow, QMessageBox, QProgressDialog, QTableWidgetItem) -from dls_pmaccontrol.axissettings import (Axissettingsform, +from dls_pmac_control.axissettings import (Axissettingsform, PpmacAxissettingsform) -from dls_pmaccontrol.commsThread import CommsThread -from dls_pmaccontrol.CSstatus import CSStatusForm, PpmacCSStatusForm -from dls_pmaccontrol.energise import Energiseform -from dls_pmaccontrol.gather import PmacGatherform -from dls_pmaccontrol.GlobalStatus import (GlobalStatusForm, +from dls_pmac_control.commsThread import CommsThread +from dls_pmac_control.CSstatus import CSStatusForm, PpmacCSStatusForm +from dls_pmac_control.energise import Energiseform +from dls_pmac_control.gather import PmacGatherform +from dls_pmac_control.GlobalStatus import (GlobalStatusForm, PpmacGlobalStatusForm) -from dls_pmaccontrol.login import Loginform -from dls_pmaccontrol.ppmacgather import PpmacGatherform -from dls_pmaccontrol.status import PpmacStatusform, Statusform -from dls_pmaccontrol.ui_formControl import Ui_ControlForm -from dls_pmaccontrol.watches import Watchesform +from dls_pmac_control.login import Loginform +from dls_pmac_control.ppmacgather import PpmacGatherform +from dls_pmac_control.status import PpmacStatusform, Statusform +from dls_pmac_control.ui_formControl import Ui_ControlForm +from dls_pmac_control.watches import Watchesform from dls_pmaclib.dls_pmacremote import (PmacEthernetInterface, PmacSerialInterface, PmacTelnetInterface, PPmacSshInterface) diff --git a/src/dls_pmac_control/ppmacgather.py b/src/dls_pmac_control/ppmacgather.py index 94308b8..1f30254 100644 --- a/src/dls_pmac_control/ppmacgather.py +++ b/src/dls_pmac_control/ppmacgather.py @@ -8,8 +8,8 @@ from PyQt5.QtWidgets import QDialog, QFileDialog, QMessageBox from qwt import QwtPlotCurve -from dls_pmaccontrol.gatherchannel import PpmacGatherChannel, ppmacDataSources -from dls_pmaccontrol.ui_formGather import Ui_formGather +from dls_pmac_control.gatherchannel import PpmacGatherChannel, ppmacDataSources +from dls_pmac_control.ui_formGather import Ui_formGather # TODO - this needs the logic decoupled from the GUI and moved into pmaclib # work has started in pmaclib but currently duplicates code in this module diff --git a/src/dls_pmac_control/status.py b/src/dls_pmac_control/status.py index 213a9d0..9c95fb5 100644 --- a/src/dls_pmac_control/status.py +++ b/src/dls_pmac_control/status.py @@ -6,7 +6,7 @@ from PyQt5.QtCore import QObject, Qt, pyqtSignal, pyqtSlot from PyQt5.QtWidgets import QDialog, QLabel -from dls_pmaccontrol.ui_formStatus import Ui_formStatus +from dls_pmac_control.ui_formStatus import Ui_formStatus class Statusform(QDialog, Ui_formStatus): diff --git a/src/dls_pmac_control/ui_formAxisSettings.py b/src/dls_pmac_control/ui_formAxisSettings.py index fa155b0..97cd844 100644 --- a/src/dls_pmac_control/ui_formAxisSettings.py +++ b/src/dls_pmac_control/ui_formAxisSettings.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Form implementation generated from reading ui file 'dls_pmaccontrol/formAxisSettings.ui' +# Form implementation generated from reading ui file 'dls_pmac_control/formAxisSettings.ui' # # Created by: PyQt5 UI code generator 5.12.2 # diff --git a/src/dls_pmac_control/ui_formCSStatus.py b/src/dls_pmac_control/ui_formCSStatus.py index c7317a3..3ee06de 100644 --- a/src/dls_pmac_control/ui_formCSStatus.py +++ b/src/dls_pmac_control/ui_formCSStatus.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Form implementation generated from reading ui file 'src/dls_pmaccontrol/formCSStatus.ui' +# Form implementation generated from reading ui file 'src/dls_pmac_control/formCSStatus.ui' # # Created by: PyQt5 UI code generator 5.12.2 # diff --git a/src/dls_pmac_control/ui_formControl.py b/src/dls_pmac_control/ui_formControl.py index eb4b2c3..1fd6b61 100644 --- a/src/dls_pmac_control/ui_formControl.py +++ b/src/dls_pmac_control/ui_formControl.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Form implementation generated from reading ui file 'dls_pmaccontrol/formControl.ui' +# Form implementation generated from reading ui file 'dls_pmac_control/formControl.ui' # # Created by: PyQt5 UI code generator 5.12.2 # diff --git a/src/dls_pmac_control/ui_formEnergise.py b/src/dls_pmac_control/ui_formEnergise.py index 933d0b2..ac9a122 100644 --- a/src/dls_pmac_control/ui_formEnergise.py +++ b/src/dls_pmac_control/ui_formEnergise.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Form implementation generated from reading ui file 'dls_pmaccontrol/formEnergise.ui' +# Form implementation generated from reading ui file 'dls_pmac_control/formEnergise.ui' # # Created by: PyQt5 UI code generator 5.15.4 # diff --git a/src/dls_pmac_control/ui_formGather.py b/src/dls_pmac_control/ui_formGather.py index c1fb6ca..e0ff1fa 100644 --- a/src/dls_pmac_control/ui_formGather.py +++ b/src/dls_pmac_control/ui_formGather.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Form implementation generated from reading ui file 'dls_pmaccontrol/formGather.ui' +# Form implementation generated from reading ui file 'dls_pmac_control/formGather.ui' # # Created by: PyQt5 UI code generator 5.15.4 # diff --git a/src/dls_pmac_control/ui_formGlobalStatus.py b/src/dls_pmac_control/ui_formGlobalStatus.py index 0d33812..b371a59 100644 --- a/src/dls_pmac_control/ui_formGlobalStatus.py +++ b/src/dls_pmac_control/ui_formGlobalStatus.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Form implementation generated from reading ui file 'dls_pmaccontrol/formGlobalStatus.ui' +# Form implementation generated from reading ui file 'dls_pmac_control/formGlobalStatus.ui' # # Created by: PyQt5 UI code generator 5.15.4 # diff --git a/src/dls_pmac_control/ui_formLogin.py b/src/dls_pmac_control/ui_formLogin.py index 1f41da5..bcfbd07 100644 --- a/src/dls_pmac_control/ui_formLogin.py +++ b/src/dls_pmac_control/ui_formLogin.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Form implementation generated from reading ui file 'dls_pmaccontrol/formLogin.ui' +# Form implementation generated from reading ui file 'dls_pmac_control/formLogin.ui' # # Created by: PyQt5 UI code generator 5.15.4 # diff --git a/src/dls_pmac_control/ui_formPpmacAxisSettings.py b/src/dls_pmac_control/ui_formPpmacAxisSettings.py index ff1ca51..f71e207 100644 --- a/src/dls_pmac_control/ui_formPpmacAxisSettings.py +++ b/src/dls_pmac_control/ui_formPpmacAxisSettings.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Form implementation generated from reading ui file 'dls_pmaccontrol/formPpmacAxisSettings.ui' +# Form implementation generated from reading ui file 'dls_pmac_control/formPpmacAxisSettings.ui' # # Created by: PyQt5 UI code generator 5.12.2 # diff --git a/src/dls_pmac_control/ui_formPpmacCSStatus.py b/src/dls_pmac_control/ui_formPpmacCSStatus.py index da55039..d369ec6 100644 --- a/src/dls_pmac_control/ui_formPpmacCSStatus.py +++ b/src/dls_pmac_control/ui_formPpmacCSStatus.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Form implementation generated from reading ui file 'dls_pmaccontrol/formPpmacCSStatus.ui' +# Form implementation generated from reading ui file 'dls_pmac_control/formPpmacCSStatus.ui' # # Created by: PyQt5 UI code generator 5.15.4 # diff --git a/src/dls_pmac_control/ui_formStatus.py b/src/dls_pmac_control/ui_formStatus.py index 1f293ea..b772ea9 100644 --- a/src/dls_pmac_control/ui_formStatus.py +++ b/src/dls_pmac_control/ui_formStatus.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Form implementation generated from reading ui file 'dls_pmaccontrol/formStatus.ui' +# Form implementation generated from reading ui file 'dls_pmac_control/formStatus.ui' # # Created by: PyQt5 UI code generator 5.15.4 # diff --git a/src/dls_pmac_control/ui_formWatches.py b/src/dls_pmac_control/ui_formWatches.py index 40c53cd..a66061b 100644 --- a/src/dls_pmac_control/ui_formWatches.py +++ b/src/dls_pmac_control/ui_formWatches.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Form implementation generated from reading ui file 'dls_pmaccontrol/formWatches.ui' +# Form implementation generated from reading ui file 'dls_pmac_control/formWatches.ui' # # Created by: PyQt5 UI code generator 5.15.4 # diff --git a/src/dls_pmac_control/watches.py b/src/dls_pmac_control/watches.py index d584fd1..ab0ff0d 100644 --- a/src/dls_pmac_control/watches.py +++ b/src/dls_pmac_control/watches.py @@ -4,7 +4,7 @@ from PyQt5.QtWidgets import QDialog, QMessageBox, QTableWidgetItem -from dls_pmaccontrol.ui_formWatches import Ui_formWatches +from dls_pmac_control.ui_formWatches import Ui_formWatches # [TODO] Make sure variable types are not changed when writing to the PMAC # [TODO] Add warnings when value being edited has changed in diff --git a/tests/test_axissettings.py b/tests/test_axissettings.py index f29fbf1..65c2836 100644 --- a/tests/test_axissettings.py +++ b/tests/test_axissettings.py @@ -5,7 +5,7 @@ from PyQt5.QtTest import QTest from PyQt5.QtWidgets import QMainWindow -from dls_pmaccontrol.axissettings import Axissettingsform, PpmacAxissettingsform +from dls_pmac_control.axissettings import Axissettingsform, PpmacAxissettingsform class DummyTestWidget(QMainWindow): @@ -45,9 +45,9 @@ def test_change_axis_not_visible(self): assert self.obj.currentMotor == 2 @patch( - "dls_pmaccontrol.axissettings.Axissettingsform._updateAxisSignalControlsVars" + "dls_pmac_control.axissettings.Axissettingsform._updateAxisSignalControlsVars" ) - @patch("dls_pmaccontrol.axissettings.Axissettingsform._updateAxisSetupIVars") + @patch("dls_pmac_control.axissettings.Axissettingsform._updateAxisSetupIVars") def test_change_axis_visible(self, mock_setup, mock_signal): self.obj.show() self.obj.changeAxis(2) @@ -57,9 +57,9 @@ def test_change_axis_visible(self, mock_setup, mock_signal): self.assertTrue(mock_signal.called) @patch( - "dls_pmaccontrol.axissettings.Axissettingsform._updateAxisSignalControlsVars" + "dls_pmac_control.axissettings.Axissettingsform._updateAxisSignalControlsVars" ) - @patch("dls_pmaccontrol.axissettings.Axissettingsform._updateAxisSetupIVars") + @patch("dls_pmac_control.axissettings.Axissettingsform._updateAxisSetupIVars") def test_change_tab(self, mock_setup, mock_signal): QTest.mouseClick(self.obj.tabAxisSetup, Qt.LeftButton) assert self.obj.tabAxisSetup.currentIndex() == 1 @@ -100,7 +100,7 @@ def test_sendOutputMode(self): self.obj.sendLoopSelect() self.assertTrue(self.test_widget.pmac.setOnboardAxisI7000PlusIVar.called) - @patch("dls_pmaccontrol.axissettings.Axissettingsform.axisUpdate") + @patch("dls_pmac_control.axissettings.Axissettingsform.axisUpdate") def test_sendIx(self, mock_update): ivars = [11, 12, 13, 14, 15, 16, 17, 19, 20, 21, 22, 23, 25, 26] for i in range(len(ivars)): @@ -121,14 +121,14 @@ def test_change_axis_not_visible(self): self.obj.changeAxis(2) assert self.obj.currentMotor == 2 - @patch("dls_pmaccontrol.axissettings.PpmacAxissettingsform._updateAxisSetupIVars") + @patch("dls_pmac_control.axissettings.PpmacAxissettingsform._updateAxisSetupIVars") def test_change_axis_visible(self, mock_setup): self.obj.show() self.obj.changeAxis(2) assert self.obj.currentMotor == 2 self.assertTrue(mock_setup.called) - @patch("dls_pmaccontrol.axissettings.PpmacAxissettingsform._updateAxisSetupIVars") + @patch("dls_pmac_control.axissettings.PpmacAxissettingsform._updateAxisSetupIVars") def test_change_tab(self, mock_setup): QTest.mouseClick(self.obj.tabAxisSetup, Qt.LeftButton) assert self.obj.tabAxisSetup.currentIndex() == 0 @@ -139,13 +139,13 @@ def test_updateAxisSetupIVars(self): assert self.obj.lneIx16.text() == "return" assert self.obj.lneIx23.text() == "return" - @patch("dls_pmaccontrol.axissettings.PpmacAxissettingsform.axisUpdate") + @patch("dls_pmac_control.axissettings.PpmacAxissettingsform.axisUpdate") def test_setAxisSetupIVar(self, mock_update): self.obj.setAxisSetupIVar(12, 1234) self.assertTrue(mock_update.called) - @patch("dls_pmaccontrol.axissettings.PpmacAxissettingsform.setAxisSetupIVar") - @patch("dls_pmaccontrol.axissettings.PpmacAxissettingsform.axisUpdate") + @patch("dls_pmac_control.axissettings.PpmacAxissettingsform.setAxisSetupIVar") + @patch("dls_pmac_control.axissettings.PpmacAxissettingsform.axisUpdate") def test_sendIx(self, mock_update, mock_setup): ivars = [11, 12, 13, 14, 15, 16, 17, 19, 20, 21, 22, 23, 25, 26] for i in range(len(ivars)): diff --git a/tests/test_commsthread.py b/tests/test_commsthread.py index fd12067..60addcd 100644 --- a/tests/test_commsthread.py +++ b/tests/test_commsthread.py @@ -3,7 +3,7 @@ from mock import Mock, patch from PyQt5.QtWidgets import QMainWindow -from dls_pmaccontrol.commsThread import CommsThread +from dls_pmac_control.commsThread import CommsThread class DummyTestWidget(QMainWindow): @@ -60,21 +60,21 @@ def test_read_watch(self): assert self.obj.read_watch("test") is None @patch("PyQt5.QtCore.QCoreApplication.postEvent") - @patch("dls_pmaccontrol.commsThread.CustomEvent") + @patch("dls_pmac_control.commsThread.CustomEvent") def test_send_tick(self, mock_custom, mock_event): self.obj.sendTick(0, "err") assert mock_custom.called assert mock_event.called @patch("PyQt5.QtCore.QCoreApplication.postEvent") - @patch("dls_pmaccontrol.commsThread.CustomEvent") + @patch("dls_pmac_control.commsThread.CustomEvent") def test_send_complete(self, mock_custom, mock_event): self.obj.sendComplete("msg") assert self.obj.gen is None assert mock_custom.called assert mock_event.called - @patch("dls_pmaccontrol.commsThread.CommsThread.updateFunc") + @patch("dls_pmac_control.commsThread.CommsThread.updateFunc") def test_update_thread(self, mock_updatefunc): mock_updatefunc.return_value = True self.obj.updateThread() @@ -96,7 +96,7 @@ def test_update_func_die(self, mock_get): mock_get.assert_called_with(block=False) @patch("PyQt5.QtCore.QCoreApplication.postEvent") - @patch("dls_pmaccontrol.commsThread.CustomEvent") + @patch("dls_pmac_control.commsThread.CustomEvent") @patch("queue.Queue.put") @patch("queue.Queue.get") def test_update_func_sendseries(self, mock_get, mock_put, mock_custom, mock_event): @@ -118,7 +118,7 @@ def test_update_func_disable(self, mock_get): mock_get.assert_called_with(block=False) @patch("PyQt5.QtCore.QCoreApplication.postEvent") - @patch("dls_pmaccontrol.commsThread.CustomEvent") + @patch("dls_pmac_control.commsThread.CustomEvent") @patch("queue.Queue.put") @patch("queue.Queue.get") def test_update_func_cancel(self, mock_get, mock_put, mock_custom, mock_event): diff --git a/tests/test_csstatus.py b/tests/test_csstatus.py index d78e932..c559736 100644 --- a/tests/test_csstatus.py +++ b/tests/test_csstatus.py @@ -7,7 +7,7 @@ from PyQt5.QtTest import QTest from PyQt5.QtWidgets import QMainWindow -from dls_pmaccontrol.CSstatus import CSStatusForm, PpmacCSStatusForm +from dls_pmac_control.CSstatus import CSStatusForm, PpmacCSStatusForm class DummyTestWidget(QMainWindow): diff --git a/tests/test_dls_pmaccontrol.py b/tests/test_dls_pmaccontrol.py index 8fbe80a..9d95020 100644 --- a/tests/test_dls_pmaccontrol.py +++ b/tests/test_dls_pmaccontrol.py @@ -1,9 +1,9 @@ import subprocess import sys -from dls_pmaccontrol import __version__ +from dls_pmac_control import __version__ def test_cli_version(): - cmd = [sys.executable, "-m", "dls_pmaccontrol", "--version"] + cmd = [sys.executable, "-m", "dls_pmac_control", "--version"] assert subprocess.check_output(cmd).decode().strip() == __version__ diff --git a/tests/test_energise.py b/tests/test_energise.py index a64bb77..e722b1f 100644 --- a/tests/test_energise.py +++ b/tests/test_energise.py @@ -3,7 +3,7 @@ from mock import Mock, patch from PyQt5.QtWidgets import QCheckBox, QMainWindow -from dls_pmaccontrol.energise import Energiseform +from dls_pmac_control.energise import Energiseform class DummyTestWidget(QMainWindow): @@ -17,9 +17,9 @@ def __init__(self, parent=None): class EnergiseTest(unittest.TestCase): - @patch("dls_pmaccontrol.energise.Energiseform.updateScreen") - @patch("dls_pmaccontrol.energise.Energiseform.readM750x") - @patch("dls_pmaccontrol.energise.Energiseform.createCheckBoxes") + @patch("dls_pmac_control.energise.Energiseform.updateScreen") + @patch("dls_pmac_control.energise.Energiseform.readM750x") + @patch("dls_pmac_control.energise.Energiseform.createCheckBoxes") def setUp(self, mock_boxes, mock_read, mock_update): mock_read.return_value = (0, 0) self.test_widget = DummyTestWidget() @@ -48,17 +48,17 @@ def test_update_screen(self): for k in range(18, 32): assert self.obj.lstCheckBoxes[k].isChecked() is False - @patch("dls_pmaccontrol.energise.Energiseform.readM750x") + @patch("dls_pmac_control.energise.Energiseform.readM750x") def test_isScreenUpToDate(self, mock_read): mock_read.return_value = (0x00FFFF, 0x00FFFF) self.obj.val7501 = 0x00FFFF self.obj.val7503 = 0x00FFFF assert self.obj.isScreenUpToDate() is True - @patch("dls_pmaccontrol.energise.Energiseform.updateScreen") - @patch("dls_pmaccontrol.energise.Energiseform.readM750x") + @patch("dls_pmac_control.energise.Energiseform.updateScreen") + @patch("dls_pmac_control.energise.Energiseform.readM750x") @patch("PyQt5.QtWidgets.QMessageBox.information") - @patch("dls_pmaccontrol.energise.Energiseform.isScreenUpToDate") + @patch("dls_pmac_control.energise.Energiseform.isScreenUpToDate") def test_sendCommand_outofdate(self, mock_screen, mock_box, mock_read, mock_update): mock_screen.return_value = False mock_read.return_value = (None, None) @@ -78,7 +78,7 @@ def test_sendCommand_outofdate(self, mock_screen, mock_box, mock_read, mock_upda assert mock_read.called assert mock_screen.called - @patch("dls_pmaccontrol.energise.Energiseform.isScreenUpToDate") + @patch("dls_pmac_control.energise.Energiseform.isScreenUpToDate") def test_sendCommand_uptodate(self, mock_screen): mock_screen.return_value = True self.obj.val7501 = 0xFF0000 diff --git a/tests/test_gather.py b/tests/test_gather.py index b7c3277..a15ffb8 100644 --- a/tests/test_gather.py +++ b/tests/test_gather.py @@ -7,8 +7,8 @@ from PyQt5.QtWidgets import QMainWindow from qwt import QwtPlotCurve -from dls_pmaccontrol.gather import PmacGatherform -from dls_pmaccontrol.ppmacgather import PpmacGatherform +from dls_pmac_control.gather import PmacGatherform +from dls_pmac_control.ppmacgather import PpmacGatherform class DummyTestWidget(QMainWindow): @@ -89,14 +89,14 @@ def test_gather_setup(self): assert self.obj.lstChannels[1].dataType == int assert self.obj.lstChannels[2].dataType == int - @patch("dls_pmaccontrol.gather.PmacGatherform.calcSampleTime") + @patch("dls_pmac_control.gather.PmacGatherform.calcSampleTime") def test_change_no_samples(self, mock_calc): self.obj.lneNumberSamples.setText("1000") QTest.keyClick(self.obj.lneNumberSamples, Qt.Key_Enter) assert self.obj.nGatherPoints == 1000 assert self.obj.nServoCyclesGather == 10 - @patch("dls_pmaccontrol.gather.PmacGatherform.calcSampleTime") + @patch("dls_pmac_control.gather.PmacGatherform.calcSampleTime") def test_change_sample_time(self, mock_calc): self.obj.lneSampleTime.setText("5") QTest.keyClick(self.obj.lneSampleTime, Qt.Key_Enter) @@ -113,7 +113,7 @@ def test_click_apply(self): self.assertFalse(self.obj.btnCollect.isEnabled()) self.assertFalse(self.obj.btnSave.isEnabled()) - @patch("dls_pmaccontrol.gather.PmacGatherform.gatherSetup") + @patch("dls_pmac_control.gather.PmacGatherform.gatherSetup") def test_setup_clicked(self, mock_setup): self.obj.btnSetup.setEnabled(True) QTest.mouseClick(self.obj.btnSetup, Qt.LeftButton) @@ -150,8 +150,8 @@ def test_calc_sample_time(self): assert self.obj.servoCycleTime == 1.0 assert self.obj.sampleTime == 1.0 - @patch("dls_pmaccontrol.gather.PmacGatherform.plotData") - @patch("dls_pmaccontrol.gather.PmacGatherform.collectData") + @patch("dls_pmac_control.gather.PmacGatherform.plotData") + @patch("dls_pmac_control.gather.PmacGatherform.collectData") def test_collect_clicked(self, mock_collect, mock_plot): self.obj.btnCollect.setEnabled(True) QTest.mouseClick(self.obj.btnCollect, Qt.LeftButton) @@ -233,7 +233,7 @@ def test_gather_config_chkbox_checked(self): assert self.obj.gatherConfig() is True self.test_widget.pmac.sendCommand.assert_called_with("Gather.items=1") - @patch("dls_pmaccontrol.ppmacgather.PpmacGatherform.gatherConfig") + @patch("dls_pmac_control.ppmacgather.PpmacGatherform.gatherConfig") def test_click_apply(self, mock_config): mock_config.return_value = True self.obj.nServoCyclesGather = 10 @@ -273,7 +273,7 @@ def test_calc_sample_time(self): assert self.obj.servoCycleTime == 1.0 assert self.obj.sampleTime == 1.0 - @patch("dls_pmaccontrol.ppmacgather.PpmacGatherform.calcSampleTime") + @patch("dls_pmac_control.ppmacgather.PpmacGatherform.calcSampleTime") def test_changed_tab(self, mock_calc): attrs = {"sendCommand.return_value": ("10", True)} self.obj.parent.pmac.configure_mock(**attrs) @@ -286,8 +286,8 @@ def test_changed_tab(self, mock_calc): assert self.obj.nGatherPoints == 10 assert self.obj.lneNumberSamples.text() == "10" - @patch("dls_pmaccontrol.ppmacgather.PpmacGatherform.plotData") - @patch("dls_pmaccontrol.ppmacgather.PpmacGatherform.collectData") + @patch("dls_pmac_control.ppmacgather.PpmacGatherform.plotData") + @patch("dls_pmac_control.ppmacgather.PpmacGatherform.collectData") def test_collect_clicked(self, mock_collect, mock_plot): self.obj.btnCollect.setEnabled(True) QTest.mouseClick(self.obj.btnCollect, Qt.LeftButton) diff --git a/tests/test_gatherchannel.py b/tests/test_gatherchannel.py index 619797f..1f54390 100644 --- a/tests/test_gatherchannel.py +++ b/tests/test_gatherchannel.py @@ -4,7 +4,7 @@ from PyQt5.QtWidgets import QMainWindow from qwt import QwtPlotCurve -from dls_pmaccontrol.gatherchannel import PmacGatherChannel, PpmacGatherChannel +from dls_pmac_control.gatherchannel import PmacGatherChannel, PpmacGatherChannel class DummyTestWidget(QMainWindow): diff --git a/tests/test_globalstatus.py b/tests/test_globalstatus.py index f4ad9ea..6930efd 100644 --- a/tests/test_globalstatus.py +++ b/tests/test_globalstatus.py @@ -5,7 +5,7 @@ from PyQt5.QtGui import QPixmap from PyQt5.QtWidgets import QMainWindow -from dls_pmaccontrol.GlobalStatus import GlobalStatusForm, PpmacGlobalStatusForm +from dls_pmac_control.GlobalStatus import GlobalStatusForm, PpmacGlobalStatusForm class DummyTestWidget(QMainWindow): diff --git a/tests/test_login.py b/tests/test_login.py index 977d38c..b324db7 100644 --- a/tests/test_login.py +++ b/tests/test_login.py @@ -6,7 +6,7 @@ from PyQt5.QtTest import QTest from PyQt5.QtWidgets import QApplication, QWidget -from dls_pmaccontrol.login import Loginform +from dls_pmac_control.login import Loginform app = QApplication(sys.argv) test_widget = QWidget() @@ -22,7 +22,7 @@ def test_inital_form(self): self.assertTrue(self.obj.btnCancel.isEnabled()) self.assertTrue(self.obj.btnOK.isEnabled()) - @patch("dls_pmaccontrol.login.Loginform.accept") + @patch("dls_pmac_control.login.Loginform.accept") def test_ok_clicked(self, mock_accept): self.obj.lneUsername.setText("username") self.obj.lnePassword.setText("password") @@ -33,7 +33,7 @@ def test_ok_clicked(self, mock_accept): self.assertEqual(self.obj.lnePassword.text(), "password") assert mock_accept.called - @patch("dls_pmaccontrol.login.Loginform.reject") + @patch("dls_pmac_control.login.Loginform.reject") def test_cancel_clicked(self, mock_reject): self.obj.lneUsername.setText("username") self.obj.lnePassword.setText("password") diff --git a/tests/test_motor.py b/tests/test_motor.py index 585e747..4a2147e 100644 --- a/tests/test_motor.py +++ b/tests/test_motor.py @@ -5,7 +5,7 @@ from PyQt5.QtCore import Qt from PyQt5.QtTest import QTest -from dls_pmaccontrol.motor import Controlform +from dls_pmac_control.motor import Controlform class DummyTestOptionsTelnet: @@ -65,19 +65,19 @@ def __init__(self): class MotorTestTelnet(unittest.TestCase): - @patch("dls_pmaccontrol.status.Statusform") - @patch("dls_pmaccontrol.status.PpmacStatusform") - @patch("dls_pmaccontrol.CSstatus.CSStatusForm") - @patch("dls_pmaccontrol.CSstatus.PpmacCSStatusForm") - @patch("dls_pmaccontrol.GlobalStatus.GlobalStatusForm") - @patch("dls_pmaccontrol.GlobalStatus.PpmacGlobalStatusForm") - @patch("dls_pmaccontrol.axissettings.Axissettingsform") - @patch("dls_pmaccontrol.axissettings.PpmacAxissettingsform") - @patch("dls_pmaccontrol.gather.PmacGatherform") - @patch("dls_pmaccontrol.ppmacgather.PpmacGatherform") - @patch("dls_pmaccontrol.watches.Watchesform") - @patch("dls_pmaccontrol.login.Loginform") - @patch("dls_pmaccontrol.commsThread.CommsThread") + @patch("dls_pmac_control.status.Statusform") + @patch("dls_pmac_control.status.PpmacStatusform") + @patch("dls_pmac_control.CSstatus.CSStatusForm") + @patch("dls_pmac_control.CSstatus.PpmacCSStatusForm") + @patch("dls_pmac_control.GlobalStatus.GlobalStatusForm") + @patch("dls_pmac_control.GlobalStatus.PpmacGlobalStatusForm") + @patch("dls_pmac_control.axissettings.Axissettingsform") + @patch("dls_pmac_control.axissettings.PpmacAxissettingsform") + @patch("dls_pmac_control.gather.PmacGatherform") + @patch("dls_pmac_control.ppmacgather.PpmacGatherform") + @patch("dls_pmac_control.watches.Watchesform") + @patch("dls_pmac_control.login.Loginform") + @patch("dls_pmac_control.commsThread.CommsThread") @patch("PyQt5.QtCore.QEvent") @patch("threading.Thread") @patch("signal.signal") @@ -265,19 +265,19 @@ class MotorTestTelnetConnectionRequired(unittest.TestCase): @patch("dls_pmaclib.dls_pmacremote.PmacTelnetInterface.getPmacModel") @patch("dls_pmaclib.dls_pmacremote.PmacTelnetInterface.connect") @patch("dls_pmaclib.dls_pmacremote.PmacTelnetInterface.setConnectionParams") - @patch("dls_pmaccontrol.status.Statusform") - @patch("dls_pmaccontrol.status.PpmacStatusform") - @patch("dls_pmaccontrol.CSstatus.CSStatusForm") - @patch("dls_pmaccontrol.CSstatus.PpmacCSStatusForm") - @patch("dls_pmaccontrol.GlobalStatus.GlobalStatusForm") - @patch("dls_pmaccontrol.GlobalStatus.PpmacGlobalStatusForm") - @patch("dls_pmaccontrol.axissettings.Axissettingsform") - @patch("dls_pmaccontrol.axissettings.PpmacAxissettingsform") - @patch("dls_pmaccontrol.gather.PmacGatherform") - @patch("dls_pmaccontrol.ppmacgather.PpmacGatherform") - @patch("dls_pmaccontrol.watches.Watchesform") - @patch("dls_pmaccontrol.login.Loginform") - @patch("dls_pmaccontrol.commsThread.CommsThread") + @patch("dls_pmac_control.status.Statusform") + @patch("dls_pmac_control.status.PpmacStatusform") + @patch("dls_pmac_control.CSstatus.CSStatusForm") + @patch("dls_pmac_control.CSstatus.PpmacCSStatusForm") + @patch("dls_pmac_control.GlobalStatus.GlobalStatusForm") + @patch("dls_pmac_control.GlobalStatus.PpmacGlobalStatusForm") + @patch("dls_pmac_control.axissettings.Axissettingsform") + @patch("dls_pmac_control.axissettings.PpmacAxissettingsform") + @patch("dls_pmac_control.gather.PmacGatherform") + @patch("dls_pmac_control.ppmacgather.PpmacGatherform") + @patch("dls_pmac_control.watches.Watchesform") + @patch("dls_pmac_control.login.Loginform") + @patch("dls_pmac_control.commsThread.CommsThread") @patch("PyQt5.QtCore.QEvent") @patch("threading.Thread") @patch("signal.signal") @@ -350,7 +350,7 @@ def test_remote_disconnect(self, mock_disconnect, mock_pixmap): mock_pixmap.assert_called_with(self.obj.greenLedOff) assert self.obj.lblIdentity.text() == "" - @patch("dls_pmaccontrol.motor.Controlform.addToTxtShell") + @patch("dls_pmac_control.motor.Controlform.addToTxtShell") @patch("dls_pmaclib.dls_pmacremote.PmacTelnetInterface.jogInc") def test_jog_neg(self, mock_joginc, mock_addtxt): mock_joginc.return_value = ("cmd", "response", True) @@ -359,7 +359,7 @@ def test_jog_neg(self, mock_joginc, mock_addtxt): self.obj.currentMotor, "neg", str(self.obj.lneJogDist.text()) ) - @patch("dls_pmaccontrol.motor.Controlform.addToTxtShell") + @patch("dls_pmac_control.motor.Controlform.addToTxtShell") @patch("dls_pmaclib.dls_pmacremote.PmacTelnetInterface.jogInc") def test_jog_pos(self, mock_joginc, mock_addtxt): mock_joginc.return_value = ("cmd", "response", True) @@ -368,14 +368,14 @@ def test_jog_pos(self, mock_joginc, mock_addtxt): self.obj.currentMotor, "pos", str(self.obj.lneJogDist.text()) ) - @patch("dls_pmaccontrol.motor.Controlform.addToTxtShell") + @patch("dls_pmac_control.motor.Controlform.addToTxtShell") @patch("dls_pmaclib.dls_pmacremote.PmacTelnetInterface.jogStop") def test_jog_stop(self, mock_jogstop, mock_addtxt): mock_jogstop.return_value = ("cmd", "response", True) assert self.obj.jogStop() is None mock_jogstop.assert_called_with(self.obj.currentMotor) - @patch("dls_pmaccontrol.motor.Controlform.addToTxtShell") + @patch("dls_pmac_control.motor.Controlform.addToTxtShell") @patch("dls_pmaclib.dls_pmacremote.PmacTelnetInterface.homeCommand") def test_jog_home(self, mock_home, mock_addtxt): mock_home.return_value = ("cmd", "response", True) @@ -388,19 +388,19 @@ def tearDown(self): class MotorTestEthernet(unittest.TestCase): - @patch("dls_pmaccontrol.status.Statusform") - @patch("dls_pmaccontrol.status.PpmacStatusform") - @patch("dls_pmaccontrol.CSstatus.CSStatusForm") - @patch("dls_pmaccontrol.CSstatus.PpmacCSStatusForm") - @patch("dls_pmaccontrol.GlobalStatus.GlobalStatusForm") - @patch("dls_pmaccontrol.GlobalStatus.PpmacGlobalStatusForm") - @patch("dls_pmaccontrol.axissettings.Axissettingsform") - @patch("dls_pmaccontrol.axissettings.PpmacAxissettingsform") - @patch("dls_pmaccontrol.gather.PmacGatherform") - @patch("dls_pmaccontrol.ppmacgather.PpmacGatherform") - @patch("dls_pmaccontrol.watches.Watchesform") - @patch("dls_pmaccontrol.login.Loginform") - @patch("dls_pmaccontrol.commsThread.CommsThread") + @patch("dls_pmac_control.status.Statusform") + @patch("dls_pmac_control.status.PpmacStatusform") + @patch("dls_pmac_control.CSstatus.CSStatusForm") + @patch("dls_pmac_control.CSstatus.PpmacCSStatusForm") + @patch("dls_pmac_control.GlobalStatus.GlobalStatusForm") + @patch("dls_pmac_control.GlobalStatus.PpmacGlobalStatusForm") + @patch("dls_pmac_control.axissettings.Axissettingsform") + @patch("dls_pmac_control.axissettings.PpmacAxissettingsform") + @patch("dls_pmac_control.gather.PmacGatherform") + @patch("dls_pmac_control.ppmacgather.PpmacGatherform") + @patch("dls_pmac_control.watches.Watchesform") + @patch("dls_pmac_control.login.Loginform") + @patch("dls_pmac_control.commsThread.CommsThread") @patch("PyQt5.QtCore.QEvent") @patch("threading.Thread") @patch("signal.signal") @@ -543,19 +543,19 @@ def tearDown(self): class MotorTestSerial(unittest.TestCase): - @patch("dls_pmaccontrol.status.Statusform") - @patch("dls_pmaccontrol.status.PpmacStatusform") - @patch("dls_pmaccontrol.CSstatus.CSStatusForm") - @patch("dls_pmaccontrol.CSstatus.PpmacCSStatusForm") - @patch("dls_pmaccontrol.GlobalStatus.GlobalStatusForm") - @patch("dls_pmaccontrol.GlobalStatus.PpmacGlobalStatusForm") - @patch("dls_pmaccontrol.axissettings.Axissettingsform") - @patch("dls_pmaccontrol.axissettings.PpmacAxissettingsform") - @patch("dls_pmaccontrol.gather.PmacGatherform") - @patch("dls_pmaccontrol.ppmacgather.PpmacGatherform") - @patch("dls_pmaccontrol.watches.Watchesform") - @patch("dls_pmaccontrol.login.Loginform") - @patch("dls_pmaccontrol.commsThread.CommsThread") + @patch("dls_pmac_control.status.Statusform") + @patch("dls_pmac_control.status.PpmacStatusform") + @patch("dls_pmac_control.CSstatus.CSStatusForm") + @patch("dls_pmac_control.CSstatus.PpmacCSStatusForm") + @patch("dls_pmac_control.GlobalStatus.GlobalStatusForm") + @patch("dls_pmac_control.GlobalStatus.PpmacGlobalStatusForm") + @patch("dls_pmac_control.axissettings.Axissettingsform") + @patch("dls_pmac_control.axissettings.PpmacAxissettingsform") + @patch("dls_pmac_control.gather.PmacGatherform") + @patch("dls_pmac_control.ppmacgather.PpmacGatherform") + @patch("dls_pmac_control.watches.Watchesform") + @patch("dls_pmac_control.login.Loginform") + @patch("dls_pmac_control.commsThread.CommsThread") @patch("PyQt5.QtCore.QEvent") @patch("threading.Thread") @patch("signal.signal") @@ -717,19 +717,19 @@ def tearDown(self): class MotorTestSsh(unittest.TestCase): - @patch("dls_pmaccontrol.status.Statusform") - @patch("dls_pmaccontrol.status.PpmacStatusform") - @patch("dls_pmaccontrol.CSstatus.CSStatusForm") - @patch("dls_pmaccontrol.CSstatus.PpmacCSStatusForm") - @patch("dls_pmaccontrol.GlobalStatus.GlobalStatusForm") - @patch("dls_pmaccontrol.GlobalStatus.PpmacGlobalStatusForm") - @patch("dls_pmaccontrol.axissettings.Axissettingsform") - @patch("dls_pmaccontrol.axissettings.PpmacAxissettingsform") - @patch("dls_pmaccontrol.gather.PmacGatherform") - @patch("dls_pmaccontrol.ppmacgather.PpmacGatherform") - @patch("dls_pmaccontrol.watches.Watchesform") - @patch("dls_pmaccontrol.login.Loginform") - @patch("dls_pmaccontrol.commsThread.CommsThread") + @patch("dls_pmac_control.status.Statusform") + @patch("dls_pmac_control.status.PpmacStatusform") + @patch("dls_pmac_control.CSstatus.CSStatusForm") + @patch("dls_pmac_control.CSstatus.PpmacCSStatusForm") + @patch("dls_pmac_control.GlobalStatus.GlobalStatusForm") + @patch("dls_pmac_control.GlobalStatus.PpmacGlobalStatusForm") + @patch("dls_pmac_control.axissettings.Axissettingsform") + @patch("dls_pmac_control.axissettings.PpmacAxissettingsform") + @patch("dls_pmac_control.gather.PmacGatherform") + @patch("dls_pmac_control.ppmacgather.PpmacGatherform") + @patch("dls_pmac_control.watches.Watchesform") + @patch("dls_pmac_control.login.Loginform") + @patch("dls_pmac_control.commsThread.CommsThread") @patch("PyQt5.QtCore.QEvent") @patch("threading.Thread") @patch("signal.signal") @@ -779,7 +779,7 @@ def test_useSshConnection(self): self.assertFalse(self.obj.lnePollRate.isEnabled()) self.assertFalse(self.obj.lblPollRate.isEnabled()) - @patch("dls_pmaccontrol.login.Loginform.exec") + @patch("dls_pmac_control.login.Loginform.exec") @patch("PyQt5.QtWidgets.QMessageBox.information") @patch("dls_pmaclib.dls_pmacremote.PPmacSshInterface.connect") @patch("dls_pmaclib.dls_pmacremote.PPmacSshInterface.setConnectionParams") @@ -795,7 +795,7 @@ def test_remote_connect_auth_error( assert ret is None @patch("PyQt5.QtWidgets.QLabel.setPixmap") - @patch("dls_pmaccontrol.login.Loginform.exec") + @patch("dls_pmac_control.login.Loginform.exec") @patch("dls_pmaclib.dls_pmacremote.PPmacSshInterface.isModelGeobrick") @patch("dls_pmaclib.dls_pmacremote.PPmacSshInterface.getNumberOfAxes") @patch("dls_pmaclib.dls_pmacremote.PPmacSshInterface.getPmacModel") @@ -871,7 +871,7 @@ def test_update_motors(self): @patch("dls_pmaclib.dls_pmacremote.PPmacSshInterface.getPmacModel") @patch("dls_pmaclib.dls_pmacremote.PPmacSshInterface.connect") @patch("dls_pmaclib.dls_pmacremote.PPmacSshInterface.setConnectionParams") - @patch("dls_pmaccontrol.login.Loginform.exec") + @patch("dls_pmac_control.login.Loginform.exec") def test_update_identity( self, mock_login, diff --git a/tests/test_status.py b/tests/test_status.py index f391f6a..891fe1a 100644 --- a/tests/test_status.py +++ b/tests/test_status.py @@ -5,7 +5,7 @@ from PyQt5.QtGui import QPixmap from PyQt5.QtWidgets import QMainWindow -from dls_pmaccontrol.status import PpmacStatusform, Statusform +from dls_pmac_control.status import PpmacStatusform, Statusform class DummyTestWidget(QMainWindow): diff --git a/tests/test_watches.py b/tests/test_watches.py index f2802f1..51cf856 100644 --- a/tests/test_watches.py +++ b/tests/test_watches.py @@ -5,7 +5,7 @@ from PyQt5.QtTest import QTest from PyQt5.QtWidgets import QMainWindow -from dls_pmaccontrol.watches import Watchesform +from dls_pmac_control.watches import Watchesform class DummyTestWidget(QMainWindow): @@ -57,8 +57,8 @@ def test_add_existing_watch(self, mock_box): self.assertFalse(self.obj.panelEditWatch.isEnabled()) mock_box.assert_called_with(self.obj, "Cannot create watch", error_msg) - @patch("dls_pmaccontrol.watches.Watchesform.getPolledValue") - @patch("dls_pmaccontrol.watches.Watch") + @patch("dls_pmac_control.watches.Watchesform.getPolledValue") + @patch("dls_pmac_control.watches.Watch") def test_add_watch(self, mock_watch, mock_get_value): mock_get_value.return_value = "12" self.obj.lneVariableName.setText("watch") @@ -79,8 +79,8 @@ def test_get_watch_does_not_exist(self): error_msg = 'There is no watch for variable "test"' self.assertRaises(ValueError, msg=error_msg) - @patch("dls_pmaccontrol.watches.Watchesform.getPolledValue") - @patch("dls_pmaccontrol.watches.Watch") + @patch("dls_pmac_control.watches.Watchesform.getPolledValue") + @patch("dls_pmac_control.watches.Watch") def test_remove_watch(self, mock_watch, mock_get_value): # add watch to be removed mock_get_value.return_value = "3" @@ -103,8 +103,8 @@ def test_clear_watches(self): self.assertEqual(self.obj.lneVariableName.text(), "") self.assertEqual(self.obj.lneEditValue.text(), "") - @patch("dls_pmaccontrol.watches.Watchesform.getPolledValue") - @patch("dls_pmaccontrol.watches.Watch") + @patch("dls_pmac_control.watches.Watchesform.getPolledValue") + @patch("dls_pmac_control.watches.Watch") def test_apply_edit_watch(self, mock_watch, mock_get_value): # add watch to be edited mock_get_value.return_value = "-8" From b5f70e150386bd97744408b65272867ebc80296d Mon Sep 17 00:00:00 2001 From: Giles Knap Date: Sun, 11 Feb 2024 20:49:54 +0000 Subject: [PATCH 24/36] fix tests --- .devcontainer.json | 39 --------------------------------- Dockerfile | 6 +++++ RELEASE.txt | 13 ++++++----- pyproject.toml | 2 +- src/dls_pmac_control/watches.py | 4 ++-- tests/test_motor.py | 6 ++--- 6 files changed, 20 insertions(+), 50 deletions(-) delete mode 100644 .devcontainer.json diff --git a/.devcontainer.json b/.devcontainer.json deleted file mode 100644 index d0921df..0000000 --- a/.devcontainer.json +++ /dev/null @@ -1,39 +0,0 @@ -// For format details, see https://aka.ms/devcontainer.json -{ - "name": "Python 3 Developer Container", - "build": { - "dockerfile": "Dockerfile", - "target": "build", - "context": ".", - "args": {} - }, - "remoteEnv": { - "DISPLAY": "${localEnv:DISPLAY}" - }, - // Set *default* container specific settings.json values on container create. - "settings": { - "python.defaultInterpreterPath": "/venv/bin/python", - "python.linting.enabled": true - }, - // Add the IDs of extensions you want installed when the container is created. - "extensions": [ - "ms-python.python", - "ms-python.vscode-pylance" - ], - // Make sure the files we are mapping into the container exist on the host - "initializeCommand": "bash -c 'for i in $HOME/.inputrc; do [ -f $i ] || touch $i; done'", - "runArgs": [ - "--net=host", - "-v=${localEnv:HOME}/.ssh:/root/.ssh", - "-v=${localEnv:HOME}/.inputrc:/root/.inputrc" - ], - "mounts": [ - // map in home directory - not strictly necessary but useful - "source=${localEnv:HOME},target=${localEnv:HOME},type=bind,consistency=cached" - ], - // make the workspace folder the same inside and outside of the container - "workspaceMount": "source=${localWorkspaceFolder},target=${localWorkspaceFolder},type=bind", - "workspaceFolder": "${localWorkspaceFolder}", - // After the container is created, install the python project in editable form - "postCreateCommand": "pip install $([ -f requirements_dev.txt ] && echo -r requirements_dev.txt ) -e .[dev]" -} \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index 6c754ac..5e34e5e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -6,12 +6,17 @@ FROM python:${PYTHON_VERSION} as developer # Add any system dependencies for the developer/build environment here RUN apt-get update && apt-get install -y --no-install-recommends \ graphviz \ + libqt5gui5 libxcb-xinerama0 \ && rm -rf /var/lib/apt/lists/* # Set up a virtual environment and put it in PATH RUN python -m venv /venv ENV PATH=/venv/bin:$PATH +# allow tests to run headless in the dev container +ENV QT_QPA_PLATFORM=offscreen +ENV XDG_RUNTIME_DIR=/tmp/runtime-vscode + # The build stage installs the context into the venv FROM developer as build COPY . /context @@ -27,3 +32,4 @@ ENV PATH=/venv/bin:$PATH # change this entrypoint if it is not the same as the repo ENTRYPOINT ["dls-pmac-control"] CMD ["--version"] + diff --git a/RELEASE.txt b/RELEASE.txt index 4019b46..9afee93 100644 --- a/RELEASE.txt +++ b/RELEASE.txt @@ -2,7 +2,10 @@ Control Application Alpha Release 28th September 2021 Bonnie McCallion -Currently data gather is fully functional for the Power PMAC and there is a simple watch window for both +UPDATE:2024-02 updating to the python copier template - these instructions will +require review. + +Currently data gather is fully functional for the Power PMAC and there is a simple watch window for both PMAC and Power PMAC. Tested on OSL demo hardware, further testing to be done by DLS. To Do: @@ -13,12 +16,12 @@ To Do: Notes: - Loading a pmc file works for the Power PMAC but existing files for PMAC might not work. Some PMAC commands -do not work for Power PMAC (e.g. clear command does not work) and might cause the application to crash/ get +do not work for Power PMAC (e.g. clear command does not work) and might cause the application to crash/ get stuck while downloading. - There is no Ix24 equivalent for the Power PMAC so this has not been included in the axis settings screen. - No scaling has been included for the Power PMAC data gather. Might need to include some checks for this. - - When changing # of samples/ sample time in the config tab you must press enter to change the values. - - Watch window variables are not reformatted before being shown and when writing new values to variables + - When changing # of samples/ sample time in the config tab you must press enter to change the values. + - Watch window variables are not reformatted before being shown and when writing new values to variables the value may be changed (e.g. rounded or converted to a different format). Installation: @@ -46,7 +49,7 @@ Installation: i. Make the screens: - Install pyqt5 pip install pyqt5-tools - - Make + - Make make clean make diff --git a/pyproject.toml b/pyproject.toml index 3638cd0..8f97f75 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -61,7 +61,7 @@ addopts = """ --tb=native -vv --doctest-modules --doctest-glob="*.rst" """ # https://iscinumpy.gitlab.io/post/bound-version-constraints/#watch-for-warnings -filterwarnings = "error" +filterwarnings = ["error", "ignore::DeprecationWarning"] # Doctest python code in docs, python code in src docstrings, test functions in tests testpaths = "docs src tests" diff --git a/src/dls_pmac_control/watches.py b/src/dls_pmac_control/watches.py index ab0ff0d..4733c49 100644 --- a/src/dls_pmac_control/watches.py +++ b/src/dls_pmac_control/watches.py @@ -69,7 +69,7 @@ def updateCurrentWatch(self): def removeWatch(self): row = self.table.currentRow() - if row is -1: + if row == -1: return None assert type(row) is int varName = self.table.item(row, 0).text() @@ -91,7 +91,7 @@ def clickTable(self, row, column): def selectedVarName(self): currRow = self.table.currentRow() - if currRow is -1: + if currRow == -1: return None else: return self.table.item(currRow, 0).text() diff --git a/tests/test_motor.py b/tests/test_motor.py index 4a2147e..3ab12a6 100644 --- a/tests/test_motor.py +++ b/tests/test_motor.py @@ -861,9 +861,9 @@ def test_update_motors(self): self.obj.commsThread.resultQueue.configure_mock(**attrs) ret = self.obj.updateMotors() assert ret is None - assert self.obj.lblPosition.text() == "0.0" - assert self.obj.lblVelo.text() == "0.0" - assert self.obj.lblFolErr.text() == "0.0" + assert float(self.obj.lblPosition.text()) == 0.0 + assert float(self.obj.lblVelo.text()) == 0.0 + assert float(self.obj.lblFolErr.text()) == 0.0 @patch("dls_pmaclib.dls_pmacremote.PPmacSshInterface.getShortModelName") @patch("dls_pmaclib.dls_pmacremote.PPmacSshInterface.isModelGeobrick") From 7a799637dd885d3204b8ec0a6f46c49262123e0b Mon Sep 17 00:00:00 2001 From: Giles Knap Date: Sun, 11 Feb 2024 20:52:49 +0000 Subject: [PATCH 25/36] safe ruff fixes --- docs/conf.py | 2 +- pyproject.toml | 4 +++ src/dls_pmac_control/CSstatus.py | 1 - src/dls_pmac_control/GlobalStatus.py | 1 - src/dls_pmac_control/axissettings.py | 1 - src/dls_pmac_control/commsThread.py | 12 ++++---- src/dls_pmac_control/energise.py | 1 - src/dls_pmac_control/login.py | 1 - src/dls_pmac_control/motor.py | 30 ++++++++++++------- src/dls_pmac_control/status.py | 1 - src/dls_pmac_control/ui_formAxisSettings.py | 5 ++-- src/dls_pmac_control/ui_formCSStatus.py | 5 ++-- src/dls_pmac_control/ui_formControl.py | 3 +- src/dls_pmac_control/ui_formEnergise.py | 5 ++-- src/dls_pmac_control/ui_formGather.py | 3 +- src/dls_pmac_control/ui_formGlobalStatus.py | 5 ++-- src/dls_pmac_control/ui_formLogin.py | 5 ++-- .../ui_formPpmacAxisSettings.py | 5 ++-- src/dls_pmac_control/ui_formPpmacCSStatus.py | 5 ++-- src/dls_pmac_control/ui_formStatus.py | 5 ++-- src/dls_pmac_control/ui_formWatches.py | 5 ++-- src/dls_pmac_control/watches.py | 5 ++-- tests/test_axissettings.py | 2 +- tests/test_commsthread.py | 2 +- tests/test_csstatus.py | 2 +- tests/test_energise.py | 2 +- tests/test_gather.py | 2 +- tests/test_gatherchannel.py | 2 +- tests/test_globalstatus.py | 2 +- tests/test_login.py | 2 +- tests/test_motor.py | 2 +- tests/test_status.py | 2 +- tests/test_watches.py | 2 +- 33 files changed, 64 insertions(+), 68 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index ae2aa88..4066b2f 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -187,4 +187,4 @@ html_logo = "images/dls-logo.svg" html_favicon = html_logo -numfig = True \ No newline at end of file +numfig = True diff --git a/pyproject.toml b/pyproject.toml index 8f97f75..427b0e2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -99,6 +99,10 @@ commands = [tool.ruff] src = ["src", "tests"] line-length = 88 +# ignoring line to long for the moment to avoid signficant changes to the code +lint.ignore = [ + "E501", # line too long +] lint.select = [ "B", # flake8-bugbear - https://docs.astral.sh/ruff/rules/#flake8-bugbear-b "C4", # flake8-comprehensions - https://docs.astral.sh/ruff/rules/#flake8-comprehensions-c4 diff --git a/src/dls_pmac_control/CSstatus.py b/src/dls_pmac_control/CSstatus.py index d209778..dab9081 100755 --- a/src/dls_pmac_control/CSstatus.py +++ b/src/dls_pmac_control/CSstatus.py @@ -1,5 +1,4 @@ #!/bin/env dls-python2.6 -# -*- coding: utf-8 -*- import sys diff --git a/src/dls_pmac_control/GlobalStatus.py b/src/dls_pmac_control/GlobalStatus.py index b18c373..a979eb8 100644 --- a/src/dls_pmac_control/GlobalStatus.py +++ b/src/dls_pmac_control/GlobalStatus.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- import sys from PyQt5.QtCore import QObject, Qt, pyqtSignal, pyqtSlot diff --git a/src/dls_pmac_control/axissettings.py b/src/dls_pmac_control/axissettings.py index 0271e2a..89bb3d5 100644 --- a/src/dls_pmac_control/axissettings.py +++ b/src/dls_pmac_control/axissettings.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from PyQt5.QtWidgets import QDialog, QMessageBox diff --git a/src/dls_pmac_control/commsThread.py b/src/dls_pmac_control/commsThread.py index f8e6153..4fb5321 100644 --- a/src/dls_pmac_control/commsThread.py +++ b/src/dls_pmac_control/commsThread.py @@ -3,11 +3,13 @@ import traceback from queue import Empty, Queue +from dls_pmaclib.dls_pmacremote import ( + PmacEthernetInterface, + PmacSerialInterface, + PPmacSshInterface, +) from PyQt5.QtCore import QCoreApplication, QEvent -from dls_pmaclib.dls_pmacremote import (PmacEthernetInterface, - PmacSerialInterface, PPmacSshInterface) - class CustomEvent(QEvent): _data = None @@ -20,7 +22,7 @@ def data(self): return self._data -class CommsThread(object): +class CommsThread: def __init__(self, parent): self.parent = parent self.CSNum = 1 @@ -159,7 +161,7 @@ def updateFunc(self): # PowerBrick channels are zero-indexed cmd = cmd + "BrickLV.Chan[" + str(motorNo - 1) + "].I2tFaultStatus BrickLV.Chan[" + str(motorNo - 1) + "].OverCurrent" else: - # Add a dummy request to keep the request chunks + # Add a dummy request to keep the request chunks # the same length (p99 always returns zero) cmd = cmd + "m" + str(motorNo) + "90 p99" else: diff --git a/src/dls_pmac_control/energise.py b/src/dls_pmac_control/energise.py index 0472b64..2960f5a 100644 --- a/src/dls_pmac_control/energise.py +++ b/src/dls_pmac_control/energise.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- import re import sys diff --git a/src/dls_pmac_control/login.py b/src/dls_pmac_control/login.py index c0f158a..5b60ae0 100644 --- a/src/dls_pmac_control/login.py +++ b/src/dls_pmac_control/login.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from PyQt5.QtWidgets import QDialog from dls_pmac_control.ui_formLogin import Ui_Login diff --git a/src/dls_pmac_control/motor.py b/src/dls_pmac_control/motor.py index 8fb8b2b..0e68d98 100755 --- a/src/dls_pmac_control/motor.py +++ b/src/dls_pmac_control/motor.py @@ -6,28 +6,36 @@ from os import path from queue import Empty +from dls_pmaclib.dls_pmacremote import ( + PmacEthernetInterface, + PmacSerialInterface, + PmacTelnetInterface, + PPmacSshInterface, +) +from dls_pmaclib.dls_pmcpreprocessor import ClsPmacParser from PyQt5.QtCore import QEvent, Qt, pyqtSlot from PyQt5.QtGui import QIcon, QPixmap -from PyQt5.QtWidgets import (QApplication, QFileDialog, QLineEdit, QMainWindow, - QMessageBox, QProgressDialog, QTableWidgetItem) - -from dls_pmac_control.axissettings import (Axissettingsform, - PpmacAxissettingsform) +from PyQt5.QtWidgets import ( + QApplication, + QFileDialog, + QLineEdit, + QMainWindow, + QMessageBox, + QProgressDialog, + QTableWidgetItem, +) + +from dls_pmac_control.axissettings import Axissettingsform, PpmacAxissettingsform from dls_pmac_control.commsThread import CommsThread from dls_pmac_control.CSstatus import CSStatusForm, PpmacCSStatusForm from dls_pmac_control.energise import Energiseform from dls_pmac_control.gather import PmacGatherform -from dls_pmac_control.GlobalStatus import (GlobalStatusForm, - PpmacGlobalStatusForm) +from dls_pmac_control.GlobalStatus import GlobalStatusForm, PpmacGlobalStatusForm from dls_pmac_control.login import Loginform from dls_pmac_control.ppmacgather import PpmacGatherform from dls_pmac_control.status import PpmacStatusform, Statusform from dls_pmac_control.ui_formControl import Ui_ControlForm from dls_pmac_control.watches import Watchesform -from dls_pmaclib.dls_pmacremote import (PmacEthernetInterface, - PmacSerialInterface, - PmacTelnetInterface, PPmacSshInterface) -from dls_pmaclib.dls_pmcpreprocessor import ClsPmacParser from . import __version__ diff --git a/src/dls_pmac_control/status.py b/src/dls_pmac_control/status.py index 9c95fb5..641ff21 100644 --- a/src/dls_pmac_control/status.py +++ b/src/dls_pmac_control/status.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- import sys diff --git a/src/dls_pmac_control/ui_formAxisSettings.py b/src/dls_pmac_control/ui_formAxisSettings.py index 97cd844..b2e2e52 100644 --- a/src/dls_pmac_control/ui_formAxisSettings.py +++ b/src/dls_pmac_control/ui_formAxisSettings.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Form implementation generated from reading ui file 'dls_pmac_control/formAxisSettings.ui' # @@ -6,10 +5,10 @@ # # WARNING! All changes made in this file will be lost! -from PyQt5 import QtCore, QtGui, QtWidgets +from PyQt5 import QtCore, QtWidgets -class Ui_formAxisSettings(object): +class Ui_formAxisSettings: def setupUi(self, formAxisSettings): formAxisSettings.setObjectName("formAxisSettings") formAxisSettings.resize(508, 548) diff --git a/src/dls_pmac_control/ui_formCSStatus.py b/src/dls_pmac_control/ui_formCSStatus.py index 3ee06de..7660a75 100644 --- a/src/dls_pmac_control/ui_formCSStatus.py +++ b/src/dls_pmac_control/ui_formCSStatus.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Form implementation generated from reading ui file 'src/dls_pmac_control/formCSStatus.ui' # @@ -6,10 +5,10 @@ # # WARNING! All changes made in this file will be lost! -from PyQt5 import QtCore, QtGui, QtWidgets +from PyQt5 import QtCore, QtWidgets -class Ui_formCSStatus(object): +class Ui_formCSStatus: def setupUi(self, formCSStatus): formCSStatus.setObjectName("formCSStatus") formCSStatus.resize(433, 311) diff --git a/src/dls_pmac_control/ui_formControl.py b/src/dls_pmac_control/ui_formControl.py index 1fd6b61..9bbb46a 100644 --- a/src/dls_pmac_control/ui_formControl.py +++ b/src/dls_pmac_control/ui_formControl.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Form implementation generated from reading ui file 'dls_pmac_control/formControl.ui' # @@ -9,7 +8,7 @@ from PyQt5 import QtCore, QtGui, QtWidgets -class Ui_ControlForm(object): +class Ui_ControlForm: def setupUi(self, ControlForm): ControlForm.setObjectName("ControlForm") ControlForm.resize(675, 805) diff --git a/src/dls_pmac_control/ui_formEnergise.py b/src/dls_pmac_control/ui_formEnergise.py index ac9a122..1e193d5 100644 --- a/src/dls_pmac_control/ui_formEnergise.py +++ b/src/dls_pmac_control/ui_formEnergise.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Form implementation generated from reading ui file 'dls_pmac_control/formEnergise.ui' # @@ -8,10 +7,10 @@ # run again. Do not edit this file unless you know what you are doing. -from PyQt5 import QtCore, QtGui, QtWidgets +from PyQt5 import QtCore, QtWidgets -class Ui_formEnergise(object): +class Ui_formEnergise: def setupUi(self, formEnergise): formEnergise.setObjectName("formEnergise") formEnergise.resize(192, 252) diff --git a/src/dls_pmac_control/ui_formGather.py b/src/dls_pmac_control/ui_formGather.py index e0ff1fa..00e3369 100644 --- a/src/dls_pmac_control/ui_formGather.py +++ b/src/dls_pmac_control/ui_formGather.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Form implementation generated from reading ui file 'dls_pmac_control/formGather.ui' # @@ -12,7 +11,7 @@ from qwt import QwtPlot -class Ui_formGather(object): +class Ui_formGather: def setupUi(self, formGather): formGather.setObjectName("formGather") formGather.resize(608, 429) diff --git a/src/dls_pmac_control/ui_formGlobalStatus.py b/src/dls_pmac_control/ui_formGlobalStatus.py index b371a59..b905333 100644 --- a/src/dls_pmac_control/ui_formGlobalStatus.py +++ b/src/dls_pmac_control/ui_formGlobalStatus.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Form implementation generated from reading ui file 'dls_pmac_control/formGlobalStatus.ui' # @@ -8,10 +7,10 @@ # run again. Do not edit this file unless you know what you are doing. -from PyQt5 import QtCore, QtGui, QtWidgets +from PyQt5 import QtCore, QtWidgets -class Ui_formGlobalStatus(object): +class Ui_formGlobalStatus: def setupUi(self, formGlobalStatus): formGlobalStatus.setObjectName("formGlobalStatus") formGlobalStatus.resize(122, 144) diff --git a/src/dls_pmac_control/ui_formLogin.py b/src/dls_pmac_control/ui_formLogin.py index bcfbd07..e46cfcc 100644 --- a/src/dls_pmac_control/ui_formLogin.py +++ b/src/dls_pmac_control/ui_formLogin.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Form implementation generated from reading ui file 'dls_pmac_control/formLogin.ui' # @@ -8,10 +7,10 @@ # run again. Do not edit this file unless you know what you are doing. -from PyQt5 import QtCore, QtGui, QtWidgets +from PyQt5 import QtCore, QtWidgets -class Ui_Login(object): +class Ui_Login: def setupUi(self, Login): Login.setObjectName("Login") Login.resize(314, 145) diff --git a/src/dls_pmac_control/ui_formPpmacAxisSettings.py b/src/dls_pmac_control/ui_formPpmacAxisSettings.py index f71e207..04adb90 100644 --- a/src/dls_pmac_control/ui_formPpmacAxisSettings.py +++ b/src/dls_pmac_control/ui_formPpmacAxisSettings.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Form implementation generated from reading ui file 'dls_pmac_control/formPpmacAxisSettings.ui' # @@ -6,10 +5,10 @@ # # WARNING! All changes made in this file will be lost! -from PyQt5 import QtCore, QtGui, QtWidgets +from PyQt5 import QtCore, QtWidgets -class Ui_formPpmacAxisSettings(object): +class Ui_formPpmacAxisSettings: def setupUi(self, formPpmacAxisSettings): formPpmacAxisSettings.setObjectName("formPpmacAxisSettings") formPpmacAxisSettings.resize(580, 688) diff --git a/src/dls_pmac_control/ui_formPpmacCSStatus.py b/src/dls_pmac_control/ui_formPpmacCSStatus.py index d369ec6..2cbfc20 100644 --- a/src/dls_pmac_control/ui_formPpmacCSStatus.py +++ b/src/dls_pmac_control/ui_formPpmacCSStatus.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Form implementation generated from reading ui file 'dls_pmac_control/formPpmacCSStatus.ui' # @@ -8,10 +7,10 @@ # run again. Do not edit this file unless you know what you are doing. -from PyQt5 import QtCore, QtGui, QtWidgets +from PyQt5 import QtCore, QtWidgets -class Ui_formPpmacCSStatus(object): +class Ui_formPpmacCSStatus: def setupUi(self, formCSStatus): formCSStatus.setObjectName("formCSStatus") formCSStatus.setGeometry(QtCore.QRect(0, 0, 433, 311)) diff --git a/src/dls_pmac_control/ui_formStatus.py b/src/dls_pmac_control/ui_formStatus.py index b772ea9..bcc23ac 100644 --- a/src/dls_pmac_control/ui_formStatus.py +++ b/src/dls_pmac_control/ui_formStatus.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Form implementation generated from reading ui file 'dls_pmac_control/formStatus.ui' # @@ -8,10 +7,10 @@ # run again. Do not edit this file unless you know what you are doing. -from PyQt5 import QtCore, QtGui, QtWidgets +from PyQt5 import QtCore, QtWidgets -class Ui_formStatus(object): +class Ui_formStatus: def setupUi(self, formStatus): formStatus.setObjectName("formStatus") formStatus.resize(99, 189) diff --git a/src/dls_pmac_control/ui_formWatches.py b/src/dls_pmac_control/ui_formWatches.py index a66061b..667b68d 100644 --- a/src/dls_pmac_control/ui_formWatches.py +++ b/src/dls_pmac_control/ui_formWatches.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Form implementation generated from reading ui file 'dls_pmac_control/formWatches.ui' # @@ -8,10 +7,10 @@ # run again. Do not edit this file unless you know what you are doing. -from PyQt5 import QtCore, QtGui, QtWidgets +from PyQt5 import QtCore, QtWidgets -class Ui_formWatches(object): +class Ui_formWatches: def setupUi(self, formWatches): formWatches.setObjectName("formWatches") formWatches.resize(905, 585) diff --git a/src/dls_pmac_control/watches.py b/src/dls_pmac_control/watches.py index 4733c49..ad3a3c6 100644 --- a/src/dls_pmac_control/watches.py +++ b/src/dls_pmac_control/watches.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- import re @@ -115,7 +114,7 @@ def applyEditWatch(self): self.updateCurrentWatch() self.lneEditValue.setText("") self.panelEditWatch.setEnabled(False) - except (ValueError, IOError) as e: + except (OSError, ValueError) as e: self.lneEditValue.setText("") self.panelEditWatch.setEnabled(False) QMessageBox.information(self, "Cannot change value", str(e)) @@ -162,7 +161,7 @@ def _sendPMACCommand(self, command): # Get response from PMAC; the 2nd returned boolean indicates absence of timeout (s, wasNoTimeout) = self.pmac.sendCommand(command) if not wasNoTimeout: - raise IOError("Connection to PMAC timed out") + raise OSError("Connection to PMAC timed out") # Check whether PMAC doesn't reply with an ERRxx type response matchObject = re.match(r"^\x07(ERR\d+)\r$", s) diff --git a/tests/test_axissettings.py b/tests/test_axissettings.py index 65c2836..2776f67 100644 --- a/tests/test_axissettings.py +++ b/tests/test_axissettings.py @@ -1,6 +1,6 @@ import unittest +from unittest.mock import Mock, patch -from mock import Mock, patch from PyQt5.QtCore import Qt from PyQt5.QtTest import QTest from PyQt5.QtWidgets import QMainWindow diff --git a/tests/test_commsthread.py b/tests/test_commsthread.py index 60addcd..9f24d23 100644 --- a/tests/test_commsthread.py +++ b/tests/test_commsthread.py @@ -1,6 +1,6 @@ import unittest +from unittest.mock import Mock, patch -from mock import Mock, patch from PyQt5.QtWidgets import QMainWindow from dls_pmac_control.commsThread import CommsThread diff --git a/tests/test_csstatus.py b/tests/test_csstatus.py index c559736..08d454b 100644 --- a/tests/test_csstatus.py +++ b/tests/test_csstatus.py @@ -1,7 +1,7 @@ import unittest from os import path +from unittest.mock import Mock, patch -from mock import Mock, patch from PyQt5.QtCore import Qt from PyQt5.QtGui import QPixmap from PyQt5.QtTest import QTest diff --git a/tests/test_energise.py b/tests/test_energise.py index e722b1f..1a5b3aa 100644 --- a/tests/test_energise.py +++ b/tests/test_energise.py @@ -1,6 +1,6 @@ import unittest +from unittest.mock import Mock, patch -from mock import Mock, patch from PyQt5.QtWidgets import QCheckBox, QMainWindow from dls_pmac_control.energise import Energiseform diff --git a/tests/test_gather.py b/tests/test_gather.py index a15ffb8..830c33e 100644 --- a/tests/test_gather.py +++ b/tests/test_gather.py @@ -1,7 +1,7 @@ import os import unittest +from unittest.mock import Mock, patch -from mock import Mock, patch from PyQt5.QtCore import QPoint, Qt from PyQt5.QtTest import QTest from PyQt5.QtWidgets import QMainWindow diff --git a/tests/test_gatherchannel.py b/tests/test_gatherchannel.py index 1f54390..be3c262 100644 --- a/tests/test_gatherchannel.py +++ b/tests/test_gatherchannel.py @@ -1,6 +1,6 @@ import unittest +from unittest.mock import Mock -from mock import Mock from PyQt5.QtWidgets import QMainWindow from qwt import QwtPlotCurve diff --git a/tests/test_globalstatus.py b/tests/test_globalstatus.py index 6930efd..12a2695 100644 --- a/tests/test_globalstatus.py +++ b/tests/test_globalstatus.py @@ -1,7 +1,7 @@ import unittest from os import path +from unittest.mock import patch -from mock import patch from PyQt5.QtGui import QPixmap from PyQt5.QtWidgets import QMainWindow diff --git a/tests/test_login.py b/tests/test_login.py index b324db7..e8bf44b 100644 --- a/tests/test_login.py +++ b/tests/test_login.py @@ -1,7 +1,7 @@ import sys import unittest +from unittest.mock import patch -from mock import patch from PyQt5.QtCore import Qt from PyQt5.QtTest import QTest from PyQt5.QtWidgets import QApplication, QWidget diff --git a/tests/test_motor.py b/tests/test_motor.py index 3ab12a6..524e99c 100644 --- a/tests/test_motor.py +++ b/tests/test_motor.py @@ -1,7 +1,7 @@ import os import unittest +from unittest.mock import Mock, patch -from mock import Mock, patch from PyQt5.QtCore import Qt from PyQt5.QtTest import QTest diff --git a/tests/test_status.py b/tests/test_status.py index 891fe1a..d1a2e7c 100644 --- a/tests/test_status.py +++ b/tests/test_status.py @@ -1,7 +1,7 @@ import unittest from os import path +from unittest.mock import patch -from mock import patch from PyQt5.QtGui import QPixmap from PyQt5.QtWidgets import QMainWindow diff --git a/tests/test_watches.py b/tests/test_watches.py index 51cf856..be3ab9d 100644 --- a/tests/test_watches.py +++ b/tests/test_watches.py @@ -1,6 +1,6 @@ import unittest +from unittest.mock import Mock, patch -from mock import Mock, patch from PyQt5.QtCore import Qt from PyQt5.QtTest import QTest from PyQt5.QtWidgets import QMainWindow From 02e3245fd08862400fb5ab71aebfa92fd59bb97a Mon Sep 17 00:00:00 2001 From: Giles Knap Date: Sun, 11 Feb 2024 20:53:45 +0000 Subject: [PATCH 26/36] ruff unsafe fixes --- .github/pages/make_switcher.py | 12 ++++++------ src/dls_pmac_control/CSstatus.py | 4 ++-- src/dls_pmac_control/axissettings.py | 2 +- src/dls_pmac_control/commsThread.py | 2 +- src/dls_pmac_control/energise.py | 2 +- src/dls_pmac_control/gather.py | 8 ++++---- src/dls_pmac_control/motor.py | 6 +++--- src/dls_pmac_control/ppmacgather.py | 4 ++-- src/dls_pmac_control/watches.py | 4 ++-- 9 files changed, 22 insertions(+), 22 deletions(-) diff --git a/.github/pages/make_switcher.py b/.github/pages/make_switcher.py index e2c8e6f..2b81e76 100755 --- a/.github/pages/make_switcher.py +++ b/.github/pages/make_switcher.py @@ -3,28 +3,28 @@ from argparse import ArgumentParser from pathlib import Path from subprocess import CalledProcessError, check_output -from typing import List, Optional +from typing import Optional -def report_output(stdout: bytes, label: str) -> List[str]: +def report_output(stdout: bytes, label: str) -> list[str]: ret = stdout.decode().strip().split("\n") print(f"{label}: {ret}") return ret -def get_branch_contents(ref: str) -> List[str]: +def get_branch_contents(ref: str) -> list[str]: """Get the list of directories in a branch.""" stdout = check_output(["git", "ls-tree", "-d", "--name-only", ref]) return report_output(stdout, "Branch contents") -def get_sorted_tags_list() -> List[str]: +def get_sorted_tags_list() -> list[str]: """Get a list of sorted tags in descending order from the repository.""" stdout = check_output(["git", "tag", "-l", "--sort=-v:refname"]) return report_output(stdout, "Tags list") -def get_versions(ref: str, add: Optional[str]) -> List[str]: +def get_versions(ref: str, add: Optional[str]) -> list[str]: """Generate the file containing the list of all GitHub Pages builds.""" # Get the directories (i.e. builds) from the GitHub Pages branch try: @@ -41,7 +41,7 @@ def get_versions(ref: str, add: Optional[str]) -> List[str]: tags = get_sorted_tags_list() # Make the sorted versions list from main branches and tags - versions: List[str] = [] + versions: list[str] = [] for version in ["master", "main"] + tags: if version in builds: versions.append(version) diff --git a/src/dls_pmac_control/CSstatus.py b/src/dls_pmac_control/CSstatus.py index dab9081..866b17d 100755 --- a/src/dls_pmac_control/CSstatus.py +++ b/src/dls_pmac_control/CSstatus.py @@ -557,7 +557,7 @@ def __init__(self, parent): i = 24 * (word - 1) + bit self.lstLeds.append(QLabel(self.ledGroup)) self.lstLabels.append( - QLabel("Word%s Bit%s" % (word + 1, bit), self.ledGroup) + QLabel(f"Word{word + 1} Bit{bit}", self.ledGroup) ) ledGroupLayout.addWidget(self.lstLeds[i], bit, word * 2) ledGroupLayout.addWidget(self.lstLabels[i], bit, word * 2 + 1) @@ -770,7 +770,7 @@ def __init__(self, parent): i = 16 * (word - 1) + bit self.lstLeds.append(QLabel(self.ledGroup)) self.lstLabels.append( - QLabel("Word%s Bit%s" % (word + 1, bit), self.ledGroup) + QLabel(f"Word{word + 1} Bit{bit}", self.ledGroup) ) ledGroupLayout.addWidget(self.lstLeds[i], bit, word * 2) ledGroupLayout.addWidget(self.lstLabels[i], bit, word * 2 + 1) diff --git a/src/dls_pmac_control/axissettings.py b/src/dls_pmac_control/axissettings.py index 89bb3d5..a47b627 100644 --- a/src/dls_pmac_control/axissettings.py +++ b/src/dls_pmac_control/axissettings.py @@ -375,7 +375,7 @@ def _updateAxisSetupDirectCmds(self, ppmacCmds): retLst.append("Error") if retLst: for i, retVal in enumerate(retLst): - exec('self.lne%s.setText(str("%s"))' % (ppmacCmds[i], retVal)) + exec(f'self.lne{ppmacCmds[i]}.setText(str("{retVal}"))') def axisUpdate(self): self._updateAxisSetupIVars( diff --git a/src/dls_pmac_control/commsThread.py b/src/dls_pmac_control/commsThread.py index 4fb5321..caa27fc 100644 --- a/src/dls_pmac_control/commsThread.py +++ b/src/dls_pmac_control/commsThread.py @@ -127,7 +127,7 @@ def updateFunc(self): else: err = "" if not wasSuccessful: - err = "%s: command '%s' generated '%s'" % ( + err = "{}: command '{}' generated '{}'".format( self.lineNumber, command, pmacResponseStr.replace("\r", " ").replace("\x07", ""), diff --git a/src/dls_pmac_control/energise.py b/src/dls_pmac_control/energise.py index 2960f5a..5702437 100644 --- a/src/dls_pmac_control/energise.py +++ b/src/dls_pmac_control/energise.py @@ -113,7 +113,7 @@ def sendCommand(self): self.val7503 = newVal7503 # Write m7501, m7503 to the PMAC - cmd = "m7501=$%x m7503=$%x" % (self.val7501, self.val7503) + cmd = f"m7501=${self.val7501:x} m7503=${self.val7503:x}" (retStr, retStatus) = self.pmac.sendCommand(cmd) if not retStatus: QMessageBox.information(self, "Error", "Send command error:\n" + retStr) diff --git a/src/dls_pmac_control/gather.py b/src/dls_pmac_control/gather.py index d6ebac6..41ca8ea 100644 --- a/src/dls_pmac_control/gather.py +++ b/src/dls_pmac_control/gather.py @@ -123,7 +123,7 @@ def gatherConfig(self): self.parent.pmac.sendCommand(cmd) # Clear the plot by setting empty plotitems - for chIndex, ch in enumerate(self.lstChannels): + for _chIndex, ch in enumerate(self.lstChannels): ch.qwtCurve.setData([], []) # reset the data channels from class GatherChannel @@ -141,8 +141,8 @@ def gatherConfig(self): baseAddress = motorBaseAddrs[axisSpinBox.value() - 1] dataWidth = pmacDataSources[cmbBox.currentIndex()]["size"] ivar = "i50%02d" % (index + 1) - addr = "$%X%05X" % (dataWidth, baseAddress + dataOffset) - cmd = "%s=%s" % (ivar, addr) + addr = f"${dataWidth:X}{baseAddress + dataOffset:05X}" + cmd = f"{ivar}={addr}" if chkBox.isChecked(): self.parent.pmac.sendCommand(cmd) @@ -314,7 +314,7 @@ def parseData(self, lstDataStrings): def plotData(self): # xAxisData = range(self.numberOfSamples) - for chIndex, ch in enumerate(self.lstChannels): + for _chIndex, ch in enumerate(self.lstChannels): data = ch.scaledData # print "*** plotting data channel %d **************"%chIndex # print "datatype: %s"%str(ch.dataType) diff --git a/src/dls_pmac_control/motor.py b/src/dls_pmac_control/motor.py index 0e68d98..f535435 100755 --- a/src/dls_pmac_control/motor.py +++ b/src/dls_pmac_control/motor.py @@ -261,7 +261,7 @@ def remoteConnect(self): server_name = self.lneServer.text() server_port = self.lnePort.text() self.pmac.setConnectionParams(server_name, server_port) - self.txtShell.append("Connecting to %s %s" % (server_name, server_port)) + self.txtShell.append(f"Connecting to {server_name} {server_port}") # Connect to the interface/PMAC # Show login window if ssh connection @@ -638,7 +638,7 @@ def updateMotors(self): over_temperature = False self.commsThread.resultQueue.qsize() - for queItem in range(0, self.commsThread.resultQueue.qsize()): + for _queItem in range(0, self.commsThread.resultQueue.qsize()): try: value = self.commsThread.resultQueue.get(False) except Empty: @@ -865,7 +865,7 @@ def updateIdentity(self, id): def updateWatches(self): self.commsThread.watchesQueue.qsize() - for queItem in range(0, self.commsThread.watchesQueue.qsize()): + for _queItem in range(0, self.commsThread.watchesQueue.qsize()): try: value = self.commsThread.watchesQueue.get(False) except Empty: diff --git a/src/dls_pmac_control/ppmacgather.py b/src/dls_pmac_control/ppmacgather.py index 1f30254..cab2504 100644 --- a/src/dls_pmac_control/ppmacgather.py +++ b/src/dls_pmac_control/ppmacgather.py @@ -99,7 +99,7 @@ def __init__(self, parent, currentMotor=1): def gatherConfig(self): # Clear the plot by setting empty plotitems - for chIndex, ch in enumerate(self.lstChannels): + for _chIndex, ch in enumerate(self.lstChannels): ch.qwtCurve.setData([], []) # Reset the data channels from class PpmacGatherChannel @@ -120,7 +120,7 @@ def gatherConfig(self): addr_str = ppmacDataSources[cmBox.currentIndex()]["addr"] gather_addr = "Gather.Addr[%d]" % items addr = "Motor[%d].%s" % (axisSpinBox.value(), addr_str) - cmd = "%s=%s" % (gather_addr, addr) + cmd = f"{gather_addr}={addr}" if chkBox.isChecked(): items += 1 diff --git a/src/dls_pmac_control/watches.py b/src/dls_pmac_control/watches.py index ad3a3c6..db470d9 100644 --- a/src/dls_pmac_control/watches.py +++ b/src/dls_pmac_control/watches.py @@ -150,9 +150,9 @@ def setVariableValue(self, newValue): # check type matches before sending command to set variable assert type(newValue) in (str, int, float) if self.varName[-2:] == "->": - self._sendPMACCommand("%s%s" % (self.varName, str(newValue))) + self._sendPMACCommand(f"{self.varName}{str(newValue)}") else: - self._sendPMACCommand("%s=%s" % (self.varName, str(newValue))) + self._sendPMACCommand(f"{self.varName}={str(newValue)}") def _sendPMACCommand(self, command): """Send a command to PMAC. From 48c8eaa63fa475e261177701c62102a794d89e77 Mon Sep 17 00:00:00 2001 From: Giles Knap Date: Sun, 11 Feb 2024 20:58:54 +0000 Subject: [PATCH 27/36] manual ruff fixes --- src/dls_pmac_control/gather.py | 8 ++------ src/dls_pmac_control/motor.py | 22 ++++++++++++++-------- src/dls_pmac_control/watches.py | 13 ++++++------- 3 files changed, 22 insertions(+), 21 deletions(-) diff --git a/src/dls_pmac_control/gather.py b/src/dls_pmac_control/gather.py index 41ca8ea..f1bcd20 100644 --- a/src/dls_pmac_control/gather.py +++ b/src/dls_pmac_control/gather.py @@ -187,7 +187,6 @@ def gatherConfig(self): return True def gatherSetup(self, numberOfSamples=1): - # Run through the bitmasks i5050 and i5051 to see which of the # 48 channels should be sampled. bitOffset = 1 @@ -223,10 +222,8 @@ def gatherSetup(self, numberOfSamples=1): # Run through all the channels to sample from self.oddNumberOfWords = False - for chIndex, ch in enumerate(self.lstChannels): - + for _, ch in enumerate(self.lstChannels): # Get the data info - # print "channel: %d"%chIndex ch.getDataInfo() # Figure out the data width and odd/even number of data words @@ -312,7 +309,6 @@ def parseData(self, lstDataStrings): ch.rawToScaled() def plotData(self): - # xAxisData = range(self.numberOfSamples) for _chIndex, ch in enumerate(self.lstChannels): data = ch.scaledData @@ -430,7 +426,7 @@ def saveClicked(self): QMessageBox.information( self, "Error", - "Could not open file for writing." + "Could not open file for writing.", # buttons=1, # p_str_1="OK", ) diff --git a/src/dls_pmac_control/motor.py b/src/dls_pmac_control/motor.py index f535435..67ffe1d 100755 --- a/src/dls_pmac_control/motor.py +++ b/src/dls_pmac_control/motor.py @@ -632,7 +632,6 @@ def addToTxtShell(self, command, retStr=None, chkShowAll=True): # Called when an event comes out of the polling thread # and the jog ribbon. def updateMotors(self): - under_voltage = False over_voltage = False over_temperature = False @@ -647,7 +646,7 @@ def updateMotors(self): try: motorRow = value[6] # check for special cases - if type(motorRow) == str: + if isinstance(motorRow, str): if isinstance(self.pmac, PPmacSshInterface): if motorRow == "G": self.PpmacGlobalStatusScreen.updateStatus( @@ -702,14 +701,13 @@ def updateMotors(self): over_current = False if motorRow < 8: - if isinstance(self.pmac, PPmacSshInterface): if int(value[4]) > 0: i2t_fault = True if int(value[5]) > 0: over_current = True elif isinstance(self.pmac, PmacEthernetInterface): - amp_status = ((int(value[4])&448)>>6) + amp_status = (int(value[4]) & 448) >> 6 if amp_status == 5: i2t_fault = True elif amp_status == 6: @@ -732,13 +730,21 @@ def updateMotors(self): if isinstance(self.pmac, PPmacSshInterface): loLim = bool(statusWord & 0x2000000000000000) # MinusLimit hiLim = bool(statusWord & 0x1000000000000000) # PlusLimit - loLimSoft = bool(statusWord & 0x0080000000000000) # SoftMinusLimit - hiLimSoft = bool(statusWord & 0x0040000000000000) # SoftPlusLimit + loLimSoft = bool( + statusWord & 0x0080000000000000 + ) # SoftMinusLimit + hiLimSoft = bool( + statusWord & 0x0040000000000000 + ) # SoftPlusLimit # define high and low limits for pmac else: - loLim = bool(statusWord & 0x400000000000) # negative end limit set - hiLim = bool(statusWord & 0x200000000000) # positive end limit set + loLim = bool( + statusWord & 0x400000000000 + ) # negative end limit set + hiLim = bool( + statusWord & 0x200000000000 + ) # positive end limit set loLimSoft = False hiLimSoft = False diff --git a/src/dls_pmac_control/watches.py b/src/dls_pmac_control/watches.py index db470d9..2eb8266 100644 --- a/src/dls_pmac_control/watches.py +++ b/src/dls_pmac_control/watches.py @@ -1,4 +1,3 @@ - import re from PyQt5.QtWidgets import QDialog, QMessageBox, QTableWidgetItem @@ -23,7 +22,7 @@ def __init__(self, parent): def addWatch(self): varName = str(self.lneVariableName.text()) try: - assert type(varName) is str + assert isinstance(varName, str) varName = varName.lower() if varName in unsafeCommands: raise ValueError("%s is an unsafe command" % varName) @@ -50,8 +49,8 @@ def getWatch(self, varName): varName = varName.lower() try: watch = self._watches[varName] - except KeyError: - raise ValueError('There is no watch for variable "%s"' % varName) + except KeyError as e: + raise ValueError(msg='There is no watch for variable "%s"' % varName) from e return watch def updateWatch(self, row): @@ -70,13 +69,13 @@ def removeWatch(self): row = self.table.currentRow() if row == -1: return None - assert type(row) is int + assert isinstance(row, int) varName = self.table.item(row, 0).text() try: del self._watches[varName] self.parent.commsThread.remove_watch(varName) - except KeyError: - raise ValueError('There is no watch for variable "%s"' % varName) + except KeyError as e: + raise ValueError(msg='There is no watch for variable "%s"' % varName) from e try: self.table.removeRow(row) # self.updateEditWatchPanel() From 49873796d9fb85e6fe67dad3f0ba308927bdd703 Mon Sep 17 00:00:00 2001 From: Giles Knap Date: Sun, 11 Feb 2024 21:01:52 +0000 Subject: [PATCH 28/36] ruff formatting --- src/dls_pmac_control/CSstatus.py | 8 +- src/dls_pmac_control/axissettings.py | 1 - src/dls_pmac_control/commsThread.py | 14 +- src/dls_pmac_control/energise.py | 2 - src/dls_pmac_control/gatherchannel.py | 1 - src/dls_pmac_control/status.py | 1 - src/dls_pmac_control/ui_formAxisSettings.py | 178 +++++++++---- src/dls_pmac_control/ui_formCSStatus.py | 7 +- src/dls_pmac_control/ui_formControl.py | 165 ++++++++---- src/dls_pmac_control/ui_formEnergise.py | 1 - src/dls_pmac_control/ui_formGather.py | 1 - src/dls_pmac_control/ui_formGlobalStatus.py | 1 - src/dls_pmac_control/ui_formLogin.py | 1 - .../ui_formPpmacAxisSettings.py | 242 +++++++++++++----- src/dls_pmac_control/ui_formPpmacCSStatus.py | 1 - src/dls_pmac_control/ui_formStatus.py | 1 - src/dls_pmac_control/ui_formWatches.py | 1 - 17 files changed, 437 insertions(+), 189 deletions(-) diff --git a/src/dls_pmac_control/CSstatus.py b/src/dls_pmac_control/CSstatus.py index 866b17d..8697f97 100755 --- a/src/dls_pmac_control/CSstatus.py +++ b/src/dls_pmac_control/CSstatus.py @@ -556,9 +556,7 @@ def __init__(self, parent): for bit in range(0, 24): i = 24 * (word - 1) + bit self.lstLeds.append(QLabel(self.ledGroup)) - self.lstLabels.append( - QLabel(f"Word{word + 1} Bit{bit}", self.ledGroup) - ) + self.lstLabels.append(QLabel(f"Word{word + 1} Bit{bit}", self.ledGroup)) ledGroupLayout.addWidget(self.lstLeds[i], bit, word * 2) ledGroupLayout.addWidget(self.lstLabels[i], bit, word * 2 + 1) self.lstLeds[i].setPixmap(self.greenLedOff) @@ -769,9 +767,7 @@ def __init__(self, parent): for bit in range(0, 16): i = 16 * (word - 1) + bit self.lstLeds.append(QLabel(self.ledGroup)) - self.lstLabels.append( - QLabel(f"Word{word + 1} Bit{bit}", self.ledGroup) - ) + self.lstLabels.append(QLabel(f"Word{word + 1} Bit{bit}", self.ledGroup)) ledGroupLayout.addWidget(self.lstLeds[i], bit, word * 2) ledGroupLayout.addWidget(self.lstLabels[i], bit, word * 2 + 1) self.lstLeds[i].setPixmap(self.greenLedOff) diff --git a/src/dls_pmac_control/axissettings.py b/src/dls_pmac_control/axissettings.py index a47b627..cd08cd2 100644 --- a/src/dls_pmac_control/axissettings.py +++ b/src/dls_pmac_control/axissettings.py @@ -1,4 +1,3 @@ - from PyQt5.QtWidgets import QDialog, QMessageBox from dls_pmac_control.ui_formAxisSettings import Ui_formAxisSettings diff --git a/src/dls_pmac_control/commsThread.py b/src/dls_pmac_control/commsThread.py index caa27fc..a5a02c9 100644 --- a/src/dls_pmac_control/commsThread.py +++ b/src/dls_pmac_control/commsThread.py @@ -148,7 +148,10 @@ def updateFunc(self): if isinstance(self.parent.pmac, PPmacSshInterface): # The %% is because % needs escaping - only one % is actually sent # There has to be a space before the first BrickLV string to avoid its B being interpreted as a 'begin' command - cmd = "i65?&%s?%% BrickLV.BusUnderVoltage BrickLV.BusOverVoltage BrickLV.OverTemp" % self.CSNum + cmd = ( + "i65?&%s?%% BrickLV.BusUnderVoltage BrickLV.BusOverVoltage BrickLV.OverTemp" + % self.CSNum + ) elif isinstance(self.parent.pmac, PmacEthernetInterface): # Add the 7 segment display status query cmd = "i65???&%s??%%" % self.CSNum @@ -159,7 +162,14 @@ def updateFunc(self): if motorNo < 9: if isinstance(self.parent.pmac, PPmacSshInterface): # PowerBrick channels are zero-indexed - cmd = cmd + "BrickLV.Chan[" + str(motorNo - 1) + "].I2tFaultStatus BrickLV.Chan[" + str(motorNo - 1) + "].OverCurrent" + cmd = ( + cmd + + "BrickLV.Chan[" + + str(motorNo - 1) + + "].I2tFaultStatus BrickLV.Chan[" + + str(motorNo - 1) + + "].OverCurrent" + ) else: # Add a dummy request to keep the request chunks # the same length (p99 always returns zero) diff --git a/src/dls_pmac_control/energise.py b/src/dls_pmac_control/energise.py index 5702437..b583397 100644 --- a/src/dls_pmac_control/energise.py +++ b/src/dls_pmac_control/energise.py @@ -1,4 +1,3 @@ - import re import sys @@ -81,7 +80,6 @@ def isScreenUpToDate(self): # set the corresponding checkboxes to reflect the read # back value. def sendCommand(self): - # Make sure that self.val7501 and self.val7503 truly reflect the # current values of M7501 and M7503 (on the PMAC) if not self.isScreenUpToDate(): diff --git a/src/dls_pmac_control/gatherchannel.py b/src/dls_pmac_control/gatherchannel.py index 6602877..06f5484 100644 --- a/src/dls_pmac_control/gatherchannel.py +++ b/src/dls_pmac_control/gatherchannel.py @@ -138,7 +138,6 @@ def setDataGatherPointer(self, ivar): # address to determine: datawidth, datatype, unit and scaling factor # result is returned in a dictionary def getDataInfo(self): - # read the gather I variable from the pmac (retStr, status) = self.pmac.sendCommand(self.pSrcIvar) if not status: diff --git a/src/dls_pmac_control/status.py b/src/dls_pmac_control/status.py index 641ff21..fbe2a6a 100644 --- a/src/dls_pmac_control/status.py +++ b/src/dls_pmac_control/status.py @@ -1,4 +1,3 @@ - import sys from PyQt5.Qt import QApplication diff --git a/src/dls_pmac_control/ui_formAxisSettings.py b/src/dls_pmac_control/ui_formAxisSettings.py index b2e2e52..793df5d 100644 --- a/src/dls_pmac_control/ui_formAxisSettings.py +++ b/src/dls_pmac_control/ui_formAxisSettings.py @@ -1,4 +1,3 @@ - # Form implementation generated from reading ui file 'dls_pmac_control/formAxisSettings.ui' # # Created by: PyQt5 UI code generator 5.12.2 @@ -12,7 +11,9 @@ class Ui_formAxisSettings: def setupUi(self, formAxisSettings): formAxisSettings.setObjectName("formAxisSettings") formAxisSettings.resize(508, 548) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(formAxisSettings.sizePolicy().hasHeightForWidth()) @@ -52,7 +53,9 @@ def setupUi(self, formAxisSettings): self.textLabel2_2 = QtWidgets.QLabel(self.groupBox1) self.textLabel2_2.setWordWrap(False) self.textLabel2_2.setObjectName("textLabel2_2") - self.formLayout_2.setWidget(1, QtWidgets.QFormLayout.LabelRole, self.textLabel2_2) + self.formLayout_2.setWidget( + 1, QtWidgets.QFormLayout.LabelRole, self.textLabel2_2 + ) self.lneIx12 = QtWidgets.QLineEdit(self.groupBox1) self.lneIx12.setMinimumSize(QtCore.QSize(60, 0)) self.lneIx12.setMaximumSize(QtCore.QSize(31222, 32767)) @@ -61,7 +64,9 @@ def setupUi(self, formAxisSettings): self.textLabel2_3 = QtWidgets.QLabel(self.groupBox1) self.textLabel2_3.setWordWrap(False) self.textLabel2_3.setObjectName("textLabel2_3") - self.formLayout_2.setWidget(2, QtWidgets.QFormLayout.LabelRole, self.textLabel2_3) + self.formLayout_2.setWidget( + 2, QtWidgets.QFormLayout.LabelRole, self.textLabel2_3 + ) self.lneIx13 = QtWidgets.QLineEdit(self.groupBox1) self.lneIx13.setMinimumSize(QtCore.QSize(60, 0)) self.lneIx13.setMaximumSize(QtCore.QSize(31222, 32767)) @@ -70,7 +75,9 @@ def setupUi(self, formAxisSettings): self.textLabel2_4 = QtWidgets.QLabel(self.groupBox1) self.textLabel2_4.setWordWrap(False) self.textLabel2_4.setObjectName("textLabel2_4") - self.formLayout_2.setWidget(3, QtWidgets.QFormLayout.LabelRole, self.textLabel2_4) + self.formLayout_2.setWidget( + 3, QtWidgets.QFormLayout.LabelRole, self.textLabel2_4 + ) self.lneIx14 = QtWidgets.QLineEdit(self.groupBox1) self.lneIx14.setMinimumSize(QtCore.QSize(60, 0)) self.lneIx14.setMaximumSize(QtCore.QSize(31222, 32767)) @@ -79,7 +86,9 @@ def setupUi(self, formAxisSettings): self.textLabel2_5 = QtWidgets.QLabel(self.groupBox1) self.textLabel2_5.setWordWrap(False) self.textLabel2_5.setObjectName("textLabel2_5") - self.formLayout_2.setWidget(4, QtWidgets.QFormLayout.LabelRole, self.textLabel2_5) + self.formLayout_2.setWidget( + 4, QtWidgets.QFormLayout.LabelRole, self.textLabel2_5 + ) self.lneIx15 = QtWidgets.QLineEdit(self.groupBox1) self.lneIx15.setMinimumSize(QtCore.QSize(60, 0)) self.lneIx15.setMaximumSize(QtCore.QSize(31222, 32767)) @@ -88,7 +97,9 @@ def setupUi(self, formAxisSettings): self.textLabel2_6 = QtWidgets.QLabel(self.groupBox1) self.textLabel2_6.setWordWrap(False) self.textLabel2_6.setObjectName("textLabel2_6") - self.formLayout_2.setWidget(5, QtWidgets.QFormLayout.LabelRole, self.textLabel2_6) + self.formLayout_2.setWidget( + 5, QtWidgets.QFormLayout.LabelRole, self.textLabel2_6 + ) self.lneIx16 = QtWidgets.QLineEdit(self.groupBox1) self.lneIx16.setMinimumSize(QtCore.QSize(60, 0)) self.lneIx16.setMaximumSize(QtCore.QSize(31222, 32767)) @@ -97,7 +108,9 @@ def setupUi(self, formAxisSettings): self.textLabel2_7 = QtWidgets.QLabel(self.groupBox1) self.textLabel2_7.setWordWrap(False) self.textLabel2_7.setObjectName("textLabel2_7") - self.formLayout_2.setWidget(6, QtWidgets.QFormLayout.LabelRole, self.textLabel2_7) + self.formLayout_2.setWidget( + 6, QtWidgets.QFormLayout.LabelRole, self.textLabel2_7 + ) self.lneIx17 = QtWidgets.QLineEdit(self.groupBox1) self.lneIx17.setMinimumSize(QtCore.QSize(60, 0)) self.lneIx17.setMaximumSize(QtCore.QSize(31222, 32767)) @@ -106,7 +119,9 @@ def setupUi(self, formAxisSettings): self.textLabel2_8 = QtWidgets.QLabel(self.groupBox1) self.textLabel2_8.setWordWrap(False) self.textLabel2_8.setObjectName("textLabel2_8") - self.formLayout_2.setWidget(7, QtWidgets.QFormLayout.LabelRole, self.textLabel2_8) + self.formLayout_2.setWidget( + 7, QtWidgets.QFormLayout.LabelRole, self.textLabel2_8 + ) self.lneIx19 = QtWidgets.QLineEdit(self.groupBox1) self.lneIx19.setMinimumSize(QtCore.QSize(60, 0)) self.lneIx19.setMaximumSize(QtCore.QSize(31222, 32767)) @@ -124,7 +139,9 @@ def setupUi(self, formAxisSettings): self.textLabel2_9.setObjectName("textLabel2_9") self.formLayout.setWidget(0, QtWidgets.QFormLayout.LabelRole, self.textLabel2_9) self.lneIx20 = QtWidgets.QLineEdit(self.groupBox2) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.lneIx20.sizePolicy().hasHeightForWidth()) @@ -136,7 +153,9 @@ def setupUi(self, formAxisSettings): self.textLabel2_2_2 = QtWidgets.QLabel(self.groupBox2) self.textLabel2_2_2.setWordWrap(False) self.textLabel2_2_2.setObjectName("textLabel2_2_2") - self.formLayout.setWidget(1, QtWidgets.QFormLayout.LabelRole, self.textLabel2_2_2) + self.formLayout.setWidget( + 1, QtWidgets.QFormLayout.LabelRole, self.textLabel2_2_2 + ) self.lneIx21 = QtWidgets.QLineEdit(self.groupBox2) self.lneIx21.setMinimumSize(QtCore.QSize(60, 0)) self.lneIx21.setMaximumSize(QtCore.QSize(32222, 32767)) @@ -145,7 +164,9 @@ def setupUi(self, formAxisSettings): self.textLabel2_3_2 = QtWidgets.QLabel(self.groupBox2) self.textLabel2_3_2.setWordWrap(False) self.textLabel2_3_2.setObjectName("textLabel2_3_2") - self.formLayout.setWidget(2, QtWidgets.QFormLayout.LabelRole, self.textLabel2_3_2) + self.formLayout.setWidget( + 2, QtWidgets.QFormLayout.LabelRole, self.textLabel2_3_2 + ) self.lneIx22 = QtWidgets.QLineEdit(self.groupBox2) self.lneIx22.setMinimumSize(QtCore.QSize(60, 0)) self.lneIx22.setMaximumSize(QtCore.QSize(32222, 32767)) @@ -154,7 +175,9 @@ def setupUi(self, formAxisSettings): self.textLabel2_4_2 = QtWidgets.QLabel(self.groupBox2) self.textLabel2_4_2.setWordWrap(False) self.textLabel2_4_2.setObjectName("textLabel2_4_2") - self.formLayout.setWidget(3, QtWidgets.QFormLayout.LabelRole, self.textLabel2_4_2) + self.formLayout.setWidget( + 3, QtWidgets.QFormLayout.LabelRole, self.textLabel2_4_2 + ) self.lneIx23 = QtWidgets.QLineEdit(self.groupBox2) self.lneIx23.setMinimumSize(QtCore.QSize(60, 0)) self.lneIx23.setMaximumSize(QtCore.QSize(32222, 32767)) @@ -163,7 +186,9 @@ def setupUi(self, formAxisSettings): self.textLabel2_5_2 = QtWidgets.QLabel(self.groupBox2) self.textLabel2_5_2.setWordWrap(False) self.textLabel2_5_2.setObjectName("textLabel2_5_2") - self.formLayout.setWidget(4, QtWidgets.QFormLayout.LabelRole, self.textLabel2_5_2) + self.formLayout.setWidget( + 4, QtWidgets.QFormLayout.LabelRole, self.textLabel2_5_2 + ) self.lneIx24 = QtWidgets.QLineEdit(self.groupBox2) self.lneIx24.setMinimumSize(QtCore.QSize(60, 0)) self.lneIx24.setMaximumSize(QtCore.QSize(32222, 32767)) @@ -172,7 +197,9 @@ def setupUi(self, formAxisSettings): self.textLabel2_6_2 = QtWidgets.QLabel(self.groupBox2) self.textLabel2_6_2.setWordWrap(False) self.textLabel2_6_2.setObjectName("textLabel2_6_2") - self.formLayout.setWidget(5, QtWidgets.QFormLayout.LabelRole, self.textLabel2_6_2) + self.formLayout.setWidget( + 5, QtWidgets.QFormLayout.LabelRole, self.textLabel2_6_2 + ) self.lneIx25 = QtWidgets.QLineEdit(self.groupBox2) self.lneIx25.setMinimumSize(QtCore.QSize(60, 0)) self.lneIx25.setMaximumSize(QtCore.QSize(32222, 32767)) @@ -181,7 +208,9 @@ def setupUi(self, formAxisSettings): self.textLabel2_7_2 = QtWidgets.QLabel(self.groupBox2) self.textLabel2_7_2.setWordWrap(False) self.textLabel2_7_2.setObjectName("textLabel2_7_2") - self.formLayout.setWidget(6, QtWidgets.QFormLayout.LabelRole, self.textLabel2_7_2) + self.formLayout.setWidget( + 6, QtWidgets.QFormLayout.LabelRole, self.textLabel2_7_2 + ) self.lneIx26 = QtWidgets.QLineEdit(self.groupBox2) self.lneIx26.setMinimumSize(QtCore.QSize(0, 0)) self.lneIx26.setMaximumSize(QtCore.QSize(32222, 32767)) @@ -196,7 +225,9 @@ def setupUi(self, formAxisSettings): self.gridLayout.setSpacing(6) self.gridLayout.setObjectName("gridLayout") self.groupBox1_2 = QtWidgets.QGroupBox(self.tab1) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.groupBox1_2.sizePolicy().hasHeightForWidth()) @@ -209,7 +240,9 @@ def setupUi(self, formAxisSettings): self.textLabel2_10 = QtWidgets.QLabel(self.groupBox1_2) self.textLabel2_10.setWordWrap(False) self.textLabel2_10.setObjectName("textLabel2_10") - self.formLayout_3.setWidget(0, QtWidgets.QFormLayout.LabelRole, self.textLabel2_10) + self.formLayout_3.setWidget( + 0, QtWidgets.QFormLayout.LabelRole, self.textLabel2_10 + ) self.lneIx30 = QtWidgets.QLineEdit(self.groupBox1_2) self.lneIx30.setMinimumSize(QtCore.QSize(60, 0)) self.lneIx30.setMaximumSize(QtCore.QSize(32233, 32767)) @@ -218,7 +251,9 @@ def setupUi(self, formAxisSettings): self.textLabel2_2_3 = QtWidgets.QLabel(self.groupBox1_2) self.textLabel2_2_3.setWordWrap(False) self.textLabel2_2_3.setObjectName("textLabel2_2_3") - self.formLayout_3.setWidget(1, QtWidgets.QFormLayout.LabelRole, self.textLabel2_2_3) + self.formLayout_3.setWidget( + 1, QtWidgets.QFormLayout.LabelRole, self.textLabel2_2_3 + ) self.lneIx31 = QtWidgets.QLineEdit(self.groupBox1_2) self.lneIx31.setMinimumSize(QtCore.QSize(60, 0)) self.lneIx31.setMaximumSize(QtCore.QSize(32233, 32767)) @@ -227,7 +262,9 @@ def setupUi(self, formAxisSettings): self.textLabel2_3_3 = QtWidgets.QLabel(self.groupBox1_2) self.textLabel2_3_3.setWordWrap(False) self.textLabel2_3_3.setObjectName("textLabel2_3_3") - self.formLayout_3.setWidget(2, QtWidgets.QFormLayout.LabelRole, self.textLabel2_3_3) + self.formLayout_3.setWidget( + 2, QtWidgets.QFormLayout.LabelRole, self.textLabel2_3_3 + ) self.lneIx32 = QtWidgets.QLineEdit(self.groupBox1_2) self.lneIx32.setMinimumSize(QtCore.QSize(60, 0)) self.lneIx32.setMaximumSize(QtCore.QSize(32233, 32767)) @@ -236,7 +273,9 @@ def setupUi(self, formAxisSettings): self.textLabel2_4_3 = QtWidgets.QLabel(self.groupBox1_2) self.textLabel2_4_3.setWordWrap(False) self.textLabel2_4_3.setObjectName("textLabel2_4_3") - self.formLayout_3.setWidget(3, QtWidgets.QFormLayout.LabelRole, self.textLabel2_4_3) + self.formLayout_3.setWidget( + 3, QtWidgets.QFormLayout.LabelRole, self.textLabel2_4_3 + ) self.lneIx33 = QtWidgets.QLineEdit(self.groupBox1_2) self.lneIx33.setMinimumSize(QtCore.QSize(60, 0)) self.lneIx33.setMaximumSize(QtCore.QSize(32233, 32767)) @@ -245,7 +284,9 @@ def setupUi(self, formAxisSettings): self.textLabel2_5_3 = QtWidgets.QLabel(self.groupBox1_2) self.textLabel2_5_3.setWordWrap(False) self.textLabel2_5_3.setObjectName("textLabel2_5_3") - self.formLayout_3.setWidget(4, QtWidgets.QFormLayout.LabelRole, self.textLabel2_5_3) + self.formLayout_3.setWidget( + 4, QtWidgets.QFormLayout.LabelRole, self.textLabel2_5_3 + ) self.lneIx34 = QtWidgets.QLineEdit(self.groupBox1_2) self.lneIx34.setMinimumSize(QtCore.QSize(60, 0)) self.lneIx34.setMaximumSize(QtCore.QSize(32233, 32767)) @@ -254,7 +295,9 @@ def setupUi(self, formAxisSettings): self.textLabel2_10_2 = QtWidgets.QLabel(self.groupBox1_2) self.textLabel2_10_2.setWordWrap(False) self.textLabel2_10_2.setObjectName("textLabel2_10_2") - self.formLayout_3.setWidget(5, QtWidgets.QFormLayout.LabelRole, self.textLabel2_10_2) + self.formLayout_3.setWidget( + 5, QtWidgets.QFormLayout.LabelRole, self.textLabel2_10_2 + ) self.lneIx35 = QtWidgets.QLineEdit(self.groupBox1_2) self.lneIx35.setMinimumSize(QtCore.QSize(60, 0)) self.lneIx35.setMaximumSize(QtCore.QSize(32233, 32767)) @@ -263,7 +306,9 @@ def setupUi(self, formAxisSettings): self.textLabel2_10_2_2 = QtWidgets.QLabel(self.groupBox1_2) self.textLabel2_10_2_2.setWordWrap(False) self.textLabel2_10_2_2.setObjectName("textLabel2_10_2_2") - self.formLayout_3.setWidget(6, QtWidgets.QFormLayout.LabelRole, self.textLabel2_10_2_2) + self.formLayout_3.setWidget( + 6, QtWidgets.QFormLayout.LabelRole, self.textLabel2_10_2_2 + ) self.lneIx65 = QtWidgets.QLineEdit(self.groupBox1_2) self.lneIx65.setMinimumSize(QtCore.QSize(60, 0)) self.lneIx65.setMaximumSize(QtCore.QSize(32233, 32767)) @@ -271,26 +316,36 @@ def setupUi(self, formAxisSettings): self.formLayout_3.setWidget(6, QtWidgets.QFormLayout.FieldRole, self.lneIx65) self.gridLayout.addWidget(self.groupBox1_2, 0, 0, 2, 1) self.groupBox1_2_2 = QtWidgets.QGroupBox(self.tab1) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.groupBox1_2_2.sizePolicy().hasHeightForWidth()) + sizePolicy.setHeightForWidth( + self.groupBox1_2_2.sizePolicy().hasHeightForWidth() + ) self.groupBox1_2_2.setSizePolicy(sizePolicy) self.groupBox1_2_2.setObjectName("groupBox1_2_2") self.formLayout_4 = QtWidgets.QFormLayout(self.groupBox1_2_2) - self.formLayout_4.setFieldGrowthPolicy(QtWidgets.QFormLayout.AllNonFixedFieldsGrow) + self.formLayout_4.setFieldGrowthPolicy( + QtWidgets.QFormLayout.AllNonFixedFieldsGrow + ) self.formLayout_4.setContentsMargins(11, 11, 11, 11) self.formLayout_4.setSpacing(6) self.formLayout_4.setObjectName("formLayout_4") self.lLoopSelect = QtWidgets.QLabel(self.groupBox1_2_2) self.lLoopSelect.setWordWrap(False) self.lLoopSelect.setObjectName("lLoopSelect") - self.formLayout_4.setWidget(0, QtWidgets.QFormLayout.LabelRole, self.lLoopSelect) + self.formLayout_4.setWidget( + 0, QtWidgets.QFormLayout.LabelRole, self.lLoopSelect + ) self.lneLoopSelect = QtWidgets.QLineEdit(self.groupBox1_2_2) self.lneLoopSelect.setMinimumSize(QtCore.QSize(60, 0)) self.lneLoopSelect.setMaximumSize(QtCore.QSize(32222, 32767)) self.lneLoopSelect.setObjectName("lneLoopSelect") - self.formLayout_4.setWidget(0, QtWidgets.QFormLayout.FieldRole, self.lneLoopSelect) + self.formLayout_4.setWidget( + 0, QtWidgets.QFormLayout.FieldRole, self.lneLoopSelect + ) self.lCaptureOn = QtWidgets.QLabel(self.groupBox1_2_2) self.lCaptureOn.setWordWrap(False) self.lCaptureOn.setObjectName("lCaptureOn") @@ -299,36 +354,52 @@ def setupUi(self, formAxisSettings): self.lneCaptureOn.setMinimumSize(QtCore.QSize(60, 0)) self.lneCaptureOn.setMaximumSize(QtCore.QSize(32222, 32767)) self.lneCaptureOn.setObjectName("lneCaptureOn") - self.formLayout_4.setWidget(1, QtWidgets.QFormLayout.FieldRole, self.lneCaptureOn) + self.formLayout_4.setWidget( + 1, QtWidgets.QFormLayout.FieldRole, self.lneCaptureOn + ) self.lCaptureFlag = QtWidgets.QLabel(self.groupBox1_2_2) self.lCaptureFlag.setWordWrap(False) self.lCaptureFlag.setObjectName("lCaptureFlag") - self.formLayout_4.setWidget(2, QtWidgets.QFormLayout.LabelRole, self.lCaptureFlag) + self.formLayout_4.setWidget( + 2, QtWidgets.QFormLayout.LabelRole, self.lCaptureFlag + ) self.lneCaptureFlag = QtWidgets.QLineEdit(self.groupBox1_2_2) self.lneCaptureFlag.setMinimumSize(QtCore.QSize(60, 0)) self.lneCaptureFlag.setMaximumSize(QtCore.QSize(32222, 32767)) self.lneCaptureFlag.setObjectName("lneCaptureFlag") - self.formLayout_4.setWidget(2, QtWidgets.QFormLayout.FieldRole, self.lneCaptureFlag) + self.formLayout_4.setWidget( + 2, QtWidgets.QFormLayout.FieldRole, self.lneCaptureFlag + ) self.lOutputMode = QtWidgets.QLabel(self.groupBox1_2_2) self.lOutputMode.setWordWrap(False) self.lOutputMode.setObjectName("lOutputMode") - self.formLayout_4.setWidget(3, QtWidgets.QFormLayout.LabelRole, self.lOutputMode) + self.formLayout_4.setWidget( + 3, QtWidgets.QFormLayout.LabelRole, self.lOutputMode + ) self.lneOutputMode = QtWidgets.QLineEdit(self.groupBox1_2_2) self.lneOutputMode.setMinimumSize(QtCore.QSize(60, 0)) self.lneOutputMode.setMaximumSize(QtCore.QSize(32222, 32767)) self.lneOutputMode.setObjectName("lneOutputMode") - self.formLayout_4.setWidget(3, QtWidgets.QFormLayout.FieldRole, self.lneOutputMode) + self.formLayout_4.setWidget( + 3, QtWidgets.QFormLayout.FieldRole, self.lneOutputMode + ) self.gridLayout.addWidget(self.groupBox1_2_2, 0, 1, 1, 1) - spacerItem = QtWidgets.QSpacerItem(20, 125, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) + spacerItem = QtWidgets.QSpacerItem( + 20, 125, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding + ) self.gridLayout.addItem(spacerItem, 1, 1, 2, 1) - spacerItem1 = QtWidgets.QSpacerItem(20, 26, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) + spacerItem1 = QtWidgets.QSpacerItem( + 20, 26, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding + ) self.gridLayout.addItem(spacerItem1, 2, 0, 1, 1) self.tabAxisSetup.addTab(self.tab1, "") self.gridLayout_3.addWidget(self.tabAxisSetup, 1, 0, 1, 3) self.btnUpdate = QtWidgets.QPushButton(formAxisSettings) self.btnUpdate.setObjectName("btnUpdate") self.gridLayout_3.addWidget(self.btnUpdate, 2, 0, 1, 1) - spacerItem2 = QtWidgets.QSpacerItem(185, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + spacerItem2 = QtWidgets.QSpacerItem( + 185, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum + ) self.gridLayout_3.addItem(spacerItem2, 2, 1, 1, 1) self.btnClose = QtWidgets.QPushButton(formAxisSettings) self.btnClose.setObjectName("btnClose") @@ -364,7 +435,7 @@ def setupUi(self, formAxisSettings): self.lneCaptureOn.returnPressed.connect(formAxisSettings.sendCaptureOn) self.lneCaptureFlag.returnPressed.connect(formAxisSettings.sendCaptureFlag) self.lneOutputMode.returnPressed.connect(formAxisSettings.sendOutputMode) - self.tabAxisSetup.currentChanged['int'].connect(formAxisSettings.tabChange) + self.tabAxisSetup.currentChanged["int"].connect(formAxisSettings.tabChange) QtCore.QMetaObject.connectSlotsByName(formAxisSettings) formAxisSettings.setTabOrder(self.lneIx11, self.lneIx12) formAxisSettings.setTabOrder(self.lneIx12, self.lneIx13) @@ -386,10 +457,17 @@ def setupUi(self, formAxisSettings): def retranslateUi(self, formAxisSettings): _translate = QtCore.QCoreApplication.translate formAxisSettings.setWindowTitle(_translate("formAxisSettings", "Axis setup")) - self.textLabel1.setText(_translate("formAxisSettings", "Note this screen does not update continuously.\n" -"Hit the update button to read out the current values from pmac.\n" -"Write demand values in the text fields and hit enter to send.")) - self.groupBox1.setTitle(_translate("formAxisSettings", "Definition I variables")) + self.textLabel1.setText( + _translate( + "formAxisSettings", + "Note this screen does not update continuously.\n" + "Hit the update button to read out the current values from pmac.\n" + "Write demand values in the text fields and hit enter to send.", + ) + ) + self.groupBox1.setTitle( + _translate("formAxisSettings", "Definition I variables") + ) self.textLabel2.setText(_translate("formAxisSettings", "Ix11:")) self.textLabel2_2.setText(_translate("formAxisSettings", "Ix12:")) self.textLabel2_3.setText(_translate("formAxisSettings", "Ix13:")) @@ -406,8 +484,13 @@ def retranslateUi(self, formAxisSettings): self.textLabel2_5_2.setText(_translate("formAxisSettings", "Ix24")) self.textLabel2_6_2.setText(_translate("formAxisSettings", "Ix25")) self.textLabel2_7_2.setText(_translate("formAxisSettings", "Ix26")) - self.tabAxisSetup.setTabText(self.tabAxisSetup.indexOf(self.tab), _translate("formAxisSettings", "definition and safety")) - self.groupBox1_2.setTitle(_translate("formAxisSettings", "PID tuning variables")) + self.tabAxisSetup.setTabText( + self.tabAxisSetup.indexOf(self.tab), + _translate("formAxisSettings", "definition and safety"), + ) + self.groupBox1_2.setTitle( + _translate("formAxisSettings", "PID tuning variables") + ) self.textLabel2_10.setText(_translate("formAxisSettings", "ix30:")) self.textLabel2_2_3.setText(_translate("formAxisSettings", "Ix31:")) self.textLabel2_3_3.setText(_translate("formAxisSettings", "Ix32:")) @@ -420,8 +503,9 @@ def retranslateUi(self, formAxisSettings): self.lCaptureOn.setText(_translate("formAxisSettings", "capture on:")) self.lCaptureFlag.setText(_translate("formAxisSettings", "capture flag:")) self.lOutputMode.setText(_translate("formAxisSettings", "output mode:")) - self.tabAxisSetup.setTabText(self.tabAxisSetup.indexOf(self.tab1), _translate("formAxisSettings", "PID and macro")) + self.tabAxisSetup.setTabText( + self.tabAxisSetup.indexOf(self.tab1), + _translate("formAxisSettings", "PID and macro"), + ) self.btnUpdate.setText(_translate("formAxisSettings", "update")) self.btnClose.setText(_translate("formAxisSettings", "close")) - - diff --git a/src/dls_pmac_control/ui_formCSStatus.py b/src/dls_pmac_control/ui_formCSStatus.py index 7660a75..dab5e90 100644 --- a/src/dls_pmac_control/ui_formCSStatus.py +++ b/src/dls_pmac_control/ui_formCSStatus.py @@ -1,4 +1,3 @@ - # Form implementation generated from reading ui file 'src/dls_pmac_control/formCSStatus.ui' # # Created by: PyQt5 UI code generator 5.12.2 @@ -43,7 +42,9 @@ def setupUi(self, formCSStatus): self.gridLayout.addWidget(self.csSpin, 0, 1, 1, 1) self.gridLayout_2.addWidget(self.ctrlGroup, 0, 0, 1, 1) self.ledGroup = QtWidgets.QGroupBox(formCSStatus) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Expanding) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Expanding + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.ledGroup.sizePolicy().hasHeightForWidth()) @@ -65,5 +66,3 @@ def retranslateUi(self, formCSStatus): self.textLabel1.setText(_translate("formCSStatus", "CS Number:")) self.textLabel1_2.setText(_translate("formCSStatus", "Feed Rate:")) self.ledGroup.setTitle(_translate("formCSStatus", "CS Status")) - - diff --git a/src/dls_pmac_control/ui_formControl.py b/src/dls_pmac_control/ui_formControl.py index 9bbb46a..c967575 100644 --- a/src/dls_pmac_control/ui_formControl.py +++ b/src/dls_pmac_control/ui_formControl.py @@ -1,4 +1,3 @@ - # Form implementation generated from reading ui file 'dls_pmac_control/formControl.ui' # # Created by: PyQt5 UI code generator 5.12.2 @@ -21,7 +20,9 @@ def setupUi(self, ControlForm): self.gridLayout_2.setSpacing(6) self.gridLayout_2.setObjectName("gridLayout_2") self.grpJog = QtWidgets.QGroupBox(self.widget) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.grpJog.sizePolicy().hasHeightForWidth()) @@ -35,7 +36,9 @@ def setupUi(self, ControlForm): self.horizontalLayout.setSpacing(6) self.horizontalLayout.setObjectName("horizontalLayout") self.spnJogMotor = QtWidgets.QSpinBox(self.grpJog) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.spnJogMotor.sizePolicy().hasHeightForWidth()) @@ -91,7 +94,9 @@ def setupUi(self, ControlForm): self.lblPosition.setMinimumSize(QtCore.QSize(0, 28)) self.lblPosition.setFrameShape(QtWidgets.QFrame.Box) self.lblPosition.setFrameShadow(QtWidgets.QFrame.Sunken) - self.lblPosition.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter) + self.lblPosition.setAlignment( + QtCore.Qt.AlignRight | QtCore.Qt.AlignTrailing | QtCore.Qt.AlignVCenter + ) self.lblPosition.setWordWrap(False) self.lblPosition.setObjectName("lblPosition") self.gridLayout.addWidget(self.lblPosition, 3, 1, 1, 1) @@ -121,7 +126,9 @@ def setupUi(self, ControlForm): self.lblVelo.setMinimumSize(QtCore.QSize(0, 28)) self.lblVelo.setFrameShape(QtWidgets.QFrame.Box) self.lblVelo.setFrameShadow(QtWidgets.QFrame.Sunken) - self.lblVelo.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter) + self.lblVelo.setAlignment( + QtCore.Qt.AlignRight | QtCore.Qt.AlignTrailing | QtCore.Qt.AlignVCenter + ) self.lblVelo.setWordWrap(False) self.lblVelo.setObjectName("lblVelo") self.gridLayout.addWidget(self.lblVelo, 4, 1, 1, 1) @@ -151,7 +158,9 @@ def setupUi(self, ControlForm): self.lblFolErr.setMinimumSize(QtCore.QSize(0, 28)) self.lblFolErr.setFrameShape(QtWidgets.QFrame.Box) self.lblFolErr.setFrameShadow(QtWidgets.QFrame.Sunken) - self.lblFolErr.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter) + self.lblFolErr.setAlignment( + QtCore.Qt.AlignRight | QtCore.Qt.AlignTrailing | QtCore.Qt.AlignVCenter + ) self.lblFolErr.setWordWrap(False) self.lblFolErr.setObjectName("lblFolErr") self.gridLayout.addWidget(self.lblFolErr, 5, 1, 1, 1) @@ -184,7 +193,9 @@ def setupUi(self, ControlForm): self.gridLayout.addWidget(self.btnJogStop, 5, 3, 1, 1) self.lneJogDist = QtWidgets.QLineEdit(self.grpJog) self.lneJogDist.setEnabled(False) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.Fixed) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.Fixed + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.lneJogDist.sizePolicy().hasHeightForWidth()) @@ -208,7 +219,9 @@ def setupUi(self, ControlForm): self.gridLayout.addWidget(self.textLabel3, 2, 0, 1, 1) self.lneJogTo = QtWidgets.QLineEdit(self.grpJog) self.lneJogTo.setEnabled(False) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.Fixed) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.Fixed + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.lneJogTo.sizePolicy().hasHeightForWidth()) @@ -234,12 +247,16 @@ def setupUi(self, ControlForm): self.gridLayout.addWidget(self.btnKillMotor, 6, 3, 1, 1) self.gridLayout_2.addWidget(self.grpJog, 0, 1, 1, 1) self.groupBox1 = QtWidgets.QGroupBox(self.widget) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Fixed) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Fixed + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.groupBox1.sizePolicy().hasHeightForWidth()) self.groupBox1.setSizePolicy(sizePolicy) - self.groupBox1.setAlignment(QtCore.Qt.AlignLeading|QtCore.Qt.AlignLeft|QtCore.Qt.AlignTop) + self.groupBox1.setAlignment( + QtCore.Qt.AlignLeading | QtCore.Qt.AlignLeft | QtCore.Qt.AlignTop + ) self.groupBox1.setObjectName("groupBox1") self.verticalLayout = QtWidgets.QVBoxLayout(self.groupBox1) self.verticalLayout.setContentsMargins(11, 11, 11, 11) @@ -253,17 +270,23 @@ def setupUi(self, ControlForm): self.gridLayout_3.setSpacing(6) self.gridLayout_3.setObjectName("gridLayout_3") self.rbUseTerminalServer = QtWidgets.QRadioButton(self.btnGroupProtocol) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.rbUseTerminalServer.sizePolicy().hasHeightForWidth()) + sizePolicy.setHeightForWidth( + self.rbUseTerminalServer.sizePolicy().hasHeightForWidth() + ) self.rbUseTerminalServer.setSizePolicy(sizePolicy) self.rbUseTerminalServer.setChecked(False) self.rbUseTerminalServer.setObjectName("rbUseTerminalServer") self.gridLayout_3.addWidget(self.rbUseTerminalServer, 0, 0, 1, 1) self.rbUseSocket = QtWidgets.QRadioButton(self.btnGroupProtocol) self.rbUseSocket.setEnabled(True) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.rbUseSocket.sizePolicy().hasHeightForWidth()) @@ -271,7 +294,9 @@ def setupUi(self, ControlForm): self.rbUseSocket.setObjectName("rbUseSocket") self.gridLayout_3.addWidget(self.rbUseSocket, 1, 0, 1, 1) self.rbUseSerial = QtWidgets.QRadioButton(self.btnGroupProtocol) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Expanding) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Expanding + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.rbUseSerial.sizePolicy().hasHeightForWidth()) @@ -281,7 +306,9 @@ def setupUi(self, ControlForm): self.gridLayout_3.addWidget(self.rbUseSerial, 2, 0, 1, 1) self.rbUseSsh = QtWidgets.QRadioButton(self.btnGroupProtocol) self.rbUseSsh.setEnabled(True) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Expanding) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Expanding + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.rbUseSsh.sizePolicy().hasHeightForWidth()) @@ -339,7 +366,9 @@ def setupUi(self, ControlForm): self.hboxlayout1.addWidget(self.chkShowAll) self.gridLayout_2.addLayout(self.hboxlayout1, 7, 0, 1, 2) self.frame3 = QtWidgets.QFrame(self.widget) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.frame3.sizePolicy().hasHeightForWidth()) @@ -385,7 +414,9 @@ def setupUi(self, ControlForm): self.gridLayout_4.addWidget(self.btnGlobalStatus, 2, 6, 1, 1) self.btnKillAll = QtWidgets.QPushButton(self.frame3) self.btnKillAll.setEnabled(False) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Minimum) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Minimum + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.btnKillAll.sizePolicy().hasHeightForWidth()) @@ -422,7 +453,9 @@ def setupUi(self, ControlForm): self.gridLayout_4.addWidget(self.btnWatches, 2, 4, 1, 1) self.gridLayout_2.addWidget(self.frame3, 5, 0, 1, 2) self.splitter = QtWidgets.QSplitter(self.widget) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Expanding) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Expanding + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.splitter.sizePolicy().hasHeightForWidth()) @@ -430,7 +463,9 @@ def setupUi(self, ControlForm): self.splitter.setOrientation(QtCore.Qt.Vertical) self.splitter.setObjectName("splitter") self.table = QtWidgets.QTableWidget(self.splitter) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding + ) sizePolicy.setHorizontalStretch(1) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.table.sizePolicy().hasHeightForWidth()) @@ -470,7 +505,9 @@ def setupUi(self, ControlForm): self.table.verticalHeader().setDefaultSectionSize(20) self.txtShell = QtWidgets.QTextEdit(self.splitter) self.txtShell.setEnabled(True) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding + ) sizePolicy.setHorizontalStretch(1) sizePolicy.setVerticalStretch(1) sizePolicy.setHeightForWidth(self.txtShell.sizePolicy().hasHeightForWidth()) @@ -487,7 +524,9 @@ def setupUi(self, ControlForm): self.horizontalLayout_6.setSpacing(6) self.horizontalLayout_6.setObjectName("horizontalLayout_6") self.lblIdentity = QtWidgets.QLabel(self.widget) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.Preferred) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.Preferred + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.lblIdentity.sizePolicy().hasHeightForWidth()) @@ -529,7 +568,7 @@ def setupUi(self, ControlForm): ControlForm.setCentralWidget(self.widget) self.retranslateUi(ControlForm) - self.spnJogMotor.valueChanged['int'].connect(ControlForm.jogChangeMotor) + self.spnJogMotor.valueChanged["int"].connect(ControlForm.jogChangeMotor) self.btnJogPos.clicked.connect(ControlForm.jogPos) self.btnSend.clicked.connect(ControlForm.sendSingleCommand) self.lneSend.returnPressed.connect(ControlForm.sendSingleCommand) @@ -537,20 +576,24 @@ def setupUi(self, ControlForm): self.lneServer.returnPressed.connect(self.lnePort.selectAll) self.lneServer.returnPressed.connect(self.lnePort.setFocus) self.lnePort.returnPressed.connect(self.rbUseTerminalServer.setFocus) - self.rbUseTerminalServer.clicked.connect(ControlForm.useTerminalServerConnection) + self.rbUseTerminalServer.clicked.connect( + ControlForm.useTerminalServerConnection + ) self.rbUseSocket.clicked.connect(ControlForm.useSocketConnection) self.rbUseSsh.clicked.connect(ControlForm.useSshConnection) self.btnDisconnect.clicked.connect(ControlForm.remoteDisconnect) self.btnConnect.clicked.connect(ControlForm.remoteConnect) self.lnePort.returnPressed.connect(ControlForm.remoteConnect) self.btnKillMotor.clicked.connect(ControlForm.killMotor) - self.chkJogInc.toggled['bool'].connect(ControlForm.jogIncrementally) + self.chkJogInc.toggled["bool"].connect(ControlForm.jogIncrementally) self.btnJogStop.clicked.connect(ControlForm.jogStop) self.btnJogTo.clicked.connect(ControlForm.jogGoToPosition) self.btnSettings.clicked.connect(ControlForm.jogParameters) self.btnStatus.clicked.connect(ControlForm.statusScreen) self.btnJogNeg.clicked.connect(ControlForm.jogNeg) - self.table.cellDoubleClicked['int','int'].connect(ControlForm.chooseMotorFromTable) + self.table.cellDoubleClicked["int", "int"].connect( + ControlForm.chooseMotorFromTable + ) self.btnGather.clicked.connect(ControlForm.dataGather) self.btnWatches.clicked.connect(ControlForm.watches) self.btnPollingStatus.clicked.connect(ControlForm.pmacPollingStatus) @@ -592,9 +635,13 @@ def setupUi(self, ControlForm): def retranslateUi(self, ControlForm): _translate = QtCore.QCoreApplication.translate - ControlForm.setWindowTitle(_translate("ControlForm", "Delta Tau motor controller")) + ControlForm.setWindowTitle( + _translate("ControlForm", "Delta Tau motor controller") + ) self.grpJog.setTitle(_translate("ControlForm", "Jog ribbon")) - self.spnJogMotor.setToolTip(_translate("ControlForm", "Choose the motor to jog")) + self.spnJogMotor.setToolTip( + _translate("ControlForm", "Choose the motor to jog") + ) self.btnJogNeg.setText(_translate("ControlForm", "jog neg")) self.btnHome.setText(_translate("ControlForm", "home")) self.btnJogPos.setText(_translate("ControlForm", "jog pos")) @@ -639,7 +686,12 @@ def retranslateUi(self, ControlForm): self.lblPolling.setText(_translate("ControlForm", "Polling")) self.lblPollRate.setText(_translate("ControlForm", "Hz")) self.btnGlobalStatus.setText(_translate("ControlForm", "Global Status...")) - self.btnKillAll.setToolTip(_translate("ControlForm", "Kill All (CTRL-K) motion by opening servo loops and setting zero velocity")) + self.btnKillAll.setToolTip( + _translate( + "ControlForm", + "Kill All (CTRL-K) motion by opening servo loops and setting zero velocity", + ) + ) self.btnKillAll.setText(_translate("ControlForm", "KILL ALL!")) self.btnLoadFile.setText(_translate("ControlForm", "load pmc...")) self.btnPollingStatus.setText(_translate("ControlForm", "disable polling")) @@ -659,34 +711,37 @@ def retranslateUi(self, ControlForm): item.setText(_translate("ControlForm", "i2t fault")) item = self.table.horizontalHeaderItem(6) item.setText(_translate("ControlForm", "over current")) - self.txtShell.setHtml(_translate("ControlForm", "\n" -"\n" -"\n" -"\n" -"
\n" -"


\n" -"


\n" -"


\n" -"


\n" -"


\n" -"


\n" -"


\n" -"


\n" -"


\n" -"


\n" -"


\n" -"


\n" -"


\n" -"


\n" -"


\n" -"


\n" -"


\n" -"


")) + self.txtShell.setHtml( + _translate( + "ControlForm", + '\n' + '\n" + '\n' + "\n" + '
\n' + '


\n' + '


\n' + '


\n' + '


\n' + '


\n' + '


\n' + '


\n' + '


\n' + '


\n' + '


\n' + '


\n' + '


\n' + '


\n' + '


\n' + '


\n' + '


\n' + '


\n' + '


', + ) + ) self.lblIdentity.setText(_translate("ControlForm", "Test")) self.lblUnderVoltage.setText(_translate("ControlForm", "Under Voltage")) self.lblOverVoltage.setText(_translate("ControlForm", "Over Voltage")) self.lblOverTemperature.setText(_translate("ControlForm", "Over Temperature")) - - diff --git a/src/dls_pmac_control/ui_formEnergise.py b/src/dls_pmac_control/ui_formEnergise.py index 1e193d5..208ae86 100644 --- a/src/dls_pmac_control/ui_formEnergise.py +++ b/src/dls_pmac_control/ui_formEnergise.py @@ -1,4 +1,3 @@ - # Form implementation generated from reading ui file 'dls_pmac_control/formEnergise.ui' # # Created by: PyQt5 UI code generator 5.15.4 diff --git a/src/dls_pmac_control/ui_formGather.py b/src/dls_pmac_control/ui_formGather.py index 00e3369..b9df94f 100644 --- a/src/dls_pmac_control/ui_formGather.py +++ b/src/dls_pmac_control/ui_formGather.py @@ -1,4 +1,3 @@ - # Form implementation generated from reading ui file 'dls_pmac_control/formGather.ui' # # Created by: PyQt5 UI code generator 5.15.4 diff --git a/src/dls_pmac_control/ui_formGlobalStatus.py b/src/dls_pmac_control/ui_formGlobalStatus.py index b905333..f6f9c1c 100644 --- a/src/dls_pmac_control/ui_formGlobalStatus.py +++ b/src/dls_pmac_control/ui_formGlobalStatus.py @@ -1,4 +1,3 @@ - # Form implementation generated from reading ui file 'dls_pmac_control/formGlobalStatus.ui' # # Created by: PyQt5 UI code generator 5.15.4 diff --git a/src/dls_pmac_control/ui_formLogin.py b/src/dls_pmac_control/ui_formLogin.py index e46cfcc..f1608c4 100644 --- a/src/dls_pmac_control/ui_formLogin.py +++ b/src/dls_pmac_control/ui_formLogin.py @@ -1,4 +1,3 @@ - # Form implementation generated from reading ui file 'dls_pmac_control/formLogin.ui' # # Created by: PyQt5 UI code generator 5.15.4 diff --git a/src/dls_pmac_control/ui_formPpmacAxisSettings.py b/src/dls_pmac_control/ui_formPpmacAxisSettings.py index 04adb90..9f32cde 100644 --- a/src/dls_pmac_control/ui_formPpmacAxisSettings.py +++ b/src/dls_pmac_control/ui_formPpmacAxisSettings.py @@ -1,4 +1,3 @@ - # Form implementation generated from reading ui file 'dls_pmac_control/formPpmacAxisSettings.ui' # # Created by: PyQt5 UI code generator 5.12.2 @@ -12,10 +11,14 @@ class Ui_formPpmacAxisSettings: def setupUi(self, formPpmacAxisSettings): formPpmacAxisSettings.setObjectName("formPpmacAxisSettings") formPpmacAxisSettings.resize(580, 688) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(formPpmacAxisSettings.sizePolicy().hasHeightForWidth()) + sizePolicy.setHeightForWidth( + formPpmacAxisSettings.sizePolicy().hasHeightForWidth() + ) formPpmacAxisSettings.setSizePolicy(sizePolicy) formPpmacAxisSettings.setMaximumSize(QtCore.QSize(1024, 768)) self.gridLayout_3 = QtWidgets.QGridLayout(formPpmacAxisSettings) @@ -29,7 +32,9 @@ def setupUi(self, formPpmacAxisSettings): self.textLabel1.setWordWrap(False) self.textLabel1.setObjectName("textLabel1") self.gridLayout_3.addWidget(self.textLabel1, 0, 0, 1, 3) - spacerItem = QtWidgets.QSpacerItem(185, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + spacerItem = QtWidgets.QSpacerItem( + 185, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum + ) self.gridLayout_3.addItem(spacerItem, 2, 1, 1, 1) self.btnClose = QtWidgets.QPushButton(formPpmacAxisSettings) self.btnClose.setObjectName("btnClose") @@ -56,25 +61,37 @@ def setupUi(self, formPpmacAxisSettings): self.textLabel2_2_2 = QtWidgets.QLabel(self.groupBox2) self.textLabel2_2_2.setWordWrap(False) self.textLabel2_2_2.setObjectName("textLabel2_2_2") - self.formLayout.setWidget(2, QtWidgets.QFormLayout.LabelRole, self.textLabel2_2_2) + self.formLayout.setWidget( + 2, QtWidgets.QFormLayout.LabelRole, self.textLabel2_2_2 + ) self.textLabel2_3_2 = QtWidgets.QLabel(self.groupBox2) self.textLabel2_3_2.setWordWrap(False) self.textLabel2_3_2.setObjectName("textLabel2_3_2") - self.formLayout.setWidget(4, QtWidgets.QFormLayout.LabelRole, self.textLabel2_3_2) + self.formLayout.setWidget( + 4, QtWidgets.QFormLayout.LabelRole, self.textLabel2_3_2 + ) self.textLabel2_4_2 = QtWidgets.QLabel(self.groupBox2) self.textLabel2_4_2.setWordWrap(False) self.textLabel2_4_2.setObjectName("textLabel2_4_2") - self.formLayout.setWidget(6, QtWidgets.QFormLayout.LabelRole, self.textLabel2_4_2) + self.formLayout.setWidget( + 6, QtWidgets.QFormLayout.LabelRole, self.textLabel2_4_2 + ) self.textLabel2_6_2 = QtWidgets.QLabel(self.groupBox2) self.textLabel2_6_2.setWordWrap(False) self.textLabel2_6_2.setObjectName("textLabel2_6_2") - self.formLayout.setWidget(8, QtWidgets.QFormLayout.LabelRole, self.textLabel2_6_2) + self.formLayout.setWidget( + 8, QtWidgets.QFormLayout.LabelRole, self.textLabel2_6_2 + ) self.textLabel2_7_2 = QtWidgets.QLabel(self.groupBox2) self.textLabel2_7_2.setWordWrap(False) self.textLabel2_7_2.setObjectName("textLabel2_7_2") - self.formLayout.setWidget(10, QtWidgets.QFormLayout.LabelRole, self.textLabel2_7_2) + self.formLayout.setWidget( + 10, QtWidgets.QFormLayout.LabelRole, self.textLabel2_7_2 + ) self.lneIx20 = QtWidgets.QLineEdit(self.groupBox2) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.lneIx20.sizePolicy().hasHeightForWidth()) @@ -142,15 +159,21 @@ def setupUi(self, formPpmacAxisSettings): self.textLabel2_2 = QtWidgets.QLabel(self.groupBox1) self.textLabel2_2.setWordWrap(False) self.textLabel2_2.setObjectName("textLabel2_2") - self.formLayout_2.setWidget(2, QtWidgets.QFormLayout.LabelRole, self.textLabel2_2) + self.formLayout_2.setWidget( + 2, QtWidgets.QFormLayout.LabelRole, self.textLabel2_2 + ) self.textLabel2_3 = QtWidgets.QLabel(self.groupBox1) self.textLabel2_3.setWordWrap(False) self.textLabel2_3.setObjectName("textLabel2_3") - self.formLayout_2.setWidget(4, QtWidgets.QFormLayout.LabelRole, self.textLabel2_3) + self.formLayout_2.setWidget( + 4, QtWidgets.QFormLayout.LabelRole, self.textLabel2_3 + ) self.textLabel2_4 = QtWidgets.QLabel(self.groupBox1) self.textLabel2_4.setWordWrap(False) self.textLabel2_4.setObjectName("textLabel2_4") - self.formLayout_2.setWidget(5, QtWidgets.QFormLayout.LabelRole, self.textLabel2_4) + self.formLayout_2.setWidget( + 5, QtWidgets.QFormLayout.LabelRole, self.textLabel2_4 + ) self.lneIx14 = QtWidgets.QLineEdit(self.groupBox1) self.lneIx14.setMinimumSize(QtCore.QSize(60, 0)) self.lneIx14.setMaximumSize(QtCore.QSize(31222, 32767)) @@ -159,11 +182,15 @@ def setupUi(self, formPpmacAxisSettings): self.textLabel2_5 = QtWidgets.QLabel(self.groupBox1) self.textLabel2_5.setWordWrap(False) self.textLabel2_5.setObjectName("textLabel2_5") - self.formLayout_2.setWidget(7, QtWidgets.QFormLayout.LabelRole, self.textLabel2_5) + self.formLayout_2.setWidget( + 7, QtWidgets.QFormLayout.LabelRole, self.textLabel2_5 + ) self.textLabel2_6 = QtWidgets.QLabel(self.groupBox1) self.textLabel2_6.setWordWrap(False) self.textLabel2_6.setObjectName("textLabel2_6") - self.formLayout_2.setWidget(8, QtWidgets.QFormLayout.LabelRole, self.textLabel2_6) + self.formLayout_2.setWidget( + 8, QtWidgets.QFormLayout.LabelRole, self.textLabel2_6 + ) self.lneIx16 = QtWidgets.QLineEdit(self.groupBox1) self.lneIx16.setMinimumSize(QtCore.QSize(60, 0)) self.lneIx16.setMaximumSize(QtCore.QSize(31222, 32767)) @@ -172,7 +199,9 @@ def setupUi(self, formPpmacAxisSettings): self.textLabel2_7 = QtWidgets.QLabel(self.groupBox1) self.textLabel2_7.setWordWrap(False) self.textLabel2_7.setObjectName("textLabel2_7") - self.formLayout_2.setWidget(9, QtWidgets.QFormLayout.LabelRole, self.textLabel2_7) + self.formLayout_2.setWidget( + 9, QtWidgets.QFormLayout.LabelRole, self.textLabel2_7 + ) self.lneIx17 = QtWidgets.QLineEdit(self.groupBox1) self.lneIx17.setMinimumSize(QtCore.QSize(60, 0)) self.lneIx17.setMaximumSize(QtCore.QSize(31222, 32767)) @@ -181,7 +210,9 @@ def setupUi(self, formPpmacAxisSettings): self.textLabel2_8 = QtWidgets.QLabel(self.groupBox1) self.textLabel2_8.setWordWrap(False) self.textLabel2_8.setObjectName("textLabel2_8") - self.formLayout_2.setWidget(10, QtWidgets.QFormLayout.LabelRole, self.textLabel2_8) + self.formLayout_2.setWidget( + 10, QtWidgets.QFormLayout.LabelRole, self.textLabel2_8 + ) self.lneIx19 = QtWidgets.QLineEdit(self.groupBox1) self.lneIx19.setMinimumSize(QtCore.QSize(60, 0)) self.lneIx19.setMaximumSize(QtCore.QSize(31222, 32767)) @@ -193,7 +224,9 @@ def setupUi(self, formPpmacAxisSettings): self.tab_2.setObjectName("tab_2") self.groupBox1_2 = QtWidgets.QGroupBox(self.tab_2) self.groupBox1_2.setGeometry(QtCore.QRect(10, 20, 271, 330)) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.groupBox1_2.sizePolicy().hasHeightForWidth()) @@ -206,7 +239,9 @@ def setupUi(self, formPpmacAxisSettings): self.textLabel2_10 = QtWidgets.QLabel(self.groupBox1_2) self.textLabel2_10.setWordWrap(False) self.textLabel2_10.setObjectName("textLabel2_10") - self.formLayout_3.setWidget(0, QtWidgets.QFormLayout.LabelRole, self.textLabel2_10) + self.formLayout_3.setWidget( + 0, QtWidgets.QFormLayout.LabelRole, self.textLabel2_10 + ) self.lneIx30 = QtWidgets.QLineEdit(self.groupBox1_2) self.lneIx30.setMinimumSize(QtCore.QSize(60, 0)) self.lneIx30.setMaximumSize(QtCore.QSize(32233, 32767)) @@ -215,7 +250,9 @@ def setupUi(self, formPpmacAxisSettings): self.textLabel2_2_3 = QtWidgets.QLabel(self.groupBox1_2) self.textLabel2_2_3.setWordWrap(False) self.textLabel2_2_3.setObjectName("textLabel2_2_3") - self.formLayout_3.setWidget(1, QtWidgets.QFormLayout.LabelRole, self.textLabel2_2_3) + self.formLayout_3.setWidget( + 1, QtWidgets.QFormLayout.LabelRole, self.textLabel2_2_3 + ) self.lneIx31 = QtWidgets.QLineEdit(self.groupBox1_2) self.lneIx31.setMinimumSize(QtCore.QSize(60, 0)) self.lneIx31.setMaximumSize(QtCore.QSize(32233, 32767)) @@ -224,16 +261,22 @@ def setupUi(self, formPpmacAxisSettings): self.textLabel2_3_3 = QtWidgets.QLabel(self.groupBox1_2) self.textLabel2_3_3.setWordWrap(False) self.textLabel2_3_3.setObjectName("textLabel2_3_3") - self.formLayout_3.setWidget(2, QtWidgets.QFormLayout.LabelRole, self.textLabel2_3_3) + self.formLayout_3.setWidget( + 2, QtWidgets.QFormLayout.LabelRole, self.textLabel2_3_3 + ) self.lneDerivative2 = QtWidgets.QLineEdit(self.groupBox1_2) self.lneDerivative2.setMinimumSize(QtCore.QSize(60, 0)) self.lneDerivative2.setMaximumSize(QtCore.QSize(32233, 32767)) self.lneDerivative2.setObjectName("lneDerivative2") - self.formLayout_3.setWidget(2, QtWidgets.QFormLayout.FieldRole, self.lneDerivative2) + self.formLayout_3.setWidget( + 2, QtWidgets.QFormLayout.FieldRole, self.lneDerivative2 + ) self.textLabel2_4_3 = QtWidgets.QLabel(self.groupBox1_2) self.textLabel2_4_3.setWordWrap(False) self.textLabel2_4_3.setObjectName("textLabel2_4_3") - self.formLayout_3.setWidget(3, QtWidgets.QFormLayout.LabelRole, self.textLabel2_4_3) + self.formLayout_3.setWidget( + 3, QtWidgets.QFormLayout.LabelRole, self.textLabel2_4_3 + ) self.lneIx33 = QtWidgets.QLineEdit(self.groupBox1_2) self.lneIx33.setMinimumSize(QtCore.QSize(60, 0)) self.lneIx33.setMaximumSize(QtCore.QSize(32233, 32767)) @@ -242,7 +285,9 @@ def setupUi(self, formPpmacAxisSettings): self.textLabel2_5_3 = QtWidgets.QLabel(self.groupBox1_2) self.textLabel2_5_3.setWordWrap(False) self.textLabel2_5_3.setObjectName("textLabel2_5_3") - self.formLayout_3.setWidget(4, QtWidgets.QFormLayout.LabelRole, self.textLabel2_5_3) + self.formLayout_3.setWidget( + 4, QtWidgets.QFormLayout.LabelRole, self.textLabel2_5_3 + ) self.lneIx32 = QtWidgets.QLineEdit(self.groupBox1_2) self.lneIx32.setMinimumSize(QtCore.QSize(60, 0)) self.lneIx32.setMaximumSize(QtCore.QSize(32233, 32767)) @@ -251,7 +296,9 @@ def setupUi(self, formPpmacAxisSettings): self.textLabel2_10_2 = QtWidgets.QLabel(self.groupBox1_2) self.textLabel2_10_2.setWordWrap(False) self.textLabel2_10_2.setObjectName("textLabel2_10_2") - self.formLayout_3.setWidget(5, QtWidgets.QFormLayout.LabelRole, self.textLabel2_10_2) + self.formLayout_3.setWidget( + 5, QtWidgets.QFormLayout.LabelRole, self.textLabel2_10_2 + ) self.lneVFF2 = QtWidgets.QLineEdit(self.groupBox1_2) self.lneVFF2.setMinimumSize(QtCore.QSize(60, 0)) self.lneVFF2.setMaximumSize(QtCore.QSize(32233, 32767)) @@ -260,7 +307,9 @@ def setupUi(self, formPpmacAxisSettings): self.textLabel2_10_2_2 = QtWidgets.QLabel(self.groupBox1_2) self.textLabel2_10_2_2.setWordWrap(False) self.textLabel2_10_2_2.setObjectName("textLabel2_10_2_2") - self.formLayout_3.setWidget(6, QtWidgets.QFormLayout.LabelRole, self.textLabel2_10_2_2) + self.formLayout_3.setWidget( + 6, QtWidgets.QFormLayout.LabelRole, self.textLabel2_10_2_2 + ) self.lneIx35 = QtWidgets.QLineEdit(self.groupBox1_2) self.lneIx35.setMinimumSize(QtCore.QSize(60, 0)) self.lneIx35.setMaximumSize(QtCore.QSize(32233, 32767)) @@ -268,27 +317,37 @@ def setupUi(self, formPpmacAxisSettings): self.formLayout_3.setWidget(6, QtWidgets.QFormLayout.FieldRole, self.lneIx35) self.groupBox1_2_2 = QtWidgets.QGroupBox(self.tab_2) self.groupBox1_2_2.setGeometry(QtCore.QRect(290, 20, 260, 81)) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed + ) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.groupBox1_2_2.sizePolicy().hasHeightForWidth()) + sizePolicy.setHeightForWidth( + self.groupBox1_2_2.sizePolicy().hasHeightForWidth() + ) self.groupBox1_2_2.setSizePolicy(sizePolicy) self.groupBox1_2_2.setObjectName("groupBox1_2_2") self.formLayout_4 = QtWidgets.QFormLayout(self.groupBox1_2_2) - self.formLayout_4.setFieldGrowthPolicy(QtWidgets.QFormLayout.AllNonFixedFieldsGrow) + self.formLayout_4.setFieldGrowthPolicy( + QtWidgets.QFormLayout.AllNonFixedFieldsGrow + ) self.formLayout_4.setContentsMargins(11, 11, 11, 11) self.formLayout_4.setSpacing(6) self.formLayout_4.setObjectName("formLayout_4") self.lLoopSelect = QtWidgets.QLabel(self.groupBox1_2_2) self.lLoopSelect.setWordWrap(False) self.lLoopSelect.setObjectName("lLoopSelect") - self.formLayout_4.setWidget(0, QtWidgets.QFormLayout.LabelRole, self.lLoopSelect) + self.formLayout_4.setWidget( + 0, QtWidgets.QFormLayout.LabelRole, self.lLoopSelect + ) self.lneIx34 = QtWidgets.QLineEdit(self.groupBox1_2_2) self.lneIx34.setMinimumSize(QtCore.QSize(60, 0)) self.lneIx34.setMaximumSize(QtCore.QSize(32222, 32767)) self.lneIx34.setObjectName("lneIx34") self.formLayout_4.setWidget(0, QtWidgets.QFormLayout.FieldRole, self.lneIx34) - spacerItem1 = QtWidgets.QSpacerItem(30, 0, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) + spacerItem1 = QtWidgets.QSpacerItem( + 30, 0, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding + ) self.formLayout_4.setItem(2, QtWidgets.QFormLayout.SpanningRole, spacerItem1) self.tabAxisSetup.addTab(self.tab_2, "") self.gridLayout_3.addWidget(self.tabAxisSetup, 1, 0, 1, 3) @@ -307,7 +366,7 @@ def setupUi(self, formPpmacAxisSettings): self.lneIx21.returnPressed.connect(formPpmacAxisSettings.sendIx21) self.lneIx22.returnPressed.connect(formPpmacAxisSettings.sendIx22) self.lneIx26.returnPressed.connect(formPpmacAxisSettings.sendIx26) - self.tabAxisSetup.currentChanged['int'].connect(formPpmacAxisSettings.tabChange) + self.tabAxisSetup.currentChanged["int"].connect(formPpmacAxisSettings.tabChange) self.lneIx11.returnPressed.connect(formPpmacAxisSettings.sendIx11) self.lneIx14.returnPressed.connect(formPpmacAxisSettings.sendIx14) self.lneIx25.returnPressed.connect(formPpmacAxisSettings.sendIx25) @@ -326,39 +385,96 @@ def setupUi(self, formPpmacAxisSettings): def retranslateUi(self, formPpmacAxisSettings): _translate = QtCore.QCoreApplication.translate - formPpmacAxisSettings.setWindowTitle(_translate("formPpmacAxisSettings", "Axis setup")) + formPpmacAxisSettings.setWindowTitle( + _translate("formPpmacAxisSettings", "Axis setup") + ) self.btnUpdate.setText(_translate("formPpmacAxisSettings", "update")) - self.textLabel1.setText(_translate("formPpmacAxisSettings", "Note this screen does not update continuously.\n" -"Hit the update button to read out the current values from pmac.\n" -"Write demand values in the text fields and hit enter to send.")) + self.textLabel1.setText( + _translate( + "formPpmacAxisSettings", + "Note this screen does not update continuously.\n" + "Hit the update button to read out the current values from pmac.\n" + "Write demand values in the text fields and hit enter to send.", + ) + ) self.btnClose.setText(_translate("formPpmacAxisSettings", "close")) - self.groupBox2.setTitle(_translate("formPpmacAxisSettings", "Safety I variables")) - self.textLabel2_9.setText(_translate("formPpmacAxisSettings", "Motor[x].JogTa:")) - self.textLabel2_2_2.setText(_translate("formPpmacAxisSettings", "Motor[x].JogTs:")) - self.textLabel2_3_2.setText(_translate("formPpmacAxisSettings", "Motor[x].JogSpeed:")) - self.textLabel2_4_2.setText(_translate("formPpmacAxisSettings", "Motor[x].HomeVel:")) - self.textLabel2_6_2.setText(_translate("formPpmacAxisSettings", "Motor[x].pEncStatus:")) - self.textLabel2_7_2.setText(_translate("formPpmacAxisSettings", "Motor[x].HomeOffset:")) - self.groupBox1.setTitle(_translate("formPpmacAxisSettings", "Definition I variables")) - self.textLabel2.setText(_translate("formPpmacAxisSettings", "Motor[x].FatalFeLimit:")) - self.textLabel2_2.setText(_translate("formPpmacAxisSettings", "Motor[x].WarnFeLimit:")) - self.textLabel2_3.setText(_translate("formPpmacAxisSettings", "Motor[x].MaxPos:")) - self.textLabel2_4.setText(_translate("formPpmacAxisSettings", "Motor[x].MinPos:")) - self.textLabel2_5.setText(_translate("formPpmacAxisSettings", "Motor[x].AbortTa:")) - self.textLabel2_6.setText(_translate("formPpmacAxisSettings", "Motor[x].MaxSpeed:")) - self.textLabel2_7.setText(_translate("formPpmacAxisSettings", "Motor[x].InvAmax:")) - self.textLabel2_8.setText(_translate("formPpmacAxisSettings", "Motor[x].AbortTs:")) - self.tabAxisSetup.setTabText(self.tabAxisSetup.indexOf(self.tab), _translate("formPpmacAxisSettings", "definition and safety")) + self.groupBox2.setTitle( + _translate("formPpmacAxisSettings", "Safety I variables") + ) + self.textLabel2_9.setText( + _translate("formPpmacAxisSettings", "Motor[x].JogTa:") + ) + self.textLabel2_2_2.setText( + _translate("formPpmacAxisSettings", "Motor[x].JogTs:") + ) + self.textLabel2_3_2.setText( + _translate("formPpmacAxisSettings", "Motor[x].JogSpeed:") + ) + self.textLabel2_4_2.setText( + _translate("formPpmacAxisSettings", "Motor[x].HomeVel:") + ) + self.textLabel2_6_2.setText( + _translate("formPpmacAxisSettings", "Motor[x].pEncStatus:") + ) + self.textLabel2_7_2.setText( + _translate("formPpmacAxisSettings", "Motor[x].HomeOffset:") + ) + self.groupBox1.setTitle( + _translate("formPpmacAxisSettings", "Definition I variables") + ) + self.textLabel2.setText( + _translate("formPpmacAxisSettings", "Motor[x].FatalFeLimit:") + ) + self.textLabel2_2.setText( + _translate("formPpmacAxisSettings", "Motor[x].WarnFeLimit:") + ) + self.textLabel2_3.setText( + _translate("formPpmacAxisSettings", "Motor[x].MaxPos:") + ) + self.textLabel2_4.setText( + _translate("formPpmacAxisSettings", "Motor[x].MinPos:") + ) + self.textLabel2_5.setText( + _translate("formPpmacAxisSettings", "Motor[x].AbortTa:") + ) + self.textLabel2_6.setText( + _translate("formPpmacAxisSettings", "Motor[x].MaxSpeed:") + ) + self.textLabel2_7.setText( + _translate("formPpmacAxisSettings", "Motor[x].InvAmax:") + ) + self.textLabel2_8.setText( + _translate("formPpmacAxisSettings", "Motor[x].AbortTs:") + ) + self.tabAxisSetup.setTabText( + self.tabAxisSetup.indexOf(self.tab), + _translate("formPpmacAxisSettings", "definition and safety"), + ) self.groupBox1_2.setTitle(_translate("formPpmacAxisSettings", "Gains")) self.textLabel2_10.setText(_translate("formPpmacAxisSettings", "Proportional:")) - self.textLabel2_2_3.setText(_translate("formPpmacAxisSettings", "Derivative 1:")) - self.textLabel2_3_3.setText(_translate("formPpmacAxisSettings", "Derivative 2:")) + self.textLabel2_2_3.setText( + _translate("formPpmacAxisSettings", "Derivative 1:") + ) + self.textLabel2_3_3.setText( + _translate("formPpmacAxisSettings", "Derivative 2:") + ) self.textLabel2_4_3.setText(_translate("formPpmacAxisSettings", "Integral:")) - self.textLabel2_5_3.setText(_translate("formPpmacAxisSettings", "Vel. Feedforward 1:")) - self.textLabel2_10_2.setText(_translate("formPpmacAxisSettings", "Vel. Feedforward 2:")) - self.textLabel2_10_2_2.setText(_translate("formPpmacAxisSettings", "Accel. Feedforward:")) - self.groupBox1_2_2.setTitle(_translate("formPpmacAxisSettings", "Other Servo Settings")) - self.lLoopSelect.setText(_translate("formPpmacAxisSettings", "Integrator Mode:")) - self.tabAxisSetup.setTabText(self.tabAxisSetup.indexOf(self.tab_2), _translate("formPpmacAxisSettings", "PID and macro")) - - + self.textLabel2_5_3.setText( + _translate("formPpmacAxisSettings", "Vel. Feedforward 1:") + ) + self.textLabel2_10_2.setText( + _translate("formPpmacAxisSettings", "Vel. Feedforward 2:") + ) + self.textLabel2_10_2_2.setText( + _translate("formPpmacAxisSettings", "Accel. Feedforward:") + ) + self.groupBox1_2_2.setTitle( + _translate("formPpmacAxisSettings", "Other Servo Settings") + ) + self.lLoopSelect.setText( + _translate("formPpmacAxisSettings", "Integrator Mode:") + ) + self.tabAxisSetup.setTabText( + self.tabAxisSetup.indexOf(self.tab_2), + _translate("formPpmacAxisSettings", "PID and macro"), + ) diff --git a/src/dls_pmac_control/ui_formPpmacCSStatus.py b/src/dls_pmac_control/ui_formPpmacCSStatus.py index 2cbfc20..797e67e 100644 --- a/src/dls_pmac_control/ui_formPpmacCSStatus.py +++ b/src/dls_pmac_control/ui_formPpmacCSStatus.py @@ -1,4 +1,3 @@ - # Form implementation generated from reading ui file 'dls_pmac_control/formPpmacCSStatus.ui' # # Created by: PyQt5 UI code generator 5.15.4 diff --git a/src/dls_pmac_control/ui_formStatus.py b/src/dls_pmac_control/ui_formStatus.py index bcc23ac..7227a15 100644 --- a/src/dls_pmac_control/ui_formStatus.py +++ b/src/dls_pmac_control/ui_formStatus.py @@ -1,4 +1,3 @@ - # Form implementation generated from reading ui file 'dls_pmac_control/formStatus.ui' # # Created by: PyQt5 UI code generator 5.15.4 diff --git a/src/dls_pmac_control/ui_formWatches.py b/src/dls_pmac_control/ui_formWatches.py index 667b68d..48db6d6 100644 --- a/src/dls_pmac_control/ui_formWatches.py +++ b/src/dls_pmac_control/ui_formWatches.py @@ -1,4 +1,3 @@ - # Form implementation generated from reading ui file 'dls_pmac_control/formWatches.ui' # # Created by: PyQt5 UI code generator 5.15.4 From 9248b96d27f381ccf94ad7d2a4fc737343f328e3 Mon Sep 17 00:00:00 2001 From: Giles Knap Date: Sun, 11 Feb 2024 21:11:36 +0000 Subject: [PATCH 29/36] disable pyright because of QT5 --- pyproject.toml | 4 +++- src/dls_pmac_control/watches.py | 6 ++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 427b0e2..16f15aa 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -27,6 +27,7 @@ dev = [ "pipdeptree", "pre-commit", "pydata-sphinx-theme>=0.12", + "pyqt5-stubs", "pyright", "pytest", "pytest-cov", @@ -91,7 +92,8 @@ allowlist_externals = sphinx-autobuild commands = pytest: pytest --cov=dls_pmac_control --cov-report term --cov-report xml:cov.xml {posargs} - pyright: pyright src tests {posargs} + # TODO: pyright disabled becaue pyQT gives 290 errors - will investigate + # pyright: pyright src {posargs} pre-commit: pre-commit run --all-files {posargs} docs: sphinx-{posargs:build -EW --keep-going} -T docs build/html """ diff --git a/src/dls_pmac_control/watches.py b/src/dls_pmac_control/watches.py index 2eb8266..ddf4a31 100644 --- a/src/dls_pmac_control/watches.py +++ b/src/dls_pmac_control/watches.py @@ -50,7 +50,8 @@ def getWatch(self, varName): try: watch = self._watches[varName] except KeyError as e: - raise ValueError(msg='There is no watch for variable "%s"' % varName) from e + print('There is no watch for variable "%s"' % varName) + raise ValueError() from e return watch def updateWatch(self, row): @@ -75,7 +76,8 @@ def removeWatch(self): del self._watches[varName] self.parent.commsThread.remove_watch(varName) except KeyError as e: - raise ValueError(msg='There is no watch for variable "%s"' % varName) from e + print('There is no watch for variable "%s"' % varName) + raise ValueError() from e try: self.table.removeRow(row) # self.updateEditWatchPanel() From 09b2cf39d7df5c6bd0dbf9244ee52c6b862bf5cc Mon Sep 17 00:00:00 2001 From: Giles Knap Date: Sun, 11 Feb 2024 21:42:24 +0000 Subject: [PATCH 30/36] move motor to __main__ --- pyproject.toml | 2 +- src/dls_pmac_control/__main__.py | 1012 ++++++++++++++++++++++++++++- src/dls_pmac_control/motor.py | 1019 ------------------------------ src/dls_pmac_control/re | 0 src/dls_pmac_control/signal | 0 src/dls_pmac_control/sys | 0 src/dls_pmac_control/types | 0 tests/test_motor.py | 10 +- 8 files changed, 1011 insertions(+), 1032 deletions(-) mode change 100644 => 100755 src/dls_pmac_control/__main__.py delete mode 100755 src/dls_pmac_control/motor.py create mode 100644 src/dls_pmac_control/re create mode 100644 src/dls_pmac_control/signal create mode 100644 src/dls_pmac_control/sys create mode 100644 src/dls_pmac_control/types diff --git a/pyproject.toml b/pyproject.toml index 16f15aa..3d6cb2d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -40,7 +40,7 @@ dev = [ ] [project.scripts] -dls-pmac-control = "dls_pmac_control.__main__:main" +dls-pmac-control = "dls_pmac_control.motor:main" [project.urls] GitHub = "https://github.com/DiamondLightSource/dls-pmac-control" diff --git a/src/dls_pmac_control/__main__.py b/src/dls_pmac_control/__main__.py old mode 100644 new mode 100755 index cd2a93e..3a6563c --- a/src/dls_pmac_control/__main__.py +++ b/src/dls_pmac_control/__main__.py @@ -1,16 +1,1014 @@ -from argparse import ArgumentParser +import re +import signal +import sys +import types +from optparse import OptionParser +from os import path +from queue import Empty + +from dls_pmaclib.dls_pmacremote import ( + PmacEthernetInterface, + PmacSerialInterface, + PmacTelnetInterface, + PPmacSshInterface, +) +from dls_pmaclib.dls_pmcpreprocessor import ClsPmacParser +from PyQt5.QtCore import QEvent, Qt, pyqtSlot +from PyQt5.QtGui import QIcon, QPixmap +from PyQt5.QtWidgets import ( + QApplication, + QFileDialog, + QLineEdit, + QMainWindow, + QMessageBox, + QProgressDialog, + QTableWidgetItem, +) + +from dls_pmac_control.axissettings import Axissettingsform, PpmacAxissettingsform +from dls_pmac_control.commsThread import CommsThread +from dls_pmac_control.CSstatus import CSStatusForm, PpmacCSStatusForm +from dls_pmac_control.energise import Energiseform +from dls_pmac_control.gather import PmacGatherform +from dls_pmac_control.GlobalStatus import GlobalStatusForm, PpmacGlobalStatusForm +from dls_pmac_control.login import Loginform +from dls_pmac_control.ppmacgather import PpmacGatherform +from dls_pmac_control.status import PpmacStatusform, Statusform +from dls_pmac_control.ui_formControl import Ui_ControlForm +from dls_pmac_control.watches import Watchesform from . import __version__ -__all__ = ["main"] +class Controlform(QMainWindow, Ui_ControlForm): + def __init__(self, options, parent=None): + signal.signal(2, self.signalHandler) + # setup signals + + QMainWindow.__init__(self, parent) + self.setupUi(self) + # self.parent = parent + + self.greenLedOn = QPixmap(path.join(path.dirname(__file__), "greenLedOn.png")) + self.greenLedOff = QPixmap(path.join(path.dirname(__file__), "greenLedOff.png")) + self.redLedOn = QPixmap(path.join(path.dirname(__file__), "redLedOn.png")) + self.redLedOff = QPixmap(path.join(path.dirname(__file__), "redLedOff.png")) + self.amberLedOn = QPixmap(path.join(path.dirname(__file__), "led-amber.png")) + + self.pollingStatus = True + self.isUsingSerial = False + + self.lneServer.setText(options.server) + self.lnePort.setText(options.port) + self.currentMotor = int(options.defaultAxis) + self.nAxes = options.nAxes + self.macroAxisStartIndex = int(options.macroAxisStartIndex) + + self.username = options.username + self.password = options.password + + self.verboseMode = options.verbose + + self.connectionProtocol = options.protocol + if self.connectionProtocol == "ts": + # use terminal server + self.rbUseTerminalServer.setChecked(True) + self.ConnectionType = 0 + elif self.connectionProtocol == "tcpip": + # use TCP/IP socket connection + self.rbUseSocket.setChecked(True) + self.ConnectionType = 1 + elif self.connectionProtocol == "rs232": + # use serial connection + self.rbUseSerial.setChecked(True) + self.ConnectionType = 2 + elif self.connectionProtocol == "ssh": + # use ssh + self.rbUseSsh.setChecked(True) + self.ConnectionType = 3 + else: + QMessageBox.information( + self, + "Error", + "Wrong connection protocol specified on " + 'command line (use "ts" or "tcpip").', + ) + sys.exit(-1) + + self.connectionTimeout = max(options.timeout, 1) + + # This will hold a PmacRemoteInterface once self.remoteConnect() is + # called + self.pmac = None + self.powerpmac = None + + self.statusScreen = Statusform(self, self.currentMotor) + self.ppmacstatusScreen = PpmacStatusform(self, self.currentMotor) + self.CSStatusScreen = CSStatusForm(self) + self.PpmacCSStatusScreen = PpmacCSStatusForm(self) + self.GlobalStatusScreen = GlobalStatusForm(self) + self.PpmacGlobalStatusScreen = PpmacGlobalStatusForm(self) + self.axisSettingsScreen = Axissettingsform( + self, self.currentMotor, self.macroAxisStartIndex + ) + self.ppmacaxisSettingsScreen = PpmacAxissettingsform(self, self.currentMotor) + self.pmacgatherScreen = PmacGatherform(self, self.currentMotor) + self.ppmacgatherScreen = PpmacGatherform(self, self.currentMotor) + self.watchesScreen = Watchesform(self) + self.login = Loginform(self, self.username, self.password) + # self.energiseScreen = Energiseform(self.pmac,self) + self.commsThread = CommsThread(self) + + self.spnJogMotor.setValue(self.currentMotor) + + # a few details for use when downloading pmc file + self.progressEventType = QEvent.User + 1 + self.downloadDoneEventType = QEvent.User + 2 + self.updatesReadyEventType = QEvent.User + 3 + self.progressDialog = None + self.canceledDownload = False + + self.table.setColumnWidth(3, 40) + self.table.setColumnWidth(4, 40) + self.table.cellDoubleClicked.connect(self.chooseMotorFromTable) + + self.commands = [] + self.commands_i = 0 + self.lneSend.keyPressEvent = types.MethodType(self.checkHistory, self.lneSend) + self.dirname = "." + + self.lblIdentity.setText("") + self.txtShell.clear() + + def useTerminalServerConnection(self): + if self.ConnectionType != 0: + self.ConnectionType = 0 + # set the server and port fields to defaults for this connection + # type + self.lneServer.setText("blxxi-nt-tserv-01") + self.lnePort.setText("7017") + self.textLabel1.setText("Server:") + self.textLabel2.setText("Port:") + self.lblPolling.setText("Polling") + self.lnePollRate.setEnabled(False) + self.lblPollRate.setEnabled(False) + + def useSocketConnection(self): + if self.ConnectionType != 1: + self.ConnectionType = 1 + # set the server and port fields to defaults for this connection + # type + self.lneServer.setText("172.23.240.97") + self.lnePort.setText("1025") + self.textLabel1.setText("IP address:") + self.textLabel2.setText("Port:") + self.lblPolling.setText("Polling") + self.lnePollRate.setEnabled(False) + self.lblPollRate.setEnabled(False) + + def useSerial(self): + if self.ConnectionType != 2: + self.ConnectionType = 2 + self.isUsingSerial = False + # set the server and port fields to defaults for this connection + # type + self.lneServer.setText("/dev/ttyUSB0") + self.lnePort.setText("38400") + self.textLabel1.setText("COM port:") + self.textLabel2.setText("Baudrate:") + self.lblPolling.setText("Polling @") + self.lnePollRate.setEnabled(True) + self.lnePollRate.setText("0") + self.lblPollRate.setEnabled(True) + + def useSshConnection(self): + if self.ConnectionType != 3: + self.ConnectionType = 3 + # set the server and port fields to defaults for this connection + # type + self.lneServer.setText("172.23.240.97") + self.lnePort.setText("22") + self.textLabel1.setText("IP address:") + self.textLabel2.setText("Port:") + # self.textLabel3.setText("Username:") + # self.textLabel4.setText("Password:") + self.lblPolling.setText("Polling") + self.lnePollRate.setEnabled(False) + self.lblPollRate.setEnabled(False) + + def checkHistory(self, edit, event): + if event.key() == Qt.Key_Up: + if len(self.commands) == 0: + self.commands_i = 0 + self.lneSend.setText("") + elif self.commands_i > -len(self.commands): + self.commands_i -= 1 + self.lneSend.setText(self.commands[self.commands_i]) + else: + self.lneSend.setText(self.commands[self.commands_i]) + elif event.key() == Qt.Key_Down: + if self.commands_i >= -1: + self.commands_i = 0 + self.lneSend.setText("") + else: + self.commands_i += 1 + self.lneSend.setText(self.commands[self.commands_i]) + QLineEdit.keyPressEvent(edit, event) + + def remoteConnect(self): + # Create a remote PMAC interface, of the correct type, depending on + # radio-box selection in the "Connection to PMAC" section + if self.ConnectionType == 0: + self.pmac = PmacTelnetInterface( + self, + verbose=self.verboseMode, + numAxes=self.nAxes, + timeout=self.connectionTimeout, + ) + elif self.ConnectionType == 1: + self.pmac = PmacEthernetInterface( + self, + verbose=self.verboseMode, + numAxes=self.nAxes, + timeout=self.connectionTimeout, + ) + elif self.ConnectionType == 2: + try: + pollrate = float(self.lnePollRate.text()) + except ValueError: + pollrate = False + self.commsThread.max_pollrate = pollrate + self.pmac = PmacSerialInterface( + self, + verbose=self.verboseMode, + numAxes=self.nAxes, + timeout=self.connectionTimeout, + ) + elif self.ConnectionType == 3: + self.pmac = PPmacSshInterface( + self, + verbose=self.verboseMode, + numAxes=self.nAxes, + timeout=self.connectionTimeout, + ) + + # Set the server name and port + server_name = self.lneServer.text() + server_port = self.lnePort.text() + self.pmac.setConnectionParams(server_name, server_port) + self.txtShell.append(f"Connecting to {server_name} {server_port}") + + # Connect to the interface/PMAC + # Show login window if ssh connection + if self.ConnectionType == 3: + # use exec instead of show to wait until login is done + is_clickedOK = self.login.exec() + if not is_clickedOK: + return + else: + # try to connect again + connection_status = self.pmac.connect( + username=self.login.username, password=self.login.password + ) + if connection_status: + QMessageBox.information(self, "Error", connection_status) + return + else: + connection_status = self.pmac.connect() + + if connection_status: + QMessageBox.information(self, "Error", connection_status) + return + + # Find out the type of the PMAC + pmac_model_str = self.pmac.getPmacModel() + if pmac_model_str: + self.setWindowTitle("Delta Tau motor controller - %s" % pmac_model_str) + else: + QMessageBox.information(self, "Error", "Could not determine PMAC model") + return + + self.table.setRowCount(self.pmac.getNumberOfAxes()) + self.spnJogMotor.setMaximum(self.pmac.getNumberOfAxes()) + + self.btnConnect.setEnabled(False) + self.lneServer.setEnabled(False) + self.lnePort.setEnabled(False) + self.btnGroupProtocol.setEnabled(False) + self.btnDisconnect.setEnabled(True) + self.btnJogNeg.setEnabled(True) + self.btnJogPos.setEnabled(True) + self.btnJogStop.setEnabled(True) + self.btnHome.setEnabled(True) + self.lneSend.setEnabled(True) + self.btnSend.setEnabled(True) + self.lneJogTo.setEnabled(True) + self.lneJogDist.setEnabled(True) + self.btnJogTo.setEnabled(True) + self.btnEnergise.setEnabled(False) + # disable energise button for geobrick and power pmac + enableEnergise = ( + not self.pmac.isModelGeobrick() and not self.ConnectionType == 3 + ) + self.btnEnergise.setEnabled(enableEnergise) + self.btnKillAll.setEnabled(True) + self.btnStatus.setEnabled(True) + self.btnCSStatus.setEnabled(True) + self.btnGlobalStatus.setEnabled(True) + self.btnLoadFile.setEnabled(True) + self.btnSettings.setEnabled(True) + self.btnKillMotor.setEnabled(True) + self.chkJogInc.setEnabled(True) + self.btnPollingStatus.setEnabled(True) + self.btnGather.setEnabled(True) + self.btnWatches.setEnabled(True) + self.table.setEnabled(True) + self.lnePollRate.setEnabled(False) + self.lblPollRate.setEnabled(False) + self.pixPolling.setPixmap(self.greenLedOn) + + def remoteDisconnect(self): + # If the PMAC interface has been already defined, make it disconnect + # (this will do nothing if the interface is not connected) + if self.pmac: + self.txtShell.append("Disconnected") + self.pmac.disconnect() + + self.setWindowTitle("Delta Tau motor controller") + self.btnConnect.setEnabled(True) + self.btnDisconnect.setEnabled(False) + self.lneServer.setEnabled(True) + self.lnePort.setEnabled(True) + self.btnGroupProtocol.setEnabled(True) + self.btnJogNeg.setEnabled(False) + self.btnJogPos.setEnabled(False) + self.btnJogStop.setEnabled(False) + self.btnHome.setEnabled(False) + self.lneSend.setEnabled(False) + self.btnSend.setEnabled(False) + self.lneJogTo.setEnabled(False) + self.lneJogDist.setEnabled(False) + self.btnJogTo.setEnabled(False) + self.btnEnergise.setEnabled(False) + self.btnKillAll.setEnabled(False) + self.btnStatus.setEnabled(False) + self.btnCSStatus.setEnabled(False) + self.btnGlobalStatus.setEnabled(False) + self.btnSettings.setEnabled(False) + self.btnKillMotor.setEnabled(False) + self.btnLoadFile.setEnabled(False) + self.chkJogInc.setEnabled(False) + self.btnPollingStatus.setEnabled(False) + self.btnGather.setEnabled(False) + self.btnWatches.setEnabled(False) + self.table.setEnabled(False) + self.pixPolling.setPixmap(self.greenLedOff) + self.lblIdentity.setText("") + + self.axisSettingsScreen.close() + self.ppmacaxisSettingsScreen.close() + self.statusScreen.close() + self.ppmacstatusScreen.close() + self.CSStatusScreen.close() + self.PpmacCSStatusScreen.close() + self.GlobalStatusScreen.close() + self.PpmacGlobalStatusScreen.close() + self.pmacgatherScreen.close() + self.ppmacgatherScreen.close() + self.watchesScreen.clearWatches() + self.watchesScreen.close() + try: + self.energiseScreen.close() + except Exception: + pass + + def jogNeg(self): + (command, retStr, retStatus) = self.pmac.jogInc( + self.currentMotor, "neg", str(self.lneJogDist.text()) + ) + self.addToTxtShell(command, retStr) + + # public slot + def jogPos(self): + (command, retStr, retStatus) = self.pmac.jogInc( + self.currentMotor, "pos", str(self.lneJogDist.text()) + ) + self.addToTxtShell(command, retStr) + + # public slot + + def jogStop(self): + (command, retStr, retStatus) = self.pmac.jogStop(self.currentMotor) + self.addToTxtShell(command, retStr) + + # public slot + + def jogHome(self): + (command, retStr, retStatus) = self.pmac.homeCommand(self.currentMotor) + self.addToTxtShell(command, retStr) + + # public slot + + def jogGoToPosition(self): + (command, retStr, retStatus) = self.pmac.jogTo( + self.currentMotor, self.lneJogTo.text() + ) + self.addToTxtShell(command, retStr) + + # public slot + def jogChangeMotor(self, newMotor): + self.currentMotor = newMotor + self.statusScreen.changeAxis(self.currentMotor) + self.ppmacstatusScreen.changeAxis(self.currentMotor) + self.axisSettingsScreen.changeAxis(self.currentMotor) + self.ppmacaxisSettingsScreen.changeAxis(self.currentMotor) + + # Send a #Xk command to kill the current motor. + def killMotor(self): + command = "#%dk" % self.currentMotor + (returnString, status) = self.pmac.sendCommand(command) + self.addToTxtShell(command) + + # Send a (ASCII 0x0B) command to the PMAC to kill all motion + # all servo loops will be opened and amplifier enable set false. + # see TURBO SRM page 289 + def killAllMotors(self): + # print "killing all motors!" + command = "\x0B" + (returnString, status) = self.pmac.sendCommand(command) + self.addToTxtShell("CTRL-K") + + def dataGather(self): + # if power pmac + # if self.ConnectionType == 3: + if isinstance(self.pmac, PPmacSshInterface): + self.ppmacgatherScreen.show() + else: + self.pmacgatherScreen.show() + + # public slot + def watches(self): + self.watchesScreen.show() + + def pmacEnergiseAxis(self): + self.energiseScreen = Energiseform(self.pmac, self) + self.energiseScreen.show() + + def statusScreen(self): + # if power pmac + if isinstance(self.pmac, PPmacSshInterface): + self.ppmacstatusScreen.show() + else: + self.statusScreen.show() + + def CSStatusScreen(self): + # if power pmac + if isinstance(self.pmac, PPmacSshInterface): + self.PpmacCSStatusScreen.show() + else: + self.CSStatusScreen.show() + + def GlobalStatusScreen(self): + # if power pmac + if isinstance(self.pmac, PPmacSshInterface): + self.PpmacGlobalStatusScreen.show() + else: + self.GlobalStatusScreen.show() + + # public slot + def jogParameters(self): + if isinstance(self.pmac, PPmacSshInterface): + self.ppmacaxisSettingsScreen.show() + self.ppmacaxisSettingsScreen.axisUpdate() + else: + self.axisSettingsScreen.show() + self.axisSettingsScreen.axisUpdate() + + # Download a pmc configuration file to the PMAC + def pmacLoadConfig(self): + # First get the file from a file dialog + myDialog = QFileDialog(self) + q_file = myDialog.getOpenFileName( + self, "Load PMC file", self.dirname, "PMAC configuration (*.pmc *.PMC)" + ) + fileName, _ = q_file + if not fileName: + return + self.dirname = path.dirname(str(fileName)) + + # A couple of regular expressions for use in parsing the pmc file + blankLine = re.compile(r"^\s*$") # match blank lines + + # parsing through the file + pmc = ClsPmacParser() + pmcLines = pmc.parse(fileName) + + if pmcLines: + # Get rid of all the empty lines, but keep line numbers + commands = [] + for i, pmcLine in enumerate(pmcLines): + if not blankLine.match(pmcLine): + commands.append((i + 1, pmcLine)) + + # Prepend two close commands and a delete gather to the front of + # any pmc file uploaded. This ensures that any open PLC buffers + # are closed before an upload and that the gather buffer is + # erased to make memory available for the new PLC. Two close + # commands are sent to ensure that we leave any nested statements + # (first close) before then closing the buffer (second close). + # Dummy line numbers of zero are paired with each command to + # match the formatting and to not disrupt the real line numbering + closeCommands = [(0, "CLOSE"), (0, "CLOSE"), (0, "DELETE GATHER")] + commands = closeCommands + commands + + # Open up progress dialog and start sending the commands. + self.canceledDownload = False + self.progressDialog = QProgressDialog( + "Downloading PMAC configuration", "cancel", 0, len(pmcLines), self + ) + self.progressDialog.setWindowModality(Qt.ApplicationModal) + self.progressDialog.canceled.connect(self.cancel) + self.txtShell.append("Beginning download of pmc file: " + fileName) + self.commsThread.inputQueue.put(("sendSeries", commands)) + + def cancel(self): + self.canceledDownload = True + self.commsThread.inputQueue.put(("cancelSendSeries", "")) + + def pmacPollingStatus(self): + # If we are already polling, disable it + if self.pollingStatus: + self.pollingStatus = False + self.commsThread.inputQueue.put(("disablePollingStatus", True)) + + self.btnPollingStatus.setText("enable polling") + + # Disable all the controls and status displays to indicate that we + # do not have updates available + self.table.setEnabled(False) + self.lblPosition.setEnabled(False) + self.lblVelo.setEnabled(False) + self.lblFolErr.setEnabled(False) + self.pixPolling.setPixmap(self.greenLedOff) + + # else, if we are not polling: start polling! + else: + self.pollingStatus = True + self.commsThread.inputQueue.put(("disablePollingStatus", False)) + self.btnPollingStatus.setText("disable polling") + + # Re-enable all the disabled labels and controls + self.table.setEnabled(True) + self.lblPosition.setEnabled(True) + self.lblVelo.setEnabled(True) + self.lblFolErr.setEnabled(True) + self.pixPolling.setPixmap(self.greenLedOn) + + def jogNegContinousStart(self): + # print "controlform.jogNegContinousStart(): Not implemented yet" + (command, retStr, retStatus) = self.pmac.jogContinous(self.currentMotor, "neg") + self.addToTxtShell(command, retStr) + + # public slot + def jogPosContinousStart(self): + # print "controlform.jogPosContinousStart(): Not implemented yet" + (command, retStr, retStatus) = self.pmac.jogContinous(self.currentMotor, "pos") + self.addToTxtShell(command, retStr) + + # public slot + def sendSingleCommand(self): + # print "controlform.sendSingleCommand(): Not implemented yet" + command = self.lneSend.text() + if len(self.commands) == 0 or self.commands[-1] != command: + self.commands.append(command) + (retStr, status) = self.pmac.sendCommand(command) + self.addToTxtShell(command, retStr, False) + self.commands_i = 0 + self.lneSend.setText("") + + @pyqtSlot(int, int, name="chooseMotorFromTable") + def chooseMotorFromTable(self, a0): + self.spnJogMotor.setValue(a0 + 1) + + # public slot + def jogIncrementally(self, a0): # a0 is True if 'jog inc' box checked + self.lneJogDist.setEnabled(a0) + if a0: + self.btnJogPos.pressed.disconnect(self.jogPosContinousStart) + self.btnJogPos.released.disconnect(self.jogStop) + self.btnJogNeg.pressed.disconnect(self.jogNegContinousStart) + self.btnJogNeg.released.disconnect(self.jogStop) + self.btnJogNeg.clicked.connect(self.jogNeg) + self.btnJogPos.clicked.connect(self.jogPos) + else: + self.btnJogPos.pressed.connect(self.jogPosContinousStart) + self.btnJogPos.released.connect(self.jogStop) + self.btnJogNeg.pressed.connect(self.jogNegContinousStart) + self.btnJogNeg.released.connect(self.jogStop) + self.btnJogNeg.clicked.disconnect(self.jogNeg) + self.btnJogPos.clicked.disconnect(self.jogPos) + + def __item(self, row, col): + item = self.table.item(row, col) + if not item: + item = QTableWidgetItem() + self.table.setItem(row, col, item) + item.setFlags(Qt.ItemIsEnabled) + return item + + def addToTxtShell(self, command, retStr=None, chkShowAll=True): + if chkShowAll is False or self.chkShowAll.isChecked(): + self.txtShell.append(command) + if retStr is not None: + self.txtShell.append( + retStr.rstrip("\x06").lstrip("\x07").replace("\r", " ") + ) + + # Called when an event comes out of the polling thread + # and the jog ribbon. + def updateMotors(self): + under_voltage = False + over_voltage = False + over_temperature = False + + self.commsThread.resultQueue.qsize() + for _queItem in range(0, self.commsThread.resultQueue.qsize()): + try: + value = self.commsThread.resultQueue.get(False) + except Empty: + return + + try: + motorRow = value[6] + # check for special cases + if isinstance(motorRow, str): + if isinstance(self.pmac, PPmacSshInterface): + if motorRow == "G": + self.PpmacGlobalStatusScreen.updateStatus( + int(value[0].strip("$"), 16) + ) + continue + if motorRow.startswith("CS"): + self.PpmacCSStatusScreen.updateStatus( + int(value[0].strip("$"), 16) + ) + continue + if motorRow.startswith("FEED"): + self.PpmacCSStatusScreen.updateFeed( + int(round(float(value[0]))) + ) + continue + if motorRow == "IDENT": + self.updateIdentity(int(value[0])) + continue + if motorRow == "UVOL": + if int(value[0]) != 0: + under_voltage = True + continue + if motorRow == "OVOL": + if int(value[0]) != 0: + over_voltage = True + continue + if motorRow == "OTEMP": + if int(value[0]) != 0: + over_temperature = True + continue + else: + if motorRow == "G": + self.GlobalStatusScreen.updateStatus(int(value[0], 16)) + continue + if motorRow.startswith("CS"): + self.CSStatusScreen.updateStatus(int(value[0], 16)) + continue + if motorRow.startswith("FEED"): + self.CSStatusScreen.updateFeed(int(round(float(value[0])))) + continue + if motorRow == "IDENT": + self.updateIdentity(int(value[0])) + continue + + else: + position = str(round(float(value[1]), 1)) + velocity = str(round(float(value[2]), 1)) + folerr = str(round(float(value[3]), 1)) + + i2t_fault = False + over_current = False + + if motorRow < 8: + if isinstance(self.pmac, PPmacSshInterface): + if int(value[4]) > 0: + i2t_fault = True + if int(value[5]) > 0: + over_current = True + elif isinstance(self.pmac, PmacEthernetInterface): + amp_status = (int(value[4]) & 448) >> 6 + if amp_status == 5: + i2t_fault = True + elif amp_status == 6: + over_current = True + if motorRow < 4: + if amp_status == 2: + under_voltage = True + elif amp_status == 3: + over_temperature = True + elif amp_status == 4: + over_voltage = True + + self.__item(motorRow, 0).setText(position) + self.__item(motorRow, 1).setText(velocity) + self.__item(motorRow, 2).setText(folerr) + + statusWord = int(value[0].strip("$"), 16) + + # define high and low limits for power pmac + if isinstance(self.pmac, PPmacSshInterface): + loLim = bool(statusWord & 0x2000000000000000) # MinusLimit + hiLim = bool(statusWord & 0x1000000000000000) # PlusLimit + loLimSoft = bool( + statusWord & 0x0080000000000000 + ) # SoftMinusLimit + hiLimSoft = bool( + statusWord & 0x0040000000000000 + ) # SoftPlusLimit + + # define high and low limits for pmac + else: + loLim = bool( + statusWord & 0x400000000000 + ) # negative end limit set + hiLim = bool( + statusWord & 0x200000000000 + ) # positive end limit set + loLimSoft = False + hiLimSoft = False + + # set limit indicators in polling table + if hiLim: + self.__item(motorRow, 3).setIcon(QIcon(self.redLedOn)) + elif hiLimSoft: + self.__item(motorRow, 3).setIcon(QIcon(self.amberLedOn)) + else: + self.__item(motorRow, 3).setIcon(QIcon(self.redLedOff)) + if loLim: + self.__item(motorRow, 4).setIcon(QIcon(self.redLedOn)) + elif loLimSoft: + self.__item(motorRow, 4).setIcon(QIcon(self.amberLedOn)) + else: + self.__item(motorRow, 4).setIcon(QIcon(self.redLedOff)) + + # set amplifier status indicators in polling table + if i2t_fault: + self.__item(motorRow, 5).setIcon(QIcon(self.redLedOn)) + else: + self.__item(motorRow, 5).setIcon(QIcon(self.redLedOff)) + if over_current: + self.__item(motorRow, 6).setIcon(QIcon(self.redLedOn)) + else: + self.__item(motorRow, 6).setIcon(QIcon(self.redLedOff)) + + # Update also the jog ribbon + if motorRow + 1 == self.currentMotor: + self.lblPosition.setText(position) + self.lblVelo.setText(velocity) + self.lblFolErr.setText(folerr) + if hiLim: + self.pixHiLim.setPixmap(self.redLedOn) + elif hiLimSoft: + self.pixHiLim.setPixmap(self.amberLedOn) + else: + self.pixHiLim.setPixmap(self.redLedOff) + if loLim: + self.pixLoLim.setPixmap(self.redLedOn) + elif loLimSoft: + self.pixLoLim.setPixmap(self.amberLedOn) + else: + self.pixLoLim.setPixmap(self.redLedOff) + self.statusScreen.updateStatus(statusWord) + self.ppmacstatusScreen.updateStatus(statusWord) + + # set controller status indicators on main window + if under_voltage: + self.pixUnderVoltage.setPixmap(self.redLedOn) + else: + self.pixUnderVoltage.setPixmap(self.redLedOff) + if over_voltage: + self.pixOverVoltage.setPixmap(self.redLedOn) + else: + self.pixOverVoltage.setPixmap(self.redLedOff) + if over_temperature: + self.pixOverTemperature.setPixmap(self.redLedOn) + else: + self.pixOverTemperature.setPixmap(self.redLedOff) + + except (ValueError, IndexError): + # Catch the exception and continue, since there may be other + # updates waiting in the queue. + if self.verboseMode: + print("Update request received invalid response: ", value) + + domainNames = [ + "BL", + "BR", + "BS", + "FE", + "LB", + "LI", + "ME", + "SR", + "LA", + "TBD", + "TBD", + "TBD", + "TBD", + "TBD", + "TBD", + "RSV", + ] + subdomainLetters = [ + ["I", "B", "J", "C", "K", "D", "L", "E"], + ["C", "S", "", "", "", "", "", ""], + ["", "", "", "", "", "", "", ""], + ["I", "B", "J", "C", "K", "D", "L", "E"], + ["", "", "", "", "", "", "", ""], + ["", "", "", "", "", "", "", ""], + ["D", "P", "C", "T", "M", "G", "", ""], + ["I", "A", "J", "C", "K", "R", "L", "S"], + ["R", "", "", "", "", "", "", ""], + ["", "", "", "", "", "", "", ""], + ["", "", "", "", "", "", "", ""], + ["", "", "", "", "", "", "", ""], + ["", "", "", "", "", "", "", ""], + ["", "", "", "", "", "", "", ""], + ["", "", "", "", "", "", "", ""], + ["", "", "", "", "", "", "", ""], + ] + + def updateIdentity(self, id): + if not self.btnConnect.isEnabled(): + if id == 0: + text = "Identity not set" + else: + domain = (id >> 20) & 0x0F + # swVersion = (id >> 13) & 0x7F + subdomainNum = (id >> 7) & 0x1F + pmacNum = id & 0x1F + subdomainLetter = ( + ((id >> 6) & 0x01) | ((id >> 4) & 0x02) | ((id >> 10) & 0x04) + ) + text = self.domainNames[domain] + if subdomainNum != 0: + text += "%02d" % subdomainNum + text += self.subdomainLetters[domain][subdomainLetter] + text += " %s " % self.pmac.getShortModelName() + text += "%d" % pmacNum + self.lblIdentity.setText(text) + + def updateWatches(self): + self.commsThread.watchesQueue.qsize() + for _queItem in range(0, self.commsThread.watchesQueue.qsize()): + try: + value = self.commsThread.watchesQueue.get(False) + except Empty: + return + for n in range(len(value)): + if "." in value[n]: + value[n] = round(float(value[n]), 1) + self.watchesScreen.table.setItem(n, 1, QTableWidgetItem(str(value[n]))) + + def customEvent(self, E): + if E.type() == self.progressEventType: + (lines, err) = E.data() + self.progressDialog.setValue(lines) + if err: + self.txtShell.append(err) + elif E.type() == self.downloadDoneEventType: + self.progressDialog.setValue(self.progressDialog.maximum()) + self.txtShell.append(str(E.data())) + elif E.type() == self.updatesReadyEventType: + self.updateMotors() + self.updateWatches() + + def signalHandler(self, signum, frame): + if signum == 2: # SIGINT + print("Closing connection...") + self.pmac.disconnect() + print("Closing application.") + QApplication.exit(0) + + def die(self): + self.remoteDisconnect() + self.commsThread.inputQueue.put(("die", "")) + + +# Main function in the pmaccontrol application. +def main(): + usage = """usage: %prog [options] +%prog is a graphical frontend to the Deltatau motorcontroller known as PMAC.""" + parser = OptionParser(usage) + parser.add_option( + "-v", + "--verbose", + action="store_true", + dest="verbose", + default=False, + help="Print more details (than necessary in most " "cases...)", + ) + parser.add_option( + "-o", + "--protocol", + action="store", + dest="protocol", + default="ts", + help='Set the connection protocol; use "ts" for ' + "serial via terminal server (the default), " + 'or "tcpip" for network TCP/IP connection.', + ) + parser.add_option( + "-s", + "--server", + action="store", + dest="server", + default="blxxi-nt-tserv-01", + help="Set server name (default: blxxi-nt-tserv-01)", + ) + parser.add_option( + "-p", + "--port", + action="store", + dest="port", + default="7017", + help="Set IP port number to connect to (default: 7017)", + ) + parser.add_option( + "--username", + action="store", + dest="username", + default="root", + help="Set the SSH username (default: root)", + ) + parser.add_option( + "--password", + action="store", + dest="password", + default="deltatau", + help="Set the SSH password (default: deltatau)", + ) + parser.add_option( + "-a", + "--axis", + action="store", + dest="defaultAxis", + default=1, + help="Set an axis as a default selected axis when " + "starting up the application (default: 1)", + ) + parser.add_option( + "-m", + "--macroAxisStartIndex", + action="store", + dest="macroAxisStartIndex", + default=0, + help="Set the first macro axis (default: 0)", + ) + parser.add_option( + "-n", + "--naxes", + action="store", + dest="nAxes", + help="Display and poll NAXES axes. Default is 32 for a " + "PMAC, 8 for a geoBrick", + ) + parser.add_option( + "-t", + "--timeout", + action="store", + type="float", + dest="timeout", + default=3.0, + help="Set the communication timeout (default: 3 seconds, " "minimum: 1 second)", + ) + parser.add_option( + "--version", + action="store_true", + help="get the version of dls-pmac-control", + ) + (options, args) = parser.parse_args() + + if options.version: + print(__version__) + exit(0) -def main(args=None): - parser = ArgumentParser() - parser.add_argument("--version", action="version", version=__version__) - args = parser.parse_args(args) + app = QApplication(sys.argv) + app.lastWindowClosed.connect(app.quit) + win = Controlform(options) + app.aboutToQuit.connect(win.die) + win.show() + win.splitter.moveSplitter(180, 1) + # catch CTRL-C + signal.signal(signal.SIGINT, signal.SIG_DFL) + app.exec_() -# test with: pipenv run python -m dls_pmac_control if __name__ == "__main__": main() diff --git a/src/dls_pmac_control/motor.py b/src/dls_pmac_control/motor.py deleted file mode 100755 index 67ffe1d..0000000 --- a/src/dls_pmac_control/motor.py +++ /dev/null @@ -1,1019 +0,0 @@ -import re -import signal -import sys -import types -from optparse import OptionParser -from os import path -from queue import Empty - -from dls_pmaclib.dls_pmacremote import ( - PmacEthernetInterface, - PmacSerialInterface, - PmacTelnetInterface, - PPmacSshInterface, -) -from dls_pmaclib.dls_pmcpreprocessor import ClsPmacParser -from PyQt5.QtCore import QEvent, Qt, pyqtSlot -from PyQt5.QtGui import QIcon, QPixmap -from PyQt5.QtWidgets import ( - QApplication, - QFileDialog, - QLineEdit, - QMainWindow, - QMessageBox, - QProgressDialog, - QTableWidgetItem, -) - -from dls_pmac_control.axissettings import Axissettingsform, PpmacAxissettingsform -from dls_pmac_control.commsThread import CommsThread -from dls_pmac_control.CSstatus import CSStatusForm, PpmacCSStatusForm -from dls_pmac_control.energise import Energiseform -from dls_pmac_control.gather import PmacGatherform -from dls_pmac_control.GlobalStatus import GlobalStatusForm, PpmacGlobalStatusForm -from dls_pmac_control.login import Loginform -from dls_pmac_control.ppmacgather import PpmacGatherform -from dls_pmac_control.status import PpmacStatusform, Statusform -from dls_pmac_control.ui_formControl import Ui_ControlForm -from dls_pmac_control.watches import Watchesform - -from . import __version__ - -# from optparse import OptionParser - -if __name__ == "__main__": - pass - - -class Controlform(QMainWindow, Ui_ControlForm): - def __init__(self, options, parent=None): - signal.signal(2, self.signalHandler) - # setup signals - - QMainWindow.__init__(self, parent) - self.setupUi(self) - # self.parent = parent - - self.greenLedOn = QPixmap(path.join(path.dirname(__file__), "greenLedOn.png")) - self.greenLedOff = QPixmap(path.join(path.dirname(__file__), "greenLedOff.png")) - self.redLedOn = QPixmap(path.join(path.dirname(__file__), "redLedOn.png")) - self.redLedOff = QPixmap(path.join(path.dirname(__file__), "redLedOff.png")) - self.amberLedOn = QPixmap(path.join(path.dirname(__file__), "led-amber.png")) - - self.pollingStatus = True - self.isUsingSerial = False - - self.lneServer.setText(options.server) - self.lnePort.setText(options.port) - self.currentMotor = int(options.defaultAxis) - self.nAxes = options.nAxes - self.macroAxisStartIndex = int(options.macroAxisStartIndex) - - self.username = options.username - self.password = options.password - - self.verboseMode = options.verbose - - self.connectionProtocol = options.protocol - if self.connectionProtocol == "ts": - # use terminal server - self.rbUseTerminalServer.setChecked(True) - self.ConnectionType = 0 - elif self.connectionProtocol == "tcpip": - # use TCP/IP socket connection - self.rbUseSocket.setChecked(True) - self.ConnectionType = 1 - elif self.connectionProtocol == "rs232": - # use serial connection - self.rbUseSerial.setChecked(True) - self.ConnectionType = 2 - elif self.connectionProtocol == "ssh": - # use ssh - self.rbUseSsh.setChecked(True) - self.ConnectionType = 3 - else: - QMessageBox.information( - self, - "Error", - "Wrong connection protocol specified on " - 'command line (use "ts" or "tcpip").', - ) - sys.exit(-1) - - self.connectionTimeout = max(options.timeout, 1) - - # This will hold a PmacRemoteInterface once self.remoteConnect() is - # called - self.pmac = None - self.powerpmac = None - - self.statusScreen = Statusform(self, self.currentMotor) - self.ppmacstatusScreen = PpmacStatusform(self, self.currentMotor) - self.CSStatusScreen = CSStatusForm(self) - self.PpmacCSStatusScreen = PpmacCSStatusForm(self) - self.GlobalStatusScreen = GlobalStatusForm(self) - self.PpmacGlobalStatusScreen = PpmacGlobalStatusForm(self) - self.axisSettingsScreen = Axissettingsform( - self, self.currentMotor, self.macroAxisStartIndex - ) - self.ppmacaxisSettingsScreen = PpmacAxissettingsform(self, self.currentMotor) - self.pmacgatherScreen = PmacGatherform(self, self.currentMotor) - self.ppmacgatherScreen = PpmacGatherform(self, self.currentMotor) - self.watchesScreen = Watchesform(self) - self.login = Loginform(self, self.username, self.password) - # self.energiseScreen = Energiseform(self.pmac,self) - self.commsThread = CommsThread(self) - - self.spnJogMotor.setValue(self.currentMotor) - - # a few details for use when downloading pmc file - self.progressEventType = QEvent.User + 1 - self.downloadDoneEventType = QEvent.User + 2 - self.updatesReadyEventType = QEvent.User + 3 - self.progressDialog = None - self.canceledDownload = False - - self.table.setColumnWidth(3, 40) - self.table.setColumnWidth(4, 40) - self.table.cellDoubleClicked.connect(self.chooseMotorFromTable) - - self.commands = [] - self.commands_i = 0 - self.lneSend.keyPressEvent = types.MethodType(self.checkHistory, self.lneSend) - self.dirname = "." - - self.lblIdentity.setText("") - self.txtShell.clear() - - def useTerminalServerConnection(self): - if self.ConnectionType != 0: - self.ConnectionType = 0 - # set the server and port fields to defaults for this connection - # type - self.lneServer.setText("blxxi-nt-tserv-01") - self.lnePort.setText("7017") - self.textLabel1.setText("Server:") - self.textLabel2.setText("Port:") - self.lblPolling.setText("Polling") - self.lnePollRate.setEnabled(False) - self.lblPollRate.setEnabled(False) - - def useSocketConnection(self): - if self.ConnectionType != 1: - self.ConnectionType = 1 - # set the server and port fields to defaults for this connection - # type - self.lneServer.setText("172.23.240.97") - self.lnePort.setText("1025") - self.textLabel1.setText("IP address:") - self.textLabel2.setText("Port:") - self.lblPolling.setText("Polling") - self.lnePollRate.setEnabled(False) - self.lblPollRate.setEnabled(False) - - def useSerial(self): - if self.ConnectionType != 2: - self.ConnectionType = 2 - self.isUsingSerial = False - # set the server and port fields to defaults for this connection - # type - self.lneServer.setText("/dev/ttyUSB0") - self.lnePort.setText("38400") - self.textLabel1.setText("COM port:") - self.textLabel2.setText("Baudrate:") - self.lblPolling.setText("Polling @") - self.lnePollRate.setEnabled(True) - self.lnePollRate.setText("0") - self.lblPollRate.setEnabled(True) - - def useSshConnection(self): - if self.ConnectionType != 3: - self.ConnectionType = 3 - # set the server and port fields to defaults for this connection - # type - self.lneServer.setText("172.23.240.97") - self.lnePort.setText("22") - self.textLabel1.setText("IP address:") - self.textLabel2.setText("Port:") - # self.textLabel3.setText("Username:") - # self.textLabel4.setText("Password:") - self.lblPolling.setText("Polling") - self.lnePollRate.setEnabled(False) - self.lblPollRate.setEnabled(False) - - def checkHistory(self, edit, event): - if event.key() == Qt.Key_Up: - if len(self.commands) == 0: - self.commands_i = 0 - self.lneSend.setText("") - elif self.commands_i > -len(self.commands): - self.commands_i -= 1 - self.lneSend.setText(self.commands[self.commands_i]) - else: - self.lneSend.setText(self.commands[self.commands_i]) - elif event.key() == Qt.Key_Down: - if self.commands_i >= -1: - self.commands_i = 0 - self.lneSend.setText("") - else: - self.commands_i += 1 - self.lneSend.setText(self.commands[self.commands_i]) - QLineEdit.keyPressEvent(edit, event) - - def remoteConnect(self): - # Create a remote PMAC interface, of the correct type, depending on - # radio-box selection in the "Connection to PMAC" section - if self.ConnectionType == 0: - self.pmac = PmacTelnetInterface( - self, - verbose=self.verboseMode, - numAxes=self.nAxes, - timeout=self.connectionTimeout, - ) - elif self.ConnectionType == 1: - self.pmac = PmacEthernetInterface( - self, - verbose=self.verboseMode, - numAxes=self.nAxes, - timeout=self.connectionTimeout, - ) - elif self.ConnectionType == 2: - try: - pollrate = float(self.lnePollRate.text()) - except ValueError: - pollrate = False - self.commsThread.max_pollrate = pollrate - self.pmac = PmacSerialInterface( - self, - verbose=self.verboseMode, - numAxes=self.nAxes, - timeout=self.connectionTimeout, - ) - elif self.ConnectionType == 3: - self.pmac = PPmacSshInterface( - self, - verbose=self.verboseMode, - numAxes=self.nAxes, - timeout=self.connectionTimeout, - ) - - # Set the server name and port - server_name = self.lneServer.text() - server_port = self.lnePort.text() - self.pmac.setConnectionParams(server_name, server_port) - self.txtShell.append(f"Connecting to {server_name} {server_port}") - - # Connect to the interface/PMAC - # Show login window if ssh connection - if self.ConnectionType == 3: - # use exec instead of show to wait until login is done - is_clickedOK = self.login.exec() - if not is_clickedOK: - return - else: - # try to connect again - connection_status = self.pmac.connect( - username=self.login.username, password=self.login.password - ) - if connection_status: - QMessageBox.information(self, "Error", connection_status) - return - else: - connection_status = self.pmac.connect() - - if connection_status: - QMessageBox.information(self, "Error", connection_status) - return - - # Find out the type of the PMAC - pmac_model_str = self.pmac.getPmacModel() - if pmac_model_str: - self.setWindowTitle("Delta Tau motor controller - %s" % pmac_model_str) - else: - QMessageBox.information(self, "Error", "Could not determine PMAC model") - return - - self.table.setRowCount(self.pmac.getNumberOfAxes()) - self.spnJogMotor.setMaximum(self.pmac.getNumberOfAxes()) - - self.btnConnect.setEnabled(False) - self.lneServer.setEnabled(False) - self.lnePort.setEnabled(False) - self.btnGroupProtocol.setEnabled(False) - self.btnDisconnect.setEnabled(True) - self.btnJogNeg.setEnabled(True) - self.btnJogPos.setEnabled(True) - self.btnJogStop.setEnabled(True) - self.btnHome.setEnabled(True) - self.lneSend.setEnabled(True) - self.btnSend.setEnabled(True) - self.lneJogTo.setEnabled(True) - self.lneJogDist.setEnabled(True) - self.btnJogTo.setEnabled(True) - self.btnEnergise.setEnabled(False) - # disable energise button for geobrick and power pmac - enableEnergise = ( - not self.pmac.isModelGeobrick() and not self.ConnectionType == 3 - ) - self.btnEnergise.setEnabled(enableEnergise) - self.btnKillAll.setEnabled(True) - self.btnStatus.setEnabled(True) - self.btnCSStatus.setEnabled(True) - self.btnGlobalStatus.setEnabled(True) - self.btnLoadFile.setEnabled(True) - self.btnSettings.setEnabled(True) - self.btnKillMotor.setEnabled(True) - self.chkJogInc.setEnabled(True) - self.btnPollingStatus.setEnabled(True) - self.btnGather.setEnabled(True) - self.btnWatches.setEnabled(True) - self.table.setEnabled(True) - self.lnePollRate.setEnabled(False) - self.lblPollRate.setEnabled(False) - self.pixPolling.setPixmap(self.greenLedOn) - - def remoteDisconnect(self): - # If the PMAC interface has been already defined, make it disconnect - # (this will do nothing if the interface is not connected) - if self.pmac: - self.txtShell.append("Disconnected") - self.pmac.disconnect() - - self.setWindowTitle("Delta Tau motor controller") - self.btnConnect.setEnabled(True) - self.btnDisconnect.setEnabled(False) - self.lneServer.setEnabled(True) - self.lnePort.setEnabled(True) - self.btnGroupProtocol.setEnabled(True) - self.btnJogNeg.setEnabled(False) - self.btnJogPos.setEnabled(False) - self.btnJogStop.setEnabled(False) - self.btnHome.setEnabled(False) - self.lneSend.setEnabled(False) - self.btnSend.setEnabled(False) - self.lneJogTo.setEnabled(False) - self.lneJogDist.setEnabled(False) - self.btnJogTo.setEnabled(False) - self.btnEnergise.setEnabled(False) - self.btnKillAll.setEnabled(False) - self.btnStatus.setEnabled(False) - self.btnCSStatus.setEnabled(False) - self.btnGlobalStatus.setEnabled(False) - self.btnSettings.setEnabled(False) - self.btnKillMotor.setEnabled(False) - self.btnLoadFile.setEnabled(False) - self.chkJogInc.setEnabled(False) - self.btnPollingStatus.setEnabled(False) - self.btnGather.setEnabled(False) - self.btnWatches.setEnabled(False) - self.table.setEnabled(False) - self.pixPolling.setPixmap(self.greenLedOff) - self.lblIdentity.setText("") - - self.axisSettingsScreen.close() - self.ppmacaxisSettingsScreen.close() - self.statusScreen.close() - self.ppmacstatusScreen.close() - self.CSStatusScreen.close() - self.PpmacCSStatusScreen.close() - self.GlobalStatusScreen.close() - self.PpmacGlobalStatusScreen.close() - self.pmacgatherScreen.close() - self.ppmacgatherScreen.close() - self.watchesScreen.clearWatches() - self.watchesScreen.close() - try: - self.energiseScreen.close() - except Exception: - pass - - def jogNeg(self): - (command, retStr, retStatus) = self.pmac.jogInc( - self.currentMotor, "neg", str(self.lneJogDist.text()) - ) - self.addToTxtShell(command, retStr) - - # public slot - def jogPos(self): - (command, retStr, retStatus) = self.pmac.jogInc( - self.currentMotor, "pos", str(self.lneJogDist.text()) - ) - self.addToTxtShell(command, retStr) - - # public slot - - def jogStop(self): - (command, retStr, retStatus) = self.pmac.jogStop(self.currentMotor) - self.addToTxtShell(command, retStr) - - # public slot - - def jogHome(self): - (command, retStr, retStatus) = self.pmac.homeCommand(self.currentMotor) - self.addToTxtShell(command, retStr) - - # public slot - - def jogGoToPosition(self): - (command, retStr, retStatus) = self.pmac.jogTo( - self.currentMotor, self.lneJogTo.text() - ) - self.addToTxtShell(command, retStr) - - # public slot - def jogChangeMotor(self, newMotor): - self.currentMotor = newMotor - self.statusScreen.changeAxis(self.currentMotor) - self.ppmacstatusScreen.changeAxis(self.currentMotor) - self.axisSettingsScreen.changeAxis(self.currentMotor) - self.ppmacaxisSettingsScreen.changeAxis(self.currentMotor) - - # Send a #Xk command to kill the current motor. - def killMotor(self): - command = "#%dk" % self.currentMotor - (returnString, status) = self.pmac.sendCommand(command) - self.addToTxtShell(command) - - # Send a (ASCII 0x0B) command to the PMAC to kill all motion - # all servo loops will be opened and amplifier enable set false. - # see TURBO SRM page 289 - def killAllMotors(self): - # print "killing all motors!" - command = "\x0B" - (returnString, status) = self.pmac.sendCommand(command) - self.addToTxtShell("CTRL-K") - - def dataGather(self): - # if power pmac - # if self.ConnectionType == 3: - if isinstance(self.pmac, PPmacSshInterface): - self.ppmacgatherScreen.show() - else: - self.pmacgatherScreen.show() - - # public slot - def watches(self): - self.watchesScreen.show() - - def pmacEnergiseAxis(self): - self.energiseScreen = Energiseform(self.pmac, self) - self.energiseScreen.show() - - def statusScreen(self): - # if power pmac - if isinstance(self.pmac, PPmacSshInterface): - self.ppmacstatusScreen.show() - else: - self.statusScreen.show() - - def CSStatusScreen(self): - # if power pmac - if isinstance(self.pmac, PPmacSshInterface): - self.PpmacCSStatusScreen.show() - else: - self.CSStatusScreen.show() - - def GlobalStatusScreen(self): - # if power pmac - if isinstance(self.pmac, PPmacSshInterface): - self.PpmacGlobalStatusScreen.show() - else: - self.GlobalStatusScreen.show() - - # public slot - def jogParameters(self): - if isinstance(self.pmac, PPmacSshInterface): - self.ppmacaxisSettingsScreen.show() - self.ppmacaxisSettingsScreen.axisUpdate() - else: - self.axisSettingsScreen.show() - self.axisSettingsScreen.axisUpdate() - - # Download a pmc configuration file to the PMAC - def pmacLoadConfig(self): - # First get the file from a file dialog - myDialog = QFileDialog(self) - q_file = myDialog.getOpenFileName( - self, "Load PMC file", self.dirname, "PMAC configuration (*.pmc *.PMC)" - ) - fileName, _ = q_file - if not fileName: - return - self.dirname = path.dirname(str(fileName)) - - # A couple of regular expressions for use in parsing the pmc file - blankLine = re.compile(r"^\s*$") # match blank lines - - # parsing through the file - pmc = ClsPmacParser() - pmcLines = pmc.parse(fileName) - - if pmcLines: - # Get rid of all the empty lines, but keep line numbers - commands = [] - for i, pmcLine in enumerate(pmcLines): - if not blankLine.match(pmcLine): - commands.append((i + 1, pmcLine)) - - # Prepend two close commands and a delete gather to the front of - # any pmc file uploaded. This ensures that any open PLC buffers - # are closed before an upload and that the gather buffer is - # erased to make memory available for the new PLC. Two close - # commands are sent to ensure that we leave any nested statements - # (first close) before then closing the buffer (second close). - # Dummy line numbers of zero are paired with each command to - # match the formatting and to not disrupt the real line numbering - closeCommands = [(0, "CLOSE"), (0, "CLOSE"), (0, "DELETE GATHER")] - commands = closeCommands + commands - - # Open up progress dialog and start sending the commands. - self.canceledDownload = False - self.progressDialog = QProgressDialog( - "Downloading PMAC configuration", "cancel", 0, len(pmcLines), self - ) - self.progressDialog.setWindowModality(Qt.ApplicationModal) - self.progressDialog.canceled.connect(self.cancel) - self.txtShell.append("Beginning download of pmc file: " + fileName) - self.commsThread.inputQueue.put(("sendSeries", commands)) - - def cancel(self): - self.canceledDownload = True - self.commsThread.inputQueue.put(("cancelSendSeries", "")) - - def pmacPollingStatus(self): - # If we are already polling, disable it - if self.pollingStatus: - self.pollingStatus = False - self.commsThread.inputQueue.put(("disablePollingStatus", True)) - - self.btnPollingStatus.setText("enable polling") - - # Disable all the controls and status displays to indicate that we - # do not have updates available - self.table.setEnabled(False) - self.lblPosition.setEnabled(False) - self.lblVelo.setEnabled(False) - self.lblFolErr.setEnabled(False) - self.pixPolling.setPixmap(self.greenLedOff) - - # else, if we are not polling: start polling! - else: - self.pollingStatus = True - self.commsThread.inputQueue.put(("disablePollingStatus", False)) - self.btnPollingStatus.setText("disable polling") - - # Re-enable all the disabled labels and controls - self.table.setEnabled(True) - self.lblPosition.setEnabled(True) - self.lblVelo.setEnabled(True) - self.lblFolErr.setEnabled(True) - self.pixPolling.setPixmap(self.greenLedOn) - - def jogNegContinousStart(self): - # print "controlform.jogNegContinousStart(): Not implemented yet" - (command, retStr, retStatus) = self.pmac.jogContinous(self.currentMotor, "neg") - self.addToTxtShell(command, retStr) - - # public slot - def jogPosContinousStart(self): - # print "controlform.jogPosContinousStart(): Not implemented yet" - (command, retStr, retStatus) = self.pmac.jogContinous(self.currentMotor, "pos") - self.addToTxtShell(command, retStr) - - # public slot - def sendSingleCommand(self): - # print "controlform.sendSingleCommand(): Not implemented yet" - command = self.lneSend.text() - if len(self.commands) == 0 or self.commands[-1] != command: - self.commands.append(command) - (retStr, status) = self.pmac.sendCommand(command) - self.addToTxtShell(command, retStr, False) - self.commands_i = 0 - self.lneSend.setText("") - - @pyqtSlot(int, int, name="chooseMotorFromTable") - def chooseMotorFromTable(self, a0): - self.spnJogMotor.setValue(a0 + 1) - - # public slot - def jogIncrementally(self, a0): # a0 is True if 'jog inc' box checked - self.lneJogDist.setEnabled(a0) - if a0: - self.btnJogPos.pressed.disconnect(self.jogPosContinousStart) - self.btnJogPos.released.disconnect(self.jogStop) - self.btnJogNeg.pressed.disconnect(self.jogNegContinousStart) - self.btnJogNeg.released.disconnect(self.jogStop) - self.btnJogNeg.clicked.connect(self.jogNeg) - self.btnJogPos.clicked.connect(self.jogPos) - else: - self.btnJogPos.pressed.connect(self.jogPosContinousStart) - self.btnJogPos.released.connect(self.jogStop) - self.btnJogNeg.pressed.connect(self.jogNegContinousStart) - self.btnJogNeg.released.connect(self.jogStop) - self.btnJogNeg.clicked.disconnect(self.jogNeg) - self.btnJogPos.clicked.disconnect(self.jogPos) - - def __item(self, row, col): - item = self.table.item(row, col) - if not item: - item = QTableWidgetItem() - self.table.setItem(row, col, item) - item.setFlags(Qt.ItemIsEnabled) - return item - - def addToTxtShell(self, command, retStr=None, chkShowAll=True): - if chkShowAll is False or self.chkShowAll.isChecked(): - self.txtShell.append(command) - if retStr is not None: - self.txtShell.append( - retStr.rstrip("\x06").lstrip("\x07").replace("\r", " ") - ) - - # Called when an event comes out of the polling thread - # and the jog ribbon. - def updateMotors(self): - under_voltage = False - over_voltage = False - over_temperature = False - - self.commsThread.resultQueue.qsize() - for _queItem in range(0, self.commsThread.resultQueue.qsize()): - try: - value = self.commsThread.resultQueue.get(False) - except Empty: - return - - try: - motorRow = value[6] - # check for special cases - if isinstance(motorRow, str): - if isinstance(self.pmac, PPmacSshInterface): - if motorRow == "G": - self.PpmacGlobalStatusScreen.updateStatus( - int(value[0].strip("$"), 16) - ) - continue - if motorRow.startswith("CS"): - self.PpmacCSStatusScreen.updateStatus( - int(value[0].strip("$"), 16) - ) - continue - if motorRow.startswith("FEED"): - self.PpmacCSStatusScreen.updateFeed( - int(round(float(value[0]))) - ) - continue - if motorRow == "IDENT": - self.updateIdentity(int(value[0])) - continue - if motorRow == "UVOL": - if int(value[0]) != 0: - under_voltage = True - continue - if motorRow == "OVOL": - if int(value[0]) != 0: - over_voltage = True - continue - if motorRow == "OTEMP": - if int(value[0]) != 0: - over_temperature = True - continue - else: - if motorRow == "G": - self.GlobalStatusScreen.updateStatus(int(value[0], 16)) - continue - if motorRow.startswith("CS"): - self.CSStatusScreen.updateStatus(int(value[0], 16)) - continue - if motorRow.startswith("FEED"): - self.CSStatusScreen.updateFeed(int(round(float(value[0])))) - continue - if motorRow == "IDENT": - self.updateIdentity(int(value[0])) - continue - - else: - position = str(round(float(value[1]), 1)) - velocity = str(round(float(value[2]), 1)) - folerr = str(round(float(value[3]), 1)) - - i2t_fault = False - over_current = False - - if motorRow < 8: - if isinstance(self.pmac, PPmacSshInterface): - if int(value[4]) > 0: - i2t_fault = True - if int(value[5]) > 0: - over_current = True - elif isinstance(self.pmac, PmacEthernetInterface): - amp_status = (int(value[4]) & 448) >> 6 - if amp_status == 5: - i2t_fault = True - elif amp_status == 6: - over_current = True - if motorRow < 4: - if amp_status == 2: - under_voltage = True - elif amp_status == 3: - over_temperature = True - elif amp_status == 4: - over_voltage = True - - self.__item(motorRow, 0).setText(position) - self.__item(motorRow, 1).setText(velocity) - self.__item(motorRow, 2).setText(folerr) - - statusWord = int(value[0].strip("$"), 16) - - # define high and low limits for power pmac - if isinstance(self.pmac, PPmacSshInterface): - loLim = bool(statusWord & 0x2000000000000000) # MinusLimit - hiLim = bool(statusWord & 0x1000000000000000) # PlusLimit - loLimSoft = bool( - statusWord & 0x0080000000000000 - ) # SoftMinusLimit - hiLimSoft = bool( - statusWord & 0x0040000000000000 - ) # SoftPlusLimit - - # define high and low limits for pmac - else: - loLim = bool( - statusWord & 0x400000000000 - ) # negative end limit set - hiLim = bool( - statusWord & 0x200000000000 - ) # positive end limit set - loLimSoft = False - hiLimSoft = False - - # set limit indicators in polling table - if hiLim: - self.__item(motorRow, 3).setIcon(QIcon(self.redLedOn)) - elif hiLimSoft: - self.__item(motorRow, 3).setIcon(QIcon(self.amberLedOn)) - else: - self.__item(motorRow, 3).setIcon(QIcon(self.redLedOff)) - if loLim: - self.__item(motorRow, 4).setIcon(QIcon(self.redLedOn)) - elif loLimSoft: - self.__item(motorRow, 4).setIcon(QIcon(self.amberLedOn)) - else: - self.__item(motorRow, 4).setIcon(QIcon(self.redLedOff)) - - # set amplifier status indicators in polling table - if i2t_fault: - self.__item(motorRow, 5).setIcon(QIcon(self.redLedOn)) - else: - self.__item(motorRow, 5).setIcon(QIcon(self.redLedOff)) - if over_current: - self.__item(motorRow, 6).setIcon(QIcon(self.redLedOn)) - else: - self.__item(motorRow, 6).setIcon(QIcon(self.redLedOff)) - - # Update also the jog ribbon - if motorRow + 1 == self.currentMotor: - self.lblPosition.setText(position) - self.lblVelo.setText(velocity) - self.lblFolErr.setText(folerr) - if hiLim: - self.pixHiLim.setPixmap(self.redLedOn) - elif hiLimSoft: - self.pixHiLim.setPixmap(self.amberLedOn) - else: - self.pixHiLim.setPixmap(self.redLedOff) - if loLim: - self.pixLoLim.setPixmap(self.redLedOn) - elif loLimSoft: - self.pixLoLim.setPixmap(self.amberLedOn) - else: - self.pixLoLim.setPixmap(self.redLedOff) - self.statusScreen.updateStatus(statusWord) - self.ppmacstatusScreen.updateStatus(statusWord) - - # set controller status indicators on main window - if under_voltage: - self.pixUnderVoltage.setPixmap(self.redLedOn) - else: - self.pixUnderVoltage.setPixmap(self.redLedOff) - if over_voltage: - self.pixOverVoltage.setPixmap(self.redLedOn) - else: - self.pixOverVoltage.setPixmap(self.redLedOff) - if over_temperature: - self.pixOverTemperature.setPixmap(self.redLedOn) - else: - self.pixOverTemperature.setPixmap(self.redLedOff) - - except (ValueError, IndexError): - # Catch the exception and continue, since there may be other - # updates waiting in the queue. - if self.verboseMode: - print("Update request received invalid response: ", value) - - domainNames = [ - "BL", - "BR", - "BS", - "FE", - "LB", - "LI", - "ME", - "SR", - "LA", - "TBD", - "TBD", - "TBD", - "TBD", - "TBD", - "TBD", - "RSV", - ] - subdomainLetters = [ - ["I", "B", "J", "C", "K", "D", "L", "E"], - ["C", "S", "", "", "", "", "", ""], - ["", "", "", "", "", "", "", ""], - ["I", "B", "J", "C", "K", "D", "L", "E"], - ["", "", "", "", "", "", "", ""], - ["", "", "", "", "", "", "", ""], - ["D", "P", "C", "T", "M", "G", "", ""], - ["I", "A", "J", "C", "K", "R", "L", "S"], - ["R", "", "", "", "", "", "", ""], - ["", "", "", "", "", "", "", ""], - ["", "", "", "", "", "", "", ""], - ["", "", "", "", "", "", "", ""], - ["", "", "", "", "", "", "", ""], - ["", "", "", "", "", "", "", ""], - ["", "", "", "", "", "", "", ""], - ["", "", "", "", "", "", "", ""], - ] - - def updateIdentity(self, id): - if not self.btnConnect.isEnabled(): - if id == 0: - text = "Identity not set" - else: - domain = (id >> 20) & 0x0F - # swVersion = (id >> 13) & 0x7F - subdomainNum = (id >> 7) & 0x1F - pmacNum = id & 0x1F - subdomainLetter = ( - ((id >> 6) & 0x01) | ((id >> 4) & 0x02) | ((id >> 10) & 0x04) - ) - text = self.domainNames[domain] - if subdomainNum != 0: - text += "%02d" % subdomainNum - text += self.subdomainLetters[domain][subdomainLetter] - text += " %s " % self.pmac.getShortModelName() - text += "%d" % pmacNum - self.lblIdentity.setText(text) - - def updateWatches(self): - self.commsThread.watchesQueue.qsize() - for _queItem in range(0, self.commsThread.watchesQueue.qsize()): - try: - value = self.commsThread.watchesQueue.get(False) - except Empty: - return - for n in range(len(value)): - if "." in value[n]: - value[n] = round(float(value[n]), 1) - self.watchesScreen.table.setItem(n, 1, QTableWidgetItem(str(value[n]))) - - def customEvent(self, E): - if E.type() == self.progressEventType: - (lines, err) = E.data() - self.progressDialog.setValue(lines) - if err: - self.txtShell.append(err) - elif E.type() == self.downloadDoneEventType: - self.progressDialog.setValue(self.progressDialog.maximum()) - self.txtShell.append(str(E.data())) - elif E.type() == self.updatesReadyEventType: - self.updateMotors() - self.updateWatches() - - def signalHandler(self, signum, frame): - if signum == 2: # SIGINT - print("Closing connection...") - self.pmac.disconnect() - print("Closing application.") - QApplication.exit(0) - - def die(self): - self.remoteDisconnect() - self.commsThread.inputQueue.put(("die", "")) - - -# Main function in the pmaccontrol application. -def main(): - usage = """usage: %prog [options] -%prog is a graphical frontend to the Deltatau motorcontroller known as PMAC.""" - parser = OptionParser(usage) - parser.add_option( - "-v", - "--verbose", - action="store_true", - dest="verbose", - default=False, - help="Print more details (than necessary in most " "cases...)", - ) - parser.add_option( - "-o", - "--protocol", - action="store", - dest="protocol", - default="ts", - help='Set the connection protocol; use "ts" for ' - "serial via terminal server (the default), " - 'or "tcpip" for network TCP/IP connection.', - ) - parser.add_option( - "-s", - "--server", - action="store", - dest="server", - default="blxxi-nt-tserv-01", - help="Set server name (default: blxxi-nt-tserv-01)", - ) - parser.add_option( - "-p", - "--port", - action="store", - dest="port", - default="7017", - help="Set IP port number to connect to (default: 7017)", - ) - parser.add_option( - "--username", - action="store", - dest="username", - default="root", - help="Set the SSH username (default: root)", - ) - parser.add_option( - "--password", - action="store", - dest="password", - default="deltatau", - help="Set the SSH password (default: deltatau)", - ) - parser.add_option( - "-a", - "--axis", - action="store", - dest="defaultAxis", - default=1, - help="Set an axis as a default selected axis when " - "starting up the application (default: 1)", - ) - parser.add_option( - "-m", - "--macroAxisStartIndex", - action="store", - dest="macroAxisStartIndex", - default=0, - help="Set the first macro axis (default: 0)", - ) - parser.add_option( - "-n", - "--naxes", - action="store", - dest="nAxes", - help="Display and poll NAXES axes. Default is 32 for a " - "PMAC, 8 for a geoBrick", - ) - parser.add_option( - "-t", - "--timeout", - action="store", - type="float", - dest="timeout", - default=3.0, - help="Set the communication timeout (default: 3 seconds, " "minimum: 1 second)", - ) - parser.add_option( - "--version", - action="store_true", - help="get the version of dls-pmac-control", - ) - (options, args) = parser.parse_args() - - if options.version: - print(__version__) - exit(0) - - app = QApplication(sys.argv) - app.lastWindowClosed.connect(app.quit) - win = Controlform(options) - app.aboutToQuit.connect(win.die) - win.show() - win.splitter.moveSplitter(180, 1) - # catch CTRL-C - signal.signal(signal.SIGINT, signal.SIG_DFL) - app.exec_() - - -if __name__ == "__main__": - main() diff --git a/src/dls_pmac_control/re b/src/dls_pmac_control/re new file mode 100644 index 0000000..e69de29 diff --git a/src/dls_pmac_control/signal b/src/dls_pmac_control/signal new file mode 100644 index 0000000..e69de29 diff --git a/src/dls_pmac_control/sys b/src/dls_pmac_control/sys new file mode 100644 index 0000000..e69de29 diff --git a/src/dls_pmac_control/types b/src/dls_pmac_control/types new file mode 100644 index 0000000..e69de29 diff --git a/tests/test_motor.py b/tests/test_motor.py index 524e99c..d6264bb 100644 --- a/tests/test_motor.py +++ b/tests/test_motor.py @@ -5,7 +5,7 @@ from PyQt5.QtCore import Qt from PyQt5.QtTest import QTest -from dls_pmac_control.motor import Controlform +from dls_pmac_control.__main__ import Controlform class DummyTestOptionsTelnet: @@ -350,7 +350,7 @@ def test_remote_disconnect(self, mock_disconnect, mock_pixmap): mock_pixmap.assert_called_with(self.obj.greenLedOff) assert self.obj.lblIdentity.text() == "" - @patch("dls_pmac_control.motor.Controlform.addToTxtShell") + @patch("dls_pmac_control.__main__.Controlform.addToTxtShell") @patch("dls_pmaclib.dls_pmacremote.PmacTelnetInterface.jogInc") def test_jog_neg(self, mock_joginc, mock_addtxt): mock_joginc.return_value = ("cmd", "response", True) @@ -359,7 +359,7 @@ def test_jog_neg(self, mock_joginc, mock_addtxt): self.obj.currentMotor, "neg", str(self.obj.lneJogDist.text()) ) - @patch("dls_pmac_control.motor.Controlform.addToTxtShell") + @patch("dls_pmac_control.__main__.Controlform.addToTxtShell") @patch("dls_pmaclib.dls_pmacremote.PmacTelnetInterface.jogInc") def test_jog_pos(self, mock_joginc, mock_addtxt): mock_joginc.return_value = ("cmd", "response", True) @@ -368,14 +368,14 @@ def test_jog_pos(self, mock_joginc, mock_addtxt): self.obj.currentMotor, "pos", str(self.obj.lneJogDist.text()) ) - @patch("dls_pmac_control.motor.Controlform.addToTxtShell") + @patch("dls_pmac_control.__main__.Controlform.addToTxtShell") @patch("dls_pmaclib.dls_pmacremote.PmacTelnetInterface.jogStop") def test_jog_stop(self, mock_jogstop, mock_addtxt): mock_jogstop.return_value = ("cmd", "response", True) assert self.obj.jogStop() is None mock_jogstop.assert_called_with(self.obj.currentMotor) - @patch("dls_pmac_control.motor.Controlform.addToTxtShell") + @patch("dls_pmac_control.__main__.Controlform.addToTxtShell") @patch("dls_pmaclib.dls_pmacremote.PmacTelnetInterface.homeCommand") def test_jog_home(self, mock_home, mock_addtxt): mock_home.return_value = ("cmd", "response", True) From a10d6a2d6d29c6bff37b837c9c2af7b4b00d1f2b Mon Sep 17 00:00:00 2001 From: Giles Knap Date: Sun, 11 Feb 2024 22:22:57 +0000 Subject: [PATCH 31/36] fix issues with QT_QPA_PLATFORM --- .devcontainer/Dockerfile | 36 ------------------------------------ .github/workflows/_test.yml | 2 ++ Dockerfile | 2 -- pyproject.toml | 2 +- 4 files changed, 3 insertions(+), 39 deletions(-) delete mode 100644 .devcontainer/Dockerfile diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile deleted file mode 100644 index 83d928f..0000000 --- a/.devcontainer/Dockerfile +++ /dev/null @@ -1,36 +0,0 @@ -# ideas from https://www.docker.com/blog/containerized-python-development-part-1/ - -# This file is for use as a .vscode devcontainer as well as a runtime -# container. The devcontainer should be rootful and use podman or docker -# with user namespaces. - -ARG BASE="mcr.microsoft.com/vscode/devcontainers/python:0-3.10-bullseye" -FROM ${BASE} as base - -# use root to pin where the packages will install -USER root -ENV PATH=/root/.local/bin:$PATH - -# things to make pyQt5 work -RUN apt-get update && export DEBIAN_FRONTEND=noninteractive && \ - apt-get install -y --no-install-recommends \ - libqt5gui5 libxcb-xinerama0 && \ - rm -rf /var/lib/apt/lists/* - -ENV XDG_RUNTIME_DIR=/tmp/runtime-vscode - -FROM base as developer - -WORKDIR /workspace -COPY . . - -# install runtime from DIST if there is one -RUN mkdir -p /root/.local && \ - test -d dist && \ - requirements=$(test -f requirements.txt && echo -r requirements.txt) \ - pip install --user $requirements dist/*.whl || : - -FROM base as runtime -COPY --from=developer /root/.local /root/.local - -ENTRYPOINT ["dls-pmac-control"] diff --git a/.github/workflows/_test.yml b/.github/workflows/_test.yml index 9b1f21f..de736fc 100644 --- a/.github/workflows/_test.yml +++ b/.github/workflows/_test.yml @@ -16,6 +16,8 @@ on: env: # https://github.com/pytest-dev/pytest/issues/2042 PY_IGNORE_IMPORTMISMATCH: "1" + # allow tests to run headless + ENV QT_QPA_PLATFORM: offscreen jobs: run: diff --git a/Dockerfile b/Dockerfile index 5e34e5e..de52c8e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -13,8 +13,6 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ RUN python -m venv /venv ENV PATH=/venv/bin:$PATH -# allow tests to run headless in the dev container -ENV QT_QPA_PLATFORM=offscreen ENV XDG_RUNTIME_DIR=/tmp/runtime-vscode # The build stage installs the context into the venv diff --git a/pyproject.toml b/pyproject.toml index 3d6cb2d..16f15aa 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -40,7 +40,7 @@ dev = [ ] [project.scripts] -dls-pmac-control = "dls_pmac_control.motor:main" +dls-pmac-control = "dls_pmac_control.__main__:main" [project.urls] GitHub = "https://github.com/DiamondLightSource/dls-pmac-control" From 11d8ae2c94d903e5d1f4f447cb2aaa1e31e1a847 Mon Sep 17 00:00:00 2001 From: Giles Knap Date: Mon, 12 Feb 2024 07:17:40 +0000 Subject: [PATCH 32/36] add QT_QPA_PLATFORM to tests --- .github/workflows/_test.yml | 1 - Dockerfile | 6 ++++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/.github/workflows/_test.yml b/.github/workflows/_test.yml index de736fc..5bacee1 100644 --- a/.github/workflows/_test.yml +++ b/.github/workflows/_test.yml @@ -16,7 +16,6 @@ on: env: # https://github.com/pytest-dev/pytest/issues/2042 PY_IGNORE_IMPORTMISMATCH: "1" - # allow tests to run headless ENV QT_QPA_PLATFORM: offscreen jobs: diff --git a/Dockerfile b/Dockerfile index de52c8e..9fdf561 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,14 +1,16 @@ # The devcontainer should use the developer target and run as root with podman # or docker with user namespaces. ARG PYTHON_VERSION=3.11 -FROM python:${PYTHON_VERSION} as developer +FROM python:${PYTHON_VERSION} as system -# Add any system dependencies for the developer/build environment here +# Add any system dependencies for developer and runtime targets RUN apt-get update && apt-get install -y --no-install-recommends \ graphviz \ libqt5gui5 libxcb-xinerama0 \ && rm -rf /var/lib/apt/lists/* +FROM system as developer + # Set up a virtual environment and put it in PATH RUN python -m venv /venv ENV PATH=/venv/bin:$PATH From 90a4ff855311632a60c3d07049ca7399307e9d7e Mon Sep 17 00:00:00 2001 From: Giles Knap Date: Mon, 12 Feb 2024 07:33:29 +0000 Subject: [PATCH 33/36] fix Dockerfile runtime --- .dockerignore | 3 +++ .github/workflows/_test.yml | 2 +- Dockerfile | 14 +++++++++----- 3 files changed, 13 insertions(+), 6 deletions(-) create mode 100644 .dockerignore diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..1f491d4 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,3 @@ +Dockerfile +README.md +tests\** diff --git a/.github/workflows/_test.yml b/.github/workflows/_test.yml index 5bacee1..636dd61 100644 --- a/.github/workflows/_test.yml +++ b/.github/workflows/_test.yml @@ -16,7 +16,7 @@ on: env: # https://github.com/pytest-dev/pytest/issues/2042 PY_IGNORE_IMPORTMISMATCH: "1" - ENV QT_QPA_PLATFORM: offscreen + QT_QPA_PLATFORM: offscreen jobs: run: diff --git a/Dockerfile b/Dockerfile index 9fdf561..66a6fbe 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,16 +1,15 @@ # The devcontainer should use the developer target and run as root with podman # or docker with user namespaces. ARG PYTHON_VERSION=3.11 -FROM python:${PYTHON_VERSION} as system +FROM python:${PYTHON_VERSION} as developer -# Add any system dependencies for developer and runtime targets +# Add any system dependencies for the developer/build environment here RUN apt-get update && apt-get install -y --no-install-recommends \ graphviz \ + libglib2.0-0 \ libqt5gui5 libxcb-xinerama0 \ && rm -rf /var/lib/apt/lists/* -FROM system as developer - # Set up a virtual environment and put it in PATH RUN python -m venv /venv ENV PATH=/venv/bin:$PATH @@ -25,11 +24,16 @@ RUN pip install . # The runtime stage copies the built venv into a slim runtime container FROM python:${PYTHON_VERSION}-slim as runtime + # Add apt-get system dependecies for runtime here if needed +RUN apt-get update && apt-get install -y --no-install-recommends \ + libqt5gui5 libxcb-xinerama0 \ + && rm -rf /var/lib/apt/lists/* + COPY --from=build /venv/ /venv/ ENV PATH=/venv/bin:$PATH # change this entrypoint if it is not the same as the repo ENTRYPOINT ["dls-pmac-control"] -CMD ["--version"] + From c29e59e102bbac3d0ad08de91b969833987e90bb Mon Sep 17 00:00:00 2001 From: Giles Knap Date: Mon, 12 Feb 2024 07:48:07 +0000 Subject: [PATCH 34/36] fix pypi trusted publishing --- .github/workflows/_pypi.yml | 5 ----- 1 file changed, 5 deletions(-) diff --git a/.github/workflows/_pypi.yml b/.github/workflows/_pypi.yml index f2ead1b..0c5258d 100644 --- a/.github/workflows/_pypi.yml +++ b/.github/workflows/_pypi.yml @@ -1,8 +1,5 @@ on: workflow_call: - secrets: - PYPI_TOKEN: - required: true jobs: upload: @@ -18,5 +15,3 @@ jobs: - name: Publish to PyPI using trusted publishing uses: pypa/gh-action-pypi-publish@release/v1 - with: - password: ${{ secrets.PYPI_TOKEN }} From 4287625f0c05d3c8c4193c3f1fb3ad3ede20b0ef Mon Sep 17 00:00:00 2001 From: Giles Knap Date: Mon, 12 Feb 2024 10:59:46 +0000 Subject: [PATCH 35/36] set XDG_RUNTIME_DIR in runtime container --- Dockerfile | 1 + 1 file changed, 1 insertion(+) diff --git a/Dockerfile b/Dockerfile index 66a6fbe..65deab6 100644 --- a/Dockerfile +++ b/Dockerfile @@ -32,6 +32,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ COPY --from=build /venv/ /venv/ ENV PATH=/venv/bin:$PATH +ENV XDG_RUNTIME_DIR=/tmp/runtime-:$USER # change this entrypoint if it is not the same as the repo ENTRYPOINT ["dls-pmac-control"] From 1c6b7ff082aeffb2c7a98cb00d22e336ab2b42a6 Mon Sep 17 00:00:00 2001 From: Giles Knap Date: Mon, 12 Feb 2024 11:04:12 +0000 Subject: [PATCH 36/36] remove redundant TOKEN ref --- .github/workflows/ci.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1f69047..258d8a9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -57,8 +57,6 @@ jobs: uses: ./.github/workflows/_pypi.yml permissions: id-token: write - secrets: - PYPI_TOKEN: ${{ secrets.PYPI_TOKEN }} release: if: github.ref_type == 'tag'