src/eric7/MicroPython/MicroPythonWidget.py

branch
eric7
changeset 9221
bf71ee032bb4
parent 9209
b99e7fd55fd3
child 9413
80c06d472826
--- a/src/eric7/MicroPython/MicroPythonWidget.py	Wed Jul 13 11:16:20 2022 +0200
+++ b/src/eric7/MicroPython/MicroPythonWidget.py	Wed Jul 13 14:55:47 2022 +0200
@@ -15,8 +15,15 @@
 from PyQt6.QtCore import pyqtSlot, pyqtSignal, Qt, QPoint, QEvent
 from PyQt6.QtGui import QColor, QKeySequence, QTextCursor, QBrush, QClipboard
 from PyQt6.QtWidgets import (
-    QWidget, QMenu, QApplication, QHBoxLayout, QSpacerItem, QSizePolicy,
-    QTextEdit, QToolButton, QDialog
+    QWidget,
+    QMenu,
+    QApplication,
+    QHBoxLayout,
+    QSpacerItem,
+    QSizePolicy,
+    QTextEdit,
+    QToolButton,
+    QDialog,
 )
 
 from EricWidgets.EricZoomWidget import EricZoomWidget
@@ -29,14 +36,18 @@
 
 from . import MicroPythonDevices
 from . import UF2FlashDialog
+
 try:
     from .MicroPythonGraphWidget import MicroPythonGraphWidget
+
     HAS_QTCHART = True
 except ImportError:
     HAS_QTCHART = False
 from .MicroPythonFileManagerWidget import MicroPythonFileManagerWidget
+
 try:
     from .MicroPythonCommandsInterface import MicroPythonCommandsInterface
+
     HAS_QTSERIALPORT = True
 except ImportError:
     HAS_QTSERIALPORT = False
@@ -182,92 +193,90 @@
 class MicroPythonWidget(QWidget, Ui_MicroPythonWidget):
     """
     Class implementing the MicroPython REPL widget.
-    
+
     @signal dataReceived(data) emitted to send data received via the serial
         connection for further processing
     """
+
     ZoomMin = -10
     ZoomMax = 20
-    
+
     DeviceTypeRole = Qt.ItemDataRole.UserRole
     DeviceBoardRole = Qt.ItemDataRole.UserRole + 1
     DevicePortRole = Qt.ItemDataRole.UserRole + 2
     DeviceVidRole = Qt.ItemDataRole.UserRole + 3
     DevicePidRole = Qt.ItemDataRole.UserRole + 4
-    
+
     dataReceived = pyqtSignal(bytes)
-    
+
     ManualMarker = "<manual>"
-    
+
     def __init__(self, parent=None):
         """
         Constructor
-        
+
         @param parent reference to the parent widget
         @type QWidget
         """
         super().__init__(parent)
         self.setupUi(self)
-        
+
         self.layout().setContentsMargins(0, 3, 0, 0)
-        
+
         self.__ui = parent
-        
+
         self.__superMenu = QMenu(self)
         self.__superMenu.aboutToShow.connect(self.__aboutToShowSuperMenu)
-        
-        self.menuButton.setObjectName(
-            "micropython_supermenu_button")
+
+        self.menuButton.setObjectName("micropython_supermenu_button")
         self.menuButton.setIcon(UI.PixmapCache.getIcon("superMenu"))
         self.menuButton.setToolTip(self.tr("MicroPython Menu"))
-        self.menuButton.setPopupMode(
-            QToolButton.ToolButtonPopupMode.InstantPopup)
-        self.menuButton.setToolButtonStyle(
-            Qt.ToolButtonStyle.ToolButtonIconOnly)
+        self.menuButton.setPopupMode(QToolButton.ToolButtonPopupMode.InstantPopup)
+        self.menuButton.setToolButtonStyle(Qt.ToolButtonStyle.ToolButtonIconOnly)
         self.menuButton.setFocusPolicy(Qt.FocusPolicy.NoFocus)
         self.menuButton.setAutoRaise(True)
         self.menuButton.setShowMenuInside(True)
         self.menuButton.setMenu(self.__superMenu)
-        
-        self.deviceIconLabel.setPixmap(MicroPythonDevices.getDeviceIcon(
-            "", False))
-        
+
+        self.deviceIconLabel.setPixmap(MicroPythonDevices.getDeviceIcon("", False))
+
         self.openButton.setIcon(UI.PixmapCache.getIcon("open"))
         self.saveButton.setIcon(UI.PixmapCache.getIcon("fileSaveAs"))
-        
+
         self.checkButton.setIcon(UI.PixmapCache.getIcon("question"))
         self.runButton.setIcon(UI.PixmapCache.getIcon("start"))
         self.replButton.setIcon(UI.PixmapCache.getIcon("terminal"))
         self.filesButton.setIcon(UI.PixmapCache.getIcon("filemanager"))
         self.chartButton.setIcon(UI.PixmapCache.getIcon("chart"))
         self.connectButton.setIcon(UI.PixmapCache.getIcon("linkConnect"))
-        
+
         self.__zoomLayout = QHBoxLayout()
-        spacerItem = QSpacerItem(40, 20, QSizePolicy.Policy.Expanding,
-                                 QSizePolicy.Policy.Minimum)
+        spacerItem = QSpacerItem(
+            40, 20, QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Minimum
+        )
         self.__zoomLayout.addSpacerItem(spacerItem)
-        
+
         self.__zoom0 = self.replEdit.fontPointSize()
         self.__zoomWidget = EricZoomWidget(
             UI.PixmapCache.getPixmap("zoomOut"),
             UI.PixmapCache.getPixmap("zoomIn"),
-            UI.PixmapCache.getPixmap("zoomReset"), self)
+            UI.PixmapCache.getPixmap("zoomReset"),
+            self,
+        )
         self.__zoomLayout.addWidget(self.__zoomWidget)
-        self.layout().insertLayout(
-            self.layout().count() - 1,
-            self.__zoomLayout)
+        self.layout().insertLayout(self.layout().count() - 1, self.__zoomLayout)
         self.__zoomWidget.setMinimum(self.ZoomMin)
         self.__zoomWidget.setMaximum(self.ZoomMax)
         self.__zoomWidget.valueChanged.connect(self.__doZoom)
         self.__currentZoom = 0
-        
+
         self.__fileManagerWidget = None
         self.__chartWidget = None
-        
+
         self.__unknownPorts = []
         self.__lastPort = None
         self.__lastDeviceType = None
-        
+
         if HAS_QTSERIALPORT:
             self.__interface = MicroPythonCommandsInterface(self)
         else:
@@ -275,229 +284,241 @@
         self.__device = None
         self.__connected = False
         self.__setConnected(False)
-        
+
         if not HAS_QTSERIALPORT:
-            self.replEdit.setHtml(self.tr(
-                "<h3>The QtSerialPort package is not available.<br/>"
-                "MicroPython support is deactivated.</h3>"))
+            self.replEdit.setHtml(
+                self.tr(
+                    "<h3>The QtSerialPort package is not available.<br/>"
+                    "MicroPython support is deactivated.</h3>"
+                )
+            )
             self.setEnabled(False)
             return
-        
+
         self.__vt100Re = re.compile(
-            r'(?P<count>\d*)(?P<color>(?:;?\d*)*)(?P<action>[ABCDKm])')
-        
+            r"(?P<count>\d*)(?P<color>(?:;?\d*)*)(?P<action>[ABCDKm])"
+        )
+
         self.__populateDeviceTypeComboBox()
-        
+
         self.replEdit.installEventFilter(self)
         # Hack to intercept middle button paste
         self.__origReplEditMouseReleaseEvent = self.replEdit.mouseReleaseEvent
         self.replEdit.mouseReleaseEvent = self.__replEditMouseReleaseEvent
-        
-        self.replEdit.customContextMenuRequested.connect(
-            self.__showContextMenu)
+
+        self.replEdit.customContextMenuRequested.connect(self.__showContextMenu)
         self.__ui.preferencesChanged.connect(self.__handlePreferencesChanged)
-        self.__ui.preferencesChanged.connect(
-            self.__interface.handlePreferencesChanged)
-        
+        self.__ui.preferencesChanged.connect(self.__interface.handlePreferencesChanged)
+
         self.__handlePreferencesChanged()
-        
+
         charFormat = self.replEdit.currentCharFormat()
         self.DefaultForeground = charFormat.foreground()
         self.DefaultBackground = charFormat.background()
-    
+
     def __populateDeviceTypeComboBox(self):
         """
         Private method to populate the device type selector.
         """
         currentDevice = self.deviceTypeComboBox.currentText()
-        
+
         self.deviceTypeComboBox.clear()
         self.deviceInfoLabel.clear()
-        
+
         self.deviceTypeComboBox.addItem("", "")
