Thu, 20 Mar 2025 11:54:57 +0100
Corrected some issues related to controllers with small RAM and limited numbers support (i.e. BBC micro:bit and Calliope mini).
--- a/src/eric7/APIs/Python3/eric7.api Tue Mar 18 18:32:29 2025 +0100 +++ b/src/eric7/APIs/Python3/eric7.api Thu Mar 20 11:54:57 2025 +0100 @@ -3017,6 +3017,7 @@ eric7.MicroPython.Devices.MicrobitDevices.MicrobitDevice.deviceName?4() eric7.MicroPython.Devices.MicrobitDevices.MicrobitDevice.forceInterrupt?4() eric7.MicroPython.Devices.MicrobitDevices.MicrobitDevice.getBluetoothStatus?4() +eric7.MicroPython.Devices.MicrobitDevices.MicrobitDevice.getBoardInformation?4() eric7.MicroPython.Devices.MicrobitDevices.MicrobitDevice.getDeviceScan?4(timeout=10) eric7.MicroPython.Devices.MicrobitDevices.MicrobitDevice.getDocumentationUrl?4() eric7.MicroPython.Devices.MicrobitDevices.MicrobitDevice.getDownloadMenuEntries?4() @@ -9613,6 +9614,9 @@ eric7.QScintilla.MiniEditor.MiniEditor.getSearchSelectionHighlight?4() eric7.QScintilla.MiniEditor.MiniEditor.gotoLine?4(line, pos=1) eric7.QScintilla.MiniEditor.MiniEditor.highlightSearchSelection?4(startLine, startIndex, endLine, endIndex) +eric7.QScintilla.MiniEditor.MiniEditor.isMicroPythonFile?4() +eric7.QScintilla.MiniEditor.MiniEditor.isPy3File?4() +eric7.QScintilla.MiniEditor.MiniEditor.isPyFile?7 eric7.QScintilla.MiniEditor.MiniEditor.languageChanged?7 eric7.QScintilla.MiniEditor.MiniEditor.refreshed?7 eric7.QScintilla.MiniEditor.MiniEditor.setFileName?4(name)
--- a/src/eric7/Documentation/Help/source.qhp Tue Mar 18 18:32:29 2025 +0100 +++ b/src/eric7/Documentation/Help/source.qhp Thu Mar 20 11:54:57 2025 +0100 @@ -11875,6 +11875,7 @@ <keyword name="MicrobitDevice.deviceName" id="MicrobitDevice.deviceName" ref="eric7.MicroPython.Devices.MicrobitDevices.html#MicrobitDevice.deviceName" /> <keyword name="MicrobitDevice.forceInterrupt" id="MicrobitDevice.forceInterrupt" ref="eric7.MicroPython.Devices.MicrobitDevices.html#MicrobitDevice.forceInterrupt" /> <keyword name="MicrobitDevice.getBluetoothStatus" id="MicrobitDevice.getBluetoothStatus" ref="eric7.MicroPython.Devices.MicrobitDevices.html#MicrobitDevice.getBluetoothStatus" /> + <keyword name="MicrobitDevice.getBoardInformation" id="MicrobitDevice.getBoardInformation" ref="eric7.MicroPython.Devices.MicrobitDevices.html#MicrobitDevice.getBoardInformation" /> <keyword name="MicrobitDevice.getDeviceScan" id="MicrobitDevice.getDeviceScan" ref="eric7.MicroPython.Devices.MicrobitDevices.html#MicrobitDevice.getDeviceScan" /> <keyword name="MicrobitDevice.getDocumentationUrl" id="MicrobitDevice.getDocumentationUrl" ref="eric7.MicroPython.Devices.MicrobitDevices.html#MicrobitDevice.getDocumentationUrl" /> <keyword name="MicrobitDevice.getDownloadMenuEntries" id="MicrobitDevice.getDownloadMenuEntries" ref="eric7.MicroPython.Devices.MicrobitDevices.html#MicrobitDevice.getDownloadMenuEntries" /> @@ -11996,6 +11997,8 @@ <keyword name="MiniEditor.getSearchSelectionHighlight" id="MiniEditor.getSearchSelectionHighlight" ref="eric7.QScintilla.MiniEditor.html#MiniEditor.getSearchSelectionHighlight" /> <keyword name="MiniEditor.gotoLine" id="MiniEditor.gotoLine" ref="eric7.QScintilla.MiniEditor.html#MiniEditor.gotoLine" /> <keyword name="MiniEditor.highlightSearchSelection" id="MiniEditor.highlightSearchSelection" ref="eric7.QScintilla.MiniEditor.html#MiniEditor.highlightSearchSelection" /> + <keyword name="MiniEditor.isMicroPythonFile" id="MiniEditor.isMicroPythonFile" ref="eric7.QScintilla.MiniEditor.html#MiniEditor.isMicroPythonFile" /> + <keyword name="MiniEditor.isPy3File" id="MiniEditor.isPy3File" ref="eric7.QScintilla.MiniEditor.html#MiniEditor.isPy3File" /> <keyword name="MiniEditor.setFileName" id="MiniEditor.setFileName" ref="eric7.QScintilla.MiniEditor.html#MiniEditor.setFileName" /> <keyword name="MiniEditor.setLanguage" id="MiniEditor.setLanguage" ref="eric7.QScintilla.MiniEditor.html#MiniEditor.setLanguage" /> <keyword name="MiniEditor.setModified" id="MiniEditor.setModified" ref="eric7.QScintilla.MiniEditor.html#MiniEditor.setModified" />
--- a/src/eric7/Documentation/Source/eric7.MicroPython.Devices.MicrobitDevices.html Tue Mar 18 18:32:29 2025 +0100 +++ b/src/eric7/Documentation/Source/eric7.MicroPython.Devices.MicrobitDevices.html Thu Mar 20 11:54:57 2025 +0100 @@ -140,6 +140,10 @@ <td>Public method to get Bluetooth status data of the connected board.</td> </tr> <tr> +<td><a href="#MicrobitDevice.getBoardInformation">getBoardInformation</a></td> +<td>Public method to get some information data of the connected board.</td> +</tr> +<tr> <td><a href="#MicrobitDevice.getDeviceScan">getDeviceScan</a></td> <td>Public method to perform a Bluetooth device scan.</td> </tr> @@ -576,6 +580,25 @@ raised to indicate an issue with the device </dd> </dl> +<a NAME="MicrobitDevice.getBoardInformation" ID="MicrobitDevice.getBoardInformation"></a> +<h4>MicrobitDevice.getBoardInformation</h4> +<b>getBoardInformation</b>(<i></i>) +<p> + Public method to get some information data of the connected board. +</p> + +<dl> +<dt>Return:</dt> +<dd> +dictionary containing the determined data +</dd> +</dl> +<dl> +<dt>Return Type:</dt> +<dd> +dict +</dd> +</dl> <a NAME="MicrobitDevice.getDeviceScan" ID="MicrobitDevice.getDeviceScan"></a> <h4>MicrobitDevice.getDeviceScan</h4> <b>getDeviceScan</b>(<i>timeout=10</i>)
--- a/src/eric7/Documentation/Source/eric7.QScintilla.MiniEditor.html Tue Mar 18 18:32:29 2025 +0100 +++ b/src/eric7/Documentation/Source/eric7.QScintilla.MiniEditor.html Thu Mar 20 11:54:57 2025 +0100 @@ -75,7 +75,7 @@ EricMainWindow <h3>Class Attributes</h3> <table> -<tr><td>None</td></tr> +<tr><td>isPyFile</td></tr> </table> <h3>Class Methods</h3> @@ -446,6 +446,14 @@ <td>Public method to set a highlight for the selection at the start of a search.</td> </tr> <tr> +<td><a href="#MiniEditor.isMicroPythonFile">isMicroPythonFile</a></td> +<td>Public method to return a flag indicating a MicroPython file.</td> +</tr> +<tr> +<td><a href="#MiniEditor.isPy3File">isPy3File</a></td> +<td>Public method to return a flag indicating a Python3 file.</td> +</tr> +<tr> <td><a href="#MiniEditor.setFileName">setFileName</a></td> <td>Public method to set the file name of the file being displayed.</td> </tr> @@ -1667,6 +1675,44 @@ index of the selection end </dd> </dl> +<a NAME="MiniEditor.isMicroPythonFile" ID="MiniEditor.isMicroPythonFile"></a> +<h4>MiniEditor.isMicroPythonFile</h4> +<b>isMicroPythonFile</b>(<i></i>) +<p> + Public method to return a flag indicating a MicroPython file. +</p> + +<dl> +<dt>Return:</dt> +<dd> +flag indicating a MicroPython file +</dd> +</dl> +<dl> +<dt>Return Type:</dt> +<dd> +bool +</dd> +</dl> +<a NAME="MiniEditor.isPy3File" ID="MiniEditor.isPy3File"></a> +<h4>MiniEditor.isPy3File</h4> +<b>isPy3File</b>(<i></i>) +<p> + Public method to return a flag indicating a Python3 file. +</p> + +<dl> +<dt>Return:</dt> +<dd> +flag indicating a Python3 file +</dd> +</dl> +<dl> +<dt>Return Type:</dt> +<dd> +bool +</dd> +</dl> <a NAME="MiniEditor.setFileName" ID="MiniEditor.setFileName"></a> <h4>MiniEditor.setFileName</h4> <b>setFileName</b>(<i>name</i>)
--- a/src/eric7/MicroPython/Devices/DeviceBase.py Tue Mar 18 18:32:29 2025 +0100 +++ b/src/eric7/MicroPython/Devices/DeviceBase.py Thu Mar 20 11:54:57 2025 +0100 @@ -1065,8 +1065,8 @@ @rtype dict @exception OSError raised to indicate an issue with the device """ - command = """ -def get_device_data(): + commands = [ # needs to be splitted for boards with low memory + """def get_device_data(): res = {} try: @@ -1084,6 +1084,13 @@ res['release'] = '.'.join(str(v) for v in sys.implementation.version) res['version'] = sys.version.split(';', 1)[-1].strip() res['machine'] = sys.implementation._machine + return res + +print(get_device_data()) +del get_device_data +""", + """def get_device_data(): + res = {} import sys res['py_platform'] = sys.platform @@ -1105,6 +1112,13 @@ res['mpy_file_version'] = sys.implementation.mpy & 0xff else: res['mpy_file_version'] = 0 + return res + +print(get_device_data()) +del get_device_data +""", + """def get_device_data(): + res = {} try: import pimoroni @@ -1120,6 +1134,13 @@ res['mpy_variant'] = '' res['mpy_variant_info'] = '' res['mpy_variant_version'] = '' + return res + +print(get_device_data()) +del get_device_data +""", + """def get_device_data(): + res = {} res['mip'] = False res['upip'] = False @@ -1144,10 +1165,14 @@ print(get_device_data()) del get_device_data """ - out, err = self.executeCommands(command, mode=self._submitMode) - if err: - raise OSError(self._shortError(err)) - return ast.literal_eval(out.decode("utf-8")) + ] + res = {} + for command in commands: + out, err = self.executeCommands(command, mode=self._submitMode) + if err: + raise OSError(self._shortError(err)) + res.update(ast.literal_eval(out.decode("utf-8"))) + return res def getBoardInformation(self): """ @@ -1161,27 +1186,6 @@ """def get_board_info(): res = {} - import gc - gc.enable() - gc.collect() - mem_alloc = gc.mem_alloc() - mem_free = gc.mem_free() - mem_total = mem_alloc + mem_free - res['mem_total_kb'] = mem_total / 1024.0 - res['mem_used_kb'] = mem_alloc / 1024.0 - res['mem_used_pc'] = mem_alloc / mem_total * 100.0 - res['mem_free_kb'] = mem_free / 1024.0 - res['mem_free_pc'] = mem_free / mem_total * 100.0 - del gc, mem_alloc, mem_free, mem_total - - return res - -print(get_board_info()) -del get_board_info -""", - """def get_board_info(): - res = {} - try: import os uname = os.uname() @@ -1242,60 +1246,6 @@ res = {} try: - import os - stat_ = os.statvfs('/flash') - res['flash_info_available'] = True - res['flash_total_kb'] = stat_[2] * stat_[0] / 1024.0 - res['flash_free_kb'] = stat_[3] * stat_[0] / 1024.0 - res['flash_used_kb'] = res['flash_total_kb'] - res['flash_free_kb'] - res['flash_free_pc'] = res['flash_free_kb'] / res['flash_total_kb'] * 100.0 - res['flash_used_pc'] = res['flash_used_kb'] / res['flash_total_kb'] * 100.0 - except (AttributeError, OSError): - res['flash_info_available'] = False - - return res - -print(get_board_info()) -del get_board_info -""", - """def get_board_info(): - res = {} - - try: - import machine as mc - try: - if isinstance(mc.freq(), tuple): - res['mc_frequency_mhz'] = mc.freq()[0] / 1000000.0 - else: - res['mc_frequency_mhz'] = mc.freq() / 1000000.0 - except NotImplementedError: - res['mc_frequency_mhz'] = None - try: - res['mc_temp_c'] = mc.Temp().read() - except AttributeError: - pass - res['mc_id'] = mc.unique_id() - except ImportError: - try: - import microcontroller as mc - res['mc_frequency_mhz'] = mc.cpu.frequency / 1000000.0 - res['mc_temp_c'] = mc.cpu.temperature - res['mc_id'] = mc.cpu.uid - except ImportError: - res['mc_frequency_mhz'] = None - res['mc_temp_c'] = None - if 'mc_id' in res: - res['mc_id'] = ':'.join('{0:02X}'.format(x) for x in res['mc_id']) - - return res - -print(get_board_info()) -del get_board_info -""", - """def get_board_info(): - res = {} - - try: import ulab res['ulab'] = ulab.__version__ except ImportError: @@ -1307,12 +1257,124 @@ del get_board_info """, ] + + gc_command = """def get_board_info(): + res = {} + + import gc + gc.enable() + gc.collect() + mem_alloc = gc.mem_alloc() + mem_free = gc.mem_free() + mem_total = mem_alloc + mem_free + res['mem_total'] = mem_total + res['mem_used'] = mem_alloc + res['mem_free'] = mem_free + del gc, mem_alloc, mem_free, mem_total + + return res + +print(get_board_info()) +del get_board_info +""" + + flash_command = """def get_board_info(): + res = {} + + try: + import os + stat_ = os.statvfs('/flash') + res['flash_info_available'] = True + res['flash_total'] = stat_[2] * stat_[0] + res['flash_free'] = stat_[3] * stat_[0] + except (AttributeError, OSError): + res['flash_info_available'] = False + + return res + +print(get_board_info()) +del get_board_info +""" + + machine_command = """def get_board_info(): + res = {} + + try: + import machine as mc + try: + if isinstance(mc.freq(), tuple): + res['mc_frequency'] = mc.freq()[0] + else: + res['mc_frequency'] = mc.freq() + except NotImplementedError: + res['mc_frequency'] = None + try: + res['mc_temp_c'] = mc.Temp().read() + except AttributeError: + res['mc_temp_c'] = None + res['mc_id'] = mc.unique_id() + except ImportError: + try: + import microcontroller as mc + res['mc_frequency'] = mc.cpu.frequency + res['mc_temp_c'] = mc.cpu.temperature + res['mc_id'] = mc.cpu.uid + except ImportError: + res['mc_frequency'] = None + res['mc_temp_c'] = None + if 'mc_id' in res: + res['mc_id'] = ':'.join('{0:02X}'.format(x) for x in res['mc_id']) + else: + res['mc_id'] = None + + return res + +print(get_board_info()) +del get_board_info +""" res = {} for command in commands: out, err = self.executeCommands(command, mode=self._submitMode) if err: raise OSError(self._shortError(err)) res.update(ast.literal_eval(out.decode("utf-8"))) + + # Execute the commands needing some special postprocessing due to some + # boards supporting integer only. + out, err = self.executeCommands(gc_command, mode=self._submitMode) + if err: + raise OSError(self._shortError(err)) + gc_res = ast.literal_eval(out.decode("utf-8")) + res['mem_total_kb'] = gc_res["mem_total"] / 1024.0 + res['mem_used_kb'] = gc_res["mem_used"] / 1024.0 + res['mem_used_pc'] = gc_res["mem_used"] / gc_res["mem_total"] * 100.0 + res['mem_free_kb'] = gc_res["mem_free"] / 1024.0 + res['mem_free_pc'] = gc_res["mem_free"] / gc_res["mem_total"] * 100.0 + + out, err = self.executeCommands(flash_command, mode=self._submitMode) + if err: + raise OSError(self._shortError(err)) + flash_res = ast.literal_eval(out.decode("utf-8")) + res['flash_info_available'] = flash_res["flash_info_available"] + if flash_res["flash_info_available"]: + res['flash_total_kb'] = flash_res["flash_total"] / 1024.0 + res['flash_free_kb'] = flash_res["flash_free"] / 1024.0 + res['flash_used_kb'] = res['flash_total_kb'] - res['flash_free_kb'] + res['flash_free_pc'] = res['flash_free_kb'] / res['flash_total_kb'] * 100.0 + res['flash_used_pc'] = res['flash_used_kb'] / res['flash_total_kb'] * 100.0 + + out, err = self.executeCommands(machine_command, mode=self._submitMode) + if err: + raise OSError(self._shortError(err)) + machine_res = ast.literal_eval(out.decode("utf-8")) + res['mc_frequency_mhz'] = ( + machine_res["mc_frequency"] / 1000000.0 + if machine_res["mc_frequency"] is not None + else None + ) + res["mc_temp_c"] = machine_res["mc_temp_c"] + res["mc_id"] = machine_res["mc_id"] + return res def getModules(self):
--- a/src/eric7/MicroPython/Devices/MicrobitDevices.py Tue Mar 18 18:32:29 2025 +0100 +++ b/src/eric7/MicroPython/Devices/MicrobitDevices.py Thu Mar 20 11:54:57 2025 +0100 @@ -73,7 +73,8 @@ """ super().setConnected(connected) - self._deviceData["local_mip"] = False + if self._deviceData: + self._deviceData["local_mip"] = False if self.hasCircuitPython(): self._submitMode = "paste" @@ -281,20 +282,22 @@ # BBC micro:bit if firmware: deviceDirectories = FileSystemUtilities.findVolume( - "MAINTENANCE", findAll=True + "MAINTENANCE", findAll=True, markerFile="DETAILS.TXT" ) else: deviceDirectories = FileSystemUtilities.findVolume( - "MICROBIT", findAll=True + "MICROBIT", findAll=True, markerFile="DETAILS.TXT" ) else: # Calliope mini if firmware: deviceDirectories = FileSystemUtilities.findVolume( - "MAINTENANCE", findAll=True + "MAINTENANCE", findAll=True, markerFile="DETAILS.TXT" ) else: - deviceDirectories = FileSystemUtilities.findVolume("MINI", findAll=True) + deviceDirectories = FileSystemUtilities.findVolume( + "MINI", findAll=True, markerFile="DETAILS.TXT" + ) if len(deviceDirectories) == 0: if self.getDeviceType() == "bbc_microbit": # BBC micro:bit is not ready or not mounted @@ -968,6 +971,21 @@ return True + def getBoardInformation(self): + """ + Public method to get some information data of the connected board. + + @return dictionary containing the determined data + @rtype dict + """ + res = super().getBoardInformation() + with contextlib.suppress(KeyError): + if res["mc_temp_c"] is not None: + res["mc_temp_c"] = res["mc_temp_c"] / 100 # due to integer support only + + return res + + def createDevice(microPythonWidget, deviceType, _vid, _pid, _boardName, serialNumber): """ Function to instantiate a MicroPython device object.
--- a/src/eric7/QScintilla/MiniEditor.py Tue Mar 18 18:32:29 2025 +0100 +++ b/src/eric7/QScintilla/MiniEditor.py Thu Mar 20 11:54:57 2025 +0100 @@ -54,7 +54,7 @@ from eric7.EricWidgets.EricClickableLabel import EricClickableLabel from eric7.EricWidgets.EricMainWindow import EricMainWindow from eric7.EricWidgets.EricZoomWidget import EricZoomWidget -from eric7.SystemUtilities import FileSystemUtilities, OSUtilities +from eric7.SystemUtilities import FileSystemUtilities, OSUtilities, PythonUtilities from . import Lexers from .EditorOutline import EditorOutlineView @@ -3421,6 +3421,26 @@ """ return pathlib.Path(fullFileName).name + def isPy3File(self): + """ + Public method to return a flag indicating a Python3 file. + + @return flag indicating a Python3 file + @rtype bool + """ + return self.filetype in ("Python", "Python3") + + isPyFile = isPy3File + + def isMicroPythonFile(self): + """ + Public method to return a flag indicating a MicroPython file. + + @return flag indicating a MicroPython file + @rtype bool + """ + return self.filetype == "MicroPython" + def __modificationChanged(self, m): """ Private slot to handle the modificationChanged signal.