Mon, 06 Feb 2023 10:09:18 +0100
MicroPython
- Added functionality to update modules of CircuitPython devices with `circup`
(adapted for use within eric-ide).
--- a/docs/changelog.md Mon Feb 06 10:02:35 2023 +0100 +++ b/docs/changelog.md Mon Feb 06 10:09:18 2023 +0100 @@ -6,6 +6,8 @@ - Updated the list of known CircuitPython boards. - Updated the list of known UF2 capable boards. - Some smaller enhancements for CircuitPython devices. + - Added functionality to update modules of CircuitPython devices with `circup` + (adapted for use within eric-ide). - PDF Viewer - added a tool based on `QtPdf` and `QtPdfWidgets` to show the contents of PDF files
--- a/eric7.epj Mon Feb 06 10:02:35 2023 +0100 +++ b/eric7.epj Mon Feb 06 10:09:18 2023 +0100 @@ -333,6 +333,11 @@ "src/eric7/JediInterface/RefactoringPreviewDialog.ui", "src/eric7/MicroPython/AddEditDevicesDialog.ui", "src/eric7/MicroPython/BoardDataDialog.ui", + "src/eric7/MicroPython/CircuitPythonUpdater/RequirementsDialog.ui", + "src/eric7/MicroPython/CircuitPythonUpdater/ShowBundlesDialog.ui", + "src/eric7/MicroPython/CircuitPythonUpdater/ShowInstalledDialog.ui", + "src/eric7/MicroPython/CircuitPythonUpdater/ShowModulesDialog.ui", + "src/eric7/MicroPython/CircuitPythonUpdater/ShowOutdatedDialog.ui", "src/eric7/MicroPython/ConnectionSelectionDialog.ui", "src/eric7/MicroPython/EspBackupRestoreFirmwareDialog.ui", "src/eric7/MicroPython/EspFirmwareSelectionDialog.ui", @@ -1276,6 +1281,14 @@ "src/eric7/MicroPython/AddEditDevicesDialog.py", "src/eric7/MicroPython/BoardDataDialog.py", "src/eric7/MicroPython/CircuitPythonDevices.py", + "src/eric7/MicroPython/CircuitPythonUpdater/CircuitPythonUpdaterInterface.py", + "src/eric7/MicroPython/CircuitPythonUpdater/CircupFunctions.py", + "src/eric7/MicroPython/CircuitPythonUpdater/RequirementsDialog.py", + "src/eric7/MicroPython/CircuitPythonUpdater/ShowBundlesDialog.py", + "src/eric7/MicroPython/CircuitPythonUpdater/ShowInstalledDialog.py", + "src/eric7/MicroPython/CircuitPythonUpdater/ShowModulesDialog.py", + "src/eric7/MicroPython/CircuitPythonUpdater/ShowOutdatedDialog.py", + "src/eric7/MicroPython/CircuitPythonUpdater/__init__.py", "src/eric7/MicroPython/ConnectionSelectionDialog.py", "src/eric7/MicroPython/EspBackupRestoreFirmwareDialog.py", "src/eric7/MicroPython/EspDevices.py",
--- a/src/eric7/APIs/Python3/eric7.api Mon Feb 06 10:02:35 2023 +0100 +++ b/src/eric7/APIs/Python3/eric7.api Mon Feb 06 10:09:18 2023 +0100 @@ -2554,8 +2554,35 @@ eric7.MicroPython.CircuitPythonDevices.CircuitPythonDevice.runScript?4(script) eric7.MicroPython.CircuitPythonDevices.CircuitPythonDevice.setButtons?4() eric7.MicroPython.CircuitPythonDevices.CircuitPythonDevice.supportsLocalFileAccess?4() -eric7.MicroPython.CircuitPythonDevices.CircuitPythonDevice?1(microPythonWidget, deviceType, parent=None) -eric7.MicroPython.CircuitPythonDevices.createDevice?4(microPythonWidget, deviceType, vid, pid) +eric7.MicroPython.CircuitPythonDevices.CircuitPythonDevice?1(microPythonWidget, deviceType, boardName, parent=None) +eric7.MicroPython.CircuitPythonDevices.createDevice?4(microPythonWidget, deviceType, vid, pid, boardName) +eric7.MicroPython.CircuitPythonUpdater.CircuitPythonUpdaterInterface.CircuitPythonUpdaterInterface.installCircup?4() +eric7.MicroPython.CircuitPythonUpdater.CircuitPythonUpdaterInterface.CircuitPythonUpdaterInterface.populateMenu?4(menu) +eric7.MicroPython.CircuitPythonUpdater.CircuitPythonUpdaterInterface.CircuitPythonUpdaterInterface?1(device, parent=None) +eric7.MicroPython.CircuitPythonUpdater.CircuitPythonUpdaterInterface.isCircupAvailable?4() +eric7.MicroPython.CircuitPythonUpdater.CircupFunctions.ensure_latest_bundle?4(bundle) +eric7.MicroPython.CircuitPythonUpdater.CircupFunctions.find_modules?4(device_path, bundles_list) +eric7.MicroPython.CircuitPythonUpdater.CircupFunctions.get_circuitpython_version?4(device_path) +eric7.MicroPython.CircuitPythonUpdater.CircupFunctions.install_module?4(device_path, device_modules, name, py, mod_names) +eric7.MicroPython.CircuitPythonUpdater.CircupFunctions.patch_circup?4() +eric7.MicroPython.CircuitPythonUpdater.RequirementsDialog.RequirementsDialog.on_buttonBox_clicked?4(button) +eric7.MicroPython.CircuitPythonUpdater.RequirementsDialog.RequirementsDialog.on_copyButton_clicked?4() +eric7.MicroPython.CircuitPythonUpdater.RequirementsDialog.RequirementsDialog.on_insertButton_clicked?4() +eric7.MicroPython.CircuitPythonUpdater.RequirementsDialog.RequirementsDialog.on_replaceAllButton_clicked?4() +eric7.MicroPython.CircuitPythonUpdater.RequirementsDialog.RequirementsDialog.on_replaceSelectionButton_clicked?4() +eric7.MicroPython.CircuitPythonUpdater.RequirementsDialog.RequirementsDialog.on_requirementsEdit_textChanged?4() +eric7.MicroPython.CircuitPythonUpdater.RequirementsDialog.RequirementsDialog.on_requirementsFilePicker_textChanged?4(txt) +eric7.MicroPython.CircuitPythonUpdater.RequirementsDialog.RequirementsDialog.on_saveButton_clicked?4() +eric7.MicroPython.CircuitPythonUpdater.RequirementsDialog.RequirementsDialog.on_saveToButton_clicked?4() +eric7.MicroPython.CircuitPythonUpdater.RequirementsDialog.RequirementsDialog?1(devicePath, parent=None) +eric7.MicroPython.CircuitPythonUpdater.ShowBundlesDialog.ShowBundlesDialog?1(withModules, parent=None) +eric7.MicroPython.CircuitPythonUpdater.ShowInstalledDialog.ShowInstalledDialog?1(devicePath, parent=None) +eric7.MicroPython.CircuitPythonUpdater.ShowModulesDialog.ShowModulesDialog.getSelection?4() +eric7.MicroPython.CircuitPythonUpdater.ShowModulesDialog.ShowModulesDialog.on_modulesList_itemChanged?4(item) +eric7.MicroPython.CircuitPythonUpdater.ShowModulesDialog.ShowModulesDialog?1(selectionMode=False, parent=None) +eric7.MicroPython.CircuitPythonUpdater.ShowOutdatedDialog.ShowOutdatedDialog.getSelection?4() +eric7.MicroPython.CircuitPythonUpdater.ShowOutdatedDialog.ShowOutdatedDialog.on_modulesList_itemChanged?4(item, column) +eric7.MicroPython.CircuitPythonUpdater.ShowOutdatedDialog.ShowOutdatedDialog?1(devicePath, selectionMode=False, parent=None) eric7.MicroPython.ConnectionSelectionDialog.ConnectionSelectionDialog.PortNameRole?7 eric7.MicroPython.ConnectionSelectionDialog.ConnectionSelectionDialog.VidPidRole?7 eric7.MicroPython.ConnectionSelectionDialog.ConnectionSelectionDialog.getData?4() @@ -2583,7 +2610,7 @@ eric7.MicroPython.EspDevices.EspDevice.runScript?4(script) eric7.MicroPython.EspDevices.EspDevice.setButtons?4() eric7.MicroPython.EspDevices.EspDevice?1(microPythonWidget, deviceType, parent=None) -eric7.MicroPython.EspDevices.createDevice?4(microPythonWidget, deviceType, vid, pid) +eric7.MicroPython.EspDevices.createDevice?4(microPythonWidget, deviceType, vid, pid, boardName) eric7.MicroPython.EspFirmwareSelectionDialog.EspFirmwareSelectionDialog.Chips?7 eric7.MicroPython.EspFirmwareSelectionDialog.EspFirmwareSelectionDialog.FlashAddresses?7 eric7.MicroPython.EspFirmwareSelectionDialog.EspFirmwareSelectionDialog.FlashModes?7 @@ -2602,7 +2629,7 @@ eric7.MicroPython.GenericMicroPythonDevices.GenericMicroPythonDevice.setButtons?4() eric7.MicroPython.GenericMicroPythonDevices.GenericMicroPythonDevice.supportsLocalFileAccess?4() eric7.MicroPython.GenericMicroPythonDevices.GenericMicroPythonDevice?1(microPythonWidget, deviceType, vid, pid, parent=None) -eric7.MicroPython.GenericMicroPythonDevices.createDevice?4(microPythonWidget, deviceType, vid, pid) +eric7.MicroPython.GenericMicroPythonDevices.createDevice?4(microPythonWidget, deviceType, vid, pid, boardName) eric7.MicroPython.IgnoredDevicesDialog.IgnoredDevicesDialog.getDevices?4() eric7.MicroPython.IgnoredDevicesDialog.IgnoredDevicesDialog?1(deviceList, parent=None) eric7.MicroPython.MicroPythonCommandsInterface.MicroPythonCommandsInterface.cd?4(dirname) @@ -2661,7 +2688,7 @@ eric7.MicroPython.MicroPythonDevices.MicroPythonDevice.supportsLocalFileAccess?4() eric7.MicroPython.MicroPythonDevices.MicroPythonDevice?1(microPythonWidget, deviceType, parent=None) eric7.MicroPython.MicroPythonDevices.SupportedBoards?7 -eric7.MicroPython.MicroPythonDevices.getDevice?4(deviceType, microPythonWidget, vid, pid) +eric7.MicroPython.MicroPythonDevices.getDevice?4(deviceType, microPythonWidget, vid, pid, boardName="") eric7.MicroPython.MicroPythonDevices.getDeviceIcon?4(boardName, iconFormat=True) eric7.MicroPython.MicroPythonDevices.getFoundDevices?4() eric7.MicroPython.MicroPythonDevices.getSupportedDevices?4() @@ -2773,7 +2800,7 @@ eric7.MicroPython.MicrobitDevices.MicrobitDevice.runScript?4(script) eric7.MicroPython.MicrobitDevices.MicrobitDevice.setButtons?4() eric7.MicroPython.MicrobitDevices.MicrobitDevice?1(microPythonWidget, deviceType, parent=None) -eric7.MicroPython.MicrobitDevices.createDevice?4(microPythonWidget, deviceType, vid, pid) +eric7.MicroPython.MicrobitDevices.createDevice?4(microPythonWidget, deviceType, vid, pid, boardName) eric7.MicroPython.PyBoardDevices.PyBoardDevice.DeviceVolumeName?7 eric7.MicroPython.PyBoardDevices.PyBoardDevice.FlashInstructionsURL?7 eric7.MicroPython.PyBoardDevices.PyBoardDevice.addDeviceMenuEntries?4(menu) @@ -2791,7 +2818,7 @@ eric7.MicroPython.PyBoardDevices.PyBoardDevice.setButtons?4() eric7.MicroPython.PyBoardDevices.PyBoardDevice.supportsLocalFileAccess?4() eric7.MicroPython.PyBoardDevices.PyBoardDevice?1(microPythonWidget, deviceType, parent=None) -eric7.MicroPython.PyBoardDevices.createDevice?4(microPythonWidget, deviceType, vid, pid) +eric7.MicroPython.PyBoardDevices.createDevice?4(microPythonWidget, deviceType, vid, pid, boardName) eric7.MicroPython.RP2040Devices.RP2040Device.addDeviceMenuEntries?4(menu) eric7.MicroPython.RP2040Devices.RP2040Device.canRunScript?4() eric7.MicroPython.RP2040Devices.RP2040Device.canStartFileManager?4() @@ -2805,7 +2832,7 @@ eric7.MicroPython.RP2040Devices.RP2040Device.runScript?4(script) eric7.MicroPython.RP2040Devices.RP2040Device.setButtons?4() eric7.MicroPython.RP2040Devices.RP2040Device?1(microPythonWidget, deviceType, parent=None) -eric7.MicroPython.RP2040Devices.createDevice?4(microPythonWidget, deviceType, vid, pid) +eric7.MicroPython.RP2040Devices.createDevice?4(microPythonWidget, deviceType, vid, pid, boardName) eric7.MicroPython.UF2FlashDialog.SupportedUF2Boards?7 eric7.MicroPython.UF2FlashDialog.UF2FlashDialog.DeviceTypeRole?7 eric7.MicroPython.UF2FlashDialog.UF2FlashDialog.DeviceVidPidRole?7
--- a/src/eric7/APIs/Python3/eric7.bas Mon Feb 06 10:02:35 2023 +0100 +++ b/src/eric7/APIs/Python3/eric7.bas Mon Feb 06 10:09:18 2023 +0100 @@ -80,6 +80,7 @@ ChatWidget QWidget Ui_ChatWidget ChromeImporter BookmarksImporter CircuitPythonDevice MicroPythonDevice +CircuitPythonUpdaterInterface QObject Class ClbrBaseClasses.Class VisibilityMixin ClassDecoratorType enum.Enum ClassItem UMLItem @@ -856,6 +857,7 @@ ReloadStopButton EricToolButton RemoveBookmarksCommand QUndoCommand ReqPackage Package +RequirementsDialog QDialog Ui_RequirementsDialog RestructuredTextProvider MarkupBase ReturnVisitor ast.NodeVisitor ReversedPackageDAG PackageDAG @@ -892,6 +894,10 @@ ShortcutsDialog QDialog Ui_ShortcutsDialog ShortcutsFile QObject ShortcutsReader XMLStreamReaderBase +ShowBundlesDialog QDialog Ui_ShowBundlesDialog +ShowInstalledDialog QDialog Ui_ShowInstalledDialog +ShowModulesDialog QDialog Ui_ShowModulesDialog +ShowOutdatedDialog QDialog Ui_ShowOutdatedDialog SimplePatternExtension Extension SimplifyNodeVisitor ast.NodeVisitor SingleApplicationServer QLocalServer
--- a/src/eric7/Documentation/Help/source.qhp Mon Feb 06 10:02:35 2023 +0100 +++ b/src/eric7/Documentation/Help/source.qhp Mon Feb 06 10:09:18 2023 +0100 @@ -267,6 +267,15 @@ <section title="eric7.JediInterface.RefactoringPreviewDialog" ref="eric7.JediInterface.RefactoringPreviewDialog.html" /> </section> <section title="eric7.MicroPython" ref="index-eric7.MicroPython.html"> + <section title="eric7.MicroPython.CircuitPythonUpdater" ref="index-eric7.MicroPython.CircuitPythonUpdater.html"> + <section title="eric7.MicroPython.CircuitPythonUpdater.CircuitPythonUpdaterInterface" ref="eric7.MicroPython.CircuitPythonUpdater.CircuitPythonUpdaterInterface.html" /> + <section title="eric7.MicroPython.CircuitPythonUpdater.CircupFunctions" ref="eric7.MicroPython.CircuitPythonUpdater.CircupFunctions.html" /> + <section title="eric7.MicroPython.CircuitPythonUpdater.RequirementsDialog" ref="eric7.MicroPython.CircuitPythonUpdater.RequirementsDialog.html" /> + <section title="eric7.MicroPython.CircuitPythonUpdater.ShowBundlesDialog" ref="eric7.MicroPython.CircuitPythonUpdater.ShowBundlesDialog.html" /> + <section title="eric7.MicroPython.CircuitPythonUpdater.ShowInstalledDialog" ref="eric7.MicroPython.CircuitPythonUpdater.ShowInstalledDialog.html" /> + <section title="eric7.MicroPython.CircuitPythonUpdater.ShowModulesDialog" ref="eric7.MicroPython.CircuitPythonUpdater.ShowModulesDialog.html" /> + <section title="eric7.MicroPython.CircuitPythonUpdater.ShowOutdatedDialog" ref="eric7.MicroPython.CircuitPythonUpdater.ShowOutdatedDialog.html" /> + </section> <section title="eric7.MicroPython.AddEditDevicesDialog" ref="eric7.MicroPython.AddEditDevicesDialog.html" /> <section title="eric7.MicroPython.BoardDataDialog" ref="eric7.MicroPython.BoardDataDialog.html" /> <section title="eric7.MicroPython.CircuitPythonDevices" ref="eric7.MicroPython.CircuitPythonDevices.html" /> @@ -2684,7 +2693,9 @@ <keyword name="ChromeImporter.setPath" id="ChromeImporter.setPath" ref="eric7.WebBrowser.Bookmarks.BookmarksImporters.ChromeImporter.html#ChromeImporter.setPath" /> <keyword name="CircuitPythonDevice" id="CircuitPythonDevice" ref="eric7.MicroPython.CircuitPythonDevices.html#CircuitPythonDevice" /> <keyword name="CircuitPythonDevice (Constructor)" id="CircuitPythonDevice (Constructor)" ref="eric7.MicroPython.CircuitPythonDevices.html#CircuitPythonDevice.__init__" /> + <keyword name="CircuitPythonDevice.__aboutToShowLibraryMenu" id="CircuitPythonDevice.__aboutToShowLibraryMenu" ref="eric7.MicroPython.CircuitPythonDevices.html#CircuitPythonDevice.__aboutToShowLibraryMenu" /> <keyword name="CircuitPythonDevice.__deviceVolumeMounted" id="CircuitPythonDevice.__deviceVolumeMounted" ref="eric7.MicroPython.CircuitPythonDevices.html#CircuitPythonDevice.__deviceVolumeMounted" /> + <keyword name="CircuitPythonDevice.__findDeviceDirectories" id="CircuitPythonDevice.__findDeviceDirectories" ref="eric7.MicroPython.CircuitPythonDevices.html#CircuitPythonDevice.__findDeviceDirectories" /> <keyword name="CircuitPythonDevice.__findWorkspace" id="CircuitPythonDevice.__findWorkspace" ref="eric7.MicroPython.CircuitPythonDevices.html#CircuitPythonDevice.__findWorkspace" /> <keyword name="CircuitPythonDevice.__flashCircuitPython" id="CircuitPythonDevice.__flashCircuitPython" ref="eric7.MicroPython.CircuitPythonDevices.html#CircuitPythonDevice.__flashCircuitPython" /> <keyword name="CircuitPythonDevice.__flashTeensy" id="CircuitPythonDevice.__flashTeensy" ref="eric7.MicroPython.CircuitPythonDevices.html#CircuitPythonDevice.__flashTeensy" /> @@ -2704,6 +2715,30 @@ <keyword name="CircuitPythonDevice.setButtons" id="CircuitPythonDevice.setButtons" ref="eric7.MicroPython.CircuitPythonDevices.html#CircuitPythonDevice.setButtons" /> <keyword name="CircuitPythonDevice.supportsLocalFileAccess" id="CircuitPythonDevice.supportsLocalFileAccess" ref="eric7.MicroPython.CircuitPythonDevices.html#CircuitPythonDevice.supportsLocalFileAccess" /> <keyword name="CircuitPythonDevices (Module)" id="CircuitPythonDevices (Module)" ref="eric7.MicroPython.CircuitPythonDevices.html" /> + <keyword name="CircuitPythonUpdater (Package)" id="CircuitPythonUpdater (Package)" ref="index-eric7.MicroPython.CircuitPythonUpdater.html" /> + <keyword name="CircuitPythonUpdaterInterface" id="CircuitPythonUpdaterInterface" ref="eric7.MicroPython.CircuitPythonUpdater.CircuitPythonUpdaterInterface.html#CircuitPythonUpdaterInterface" /> + <keyword name="CircuitPythonUpdaterInterface (Constructor)" id="CircuitPythonUpdaterInterface (Constructor)" ref="eric7.MicroPython.CircuitPythonUpdater.CircuitPythonUpdaterInterface.html#CircuitPythonUpdaterInterface.__init__" /> + <keyword name="CircuitPythonUpdaterInterface (Module)" id="CircuitPythonUpdaterInterface (Module)" ref="eric7.MicroPython.CircuitPythonUpdater.CircuitPythonUpdaterInterface.html" /> + <keyword name="CircuitPythonUpdaterInterface.__aboutCircup" id="CircuitPythonUpdaterInterface.__aboutCircup" ref="eric7.MicroPython.CircuitPythonUpdater.CircuitPythonUpdaterInterface.html#CircuitPythonUpdaterInterface.__aboutCircup" /> + <keyword name="CircuitPythonUpdaterInterface.__addBundle" id="CircuitPythonUpdaterInterface.__addBundle" ref="eric7.MicroPython.CircuitPythonUpdater.CircuitPythonUpdaterInterface.html#CircuitPythonUpdaterInterface.__addBundle" /> + <keyword name="CircuitPythonUpdaterInterface.__doUpdateModules" id="CircuitPythonUpdaterInterface.__doUpdateModules" ref="eric7.MicroPython.CircuitPythonUpdater.CircuitPythonUpdaterInterface.html#CircuitPythonUpdaterInterface.__doUpdateModules" /> + <keyword name="CircuitPythonUpdaterInterface.__generateRequirements" id="CircuitPythonUpdaterInterface.__generateRequirements" ref="eric7.MicroPython.CircuitPythonUpdater.CircuitPythonUpdaterInterface.html#CircuitPythonUpdaterInterface.__generateRequirements" /> + <keyword name="CircuitPythonUpdaterInterface.__installFromAvailable" id="CircuitPythonUpdaterInterface.__installFromAvailable" ref="eric7.MicroPython.CircuitPythonUpdater.CircuitPythonUpdaterInterface.html#CircuitPythonUpdaterInterface.__installFromAvailable" /> + <keyword name="CircuitPythonUpdaterInterface.__installFromCode" id="CircuitPythonUpdaterInterface.__installFromCode" ref="eric7.MicroPython.CircuitPythonUpdater.CircuitPythonUpdaterInterface.html#CircuitPythonUpdaterInterface.__installFromCode" /> + <keyword name="CircuitPythonUpdaterInterface.__installModules" id="CircuitPythonUpdaterInterface.__installModules" ref="eric7.MicroPython.CircuitPythonUpdater.CircuitPythonUpdaterInterface.html#CircuitPythonUpdaterInterface.__installModules" /> + <keyword name="CircuitPythonUpdaterInterface.__installRequirements" id="CircuitPythonUpdaterInterface.__installRequirements" ref="eric7.MicroPython.CircuitPythonUpdater.CircuitPythonUpdaterInterface.html#CircuitPythonUpdaterInterface.__installRequirements" /> + <keyword name="CircuitPythonUpdaterInterface.__listOutdatedModules" id="CircuitPythonUpdaterInterface.__listOutdatedModules" ref="eric7.MicroPython.CircuitPythonUpdater.CircuitPythonUpdaterInterface.html#CircuitPythonUpdaterInterface.__listOutdatedModules" /> + <keyword name="CircuitPythonUpdaterInterface.__removeBundle" id="CircuitPythonUpdaterInterface.__removeBundle" ref="eric7.MicroPython.CircuitPythonUpdater.CircuitPythonUpdaterInterface.html#CircuitPythonUpdaterInterface.__removeBundle" /> + <keyword name="CircuitPythonUpdaterInterface.__showAvailableModules" id="CircuitPythonUpdaterInterface.__showAvailableModules" ref="eric7.MicroPython.CircuitPythonUpdater.CircuitPythonUpdaterInterface.html#CircuitPythonUpdaterInterface.__showAvailableModules" /> + <keyword name="CircuitPythonUpdaterInterface.__showBundles" id="CircuitPythonUpdaterInterface.__showBundles" ref="eric7.MicroPython.CircuitPythonUpdater.CircuitPythonUpdaterInterface.html#CircuitPythonUpdaterInterface.__showBundles" /> + <keyword name="CircuitPythonUpdaterInterface.__showBundlesModules" id="CircuitPythonUpdaterInterface.__showBundlesModules" ref="eric7.MicroPython.CircuitPythonUpdater.CircuitPythonUpdaterInterface.html#CircuitPythonUpdaterInterface.__showBundlesModules" /> + <keyword name="CircuitPythonUpdaterInterface.__showInstalledModules" id="CircuitPythonUpdaterInterface.__showInstalledModules" ref="eric7.MicroPython.CircuitPythonUpdater.CircuitPythonUpdaterInterface.html#CircuitPythonUpdaterInterface.__showInstalledModules" /> + <keyword name="CircuitPythonUpdaterInterface.__uninstallModules" id="CircuitPythonUpdaterInterface.__uninstallModules" ref="eric7.MicroPython.CircuitPythonUpdater.CircuitPythonUpdaterInterface.html#CircuitPythonUpdaterInterface.__uninstallModules" /> + <keyword name="CircuitPythonUpdaterInterface.__updateAllModules" id="CircuitPythonUpdaterInterface.__updateAllModules" ref="eric7.MicroPython.CircuitPythonUpdater.CircuitPythonUpdaterInterface.html#CircuitPythonUpdaterInterface.__updateAllModules" /> + <keyword name="CircuitPythonUpdaterInterface.__updateModules" id="CircuitPythonUpdaterInterface.__updateModules" ref="eric7.MicroPython.CircuitPythonUpdater.CircuitPythonUpdaterInterface.html#CircuitPythonUpdaterInterface.__updateModules" /> + <keyword name="CircuitPythonUpdaterInterface.installCircup" id="CircuitPythonUpdaterInterface.installCircup" ref="eric7.MicroPython.CircuitPythonUpdater.CircuitPythonUpdaterInterface.html#CircuitPythonUpdaterInterface.installCircup" /> + <keyword name="CircuitPythonUpdaterInterface.populateMenu" id="CircuitPythonUpdaterInterface.populateMenu" ref="eric7.MicroPython.CircuitPythonUpdater.CircuitPythonUpdaterInterface.html#CircuitPythonUpdaterInterface.populateMenu" /> + <keyword name="CircupFunctions (Module)" id="CircupFunctions (Module)" ref="eric7.MicroPython.CircuitPythonUpdater.CircupFunctions.html" /> <keyword name="Class" id="Class" ref="eric7.Utilities.ClassBrowsers.ClbrBaseClasses.html#Class" /> <keyword name="Class" id="Class" ref="eric7.Utilities.ClassBrowsers.pyclbr.html#Class" /> <keyword name="Class" id="Class" ref="eric7.Utilities.ClassBrowsers.rbclbr.html#Class" /> @@ -13637,6 +13672,21 @@ <keyword name="ReqPackage.render_as_branch" id="ReqPackage.render_as_branch" ref="eric7.PipInterface.pipdeptree.html#ReqPackage.render_as_branch" /> <keyword name="ReqPackage.render_as_root" id="ReqPackage.render_as_root" ref="eric7.PipInterface.pipdeptree.html#ReqPackage.render_as_root" /> <keyword name="ReqPackage.version_spec" id="ReqPackage.version_spec" ref="eric7.PipInterface.pipdeptree.html#ReqPackage.version_spec" /> + <keyword name="RequirementsDialog" id="RequirementsDialog" ref="eric7.MicroPython.CircuitPythonUpdater.RequirementsDialog.html#RequirementsDialog" /> + <keyword name="RequirementsDialog (Constructor)" id="RequirementsDialog (Constructor)" ref="eric7.MicroPython.CircuitPythonUpdater.RequirementsDialog.html#RequirementsDialog.__init__" /> + <keyword name="RequirementsDialog (Module)" id="RequirementsDialog (Module)" ref="eric7.MicroPython.CircuitPythonUpdater.RequirementsDialog.html" /> + <keyword name="RequirementsDialog.__generateRequirements" id="RequirementsDialog.__generateRequirements" ref="eric7.MicroPython.CircuitPythonUpdater.RequirementsDialog.html#RequirementsDialog.__generateRequirements" /> + <keyword name="RequirementsDialog.__updateButtons" id="RequirementsDialog.__updateButtons" ref="eric7.MicroPython.CircuitPythonUpdater.RequirementsDialog.html#RequirementsDialog.__updateButtons" /> + <keyword name="RequirementsDialog.__writeToFile" id="RequirementsDialog.__writeToFile" ref="eric7.MicroPython.CircuitPythonUpdater.RequirementsDialog.html#RequirementsDialog.__writeToFile" /> + <keyword name="RequirementsDialog.on_buttonBox_clicked" id="RequirementsDialog.on_buttonBox_clicked" ref="eric7.MicroPython.CircuitPythonUpdater.RequirementsDialog.html#RequirementsDialog.on_buttonBox_clicked" /> + <keyword name="RequirementsDialog.on_copyButton_clicked" id="RequirementsDialog.on_copyButton_clicked" ref="eric7.MicroPython.CircuitPythonUpdater.RequirementsDialog.html#RequirementsDialog.on_copyButton_clicked" /> + <keyword name="RequirementsDialog.on_insertButton_clicked" id="RequirementsDialog.on_insertButton_clicked" ref="eric7.MicroPython.CircuitPythonUpdater.RequirementsDialog.html#RequirementsDialog.on_insertButton_clicked" /> + <keyword name="RequirementsDialog.on_replaceAllButton_clicked" id="RequirementsDialog.on_replaceAllButton_clicked" ref="eric7.MicroPython.CircuitPythonUpdater.RequirementsDialog.html#RequirementsDialog.on_replaceAllButton_clicked" /> + <keyword name="RequirementsDialog.on_replaceSelectionButton_clicked" id="RequirementsDialog.on_replaceSelectionButton_clicked" ref="eric7.MicroPython.CircuitPythonUpdater.RequirementsDialog.html#RequirementsDialog.on_replaceSelectionButton_clicked" /> + <keyword name="RequirementsDialog.on_requirementsEdit_textChanged" id="RequirementsDialog.on_requirementsEdit_textChanged" ref="eric7.MicroPython.CircuitPythonUpdater.RequirementsDialog.html#RequirementsDialog.on_requirementsEdit_textChanged" /> + <keyword name="RequirementsDialog.on_requirementsFilePicker_textChanged" id="RequirementsDialog.on_requirementsFilePicker_textChanged" ref="eric7.MicroPython.CircuitPythonUpdater.RequirementsDialog.html#RequirementsDialog.on_requirementsFilePicker_textChanged" /> + <keyword name="RequirementsDialog.on_saveButton_clicked" id="RequirementsDialog.on_saveButton_clicked" ref="eric7.MicroPython.CircuitPythonUpdater.RequirementsDialog.html#RequirementsDialog.on_saveButton_clicked" /> + <keyword name="RequirementsDialog.on_saveToButton_clicked" id="RequirementsDialog.on_saveToButton_clicked" ref="eric7.MicroPython.CircuitPythonUpdater.RequirementsDialog.html#RequirementsDialog.on_saveToButton_clicked" /> <keyword name="RestructuredTextProvider" id="RestructuredTextProvider" ref="eric7.QScintilla.MarkupProviders.RestructuredTextProvider.html#RestructuredTextProvider" /> <keyword name="RestructuredTextProvider (Constructor)" id="RestructuredTextProvider (Constructor)" ref="eric7.QScintilla.MarkupProviders.RestructuredTextProvider.html#RestructuredTextProvider.__init__" /> <keyword name="RestructuredTextProvider (Module)" id="RestructuredTextProvider (Module)" ref="eric7.QScintilla.MarkupProviders.RestructuredTextProvider.html" /> @@ -14330,6 +14380,25 @@ <keyword name="ShortcutsReader.__readShortCut" id="ShortcutsReader.__readShortCut" ref="eric7.EricXML.ShortcutsReader.html#ShortcutsReader.__readShortCut" /> <keyword name="ShortcutsReader.getShortcuts" id="ShortcutsReader.getShortcuts" ref="eric7.EricXML.ShortcutsReader.html#ShortcutsReader.getShortcuts" /> <keyword name="ShortcutsReader.readXML" id="ShortcutsReader.readXML" ref="eric7.EricXML.ShortcutsReader.html#ShortcutsReader.readXML" /> + <keyword name="ShowBundlesDialog" id="ShowBundlesDialog" ref="eric7.MicroPython.CircuitPythonUpdater.ShowBundlesDialog.html#ShowBundlesDialog" /> + <keyword name="ShowBundlesDialog (Constructor)" id="ShowBundlesDialog (Constructor)" ref="eric7.MicroPython.CircuitPythonUpdater.ShowBundlesDialog.html#ShowBundlesDialog.__init__" /> + <keyword name="ShowBundlesDialog (Module)" id="ShowBundlesDialog (Module)" ref="eric7.MicroPython.CircuitPythonUpdater.ShowBundlesDialog.html" /> + <keyword name="ShowInstalledDialog" id="ShowInstalledDialog" ref="eric7.MicroPython.CircuitPythonUpdater.ShowInstalledDialog.html#ShowInstalledDialog" /> + <keyword name="ShowInstalledDialog (Constructor)" id="ShowInstalledDialog (Constructor)" ref="eric7.MicroPython.CircuitPythonUpdater.ShowInstalledDialog.html#ShowInstalledDialog.__init__" /> + <keyword name="ShowInstalledDialog (Module)" id="ShowInstalledDialog (Module)" ref="eric7.MicroPython.CircuitPythonUpdater.ShowInstalledDialog.html" /> + <keyword name="ShowModulesDialog" id="ShowModulesDialog" ref="eric7.MicroPython.CircuitPythonUpdater.ShowModulesDialog.html#ShowModulesDialog" /> + <keyword name="ShowModulesDialog (Constructor)" id="ShowModulesDialog (Constructor)" ref="eric7.MicroPython.CircuitPythonUpdater.ShowModulesDialog.html#ShowModulesDialog.__init__" /> + <keyword name="ShowModulesDialog (Module)" id="ShowModulesDialog (Module)" ref="eric7.MicroPython.CircuitPythonUpdater.ShowModulesDialog.html" /> + <keyword name="ShowModulesDialog.__applyFilter" id="ShowModulesDialog.__applyFilter" ref="eric7.MicroPython.CircuitPythonUpdater.ShowModulesDialog.html#ShowModulesDialog.__applyFilter" /> + <keyword name="ShowModulesDialog.__checkCountUpdated" id="ShowModulesDialog.__checkCountUpdated" ref="eric7.MicroPython.CircuitPythonUpdater.ShowModulesDialog.html#ShowModulesDialog.__checkCountUpdated" /> + <keyword name="ShowModulesDialog.getSelection" id="ShowModulesDialog.getSelection" ref="eric7.MicroPython.CircuitPythonUpdater.ShowModulesDialog.html#ShowModulesDialog.getSelection" /> + <keyword name="ShowModulesDialog.on_modulesList_itemChanged" id="ShowModulesDialog.on_modulesList_itemChanged" ref="eric7.MicroPython.CircuitPythonUpdater.ShowModulesDialog.html#ShowModulesDialog.on_modulesList_itemChanged" /> + <keyword name="ShowOutdatedDialog" id="ShowOutdatedDialog" ref="eric7.MicroPython.CircuitPythonUpdater.ShowOutdatedDialog.html#ShowOutdatedDialog" /> + <keyword name="ShowOutdatedDialog (Constructor)" id="ShowOutdatedDialog (Constructor)" ref="eric7.MicroPython.CircuitPythonUpdater.ShowOutdatedDialog.html#ShowOutdatedDialog.__init__" /> + <keyword name="ShowOutdatedDialog (Module)" id="ShowOutdatedDialog (Module)" ref="eric7.MicroPython.CircuitPythonUpdater.ShowOutdatedDialog.html" /> + <keyword name="ShowOutdatedDialog.__checkCountUpdated" id="ShowOutdatedDialog.__checkCountUpdated" ref="eric7.MicroPython.CircuitPythonUpdater.ShowOutdatedDialog.html#ShowOutdatedDialog.__checkCountUpdated" /> + <keyword name="ShowOutdatedDialog.getSelection" id="ShowOutdatedDialog.getSelection" ref="eric7.MicroPython.CircuitPythonUpdater.ShowOutdatedDialog.html#ShowOutdatedDialog.getSelection" /> + <keyword name="ShowOutdatedDialog.on_modulesList_itemChanged" id="ShowOutdatedDialog.on_modulesList_itemChanged" ref="eric7.MicroPython.CircuitPythonUpdater.ShowOutdatedDialog.html#ShowOutdatedDialog.on_modulesList_itemChanged" /> <keyword name="SimplePatternExtension" id="SimplePatternExtension" ref="eric7.UI.Previewers.MarkdownExtensions.html#SimplePatternExtension" /> <keyword name="SimplePatternExtension.extendMarkdown" id="SimplePatternExtension.extendMarkdown" ref="eric7.UI.Previewers.MarkdownExtensions.html#SimplePatternExtension.extendMarkdown" /> <keyword name="Simplify (Package)" id="Simplify (Package)" ref="index-eric7.Plugins.CheckerPlugins.CodeStyleChecker.Simplify.html" /> @@ -18991,6 +19060,7 @@ <keyword name="encryptData" id="encryptData" ref="eric7.Utilities.crypto.py3AES.html#encryptData" /> <keyword name="engineDisplayName" id="engineDisplayName" ref="eric7.Plugins.UiExtensionPlugins.Translator.TranslatorEngines.__init__.html#engineDisplayName" /> <keyword name="ensureUniqueFilename" id="ensureUniqueFilename" ref="eric7.WebBrowser.Tools.WebBrowserTools.html#ensureUniqueFilename" /> + <keyword name="ensure_latest_bundle" id="ensure_latest_bundle" ref="eric7.MicroPython.CircuitPythonUpdater.CircupFunctions.html#ensure_latest_bundle" /> <keyword name="enum_key_to_value" id="enum_key_to_value" ref="eric7.PipInterface.piplicenses.html#enum_key_to_value" /> <keyword name="eradicate (Module)" id="eradicate (Module)" ref="eric7.Plugins.CheckerPlugins.CodeStyleChecker.Miscellaneous.eradicate.html" /> <keyword name="eric6SettingsName" id="eric6SettingsName" ref="eric7.Preferences.__init__.html#eric6SettingsName" /> @@ -19057,6 +19127,7 @@ <keyword name="find_license_from_classifier" id="find_license_from_classifier" ref="eric7.PipInterface.piplicenses.html#find_license_from_classifier" /> <keyword name="find_module" id="find_module" ref="eric7.Utilities.ClassBrowsers.__init__.html#find_module" /> <keyword name="find_module" id="find_module" ref="eric7.Utilities.ModuleParser.html#find_module" /> + <keyword name="find_modules" id="find_modules" ref="eric7.MicroPython.CircuitPythonUpdater.CircupFunctions.html#find_modules" /> <keyword name="flaskDebug (Module)" id="flaskDebug (Module)" ref="eric7.Plugins.CheckerPlugins.CodeStyleChecker.Security.Checks.flaskDebug.html" /> <keyword name="formatTime" id="formatTime" ref="eric7.Plugins.VcsPlugins.vcsPySvn.SvnUtilities.html#formatTime" /> <keyword name="formatargvalues" id="formatargvalues" ref="eric7.DebugClients.Python.DebugUtilities.html#formatargvalues" /> @@ -19290,6 +19361,7 @@ <keyword name="getWebEngineVersions" id="getWebEngineVersions" ref="eric7.WebBrowser.Tools.WebBrowserTools.html#getWebEngineVersions" /> <keyword name="getWindowsExecutablePath" id="getWindowsExecutablePath" ref="eric7.SystemUtilities.FileSystemUtilities.html#getWindowsExecutablePath" /> <keyword name="getWinregEntry" id="getWinregEntry" ref="eric7.eric7_post_install.html#getWinregEntry" /> + <keyword name="get_circuitpython_version" id="get_circuitpython_version" ref="eric7.MicroPython.CircuitPythonUpdater.CircupFunctions.html#get_circuitpython_version" /> <keyword name="get_class_members" id="get_class_members" ref="eric7.DebugClients.Python.FlexCompleter.html#get_class_members" /> <keyword name="get_coding" id="get_coding" ref="eric7.Utilities.__init__.html#get_coding" /> <keyword name="get_codingBytes" id="get_codingBytes" ref="eric7.Utilities.__init__.html#get_codingBytes" /> @@ -19353,6 +19425,7 @@ <keyword name="insecureHashlibNew (Module)" id="insecureHashlibNew (Module)" ref="eric7.Plugins.CheckerPlugins.CodeStyleChecker.Security.Checks.insecureHashlibNew.html" /> <keyword name="insecureSslTls (Module)" id="insecureSslTls (Module)" ref="eric7.Plugins.CheckerPlugins.CodeStyleChecker.Security.Checks.insecureSslTls.html" /> <keyword name="installGoogleAPIPackages" id="installGoogleAPIPackages" ref="eric7.EricNetwork.EricGoogleMailHelpers.html#installGoogleAPIPackages" /> + <keyword name="install_module" id="install_module" ref="eric7.MicroPython.CircuitPythonUpdater.CircupFunctions.html#install_module" /> <keyword name="instance" id="instance" ref="eric7.EricNetwork.EricTldExtractor.html#instance" /> <keyword name="instance" id="instance" ref="eric7.WebBrowser.Tools.WebIconProvider.html#instance" /> <keyword name="instance" id="instance" ref="eric7.WebBrowser.ZoomManager.ZoomManager.html#instance" /> @@ -19362,6 +19435,7 @@ <keyword name="isBaseString_1" id="isBaseString_1" ref="eric7.Plugins.CheckerPlugins.CodeStyleChecker.AstUtilities.html#isBaseString_1" /> <keyword name="isBytes" id="isBytes" ref="eric7.Plugins.CheckerPlugins.CodeStyleChecker.AstUtilities.html#isBytes" /> <keyword name="isBytes_1" id="isBytes_1" ref="eric7.Plugins.CheckerPlugins.CodeStyleChecker.AstUtilities.html#isBytes_1" /> + <keyword name="isCircupAvailable" id="isCircupAvailable" ref="eric7.MicroPython.CircuitPythonUpdater.CircuitPythonUpdaterInterface.html#isCircupAvailable" /> <keyword name="isClientSecretFileAvailable" id="isClientSecretFileAvailable" ref="eric7.EricNetwork.EricGoogleMailHelpers.html#isClientSecretFileAvailable" /> <keyword name="isCondaAvailable" id="isCondaAvailable" ref="eric7.CondaInterface.__init__.html#isCondaAvailable" /> <keyword name="isConfigured" id="isConfigured" ref="eric7.Preferences.__init__.html#isConfigured" /> @@ -19490,6 +19564,7 @@ <keyword name="patchNewProcessFunctions" id="patchNewProcessFunctions" ref="eric7.DebugClients.Python.MultiProcessDebugExtension.html#patchNewProcessFunctions" /> <keyword name="patchQProcess" id="patchQProcess" ref="eric7.DebugClients.Python.QProcessExtension.html#patchQProcess" /> <keyword name="patchSubprocess" id="patchSubprocess" ref="eric7.DebugClients.Python.SubprocessExtension.html#patchSubprocess" /> + <keyword name="patch_circup" id="patch_circup" ref="eric7.MicroPython.CircuitPythonUpdater.CircupFunctions.html#patch_circup" /> <keyword name="pbkdf2" id="pbkdf2" ref="eric7.Utilities.crypto.py3PBKDF2.html#pbkdf2" /> <keyword name="pipdeptree (Module)" id="pipdeptree (Module)" ref="eric7.PipInterface.pipdeptree.html" /> <keyword name="piplicenses (Module)" id="piplicenses (Module)" ref="eric7.PipInterface.piplicenses.html" /> @@ -19985,6 +20060,13 @@ <file>eric7.MicroPython.AddEditDevicesDialog.html</file> <file>eric7.MicroPython.BoardDataDialog.html</file> <file>eric7.MicroPython.CircuitPythonDevices.html</file> + <file>eric7.MicroPython.CircuitPythonUpdater.CircuitPythonUpdaterInterface.html</file> + <file>eric7.MicroPython.CircuitPythonUpdater.CircupFunctions.html</file> + <file>eric7.MicroPython.CircuitPythonUpdater.RequirementsDialog.html</file> + <file>eric7.MicroPython.CircuitPythonUpdater.ShowBundlesDialog.html</file> + <file>eric7.MicroPython.CircuitPythonUpdater.ShowInstalledDialog.html</file> + <file>eric7.MicroPython.CircuitPythonUpdater.ShowModulesDialog.html</file> + <file>eric7.MicroPython.CircuitPythonUpdater.ShowOutdatedDialog.html</file> <file>eric7.MicroPython.ConnectionSelectionDialog.html</file> <file>eric7.MicroPython.EspBackupRestoreFirmwareDialog.html</file> <file>eric7.MicroPython.EspDevices.html</file> @@ -20980,6 +21062,7 @@ <file>index-eric7.IconEditor.cursors.html</file> <file>index-eric7.IconEditor.html</file> <file>index-eric7.JediInterface.html</file> + <file>index-eric7.MicroPython.CircuitPythonUpdater.html</file> <file>index-eric7.MicroPython.html</file> <file>index-eric7.MultiProject.html</file> <file>index-eric7.Network.IRC.html</file>
--- a/src/eric7/Documentation/Source/eric7.MicroPython.CircuitPythonDevices.html Mon Feb 06 10:02:35 2023 +0100 +++ b/src/eric7/Documentation/Source/eric7.MicroPython.CircuitPythonDevices.html Mon Feb 06 10:09:18 2023 +0100 @@ -63,6 +63,10 @@ <td>Constructor</td> </tr> <tr> +<td><a href="#CircuitPythonDevice.__aboutToShowLibraryMenu">__aboutToShowLibraryMenu</a></td> +<td>Private slot to populate the 'Library Management' menu.</td> +</tr> +<tr> <td><a href="#CircuitPythonDevice.__deviceVolumeMounted">__deviceVolumeMounted</a></td> <td>Private method to check, if the device volume is mounted.</td> </tr> @@ -175,6 +179,13 @@ reference to the parent object </dd> </dl> +<a NAME="CircuitPythonDevice.__aboutToShowLibraryMenu" ID="CircuitPythonDevice.__aboutToShowLibraryMenu"></a> +<h4>CircuitPythonDevice.__aboutToShowLibraryMenu</h4> +<b>__aboutToShowLibraryMenu</b>(<i></i>) + +<p> + Private slot to populate the 'Library Management' menu. +</p> <a NAME="CircuitPythonDevice.__deviceVolumeMounted" ID="CircuitPythonDevice.__deviceVolumeMounted"></a> <h4>CircuitPythonDevice.__deviceVolumeMounted</h4> <b>__deviceVolumeMounted</b>(<i></i>)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/eric7/Documentation/Source/eric7.MicroPython.CircuitPythonUpdater.CircuitPythonUpdaterInterface.html Mon Feb 06 10:09:18 2023 +0100 @@ -0,0 +1,358 @@ +<!DOCTYPE html> +<html><head> +<title>eric7.MicroPython.CircuitPythonUpdater.CircuitPythonUpdaterInterface</title> +<meta charset="UTF-8"> +<link rel="stylesheet" href="styles.css"> +</head> +<body> +<a NAME="top" ID="top"></a> +<h1>eric7.MicroPython.CircuitPythonUpdater.CircuitPythonUpdaterInterface</h1> + +<p> +Module implementing an interface to the 'circup' package. +</p> +<h3>Global Attributes</h3> + +<table> +<tr><td>None</td></tr> +</table> +<h3>Classes</h3> + +<table> + +<tr> +<td><a href="#CircuitPythonUpdaterInterface">CircuitPythonUpdaterInterface</a></td> +<td>Class implementing an interface to the 'circup' package.</td> +</tr> +</table> +<h3>Functions</h3> + +<table> + +<tr> +<td><a href="#isCircupAvailable">isCircupAvailable</a></td> +<td>Function to check for the availability of 'circup'.</td> +</tr> +</table> +<hr /> +<hr /> +<a NAME="CircuitPythonUpdaterInterface" ID="CircuitPythonUpdaterInterface"></a> +<h2>CircuitPythonUpdaterInterface</h2> + +<p> + Class implementing an interface to the 'circup' package. +</p> +<h3>Derived from</h3> +QObject +<h3>Class Attributes</h3> + +<table> +<tr><td>None</td></tr> +</table> +<h3>Class Methods</h3> + +<table> +<tr><td>None</td></tr> +</table> +<h3>Methods</h3> + +<table> + +<tr> +<td><a href="#CircuitPythonUpdaterInterface.__init__">CircuitPythonUpdaterInterface</a></td> +<td>Constructor</td> +</tr> +<tr> +<td><a href="#CircuitPythonUpdaterInterface.__aboutCircup">__aboutCircup</a></td> +<td>Private slot to show some info about 'circup'.</td> +</tr> +<tr> +<td><a href="#CircuitPythonUpdaterInterface.__addBundle">__addBundle</a></td> +<td>Private slot to add a bundle to the local bundles list, by "user/repo" github string.</td> +</tr> +<tr> +<td><a href="#CircuitPythonUpdaterInterface.__doUpdateModules">__doUpdateModules</a></td> +<td>Private method to perform the update of a list of modules.</td> +</tr> +<tr> +<td><a href="#CircuitPythonUpdaterInterface.__generateRequirements">__generateRequirements</a></td> +<td>Private slot to generate requirements for the connected device.</td> +</tr> +<tr> +<td><a href="#CircuitPythonUpdaterInterface.__installFromAvailable">__installFromAvailable</a></td> +<td>Private slot to install modules onto the connected device.</td> +</tr> +<tr> +<td><a href="#CircuitPythonUpdaterInterface.__installFromCode">__installFromCode</a></td> +<td>Private slot to install modules based on the 'code.py' file of the connected device.</td> +</tr> +<tr> +<td><a href="#CircuitPythonUpdaterInterface.__installModules">__installModules</a></td> +<td>Private method to install the given list of modules.</td> +</tr> +<tr> +<td><a href="#CircuitPythonUpdaterInterface.__installRequirements">__installRequirements</a></td> +<td>Private slot to install modules determined by a requirements file.</td> +</tr> +<tr> +<td><a href="#CircuitPythonUpdaterInterface.__listOutdatedModules">__listOutdatedModules</a></td> +<td>Private slot to list the outdated modules of the connected device.</td> +</tr> +<tr> +<td><a href="#CircuitPythonUpdaterInterface.__removeBundle">__removeBundle</a></td> +<td>Private slot to remove one or more bundles from the local bundles list.</td> +</tr> +<tr> +<td><a href="#CircuitPythonUpdaterInterface.__showAvailableModules">__showAvailableModules</a></td> +<td>Private slot to show the available modules.</td> +</tr> +<tr> +<td><a href="#CircuitPythonUpdaterInterface.__showBundles">__showBundles</a></td> +<td>Private slot to show the available bundles (default and local).</td> +</tr> +<tr> +<td><a href="#CircuitPythonUpdaterInterface.__showBundlesModules">__showBundlesModules</a></td> +<td>Private slot to show the available bundles (default and local) with their modules.</td> +</tr> +<tr> +<td><a href="#CircuitPythonUpdaterInterface.__showInstalledModules">__showInstalledModules</a></td> +<td>Private slot to show the modules installed on the connected device.</td> +</tr> +<tr> +<td><a href="#CircuitPythonUpdaterInterface.__uninstallModules">__uninstallModules</a></td> +<td>Private slot to uninstall modules from the connected device.</td> +</tr> +<tr> +<td><a href="#CircuitPythonUpdaterInterface.__updateAllModules">__updateAllModules</a></td> +<td>Private slot to update all modules of the connected device.</td> +</tr> +<tr> +<td><a href="#CircuitPythonUpdaterInterface.__updateModules">__updateModules</a></td> +<td>Private slot to update the modules of the connected device.</td> +</tr> +<tr> +<td><a href="#CircuitPythonUpdaterInterface.installCircup">installCircup</a></td> +<td>Public slot to install the 'circup' package via pip.</td> +</tr> +<tr> +<td><a href="#CircuitPythonUpdaterInterface.populateMenu">populateMenu</a></td> +<td>Public method to populate the 'circup' menu.</td> +</tr> +</table> +<h3>Static Methods</h3> + +<table> +<tr><td>None</td></tr> +</table> + +<a NAME="CircuitPythonUpdaterInterface.__init__" ID="CircuitPythonUpdaterInterface.__init__"></a> +<h4>CircuitPythonUpdaterInterface (Constructor)</h4> +<b>CircuitPythonUpdaterInterface</b>(<i>device, parent=None</i>) + +<p> + Constructor +</p> +<dl> + +<dt><i>device</i> (CircuitPythonDevice)</dt> +<dd> +reference to the CircuitPython device interface +</dd> +<dt><i>parent</i> (QObject (optional))</dt> +<dd> +reference to the parent object (defaults to None) +</dd> +</dl> +<a NAME="CircuitPythonUpdaterInterface.__aboutCircup" ID="CircuitPythonUpdaterInterface.__aboutCircup"></a> +<h4>CircuitPythonUpdaterInterface.__aboutCircup</h4> +<b>__aboutCircup</b>(<i></i>) + +<p> + Private slot to show some info about 'circup'. +</p> +<a NAME="CircuitPythonUpdaterInterface.__addBundle" ID="CircuitPythonUpdaterInterface.__addBundle"></a> +<h4>CircuitPythonUpdaterInterface.__addBundle</h4> +<b>__addBundle</b>(<i></i>) + +<p> + Private slot to add a bundle to the local bundles list, by "user/repo" github + string. +</p> +<a NAME="CircuitPythonUpdaterInterface.__doUpdateModules" ID="CircuitPythonUpdaterInterface.__doUpdateModules"></a> +<h4>CircuitPythonUpdaterInterface.__doUpdateModules</h4> +<b>__doUpdateModules</b>(<i>modules</i>) + +<p> + Private method to perform the update of a list of modules. +</p> +<dl> + +<dt><i>modules</i> (circup.Module)</dt> +<dd> +list of modules to be updated +</dd> +</dl> +<a NAME="CircuitPythonUpdaterInterface.__generateRequirements" ID="CircuitPythonUpdaterInterface.__generateRequirements"></a> +<h4>CircuitPythonUpdaterInterface.__generateRequirements</h4> +<b>__generateRequirements</b>(<i></i>) + +<p> + Private slot to generate requirements for the connected device. +</p> +<a NAME="CircuitPythonUpdaterInterface.__installFromAvailable" ID="CircuitPythonUpdaterInterface.__installFromAvailable"></a> +<h4>CircuitPythonUpdaterInterface.__installFromAvailable</h4> +<b>__installFromAvailable</b>(<i></i>) + +<p> + Private slot to install modules onto the connected device. +</p> +<a NAME="CircuitPythonUpdaterInterface.__installFromCode" ID="CircuitPythonUpdaterInterface.__installFromCode"></a> +<h4>CircuitPythonUpdaterInterface.__installFromCode</h4> +<b>__installFromCode</b>(<i></i>) + +<p> + Private slot to install modules based on the 'code.py' file of the + connected device. +</p> +<a NAME="CircuitPythonUpdaterInterface.__installModules" ID="CircuitPythonUpdaterInterface.__installModules"></a> +<h4>CircuitPythonUpdaterInterface.__installModules</h4> +<b>__installModules</b>(<i>installs</i>) + +<p> + Private method to install the given list of modules. +</p> +<dl> + +<dt><i>installs</i> (list of str)</dt> +<dd> +list of module names to be installed +</dd> +</dl> +<a NAME="CircuitPythonUpdaterInterface.__installRequirements" ID="CircuitPythonUpdaterInterface.__installRequirements"></a> +<h4>CircuitPythonUpdaterInterface.__installRequirements</h4> +<b>__installRequirements</b>(<i></i>) + +<p> + Private slot to install modules determined by a requirements file. +</p> +<a NAME="CircuitPythonUpdaterInterface.__listOutdatedModules" ID="CircuitPythonUpdaterInterface.__listOutdatedModules"></a> +<h4>CircuitPythonUpdaterInterface.__listOutdatedModules</h4> +<b>__listOutdatedModules</b>(<i></i>) + +<p> + Private slot to list the outdated modules of the connected device. +</p> +<a NAME="CircuitPythonUpdaterInterface.__removeBundle" ID="CircuitPythonUpdaterInterface.__removeBundle"></a> +<h4>CircuitPythonUpdaterInterface.__removeBundle</h4> +<b>__removeBundle</b>(<i></i>) + +<p> + Private slot to remove one or more bundles from the local bundles list. +</p> +<a NAME="CircuitPythonUpdaterInterface.__showAvailableModules" ID="CircuitPythonUpdaterInterface.__showAvailableModules"></a> +<h4>CircuitPythonUpdaterInterface.__showAvailableModules</h4> +<b>__showAvailableModules</b>(<i></i>) + +<p> + Private slot to show the available modules. +</p> +<p> + These are modules which could be installed on the device. +</p> +<a NAME="CircuitPythonUpdaterInterface.__showBundles" ID="CircuitPythonUpdaterInterface.__showBundles"></a> +<h4>CircuitPythonUpdaterInterface.__showBundles</h4> +<b>__showBundles</b>(<i>withModules=False</i>) + +<p> + Private slot to show the available bundles (default and local). +</p> +<dl> + +<dt><i>withModules</i> (bool (optional))</dt> +<dd> +flag indicating to list the modules and their version + (defaults to False) +</dd> +</dl> +<a NAME="CircuitPythonUpdaterInterface.__showBundlesModules" ID="CircuitPythonUpdaterInterface.__showBundlesModules"></a> +<h4>CircuitPythonUpdaterInterface.__showBundlesModules</h4> +<b>__showBundlesModules</b>(<i></i>) + +<p> + Private slot to show the available bundles (default and local) with their + modules. +</p> +<a NAME="CircuitPythonUpdaterInterface.__showInstalledModules" ID="CircuitPythonUpdaterInterface.__showInstalledModules"></a> +<h4>CircuitPythonUpdaterInterface.__showInstalledModules</h4> +<b>__showInstalledModules</b>(<i></i>) + +<p> + Private slot to show the modules installed on the connected device. +</p> +<a NAME="CircuitPythonUpdaterInterface.__uninstallModules" ID="CircuitPythonUpdaterInterface.__uninstallModules"></a> +<h4>CircuitPythonUpdaterInterface.__uninstallModules</h4> +<b>__uninstallModules</b>(<i></i>) + +<p> + Private slot to uninstall modules from the connected device. +</p> +<a NAME="CircuitPythonUpdaterInterface.__updateAllModules" ID="CircuitPythonUpdaterInterface.__updateAllModules"></a> +<h4>CircuitPythonUpdaterInterface.__updateAllModules</h4> +<b>__updateAllModules</b>(<i></i>) + +<p> + Private slot to update all modules of the connected device. +</p> +<a NAME="CircuitPythonUpdaterInterface.__updateModules" ID="CircuitPythonUpdaterInterface.__updateModules"></a> +<h4>CircuitPythonUpdaterInterface.__updateModules</h4> +<b>__updateModules</b>(<i></i>) + +<p> + Private slot to update the modules of the connected device. +</p> +<a NAME="CircuitPythonUpdaterInterface.installCircup" ID="CircuitPythonUpdaterInterface.installCircup"></a> +<h4>CircuitPythonUpdaterInterface.installCircup</h4> +<b>installCircup</b>(<i></i>) + +<p> + Public slot to install the 'circup' package via pip. +</p> +<a NAME="CircuitPythonUpdaterInterface.populateMenu" ID="CircuitPythonUpdaterInterface.populateMenu"></a> +<h4>CircuitPythonUpdaterInterface.populateMenu</h4> +<b>populateMenu</b>(<i>menu</i>) + +<p> + Public method to populate the 'circup' menu. +</p> +<dl> + +<dt><i>menu</i> (QMenu)</dt> +<dd> +reference to the menu to be populated +</dd> +</dl> +<div align="right"><a href="#top">Up</a></div> +<hr /> +<hr /> +<a NAME="isCircupAvailable" ID="isCircupAvailable"></a> +<h2>isCircupAvailable</h2> +<b>isCircupAvailable</b>(<i></i>) + +<p> + Function to check for the availability of 'circup'. +</p> +<dl> +<dt>Return:</dt> +<dd> +flag indicating the availability of 'circup' +</dd> +</dl> +<dl> +<dt>Return Type:</dt> +<dd> +bool +</dd> +</dl> +<div align="right"><a href="#top">Up</a></div> +<hr /> +</body></html> \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/eric7/Documentation/Source/eric7.MicroPython.CircuitPythonUpdater.CircupFunctions.html Mon Feb 06 10:09:18 2023 +0100 @@ -0,0 +1,209 @@ +<!DOCTYPE html> +<html><head> +<title>eric7.MicroPython.CircuitPythonUpdater.CircupFunctions</title> +<meta charset="UTF-8"> +<link rel="stylesheet" href="styles.css"> +</head> +<body> +<a NAME="top" ID="top"></a> +<h1>eric7.MicroPython.CircuitPythonUpdater.CircupFunctions</h1> + +<p> +Module implementing variants of some 'circup' functions suitable for 'eric-ide' +integration. +</p> +<h3>Global Attributes</h3> + +<table> +<tr><td>None</td></tr> +</table> +<h3>Classes</h3> + +<table> +<tr><td>None</td></tr> +</table> +<h3>Functions</h3> + +<table> + +<tr> +<td><a href="#ensure_latest_bundle">ensure_latest_bundle</a></td> +<td>Function to ensure that there's a copy of the latest library bundle available so circup can check the metadata contained therein.</td> +</tr> +<tr> +<td><a href="#find_modules">find_modules</a></td> +<td>Function to extract metadata from the connected device and available bundles and returns this as a list of Module instances representing the modules on the device.</td> +</tr> +<tr> +<td><a href="#get_circuitpython_version">get_circuitpython_version</a></td> +<td>Function to return the version number of CircuitPython running on the board connected via ``device_path``, along with the board ID.</td> +</tr> +<tr> +<td><a href="#install_module">install_module</a></td> +<td>Function to find a connected device and install a given module name.</td> +</tr> +<tr> +<td><a href="#patch_circup">patch_circup</a></td> +<td>Function to patch 'circup' to use our functions adapted to the use within the eric-ide.</td> +</tr> +</table> +<hr /> +<hr /> +<a NAME="ensure_latest_bundle" ID="ensure_latest_bundle"></a> +<h2>ensure_latest_bundle</h2> +<b>ensure_latest_bundle</b>(<i>bundle</i>) + +<p> + Function to ensure that there's a copy of the latest library bundle available so + circup can check the metadata contained therein. +</p> +<dl> + +<dt><i>bundle</i> (circup.Bundle)</dt> +<dd> +reference to the target Bundle object. +</dd> +</dl> +<div align="right"><a href="#top">Up</a></div> +<hr /> +<hr /> +<a NAME="find_modules" ID="find_modules"></a> +<h2>find_modules</h2> +<b>find_modules</b>(<i>device_path, bundles_list</i>) + +<p> + Function to extract metadata from the connected device and available bundles and + returns this as a list of Module instances representing the modules on the device. +</p> +<dl> + +<dt><i>device_path</i> (str)</dt> +<dd> +path to the connected board +</dd> +<dt><i>bundles_list</i> (list of circup.Bundle)</dt> +<dd> +list of supported bundles +</dd> +</dl> +<dl> +<dt>Return:</dt> +<dd> +list of Module instances describing the current state of the + modules on the connected device +</dd> +</dl> +<dl> +<dt>Return Type:</dt> +<dd> +list of circup.Module +</dd> +</dl> +<div align="right"><a href="#top">Up</a></div> +<hr /> +<hr /> +<a NAME="get_circuitpython_version" ID="get_circuitpython_version"></a> +<h2>get_circuitpython_version</h2> +<b>get_circuitpython_version</b>(<i>device_path</i>) + +<p> + Function to return the version number of CircuitPython running on the board + connected via ``device_path``, along with the board ID. +</p> +<p> + This is obtained from the 'boot_out.txt' file on the device, whose first line + will start with something like this: +</p> +<p> + Adafruit CircuitPython 4.1.0 on 2019-08-02; +</p> +<p> + While the second line is: +</p> +<p> + Board ID:raspberry_pi_pico +</p> +<dl> + +<dt><i>device_path</i> (str)</dt> +<dd> +path to the connected board. +</dd> +</dl> +<dl> +<dt>Return:</dt> +<dd> +tuple with the version string for CircuitPython and the board ID string +</dd> +</dl> +<dl> +<dt>Return Type:</dt> +<dd> +tuple of (str, str) +</dd> +</dl> +<div align="right"><a href="#top">Up</a></div> +<hr /> +<hr /> +<a NAME="install_module" ID="install_module"></a> +<h2>install_module</h2> +<b>install_module</b>(<i>device_path, device_modules, name, py, mod_names</i>) + +<p> + Function to find a connected device and install a given module name. +</p> +<p> + Installation is done if it is available in the current module bundle and is not + already installed on the device. +</p> +<dl> + +<dt><i>device_path</i> (str)</dt> +<dd> +path to the connected board +</dd> +<dt><i>device_modules</i> (list of dict)</dt> +<dd> +list of module metadata from the device +</dd> +<dt><i>name</i> (str)</dt> +<dd> +name of the module to be installed +</dd> +<dt><i>py</i> (bool)</dt> +<dd> +flag indicating if the module should be installed from source or + from a pre-compiled module +</dd> +<dt><i>mod_names</i> (dict)</dt> +<dd> +dictionary containing metadata from modules that can be generated + with circup.get_bundle_versions() +</dd> +</dl> +<dl> +<dt>Return:</dt> +<dd> +flag indicating success +</dd> +</dl> +<dl> +<dt>Return Type:</dt> +<dd> +bool +</dd> +</dl> +<div align="right"><a href="#top">Up</a></div> +<hr /> +<hr /> +<a NAME="patch_circup" ID="patch_circup"></a> +<h2>patch_circup</h2> +<b>patch_circup</b>(<i></i>) + +<p> + Function to patch 'circup' to use our functions adapted to the use within the + eric-ide. +</p> +<div align="right"><a href="#top">Up</a></div> +<hr /> +</body></html> \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/eric7/Documentation/Source/eric7.MicroPython.CircuitPythonUpdater.RequirementsDialog.html Mon Feb 06 10:09:18 2023 +0100 @@ -0,0 +1,244 @@ +<!DOCTYPE html> +<html><head> +<title>eric7.MicroPython.CircuitPythonUpdater.RequirementsDialog</title> +<meta charset="UTF-8"> +<link rel="stylesheet" href="styles.css"> +</head> +<body> +<a NAME="top" ID="top"></a> +<h1>eric7.MicroPython.CircuitPythonUpdater.RequirementsDialog</h1> + +<p> +Module implementing a dialog to generate a requirements file. +</p> +<h3>Global Attributes</h3> + +<table> +<tr><td>None</td></tr> +</table> +<h3>Classes</h3> + +<table> + +<tr> +<td><a href="#RequirementsDialog">RequirementsDialog</a></td> +<td>Class implementing a dialog to generate a requirements file.</td> +</tr> +</table> +<h3>Functions</h3> + +<table> +<tr><td>None</td></tr> +</table> +<hr /> +<hr /> +<a NAME="RequirementsDialog" ID="RequirementsDialog"></a> +<h2>RequirementsDialog</h2> + +<p> + Class implementing a dialog to generate a requirements file. +</p> +<h3>Derived from</h3> +QDialog, Ui_RequirementsDialog +<h3>Class Attributes</h3> + +<table> +<tr><td>None</td></tr> +</table> +<h3>Class Methods</h3> + +<table> +<tr><td>None</td></tr> +</table> +<h3>Methods</h3> + +<table> + +<tr> +<td><a href="#RequirementsDialog.__init__">RequirementsDialog</a></td> +<td>Constructor</td> +</tr> +<tr> +<td><a href="#RequirementsDialog.__generateRequirements">__generateRequirements</a></td> +<td>Private slot to generate the requirements specifiers list.</td> +</tr> +<tr> +<td><a href="#RequirementsDialog.__updateButtons">__updateButtons</a></td> +<td>Private method to set the state of the various buttons.</td> +</tr> +<tr> +<td><a href="#RequirementsDialog.__writeToFile">__writeToFile</a></td> +<td>Private method to write the requirements text to a file.</td> +</tr> +<tr> +<td><a href="#RequirementsDialog.on_buttonBox_clicked">on_buttonBox_clicked</a></td> +<td>Private slot called by a button of the button box clicked.</td> +</tr> +<tr> +<td><a href="#RequirementsDialog.on_copyButton_clicked">on_copyButton_clicked</a></td> +<td>Private slot to copy the requirements text to the clipboard.</td> +</tr> +<tr> +<td><a href="#RequirementsDialog.on_insertButton_clicked">on_insertButton_clicked</a></td> +<td>Private slot to insert the requirements text at the cursor position of the current editor.</td> +</tr> +<tr> +<td><a href="#RequirementsDialog.on_replaceAllButton_clicked">on_replaceAllButton_clicked</a></td> +<td>Private slot to replace the text of the current editor with the requirements text.</td> +</tr> +<tr> +<td><a href="#RequirementsDialog.on_replaceSelectionButton_clicked">on_replaceSelectionButton_clicked</a></td> +<td>Private slot to replace the selected text of the current editor with the requirements text.</td> +</tr> +<tr> +<td><a href="#RequirementsDialog.on_requirementsEdit_textChanged">on_requirementsEdit_textChanged</a></td> +<td>Private slot handling changes of the requirements text.</td> +</tr> +<tr> +<td><a href="#RequirementsDialog.on_requirementsFilePicker_textChanged">on_requirementsFilePicker_textChanged</a></td> +<td>Private slot handling a change of the requirements file name.</td> +</tr> +<tr> +<td><a href="#RequirementsDialog.on_saveButton_clicked">on_saveButton_clicked</a></td> +<td>Private slot to save the requirements text to the requirements file.</td> +</tr> +<tr> +<td><a href="#RequirementsDialog.on_saveToButton_clicked">on_saveToButton_clicked</a></td> +<td>Private slot to write the requirements text to a new file.</td> +</tr> +</table> +<h3>Static Methods</h3> + +<table> +<tr><td>None</td></tr> +</table> + +<a NAME="RequirementsDialog.__init__" ID="RequirementsDialog.__init__"></a> +<h4>RequirementsDialog (Constructor)</h4> +<b>RequirementsDialog</b>(<i>devicePath, parent=None</i>) + +<p> + Constructor +</p> +<dl> + +<dt><i>devicePath</i> (str)</dt> +<dd> +path to the connected board +</dd> +<dt><i>parent</i> (QWidget (optional))</dt> +<dd> +reference to the parent widget (defaults to None) +</dd> +</dl> +<a NAME="RequirementsDialog.__generateRequirements" ID="RequirementsDialog.__generateRequirements"></a> +<h4>RequirementsDialog.__generateRequirements</h4> +<b>__generateRequirements</b>(<i></i>) + +<p> + Private slot to generate the requirements specifiers list. +</p> +<a NAME="RequirementsDialog.__updateButtons" ID="RequirementsDialog.__updateButtons"></a> +<h4>RequirementsDialog.__updateButtons</h4> +<b>__updateButtons</b>(<i></i>) + +<p> + Private method to set the state of the various buttons. +</p> +<a NAME="RequirementsDialog.__writeToFile" ID="RequirementsDialog.__writeToFile"></a> +<h4>RequirementsDialog.__writeToFile</h4> +<b>__writeToFile</b>(<i>fileName</i>) + +<p> + Private method to write the requirements text to a file. +</p> +<dl> + +<dt><i>fileName</i> (str)</dt> +<dd> +name of the file to write to +</dd> +</dl> +<a NAME="RequirementsDialog.on_buttonBox_clicked" ID="RequirementsDialog.on_buttonBox_clicked"></a> +<h4>RequirementsDialog.on_buttonBox_clicked</h4> +<b>on_buttonBox_clicked</b>(<i>button</i>) + +<p> + Private slot called by a button of the button box clicked. +</p> +<dl> + +<dt><i>button</i> (QAbstractButton)</dt> +<dd> +button that was clicked +</dd> +</dl> +<a NAME="RequirementsDialog.on_copyButton_clicked" ID="RequirementsDialog.on_copyButton_clicked"></a> +<h4>RequirementsDialog.on_copyButton_clicked</h4> +<b>on_copyButton_clicked</b>(<i></i>) + +<p> + Private slot to copy the requirements text to the clipboard. +</p> +<a NAME="RequirementsDialog.on_insertButton_clicked" ID="RequirementsDialog.on_insertButton_clicked"></a> +<h4>RequirementsDialog.on_insertButton_clicked</h4> +<b>on_insertButton_clicked</b>(<i></i>) + +<p> + Private slot to insert the requirements text at the cursor position + of the current editor. +</p> +<a NAME="RequirementsDialog.on_replaceAllButton_clicked" ID="RequirementsDialog.on_replaceAllButton_clicked"></a> +<h4>RequirementsDialog.on_replaceAllButton_clicked</h4> +<b>on_replaceAllButton_clicked</b>(<i></i>) + +<p> + Private slot to replace the text of the current editor with the + requirements text. +</p> +<a NAME="RequirementsDialog.on_replaceSelectionButton_clicked" ID="RequirementsDialog.on_replaceSelectionButton_clicked"></a> +<h4>RequirementsDialog.on_replaceSelectionButton_clicked</h4> +<b>on_replaceSelectionButton_clicked</b>(<i></i>) + +<p> + Private slot to replace the selected text of the current editor + with the requirements text. +</p> +<a NAME="RequirementsDialog.on_requirementsEdit_textChanged" ID="RequirementsDialog.on_requirementsEdit_textChanged"></a> +<h4>RequirementsDialog.on_requirementsEdit_textChanged</h4> +<b>on_requirementsEdit_textChanged</b>(<i></i>) + +<p> + Private slot handling changes of the requirements text. +</p> +<a NAME="RequirementsDialog.on_requirementsFilePicker_textChanged" ID="RequirementsDialog.on_requirementsFilePicker_textChanged"></a> +<h4>RequirementsDialog.on_requirementsFilePicker_textChanged</h4> +<b>on_requirementsFilePicker_textChanged</b>(<i>txt</i>) + +<p> + Private slot handling a change of the requirements file name. +</p> +<dl> + +<dt><i>txt</i> (str)</dt> +<dd> +name of the requirements file +</dd> +</dl> +<a NAME="RequirementsDialog.on_saveButton_clicked" ID="RequirementsDialog.on_saveButton_clicked"></a> +<h4>RequirementsDialog.on_saveButton_clicked</h4> +<b>on_saveButton_clicked</b>(<i></i>) + +<p> + Private slot to save the requirements text to the requirements file. +</p> +<a NAME="RequirementsDialog.on_saveToButton_clicked" ID="RequirementsDialog.on_saveToButton_clicked"></a> +<h4>RequirementsDialog.on_saveToButton_clicked</h4> +<b>on_saveToButton_clicked</b>(<i></i>) + +<p> + Private slot to write the requirements text to a new file. +</p> +<div align="right"><a href="#top">Up</a></div> +<hr /> +</body></html> \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/eric7/Documentation/Source/eric7.MicroPython.CircuitPythonUpdater.ShowBundlesDialog.html Mon Feb 06 10:09:18 2023 +0100 @@ -0,0 +1,88 @@ +<!DOCTYPE html> +<html><head> +<title>eric7.MicroPython.CircuitPythonUpdater.ShowBundlesDialog</title> +<meta charset="UTF-8"> +<link rel="stylesheet" href="styles.css"> +</head> +<body> +<a NAME="top" ID="top"></a> +<h1>eric7.MicroPython.CircuitPythonUpdater.ShowBundlesDialog</h1> + +<p> +Module implementing a dialog showing the available bundles and their modules. +</p> +<h3>Global Attributes</h3> + +<table> +<tr><td>None</td></tr> +</table> +<h3>Classes</h3> + +<table> + +<tr> +<td><a href="#ShowBundlesDialog">ShowBundlesDialog</a></td> +<td>Class implementing a dialog showing the available bundles and their modules.</td> +</tr> +</table> +<h3>Functions</h3> + +<table> +<tr><td>None</td></tr> +</table> +<hr /> +<hr /> +<a NAME="ShowBundlesDialog" ID="ShowBundlesDialog"></a> +<h2>ShowBundlesDialog</h2> + +<p> + Class implementing a dialog showing the available bundles and their modules. +</p> +<h3>Derived from</h3> +QDialog, Ui_ShowBundlesDialog +<h3>Class Attributes</h3> + +<table> +<tr><td>None</td></tr> +</table> +<h3>Class Methods</h3> + +<table> +<tr><td>None</td></tr> +</table> +<h3>Methods</h3> + +<table> + +<tr> +<td><a href="#ShowBundlesDialog.__init__">ShowBundlesDialog</a></td> +<td>Constructor</td> +</tr> +</table> +<h3>Static Methods</h3> + +<table> +<tr><td>None</td></tr> +</table> + +<a NAME="ShowBundlesDialog.__init__" ID="ShowBundlesDialog.__init__"></a> +<h4>ShowBundlesDialog (Constructor)</h4> +<b>ShowBundlesDialog</b>(<i>withModules, parent=None</i>) + +<p> + Constructor +</p> +<dl> + +<dt><i>withModules</i> (bool)</dt> +<dd> +flag indicating to list the modules and their version +</dd> +<dt><i>parent</i> (QWidget (optional))</dt> +<dd> +reference to the parent widget (defaults to None) +</dd> +</dl> +<div align="right"><a href="#top">Up</a></div> +<hr /> +</body></html> \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/eric7/Documentation/Source/eric7.MicroPython.CircuitPythonUpdater.ShowInstalledDialog.html Mon Feb 06 10:09:18 2023 +0100 @@ -0,0 +1,88 @@ +<!DOCTYPE html> +<html><head> +<title>eric7.MicroPython.CircuitPythonUpdater.ShowInstalledDialog</title> +<meta charset="UTF-8"> +<link rel="stylesheet" href="styles.css"> +</head> +<body> +<a NAME="top" ID="top"></a> +<h1>eric7.MicroPython.CircuitPythonUpdater.ShowInstalledDialog</h1> + +<p> +Module implementing a dialog to show the modules installed on the connected device. +</p> +<h3>Global Attributes</h3> + +<table> +<tr><td>None</td></tr> +</table> +<h3>Classes</h3> + +<table> + +<tr> +<td><a href="#ShowInstalledDialog">ShowInstalledDialog</a></td> +<td>Class implementing a dialog to show the modules installed on the connected device.</td> +</tr> +</table> +<h3>Functions</h3> + +<table> +<tr><td>None</td></tr> +</table> +<hr /> +<hr /> +<a NAME="ShowInstalledDialog" ID="ShowInstalledDialog"></a> +<h2>ShowInstalledDialog</h2> + +<p> + Class implementing a dialog to show the modules installed on the connected device. +</p> +<h3>Derived from</h3> +QDialog, Ui_ShowInstalledDialog +<h3>Class Attributes</h3> + +<table> +<tr><td>None</td></tr> +</table> +<h3>Class Methods</h3> + +<table> +<tr><td>None</td></tr> +</table> +<h3>Methods</h3> + +<table> + +<tr> +<td><a href="#ShowInstalledDialog.__init__">ShowInstalledDialog</a></td> +<td>Constructor</td> +</tr> +</table> +<h3>Static Methods</h3> + +<table> +<tr><td>None</td></tr> +</table> + +<a NAME="ShowInstalledDialog.__init__" ID="ShowInstalledDialog.__init__"></a> +<h4>ShowInstalledDialog (Constructor)</h4> +<b>ShowInstalledDialog</b>(<i>devicePath, parent=None</i>) + +<p> + Constructor +</p> +<dl> + +<dt><i>devicePath</i> (str)</dt> +<dd> +path to the connected board +</dd> +<dt><i>parent</i> (QWidget (optional))</dt> +<dd> +reference to the parent widget (defaults to None) +</dd> +</dl> +<div align="right"><a href="#top">Up</a></div> +<hr /> +</body></html> \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/eric7/Documentation/Source/eric7.MicroPython.CircuitPythonUpdater.ShowModulesDialog.html Mon Feb 06 10:09:18 2023 +0100 @@ -0,0 +1,152 @@ +<!DOCTYPE html> +<html><head> +<title>eric7.MicroPython.CircuitPythonUpdater.ShowModulesDialog</title> +<meta charset="UTF-8"> +<link rel="stylesheet" href="styles.css"> +</head> +<body> +<a NAME="top" ID="top"></a> +<h1>eric7.MicroPython.CircuitPythonUpdater.ShowModulesDialog</h1> + +<p> +Module implementing a dialog to show the available modules of all bundles. +</p> +<h3>Global Attributes</h3> + +<table> +<tr><td>None</td></tr> +</table> +<h3>Classes</h3> + +<table> + +<tr> +<td><a href="#ShowModulesDialog">ShowModulesDialog</a></td> +<td>Class implementing a dialog to show the available modules of all bundles.</td> +</tr> +</table> +<h3>Functions</h3> + +<table> +<tr><td>None</td></tr> +</table> +<hr /> +<hr /> +<a NAME="ShowModulesDialog" ID="ShowModulesDialog"></a> +<h2>ShowModulesDialog</h2> + +<p> + Class implementing a dialog to show the available modules of all bundles. +</p> +<h3>Derived from</h3> +QDialog, Ui_ShowModulesDialog +<h3>Class Attributes</h3> + +<table> +<tr><td>None</td></tr> +</table> +<h3>Class Methods</h3> + +<table> +<tr><td>None</td></tr> +</table> +<h3>Methods</h3> + +<table> + +<tr> +<td><a href="#ShowModulesDialog.__init__">ShowModulesDialog</a></td> +<td>Constructor</td> +</tr> +<tr> +<td><a href="#ShowModulesDialog.__applyFilter">__applyFilter</a></td> +<td>Private slot to apply the filter to the list of available modules.</td> +</tr> +<tr> +<td><a href="#ShowModulesDialog.__checkCountUpdated">__checkCountUpdated</a></td> +<td>Private method to handle an update of the check count.</td> +</tr> +<tr> +<td><a href="#ShowModulesDialog.getSelection">getSelection</a></td> +<td>Public method to get the list of selected modules.</td> +</tr> +<tr> +<td><a href="#ShowModulesDialog.on_modulesList_itemChanged">on_modulesList_itemChanged</a></td> +<td>Private slot to handle a change of the check state of an item.</td> +</tr> +</table> +<h3>Static Methods</h3> + +<table> +<tr><td>None</td></tr> +</table> + +<a NAME="ShowModulesDialog.__init__" ID="ShowModulesDialog.__init__"></a> +<h4>ShowModulesDialog (Constructor)</h4> +<b>ShowModulesDialog</b>(<i>selectionMode=False, parent=None</i>) + +<p> + Constructor +</p> +<dl> + +<dt><i>selectionMode</i> (bool (optional))</dt> +<dd> +flag indicating the activation of the selection mode + (defaults to False) +</dd> +<dt><i>parent</i> (QWidget (optional))</dt> +<dd> +reference to the parent widget (defaults to None) +</dd> +</dl> +<a NAME="ShowModulesDialog.__applyFilter" ID="ShowModulesDialog.__applyFilter"></a> +<h4>ShowModulesDialog.__applyFilter</h4> +<b>__applyFilter</b>(<i></i>) + +<p> + Private slot to apply the filter to the list of available modules. +</p> +<a NAME="ShowModulesDialog.__checkCountUpdated" ID="ShowModulesDialog.__checkCountUpdated"></a> +<h4>ShowModulesDialog.__checkCountUpdated</h4> +<b>__checkCountUpdated</b>(<i></i>) + +<p> + Private method to handle an update of the check count. +</p> +<a NAME="ShowModulesDialog.getSelection" ID="ShowModulesDialog.getSelection"></a> +<h4>ShowModulesDialog.getSelection</h4> +<b>getSelection</b>(<i></i>) + +<p> + Public method to get the list of selected modules. +</p> +<dl> +<dt>Return:</dt> +<dd> +list of selected modules +</dd> +</dl> +<dl> +<dt>Return Type:</dt> +<dd> +circup.Module +</dd> +</dl> +<a NAME="ShowModulesDialog.on_modulesList_itemChanged" ID="ShowModulesDialog.on_modulesList_itemChanged"></a> +<h4>ShowModulesDialog.on_modulesList_itemChanged</h4> +<b>on_modulesList_itemChanged</b>(<i>item</i>) + +<p> + Private slot to handle a change of the check state of an item. +</p> +<dl> + +<dt><i>item</i> (QTreeWidgetItem)</dt> +<dd> +reference to the changed item +</dd> +</dl> +<div align="right"><a href="#top">Up</a></div> +<hr /> +</body></html> \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/eric7/Documentation/Source/eric7.MicroPython.CircuitPythonUpdater.ShowOutdatedDialog.html Mon Feb 06 10:09:18 2023 +0100 @@ -0,0 +1,149 @@ +<!DOCTYPE html> +<html><head> +<title>eric7.MicroPython.CircuitPythonUpdater.ShowOutdatedDialog</title> +<meta charset="UTF-8"> +<link rel="stylesheet" href="styles.css"> +</head> +<body> +<a NAME="top" ID="top"></a> +<h1>eric7.MicroPython.CircuitPythonUpdater.ShowOutdatedDialog</h1> + +<p> +Module implementing a dialog to show outdated modules of a connected device. +</p> +<h3>Global Attributes</h3> + +<table> +<tr><td>None</td></tr> +</table> +<h3>Classes</h3> + +<table> + +<tr> +<td><a href="#ShowOutdatedDialog">ShowOutdatedDialog</a></td> +<td>Class implementing a dialog to show outdated modules of a connected device.</td> +</tr> +</table> +<h3>Functions</h3> + +<table> +<tr><td>None</td></tr> +</table> +<hr /> +<hr /> +<a NAME="ShowOutdatedDialog" ID="ShowOutdatedDialog"></a> +<h2>ShowOutdatedDialog</h2> + +<p> + Class implementing a dialog to show outdated modules of a connected device. +</p> +<h3>Derived from</h3> +QDialog, Ui_ShowOutdatedDialog +<h3>Class Attributes</h3> + +<table> +<tr><td>None</td></tr> +</table> +<h3>Class Methods</h3> + +<table> +<tr><td>None</td></tr> +</table> +<h3>Methods</h3> + +<table> + +<tr> +<td><a href="#ShowOutdatedDialog.__init__">ShowOutdatedDialog</a></td> +<td>Constructor</td> +</tr> +<tr> +<td><a href="#ShowOutdatedDialog.__checkCountUpdated">__checkCountUpdated</a></td> +<td>Private method to handle an update of the check count.</td> +</tr> +<tr> +<td><a href="#ShowOutdatedDialog.getSelection">getSelection</a></td> +<td>Public method to get the list of selected modules.</td> +</tr> +<tr> +<td><a href="#ShowOutdatedDialog.on_modulesList_itemChanged">on_modulesList_itemChanged</a></td> +<td>Private slot to handle a change of the check state of an item.</td> +</tr> +</table> +<h3>Static Methods</h3> + +<table> +<tr><td>None</td></tr> +</table> + +<a NAME="ShowOutdatedDialog.__init__" ID="ShowOutdatedDialog.__init__"></a> +<h4>ShowOutdatedDialog (Constructor)</h4> +<b>ShowOutdatedDialog</b>(<i>devicePath, selectionMode=False, parent=None</i>) + +<p> + Constructor +</p> +<dl> + +<dt><i>devicePath</i> (str)</dt> +<dd> +path to the connected board +</dd> +<dt><i>selectionMode</i> (bool (optional))</dt> +<dd> +flag indicating the activation of the selection mode + (defaults to False) +</dd> +<dt><i>parent</i> (QWidget (optional))</dt> +<dd> +reference to the parent widget (defaults to None) +</dd> +</dl> +<a NAME="ShowOutdatedDialog.__checkCountUpdated" ID="ShowOutdatedDialog.__checkCountUpdated"></a> +<h4>ShowOutdatedDialog.__checkCountUpdated</h4> +<b>__checkCountUpdated</b>(<i></i>) + +<p> + Private method to handle an update of the check count. +</p> +<a NAME="ShowOutdatedDialog.getSelection" ID="ShowOutdatedDialog.getSelection"></a> +<h4>ShowOutdatedDialog.getSelection</h4> +<b>getSelection</b>(<i></i>) + +<p> + Public method to get the list of selected modules. +</p> +<dl> +<dt>Return:</dt> +<dd> +list of selected modules +</dd> +</dl> +<dl> +<dt>Return Type:</dt> +<dd> +circup.Module +</dd> +</dl> +<a NAME="ShowOutdatedDialog.on_modulesList_itemChanged" ID="ShowOutdatedDialog.on_modulesList_itemChanged"></a> +<h4>ShowOutdatedDialog.on_modulesList_itemChanged</h4> +<b>on_modulesList_itemChanged</b>(<i>item, column</i>) + +<p> + Private slot to handle a change of the check state of an item. +</p> +<dl> + +<dt><i>item</i> (QTreeWidgetItem)</dt> +<dd> +reference to the changed item +</dd> +<dt><i>column</i> (int)</dt> +<dd> +changed column +</dd> +</dl> +<div align="right"><a href="#top">Up</a></div> +<hr /> +</body></html> \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/eric7/Documentation/Source/index-eric7.MicroPython.CircuitPythonUpdater.html Mon Feb 06 10:09:18 2023 +0100 @@ -0,0 +1,47 @@ +<!DOCTYPE html> +<html><head> +<title>eric7.MicroPython.CircuitPythonUpdater</title> +<meta charset="UTF-8"> +<link rel="stylesheet" href="styles.css"> +</head> +<body> +<h1>eric7.MicroPython.CircuitPythonUpdater</h1> + +<p> +Package implementing the updater and associated dialogs. +</p> + + +<h3>Modules</h3> +<table> + +<tr> +<td><a href="eric7.MicroPython.CircuitPythonUpdater.CircuitPythonUpdaterInterface.html">CircuitPythonUpdaterInterface</a></td> +<td>Module implementing an interface to the 'circup' package.</td> +</tr> +<tr> +<td><a href="eric7.MicroPython.CircuitPythonUpdater.CircupFunctions.html">CircupFunctions</a></td> +<td>Module implementing variants of some 'circup' functions suitable for 'eric-ide' integration.</td> +</tr> +<tr> +<td><a href="eric7.MicroPython.CircuitPythonUpdater.RequirementsDialog.html">RequirementsDialog</a></td> +<td>Module implementing a dialog to generate a requirements file.</td> +</tr> +<tr> +<td><a href="eric7.MicroPython.CircuitPythonUpdater.ShowBundlesDialog.html">ShowBundlesDialog</a></td> +<td>Module implementing a dialog showing the available bundles and their modules.</td> +</tr> +<tr> +<td><a href="eric7.MicroPython.CircuitPythonUpdater.ShowInstalledDialog.html">ShowInstalledDialog</a></td> +<td>Module implementing a dialog to show the modules installed on the connected device.</td> +</tr> +<tr> +<td><a href="eric7.MicroPython.CircuitPythonUpdater.ShowModulesDialog.html">ShowModulesDialog</a></td> +<td>Module implementing a dialog to show the available modules of all bundles.</td> +</tr> +<tr> +<td><a href="eric7.MicroPython.CircuitPythonUpdater.ShowOutdatedDialog.html">ShowOutdatedDialog</a></td> +<td>Module implementing a dialog to show outdated modules of a connected device.</td> +</tr> +</table> +</body></html> \ No newline at end of file
--- a/src/eric7/Documentation/Source/index-eric7.MicroPython.html Mon Feb 06 10:02:35 2023 +0100 +++ b/src/eric7/Documentation/Source/index-eric7.MicroPython.html Mon Feb 06 10:09:18 2023 +0100 @@ -11,6 +11,14 @@ Package implementing an interface to MicroPython devices like esp32. </p> +<h3>Packages</h3> +<table> + +<tr> +<td><a href="index-eric7.MicroPython.CircuitPythonUpdater.html">CircuitPythonUpdater</a></td> +<td>Package implementing the updater and associated dialogs.</td> +</tr> +</table> <h3>Modules</h3> <table>
--- a/src/eric7/DocumentationTools/IndexGenerator.py Mon Feb 06 10:02:35 2023 +0100 +++ b/src/eric7/DocumentationTools/IndexGenerator.py Mon Feb 06 10:09:18 2023 +0100 @@ -190,6 +190,13 @@ out = self.__writeIndex(package, element, newline) except OSError as v: sys.stderr.write("{0} error: {1}\n".format(package, v[1])) + except Exception as ex: + sys.stderr.write( + "{0} error writing index: {1}\n".format( + package, str(ex) + ) + ) + raise else: if out: sys.stdout.write("{0} ok\n".format(out))
--- a/src/eric7/MicroPython/CircuitPythonDevices.py Mon Feb 06 10:02:35 2023 +0100 +++ b/src/eric7/MicroPython/CircuitPythonDevices.py Mon Feb 06 10:09:18 2023 +0100 @@ -17,6 +17,10 @@ from eric7.EricWidgets import EricFileDialog, EricMessageBox from eric7.SystemUtilities import FileSystemUtilities +from .CircuitPythonUpdater.CircuitPythonUpdaterInterface import ( + CircuitPythonUpdaterInterface, + isCircupAvailable, +) from .MicroPythonDevices import MicroPythonDevice from .MicroPythonWidget import HAS_QTCHART @@ -46,6 +50,8 @@ self.__boardName = boardName self.__workspace = self.__findWorkspace() + self.__updater = CircuitPythonUpdaterInterface(self) + self.__nonUF2devices = { "teensy": self.__flashTeensy, } @@ -152,22 +158,6 @@ return self.DeviceVolumeName in self.getWorkspace(silent=True) - def getWorkspace(self, silent=False): - """ - Public method to get the workspace directory. - - @param silent flag indicating silent operations - @type bool - @return workspace directory used for saving files - @rtype str - """ - if self.__workspace: - # return cached entry - return self.__workspace - else: - self.__workspace = self.__findWorkspace(silent=silent) - return self.__workspace - def __findDeviceDirectories(self, directories): """ Private method to find the device directories associated with the @@ -232,6 +222,22 @@ return super().getWorkspace() + def getWorkspace(self, silent=False): + """ + Public method to get the workspace directory. + + @param silent flag indicating silent operations + @type bool + @return workspace directory used for saving files + @rtype str + """ + if self.__workspace: + # return cached entry + return self.__workspace + else: + self.__workspace = self.__findWorkspace(silent=silent) + return self.__workspace + def addDeviceMenuEntries(self, menu): """ Public method to add device specific entries to the given menu. @@ -242,15 +248,8 @@ connected = self.microPython.isConnected() self.__libraryMenu = QMenu(self.tr("Library Management")) - act = self.__libraryMenu.addAction( - self.tr("Install Library Files"), self.__installLibraryFiles - ) - act.setEnabled(self.__deviceVolumeMounted()) - act = self.__libraryMenu.addAction( - self.tr("Install Library Package"), - lambda: self.__installLibraryFiles(packageMode=True), - ) - act.setEnabled(self.__deviceVolumeMounted()) + self.__libraryMenu.aboutToShow.connect(self.__aboutToShowLibraryMenu) + self.__libraryMenu.setTearOffEnabled(True) act = menu.addAction( self.tr("Flash CircuitPython Firmware"), self.__flashCircuitPython @@ -259,6 +258,31 @@ menu.addSeparator() menu.addMenu(self.__libraryMenu) + @pyqtSlot() + def __aboutToShowLibraryMenu(self): + """ + Private slot to populate the 'Library Management' menu. + """ + self.__libraryMenu.clear() + + if isCircupAvailable(): + self.__updater.populateMenu(self.__libraryMenu) + else: + act = self.__libraryMenu.addAction( + self.tr("Install Library Files"), self.__installLibraryFiles + ) + act.setEnabled(self.__deviceVolumeMounted()) + act = self.__libraryMenu.addAction( + self.tr("Install Library Package"), + lambda: self.__installLibraryFiles(packageMode=True), + ) + act.setEnabled(self.__deviceVolumeMounted()) + self.__libraryMenu.addSeparator() + self.__libraryMenu.addAction( + self.tr("Install 'circup' Package"), + self.__updater.installCircup, + ) + def hasFlashMenuEntry(self): """ Public method to check, if the device has its own flash menu entry.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/eric7/MicroPython/CircuitPythonUpdater/CircuitPythonUpdaterInterface.py Mon Feb 06 10:09:18 2023 +0100 @@ -0,0 +1,652 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2023 Detlev Offenbach <detlev@die-offenbachs.de> +# + +""" +Module implementing an interface to the 'circup' package. +""" + +import importlib +import logging +import os +import re +import shutil + +import requests + +from PyQt6.QtCore import QObject, pyqtSlot +from PyQt6.QtWidgets import QDialog, QInputDialog, QLineEdit, QMenu + +from eric7 import Preferences +from eric7.EricGui.EricOverrideCursor import EricOverrideCursor +from eric7.EricWidgets import EricFileDialog, EricMessageBox +from eric7.EricWidgets.EricApplication import ericApp +from eric7.EricWidgets.EricListSelectionDialog import EricListSelectionDialog +from eric7.SystemUtilities import PythonUtilities + +try: + import circup + + circup.logger.setLevel(logging.WARNING) +except ImportError: + circup = None + + +class CircuitPythonUpdaterInterface(QObject): + """ + Class implementing an interface to the 'circup' package. + """ + + def __init__(self, device, parent=None): + """ + Constructor + + @param device reference to the CircuitPython device interface + @type CircuitPythonDevice + @param parent reference to the parent object (defaults to None) + @type QObject (optional) + """ + super().__init__(parent) + + self.__device = device + + self.__installMenu = QMenu(self.tr("Install Modules")) + self.__installMenu.setTearOffEnabled(True) + self.__installMenu.addAction( + self.tr("Select from Available Modules"), self.__installFromAvailable + ) + self.__installMenu.addAction( + self.tr("Install Requirements"), self.__installRequirements + ) + self.__installMenu.addAction( + self.tr("Install based on 'code.py'"), self.__installFromCode + ) + self.__installMenu.addSeparator() + self.__installPyAct = self.__installMenu.addAction( + self.tr("Install Python Source") + ) + self.__installPyAct.setCheckable(True) + self.__installPyAct.setChecked(False) + # kind of hack to make this action not hide the menu + # Note: parent menus are hidden nevertheless + self.__installPyAct.toggled.connect(self.__installMenu.show) + + def populateMenu(self, menu): + """ + Public method to populate the 'circup' menu. + + @param menu reference to the menu to be populated + @type QMenu + """ + from .CircupFunctions import patch_circup + + patch_circup() + + act = menu.addAction(self.tr("circup"), self.__aboutCircup) + font = act.font() + font.setBold(True) + act.setFont(font) + menu.addSeparator() + menu.addAction(self.tr("List Outdated Modules"), self.__listOutdatedModules) + menu.addAction(self.tr("Update Modules"), self.__updateModules) + menu.addAction(self.tr("Update All Modules"), self.__updateAllModules) + menu.addSeparator() + menu.addAction(self.tr("Show Available Modules"), self.__showAvailableModules) + menu.addAction(self.tr("Show Installed Modules"), self.__showInstalledModules) + menu.addMenu(self.__installMenu) + menu.addAction(self.tr("Uninstall Modules"), self.__uninstallModules) + menu.addSeparator() + menu.addAction( + self.tr("Generate Requirements ..."), self.__generateRequirements + ) + menu.addSeparator() + menu.addAction(self.tr("Show Bundles"), self.__showBundles) + menu.addAction(self.tr("Show Bundles with Modules"), self.__showBundlesModules) + menu.addSeparator() + menu.addAction(self.tr("Add Bundle"), self.__addBundle) + menu.addAction(self.tr("Remove Bundles"), self.__removeBundle) + + @pyqtSlot() + def __aboutCircup(self): + """ + Private slot to show some info about 'circup'. + """ + version = circup.get_circup_version() + if version is None: + version = self.tr("unknown") + + EricMessageBox.information( + None, + self.tr("About circup"), + self.tr( + """<p><b>circup Version {0}</b></p>""" + """<p><i>circup</i> is a tool to manage and update libraries on a""" + """ CircuitPython device.</p>""", + ).format(version), + ) + + @pyqtSlot() + def installCircup(self): + """ + Public slot to install the 'circup' package via pip. + """ + global circup + + pip = ericApp().getObject("Pip") + pip.installPackages( + ["circup"], interpreter=PythonUtilities.getPythonExecutable() + ) + + circup = importlib.import_module("circup") + circup.logger.setLevel(logging.WARNING) + + @pyqtSlot() + def __showBundles(self, withModules=False): + """ + Private slot to show the available bundles (default and local). + + @param withModules flag indicating to list the modules and their version + (defaults to False) + @type bool (optional) + """ + from .ShowBundlesDialog import ShowBundlesDialog + + with EricOverrideCursor(): + dlg = ShowBundlesDialog(withModules=withModules) + dlg.exec() + + @pyqtSlot() + def __showBundlesModules(self): + """ + Private slot to show the available bundles (default and local) with their + modules. + """ + self.__showBundles(withModules=True) + + @pyqtSlot() + def __addBundle(self): + """ + Private slot to add a bundle to the local bundles list, by "user/repo" github + string. + """ + bundle, ok = QInputDialog.getText( + None, + self.tr("Add Bundle"), + self.tr("Enter Bundle by 'User/Repo' Github String:"), + QLineEdit.EchoMode.Normal, + ) + if ok and bundle: + bundles = circup.get_bundles_local_dict() + modified = False + + # do some cleanup + bundle = re.sub(r"https?://github.com/([^/]+/[^/]+)(/.*)?", r"\1", bundle) + if bundle in bundles: + EricMessageBox.information( + None, + self.tr("Add Bundle"), + self.tr( + """<p>The bundle <b>{0}</b> is already in the list.</p>""" + ).format(bundle), + ) + return + + try: + cBundle = circup.Bundle(bundle) + except ValueError: + EricMessageBox.critical( + None, + self.tr("Add Bundle"), + self.tr( + """<p>The bundle string is invalid, expecting github URL""" + """ or 'user/repository' string.</p>""" + ), + ) + return + + result = requests.head("https://github.com/" + bundle) + if result.status_code == requests.codes.NOT_FOUND: + EricMessageBox.critical( + None, + self.tr("Add Bundle"), + self.tr( + """<p>The bundle string is invalid. The repository doesn't""" + """ exist (error code 404).</p>""" + ), + ) + return + + if not cBundle.validate(): + EricMessageBox.critical( + None, + self.tr("Add Bundle"), + self.tr( + """<p>The bundle string is invalid. Is the repository a valid""" + """circup bundle?</p>""" + ), + ) + return + + # Use the bundle string as the dictionary key for uniqueness + bundles[bundle] = bundle + modified = True + EricMessageBox.information( + None, + self.tr("Add Bundle"), + self.tr("""<p>Added bundle <b>{0}</b> ({1}).</p>""").format( + bundle, cBundle.url + ), + ) + + if modified: + # save the bundles list + circup.save_local_bundles(bundles) + # update and get the new bundle for the first time + circup.get_bundle_versions(circup.get_bundles_list()) + + @pyqtSlot() + def __removeBundle(self): + """ + Private slot to remove one or more bundles from the local bundles list. + """ + localBundles = circup.get_bundles_local_dict() + dlg = EricListSelectionDialog( + sorted(localBundles.keys()), + title=self.tr("Remove Bundles"), + message=self.tr("Select the bundles to be removed:"), + checkBoxSelection=True, + ) + modified = False + if dlg.exec() == QDialog.DialogCode.Accepted: + bundles = dlg.getSelection() + for bundle in bundles: + del localBundles[bundle] + modified = True + + if modified: + circup.save_local_bundles(localBundles) + EricMessageBox.information( + None, + self.tr("Remove Bundles"), + self.tr( + """<p>These bundles were removed from the local bundles list.{0}""" + """</p>""" + ).format("""<ul><li>{0}</li></ul>""".format("</li><li>".join(bundles))), + ) + + @pyqtSlot() + def __listOutdatedModules(self): + """ + Private slot to list the outdated modules of the connected device. + """ + from .ShowOutdatedDialog import ShowOutdatedDialog + + devicePath = self.__device.getWorkspace() + + cpyVersion, board_id = circup.get_circuitpython_version(devicePath) + circup.CPY_VERSION = cpyVersion + + with EricOverrideCursor(): + dlg = ShowOutdatedDialog(devicePath=devicePath) + dlg.exec() + + @pyqtSlot() + def __updateModules(self): + """ + Private slot to update the modules of the connected device. + """ + from .ShowOutdatedDialog import ShowOutdatedDialog + + devicePath = self.__device.getWorkspace() + + cpyVersion, board_id = circup.get_circuitpython_version(devicePath) + circup.CPY_VERSION = cpyVersion + + with EricOverrideCursor(): + dlg = ShowOutdatedDialog(devicePath=devicePath, selectionMode=True) + if dlg.exec() == QDialog.DialogCode.Accepted: + modules = dlg.getSelection() + self.__doUpdateModules(modules) + + @pyqtSlot() + def __updateAllModules(self): + """ + Private slot to update all modules of the connected device. + """ + devicePath = self.__device.getWorkspace() + + cpyVersion, board_id = circup.get_circuitpython_version(devicePath) + circup.CPY_VERSION = cpyVersion + + with EricOverrideCursor(): + modules = [ + m + for m in circup.find_modules(devicePath, circup.get_bundles_list()) + if m.outofdate + ] + if modules: + self.__doUpdateModules(modules) + else: + EricMessageBox.information( + None, + self.tr("Update Modules"), + self.tr("All modules are already up-to-date."), + ) + + def __doUpdateModules(self, modules): + """ + Private method to perform the update of a list of modules. + + @param modules list of modules to be updated + @type circup.Module + """ + updatedModules = [] + for module in modules: + try: + module.update() + updatedModules.append(module.name) + except Exception as ex: + EricMessageBox.critical( + None, + self.tr("Update Modules"), + self.tr( + """<p>There was an error updating <b>{0}</b>.</p>""" + """<p>Error: {1}</p>""" + ).format(module.name, str(ex)), + ) + + if updatedModules: + EricMessageBox.information( + None, + self.tr("Update Modules"), + self.tr( + """<p>These modules were updated on the connected device.{0}</p>""" + ).format( + """<ul><li>{0}</li></ul>""".format("</li><li>".join(updatedModules)) + ), + ) + else: + EricMessageBox.information( + None, + self.tr("Update Modules"), + self.tr("No modules could be updated."), + ) + + @pyqtSlot() + def __showAvailableModules(self): + """ + Private slot to show the available modules. + + These are modules which could be installed on the device. + """ + from .ShowModulesDialog import ShowModulesDialog + + with EricOverrideCursor(): + dlg = ShowModulesDialog() + dlg.exec() + + @pyqtSlot() + def __showInstalledModules(self): + """ + Private slot to show the modules installed on the connected device. + """ + from .ShowInstalledDialog import ShowInstalledDialog + + devicePath = self.__device.getWorkspace() + + with EricOverrideCursor(): + dlg = ShowInstalledDialog(devicePath=devicePath) + dlg.exec() + + @pyqtSlot() + def __installFromAvailable(self): + """ + Private slot to install modules onto the connected device. + """ + from .ShowModulesDialog import ShowModulesDialog + + with EricOverrideCursor(): + dlg = ShowModulesDialog(selectionMode=True) + if dlg.exec() == QDialog.DialogCode.Accepted: + modules = dlg.getSelection() + self.__installModules(modules) + + @pyqtSlot() + def __installRequirements(self): + """ + Private slot to install modules determined by a requirements file. + """ + homeDir = ( + Preferences.getMicroPython("MpyWorkspace") + or Preferences.getMultiProject("Workspace") + or os.path.expanduser("~") + ) + reqFile = EricFileDialog.getOpenFileName( + None, + self.tr("Install Modules"), + homeDir, + self.tr("Text Files (*.txt);;All Files (*)"), + ) + if reqFile: + if os.path.exists(reqFile): + with open(reqFile, "r") as fp: + requirementsText = fp.read() + modules = circup.libraries_from_requirements(requirementsText) + if modules: + self.__installModules(modules) + else: + EricMessageBox.critical( + None, + self.tr("Install Modules"), + self.tr( + """<p>The given requirements file <b>{0}</b> does not""" + """ contain valid modules.</p>""" + ).format(reqFile), + ) + else: + EricMessageBox.critical( + None, + self.tr("Install Modules"), + self.tr( + """<p>The given requirements file <b>{0}</b> does not exist.""" + """</p>""" + ).format(reqFile), + ) + + @pyqtSlot() + def __installFromCode(self): + """ + Private slot to install modules based on the 'code.py' file of the + connected device. + """ + devicePath = self.__device.getWorkspace() + + codeFile = EricFileDialog.getOpenFileName( + None, + self.tr("Install Modules"), + os.path.join(devicePath, "code.py"), + self.tr("Python Files (*.py);;All Files (*)"), + ) + if codeFile: + if os.path.exists(codeFile): + + with EricOverrideCursor(): + availableModules = circup.get_bundle_versions( + circup.get_bundles_list() + ) + moduleNames = {} + for module, metadata in availableModules.items(): + moduleNames[module.replace(".py", "")] = metadata + + modules = circup.libraries_from_imports(codeFile, moduleNames) + if modules: + self.__installModules(modules) + else: + EricMessageBox.critical( + None, + self.tr("Install Modules"), + self.tr( + """<p>The given code file <b>{0}</b> does not""" + """ contain valid import statements or does not import""" + """ external modules.</p>""" + ).format(codeFile), + ) + else: + EricMessageBox.critical( + None, + self.tr("Install Modules"), + self.tr( + """<p>The given code file <b>{0}</b> does not exist.</p>""" + ).format(codeFile), + ) + + def __installModules(self, installs): + """ + Private method to install the given list of modules. + + @param installs list of module names to be installed + @type list of str + """ + devicePath = self.__device.getWorkspace() + + cpyVersion, board_id = circup.get_circuitpython_version(devicePath) + circup.CPY_VERSION = cpyVersion + + with EricOverrideCursor(): + availableModules = circup.get_bundle_versions(circup.get_bundles_list()) + moduleNames = {} + for module, metadata in availableModules.items(): + moduleNames[module.replace(".py", "")] = metadata + toBeInstalled = circup.get_dependencies(installs, mod_names=moduleNames) + deviceModules = circup.get_device_versions(devicePath) + if toBeInstalled is not None: + dependencies = [m for m in toBeInstalled if m not in installs] + ok = EricMessageBox.yesNo( + None, + self.tr("Install Modules"), + self.tr("""<p>Ready to install these modules?{0}{1}</p>""").format( + """<ul><li>{0}</li></ul>""".format( + "</li><li>".join(sorted(installs)) + ), + self.tr("Dependencies:") + + """<ul><li>{0}</li></ul>""".format( + "</li><li>".join(sorted(dependencies)) + ) + if dependencies + else "", + ), + yesDefault=True, + ) + if ok: + installedModules = [] + with EricOverrideCursor(): + for library in toBeInstalled: + success = circup.install_module( + devicePath, + deviceModules, + library, + self.__installPyAct.isChecked(), + moduleNames, + ) + if success: + installedModules.append(library) + + if installedModules: + EricMessageBox.information( + None, + self.tr("Install Modules"), + self.tr( + "<p>Installation complete. These modules were installed" + " successfully.{0}</p>" + ).format( + """<ul><li>{0}</li></ul>""".format( + "</li><li>".join(sorted(installedModules)) + ), + ), + ) + else: + EricMessageBox.information( + None, + self.tr("Install Modules"), + self.tr( + "<p>Installation complete. No modules were installed.</p>" + ), + ) + else: + EricMessageBox.information( + None, + self.tr("Install Modules"), + self.tr("<p>No modules installation is required.</p>"), + ) + + @pyqtSlot() + def __uninstallModules(self): + """ + Private slot to uninstall modules from the connected device. + """ + devicePath = self.__device.getWorkspace() + libraryPath = os.path.join(devicePath, "lib") + + with EricOverrideCursor(): + deviceModules = circup.get_device_versions(devicePath) + modNames = {} + for moduleItem, metadata in deviceModules.items(): + modNames[moduleItem.replace(".py", "").lower()] = metadata + + dlg = EricListSelectionDialog( + sorted(modNames.keys()), + title=self.tr("Uninstall Modules"), + message=self.tr("Select the modules/packages to be uninstalled:"), + checkBoxSelection=True, + ) + if dlg.exec() == QDialog.DialogCode.Accepted: + names = dlg.getSelection() + for name in names: + modulePath = modNames[name]["path"] + if os.path.isdir(modulePath): + target = os.path.basename(os.path.dirname(modulePath)) + targetPath = os.path.join(libraryPath, target) + # Remove the package directory. + shutil.rmtree(targetPath) + else: + target = os.path.basename(modulePath) + targetPath = os.path.join(libraryPath, target) + # Remove the module file + os.remove(targetPath) + + EricMessageBox.information( + None, + self.tr("Uninstall Modules"), + self.tr( + """<p>These modules/packages were uninstalled from the connected""" + """ device.{0}</p>""" + ).format("""<ul><li>{0}</li></ul>""".format("</li><li>".join(names))), + ) + + @pyqtSlot() + def __generateRequirements(self): + """ + Private slot to generate requirements for the connected device. + """ + from .RequirementsDialog import RequirementsDialog + + devicePath = self.__device.getWorkspace() + + cpyVersion, board_id = circup.get_circuitpython_version(devicePath) + circup.CPY_VERSION = cpyVersion + + dlg = RequirementsDialog(devicePath=devicePath) + dlg.exec() + + +def isCircupAvailable(): + """ + Function to check for the availability of 'circup'. + + @return flag indicating the availability of 'circup' + @rtype bool + """ + global circup + + return circup is not None
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/eric7/MicroPython/CircuitPythonUpdater/CircupFunctions.py Mon Feb 06 10:09:18 2023 +0100 @@ -0,0 +1,256 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2023 Detlev Offenbach <detlev@die-offenbachs.de> +# + +""" +Module implementing variants of some 'circup' functions suitable for 'eric-ide' +integration. +""" + +# +# Copyright of the original sources: +# Copyright (c) 2019 Adafruit Industries +# + +import os +import shutil + +import circup +import requests + +from PyQt6.QtCore import QCoreApplication + +from eric7.EricWidgets import EricMessageBox + + +def find_modules(device_path, bundles_list): + """ + Function to extract metadata from the connected device and available bundles and + returns this as a list of Module instances representing the modules on the device. + + @param device_path path to the connected board + @type str + @param bundles_list list of supported bundles + @type list of circup.Bundle + @return list of Module instances describing the current state of the + modules on the connected device + @rtype list of circup.Module + """ + result = [] + try: + device_modules = circup.get_device_versions(device_path) + bundle_modules = circup.get_bundle_versions(bundles_list) + for name, device_metadata in device_modules.items(): + if name in bundle_modules: + path = device_metadata["path"] + bundle_metadata = bundle_modules[name] + repo = bundle_metadata.get("__repo__") + bundle = bundle_metadata.get("bundle") + device_version = device_metadata.get("__version__") + bundle_version = bundle_metadata.get("__version__") + mpy = device_metadata["mpy"] + compatibility = device_metadata.get("compatibility", (None, None)) + result.append( + circup.Module( + path, + repo, + device_version, + bundle_version, + mpy, + bundle, + compatibility, + ) + ) + except Exception as ex: + # If it's not possible to get the device and bundle metadata, bail out + # with a friendly message and indication of what's gone wrong. + EricMessageBox.critical( + None, + QCoreApplication.translate("CircupFunctions", "Find Modules"), + QCoreApplication.translate( + "CircupFunctions", """<p>There was an error: {0}</p>""" + ).format(str(ex)), + ) + + return result + + +def ensure_latest_bundle(bundle): + """ + Function to ensure that there's a copy of the latest library bundle available so + circup can check the metadata contained therein. + + @param bundle reference to the target Bundle object. + @type circup.Bundle + """ + tag = bundle.latest_tag + do_update = False + if tag == bundle.current_tag: + for platform in circup.PLATFORMS: + # missing directories (new platform added on an existing install + # or side effect of pytest or network errors) + do_update = do_update or not os.path.isdir(bundle.lib_dir(platform)) + else: + do_update = True + + if do_update: + try: + circup.get_bundle(bundle, tag) + circup.tags_data_save_tag(bundle.key, tag) + except requests.exceptions.HTTPError as ex: + EricMessageBox.critical( + None, + QCoreApplication.translate("CircupFunctions", "Download Bundle"), + QCoreApplication.translate( + "CircupFunctions", + """<p>There was a problem downloading the bundle. Please try""" + """ again in a moment.</p><p>Error: {0}</p>""", + ).format(str(ex)), + ) + + +def get_circuitpython_version(device_path): + """ + Function to return the version number of CircuitPython running on the board + connected via ``device_path``, along with the board ID. + + This is obtained from the 'boot_out.txt' file on the device, whose first line + will start with something like this: + + Adafruit CircuitPython 4.1.0 on 2019-08-02; + + While the second line is: + + Board ID:raspberry_pi_pico + + @param device_path path to the connected board. + @type str + @return tuple with the version string for CircuitPython and the board ID string + @rtype tuple of (str, str) + """ + try: + with open(os.path.join(device_path, "boot_out.txt")) as boot: + version_line = boot.readline() + circuit_python = version_line.split(";")[0].split(" ")[-3] + board_line = boot.readline() + board_id = ( + board_line[9:].strip() + if board_line.startswith("Board ID:") + else "" + ) + except FileNotFoundError: + EricMessageBox.critical( + None, + QCoreApplication.translate("CircupFunctions", "Download Bundle"), + QCoreApplication.translate( + "CircupFunctions", + """<p>Missing file <b>boot_out.txt</b> on the device: wrong path or""" + """ drive corrupted.</p>""", + ), + ) + circuit_python, board_id = "", "" + + return (circuit_python, board_id) + + +def install_module(device_path, device_modules, name, py, mod_names): + """ + Function to find a connected device and install a given module name. + + Installation is done if it is available in the current module bundle and is not + already installed on the device. + + @param device_path path to the connected board + @type str + @param device_modules list of module metadata from the device + @type list of dict + @param name name of the module to be installed + @type str + @param py flag indicating if the module should be installed from source or + from a pre-compiled module + @type bool + @param mod_names dictionary containing metadata from modules that can be generated + with circup.get_bundle_versions() + @type dict + @return flag indicating success + @rtype bool + """ + if not name: + return False + elif name in mod_names: + library_path = os.path.join(device_path, "lib") + if not os.path.exists(library_path): # pragma: no cover + os.makedirs(library_path) + metadata = mod_names[name] + bundle = metadata["bundle"] + # Grab device modules to check if module already installed + if name in device_modules: + # ignore silently + return False + if py: + # Use Python source for module. + source_path = metadata["path"] # Path to Python source version. + if os.path.isdir(source_path): + target = os.path.basename(os.path.dirname(source_path)) + target_path = os.path.join(library_path, target) + # Copy the directory. + shutil.copytree(source_path, target_path) + return True + else: + target = os.path.basename(source_path) + target_path = os.path.join(library_path, target) + # Copy file. + shutil.copyfile(source_path, target_path) + return True + else: + # Use pre-compiled mpy modules. + module_name = os.path.basename(metadata["path"]).replace(".py", ".mpy") + if not module_name: + # Must be a directory based module. + module_name = os.path.basename(os.path.dirname(metadata["path"])) + major_version = circup.CPY_VERSION.split(".")[0] + bundle_platform = "{0}mpy".format(major_version) + bundle_path = os.path.join(bundle.lib_dir(bundle_platform), module_name) + if os.path.isdir(bundle_path): + target_path = os.path.join(library_path, module_name) + # Copy the directory. + shutil.copytree(bundle_path, target_path) + return True + elif os.path.isfile(bundle_path): + target = os.path.basename(bundle_path) + target_path = os.path.join(library_path, target) + # Copy file. + shutil.copyfile(bundle_path, target_path) + return True + else: + EricMessageBox.critical( + None, + QCoreApplication.translate("CircupFunctions", "Install Modules"), + QCoreApplication.translate( + "CircupFunctions", + """<p>The compiled version of module <b>{0}</b> cannot be""" + """ found.</p>""", + ).format(name), + ) + return False + else: + EricMessageBox.critical( + None, + QCoreApplication.translate("CircupFunctions", "Install Modules"), + QCoreApplication.translate( + "CircupFunctions", """<p>The module name <b>{0}</b> is not known.</p>""" + ).format(name), + ) + return False + + +def patch_circup(): + """ + Function to patch 'circup' to use our functions adapted to the use within the + eric-ide. + """ + circup.ensure_latest_bundle = ensure_latest_bundle + circup.find_modules = find_modules + circup.get_circuitpython_version = get_circuitpython_version + circup.install_module = install_module
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/eric7/MicroPython/CircuitPythonUpdater/RequirementsDialog.py Mon Feb 06 10:09:18 2023 +0100 @@ -0,0 +1,265 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2023 Detlev Offenbach <detlev@die-offenbachs.de> +# + +""" +Module implementing a dialog to generate a requirements file. +""" + +import os + +import circup + +from PyQt6.QtCore import pyqtSlot +from PyQt6.QtGui import QGuiApplication +from PyQt6.QtWidgets import QAbstractButton, QDialog, QDialogButtonBox + +from eric7.EricWidgets import EricFileDialog, EricMessageBox +from eric7.EricWidgets.EricApplication import ericApp +from eric7.EricWidgets.EricPathPicker import EricPathPickerModes +from eric7.SystemUtilities import FileSystemUtilities + +from .Ui_RequirementsDialog import Ui_RequirementsDialog + + +class RequirementsDialog(QDialog, Ui_RequirementsDialog): + """ + Class implementing a dialog to generate a requirements file. + """ + + def __init__(self, devicePath, parent=None): + """ + Constructor + + @param devicePath path to the connected board + @type str + @param parent reference to the parent widget (defaults to None) + @type QWidget (optional) + """ + super().__init__(parent) + self.setupUi(self) + + self.__title = self.tr("Generate Requirements") + + self.__refreshButton = self.buttonBox.addButton( + self.tr("&Refresh"), QDialogButtonBox.ButtonRole.ActionRole + ) + + self.requirementsFilePicker.setMode(EricPathPickerModes.SAVE_FILE_MODE) + self.requirementsFilePicker.setFilters( + self.tr("Text Files (*.txt);;All Files (*)") + ) + + self.__devicePath = devicePath + + self.__requirementsEdited = False + self.__requirementsAvailable = False + + self.__generateRequirements() + + def __updateButtons(self): + """ + Private method to set the state of the various buttons. + """ + self.saveButton.setEnabled( + self.__requirementsAvailable + and bool(self.requirementsFilePicker.text()) + and os.path.isabs(self.requirementsFilePicker.text()) + ) + self.saveToButton.setEnabled(self.__requirementsAvailable) + self.copyButton.setEnabled(self.__requirementsAvailable) + + aw = ericApp().getObject("ViewManager").activeWindow() + if aw and self.__requirementsAvailable: + self.insertButton.setEnabled(True) + self.replaceAllButton.setEnabled(True) + self.replaceSelectionButton.setEnabled(aw.hasSelectedText()) + else: + self.insertButton.setEnabled(False) + self.replaceAllButton.setEnabled(False) + self.replaceSelectionButton.setEnabled(False) + + @pyqtSlot(str) + def on_requirementsFilePicker_textChanged(self, txt): + """ + Private slot handling a change of the requirements file name. + + @param txt name of the requirements file + @type str + """ + self.__updateButtons() + + @pyqtSlot() + def on_requirementsEdit_textChanged(self): + """ + Private slot handling changes of the requirements text. + """ + self.__requirementsEdited = True + + @pyqtSlot(QAbstractButton) + def on_buttonBox_clicked(self, button): + """ + Private slot called by a button of the button box clicked. + + @param button button that was clicked + @type QAbstractButton + """ + if button == self.buttonBox.button(QDialogButtonBox.StandardButton.Close): + self.close() + elif button == self.__refreshButton: + self.__generateRequirements() + + def __generateRequirements(self): + """ + Private slot to generate the requirements specifiers list. + """ + ok = ( + EricMessageBox.yesNo( + self, + self.__title, + self.tr( + """The requirements were changed. Do you want""" + """ to overwrite these changes?""" + ), + ) + if self.__requirementsEdited + else True + ) + if ok: + self.requirementsEdit.clear() + self.__requirementsAvailable = False + + if not bool(self.requirementsFilePicker.text()): + self.requirementsFilePicker.setText("requirements.txt") + + fileName = FileSystemUtilities.toNativeSeparators( + self.requirementsFilePicker.text() + ) + if fileName and not os.path.isabs(fileName): + fileName = "" + + modules = circup.find_modules(self.__devicePath, circup.get_bundles_list()) + specifiers = [] + if modules: + for module in modules: + specifiers.append( + "{0}=={1}".format(module.name, module.device_version) + ) + + if specifiers: + self.requirementsEdit.setPlainText("\n".join(specifiers) + "\n") + self.__requirementsAvailable = True + else: + self.requirementsEdit.setPlainText( + self.tr("No package specifiers generated by 'pip freeze'.") + ) + + self.__updateButtons() + + self.__requirementsEdited = False + + def __writeToFile(self, fileName): + """ + Private method to write the requirements text to a file. + + @param fileName name of the file to write to + @type str + """ + if os.path.exists(fileName): + ok = EricMessageBox.warning( + self, + self.__title, + self.tr( + """The file <b>{0}</b> already exists. Do you want""" + """ to overwrite it?""" + ).format(fileName), + ) + if not ok: + return + + txt = self.requirementsEdit.toPlainText() + try: + with open(fileName, "w") as f: + f.write(txt) + except OSError as err: + EricMessageBox.critical( + self, + self.__title, + self.tr( + """<p>The requirements could not be written""" + """ to <b>{0}</b>.</p><p>Reason: {1}</p>""" + ).format(fileName, str(err)), + ) + + @pyqtSlot() + def on_saveButton_clicked(self): + """ + Private slot to save the requirements text to the requirements file. + """ + fileName = self.requirementsFilePicker.text() + self.__writeToFile(fileName) + + @pyqtSlot() + def on_saveToButton_clicked(self): + """ + Private slot to write the requirements text to a new file. + """ + fileName, selectedFilter = EricFileDialog.getSaveFileNameAndFilter( + self, + self.__title, + os.path.expanduser("~"), + self.tr("Text Files (*.txt);;All Files (*)"), + None, + EricFileDialog.DontConfirmOverwrite, + ) + if fileName: + ext = os.path.splitext(fileName)[1] + if not ext: + ex = selectedFilter.split("(*")[1].split(")")[0] + if ex: + fileName += ex + self.__writeToFile(fileName) + + @pyqtSlot() + def on_copyButton_clicked(self): + """ + Private slot to copy the requirements text to the clipboard. + """ + txt = self.requirementsEdit.toPlainText() + cb = QGuiApplication.clipboard() + cb.setText(txt) + + @pyqtSlot() + def on_insertButton_clicked(self): + """ + Private slot to insert the requirements text at the cursor position + of the current editor. + """ + aw = ericApp().getObject("ViewManager").activeWindow() + if aw: + aw.beginUndoAction() + aw.insert(self.requirementsEdit.toPlainText()) + aw.endUndoAction() + + @pyqtSlot() + def on_replaceSelectionButton_clicked(self): + """ + Private slot to replace the selected text of the current editor + with the requirements text. + """ + aw = ericApp().getObject("ViewManager").activeWindow() + if aw: + aw.beginUndoAction() + aw.replaceSelectedText(self.requirementsEdit.toPlainText()) + aw.endUndoAction() + + @pyqtSlot() + def on_replaceAllButton_clicked(self): + """ + Private slot to replace the text of the current editor with the + requirements text. + """ + aw = ericApp().getObject("ViewManager").activeWindow() + if aw: + aw.setText(self.requirementsEdit.toPlainText())
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/eric7/MicroPython/CircuitPythonUpdater/RequirementsDialog.ui Mon Feb 06 10:09:18 2023 +0100 @@ -0,0 +1,210 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>RequirementsDialog</class> + <widget class="QDialog" name="RequirementsDialog"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>600</width> + <height>550</height> + </rect> + </property> + <property name="windowTitle"> + <string>Generate Requirements</string> + </property> + <property name="toolTip"> + <string>Replace the current selection with the requirements text</string> + </property> + <property name="sizeGripEnabled"> + <bool>true</bool> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <layout class="QHBoxLayout" name="horizontalLayout"> + <item> + <widget class="QLabel" name="label"> + <property name="text"> + <string>Requirements File:</string> + </property> + </widget> + </item> + <item> + <widget class="EricPathPicker" name="requirementsFilePicker" native="true"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="focusPolicy"> + <enum>Qt::StrongFocus</enum> + </property> + </widget> + </item> + </layout> + </item> + <item> + <layout class="QGridLayout" name="gridLayout"> + <item row="3" column="1"> + <widget class="Line" name="line"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + </widget> + </item> + <item row="2" column="1"> + <widget class="QPushButton" name="copyButton"> + <property name="toolTip"> + <string>Copy the requirements text to the clipboard</string> + </property> + <property name="text"> + <string>Copy</string> + </property> + </widget> + </item> + <item row="0" column="1"> + <widget class="QPushButton" name="saveButton"> + <property name="toolTip"> + <string>Press to save to the requirements file</string> + </property> + <property name="text"> + <string>Save</string> + </property> + </widget> + </item> + <item row="5" column="1"> + <widget class="QPushButton" name="insertButton"> + <property name="toolTip"> + <string>Insert the requirements text at the cursor position</string> + </property> + <property name="text"> + <string>Insert</string> + </property> + </widget> + </item> + <item row="6" column="1"> + <widget class="QPushButton" name="replaceSelectionButton"> + <property name="text"> + <string>Replace Selection</string> + </property> + </widget> + </item> + <item row="0" column="0" rowspan="9"> + <widget class="QPlainTextEdit" name="requirementsEdit"> + <property name="tabChangesFocus"> + <bool>true</bool> + </property> + </widget> + </item> + <item row="7" column="1"> + <widget class="QPushButton" name="replaceAllButton"> + <property name="toolTip"> + <string>Replace all text with the requirements text</string> + </property> + <property name="text"> + <string>Replace All</string> + </property> + </widget> + </item> + <item row="8" column="1"> + <spacer name="verticalSpacer"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>40</height> + </size> + </property> + </spacer> + </item> + <item row="1" column="1"> + <widget class="QPushButton" name="saveToButton"> + <property name="toolTip"> + <string>Save to a new file</string> + </property> + <property name="text"> + <string>Save To</string> + </property> + </widget> + </item> + <item row="4" column="1"> + <widget class="QLabel" name="label_2"> + <property name="text"> + <string><b>Editor Actions</b></string> + </property> + <property name="alignment"> + <set>Qt::AlignCenter</set> + </property> + </widget> + </item> + </layout> + </item> + <item> + <widget class="QDialogButtonBox" name="buttonBox"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="standardButtons"> + <set>QDialogButtonBox::Close</set> + </property> + </widget> + </item> + </layout> + </widget> + <customwidgets> + <customwidget> + <class>EricPathPicker</class> + <extends>QWidget</extends> + <header>eric7/EricWidgets/EricPathPicker.h</header> + <container>1</container> + </customwidget> + </customwidgets> + <tabstops> + <tabstop>requirementsFilePicker</tabstop> + <tabstop>requirementsEdit</tabstop> + <tabstop>saveButton</tabstop> + <tabstop>saveToButton</tabstop> + <tabstop>copyButton</tabstop> + <tabstop>insertButton</tabstop> + <tabstop>replaceSelectionButton</tabstop> + <tabstop>replaceAllButton</tabstop> + </tabstops> + <resources/> + <connections> + <connection> + <sender>buttonBox</sender> + <signal>accepted()</signal> + <receiver>RequirementsDialog</receiver> + <slot>accept()</slot> + <hints> + <hint type="sourcelabel"> + <x>248</x> + <y>254</y> + </hint> + <hint type="destinationlabel"> + <x>157</x> + <y>274</y> + </hint> + </hints> + </connection> + <connection> + <sender>buttonBox</sender> + <signal>rejected()</signal> + <receiver>RequirementsDialog</receiver> + <slot>reject()</slot> + <hints> + <hint type="sourcelabel"> + <x>316</x> + <y>260</y> + </hint> + <hint type="destinationlabel"> + <x>286</x> + <y>274</y> + </hint> + </hints> + </connection> + </connections> +</ui>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/eric7/MicroPython/CircuitPythonUpdater/ShowBundlesDialog.py Mon Feb 06 10:09:18 2023 +0100 @@ -0,0 +1,70 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2023 Detlev Offenbach <detlev@die-offenbachs.de> +# + +""" +Module implementing a dialog showing the available bundles and their modules. +""" + +import circup + +from PyQt6.QtCore import Qt +from PyQt6.QtWidgets import QDialog, QTreeWidgetItem + +from .Ui_ShowBundlesDialog import Ui_ShowBundlesDialog + + +class ShowBundlesDialog(QDialog, Ui_ShowBundlesDialog): + """ + Class implementing a dialog showing the available bundles and their modules. + """ + + def __init__(self, withModules, parent=None): + """ + Constructor + + @param withModules flag indicating to list the modules and their version + @type bool + @param parent reference to the parent widget (defaults to None) + @type QWidget (optional) + """ + super().__init__(parent) + self.setupUi(self) + + self.header.setText( + self.tr("Available Bundles and Modules") + if withModules + else self.tr("Available Modules") + ) + self.bundlesWidget.setColumnCount(2) + + localBundles = circup.get_bundles_local_dict().values() + bundles = circup.get_bundles_list() + availableModules = circup.get_bundle_versions(bundles) + + for bundle in bundles: + topItm = QTreeWidgetItem( + self.bundlesWidget, [bundle.key, bundle.current_tag] + ) + topItm.setExpanded(True) + if bundle.key in localBundles: + font = topItm.font(0) + font.setUnderline(True) + topItm.setFont(0, font) + itm = QTreeWidgetItem(topItm, [bundle.url]) + itm.setFirstColumnSpanned(True) + + if withModules: + modulesHeader = QTreeWidgetItem(topItm, [self.tr("Modules")]) + modulesHeader.setExpanded(True) + for name, mod in sorted(availableModules.items()): + if mod["bundle"] == bundle: + QTreeWidgetItem( + modulesHeader, + [name, mod.get("__version__", self.tr("unknown"))], + ) + + self.bundlesWidget.resizeColumnToContents(0) + self.bundlesWidget.resizeColumnToContents(1) + self.bundlesWidget.sortItems(0, Qt.SortOrder.AscendingOrder)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/eric7/MicroPython/CircuitPythonUpdater/ShowBundlesDialog.ui Mon Feb 06 10:09:18 2023 +0100 @@ -0,0 +1,98 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>ShowBundlesDialog</class> + <widget class="QDialog" name="ShowBundlesDialog"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>600</width> + <height>700</height> + </rect> + </property> + <property name="windowTitle"> + <string>CircuitPython Bundles</string> + </property> + <property name="sizeGripEnabled"> + <bool>true</bool> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <widget class="QLabel" name="header"> + <property name="text"> + <string/> + </property> + </widget> + </item> + <item> + <widget class="QTreeWidget" name="bundlesWidget"> + <property name="alternatingRowColors"> + <bool>true</bool> + </property> + <property name="selectionMode"> + <enum>QAbstractItemView::NoSelection</enum> + </property> + <property name="rootIsDecorated"> + <bool>false</bool> + </property> + <property name="headerHidden"> + <bool>true</bool> + </property> + <property name="expandsOnDoubleClick"> + <bool>false</bool> + </property> + <column> + <property name="text"> + <string notr="true">1</string> + </property> + </column> + </widget> + </item> + <item> + <widget class="QDialogButtonBox" name="buttonBox"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="standardButtons"> + <set>QDialogButtonBox::Close</set> + </property> + </widget> + </item> + </layout> + </widget> + <resources/> + <connections> + <connection> + <sender>buttonBox</sender> + <signal>accepted()</signal> + <receiver>ShowBundlesDialog</receiver> + <slot>accept()</slot> + <hints> + <hint type="sourcelabel"> + <x>248</x> + <y>254</y> + </hint> + <hint type="destinationlabel"> + <x>157</x> + <y>274</y> + </hint> + </hints> + </connection> + <connection> + <sender>buttonBox</sender> + <signal>rejected()</signal> + <receiver>ShowBundlesDialog</receiver> + <slot>reject()</slot> + <hints> + <hint type="sourcelabel"> + <x>316</x> + <y>260</y> + </hint> + <hint type="destinationlabel"> + <x>286</x> + <y>274</y> + </hint> + </hints> + </connection> + </connections> +</ui>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/eric7/MicroPython/CircuitPythonUpdater/ShowInstalledDialog.py Mon Feb 06 10:09:18 2023 +0100 @@ -0,0 +1,45 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2023 Detlev Offenbach <detlev@die-offenbachs.de> +# + +""" +Module implementing a dialog to show the modules installed on the connected device. +""" + +import circup + +from PyQt6.QtCore import Qt +from PyQt6.QtWidgets import QDialog, QTreeWidgetItem + +from .Ui_ShowInstalledDialog import Ui_ShowInstalledDialog + + +class ShowInstalledDialog(QDialog, Ui_ShowInstalledDialog): + """ + Class implementing a dialog to show the modules installed on the connected device. + """ + + def __init__(self, devicePath, parent=None): + """ + Constructor + + @param devicePath path to the connected board + @type str + @param parent reference to the parent widget (defaults to None) + @type QWidget (optional) + """ + super().__init__(parent) + self.setupUi(self) + + self.modulesList.clear() + deviceModules = circup.get_device_versions(devicePath) + for name, metadata in deviceModules.items(): + QTreeWidgetItem( + self.modulesList, + [name, metadata.get("__version__", self.tr("unknown"))], + ) + + self.modulesList.sortItems(0, Qt.SortOrder.AscendingOrder) + self.modulesList.resizeColumnToContents(0) + self.modulesList.resizeColumnToContents(1)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/eric7/MicroPython/CircuitPythonUpdater/ShowInstalledDialog.ui Mon Feb 06 10:09:18 2023 +0100 @@ -0,0 +1,96 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>ShowInstalledDialog</class> + <widget class="QDialog" name="ShowInstalledDialog"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>400</width> + <height>500</height> + </rect> + </property> + <property name="windowTitle"> + <string>Installed Modules</string> + </property> + <property name="sizeGripEnabled"> + <bool>true</bool> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <widget class="QTreeWidget" name="modulesList"> + <property name="alternatingRowColors"> + <bool>true</bool> + </property> + <property name="selectionMode"> + <enum>QAbstractItemView::NoSelection</enum> + </property> + <property name="rootIsDecorated"> + <bool>false</bool> + </property> + <property name="itemsExpandable"> + <bool>false</bool> + </property> + <attribute name="headerShowSortIndicator" stdset="0"> + <bool>false</bool> + </attribute> + <column> + <property name="text"> + <string>Module</string> + </property> + </column> + <column> + <property name="text"> + <string>Version</string> + </property> + </column> + </widget> + </item> + <item> + <widget class="QDialogButtonBox" name="buttonBox"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="standardButtons"> + <set>QDialogButtonBox::Close</set> + </property> + </widget> + </item> + </layout> + </widget> + <resources/> + <connections> + <connection> + <sender>buttonBox</sender> + <signal>accepted()</signal> + <receiver>ShowInstalledDialog</receiver> + <slot>accept()</slot> + <hints> + <hint type="sourcelabel"> + <x>248</x> + <y>254</y> + </hint> + <hint type="destinationlabel"> + <x>157</x> + <y>274</y> + </hint> + </hints> + </connection> + <connection> + <sender>buttonBox</sender> + <signal>rejected()</signal> + <receiver>ShowInstalledDialog</receiver> + <slot>reject()</slot> + <hints> + <hint type="sourcelabel"> + <x>316</x> + <y>260</y> + </hint> + <hint type="destinationlabel"> + <x>286</x> + <y>274</y> + </hint> + </hints> + </connection> + </connections> +</ui>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/eric7/MicroPython/CircuitPythonUpdater/ShowModulesDialog.py Mon Feb 06 10:09:18 2023 +0100 @@ -0,0 +1,128 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2023 Detlev Offenbach <detlev@die-offenbachs.de> +# + +""" +Module implementing a dialog to show the available modules of all bundles. +""" + +import circup + +from PyQt6.QtCore import Qt, pyqtSlot +from PyQt6.QtWidgets import QDialog, QDialogButtonBox, QListWidgetItem + +from eric7.EricGui import EricPixmapCache + +from .Ui_ShowModulesDialog import Ui_ShowModulesDialog + + +class ShowModulesDialog(QDialog, Ui_ShowModulesDialog): + """ + Class implementing a dialog to show the available modules of all bundles. + """ + + def __init__(self, selectionMode=False, parent=None): + """ + Constructor + + @param selectionMode flag indicating the activation of the selection mode + (defaults to False) + @type bool (optional) + @param parent reference to the parent widget (defaults to None) + @type QWidget (optional) + """ + super().__init__(parent) + self.setupUi(self) + + self.filterButton.setIcon(EricPixmapCache.getIcon("check")) + self.filterButton.clicked.connect(self.__applyFilter) + + self.__checkCount = 0 + self.__selectionMode = selectionMode + if self.__selectionMode: + self.buttonBox.setStandardButtons( + QDialogButtonBox.StandardButton.Ok + | QDialogButtonBox.StandardButton.Cancel + ) + else: + self.buttonBox.setStandardButtons(QDialogButtonBox.StandardButton.Close) + + availableModules = circup.get_bundle_versions(circup.get_bundles_list()) + moduleNames = [m.replace(".py", "") for m in availableModules] + if self.__selectionMode: + for moduleName in moduleNames: + itm = QListWidgetItem(moduleName) + itm.setFlags(itm.flags() | Qt.ItemFlag.ItemIsUserCheckable) + itm.setCheckState(Qt.CheckState.Unchecked) + self.modulesList.addItem(itm) + else: + self.modulesList.addItems(moduleNames) + self.modulesList.sortItems(Qt.SortOrder.AscendingOrder) + + self.__applyFilter() + + self.__checkCountUpdated() + + @pyqtSlot() + def __applyFilter(self): + """ + Private slot to apply the filter to the list of available modules. + """ + filterStr = self.filterEdit.text() + counter = 0 + for row in range(self.modulesList.count()): + itm = self.modulesList.item(row) + visible = filterStr in itm.text() if filterStr else True + itm.setHidden(not visible) + if visible: + counter += 1 + + self.statusLabel.setText( + self.tr("Showing {0} of {1} modules/packages").format( + counter, self.modulesList.count() + ) + ) + self.filterEdit.selectAll() + self.filterEdit.setFocus(Qt.FocusReason.OtherFocusReason) + + @pyqtSlot(QListWidgetItem) + def on_modulesList_itemChanged(self, item): + """ + Private slot to handle a change of the check state of an item. + + @param item reference to the changed item + @type QTreeWidgetItem + """ + if self.__selectionMode: + if item.checkState() == Qt.CheckState.Checked: + self.__checkCount += 1 + else: + self.__checkCount -= 1 + + self.__checkCountUpdated() + + def __checkCountUpdated(self): + """ + Private method to handle an update of the check count. + """ + if self.__selectionMode: + self.buttonBox.button(QDialogButtonBox.StandardButton.Ok).setEnabled( + self.__checkCount > 0 + ) + + def getSelection(self): + """ + Public method to get the list of selected modules. + + @return list of selected modules + @rtype circup.Module + """ + results = [] + if self.__selectionMode: + for row in range(self.modulesList.count()): + itm = self.modulesList.item(row) + if itm.checkState() == Qt.CheckState.Checked: + results.append(itm.text()) + + return results
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/eric7/MicroPython/CircuitPythonUpdater/ShowModulesDialog.ui Mon Feb 06 10:09:18 2023 +0100 @@ -0,0 +1,119 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>ShowModulesDialog</class> + <widget class="QDialog" name="ShowModulesDialog"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>400</width> + <height>700</height> + </rect> + </property> + <property name="windowTitle"> + <string>Available Modules</string> + </property> + <property name="sizeGripEnabled"> + <bool>true</bool> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <layout class="QHBoxLayout" name="horizontalLayout"> + <item> + <widget class="QLabel" name="label"> + <property name="text"> + <string>Filter:</string> + </property> + </widget> + </item> + <item> + <widget class="QLineEdit" name="filterEdit"> + <property name="toolTip"> + <string>Enter a string used to filter the list below.</string> + </property> + <property name="placeholderText"> + <string>Enter Filter String</string> + </property> + <property name="clearButtonEnabled"> + <bool>true</bool> + </property> + </widget> + </item> + <item> + <widget class="QToolButton" name="filterButton"> + <property name="toolTip"> + <string>Press to apply the entered filter.</string> + </property> + </widget> + </item> + </layout> + </item> + <item> + <widget class="QListWidget" name="modulesList"> + <property name="alternatingRowColors"> + <bool>true</bool> + </property> + <property name="selectionMode"> + <enum>QAbstractItemView::NoSelection</enum> + </property> + <property name="sortingEnabled"> + <bool>false</bool> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="statusLabel"/> + </item> + <item> + <widget class="QDialogButtonBox" name="buttonBox"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="standardButtons"> + <set>QDialogButtonBox::Close</set> + </property> + </widget> + </item> + </layout> + </widget> + <tabstops> + <tabstop>filterEdit</tabstop> + <tabstop>filterButton</tabstop> + <tabstop>modulesList</tabstop> + </tabstops> + <resources/> + <connections> + <connection> + <sender>buttonBox</sender> + <signal>accepted()</signal> + <receiver>ShowModulesDialog</receiver> + <slot>accept()</slot> + <hints> + <hint type="sourcelabel"> + <x>248</x> + <y>254</y> + </hint> + <hint type="destinationlabel"> + <x>157</x> + <y>274</y> + </hint> + </hints> + </connection> + <connection> + <sender>buttonBox</sender> + <signal>rejected()</signal> + <receiver>ShowModulesDialog</receiver> + <slot>reject()</slot> + <hints> + <hint type="sourcelabel"> + <x>316</x> + <y>260</y> + </hint> + <hint type="destinationlabel"> + <x>286</x> + <y>274</y> + </hint> + </hints> + </connection> + </connections> +</ui>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/eric7/MicroPython/CircuitPythonUpdater/ShowOutdatedDialog.py Mon Feb 06 10:09:18 2023 +0100 @@ -0,0 +1,156 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2023 Detlev Offenbach <detlev@die-offenbachs.de> +# + +""" +Module implementing a dialog to show outdated modules of a connected device. +""" + +import circup + +from PyQt6.QtCore import Qt, pyqtSlot +from PyQt6.QtWidgets import QDialog, QDialogButtonBox, QTreeWidgetItem +from semver import VersionInfo + +from .Ui_ShowOutdatedDialog import Ui_ShowOutdatedDialog + + +class ShowOutdatedDialog(QDialog, Ui_ShowOutdatedDialog): + """ + Class implementing a dialog to show outdated modules of a connected device. + """ + + def __init__(self, devicePath, selectionMode=False, parent=None): + """ + Constructor + + @param devicePath path to the connected board + @type str + @param selectionMode flag indicating the activation of the selection mode + (defaults to False) + @type bool (optional) + @param parent reference to the parent widget (defaults to None) + @type QWidget (optional) + """ + super().__init__(parent) + self.setupUi(self) + + self.header.clear() + self.modulesList.clear() + + self.__checkCount = 0 + self.__selectionMode = selectionMode + if self.__selectionMode: + self.buttonBox.setStandardButtons( + QDialogButtonBox.StandardButton.Ok + | QDialogButtonBox.StandardButton.Cancel + ) + else: + self.buttonBox.setStandardButtons(QDialogButtonBox.StandardButton.Close) + + self.__modules = { + m.name: m + for m in circup.find_modules(devicePath, circup.get_bundles_list()) + if m.outofdate + } + if self.__modules: + self.header.setText( + self.tr( + "The following modules are out of date or probably need an update." + "\nMajor Updates may include breaking changes. Review before" + " updating.\nMPY Format changes require an update." + ) + ) + for module in self.__modules.values(): + if isinstance(module.bundle_version, str) and not VersionInfo.isvalid( + module.bundle_version + ): + reason = self.tr("Incorrect '__version__' Metadata") + needsUpdate = True + elif module.bad_format: + reason = self.tr("Corrupted or Unknown MPY Format") + needsUpdate = True + elif module.mpy_mismatch: + reason = self.tr("MPY Format") + needsUpdate = True + elif module.major_update: + reason = self.tr("Major Version") + needsUpdate = False + else: + reason = self.tr("Minor Version") + needsUpdate = False + itm = QTreeWidgetItem( + self.modulesList, + [ + module.name, + module.device_version + if module.device_version + else self.tr("unknown"), + module.bundle_version + if module.bundle_version + else self.tr("unknown"), + reason, + ], + ) + if self.__selectionMode: + itm.setFlags(itm.flags() | Qt.ItemFlag.ItemIsUserCheckable) + itm.setCheckState( + 0, + Qt.CheckState.Checked + if needsUpdate + else Qt.CheckState.Unchecked, + ) + if needsUpdate: + self.__checkCount += 1 + else: + self.header.setText(self.tr("All modules are up-to-date.")) + + self.modulesList.sortItems(0, Qt.SortOrder.AscendingOrder) + for column in range(self.modulesList.columnCount()): + self.modulesList.resizeColumnToContents(column) + + self.__checkCountUpdated() + + @pyqtSlot(QTreeWidgetItem, int) + def on_modulesList_itemChanged(self, item, column): + """ + Private slot to handle a change of the check state of an item. + + @param item reference to the changed item + @type QTreeWidgetItem + @param column changed column + @type int + """ + if self.__selectionMode: + if item.checkState(0) == Qt.CheckState.Checked: + self.__checkCount += 1 + else: + self.__checkCount -= 1 + + self.__checkCountUpdated() + + def __checkCountUpdated(self): + """ + Private method to handle an update of the check count. + """ + if self.__selectionMode: + self.buttonBox.button(QDialogButtonBox.StandardButton.Ok).setEnabled( + self.__checkCount > 0 + ) + + def getSelection(self): + """ + Public method to get the list of selected modules. + + @return list of selected modules + @rtype circup.Module + """ + results = [] + if self.__selectionMode: + for row in range(self.modulesList.topLevelItemCount()): + itm = self.modulesList.topLevelItem(row) + if itm.checkState(0) == Qt.CheckState.Checked: + results.append(self.__modules[itm.text(0)]) + + return results
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/eric7/MicroPython/CircuitPythonUpdater/ShowOutdatedDialog.ui Mon Feb 06 10:09:18 2023 +0100 @@ -0,0 +1,113 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>ShowOutdatedDialog</class> + <widget class="QDialog" name="ShowOutdatedDialog"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>600</width> + <height>500</height> + </rect> + </property> + <property name="windowTitle"> + <string>Outdated Modules</string> + </property> + <property name="sizeGripEnabled"> + <bool>true</bool> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <widget class="QLabel" name="header"> + <property name="wordWrap"> + <bool>true</bool> + </property> + </widget> + </item> + <item> + <widget class="QTreeWidget" name="modulesList"> + <property name="alternatingRowColors"> + <bool>true</bool> + </property> + <property name="selectionMode"> + <enum>QAbstractItemView::NoSelection</enum> + </property> + <property name="rootIsDecorated"> + <bool>false</bool> + </property> + <property name="itemsExpandable"> + <bool>false</bool> + </property> + <attribute name="headerShowSortIndicator" stdset="0"> + <bool>false</bool> + </attribute> + <column> + <property name="text"> + <string>Module</string> + </property> + </column> + <column> + <property name="text"> + <string>Version</string> + </property> + </column> + <column> + <property name="text"> + <string>Latest</string> + </property> + </column> + <column> + <property name="text"> + <string>Update Reason</string> + </property> + </column> + </widget> + </item> + <item> + <widget class="QDialogButtonBox" name="buttonBox"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="standardButtons"> + <set>QDialogButtonBox::Close</set> + </property> + </widget> + </item> + </layout> + </widget> + <resources/> + <connections> + <connection> + <sender>buttonBox</sender> + <signal>accepted()</signal> + <receiver>ShowOutdatedDialog</receiver> + <slot>accept()</slot> + <hints> + <hint type="sourcelabel"> + <x>248</x> + <y>254</y> + </hint> + <hint type="destinationlabel"> + <x>157</x> + <y>274</y> + </hint> + </hints> + </connection> + <connection> + <sender>buttonBox</sender> + <signal>rejected()</signal> + <receiver>ShowOutdatedDialog</receiver> + <slot>reject()</slot> + <hints> + <hint type="sourcelabel"> + <x>316</x> + <y>260</y> + </hint> + <hint type="destinationlabel"> + <x>286</x> + <y>274</y> + </hint> + </hints> + </connection> + </connections> +</ui>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/eric7/MicroPython/CircuitPythonUpdater/__init__.py Mon Feb 06 10:09:18 2023 +0100 @@ -0,0 +1,8 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2023 Detlev Offenbach <detlev@die-offenbachs.de> +# + +""" +Package implementing the updater and associated dialogs. +"""
--- a/src/eric7/PipInterface/PipFreezeDialog.py Mon Feb 06 10:02:35 2023 +0100 +++ b/src/eric7/PipInterface/PipFreezeDialog.py Mon Feb 06 10:09:18 2023 +0100 @@ -55,11 +55,12 @@ if mode is PipFreezeDialogModes.Constraints: self.constraintsCheckBox.setChecked(False) self.constraintsCheckBox.setEnabled(False) - - self.setWindowTitle(self.tr("Generate Constraints")) + self.__title = self.tr("Generate Constraints") elif mode is PipFreezeDialogModes.Requirements: - self.setWindowTitle(self.tr("Generate Requirements")) + self.__title = self.tr("Generate Requirements") + + self.setWindowTitle(self.__title) self.__refreshButton = self.buttonBox.addButton( self.tr("&Refresh"), QDialogButtonBox.ButtonRole.ActionRole @@ -139,7 +140,7 @@ ok = ( EricMessageBox.yesNo( self, - self.tr("Generate Requirements"), + self.__title, self.tr( """The requirements were changed. Do you want""" """ to overwrite these changes?""" @@ -227,7 +228,7 @@ if os.path.exists(fileName): ok = EricMessageBox.warning( self, - self.tr("Generate Requirements"), + self.__title, self.tr( """The file <b>{0}</b> already exists. Do you want""" """ to overwrite it?""" @@ -245,7 +246,7 @@ except OSError as err: EricMessageBox.critical( self, - self.tr("Generate Requirements"), + self.__title, self.tr( """<p>The requirements could not be written""" """ to <b>{0}</b>.</p><p>Reason: {1}</p>""" @@ -267,7 +268,7 @@ """ fileName, selectedFilter = EricFileDialog.getSaveFileNameAndFilter( self, - self.tr("Generate Requirements"), + self.__title, os.path.expanduser("~"), self.tr("Text Files (*.txt);;All Files (*)"), None,
--- a/src/eric7/PipInterface/PipFreezeDialog.ui Mon Feb 06 10:02:35 2023 +0100 +++ b/src/eric7/PipInterface/PipFreezeDialog.ui Mon Feb 06 10:09:18 2023 +0100 @@ -106,13 +106,30 @@ </property> </widget> </item> - <item row="1" column="1"> - <widget class="QPushButton" name="saveToButton"> + <item row="3" column="1"> + <widget class="Line" name="line"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + </widget> + </item> + <item row="7" column="1"> + <widget class="QPushButton" name="replaceAllButton"> <property name="toolTip"> - <string>Save to a new file</string> + <string>Replace all text with the requirements text</string> </property> <property name="text"> - <string>Save To</string> + <string>Replace All</string> + </property> + </widget> + </item> + <item row="5" column="1"> + <widget class="QPushButton" name="insertButton"> + <property name="toolTip"> + <string>Insert the requirements text at the cursor position</string> + </property> + <property name="text"> + <string>Insert</string> </property> </widget> </item> @@ -126,34 +143,14 @@ </property> </widget> </item> - <item row="3" column="1"> - <widget class="QPushButton" name="insertButton"> - <property name="toolTip"> - <string>Insert the requirements text at the cursor position</string> - </property> - <property name="text"> - <string>Insert</string> + <item row="0" column="0" rowspan="9"> + <widget class="QPlainTextEdit" name="requirementsEdit"> + <property name="tabChangesFocus"> + <bool>true</bool> </property> </widget> </item> - <item row="4" column="1"> - <widget class="QPushButton" name="replaceSelectionButton"> - <property name="text"> - <string>Replace Selection</string> - </property> - </widget> - </item> - <item row="5" column="1"> - <widget class="QPushButton" name="replaceAllButton"> - <property name="toolTip"> - <string>Replace all text with the requirements text</string> - </property> - <property name="text"> - <string>Replace All</string> - </property> - </widget> - </item> - <item row="6" column="1"> + <item row="8" column="1"> <spacer name="verticalSpacer"> <property name="orientation"> <enum>Qt::Vertical</enum> @@ -166,10 +163,30 @@ </property> </spacer> </item> - <item row="0" column="0" rowspan="7"> - <widget class="QPlainTextEdit" name="requirementsEdit"> - <property name="tabChangesFocus"> - <bool>true</bool> + <item row="6" column="1"> + <widget class="QPushButton" name="replaceSelectionButton"> + <property name="text"> + <string>Replace Selection</string> + </property> + </widget> + </item> + <item row="1" column="1"> + <widget class="QPushButton" name="saveToButton"> + <property name="toolTip"> + <string>Save to a new file</string> + </property> + <property name="text"> + <string>Save To</string> + </property> + </widget> + </item> + <item row="4" column="1"> + <widget class="QLabel" name="label_2"> + <property name="text"> + <string><b>Editor Actions</b></string> + </property> + <property name="alignment"> + <set>Qt::AlignCenter</set> </property> </widget> </item>
--- a/src/eric7/eric7_doc.py Mon Feb 06 10:02:35 2023 +0100 +++ b/src/eric7/eric7_doc.py Mon Feb 06 10:09:18 2023 +0100 @@ -421,6 +421,7 @@ continue try: + print("Processing", file) module = ModuleParser.readModule( file, basename=basename, @@ -435,6 +436,13 @@ except ImportError as v: sys.stderr.write("{0} error: {1}\n".format(file, v)) continue + except Exception as ex: + sys.stderr.write( + "{0} error while parsing: {1}\n".format( + file, str(ex) + ) + ) + raise f = FileSystemUtilities.joinext( os.path.join(outputDir, moduleDocument.name()), ".html" @@ -458,9 +466,21 @@ out.write(doc) except OSError as v: sys.stderr.write("{0} error: {1}\n".format(file, v[1])) + except Exception as ex: + sys.stderr.write( + "{0} error while writing: {1}\n".format( + file, str(ex) + ) + ) + raise else: sys.stdout.write("{0} ok\n".format(f)) + sys.stdout.flush() + sys.stderr.flush() + + sys.stdout.write("code documentation generated") + sys.stdout.flush() sys.stderr.flush()