-        devices, unknownDevices, unknownPorts = (
-            MicroPythonDevices.getFoundDevices()
-        )
+        devices, unknownDevices, unknownPorts = MicroPythonDevices.getFoundDevices()
         if devices:
             supportedMessage = self.tr(
-                "%n supported device(s) detected.", "", len(devices))
-            
-            for index, (boardType, boardName, description, portName,
-                        vid, pid) in enumerate(sorted(devices), 1):
+                "%n supported device(s) detected.", "", len(devices)
+            )
+
+            for index, (
+                boardType,
+                boardName,
+                description,
+                portName,
+                vid,
+                pid,
+            ) in enumerate(sorted(devices), 1):
                 self.deviceTypeComboBox.addItem(
-                    self.tr("{0} - {1} ({2})",
-                            "board name, description, port name")
-                    .format(boardName, description, portName)
+                    self.tr(
+                        "{0} - {1} ({2})", "board name, description, port name"
+                    ).format(boardName, description, portName)
                 )
                 self.deviceTypeComboBox.setItemData(
-                    index, boardType, self.DeviceTypeRole)
+                    index, boardType, self.DeviceTypeRole
+                )
                 self.deviceTypeComboBox.setItemData(
-                    index, boardName, self.DeviceBoardRole)
+                    index, boardName, self.DeviceBoardRole
+                )
                 self.deviceTypeComboBox.setItemData(
-                    index, portName, self.DevicePortRole)
-                self.deviceTypeComboBox.setItemData(
-                    index, vid, self.DeviceVidRole)
-                self.deviceTypeComboBox.setItemData(
-                    index, pid, self.DevicePidRole)
-            
+                    index, portName, self.DevicePortRole
+                )
+                self.deviceTypeComboBox.setItemData(index, vid, self.DeviceVidRole)
+                self.deviceTypeComboBox.setItemData(index, pid, self.DevicePidRole)
+
         else:
             supportedMessage = self.tr("No supported devices detected.")
-        
+
         self.__unknownPorts = unknownPorts
         if self.__unknownPorts:
             unknownMessage = self.tr(
-                "\n%n unknown device(s) for manual selection.", "",
-                len(self.__unknownPorts))
+                "\n%n unknown device(s) for manual selection.",
+                "",
+                len(self.__unknownPorts),
+            )
             if self.deviceTypeComboBox.count():
-                self.deviceTypeComboBox.insertSeparator(
-                    self.deviceTypeComboBox.count())
+                self.deviceTypeComboBox.insertSeparator(self.deviceTypeComboBox.count())
             self.deviceTypeComboBox.addItem(self.tr("Manual Selection"))
             self.deviceTypeComboBox.setItemData(
                 self.deviceTypeComboBox.count() - 1,
-                self.ManualMarker, self.DeviceTypeRole)
+                self.ManualMarker,
+                self.DeviceTypeRole,
+            )
         else:
             unknownMessage = ""
-        
+
         self.deviceInfoLabel.setText(supportedMessage + unknownMessage)
-        
-        index = self.deviceTypeComboBox.findText(currentDevice,
-                                                 Qt.MatchFlag.MatchExactly)
+
+        index = self.deviceTypeComboBox.findText(
+            currentDevice, Qt.MatchFlag.MatchExactly
+        )
         if index == -1:
             # entry is no longer present
             index = 0
             if self.__connected:
                 # we are still connected, so disconnect
                 self.on_connectButton_clicked()
-        
+
         self.on_deviceTypeComboBox_activated(index)
         self.deviceTypeComboBox.setCurrentIndex(index)
-        
+
         if unknownDevices:
             ignoredUnknown = {
-                tuple(d)
-                for d in Preferences.getMicroPython("IgnoredUnknownDevices")
+                tuple(d) for d in Preferences.getMicroPython("IgnoredUnknownDevices")
             }
-            uf2Devices = {(*x[2], x[1])
-                          for x in UF2FlashDialog.getFoundDevices()}
-            newUnknownDevices = (
-                set(unknownDevices) - ignoredUnknown - uf2Devices
-            )
+            uf2Devices = {(*x[2], x[1]) for x in UF2FlashDialog.getFoundDevices()}
+            newUnknownDevices = set(unknownDevices) - ignoredUnknown - uf2Devices
             if newUnknownDevices:
                 button = EricMessageBox.information(
                     self,
                     self.tr("Unknown MicroPython Device"),
                     self.tr(
-                        '<p>Detected these unknown serial devices</p>'
-                        '<ul>'
-                        '<li>{0}</li>'
-                        '</ul>'
-                        '<p>Please report them together with the board name'
+                        "<p>Detected these unknown serial devices</p>"
+                        "<ul>"
+                        "<li>{0}</li>"
+                        "</ul>"
+                        "<p>Please report them together with the board name"
                         ' and a short description to <a href="mailto:{1}">'
-                        ' the eric bug reporting address</a> if it is a'
-                        ' MicroPython board.</p>'
-                    ).format("</li><li>".join([
-                        self.tr("{0} (0x{1:04x}/0x{2:04x})",
-                                "description, VId, PId").format(
-                            desc, vid, pid)
-                        for vid, pid, desc in newUnknownDevices]),
-                        BugAddress),
-                    EricMessageBox.Ignore | EricMessageBox.Ok
+                        " the eric bug reporting address</a> if it is a"
+                        " MicroPython board.</p>"
+                    ).format(
+                        "</li><li>".join(
+                            [
+                                self.tr(
+                                    "{0} (0x{1:04x}/0x{2:04x})", "description, VId, PId"
+                                ).format(desc, vid, pid)
+                                for vid, pid, desc in newUnknownDevices
+                            ]
+                        ),
+                        BugAddress,
+                    ),
+                    EricMessageBox.Ignore | EricMessageBox.Ok,
                 )
                 if button == EricMessageBox.Ignore:
                     ignoredUnknown = list(ignoredUnknown | newUnknownDevices)
-                    Preferences.setMicroPython("IgnoredUnknownDevices",
-                                               ignoredUnknown)
+                    Preferences.setMicroPython("IgnoredUnknownDevices", ignoredUnknown)
                 else:
                     yes = EricMessageBox.yesNo(
                         self,
                         self.tr("Unknown MicroPython Device"),
-                        self.tr("""Would you like to add them to the list of"""
-                                """ manually configured devices?"""),
-                        yesDefault=True)
+                        self.tr(
+                            """Would you like to add them to the list of"""
+                            """ manually configured devices?"""
+                        ),
+                        yesDefault=True,
+                    )
                     if yes:
                         self.__addUnknownDevices(list(newUnknownDevices))
-    
+
     def __handlePreferencesChanged(self):
         """
         Private slot to handle a change in preferences.
         """
         self.__colorScheme = Preferences.getMicroPython("ColorScheme")
-        
+
         self.__font = Preferences.getEditorOtherFonts("MonospacedFont")
         self.replEdit.setFontFamily(self.__font.family())
         self.replEdit.setFontPointSize(self.__font.pointSize())
-        
+
         if Preferences.getMicroPython("ReplLineWrap"):
             self.replEdit.setLineWrapMode(QTextEdit.LineWrapMode.WidgetWidth)
         else:
             self.replEdit.setLineWrapMode(QTextEdit.LineWrapMode.NoWrap)
-        
+
         if self.__chartWidget is not None:
             self.__chartWidget.preferencesChanged()
-    
+
     def commandsInterface(self):
         """
         Public method to get a reference to the commands interface object.
-        
+
         @return reference to the commands interface object
         @rtype MicroPythonCommandsInterface
         """
         return self.__interface
-    
+
     def isMicrobit(self):
         """
         Public method to check, if the connected/selected device is a
         BBC micro:bit or Calliope mini.
-        
+
         @return flag indicating a micro:bit device
         rtype bool
         """
         if self.__device and (
-            "micro:bit" in self.__device.deviceName() or
-            "Calliope" in self.__device.deviceName()
+            "micro:bit" in self.__device.deviceName()
+            or "Calliope" in self.__device.deviceName()
         ):
             return True
-        
+
         return False
-    
+
     @pyqtSlot(int)
     def on_deviceTypeComboBox_activated(self, index):
         """
         Private slot handling the selection of a device type.
-        
+
         @param index index of the selected device
         @type int
         """
-        deviceType = self.deviceTypeComboBox.itemData(
-            index, self.DeviceTypeRole)
+        deviceType = self.deviceTypeComboBox.itemData(index, self.DeviceTypeRole)
         if deviceType == self.ManualMarker:
             self.connectButton.setEnabled(bool(self.__unknownPorts))
         else:
-            self.deviceIconLabel.setPixmap(MicroPythonDevices.getDeviceIcon(
-                deviceType, False))
-            
-            vid = self.deviceTypeComboBox.itemData(
-                index, self.DeviceVidRole)
-            pid = self.deviceTypeComboBox.itemData(
-                index, self.DevicePidRole)
-            
-            self.__device = MicroPythonDevices.getDevice(deviceType, self,
-                                                         vid, pid)
+            self.deviceIconLabel.setPixmap(
+                MicroPythonDevices.getDeviceIcon(deviceType, False)
+            )
+
+            vid = self.deviceTypeComboBox.itemData(index, self.DeviceVidRole)
+            pid = self.deviceTypeComboBox.itemData(index, self.DevicePidRole)
+
+            self.__device = MicroPythonDevices.getDevice(deviceType, self, vid, pid)
             self.__device.setButtons()
-            
+
             self.connectButton.setEnabled(bool(deviceType))
-    
+
     @pyqtSlot()
     def on_checkButton_clicked(self):
         """
         Private slot to check for connected devices.
         """
         self.__populateDeviceTypeComboBox()
-    
+
     def setActionButtons(self, **kwargs):
         """
         Public method to set the enabled state of the various action buttons.
-        
+
         @keyparam kwargs keyword arguments containg the enabled states (keys
             are 'run', 'repl', 'files', 'chart', 'open', 'save'
         @type dict
@@ -514,12 +535,12 @@
             self.filesButton.setEnabled(kwargs["files"])
         if "chart" in kwargs:
             self.chartButton.setEnabled(kwargs["chart"] and HAS_QTCHART)
-    
+
     @pyqtSlot(QPoint)
     def __showContextMenu(self, pos):
         """
         Private slot to show the REPL context menu.
-        
+
         @param pos position to show the menu at
         @type QPoint
         """
@@ -531,65 +552,73 @@
             copyKeys = QKeySequence("Ctrl+Shift+C")
             pasteKeys = QKeySequence("Ctrl+Shift+V")
             selectAllKeys = QKeySequence("Ctrl+Shift+A")
-        
+
         menu = QMenu(self)
         act = menu.addAction(
-            UI.PixmapCache.getIcon("editDelete"), self.tr("Clear"),
-            self.__clear)
+            UI.PixmapCache.getIcon("editDelete"), self.tr("Clear"), self.__clear
+        )
         act.setEnabled(bool(self.replEdit.toPlainText()))
         menu.addSeparator()
         act = menu.addAction(
-            UI.PixmapCache.getIcon("editCopy"), self.tr("Copy"),
-            copyKeys, self.replEdit.copy)
+            UI.PixmapCache.getIcon("editCopy"),
+            self.tr("Copy"),
+            copyKeys,
+            self.replEdit.copy,
+        )
         act.setEnabled(self.replEdit.textCursor().hasSelection())
         act = menu.addAction(
-            UI.PixmapCache.getIcon("editPaste"), self.tr("Paste"),
-            pasteKeys, self.__paste)
-        act.setEnabled(self.replEdit.canPaste() and
-                       self.__interface.isConnected())
+            UI.PixmapCache.getIcon("editPaste"),
+            self.tr("Paste"),
+            pasteKeys,
+            self.__paste,
+        )
+        act.setEnabled(self.replEdit.canPaste() and self.__interface.isConnected())
         menu.addSeparator()
         act = menu.addAction(
-            UI.PixmapCache.getIcon("editSelectAll"), self.tr("Select All"),
-            selectAllKeys, self.replEdit.selectAll)
+            UI.PixmapCache.getIcon("editSelectAll"),
+            self.tr("Select All"),
+            selectAllKeys,
+            self.replEdit.selectAll,
+        )
         act.setEnabled(bool(self.replEdit.toPlainText()))
-        
+
         menu.exec(self.replEdit.mapToGlobal(pos))
-    
+
     def __setConnected(self, connected):
         """
         Private method to set the connection status LED.
-        
+
         @param connected connection state
         @type bool
         """
         self.__connected = connected
-        
+
         self.deviceConnectedLed.setOn(connected)
         if self.__fileManagerWidget:
             self.__fileManagerWidget.deviceConnectedLed.setOn(connected)
-        
+
         self.deviceTypeComboBox.setEnabled(not connected)
-        
+
         if connected:
-            self.connectButton.setIcon(
-                UI.PixmapCache.getIcon("linkDisconnect"))
-            self.connectButton.setToolTip(self.tr(
-                "Press to disconnect the current device"))
+            self.connectButton.setIcon(UI.PixmapCache.getIcon("linkDisconnect"))
+            self.connectButton.setToolTip(
+                self.tr("Press to disconnect the current device")
+            )
         else:
-            self.connectButton.setIcon(
-                UI.PixmapCache.getIcon("linkConnect"))
-            self.connectButton.setToolTip(self.tr(
-                "Press to connect the selected device"))
-    
+            self.connectButton.setIcon(UI.PixmapCache.getIcon("linkConnect"))
+            self.connectButton.setToolTip(
+                self.tr("Press to connect the selected device")
+            )
+
     def isConnected(self):
         """
         Public method to get the connection state.
-        
+
         @return connection state
         @rtype bool
         """
         return self.__connected
-    
+
     def __showNoDeviceMessage(self):
         """
         Private method to show a message dialog indicating a missing device.
@@ -597,58 +626,63 @@
         EricMessageBox.critical(
             self,
             self.tr("No device attached"),
-            self.tr("""Please ensure the device is plugged into your"""
-                    """ computer and selected.\n\nIt must have a version"""
-                    """ of MicroPython (or CircuitPython) flashed onto"""
-                    """ it before anything will work.\n\nFinally press"""
-                    """ the device's reset button and wait a few seconds"""
-                    """ before trying again."""))
-    
+            self.tr(
+                """Please ensure the device is plugged into your"""
+                """ computer and selected.\n\nIt must have a version"""
+                """ of MicroPython (or CircuitPython) flashed onto"""
+                """ it before anything will work.\n\nFinally press"""
+                """ the device's reset button and wait a few seconds"""
+                """ before trying again."""
+            ),
+        )
+
     @pyqtSlot(bool)
     def on_replButton_clicked(self, checked):
         """
         Private slot to connect to enable or disable the REPL widget.
-       
+
         If the selected device is not connected yet, this will be done now.
-        
+
         @param checked state of the button
         @type bool
         """
         if not self.__device:
             self.__showNoDeviceMessage()
             return
-        
+
         if checked:
             ok, reason = self.__device.canStartRepl()
             if not ok:
                 EricMessageBox.warning(
                     self,
                     self.tr("Start REPL"),
-                    self.tr("""<p>The REPL cannot be started.</p><p>Reason:"""
-                            """ {0}</p>""").format(reason))
+                    self.tr(
+                        """<p>The REPL cannot be started.</p><p>Reason:"""
+                        """ {0}</p>"""
+                    ).format(reason),
+                )
                 return
-            
+
             self.replEdit.clear()
             self.__interface.dataReceived.connect(self.__processData)
-            
+
             if not self.__interface.isConnected():
                 self.__connectToDevice()
                 if self.__device.forceInterrupt():
                     # send a Ctrl-B (exit raw mode)
-                    self.__interface.write(b'\x02')
+                    self.__interface.write(b"\x02")
                     # send Ctrl-C (keyboard interrupt)
-                    self.__interface.write(b'\x03')
-            
+                    self.__interface.write(b"\x03")
+
             self.__device.setRepl(True)
             self.replEdit.setFocus(Qt.FocusReason.OtherFocusReason)
         else:
             self.__interface.dataReceived.disconnect(self.__processData)
-            if (not self.chartButton.isChecked() and
-                    not self.filesButton.isChecked()):
+            if not self.chartButton.isChecked() and not self.filesButton.isChecked():
                 self.__disconnectFromDevice()
             self.__device.setRepl(False)
         self.replButton.setChecked(checked)
-    
+
     @pyqtSlot()
     def on_connectButton_clicked(self):
         """
@@ -658,7 +692,7 @@
         if self.__connected:
             with EricOverrideCursor():
                 self.__disconnectFromDevice()
-            
+
             if self.replButton.isChecked():
                 self.on_replButton_clicked(False)
             if self.filesButton.isChecked():
@@ -668,7 +702,7 @@
         else:
             with EricOverrideCursor():
                 self.__connectToDevice()
-    
+
     @pyqtSlot()
     def __clear(self):
         """
@@ -676,12 +710,12 @@
         """
         self.replEdit.clear()
         self.__interface.isConnected() and self.__interface.write(b"\r")
-    
+
     @pyqtSlot()
     def __paste(self, mode=QClipboard.Mode.Clipboard):
         """
         Private slot to perform a paste operation.
-        
+
         @param mode paste mode (defaults to QClipboard.Mode.Clipboard)
         @type QClipboard.Mode (optional)
         """
@@ -690,15 +724,16 @@
         if clipboard:
             pasteText = clipboard.text(mode=mode)
             if pasteText:
-                pasteText = pasteText.replace('\n\r', '\r')
-                pasteText = pasteText.replace('\n', '\r')
+                pasteText = pasteText.replace("\n\r", "\r")
+                pasteText = pasteText.replace("\n", "\r")
                 self.__interface.isConnected() and self.__interface.write(
-                    pasteText.encode("utf-8"))
-    
+                    pasteText.encode("utf-8")
+                )
+
     def eventFilter(self, obj, evt):
         """
         Public method to process events for the REPL pane.
-        
+
         @param obj reference to the object the event was meant for
         @type QObject
         @param evt reference to the event object
@@ -709,43 +744,45 @@
         if obj is self.replEdit and evt.type() == QEvent.Type.KeyPress:
             # handle the key press event on behalve of the REPL pane
             key = evt.key()
-            msg = bytes(evt.text(), 'utf8')
+            msg = bytes(evt.text(), "utf8")
             if key == Qt.Key.Key_Backspace:
-                msg = b'\b'
+                msg = b"\b"
             elif key == Qt.Key.Key_Delete:
-                msg = b'\x1B[\x33\x7E'
+                msg = b"\x1B[\x33\x7E"
             elif key == Qt.Key.Key_Up:
-                msg = b'\x1B[A'
+                msg = b"\x1B[A"
             elif key == Qt.Key.Key_Down:
-                msg = b'\x1B[B'
+                msg = b"\x1B[B"
             elif key == Qt.Key.Key_Right:
-                msg = b'\x1B[C'
+                msg = b"\x1B[C"
             elif key == Qt.Key.Key_Left:
-                msg = b'\x1B[D'
+                msg = b"\x1B[D"
             elif key == Qt.Key.Key_Home:
-                msg = b'\x1B[H'
+                msg = b"\x1B[H"
             elif key == Qt.Key.Key_End:
-                msg = b'\x1B[F'
-            elif ((Globals.isMacPlatform() and
-                   evt.modifiers() == Qt.KeyboardModifier.MetaModifier) or
-                  (not Globals.isMacPlatform() and
-                   evt.modifiers() == Qt.KeyboardModifier.ControlModifier)):
+                msg = b"\x1B[F"
+            elif (
+                Globals.isMacPlatform()
+                and evt.modifiers() == Qt.KeyboardModifier.MetaModifier
+            ) or (
+                not Globals.isMacPlatform()
+                and evt.modifiers() == Qt.KeyboardModifier.ControlModifier
+            ):
                 if Qt.Key.Key_A <= key <= Qt.Key.Key_Z:
                     # devices treat an input of \x01 as Ctrl+A, etc.
                     msg = bytes([1 + key - Qt.Key.Key_A])
-            elif (
-                evt.modifiers() == (
-                    Qt.KeyboardModifier.ControlModifier |
-                    Qt.KeyboardModifier.ShiftModifier) or
-                (Globals.isMacPlatform() and
-                 evt.modifiers() == Qt.KeyboardModifier.ControlModifier)
+            elif evt.modifiers() == (
+                Qt.KeyboardModifier.ControlModifier | Qt.KeyboardModifier.ShiftModifier
+            ) or (
+                Globals.isMacPlatform()
+                and evt.modifiers() == Qt.KeyboardModifier.ControlModifier
             ):
                 if key == Qt.Key.Key_C:
                     self.replEdit.copy()
-                    msg = b''
+                    msg = b""
                 elif key == Qt.Key.Key_V:
                     self.__paste()
-                    msg = b''
+                    msg = b""
                 elif key == Qt.Key.Key_A:
                     self.replEdit.selectAll()
                     msg = b""
@@ -758,32 +795,32 @@
         else:
             # standard event processing
             return super().eventFilter(obj, evt)
-    
+
     def __replEditMouseReleaseEvent(self, evt):
         """
         Private method handling mouse release events for the replEdit widget.
-        
+
         Note: this is a hack because QTextEdit does not allow filtering of
         QEvent.Type.MouseButtonRelease. To make middle button paste work, we
         had to intercept the protected event method (some kind of
         reimplementing it).
-        
+
         @param evt reference to the event object
         @type QMouseEvent
         """
         if evt.button() == Qt.MouseButton.MiddleButton:
             self.__paste(mode=QClipboard.Mode.Selection)
-            msg = b''
+            msg = b""
             if self.__interface.isConnected():
                 self.__interface.write(msg)
             evt.accept()
         else:
             self.__origReplEditMouseReleaseEvent(evt)
-    
+
     def __processData(self, data):
         """
         Private slot to process bytes received from the device.
-        
+
         @param data bytes received from the device
         @type bytes
         """
@@ -791,96 +828,92 @@
         # the text cursor must be on the last line
         while tc.movePosition(QTextCursor.MoveOperation.Down):
             pass
-        
+
         # set the font
         charFormat = tc.charFormat()
         charFormat.setFontFamilies([self.__font.family()])
         charFormat.setFontPointSize(self.__font.pointSize())
         tc.setCharFormat(charFormat)
-        
+
         index = 0
         while index < len(data):
-            if data[index] == 8:        # \b
+            if data[index] == 8:  # \b
                 tc.movePosition(QTextCursor.MoveOperation.Left)
                 self.replEdit.setTextCursor(tc)
-            elif data[index] in (4, 13):     # EOT, \r
+            elif data[index] in (4, 13):  # EOT, \r
                 pass
-            elif (len(data) > index + 1 and
-                  data[index] == 27 and
-                  data[index + 1] == 91):
+            elif len(data) > index + 1 and data[index] == 27 and data[index + 1] == 91:
                 # VT100 cursor command detected: <Esc>[
-                index += 2      # move index to after the [
+                index += 2  # move index to after the [
                 match = self.__vt100Re.search(
-                    data[index:].decode("utf-8", errors="replace"))
+                    data[index:].decode("utf-8", errors="replace")
+                )
                 if match:
                     # move to last position in control sequence
                     # ++ will be done at end of loop
                     index += match.end() - 1
-                    
+
                     action = match.group("action")
                     if action in "ABCD":
                         if match.group("count") == "":
                             count = 1
                         else:
                             count = int(match.group("count"))
-                        
-                        if action == "A":       # up
-                            tc.movePosition(QTextCursor.MoveOperation.Up,
-                                            n=count)
+
+                        if action == "A":  # up
+                            tc.movePosition(QTextCursor.MoveOperation.Up, n=count)
                             self.replEdit.setTextCursor(tc)
-                        elif action == "B":     # down
-                            tc.movePosition(QTextCursor.MoveOperation.Down,
-                                            n=count)
+                        elif action == "B":  # down
+                            tc.movePosition(QTextCursor.MoveOperation.Down, n=count)
                             self.replEdit.setTextCursor(tc)
-                        elif action == "C":     # right
-                            tc.movePosition(QTextCursor.MoveOperation.Right,
-                                            n=count)
+                        elif action == "C":  # right
+                            tc.movePosition(QTextCursor.MoveOperation.Right, n=count)
                             self.replEdit.setTextCursor(tc)
-                        elif action == "D":     # left
-                            tc.movePosition(QTextCursor.MoveOperation.Left,
-                                            n=count)
+                        elif action == "D":  # left
+                            tc.movePosition(QTextCursor.MoveOperation.Left, n=count)
                             self.replEdit.setTextCursor(tc)
-                    elif action == "K":     # delete things
+                    elif action == "K":  # delete things
                         if match.group("count") in ("", "0"):
                             # delete to end of line
                             tc.movePosition(
                                 QTextCursor.MoveOperation.EndOfLine,
-                                mode=QTextCursor.MoveMode.KeepAnchor)
+                                mode=QTextCursor.MoveMode.KeepAnchor,
+                            )
                             tc.removeSelectedText()
                             self.replEdit.setTextCursor(tc)
                         elif match.group("count") == "1":
                             # delete to beinning of line
                             tc.movePosition(
                                 QTextCursor.MoveOperation.StartOfLine,
-                                mode=QTextCursor.MoveMode.KeepAnchor)
+                                mode=QTextCursor.MoveMode.KeepAnchor,
+                            )
                             tc.removeSelectedText()
                             self.replEdit.setTextCursor(tc)
                         elif match.group("count") == "2":
                             # delete whole line
-                            tc.movePosition(
-                                QTextCursor.MoveOperation.EndOfLine)
+                            tc.movePosition(QTextCursor.MoveOperation.EndOfLine)
                             tc.movePosition(
                                 QTextCursor.MoveOperation.StartOfLine,
-                                mode=QTextCursor.MoveMode.KeepAnchor)
+                                mode=QTextCursor.MoveMode.KeepAnchor,
+                            )
                             tc.removeSelectedText()
                             self.replEdit.setTextCursor(tc)
                     elif action == "m":
-                        self.__setCharFormat(match.group(0)[:-1].split(";"),
-                                             tc)
+                        self.__setCharFormat(match.group(0)[:-1].split(";"), tc)
             else:
                 tc.deleteChar()
                 self.replEdit.setTextCursor(tc)
                 self.replEdit.insertPlainText(chr(data[index]))
-            
+
             index += 1
-        
+
         self.replEdit.ensureCursorVisible()
-    
+
     def __setCharFormat(self, formatCodes, textCursor):
         """
         Private method setting the current text format of the REPL pane based
         on the passed ANSI codes.
-        
+
         Following codes are used:
         <ul>
         <li>0: Reset</li>
@@ -931,7 +964,7 @@
         <li>106: bright background Cyan</li>
         <li>107: bright background White</li>
         </ul>
-        
+
         @param formatCodes list of format codes
         @type list of str
         @param textCursor reference to the text cursor
@@ -940,7 +973,7 @@
         if not formatCodes:
             # empty format codes list is treated as a reset
             formatCodes = ["0"]
-        
+
         charFormat = textCursor.charFormat()
         for formatCode in formatCodes:
             try:
@@ -948,7 +981,7 @@
             except ValueError:
                 # ignore non digit values
                 continue
-            
+
             if formatCode == 0:
                 charFormat.setFontWeight(50)
                 charFormat.setFontItalic(False)
@@ -981,27 +1014,31 @@
                 charFormat.setFontOverline(False)
             elif formatCode in (30, 31, 32, 33, 34, 35, 36, 37):
                 charFormat.setForeground(
-                    AnsiColorSchemes[self.__colorScheme][formatCode - 30])
+                    AnsiColorSchemes[self.__colorScheme][formatCode - 30]
+                )
             elif formatCode in (40, 41, 42, 43, 44, 45, 46, 47):
                 charFormat.setBackground(
-                    AnsiColorSchemes[self.__colorScheme][formatCode - 40])
+                    AnsiColorSchemes[self.__colorScheme][formatCode - 40]
+                )
             elif formatCode in (90, 91, 92, 93, 94, 95, 96, 97):
                 charFormat.setForeground(
-                    AnsiColorSchemes[self.__colorScheme][formatCode - 80])
+                    AnsiColorSchemes[self.__colorScheme][formatCode - 80]
+                )
             elif formatCode in (100, 101, 102, 103, 104, 105, 106, 107):
                 charFormat.setBackground(
-                    AnsiColorSchemes[self.__colorScheme][formatCode - 90])
+                    AnsiColorSchemes[self.__colorScheme][formatCode - 90]
+                )
             elif formatCode == 39:
                 charFormat.setForeground(self.DefaultForeground)
             elif formatCode == 49:
                 charFormat.setBackground(self.DefaultBackground)
-        
+
         textCursor.setCharFormat(charFormat)
-    
+
     def __doZoom(self, value):
         """
         Private slot to zoom the REPL pane.
-        
+
         @param value zoom value
         @type int
         """
@@ -1010,11 +1047,11 @@
         elif value > self.__currentZoom:
             self.replEdit.zoomIn(value - self.__currentZoom)
         self.__currentZoom = value
-    
+
     def getCurrentPort(self):
         """
         Public method to determine the port path of the selected device.
-        
+
         @return path of the port of the selected device
         @rtype str
         """
@@ -1028,21 +1065,21 @@
                 return "/dev/{0}".format(portName)
         else:
             return ""
-    
+
     def getCurrentBoard(self):
         """
         Public method to get the board name of the selected device.
-        
+
         @return board name of the selected device
         @rtype str
         """
         boardName = self.deviceTypeComboBox.currentData(self.DeviceBoardRole)
         return boardName
-    
+
     def getDeviceWorkspace(self):
         """
         Public method to get the workspace directory of the device.
-        
+
         @return workspace directory of the device
         @rtype str
         """
@@ -1050,7 +1087,7 @@
             return self.__device.getWorkspace()
         else:
             return ""
-    
+
     def __connectToDevice(self):
         """
         Private method to connect to the selected device.
@@ -1058,90 +1095,103 @@
         port = self.getCurrentPort()
         if not port:
             from .ConnectionSelectionDialog import ConnectionSelectionDialog
+
             with EricOverridenCursor():
                 dlg = ConnectionSelectionDialog(
                     self.__unknownPorts, self.__lastPort, self.__lastDeviceType
                 )
                 if dlg.exec() == QDialog.DialogCode.Accepted:
                     vid, pid, port, deviceType = dlg.getData()
-                    
+
                     self.deviceIconLabel.setPixmap(
-                        MicroPythonDevices.getDeviceIcon(deviceType, False))
+                        MicroPythonDevices.getDeviceIcon(deviceType, False)
+                    )
                     self.__device = MicroPythonDevices.getDevice(
-                        deviceType, self, vid, pid)
+                        deviceType, self, vid, pid
+                    )
                     self.__device.setButtons()
-                    
+
                     self.__lastPort = port
                     self.__lastDeviceType = deviceType
                 else:
                     return
-        
+
         if self.__interface.connectToDevice(port):
             self.__setConnected(True)
-            
-            if (Preferences.getMicroPython("SyncTimeAfterConnect") and
-                    self.__device.hasTimeCommands()):
+
+            if (
+                Preferences.getMicroPython("SyncTimeAfterConnect")
+                and self.__device.hasTimeCommands()
+            ):
                 self.__synchronizeTime(quiet=True)
         else:
             with EricOverridenCursor():
                 EricMessageBox.warning(
                     self,
                     self.tr("Serial Device Connect"),
-                    self.tr("""<p>Cannot connect to device at serial"""
-                            """ port <b>{0}</b>.</p>""").format(port))
-    
+                    self.tr(
+                        """<p>Cannot connect to device at serial"""
+                        """ port <b>{0}</b>.</p>"""
+                    ).format(port),
+                )
+
     def __disconnectFromDevice(self):
         """
         Private method to disconnect from the device.
         """
         self.__interface.disconnectFromDevice()
         self.__setConnected(False)
-    
+
     @pyqtSlot()
     def on_runButton_clicked(self):
         """
         Private slot to execute the script of the active editor on the
         selected device.
-        
+
         If the REPL is not active yet, it will be activated, which might cause
         an unconnected device to be connected.
         """
         if not self.__device:
             self.__showNoDeviceMessage()
             return
-        
+
         aw = ericApp().getObject("ViewManager").activeWindow()
         if aw is None:
             EricMessageBox.critical(
                 self,
                 self.tr("Run Script"),
-                self.tr("""There is no editor open. Abort..."""))
+                self.tr("""There is no editor open. Abort..."""),
+            )
             return
-        
+
         script = aw.text()
         if not script:
             EricMessageBox.critical(
                 self,
                 self.tr("Run Script"),
-                self.tr("""The current editor does not contain a script."""
-                        """ Abort..."""))
+                self.tr(
+                    """The current editor does not contain a script.""" """ Abort..."""
+                ),
+            )
             return
-        
+
         ok, reason = self.__device.canRunScript()
         if not ok:
             EricMessageBox.warning(
                 self,
                 self.tr("Run Script"),
-                self.tr("""<p>Cannot run script.</p><p>Reason:"""
-                        """ {0}</p>""").format(reason))
+                self.tr(
+                    """<p>Cannot run script.</p><p>Reason:""" """ {0}</p>"""
+                ).format(reason),
+            )
             return
-        
+
         if not self.replButton.isChecked():
             # activate on the REPL
             self.on_replButton_clicked(True)
         if self.replButton.isChecked():
             self.__device.runScript(script)
-    
+
     @pyqtSlot()
     def on_openButton_clicked(self):
         """
@@ -1150,17 +1200,18 @@
         if not self.__device:
             self.__showNoDeviceMessage()
             return
-        
+
         workspace = self.getDeviceWorkspace()
         if workspace:
             fileName = EricFileDialog.getOpenFileName(
                 self,
                 self.tr("Open Python File"),
                 workspace,
-                self.tr("Python3 Files (*.py);;All Files (*)"))
+                self.tr("Python3 Files (*.py);;All Files (*)"),
+            )
             if fileName:
                 ericApp().getObject("ViewManager").openSourceFile(fileName)
-    
+
     @pyqtSlot()
     def on_saveButton_clicked(self):
         """
@@ -1169,61 +1220,65 @@
         if not self.__device:
             self.__showNoDeviceMessage()
             return
-        
+
         aw = ericApp().getObject("ViewManager").activeWindow()
         if aw:
             workspace = self.getDeviceWorkspace()
             if workspace:
                 aw.saveFileAs(workspace)
-    
+
     @pyqtSlot(bool)
     def on_chartButton_clicked(self, checked):
         """
         Private slot to open a chart view to plot data received from the
         connected device.
-       
+
         If the selected device is not connected yet, this will be done now.
-        
+
         @param checked state of the button
         @type bool
         """
         if not HAS_QTCHART:
             # QtCharts not available => fail silently
             return
-        
+
         if not self.__device:
             self.__showNoDeviceMessage()
             return
-        
+
         if checked:
             ok, reason = self.__device.canStartPlotter()
             if not ok:
                 EricMessageBox.warning(
                     self,
                     self.tr("Start Chart"),
-                    self.tr("""<p>The Chart cannot be started.</p><p>Reason:"""
-                            """ {0}</p>""").format(reason))
+                    self.tr(
+                        """<p>The Chart cannot be started.</p><p>Reason:"""
+                        """ {0}</p>"""
+                    ).format(reason),
+                )
                 return
-            
+
             self.__chartWidget = MicroPythonGraphWidget(self)
-            self.__interface.dataReceived.connect(
-                self.__chartWidget.processData)
-            self.__chartWidget.dataFlood.connect(
-                self.handleDataFlood)
-            
-            self.__ui.addSideWidget(self.__ui.BottomSide, self.__chartWidget,
-                                    UI.PixmapCache.getIcon("chart"),
-                                    self.tr("µPy Chart"))
+            self.__interface.dataReceived.connect(self.__chartWidget.processData)
+            self.__chartWidget.dataFlood.connect(self.handleDataFlood)
+
+            self.__ui.addSideWidget(
+                self.__ui.BottomSide,
+                self.__chartWidget,
+                UI.PixmapCache.getIcon("chart"),
+                self.tr("µPy Chart"),
+            )
             self.__ui.showSideWidget(self.__chartWidget)
-            
+
             if not self.__interface.isConnected():
                 self.__connectToDevice()
                 if self.__device.forceInterrupt():
                     # send a Ctrl-B (exit raw mode)
-                    self.__interface.write(b'\x02')
+                    self.__interface.write(b"\x02")
                     # send Ctrl-C (keyboard interrupt)
-                    self.__interface.write(b'\x03')
-            
+                    self.__interface.write(b"\x03")
+
             self.__device.setPlotter(True)
         else:
             if self.__chartWidget.isDirty():
@@ -1231,28 +1286,26 @@
                     self,
                     self.tr("Unsaved Chart Data"),
                     self.tr("""The chart contains unsaved data."""),
-                    self.__chartWidget.saveData)
+                    self.__chartWidget.saveData,
+                )
                 if not res:
                     # abort
                     return
-            
-            self.__interface.dataReceived.disconnect(
-                self.__chartWidget.processData)
-            self.__chartWidget.dataFlood.disconnect(
-                self.handleDataFlood)
-            
-            if (not self.replButton.isChecked() and
-                    not self.filesButton.isChecked()):
+
+            self.__interface.dataReceived.disconnect(self.__chartWidget.processData)
+            self.__chartWidget.dataFlood.disconnect(self.handleDataFlood)
+
+            if not self.replButton.isChecked() and not self.filesButton.isChecked():
                 self.__disconnectFromDevice()
-            
+
             self.__device.setPlotter(False)
             self.__ui.removeSideWidget(self.__chartWidget)
-            
+
             self.__chartWidget.deleteLater()
             self.__chartWidget = None
-        
+
         self.chartButton.setChecked(checked)
-    
+
     @pyqtSlot()
     def handleDataFlood(self):
         """
@@ -1260,76 +1313,77 @@
         """
         self.on_connectButton_clicked()
         self.__device.handleDataFlood()
-    
+
     @pyqtSlot(bool)
     def on_filesButton_clicked(self, checked):
         """
         Private slot to open a file manager window to the connected device.
-       
+
         If the selected device is not connected yet, this will be done now.
-        
+
         @param checked state of the button
         @type bool
         """
         if not self.__device:
             self.__showNoDeviceMessage()
             return
-        
+
         if checked:
             ok, reason = self.__device.canStartFileManager()
             if not ok:
                 EricMessageBox.warning(
                     self,
                     self.tr("Start File Manager"),
-                    self.tr("""<p>The File Manager cannot be started.</p>"""
-                            """<p>Reason: {0}</p>""").format(reason))
+                    self.tr(
+                        """<p>The File Manager cannot be started.</p>"""
+                        """<p>Reason: {0}</p>"""
+                    ).format(reason),
+                )
                 return
-            
+
             with EricOverrideCursor():
                 if not self.__interface.isConnected():
                     self.__connectToDevice()
                 if self.__connected:
                     self.__fileManagerWidget = MicroPythonFileManagerWidget(
-                        self.__interface,
-                        self.__device.supportsLocalFileAccess(),
-                        self)
-                    
+                        self.__interface, self.__device.supportsLocalFileAccess(), self
+                    )
+
                     self.__ui.addSideWidget(
                         self.__ui.BottomSide,
                         self.__fileManagerWidget,
                         UI.PixmapCache.getIcon("filemanager"),
-                        self.tr("µPy Files")
+                        self.tr("µPy Files"),
                     )
                     self.__ui.showSideWidget(self.__fileManagerWidget)
 
                     self.__device.setFileManager(True)
-                    
+
                     self.__fileManagerWidget.start()
         else:
             self.__fileManagerWidget.stop()
-            
-            if (not self.replButton.isChecked() and
-                    not self.chartButton.isChecked()):
+
+            if not self.replButton.isChecked() and not self.chartButton.isChecked():
                 self.__disconnectFromDevice()
-            
+
             self.__device.setFileManager(False)
             self.__ui.removeSideWidget(self.__fileManagerWidget)
-            
+
             self.__fileManagerWidget.deleteLater()
             self.__fileManagerWidget = None
-        
+
         self.filesButton.setChecked(checked)
-    
+
     ##################################################################
     ## Super Menu related methods below
     ##################################################################
-    
+
     def __aboutToShowSuperMenu(self):
         """
         Private slot to populate the Super Menu before showing it.
         """
         self.__superMenu.clear()
-        
+
         # prepare the download menu
         if self.__device:
             menuEntries = self.__device.getDownloadMenuEntries()
@@ -1340,46 +1394,52 @@
                         downloadMenu.addSeparator()
                     else:
                         downloadMenu.addAction(
-                            text,
-                            functools.partial(self.__downloadFromUrl, url)
+                            text, functools.partial(self.__downloadFromUrl, url)
                         )
             else:
                 downloadMenu = None
-        
+
         # populate the super menu
         hasTime = self.__device.hasTimeCommands() if self.__device else False
-        
+
         act = self.__superMenu.addAction(
-            self.tr("Show Version"), self.__showDeviceVersion)
+            self.tr("Show Version"), self.__showDeviceVersion
+        )
         act.setEnabled(self.__connected)
         act = self.__superMenu.addAction(
-            self.tr("Show Implementation"), self.__showImplementation)
+            self.tr("Show Implementation"), self.__showImplementation
+        )
         act.setEnabled(self.__connected)
         act = self.__superMenu.addAction(
-            self.tr("Show Board Data"), self.__showBoardInformation)
+            self.tr("Show Board Data"), self.__showBoardInformation
+        )
         act.setEnabled(self.__connected)
         self.__superMenu.addSeparator()
         if hasTime:
             act = self.__superMenu.addAction(
-                self.tr("Synchronize Time"), self.__synchronizeTime)
+                self.tr("Synchronize Time"), self.__synchronizeTime
+            )
             act.setEnabled(self.__connected)
             act = self.__superMenu.addAction(
-                self.tr("Show Device Time"), self.__showDeviceTime)
+                self.tr("Show Device Time"), self.__showDeviceTime
+            )
             act.setEnabled(self.__connected)
-        self.__superMenu.addAction(
-            self.tr("Show Local Time"), self.__showLocalTime)
+        self.__superMenu.addAction(self.tr("Show Local Time"), self.__showLocalTime)
         if hasTime:
             act = self.__superMenu.addAction(
-                self.tr("Show Time"), self.__showLocalAndDeviceTime)
+                self.tr("Show Time"), self.__showLocalAndDeviceTime
+            )
             act.setEnabled(self.__connected)
         self.__superMenu.addSeparator()
         if not Globals.isWindowsPlatform():
             available = self.__mpyCrossAvailable()
             act = self.__superMenu.addAction(
-                self.tr("Compile Python File"), self.__compileFile2Mpy)
+                self.tr("Compile Python File"), self.__compileFile2Mpy
+            )
             act.setEnabled(available)
             act = self.__superMenu.addAction(
-                self.tr("Compile Current Editor"), self.__compileEditor2Mpy)
+                self.tr("Compile Current Editor"), self.__compileEditor2Mpy
+            )
             aw = ericApp().getObject("ViewManager").activeWindow()
             act.setEnabled(available and bool(aw))
             self.__superMenu.addSeparator()
@@ -1389,27 +1449,30 @@
             if downloadMenu is None:
                 # generic download action
                 act = self.__superMenu.addAction(
-                    self.tr("Download Firmware"), self.__downloadFirmware)
+                    self.tr("Download Firmware"), self.__downloadFirmware
+                )
                 act.setEnabled(self.__device.hasFirmwareUrl())
             else:
                 # download sub-menu
                 self.__superMenu.addMenu(downloadMenu)
             self.__superMenu.addSeparator()
             act = self.__superMenu.addAction(
-                self.tr("Show Documentation"), self.__showDocumentation)
+                self.tr("Show Documentation"), self.__showDocumentation
+            )
             act.setEnabled(self.__device.hasDocumentationUrl())
             self.__superMenu.addSeparator()
         if not self.__device.hasFlashMenuEntry():
-            self.__superMenu.addAction(self.tr("Flash UF2 Device"),
-                                       self.__flashUF2)
+            self.__superMenu.addAction(self.tr("Flash UF2 Device"), self.__flashUF2)
             self.__superMenu.addSeparator()
-        self.__superMenu.addAction(self.tr("Manage Unknown Devices"),
-                                   self.__manageUnknownDevices)
-        self.__superMenu.addAction(self.tr("Ignored Serial Devices"),
-                                   self.__manageIgnored)
+        self.__superMenu.addAction(
+            self.tr("Manage Unknown Devices"), self.__manageUnknownDevices
+        )
+        self.__superMenu.addAction(
+            self.tr("Ignored Serial Devices"), self.__manageIgnored
+        )
         self.__superMenu.addSeparator()
         self.__superMenu.addAction(self.tr("Configure"), self.__configure)
-    
+
     @pyqtSlot()
     def __showDeviceVersion(self):
         """
@@ -1418,24 +1481,20 @@
         try:
             versionInfo = self.__interface.version()
             if versionInfo:
-                msg = self.tr(
-                    "<h3>Device Version Information</h3>"
-                )
+                msg = self.tr("<h3>Device Version Information</h3>")
                 msg += "<table>"
                 for key, value in versionInfo.items():
                     msg += "<tr><td><b>{0}</b></td><td>{1}</td></tr>".format(
-                        key.capitalize(), value)
+                        key.capitalize(), value
+                    )
                 msg += "</table>"
             else:
                 msg = self.tr("No version information available.")
-            
-            EricMessageBox.information(
-                self,
-                self.tr("Device Version Information"),
-                msg)
+
+            EricMessageBox.information(self, self.tr("Device Version Information"), msg)
         except Exception as exc:
             self.__showError("version()", str(exc))
-    
+
     @pyqtSlot()
     def __showImplementation(self):
         """
@@ -1453,21 +1512,21 @@
                 name = impInfo["name"]
             version = (
                 self.tr("unknown")
-                if impInfo["version"] == "unknown" else
-                impInfo["version"]
+                if impInfo["version"] == "unknown"
+                else impInfo["version"]
             )
-            
+
             EricMessageBox.information(
                 self,
                 self.tr("Device Implementation Information"),
                 self.tr(
                     "<h3>Device Implementation Information</h3>"
                     "<p>This device contains <b>{0} {1}</b>.</p>"
-                ).format(name, version)
+                ).format(name, version),
             )
         except Exception as exc:
             self.__showError("getImplementation()", str(exc))
-    
+
     @pyqtSlot()
     def __showBoardInformation(self):
         """
@@ -1475,43 +1534,46 @@
         """
         try:
             boardInfo = self.__interface.getBoardInformation()
-            
+
             from .BoardDataDialog import BoardDataDialog
+
             dlg = BoardDataDialog(boardInfo)
             dlg.exec()
         except Exception as exc:
             self.__showError("getBoardInformation()", str(exc))
-    
+
     @pyqtSlot()
     def __synchronizeTime(self, quiet=False):
         """
         Private slot to set the time of the connected device to the local
         computer's time.
-        
+
         @param quiet flag indicating to not show a message
         @type bool
         """
         if self.__device and self.__device.hasTimeCommands():
             try:
                 self.__interface.syncTime(self.__device.getDeviceType())
-                
+
                 if not quiet:
                     with EricOverridenCursor():
                         EricMessageBox.information(
                             self,
                             self.tr("Synchronize Time"),
-                            self.tr("<p>The time of the connected device was"
-                                    " synchronized with the local time.</p>") +
-                            self.__getDeviceTime()
+                            self.tr(
+                                "<p>The time of the connected device was"
+                                " synchronized with the local time.</p>"
+                            )
+                            + self.__getDeviceTime(),
                         )
             except Exception as exc:
                 self.__showError("syncTime()", str(exc))
-    
+
     def __getDeviceTime(self):
         """
         Private method to get a string containing the date and time of the
         connected device.
-        
+
         @return date and time of the connected device
         @rtype str
         """
@@ -1528,16 +1590,15 @@
                         "</table>"
                     ).format(date, time)
                 except ValueError:
-                    return self.tr(
-                        "<h3>Device Date and Time</h3>"
-                        "<p>{0}</p>"
-                    ).format(dateTimeString.strip())
+                    return self.tr("<h3>Device Date and Time</h3>" "<p>{0}</p>").format(
+                        dateTimeString.strip()
+                    )
             except Exception as exc:
                 self.__showError("getTime()", str(exc))
                 return ""
         else:
             return ""
-    
+
     @pyqtSlot()
     def __showDeviceTime(self):
         """
@@ -1545,81 +1606,77 @@
         """
         msg = self.__getDeviceTime()
         if msg:
-            EricMessageBox.information(
-                self,
-                self.tr("Device Date and Time"),
-                msg)
-    
+            EricMessageBox.information(self, self.tr("Device Date and Time"), msg)
+
     @pyqtSlot()
     def __showLocalTime(self):
         """
         Private slot to show the local date and time.
         """
         localdatetime = time.localtime()
-        localdate = time.strftime('%Y-%m-%d', localdatetime)
-        localtime = time.strftime('%H:%M:%S', localdatetime)
+        localdate = time.strftime("%Y-%m-%d", localdatetime)
+        localtime = time.strftime("%H:%M:%S", localdatetime)
         EricMessageBox.information(
             self,
             self.tr("Local Date and Time"),
-            self.tr("<h3>Local Date and Time</h3>"
-                    "<table>"
-                    "<tr><td><b>Date</b></td><td>{0}</td></tr>"
-                    "<tr><td><b>Time</b></td><td>{1}</td></tr>"
-                    "</table>"
-                    ).format(localdate, localtime)
+            self.tr(
+                "<h3>Local Date and Time</h3>"
+                "<table>"
+                "<tr><td><b>Date</b></td><td>{0}</td></tr>"
+                "<tr><td><b>Time</b></td><td>{1}</td></tr>"
+                "</table>"
+            ).format(localdate, localtime),
         )
-    
+
     @pyqtSlot()
     def __showLocalAndDeviceTime(self):
         """
         Private slot to show the local and device time side-by-side.
         """
         localdatetime = time.localtime()
-        localdate = time.strftime('%Y-%m-%d', localdatetime)
-        localtime = time.strftime('%H:%M:%S', localdatetime)
-        
+        localdate = time.strftime("%Y-%m-%d", localdatetime)
+        localtime = time.strftime("%H:%M:%S", localdatetime)
+
         try:
             deviceDateTimeString = self.__interface.getTime()
             try:
-                devicedate, devicetime = (
-                    deviceDateTimeString.strip().split(None, 1)
-                )
+                devicedate, devicetime = deviceDateTimeString.strip().split(None, 1)
                 EricMessageBox.information(
                     self,
                     self.tr("Date and Time"),
-                    self.tr("<table>"
-                            "<tr><th></th><th>Local Date and Time</th>"
-                            "<th>Device Date and Time</th></tr>"
-                            "<tr><td><b>Date</b></td>"
-                            "<td align='center'>{0}</td>"
-                            "<td align='center'>{2}</td></tr>"
-                            "<tr><td><b>Time</b></td>"
-                            "<td align='center'>{1}</td>"
-                            "<td align='center'>{3}</td></tr>"
-                            "</table>"
-                            ).format(localdate, localtime,
-                                     devicedate, devicetime)
+                    self.tr(
+                        "<table>"
+                        "<tr><th></th><th>Local Date and Time</th>"
+                        "<th>Device Date and Time</th></tr>"
+                        "<tr><td><b>Date</b></td>"
+                        "<td align='center'>{0}</td>"
+                        "<td align='center'>{2}</td></tr>"
+                        "<tr><td><b>Time</b></td>"
+                        "<td align='center'>{1}</td>"
+                        "<td align='center'>{3}</td></tr>"
+                        "</table>"
+                    ).format(localdate, localtime, devicedate, devicetime),
                 )
             except ValueError:
                 EricMessageBox.information(
                     self,
                     self.tr("Date and Time"),
-                    self.tr("<table>"
-                            "<tr><th>Local Date and Time</th>"
-                            "<th>Device Date and Time</th></tr>"
-                            "<tr><td align='center'>{0} {1}</td>"
-                            "<td align='center'>{2}</td></tr>"
-                            "</table>"
-                            ).format(localdate, localtime,
-                                     deviceDateTimeString.strip())
+                    self.tr(
+                        "<table>"
+                        "<tr><th>Local Date and Time</th>"
+                        "<th>Device Date and Time</th></tr>"
+                        "<tr><td align='center'>{0} {1}</td>"
+                        "<td align='center'>{2}</td></tr>"
+                        "</table>"
+                    ).format(localdate, localtime, deviceDateTimeString.strip()),
                 )
         except Exception as exc:
             self.__showError("getTime()", str(exc))
-    
+
     def __showError(self, method, error):
         """
         Private method to show some error message.
-        
+
         @param method name of the method the error occured in
         @type str
         @param error error message
@@ -1629,15 +1686,17 @@
             EricMessageBox.warning(
                 self,
                 self.tr("Error handling device"),
-                self.tr("<p>There was an error communicating with the"
-                        " connected device.</p><p>Method: {0}</p>"
-                        "<p>Message: {1}</p>")
-                .format(method, error))
-    
+                self.tr(
+                    "<p>There was an error communicating with the"
+                    " connected device.</p><p>Method: {0}</p>"
+                    "<p>Message: {1}</p>"
+                ).format(method, error),
+            )
+
     def __mpyCrossAvailable(self):
         """
         Private method to check the availability of mpy-cross.
-        
+
         @return flag indicating the availability of mpy-cross
         @rtype bool
         """
@@ -1650,13 +1709,13 @@
         else:
             if Utilities.isExecutable(program):
                 available = True
-        
+
         return available
-    
+
     def __crossCompile(self, pythonFile="", title=""):
         """
         Private method to cross compile a Python file to a .mpy file.
-        
+
         @param pythonFile name of the Python file to be compiled
         @type str
         @param title title for the various dialogs
@@ -1669,12 +1728,15 @@
                 EricMessageBox.critical(
                     self,
                     title,
-                    self.tr("""The MicroPython cross compiler"""
-                            """ <b>mpy-cross</b> cannot be found. Ensure it"""
-                            """ is in the search path or configure it on"""
-                            """ the MicroPython configuration page."""))
+                    self.tr(
+                        """The MicroPython cross compiler"""
+                        """ <b>mpy-cross</b> cannot be found. Ensure it"""
+                        """ is in the search path or configure it on"""
+                        """ the MicroPython configuration page."""
+                    ),
+                )
                 return
-        
+
         if not pythonFile:
             defaultDirectory = ""
             aw = ericApp().getObject("ViewManager").activeWindow()
@@ -1684,27 +1746,30 @@
                     defaultDirectory = os.path.dirname(fn)
             if not defaultDirectory:
                 defaultDirectory = (
-                    Preferences.getMicroPython("MpyWorkspace") or
-                    Preferences.getMultiProject("Workspace") or
-                    os.path.expanduser("~")
+                    Preferences.getMicroPython("MpyWorkspace")
+                    or Preferences.getMultiProject("Workspace")
+                    or os.path.expanduser("~")
                 )
             pythonFile = EricFileDialog.getOpenFileName(
                 self,
                 title,
                 defaultDirectory,
-                self.tr("Python Files (*.py);;All Files (*)"))
+                self.tr("Python Files (*.py);;All Files (*)"),
+            )
             if not pythonFile:
                 # user cancelled
                 return
-        
+
         if not os.path.exists(pythonFile):
             EricMessageBox.critical(
                 self,
                 title,
-                self.tr("""The Python file <b>{0}</b> does not exist."""
-                        """ Aborting...""").format(pythonFile))
+                self.tr(
+                    """The Python file <b>{0}</b> does not exist.""" """ Aborting..."""
+                ).format(pythonFile),
+            )
             return
-        
+
         compileArgs = [
             pythonFile,
         ]
@@ -1712,14 +1777,14 @@
         res = dlg.startProcess(program, compileArgs)
         if res:
             dlg.exec()
-    
+
     @pyqtSlot()
     def __compileFile2Mpy(self):
         """
         Private slot to cross compile a Python file (*.py) to a .mpy file.
         """
         self.__crossCompile(title=self.tr("Compile Python File"))
-    
+
     @pyqtSlot()
     def __compileEditor2Mpy(self):
         """
@@ -1734,15 +1799,17 @@
             EricMessageBox.critical(
                 self,
                 self.tr("Compile Current Editor"),
-                self.tr("""The current editor does not contain a Python"""
-                        """ file. Aborting..."""))
+                self.tr(
+                    """The current editor does not contain a Python"""
+                    """ file. Aborting..."""
+                ),
+            )
             return
-        
+
         self.__crossCompile(
-            pythonFile=aw.getFileName(),
-            title=self.tr("Compile Current Editor")
+            pythonFile=aw.getFileName(), title=self.tr("Compile Current Editor")
         )
-    
+
     @pyqtSlot()
     def __showDocumentation(self):
         """
@@ -1751,10 +1818,10 @@
         if self.__device is None or not self.__device.hasDocumentationUrl():
             # abort silently
             return
-        
+
         url = self.__device.getDocumentationUrl()
         ericApp().getObject("UserInterface").launchHelpViewer(url)
-    
+
     @pyqtSlot()
     def __downloadFirmware(self):
         """
@@ -1763,45 +1830,44 @@
         if self.__device is None or not self.__device.hasFirmwareUrl():
             # abort silently
             return
-        
+
         self.__device.downloadFirmware()
-    
+
     def __downloadFromUrl(self, url):
         """
         Private method to open a web browser for the given URL.
-        
+
         @param url URL to be opened
         @type str
         """
         if self.__device is None:
             # abort silently
             return
-        
+
         if url:
             ericApp().getObject("UserInterface").launchHelpViewer(url)
-    
+
     @pyqtSlot()
     def __manageIgnored(self):
         """
         Private slot to manage the list of ignored serial devices.
         """
         from .IgnoredDevicesDialog import IgnoredDevicesDialog
-        
+
         dlg = IgnoredDevicesDialog(
-            Preferences.getMicroPython("IgnoredUnknownDevices"),
-            self)
+            Preferences.getMicroPython("IgnoredUnknownDevices"), self
+        )
         if dlg.exec() == QDialog.DialogCode.Accepted:
             ignoredDevices = dlg.getDevices()
-            Preferences.setMicroPython("IgnoredUnknownDevices",
-                                       ignoredDevices)
-    
+            Preferences.setMicroPython("IgnoredUnknownDevices", ignoredDevices)
+
     @pyqtSlot()
     def __configure(self):
         """
         Private slot to open the MicroPython configuration page.
         """
         ericApp().getObject("UserInterface").showPreferences("microPythonPage")
-    
+
     @pyqtSlot()
     def __manageUnknownDevices(self):
         """
@@ -1809,33 +1875,33 @@
         list of supported boards).
         """
         from .UnknownDevicesDialog import UnknownDevicesDialog
+
         dlg = UnknownDevicesDialog()
         dlg.exec()
-    
+
     def __addUnknownDevices(self, devices):
         """
         Private method to add devices to the list of manually added boards.
-        
+
         @param devices list of not ignored but unknown devices
         @type list of tuple of (int, int, str)
         """
         from .AddEditDevicesDialog import AddEditDevicesDialog
-        
+
         if len(devices) > 1:
-            from EricWidgets.EricListSelectionDialog import (
-                EricListSelectionDialog
-            )
+            from EricWidgets.EricListSelectionDialog import EricListSelectionDialog
+
             sdlg = EricListSelectionDialog(
                 [d[2] for d in devices],
                 title=self.tr("Add Unknown Devices"),
                 message=self.tr("Select the devices to be added:"),
-                checkBoxSelection=True
+                checkBoxSelection=True,
             )
             if sdlg.exec() == QDialog.DialogCode.Accepted:
                 selectedDevices = sdlg.getSelection()
         else:
             selectedDevices = devices[0][2]
-        
+
         if selectedDevices:
             manualDevices = Preferences.getMicroPython("ManualDevices")
             for vid, pid, description in devices:
@@ -1844,10 +1910,10 @@
                     if dlg.exec() == QDialog.DialogCode.Accepted:
                         manualDevices.append(dlg.getDeviceDict())
             Preferences.setMicroPython("ManualDevices", manualDevices)
-            
+
             # rescan the ports
             self.__populateDeviceTypeComboBox()
-    
+
     @pyqtSlot()
     def __flashUF2(self):
         """

eric ide

mercurial