From 85518efb6610d8f8a7633bda8dea13e28b605869 Mon Sep 17 00:00:00 2001 From: Josverl Date: Tue, 10 Dec 2024 13:50:45 +0000 Subject: [PATCH] Update mip packages --- mip/v5/createstubs.py | 24 +- mip/v5/createstubs_db.py | 12 +- mip/v5/createstubs_db_min.py | 1151 ++++++++-------------------- mip/v5/createstubs_db_mpy.mpy | Bin 9974 -> 9780 bytes mip/v5/createstubs_mem.py | 12 +- mip/v5/createstubs_mem_min.py | 1067 ++++++++------------------ mip/v5/createstubs_mem_mpy.mpy | Bin 9450 -> 9302 bytes mip/v5/createstubs_min.py | 1279 ++++++++------------------------ mip/v5/createstubs_mpy.mpy | Bin 12340 -> 12216 bytes mip/v5/modulelist.txt | 14 + mip/v6/createstubs.py | 24 +- mip/v6/createstubs_db.py | 12 +- mip/v6/createstubs_db_min.py | 1151 ++++++++-------------------- mip/v6/createstubs_db_mpy.mpy | Bin 9260 -> 9560 bytes mip/v6/createstubs_mem.py | 12 +- mip/v6/createstubs_mem_min.py | 1067 ++++++++------------------ mip/v6/createstubs_mem_mpy.mpy | Bin 8874 -> 9142 bytes mip/v6/createstubs_min.py | 1279 ++++++++------------------------ mip/v6/createstubs_mpy.mpy | Bin 12263 -> 12570 bytes mip/v6/modulelist.txt | 14 + 20 files changed, 1946 insertions(+), 5172 deletions(-) diff --git a/mip/v5/createstubs.py b/mip/v5/createstubs.py index 8c6410c4..42656793 100644 --- a/mip/v5/createstubs.py +++ b/mip/v5/createstubs.py @@ -24,7 +24,7 @@ except ImportError: from ucollections import OrderedDict # type: ignore -__version__ = "v1.23.0" +__version__ = "v1.24.0" ENOENT = 2 _MAX_CLASS_LEVEL = 2 # Max class nesting LIBS = ["lib", "/lib", "/sd/lib", "/flash/lib", "."] @@ -488,7 +488,7 @@ def ensure_folder(path: str): def _build(s): # extract build from sys.version or os.uname().version if available - # sys.version: 'MicroPython v1.23.0-preview.6.g3d0b6276f' + # sys.version: 'MicroPython v1.24.0-preview.6.g3d0b6276f' # sys.implementation.version: 'v1.13-103-gb137d064e' if not s: return "" @@ -595,10 +595,10 @@ def _info(): # type:() -> dict[str, str] if ( info["version"] and info["version"].endswith(".0") - and info["version"] >= "1.10.0" # versions from 1.10.0 to 1.23.0 do not have a micro .0 + and info["version"] >= "1.10.0" # versions from 1.10.0 to 1.24.0 do not have a micro .0 and info["version"] <= "1.19.9" ): - # versions from 1.10.0 to 1.23.0 do not have a micro .0 + # versions from 1.10.0 to 1.24.0 do not have a micro .0 info["version"] = info["version"][:-2] # spell-checker: disable @@ -657,7 +657,7 @@ def get_root() -> str: # sourcery skip: use-assigned-variable # unix port c = "." r = c - for r in [c, "/sd", "/flash", "/", "."]: + for r in ["/sd", "/flash", "/", c, "."]: try: _ = os.stat(r) break @@ -801,6 +801,7 @@ def main(): "breakout_trackball", "breakout_vl53l5cx", "btree", + "cc3200", "cmath", "collections", "crypto", @@ -811,10 +812,12 @@ def main(): "display", "display_driver_utils", "ds18x20", + "embed", "encoder", "errno", "esp", "esp32", + "esp8266", "espidf", "espnow", "ffi", @@ -854,6 +857,7 @@ def main(): "microWebSrv", "microWebTemplate", "micropython", + "mimxrt", "mip", "mip/__init__", "mip/__main__", @@ -862,11 +866,13 @@ def main(): "mpu9250", "neopixel", "network", + "nrf", "ntptime", "onewire", "openamp", "os", "pcf85063a", + "pic16bit", "picoexplorer", "picographics", "picokeypad", @@ -878,12 +884,16 @@ def main(): "pimoroni_i2c", "plasma", "platform", + "powerpc", "pyb", "pycom", "pye", + "qemu", "qrcode", "queue", "random", + "renesas", + "renesas-ra", "requests", "requests/__init__", "rp2", @@ -896,6 +906,7 @@ def main(): "ssh", "ssl", "stm", + "stm32", "struct", "sys", "termios", @@ -936,6 +947,7 @@ def main(): "umqtt/__init__", "umqtt/robust", "umqtt/simple", + "unix", "uos", "uplatform", "uqueue", @@ -961,8 +973,10 @@ def main(): "uzlib", "version", "vfs", + "webassembly", "websocket", "websocket_helper", + "windows", "wipy", "writer", "xpt2046", diff --git a/mip/v5/createstubs_db.py b/mip/v5/createstubs_db.py index 634433a4..d20cb87e 100644 --- a/mip/v5/createstubs_db.py +++ b/mip/v5/createstubs_db.py @@ -18,7 +18,7 @@ - cross compilation, using mpy-cross, to avoid the compilation step on the micropython device -This variant was generated from createstubs.py by micropython-stubber v1.23.0 +This variant was generated from createstubs.py by micropython-stubber v1.24.0 """ # Copyright (c) 2019-2024 Jos Verlinde @@ -43,7 +43,7 @@ except ImportError: from ucollections import OrderedDict # type: ignore -__version__ = "v1.23.0" +__version__ = "v1.24.0" ENOENT = 2 _MAX_CLASS_LEVEL = 2 # Max class nesting LIBS = ["lib", "/lib", "/sd/lib", "/flash/lib", "."] @@ -501,7 +501,7 @@ def ensure_folder(path: str): def _build(s): # extract build from sys.version or os.uname().version if available - # sys.version: 'MicroPython v1.23.0-preview.6.g3d0b6276f' + # sys.version: 'MicroPython v1.24.0-preview.6.g3d0b6276f' # sys.implementation.version: 'v1.13-103-gb137d064e' if not s: return "" @@ -606,10 +606,10 @@ def _info(): # type:() -> dict[str, str] if ( info["version"] and info["version"].endswith(".0") - and info["version"] >= "1.10.0" # versions from 1.10.0 to 1.23.0 do not have a micro .0 + and info["version"] >= "1.10.0" # versions from 1.10.0 to 1.24.0 do not have a micro .0 and info["version"] <= "1.19.9" ): - # versions from 1.10.0 to 1.23.0 do not have a micro .0 + # versions from 1.10.0 to 1.24.0 do not have a micro .0 info["version"] = info["version"][:-2] # spell-checker: disable @@ -668,7 +668,7 @@ def get_root() -> str: # sourcery skip: use-assigned-variable # unix port c = "." r = c - for r in [c, "/sd", "/flash", "/", "."]: + for r in ["/sd", "/flash", "/", c, "."]: try: _ = os.stat(r) break diff --git a/mip/v5/createstubs_db_min.py b/mip/v5/createstubs_db_min.py index 634433a4..b48f1711 100644 --- a/mip/v5/createstubs_db_min.py +++ b/mip/v5/createstubs_db_min.py @@ -1,825 +1,332 @@ -""" -Create stubs for (all) modules on a MicroPython board. - - This variant of the createstubs.py script is optimized for use on very-low-memory devices. - Note: this version has undergone limited testing. - - 1) reads the list of modules from a text file `modulelist.txt` that should be uploaded to the device. - 2) stored the already processed modules in a text file `modulelist.done` - 3) process the modules in the database: - - stub the module - - update the modulelist.done file - - reboots the device if it runs out of memory - 4) creates the modules.json - - If that cannot be found then only a single module (micropython) is stubbed. - In order to run this on low-memory devices two additional steps are recommended: - - minification, using python-minifierto reduce overall size, and remove logging overhead. - - cross compilation, using mpy-cross, to avoid the compilation step on the micropython device - - -This variant was generated from createstubs.py by micropython-stubber v1.23.0 -""" - -# Copyright (c) 2019-2024 Jos Verlinde - -import gc -import os -import sys +A2='No report file' +A1='Failed to create the report.' +A0='method' +z='function' +y='bool' +x='str' +w='float' +v='int' +u='micropython' +t='stubber' +s=Exception +r=KeyError +q=sorted +p=MemoryError +o=NotImplementedError +k=',\n' +j='modules.json' +i='{}/{}' +h='w' +g='dict' +f='list' +e='tuple' +d=TypeError +c=str +b=repr +W='-preview' +V='-' +U='board' +T=IndexError +S=print +R=True +Q='family' +P=len +O=ImportError +N=dir +M=open +K='port' +J='.' +I=AttributeError +H=False +G='/' +E=None +D=OSError +C='version' +B='' +import gc as F,os,sys from time import sleep - -try: - from ujson import dumps -except: - from json import dumps - -try: - from machine import reset # type: ignore -except ImportError: - pass - -try: - from collections import OrderedDict -except ImportError: - from ucollections import OrderedDict # type: ignore - -__version__ = "v1.23.0" -ENOENT = 2 -_MAX_CLASS_LEVEL = 2 # Max class nesting -LIBS = ["lib", "/lib", "/sd/lib", "/flash/lib", "."] - - -# our own logging module to avoid dependency on and interfering with logging module -class logging: - # DEBUG = 10 - INFO = 20 - WARNING = 30 - ERROR = 40 - level = INFO - prnt = print - - @staticmethod - def getLogger(name): - return logging() - - @classmethod - def basicConfig(cls, level): - cls.level = level - - # def debug(self, msg): - # if self.level <= logging.DEBUG: - # self.prnt("DEBUG :", msg) - - def info(self, msg): - if self.level <= logging.INFO: - self.prnt("INFO :", msg) - - def warning(self, msg): - if self.level <= logging.WARNING: - self.prnt("WARN :", msg) - - def error(self, msg): - if self.level <= logging.ERROR: - self.prnt("ERROR :", msg) - - -log = logging.getLogger("stubber") -logging.basicConfig(level=logging.INFO) -# logging.basicConfig(level=logging.DEBUG) - - +try:from ujson import dumps +except:from json import dumps +try:from machine import reset +except O:pass +try:from collections import OrderedDict as l +except O:from ucollections import OrderedDict as l +__version__='v1.24.0' +A3=2 +A4=2 +A5=['lib','/lib','/sd/lib','/flash/lib',J] +class L: + INFO=20;WARNING=30;ERROR=40;level=INFO;prnt=S + @staticmethod + def getLogger(name):return L() + @classmethod + def basicConfig(A,level):A.level=level + def info(A,msg): + if A.level<=L.INFO:A.prnt('INFO :',msg) + def warning(A,msg): + if A.level<=L.WARNING:A.prnt('WARN :',msg) + def error(A,msg): + if A.level<=L.ERROR:A.prnt('ERROR :',msg) +A=L.getLogger(t) +L.basicConfig(level=L.INFO) class Stubber: - "Generate stubs for modules in firmware" - - def __init__(self, path: str = None, firmware_id: str = None): # type: ignore - try: - if os.uname().release == "1.13.0" and os.uname().version < "v1.13-103": # type: ignore - raise NotImplementedError("MicroPython 1.13.0 cannot be stubbed") - except AttributeError: - pass # Allow testing on CPython 3.11 - self.info = _info() - log.info("Port: {}".format(self.info["port"])) - log.info("Board: {}".format(self.info["board"])) - gc.collect() - if firmware_id: - self._fwid = firmware_id.lower() - else: - if self.info["family"] == "micropython": - self._fwid = "{family}-v{version}-{port}-{board}".format(**self.info).rstrip("-") - else: - self._fwid = "{family}-v{version}-{port}".format(**self.info) - self._start_free = gc.mem_free() # type: ignore - - if path: - if path.endswith("/"): - path = path[:-1] - else: - path = get_root() - - self.path = "{}/stubs/{}".format(path, self.flat_fwid).replace("//", "/") - # log.debug(self.path) - try: - ensure_folder(path + "/") - except OSError: - log.error("error creating stub folder {}".format(path)) - self.problematic = [ - "upip", - "upysh", - "webrepl_setup", - "http_client", - "http_client_ssl", - "http_server", - "http_server_ssl", - ] - self.excluded = [ - "webrepl", - "_webrepl", - "port_diag", - "example_sub_led.py", - "example_pub_button.py", - ] - # there is no option to discover modules from micropython, list is read from an external file. - self.modules = [] # type: list[str] - self._json_name = None - self._json_first = False - - def get_obj_attributes(self, item_instance: object): - "extract information of the objects members and attributes" - # name_, repr_(value), type as text, item_instance - _result = [] - _errors = [] - # log.debug("get attributes {} {}".format(repr(item_instance), item_instance)) - for name in dir(item_instance): - if name.startswith("__") and not name in self.modules: - continue - # log.debug("get attribute {}".format(name)) - try: - val = getattr(item_instance, name) - # name , item_repr(value) , type as text, item_instance, order - # log.debug("attribute {}:{}".format(name, val)) - try: - type_text = repr(type(val)).split("'")[1] - except IndexError: - type_text = "" - if type_text in {"int", "float", "str", "bool", "tuple", "list", "dict"}: - order = 1 - elif type_text in {"function", "method"}: - order = 2 - elif type_text in ("class"): - order = 3 - else: - order = 4 - _result.append((name, repr(val), repr(type(val)), val, order)) - except AttributeError as e: - _errors.append("Couldn't get attribute '{}' from object '{}', Err: {}".format(name, item_instance, e)) - except MemoryError as e: - print("MemoryError: {}".format(e)) - sleep(1) - reset() - - # remove internal __ - # _result = sorted([i for i in _result if not (i[0].startswith("_"))], key=lambda x: x[4]) - _result = sorted([i for i in _result if not (i[0].startswith("__"))], key=lambda x: x[4]) - gc.collect() - return _result, _errors - - def add_modules(self, modules): - "Add additional modules to be exported" - self.modules = sorted(set(self.modules) | set(modules)) - - def create_all_stubs(self): - "Create stubs for all configured modules" - log.info("Start micropython-stubber {} on {}".format(__version__, self._fwid)) - self.report_start() - gc.collect() - for module_name in self.modules: - self.create_one_stub(module_name) - self.report_end() - log.info("Finally done") - - def create_one_stub(self, module_name: str): - if module_name in self.problematic: - log.warning("Skip module: {:<25} : Known problematic".format(module_name)) - return False - if module_name in self.excluded: - log.warning("Skip module: {:<25} : Excluded".format(module_name)) - return False - - file_name = "{}/{}.pyi".format(self.path, module_name.replace(".", "/")) - gc.collect() - result = False - try: - result = self.create_module_stub(module_name, file_name) - except OSError: - return False - gc.collect() - return result - - def create_module_stub(self, module_name: str, file_name: str = None) -> bool: # type: ignore - """Create a Stub of a single python module - - Args: - - module_name (str): name of the module to document. This module will be imported. - - file_name (Optional[str]): the 'path/filename.pyi' to write to. If omitted will be created based on the module name. - """ - if file_name is None: - fname = module_name.replace(".", "_") + ".pyi" - file_name = self.path + "/" + fname - else: - fname = file_name.split("/")[-1] - - if "/" in module_name: - # for nested modules - module_name = module_name.replace("/", ".") - - # import the module (as new_module) to examine it - new_module = None - try: - new_module = __import__(module_name, None, None, ("*")) - m1 = gc.mem_free() # type: ignore - log.info("Stub module: {:<25} to file: {:<70} mem:{:>5}".format(module_name, fname, m1)) - - except ImportError: - # log.debug("Skip module: {:<25} {:<79}".format(module_name, "Module not found.")) - return False - - # Start a new file - ensure_folder(file_name) - with open(file_name, "w") as fp: - info_ = str(self.info).replace("OrderedDict(", "").replace("})", "}") - s = '"""\nModule: \'{0}\' on {1}\n"""\n# MCU: {2}\n# Stubber: {3}\n'.format(module_name, self._fwid, info_, __version__) - fp.write(s) - fp.write("from __future__ import annotations\nfrom typing import Any, Generator\nfrom _typeshed import Incomplete\n\n") - self.write_object_stub(fp, new_module, module_name, "") - - self.report_add(module_name, file_name) - - if module_name not in {"os", "sys", "logging", "gc"}: - # try to unload the module unless we use it - try: - del new_module - except (OSError, KeyError): # lgtm [py/unreachable-statement] - log.warning("could not del new_module") - # do not try to delete from sys.modules - most times it does not work anyway - gc.collect() - return True - - def write_object_stub(self, fp, object_expr: object, obj_name: str, indent: str, in_class: int = 0): - "Write a module/object stub to an open file. Can be called recursive." - gc.collect() - if object_expr in self.problematic: - log.warning("SKIPPING problematic module:{}".format(object_expr)) - return - - # # log.debug("DUMP : {}".format(object_expr)) - items, errors = self.get_obj_attributes(object_expr) - - if errors: - log.error(errors) - - for item_name, item_repr, item_type_txt, item_instance, _ in items: - # name_, repr_(value), type as text, item_instance, order - if item_name in ["classmethod", "staticmethod", "BaseException", "Exception"]: - # do not create stubs for these primitives - continue - if item_name[0].isdigit(): - log.warning("NameError: invalid name {}".format(item_name)) - continue - # Class expansion only on first 3 levels (bit of a hack) - if ( - item_type_txt == "" - and len(indent) <= _MAX_CLASS_LEVEL * 4 - # and not obj_name.endswith(".Pin") - # avoid expansion of Pin.cpu / Pin.board to avoid crashes on most platforms - ): - # log.debug("{0}class {1}:".format(indent, item_name)) - superclass = "" - is_exception = ( - item_name.endswith("Exception") - or item_name.endswith("Error") - or item_name - in [ - "KeyboardInterrupt", - "StopIteration", - "SystemExit", - ] - ) - if is_exception: - superclass = "Exception" - s = "\n{}class {}({}):\n".format(indent, item_name, superclass) - # s += indent + " ''\n" - if is_exception: - s += indent + " ...\n" - fp.write(s) - continue - # write classdef - fp.write(s) - # first write the class literals and methods - # log.debug("# recursion over class {0}".format(item_name)) - self.write_object_stub( - fp, - item_instance, - "{0}.{1}".format(obj_name, item_name), - indent + " ", - in_class + 1, - ) - # end with the __init__ method to make sure that the literals are defined - # Add __init__ - s = indent + " def __init__(self, *argv, **kwargs) -> None:\n" - s += indent + " ...\n\n" - fp.write(s) - elif any(word in item_type_txt for word in ["method", "function", "closure"]): - # log.debug("# def {1} function/method/closure, type = '{0}'".format(item_type_txt, item_name)) - # module Function or class method - # will accept any number of params - # return type Any/Incomplete - ret = "Incomplete" - first = "" - # Self parameter only on class methods/functions - if in_class > 0: - first = "self, " - # class method - add function decoration - if "bound_method" in item_type_txt or "bound_method" in item_repr: - s = "{}@classmethod\n".format(indent) + "{}def {}(cls, *args, **kwargs) -> {}:\n".format(indent, item_name, ret) - else: - s = "{}def {}({}*args, **kwargs) -> {}:\n".format(indent, item_name, first, ret) - s += indent + " ...\n\n" - fp.write(s) - # log.debug("\n" + s) - elif item_type_txt == "": - # Skip imported modules - # fp.write("# import {}\n".format(item_name)) - pass - - elif item_type_txt.startswith("" - if " at " in item_repr: - item_repr = item_repr.split(" at ")[0] + " at ...>" - s = "{0}{1}: {2} ## {3} = {4}\n".format(indent, item_name, t, item_type_txt, item_repr) - fp.write(s) - # log.debug("\n" + s) - else: - # keep only the name - # log.debug("# all other, type = '{0}'".format(item_type_txt)) - fp.write("# all other, type = '{0}'\n".format(item_type_txt)) - - fp.write(indent + item_name + " # type: Incomplete\n") - - # del items - # del errors - # try: - # del item_name, item_repr, item_type_txt, item_instance # type: ignore - # except (OSError, KeyError, NameError): - # pass - - @property - def flat_fwid(self): - "Turn _fwid from 'v1.2.3' into '1_2_3' to be used in filename" - s = self._fwid - # path name restrictions - chars = " .()/\\:$" - for c in chars: - s = s.replace(c, "_") - return s - - def clean(self, path: str = None): # type: ignore - "Remove all files from the stub folder" - if path is None: - path = self.path - log.info("Clean/remove files in folder: {}".format(path)) - try: - os.stat(path) # TEMP workaround mpremote listdir bug - - items = os.listdir(path) - except (OSError, AttributeError): - # os.listdir fails on unix - return - for fn in items: - item = "{}/{}".format(path, fn) - try: - os.remove(item) - except OSError: - try: # folder - self.clean(item) - os.rmdir(item) - except OSError: - pass - - def report_start(self, filename: str = "modules.json"): - """Start a report of the modules that have been stubbed - "create json with list of exported modules""" - self._json_name = "{}/{}".format(self.path, filename) - self._json_first = True - ensure_folder(self._json_name) - log.info("Report file: {}".format(self._json_name)) - gc.collect() - try: - # write json by node to reduce memory requirements - with open(self._json_name, "w") as f: - f.write("{") - f.write(dumps({"firmware": self.info})[1:-1]) - f.write(",\n") - f.write(dumps({"stubber": {"version": __version__}, "stubtype": "firmware"})[1:-1]) - f.write(",\n") - f.write('"modules" :[\n') - - except OSError as e: - log.error("Failed to create the report.") - self._json_name = None - raise e - - def report_add(self, module_name: str, stub_file: str): - "Add a module to the report" - # write json by node to reduce memory requirements - if not self._json_name: - raise Exception("No report file") - try: - with open(self._json_name, "a") as f: - if not self._json_first: - f.write(",\n") - else: - self._json_first = False - line = '{{"module": "{}", "file": "{}"}}'.format(module_name, stub_file.replace("\\", "/")) - f.write(line) - - except OSError: - log.error("Failed to create the report.") - - def report_end(self): - if not self._json_name: - raise Exception("No report file") - with open(self._json_name, "a") as f: - f.write("\n]}") - # is used as sucess indicator - log.info("Path: {}".format(self.path)) - - -def ensure_folder(path: str): - "Create nested folders if needed" - i = start = 0 - while i != -1: - i = path.find("/", start) - if i != -1: - p = path[0] if i == 0 else path[:i] - # p = partial folder - try: - _ = os.stat(p) - except OSError as e: - # folder does not exist - if e.args[0] == ENOENT: - try: - os.mkdir(p) - except OSError as e2: - log.error("failed to create folder {}".format(p)) - raise e2 - # next level deep - start = i + 1 - - -def _build(s): - # extract build from sys.version or os.uname().version if available - # sys.version: 'MicroPython v1.23.0-preview.6.g3d0b6276f' - # sys.implementation.version: 'v1.13-103-gb137d064e' - if not s: - return "" - s = s.split(" on ", 1)[0] if " on " in s else s - if s.startswith("v"): - if not "-" in s: - return "" - b = s.split("-")[1] - return b - if not "-preview" in s: - return "" - b = s.split("-preview")[1].split(".")[1] - return b - - -def _info(): # type:() -> dict[str, str] - try: - fam = sys.implementation[0] # type: ignore - except TypeError: - # testing on CPython 3.11 - fam = sys.implementation.name - - info = OrderedDict( - { - "family": fam, - "version": "", - "build": "", - "ver": "", - "port": sys.platform, # port: esp32 / win32 / linux / stm32 - "board": "UNKNOWN", - "cpu": "", - "mpy": "", - "arch": "", - } - ) - # change port names to be consistent with the repo - if info["port"].startswith("pyb"): - info["port"] = "stm32" - elif info["port"] == "win32": - info["port"] = "windows" - elif info["port"] == "linux": - info["port"] = "unix" - try: - info["version"] = version_str(sys.implementation.version) # type: ignore - except AttributeError: - pass - try: - _machine = sys.implementation._machine if "_machine" in dir(sys.implementation) else os.uname().machine # type: ignore - # info["board"] = "with".join(_machine.split("with")[:-1]).strip() - info["board"] = _machine - info["cpu"] = _machine.split("with")[-1].strip() - info["mpy"] = ( - sys.implementation._mpy # type: ignore - if "_mpy" in dir(sys.implementation) - else sys.implementation.mpy if "mpy" in dir(sys.implementation) else "" # type: ignore - ) - except (AttributeError, IndexError): - pass - info["board"] = get_boardname() - - try: - if "uname" in dir(os): # old - # extract build from uname().version if available - info["build"] = _build(os.uname()[3]) # type: ignore - if not info["build"]: - # extract build from uname().release if available - info["build"] = _build(os.uname()[2]) # type: ignore - elif "version" in dir(sys): # new - # extract build from sys.version if available - info["build"] = _build(sys.version) - except (AttributeError, IndexError, TypeError): - pass - # avoid build hashes - # if info["build"] and len(info["build"]) > 5: - # info["build"] = "" - - if info["version"] == "" and sys.platform not in ("unix", "win32"): - try: - u = os.uname() # type: ignore - info["version"] = u.release - except (IndexError, AttributeError, TypeError): - pass - # detect families - for fam_name, mod_name, mod_thing in [ - ("pycopy", "pycopy", "const"), - ("pycom", "pycom", "FAT"), - ("ev3-pybricks", "pybricks.hubs", "EV3Brick"), - ]: - try: - _t = __import__(mod_name, None, None, (mod_thing)) - info["family"] = fam_name - del _t - break - except (ImportError, KeyError): - pass - - if info["family"] == "ev3-pybricks": - info["release"] = "2.0.0" - - if info["family"] == "micropython": - info["version"] - if ( - info["version"] - and info["version"].endswith(".0") - and info["version"] >= "1.10.0" # versions from 1.10.0 to 1.23.0 do not have a micro .0 - and info["version"] <= "1.19.9" - ): - # versions from 1.10.0 to 1.23.0 do not have a micro .0 - info["version"] = info["version"][:-2] - - # spell-checker: disable - if "mpy" in info and info["mpy"]: # mpy on some v1.11+ builds - sys_mpy = int(info["mpy"]) - # .mpy architecture - arch = [ - None, - "x86", - "x64", - "armv6", - "armv6m", - "armv7m", - "armv7em", - "armv7emsp", - "armv7emdp", - "xtensa", - "xtensawin", - ][sys_mpy >> 10] - if arch: - info["arch"] = arch - # .mpy version.minor - info["mpy"] = "v{}.{}".format(sys_mpy & 0xFF, sys_mpy >> 8 & 3) - if info["build"] and not info["version"].endswith("-preview"): - info["version"] = info["version"] + "-preview" - # simple to use version[-build] string - info["ver"] = f"{info['version']}-{info['build']}" if info["build"] else f"{info['version']}" - - return info - - -def version_str(version: tuple): # -> str: - v_str = ".".join([str(n) for n in version[:3]]) - if len(version) > 3 and version[3]: - v_str += "-" + version[3] - return v_str - - -def get_boardname() -> str: - "Read the board name from the boardname.py file that may have been created upfront" - try: - from boardname import BOARDNAME # type: ignore - - log.info("Found BOARDNAME: {}".format(BOARDNAME)) - except ImportError: - log.warning("BOARDNAME not found") - BOARDNAME = "" - return BOARDNAME - - -def get_root() -> str: # sourcery skip: use-assigned-variable - "Determine the root folder of the device" - try: - c = os.getcwd() - except (OSError, AttributeError): - # unix port - c = "." - r = c - for r in [c, "/sd", "/flash", "/", "."]: - try: - _ = os.stat(r) - break - except OSError: - continue - return r - - -def file_exists(filename: str): - try: - if os.stat(filename)[0] >> 14: - return True - return False - except OSError: - return False - - -def show_help(): - print("-p, --path path to store the stubs in, defaults to '.'") - sys.exit(1) - - -def read_path() -> str: - "get --path from cmdline. [unix/win]" - path = "" - if len(sys.argv) == 3: - cmd = (sys.argv[1]).lower() - if cmd in ("--path", "-p"): - path = sys.argv[2] - else: - show_help() - elif len(sys.argv) == 2: - show_help() - return path - - -def is_micropython() -> bool: - "runtime test to determine full or micropython" - # pylint: disable=unused-variable,eval-used - try: - # either test should fail on micropython - - # b) https://docs.micropython.org/en/latest/genrst/builtin_types.html#bytes-with-keywords-not-implemented - # Micropython: NotImplementedError - b = bytes("abc", encoding="utf8") # type: ignore # lgtm [py/unused-local-variable] - - # c) https://docs.micropython.org/en/latest/genrst/core_language.html#function-objects-do-not-have-the-module-attribute - # Micropython: AttributeError - c = is_micropython.__module__ # type: ignore # lgtm [py/unused-local-variable] - return False - except (NotImplementedError, AttributeError): - return True - - -SKIP_FILE = "modulelist.done" - - -def get_modules(skip=0): - # new - for p in LIBS: - fname = p + "/modulelist.txt" - if not file_exists(fname): - continue - try: - with open(fname) as f: - i = 0 - while True: - line = f.readline().strip() - if not line: - break - if len(line) > 0 and line[0] == "#": - continue - i += 1 - if i < skip: - continue - yield line - break - except OSError: - pass - - -def write_skip(done): - # write count of modules already processed to file - with open(SKIP_FILE, "w") as f: - f.write(str(done) + "\n") - - -def read_skip(): - # read count of modules already processed from file - done = 0 - try: - with open(SKIP_FILE) as f: - done = int(f.readline().strip()) - except OSError: - pass - return done - - + def __init__(B,path=E,firmware_id=E): + C=firmware_id + try: + if os.uname().release=='1.13.0'and os.uname().version<'v1.13-103':raise o('MicroPython 1.13.0 cannot be stubbed') + except I:pass + B.info=_info();A.info('Port: {}'.format(B.info[K]));A.info('Board: {}'.format(B.info[U]));F.collect() + if C:B._fwid=C.lower() + elif B.info[Q]==u:B._fwid='{family}-v{version}-{port}-{board}'.format(**B.info).rstrip(V) + else:B._fwid='{family}-v{version}-{port}'.format(**B.info) + B._start_free=F.mem_free() + if path: + if path.endswith(G):path=path[:-1] + else:path=get_root() + B.path='{}/stubs/{}'.format(path,B.flat_fwid).replace('//',G) + try:X(path+G) + except D:A.error('error creating stub folder {}'.format(path)) + B.problematic=['upip','upysh','webrepl_setup','http_client','http_client_ssl','http_server','http_server_ssl'];B.excluded=['webrepl','_webrepl','port_diag','example_sub_led.py','example_pub_button.py'];B.modules=[];B._json_name=E;B._json_first=H + def get_obj_attributes(L,item_instance): + H=item_instance;C=[];K=[] + for A in N(H): + if A.startswith('__')and not A in L.modules:continue + try: + D=getattr(H,A) + try:E=b(type(D)).split("'")[1] + except T:E=B + if E in{v,w,x,y,e,f,g}:G=1 + elif E in{z,A0}:G=2 + elif E in'class':G=3 + else:G=4 + C.append((A,b(D),b(type(D)),D,G)) + except I as J:K.append("Couldn't get attribute '{}' from object '{}', Err: {}".format(A,H,J)) + except p as J:S('MemoryError: {}'.format(J));sleep(1);reset() + C=q([A for A in C if not A[0].startswith('__')],key=lambda x:x[4]);F.collect();return C,K + def add_modules(A,modules):A.modules=q(set(A.modules)|set(modules)) + def create_all_stubs(B): + A.info('Start micropython-stubber {} on {}'.format(__version__,B._fwid));B.report_start();F.collect() + for C in B.modules:B.create_one_stub(C) + B.report_end();A.info('Finally done') + def create_one_stub(C,module_name): + B=module_name + if B in C.problematic:A.warning('Skip module: {:<25} : Known problematic'.format(B));return H + if B in C.excluded:A.warning('Skip module: {:<25} : Excluded'.format(B));return H + I='{}/{}.pyi'.format(C.path,B.replace(J,G));F.collect();E=H + try:E=C.create_module_stub(B,I) + except D:return H + F.collect();return E + def create_module_stub(K,module_name,file_name=E): + I=file_name;C=module_name + if I is E:L=C.replace(J,'_')+'.pyi';I=K.path+G+L + else:L=I.split(G)[-1] + if G in C:C=C.replace(G,J) + N=E + try:N=__import__(C,E,E,'*');Q=F.mem_free();A.info('Stub module: {:<25} to file: {:<70} mem:{:>5}'.format(C,L,Q)) + except O:return H + X(I) + with M(I,h)as P:S=c(K.info).replace('OrderedDict(',B).replace('})','}');T='"""\nModule: \'{0}\' on {1}\n"""\n# MCU: {2}\n# Stubber: {3}\n'.format(C,K._fwid,S,__version__);P.write(T);P.write('from __future__ import annotations\nfrom typing import Any, Generator\nfrom _typeshed import Incomplete\n\n');K.write_object_stub(P,N,C,B) + K.report_add(C,I) + if C not in{'os','sys','logging','gc'}: + try:del N + except(D,r):A.warning('could not del new_module') + F.collect();return R + def write_object_stub(L,fp,object_expr,obj_name,indent,in_class=0): + Z=' at ...>';Y='generator';X='{0}{1}: {3} = {2}\n';W='bound_method';V='Incomplete';O=in_class;N='Exception';M=object_expr;K=' at ';J=fp;D=indent;F.collect() + if M in L.problematic:A.warning('SKIPPING problematic module:{}'.format(M));return + a,Q=L.get_obj_attributes(M) + if Q:A.error(Q) + for(E,H,I,b,d)in a: + if E in['classmethod','staticmethod','BaseException',N]:continue + if E[0].isdigit():A.warning('NameError: invalid name {}'.format(E));continue + if I==""and P(D)<=A4*4: + R=B;S=E.endswith(N)or E.endswith('Error')or E in['KeyboardInterrupt','StopIteration','SystemExit'] + if S:R=N + C='\n{}class {}({}):\n'.format(D,E,R) + if S:C+=D+' ...\n';J.write(C);continue + J.write(C);L.write_object_stub(J,b,'{0}.{1}'.format(obj_name,E),D+' ',O+1);C=D+' def __init__(self, *argv, **kwargs) -> None:\n';C+=D+' ...\n\n';J.write(C) + elif any(A in I for A in[A0,z,'closure']): + T=V;U=B + if O>0:U='self, ' + if W in I or W in H:C='{}@classmethod\n'.format(D)+'{}def {}(cls, *args, **kwargs) -> {}:\n'.format(D,E,T) + else:C='{}def {}({}*args, **kwargs) -> {}:\n'.format(D,E,U,T) + C+=D+' ...\n\n';J.write(C) + elif I=="":0 + elif I.startswith("='1.10.0'and A[C]<='1.19.9':A[C]=A[C][:-2] + if F in A and A[F]: + G=int(A[F]);L=[E,'x86','x64','armv6','armv6m','armv7m','armv7em','armv7emsp','armv7emdp','xtensa','xtensawin'][G>>10] + if L:A[R]=L + A[F]='v{}.{}'.format(G&255,G>>8&3) + if A[D]and not A[C].endswith(W):A[C]=A[C]+W + A[M]=f"{A[C]}-{A[D]}"if A[D]else f"{A[C]}";return A +def A6(version): + A=version;B=J.join([c(A)for A in A[:3]]) + if P(A)>3 and A[3]:B+=V+A[3] + return B +def A7(): + try:from boardname import BOARDNAME as C;A.info('Found BOARDNAME: {}'.format(C)) + except O:A.warning('BOARDNAME not found');C=B + return C +def get_root(): + try:A=os.getcwd() + except(D,I):A=J + B=A + for B in['/sd','/flash',G,A,J]: + try:C=os.stat(B);break + except D:continue + return B +def Z(filename): + try: + if os.stat(filename)[0]>>14:return R + return H + except D:return H +def m():S("-p, --path path to store the stubs in, defaults to '.'");sys.exit(1) +def read_path(): + path=B + if P(sys.argv)==3: + A=sys.argv[1].lower() + if A in('--path','-p'):path=sys.argv[2] + else:m() + elif P(sys.argv)==2:m() + return path +def n(): + try:A=bytes('abc',encoding='utf8');B=n.__module__;return H + except(o,I):return R +a='modulelist.done' +def A8(skip=0): + for E in A5: + B=E+'/modulelist.txt' + if not Z(B):continue + try: + with M(B)as F: + C=0 + while R: + A=F.readline().strip() + if not A:break + if P(A)>0 and A[0]=='#':continue + C+=1 + if Cl2{NzoO4 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 literal 9974 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 F{y)=>R%ieK diff --git a/mip/v5/createstubs_mem.py b/mip/v5/createstubs_mem.py index ebe043c3..db59c6fd 100644 --- a/mip/v5/createstubs_mem.py +++ b/mip/v5/createstubs_mem.py @@ -9,7 +9,7 @@ - cross compilation, using mpy-cross, to avoid the compilation step on the micropython device -This variant was generated from createstubs.py by micropython-stubber v1.23.0 +This variant was generated from createstubs.py by micropython-stubber v1.24.0 """ # Copyright (c) 2019-2024 Jos Verlinde @@ -34,7 +34,7 @@ except ImportError: from ucollections import OrderedDict # type: ignore -__version__ = "v1.23.0" +__version__ = "v1.24.0" ENOENT = 2 _MAX_CLASS_LEVEL = 2 # Max class nesting LIBS = ["lib", "/lib", "/sd/lib", "/flash/lib", "."] @@ -492,7 +492,7 @@ def ensure_folder(path: str): def _build(s): # extract build from sys.version or os.uname().version if available - # sys.version: 'MicroPython v1.23.0-preview.6.g3d0b6276f' + # sys.version: 'MicroPython v1.24.0-preview.6.g3d0b6276f' # sys.implementation.version: 'v1.13-103-gb137d064e' if not s: return "" @@ -597,10 +597,10 @@ def _info(): # type:() -> dict[str, str] if ( info["version"] and info["version"].endswith(".0") - and info["version"] >= "1.10.0" # versions from 1.10.0 to 1.23.0 do not have a micro .0 + and info["version"] >= "1.10.0" # versions from 1.10.0 to 1.24.0 do not have a micro .0 and info["version"] <= "1.19.9" ): - # versions from 1.10.0 to 1.23.0 do not have a micro .0 + # versions from 1.10.0 to 1.24.0 do not have a micro .0 info["version"] = info["version"][:-2] # spell-checker: disable @@ -659,7 +659,7 @@ def get_root() -> str: # sourcery skip: use-assigned-variable # unix port c = "." r = c - for r in [c, "/sd", "/flash", "/", "."]: + for r in ["/sd", "/flash", "/", c, "."]: try: _ = os.stat(r) break diff --git a/mip/v5/createstubs_mem_min.py b/mip/v5/createstubs_mem_min.py index ebe043c3..dee8c794 100644 --- a/mip/v5/createstubs_mem_min.py +++ b/mip/v5/createstubs_mem_min.py @@ -1,766 +1,307 @@ -"""Create stubs for (all) modules on a MicroPython board. - - This variant of the createstubs.py script is optimised for use on low-memory devices, and reads the list of modules from a text file - `modulelist.txt` in the root or `libs` folder that should be uploaded to the device. - If that cannot be found then only a single module (micropython) is stubbed. - In order to run this on low-memory devices two additional steps are recommended: - - minifification, using python-minifier - to reduce overall size, and remove logging overhead. - - cross compilation, using mpy-cross, - to avoid the compilation step on the micropython device - -This variant was generated from createstubs.py by micropython-stubber v1.23.0 -""" - -# Copyright (c) 2019-2024 Jos Verlinde - -import gc -import os -import sys +x='No report file' +w='Failed to create the report.' +v='{}/{}' +u='method' +t='function' +s='bool' +r='str' +q='float' +p='int' +o='stubber' +n=Exception +m=KeyError +l=sorted +k=NotImplementedError +f=',\n' +e='dict' +d='list' +c='tuple' +b='micropython' +a=TypeError +Z=repr +W='-preview' +V='-' +U='board' +T=IndexError +S=print +R=True +Q='family' +P=len +O=open +N=ImportError +M=dir +K='port' +J='.' +I=AttributeError +H=False +G='/' +F=OSError +E=None +C='version' +B='' +import gc as D,os,sys from time import sleep - -try: - from ujson import dumps -except: - from json import dumps - -try: - from machine import reset # type: ignore -except ImportError: - pass - -try: - from collections import OrderedDict -except ImportError: - from ucollections import OrderedDict # type: ignore - -__version__ = "v1.23.0" -ENOENT = 2 -_MAX_CLASS_LEVEL = 2 # Max class nesting -LIBS = ["lib", "/lib", "/sd/lib", "/flash/lib", "."] - - -# our own logging module to avoid dependency on and interfering with logging module -class logging: - # DEBUG = 10 - INFO = 20 - WARNING = 30 - ERROR = 40 - level = INFO - prnt = print - - @staticmethod - def getLogger(name): - return logging() - - @classmethod - def basicConfig(cls, level): - cls.level = level - - # def debug(self, msg): - # if self.level <= logging.DEBUG: - # self.prnt("DEBUG :", msg) - - def info(self, msg): - if self.level <= logging.INFO: - self.prnt("INFO :", msg) - - def warning(self, msg): - if self.level <= logging.WARNING: - self.prnt("WARN :", msg) - - def error(self, msg): - if self.level <= logging.ERROR: - self.prnt("ERROR :", msg) - - -log = logging.getLogger("stubber") -logging.basicConfig(level=logging.INFO) -# logging.basicConfig(level=logging.DEBUG) - - +try:from ujson import dumps +except:from json import dumps +try:from machine import reset +except N:pass +try:from collections import OrderedDict as g +except N:from ucollections import OrderedDict as g +__version__='v1.24.0' +y=2 +z=2 +A0=['lib','/lib','/sd/lib','/flash/lib',J] +class L: + INFO=20;WARNING=30;ERROR=40;level=INFO;prnt=S + @staticmethod + def getLogger(name):return L() + @classmethod + def basicConfig(A,level):A.level=level + def info(A,msg): + if A.level<=L.INFO:A.prnt('INFO :',msg) + def warning(A,msg): + if A.level<=L.WARNING:A.prnt('WARN :',msg) + def error(A,msg): + if A.level<=L.ERROR:A.prnt('ERROR :',msg) +A=L.getLogger(o) +L.basicConfig(level=L.INFO) class Stubber: - "Generate stubs for modules in firmware" - - def __init__(self, path: str = None, firmware_id: str = None): # type: ignore - try: - if os.uname().release == "1.13.0" and os.uname().version < "v1.13-103": # type: ignore - raise NotImplementedError("MicroPython 1.13.0 cannot be stubbed") - except AttributeError: - pass # Allow testing on CPython 3.11 - self.info = _info() - log.info("Port: {}".format(self.info["port"])) - log.info("Board: {}".format(self.info["board"])) - gc.collect() - if firmware_id: - self._fwid = firmware_id.lower() - else: - if self.info["family"] == "micropython": - self._fwid = "{family}-v{version}-{port}-{board}".format(**self.info).rstrip("-") - else: - self._fwid = "{family}-v{version}-{port}".format(**self.info) - self._start_free = gc.mem_free() # type: ignore - - if path: - if path.endswith("/"): - path = path[:-1] - else: - path = get_root() - - self.path = "{}/stubs/{}".format(path, self.flat_fwid).replace("//", "/") - # log.debug(self.path) - try: - ensure_folder(path + "/") - except OSError: - log.error("error creating stub folder {}".format(path)) - self.problematic = [ - "upip", - "upysh", - "webrepl_setup", - "http_client", - "http_client_ssl", - "http_server", - "http_server_ssl", - ] - self.excluded = [ - "webrepl", - "_webrepl", - "port_diag", - "example_sub_led.py", - "example_pub_button.py", - ] - # there is no option to discover modules from micropython, list is read from an external file. - self.modules = [] # type: list[str] - self._json_name = None - self._json_first = False - - def get_obj_attributes(self, item_instance: object): - "extract information of the objects members and attributes" - # name_, repr_(value), type as text, item_instance - _result = [] - _errors = [] - # log.debug("get attributes {} {}".format(repr(item_instance), item_instance)) - for name in dir(item_instance): - if name.startswith("__") and not name in self.modules: - continue - # log.debug("get attribute {}".format(name)) - try: - val = getattr(item_instance, name) - # name , item_repr(value) , type as text, item_instance, order - # log.debug("attribute {}:{}".format(name, val)) - try: - type_text = repr(type(val)).split("'")[1] - except IndexError: - type_text = "" - if type_text in {"int", "float", "str", "bool", "tuple", "list", "dict"}: - order = 1 - elif type_text in {"function", "method"}: - order = 2 - elif type_text in ("class"): - order = 3 - else: - order = 4 - _result.append((name, repr(val), repr(type(val)), val, order)) - except AttributeError as e: - _errors.append("Couldn't get attribute '{}' from object '{}', Err: {}".format(name, item_instance, e)) - except MemoryError as e: - print("MemoryError: {}".format(e)) - sleep(1) - reset() - - # remove internal __ - # _result = sorted([i for i in _result if not (i[0].startswith("_"))], key=lambda x: x[4]) - _result = sorted([i for i in _result if not (i[0].startswith("__"))], key=lambda x: x[4]) - gc.collect() - return _result, _errors - - def add_modules(self, modules): - "Add additional modules to be exported" - self.modules = sorted(set(self.modules) | set(modules)) - - def create_all_stubs(self): - "Create stubs for all configured modules" - log.info("Start micropython-stubber {} on {}".format(__version__, self._fwid)) - self.report_start() - gc.collect() - for module_name in self.modules: - self.create_one_stub(module_name) - self.report_end() - log.info("Finally done") - - def create_one_stub(self, module_name: str): - if module_name in self.problematic: - log.warning("Skip module: {:<25} : Known problematic".format(module_name)) - return False - if module_name in self.excluded: - log.warning("Skip module: {:<25} : Excluded".format(module_name)) - return False - - file_name = "{}/{}.pyi".format(self.path, module_name.replace(".", "/")) - gc.collect() - result = False - try: - result = self.create_module_stub(module_name, file_name) - except OSError: - return False - gc.collect() - return result - - def create_module_stub(self, module_name: str, file_name: str = None) -> bool: # type: ignore - """Create a Stub of a single python module - - Args: - - module_name (str): name of the module to document. This module will be imported. - - file_name (Optional[str]): the 'path/filename.pyi' to write to. If omitted will be created based on the module name. - """ - if file_name is None: - fname = module_name.replace(".", "_") + ".pyi" - file_name = self.path + "/" + fname - else: - fname = file_name.split("/")[-1] - - if "/" in module_name: - # for nested modules - module_name = module_name.replace("/", ".") - - # import the module (as new_module) to examine it - new_module = None - try: - new_module = __import__(module_name, None, None, ("*")) - m1 = gc.mem_free() # type: ignore - log.info("Stub module: {:<25} to file: {:<70} mem:{:>5}".format(module_name, fname, m1)) - - except ImportError: - # log.debug("Skip module: {:<25} {:<79}".format(module_name, "Module not found.")) - return False - - # Start a new file - ensure_folder(file_name) - with open(file_name, "w") as fp: - info_ = str(self.info).replace("OrderedDict(", "").replace("})", "}") - s = '"""\nModule: \'{0}\' on {1}\n"""\n# MCU: {2}\n# Stubber: {3}\n'.format(module_name, self._fwid, info_, __version__) - fp.write(s) - fp.write("from __future__ import annotations\nfrom typing import Any, Generator\nfrom _typeshed import Incomplete\n\n") - self.write_object_stub(fp, new_module, module_name, "") - - self.report_add(module_name, file_name) - - if module_name not in {"os", "sys", "logging", "gc"}: - # try to unload the module unless we use it - try: - del new_module - except (OSError, KeyError): # lgtm [py/unreachable-statement] - log.warning("could not del new_module") - # do not try to delete from sys.modules - most times it does not work anyway - gc.collect() - return True - - def write_object_stub(self, fp, object_expr: object, obj_name: str, indent: str, in_class: int = 0): - "Write a module/object stub to an open file. Can be called recursive." - gc.collect() - if object_expr in self.problematic: - log.warning("SKIPPING problematic module:{}".format(object_expr)) - return - - # # log.debug("DUMP : {}".format(object_expr)) - items, errors = self.get_obj_attributes(object_expr) - - if errors: - log.error(errors) - - for item_name, item_repr, item_type_txt, item_instance, _ in items: - # name_, repr_(value), type as text, item_instance, order - if item_name in ["classmethod", "staticmethod", "BaseException", "Exception"]: - # do not create stubs for these primitives - continue - if item_name[0].isdigit(): - log.warning("NameError: invalid name {}".format(item_name)) - continue - # Class expansion only on first 3 levels (bit of a hack) - if ( - item_type_txt == "" - and len(indent) <= _MAX_CLASS_LEVEL * 4 - # and not obj_name.endswith(".Pin") - # avoid expansion of Pin.cpu / Pin.board to avoid crashes on most platforms - ): - # log.debug("{0}class {1}:".format(indent, item_name)) - superclass = "" - is_exception = ( - item_name.endswith("Exception") - or item_name.endswith("Error") - or item_name - in [ - "KeyboardInterrupt", - "StopIteration", - "SystemExit", - ] - ) - if is_exception: - superclass = "Exception" - s = "\n{}class {}({}):\n".format(indent, item_name, superclass) - # s += indent + " ''\n" - if is_exception: - s += indent + " ...\n" - fp.write(s) - continue - # write classdef - fp.write(s) - # first write the class literals and methods - # log.debug("# recursion over class {0}".format(item_name)) - self.write_object_stub( - fp, - item_instance, - "{0}.{1}".format(obj_name, item_name), - indent + " ", - in_class + 1, - ) - # end with the __init__ method to make sure that the literals are defined - # Add __init__ - s = indent + " def __init__(self, *argv, **kwargs) -> None:\n" - s += indent + " ...\n\n" - fp.write(s) - elif any(word in item_type_txt for word in ["method", "function", "closure"]): - # log.debug("# def {1} function/method/closure, type = '{0}'".format(item_type_txt, item_name)) - # module Function or class method - # will accept any number of params - # return type Any/Incomplete - ret = "Incomplete" - first = "" - # Self parameter only on class methods/functions - if in_class > 0: - first = "self, " - # class method - add function decoration - if "bound_method" in item_type_txt or "bound_method" in item_repr: - s = "{}@classmethod\n".format(indent) + "{}def {}(cls, *args, **kwargs) -> {}:\n".format(indent, item_name, ret) - else: - s = "{}def {}({}*args, **kwargs) -> {}:\n".format(indent, item_name, first, ret) - s += indent + " ...\n\n" - fp.write(s) - # log.debug("\n" + s) - elif item_type_txt == "": - # Skip imported modules - # fp.write("# import {}\n".format(item_name)) - pass - - elif item_type_txt.startswith("" - if " at " in item_repr: - item_repr = item_repr.split(" at ")[0] + " at ...>" - s = "{0}{1}: {2} ## {3} = {4}\n".format(indent, item_name, t, item_type_txt, item_repr) - fp.write(s) - # log.debug("\n" + s) - else: - # keep only the name - # log.debug("# all other, type = '{0}'".format(item_type_txt)) - fp.write("# all other, type = '{0}'\n".format(item_type_txt)) - - fp.write(indent + item_name + " # type: Incomplete\n") - - # del items - # del errors - # try: - # del item_name, item_repr, item_type_txt, item_instance # type: ignore - # except (OSError, KeyError, NameError): - # pass - - @property - def flat_fwid(self): - "Turn _fwid from 'v1.2.3' into '1_2_3' to be used in filename" - s = self._fwid - # path name restrictions - chars = " .()/\\:$" - for c in chars: - s = s.replace(c, "_") - return s - - def clean(self, path: str = None): # type: ignore - "Remove all files from the stub folder" - if path is None: - path = self.path - log.info("Clean/remove files in folder: {}".format(path)) - try: - os.stat(path) # TEMP workaround mpremote listdir bug - - items = os.listdir(path) - except (OSError, AttributeError): - # os.listdir fails on unix - return - for fn in items: - item = "{}/{}".format(path, fn) - try: - os.remove(item) - except OSError: - try: # folder - self.clean(item) - os.rmdir(item) - except OSError: - pass - - def report_start(self, filename: str = "modules.json"): - """Start a report of the modules that have been stubbed - "create json with list of exported modules""" - self._json_name = "{}/{}".format(self.path, filename) - self._json_first = True - ensure_folder(self._json_name) - log.info("Report file: {}".format(self._json_name)) - gc.collect() - try: - # write json by node to reduce memory requirements - with open(self._json_name, "w") as f: - f.write("{") - f.write(dumps({"firmware": self.info})[1:-1]) - f.write(",\n") - f.write(dumps({"stubber": {"version": __version__}, "stubtype": "firmware"})[1:-1]) - f.write(",\n") - f.write('"modules" :[\n') - - except OSError as e: - log.error("Failed to create the report.") - self._json_name = None - raise e - - def report_add(self, module_name: str, stub_file: str): - "Add a module to the report" - # write json by node to reduce memory requirements - if not self._json_name: - raise Exception("No report file") - try: - with open(self._json_name, "a") as f: - if not self._json_first: - f.write(",\n") - else: - self._json_first = False - line = '{{"module": "{}", "file": "{}"}}'.format(module_name, stub_file.replace("\\", "/")) - f.write(line) - - except OSError: - log.error("Failed to create the report.") - - def report_end(self): - if not self._json_name: - raise Exception("No report file") - with open(self._json_name, "a") as f: - f.write("\n]}") - # is used as sucess indicator - log.info("Path: {}".format(self.path)) - - -def ensure_folder(path: str): - "Create nested folders if needed" - i = start = 0 - while i != -1: - i = path.find("/", start) - if i != -1: - p = path[0] if i == 0 else path[:i] - # p = partial folder - try: - _ = os.stat(p) - except OSError as e: - # folder does not exist - if e.args[0] == ENOENT: - try: - os.mkdir(p) - except OSError as e2: - log.error("failed to create folder {}".format(p)) - raise e2 - # next level deep - start = i + 1 - - -def _build(s): - # extract build from sys.version or os.uname().version if available - # sys.version: 'MicroPython v1.23.0-preview.6.g3d0b6276f' - # sys.implementation.version: 'v1.13-103-gb137d064e' - if not s: - return "" - s = s.split(" on ", 1)[0] if " on " in s else s - if s.startswith("v"): - if not "-" in s: - return "" - b = s.split("-")[1] - return b - if not "-preview" in s: - return "" - b = s.split("-preview")[1].split(".")[1] - return b - - -def _info(): # type:() -> dict[str, str] - try: - fam = sys.implementation[0] # type: ignore - except TypeError: - # testing on CPython 3.11 - fam = sys.implementation.name - - info = OrderedDict( - { - "family": fam, - "version": "", - "build": "", - "ver": "", - "port": sys.platform, # port: esp32 / win32 / linux / stm32 - "board": "UNKNOWN", - "cpu": "", - "mpy": "", - "arch": "", - } - ) - # change port names to be consistent with the repo - if info["port"].startswith("pyb"): - info["port"] = "stm32" - elif info["port"] == "win32": - info["port"] = "windows" - elif info["port"] == "linux": - info["port"] = "unix" - try: - info["version"] = version_str(sys.implementation.version) # type: ignore - except AttributeError: - pass - try: - _machine = sys.implementation._machine if "_machine" in dir(sys.implementation) else os.uname().machine # type: ignore - # info["board"] = "with".join(_machine.split("with")[:-1]).strip() - info["board"] = _machine - info["cpu"] = _machine.split("with")[-1].strip() - info["mpy"] = ( - sys.implementation._mpy # type: ignore - if "_mpy" in dir(sys.implementation) - else sys.implementation.mpy if "mpy" in dir(sys.implementation) else "" # type: ignore - ) - except (AttributeError, IndexError): - pass - info["board"] = get_boardname() - - try: - if "uname" in dir(os): # old - # extract build from uname().version if available - info["build"] = _build(os.uname()[3]) # type: ignore - if not info["build"]: - # extract build from uname().release if available - info["build"] = _build(os.uname()[2]) # type: ignore - elif "version" in dir(sys): # new - # extract build from sys.version if available - info["build"] = _build(sys.version) - except (AttributeError, IndexError, TypeError): - pass - # avoid build hashes - # if info["build"] and len(info["build"]) > 5: - # info["build"] = "" - - if info["version"] == "" and sys.platform not in ("unix", "win32"): - try: - u = os.uname() # type: ignore - info["version"] = u.release - except (IndexError, AttributeError, TypeError): - pass - # detect families - for fam_name, mod_name, mod_thing in [ - ("pycopy", "pycopy", "const"), - ("pycom", "pycom", "FAT"), - ("ev3-pybricks", "pybricks.hubs", "EV3Brick"), - ]: - try: - _t = __import__(mod_name, None, None, (mod_thing)) - info["family"] = fam_name - del _t - break - except (ImportError, KeyError): - pass - - if info["family"] == "ev3-pybricks": - info["release"] = "2.0.0" - - if info["family"] == "micropython": - info["version"] - if ( - info["version"] - and info["version"].endswith(".0") - and info["version"] >= "1.10.0" # versions from 1.10.0 to 1.23.0 do not have a micro .0 - and info["version"] <= "1.19.9" - ): - # versions from 1.10.0 to 1.23.0 do not have a micro .0 - info["version"] = info["version"][:-2] - - # spell-checker: disable - if "mpy" in info and info["mpy"]: # mpy on some v1.11+ builds - sys_mpy = int(info["mpy"]) - # .mpy architecture - arch = [ - None, - "x86", - "x64", - "armv6", - "armv6m", - "armv7m", - "armv7em", - "armv7emsp", - "armv7emdp", - "xtensa", - "xtensawin", - ][sys_mpy >> 10] - if arch: - info["arch"] = arch - # .mpy version.minor - info["mpy"] = "v{}.{}".format(sys_mpy & 0xFF, sys_mpy >> 8 & 3) - if info["build"] and not info["version"].endswith("-preview"): - info["version"] = info["version"] + "-preview" - # simple to use version[-build] string - info["ver"] = f"{info['version']}-{info['build']}" if info["build"] else f"{info['version']}" - - return info - - -def version_str(version: tuple): # -> str: - v_str = ".".join([str(n) for n in version[:3]]) - if len(version) > 3 and version[3]: - v_str += "-" + version[3] - return v_str - - -def get_boardname() -> str: - "Read the board name from the boardname.py file that may have been created upfront" - try: - from boardname import BOARDNAME # type: ignore - - log.info("Found BOARDNAME: {}".format(BOARDNAME)) - except ImportError: - log.warning("BOARDNAME not found") - BOARDNAME = "" - return BOARDNAME - - -def get_root() -> str: # sourcery skip: use-assigned-variable - "Determine the root folder of the device" - try: - c = os.getcwd() - except (OSError, AttributeError): - # unix port - c = "." - r = c - for r in [c, "/sd", "/flash", "/", "."]: - try: - _ = os.stat(r) - break - except OSError: - continue - return r - - -def file_exists(filename: str): - try: - if os.stat(filename)[0] >> 14: - return True - return False - except OSError: - return False - - -def show_help(): - print("-p, --path path to store the stubs in, defaults to '.'") - sys.exit(1) - - -def read_path() -> str: - "get --path from cmdline. [unix/win]" - path = "" - if len(sys.argv) == 3: - cmd = (sys.argv[1]).lower() - if cmd in ("--path", "-p"): - path = sys.argv[2] - else: - show_help() - elif len(sys.argv) == 2: - show_help() - return path - - -def is_micropython() -> bool: - "runtime test to determine full or micropython" - # pylint: disable=unused-variable,eval-used - try: - # either test should fail on micropython - - # b) https://docs.micropython.org/en/latest/genrst/builtin_types.html#bytes-with-keywords-not-implemented - # Micropython: NotImplementedError - b = bytes("abc", encoding="utf8") # type: ignore # lgtm [py/unused-local-variable] - - # c) https://docs.micropython.org/en/latest/genrst/core_language.html#function-objects-do-not-have-the-module-attribute - # Micropython: AttributeError - c = is_micropython.__module__ # type: ignore # lgtm [py/unused-local-variable] - return False - except (NotImplementedError, AttributeError): - return True - - + def __init__(B,path=E,firmware_id=E): + C=firmware_id + try: + if os.uname().release=='1.13.0'and os.uname().version<'v1.13-103':raise k('MicroPython 1.13.0 cannot be stubbed') + except I:pass + B.info=_info();A.info('Port: {}'.format(B.info[K]));A.info('Board: {}'.format(B.info[U]));D.collect() + if C:B._fwid=C.lower() + elif B.info[Q]==b:B._fwid='{family}-v{version}-{port}-{board}'.format(**B.info).rstrip(V) + else:B._fwid='{family}-v{version}-{port}'.format(**B.info) + B._start_free=D.mem_free() + if path: + if path.endswith(G):path=path[:-1] + else:path=get_root() + B.path='{}/stubs/{}'.format(path,B.flat_fwid).replace('//',G) + try:X(path+G) + except F:A.error('error creating stub folder {}'.format(path)) + B.problematic=['upip','upysh','webrepl_setup','http_client','http_client_ssl','http_server','http_server_ssl'];B.excluded=['webrepl','_webrepl','port_diag','example_sub_led.py','example_pub_button.py'];B.modules=[];B._json_name=E;B._json_first=H + def get_obj_attributes(L,item_instance): + H=item_instance;C=[];K=[] + for A in M(H): + if A.startswith('__')and not A in L.modules:continue + try: + E=getattr(H,A) + try:F=Z(type(E)).split("'")[1] + except T:F=B + if F in{p,q,r,s,c,d,e}:G=1 + elif F in{t,u}:G=2 + elif F in'class':G=3 + else:G=4 + C.append((A,Z(E),Z(type(E)),E,G)) + except I as J:K.append("Couldn't get attribute '{}' from object '{}', Err: {}".format(A,H,J)) + except MemoryError as J:S('MemoryError: {}'.format(J));sleep(1);reset() + C=l([A for A in C if not A[0].startswith('__')],key=lambda x:x[4]);D.collect();return C,K + def add_modules(A,modules):A.modules=l(set(A.modules)|set(modules)) + def create_all_stubs(B): + A.info('Start micropython-stubber {} on {}'.format(__version__,B._fwid));B.report_start();D.collect() + for C in B.modules:B.create_one_stub(C) + B.report_end();A.info('Finally done') + def create_one_stub(C,module_name): + B=module_name + if B in C.problematic:A.warning('Skip module: {:<25} : Known problematic'.format(B));return H + if B in C.excluded:A.warning('Skip module: {:<25} : Excluded'.format(B));return H + I='{}/{}.pyi'.format(C.path,B.replace(J,G));D.collect();E=H + try:E=C.create_module_stub(B,I) + except F:return H + D.collect();return E + def create_module_stub(K,module_name,file_name=E): + I=file_name;C=module_name + if I is E:L=C.replace(J,'_')+'.pyi';I=K.path+G+L + else:L=I.split(G)[-1] + if G in C:C=C.replace(G,J) + M=E + try:M=__import__(C,E,E,'*');Q=D.mem_free();A.info('Stub module: {:<25} to file: {:<70} mem:{:>5}'.format(C,L,Q)) + except N:return H + X(I) + with O(I,'w')as P:S=str(K.info).replace('OrderedDict(',B).replace('})','}');T='"""\nModule: \'{0}\' on {1}\n"""\n# MCU: {2}\n# Stubber: {3}\n'.format(C,K._fwid,S,__version__);P.write(T);P.write('from __future__ import annotations\nfrom typing import Any, Generator\nfrom _typeshed import Incomplete\n\n');K.write_object_stub(P,M,C,B) + K.report_add(C,I) + if C not in{'os','sys','logging','gc'}: + try:del M + except(F,m):A.warning('could not del new_module') + D.collect();return R + def write_object_stub(L,fp,object_expr,obj_name,indent,in_class=0): + Z=' at ...>';Y='generator';X='{0}{1}: {3} = {2}\n';W='bound_method';V='Incomplete';O=in_class;N='Exception';M=object_expr;K=' at ';J=fp;E=indent;D.collect() + if M in L.problematic:A.warning('SKIPPING problematic module:{}'.format(M));return + a,Q=L.get_obj_attributes(M) + if Q:A.error(Q) + for(F,H,I,b,g)in a: + if F in['classmethod','staticmethod','BaseException',N]:continue + if F[0].isdigit():A.warning('NameError: invalid name {}'.format(F));continue + if I==""and P(E)<=z*4: + R=B;S=F.endswith(N)or F.endswith('Error')or F in['KeyboardInterrupt','StopIteration','SystemExit'] + if S:R=N + C='\n{}class {}({}):\n'.format(E,F,R) + if S:C+=E+' ...\n';J.write(C);continue + J.write(C);L.write_object_stub(J,b,'{0}.{1}'.format(obj_name,F),E+' ',O+1);C=E+' def __init__(self, *argv, **kwargs) -> None:\n';C+=E+' ...\n\n';J.write(C) + elif any(A in I for A in[u,t,'closure']): + T=V;U=B + if O>0:U='self, ' + if W in I or W in H:C='{}@classmethod\n'.format(E)+'{}def {}(cls, *args, **kwargs) -> {}:\n'.format(E,F,T) + else:C='{}def {}({}*args, **kwargs) -> {}:\n'.format(E,F,U,T) + C+=E+' ...\n\n';J.write(C) + elif I=="":0 + elif I.startswith("='1.10.0'and A[C]<='1.19.9':A[C]=A[C][:-2] + if F in A and A[F]: + G=int(A[F]);L=[E,'x86','x64','armv6','armv6m','armv7m','armv7em','armv7emsp','armv7emdp','xtensa','xtensawin'][G>>10] + if L:A[R]=L + A[F]='v{}.{}'.format(G&255,G>>8&3) + if A[D]and not A[C].endswith(W):A[C]=A[C]+W + A[O]=f"{A[C]}-{A[D]}"if A[D]else f"{A[C]}";return A +def A1(version): + A=version;B=J.join([str(A)for A in A[:3]]) + if P(A)>3 and A[3]:B+=V+A[3] + return B +def A2(): + try:from boardname import BOARDNAME as C;A.info('Found BOARDNAME: {}'.format(C)) + except N:A.warning('BOARDNAME not found');C=B + return C +def get_root(): + try:A=os.getcwd() + except(F,I):A=J + B=A + for B in['/sd','/flash',G,A,J]: + try:C=os.stat(B);break + except F:continue + return B +def h(filename): + try: + if os.stat(filename)[0]>>14:return R + return H + except F:return H +def i():S("-p, --path path to store the stubs in, defaults to '.'");sys.exit(1) +def read_path(): + path=B + if P(sys.argv)==3: + A=sys.argv[1].lower() + if A in('--path','-p'):path=sys.argv[2] + else:i() + elif P(sys.argv)==2:i() + return path +def j(): + try:A=bytes('abc',encoding='utf8');B=j.__module__;return H + except(k,I):return R def main(): - stubber = Stubber(path=read_path()) - # stubber = Stubber(path="/sd") - # Option: Specify a firmware name & version - # stubber = Stubber(firmware_id='HoverBot v1.2.1') - stubber.clean() - - # Read stubs from modulelist in the current folder or in /libs - # fall back to default modules - def get_modulelist(stubber): - # new - gc.collect() - stubber.modules = [] # avoid duplicates - for p in LIBS: - fname = p + "/modulelist.txt" - if not file_exists(fname): - continue - with open(fname) as f: - # print("DEBUG: list of modules: " + p + "/modulelist.txt") - while True: - line = f.readline().strip() - if not line: - break - if len(line) > 0 and line[0] != "#": - stubber.modules.append(line) - gc.collect() - print("BREAK") - break - - if not stubber.modules: - stubber.modules = ["micropython"] - # _log.warn("Could not find modulelist.txt, using default modules") - gc.collect() - - stubber.modules = [] # avoid duplicates - get_modulelist(stubber) - - gc.collect() - - stubber.create_all_stubs() - - -if __name__ == "__main__" or is_micropython(): - if not file_exists("no_auto_stubber.txt"): - try: - gc.threshold(4 * 1024) # type: ignore - gc.enable() - except BaseException: - pass - main() + stubber=Stubber(path=read_path());stubber.clean() + def A(stubber): + D.collect();stubber.modules=[] + for C in A0: + B=C+'/modulelist.txt' + if not h(B):continue + with O(B)as E: + while R: + A=E.readline().strip() + if not A:break + if P(A)>0 and A[0]!='#':stubber.modules.append(A) + D.collect();S('BREAK');break + if not stubber.modules:stubber.modules=[b] + D.collect() + stubber.modules=[];A(stubber);D.collect();stubber.create_all_stubs() +if __name__=='__main__'or j(): + if not h('no_auto_stubber.txt'): + try:D.threshold(4096);D.enable() + except BaseException:pass + main() \ No newline at end of file diff --git a/mip/v5/createstubs_mem_mpy.mpy b/mip/v5/createstubs_mem_mpy.mpy index 6826d6c3b6d55245a38b7740b9072b0dedb023bd..0c34401a9801f2a6b6e83e3f8324b6fa19d7ac8e 100644 GIT binary patch literal 9302 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 G2LA_MASWjP literal 9450 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 S>(g4Gq&D?D*$4X! bool: # type: ignore - """Create a Stub of a single python module - - Args: - - module_name (str): name of the module to document. This module will be imported. - - file_name (Optional[str]): the 'path/filename.pyi' to write to. If omitted will be created based on the module name. - """ - if file_name is None: - fname = module_name.replace(".", "_") + ".pyi" - file_name = self.path + "/" + fname - else: - fname = file_name.split("/")[-1] - - if "/" in module_name: - # for nested modules - module_name = module_name.replace("/", ".") - - # import the module (as new_module) to examine it - new_module = None - try: - new_module = __import__(module_name, None, None, ("*")) - m1 = gc.mem_free() # type: ignore - log.info("Stub module: {:<25} to file: {:<70} mem:{:>5}".format(module_name, fname, m1)) - - except ImportError: - # log.debug("Skip module: {:<25} {:<79}".format(module_name, "Module not found.")) - return False - - # Start a new file - ensure_folder(file_name) - with open(file_name, "w") as fp: - info_ = str(self.info).replace("OrderedDict(", "").replace("})", "}") - s = '"""\nModule: \'{0}\' on {1}\n"""\n# MCU: {2}\n# Stubber: {3}\n'.format( - module_name, self._fwid, info_, __version__ - ) - fp.write(s) - fp.write( - "from __future__ import annotations\nfrom typing import Any, Generator\nfrom _typeshed import Incomplete\n\n" - ) - self.write_object_stub(fp, new_module, module_name, "") - - self.report_add(module_name, file_name) - - if module_name not in {"os", "sys", "logging", "gc"}: - # try to unload the module unless we use it - try: - del new_module - except (OSError, KeyError): # lgtm [py/unreachable-statement] - log.warning("could not del new_module") - # do not try to delete from sys.modules - most times it does not work anyway - gc.collect() - return True - - def write_object_stub(self, fp, object_expr: object, obj_name: str, indent: str, in_class: int = 0): - "Write a module/object stub to an open file. Can be called recursive." - gc.collect() - if object_expr in self.problematic: - log.warning("SKIPPING problematic module:{}".format(object_expr)) - return - - # # log.debug("DUMP : {}".format(object_expr)) - items, errors = self.get_obj_attributes(object_expr) - - if errors: - log.error(errors) - - for item_name, item_repr, item_type_txt, item_instance, _ in items: - # name_, repr_(value), type as text, item_instance, order - if item_name in ["classmethod", "staticmethod", "BaseException", "Exception"]: - # do not create stubs for these primitives - continue - if item_name[0].isdigit(): - log.warning("NameError: invalid name {}".format(item_name)) - continue - # Class expansion only on first 3 levels (bit of a hack) - if ( - item_type_txt == "" - and len(indent) <= _MAX_CLASS_LEVEL * 4 - # and not obj_name.endswith(".Pin") - # avoid expansion of Pin.cpu / Pin.board to avoid crashes on most platforms - ): - # log.debug("{0}class {1}:".format(indent, item_name)) - superclass = "" - is_exception = ( - item_name.endswith("Exception") - or item_name.endswith("Error") - or item_name - in [ - "KeyboardInterrupt", - "StopIteration", - "SystemExit", - ] - ) - if is_exception: - superclass = "Exception" - s = "\n{}class {}({}):\n".format(indent, item_name, superclass) - # s += indent + " ''\n" - if is_exception: - s += indent + " ...\n" - fp.write(s) - continue - # write classdef - fp.write(s) - # first write the class literals and methods - # log.debug("# recursion over class {0}".format(item_name)) - self.write_object_stub( - fp, - item_instance, - "{0}.{1}".format(obj_name, item_name), - indent + " ", - in_class + 1, - ) - # end with the __init__ method to make sure that the literals are defined - # Add __init__ - s = indent + " def __init__(self, *argv, **kwargs) -> None:\n" - s += indent + " ...\n\n" - fp.write(s) - elif any(word in item_type_txt for word in ["method", "function", "closure"]): - # log.debug("# def {1} function/method/closure, type = '{0}'".format(item_type_txt, item_name)) - # module Function or class method - # will accept any number of params - # return type Any/Incomplete - ret = "Incomplete" - first = "" - # Self parameter only on class methods/functions - if in_class > 0: - first = "self, " - # class method - add function decoration - if "bound_method" in item_type_txt or "bound_method" in item_repr: - s = "{}@classmethod\n".format(indent) + "{}def {}(cls, *args, **kwargs) -> {}:\n".format( - indent, item_name, ret - ) - else: - s = "{}def {}({}*args, **kwargs) -> {}:\n".format(indent, item_name, first, ret) - s += indent + " ...\n\n" - fp.write(s) - # log.debug("\n" + s) - elif item_type_txt == "": - # Skip imported modules - # fp.write("# import {}\n".format(item_name)) - pass - - elif item_type_txt.startswith("" - if " at " in item_repr: - item_repr = item_repr.split(" at ")[0] + " at ...>" - s = "{0}{1}: {2} ## {3} = {4}\n".format(indent, item_name, t, item_type_txt, item_repr) - fp.write(s) - # log.debug("\n" + s) - else: - # keep only the name - # log.debug("# all other, type = '{0}'".format(item_type_txt)) - fp.write("# all other, type = '{0}'\n".format(item_type_txt)) - - fp.write(indent + item_name + " # type: Incomplete\n") - - # del items - # del errors - # try: - # del item_name, item_repr, item_type_txt, item_instance # type: ignore - # except (OSError, KeyError, NameError): - # pass - - @property - def flat_fwid(self): - "Turn _fwid from 'v1.2.3' into '1_2_3' to be used in filename" - s = self._fwid - # path name restrictions - chars = " .()/\\:$" - for c in chars: - s = s.replace(c, "_") - return s - - def clean(self, path: str = None): # type: ignore - "Remove all files from the stub folder" - if path is None: - path = self.path - log.info("Clean/remove files in folder: {}".format(path)) - try: - os.stat(path) # TEMP workaround mpremote listdir bug - - items = os.listdir(path) - except (OSError, AttributeError): - # os.listdir fails on unix - return - for fn in items: - item = "{}/{}".format(path, fn) - try: - os.remove(item) - except OSError: - try: # folder - self.clean(item) - os.rmdir(item) - except OSError: - pass - - def report_start(self, filename: str = "modules.json"): - """Start a report of the modules that have been stubbed - "create json with list of exported modules""" - self._json_name = "{}/{}".format(self.path, filename) - self._json_first = True - ensure_folder(self._json_name) - log.info("Report file: {}".format(self._json_name)) - gc.collect() - try: - # write json by node to reduce memory requirements - with open(self._json_name, "w") as f: - f.write("{") - f.write(dumps({"firmware": self.info})[1:-1]) - f.write(",\n") - f.write(dumps({"stubber": {"version": __version__}, "stubtype": "firmware"})[1:-1]) - f.write(",\n") - f.write('"modules" :[\n') - - except OSError as e: - log.error("Failed to create the report.") - self._json_name = None - raise e - - def report_add(self, module_name: str, stub_file: str): - "Add a module to the report" - # write json by node to reduce memory requirements - if not self._json_name: - raise Exception("No report file") - try: - with open(self._json_name, "a") as f: - if not self._json_first: - f.write(",\n") - else: - self._json_first = False - line = '{{"module": "{}", "file": "{}"}}'.format(module_name, stub_file.replace("\\", "/")) - f.write(line) - - except OSError: - log.error("Failed to create the report.") - - def report_end(self): - if not self._json_name: - raise Exception("No report file") - with open(self._json_name, "a") as f: - f.write("\n]}") - # is used as sucess indicator - log.info("Path: {}".format(self.path)) - - -def ensure_folder(path: str): - "Create nested folders if needed" - i = start = 0 - while i != -1: - i = path.find("/", start) - if i != -1: - p = path[0] if i == 0 else path[:i] - # p = partial folder - try: - _ = os.stat(p) - except OSError as e: - # folder does not exist - if e.args[0] == ENOENT: - try: - os.mkdir(p) - except OSError as e2: - log.error("failed to create folder {}".format(p)) - raise e2 - # next level deep - start = i + 1 - - -def _build(s): - # extract build from sys.version or os.uname().version if available - # sys.version: 'MicroPython v1.23.0-preview.6.g3d0b6276f' - # sys.implementation.version: 'v1.13-103-gb137d064e' - if not s: - return "" - s = s.split(" on ", 1)[0] if " on " in s else s - if s.startswith("v"): - if not "-" in s: - return "" - b = s.split("-")[1] - return b - if not "-preview" in s: - return "" - b = s.split("-preview")[1].split(".")[1] - return b - - -def _info(): # type:() -> dict[str, str] - try: - fam = sys.implementation[0] # type: ignore - except TypeError: - # testing on CPython 3.11 - fam = sys.implementation.name - - info = OrderedDict( - { - "family": fam, - "version": "", - "build": "", - "ver": "", - "port": sys.platform, # port: esp32 / win32 / linux / stm32 - "board": "UNKNOWN", - "cpu": "", - "mpy": "", - "arch": "", - } - ) - # change port names to be consistent with the repo - if info["port"].startswith("pyb"): - info["port"] = "stm32" - elif info["port"] == "win32": - info["port"] = "windows" - elif info["port"] == "linux": - info["port"] = "unix" - try: - info["version"] = version_str(sys.implementation.version) # type: ignore - except AttributeError: - pass - try: - _machine = ( - sys.implementation._machine if "_machine" in dir(sys.implementation) else os.uname().machine # type: ignore - ) - # info["board"] = "with".join(_machine.split("with")[:-1]).strip() - info["board"] = _machine - info["cpu"] = _machine.split("with")[-1].strip() - info["mpy"] = ( - sys.implementation._mpy # type: ignore - if "_mpy" in dir(sys.implementation) - else sys.implementation.mpy if "mpy" in dir(sys.implementation) else "" # type: ignore - ) - except (AttributeError, IndexError): - pass - info["board"] = get_boardname() - - try: - if "uname" in dir(os): # old - # extract build from uname().version if available - info["build"] = _build(os.uname()[3]) # type: ignore - if not info["build"]: - # extract build from uname().release if available - info["build"] = _build(os.uname()[2]) # type: ignore - elif "version" in dir(sys): # new - # extract build from sys.version if available - info["build"] = _build(sys.version) - except (AttributeError, IndexError, TypeError): - pass - # avoid build hashes - # if info["build"] and len(info["build"]) > 5: - # info["build"] = "" - - if info["version"] == "" and sys.platform not in ("unix", "win32"): - try: - u = os.uname() # type: ignore - info["version"] = u.release - except (IndexError, AttributeError, TypeError): - pass - # detect families - for fam_name, mod_name, mod_thing in [ - ("pycopy", "pycopy", "const"), - ("pycom", "pycom", "FAT"), - ("ev3-pybricks", "pybricks.hubs", "EV3Brick"), - ]: - try: - _t = __import__(mod_name, None, None, (mod_thing)) - info["family"] = fam_name - del _t - break - except (ImportError, KeyError): - pass - - if info["family"] == "ev3-pybricks": - info["release"] = "2.0.0" - - if info["family"] == "micropython": - info["version"] - if ( - info["version"] - and info["version"].endswith(".0") - and info["version"] >= "1.10.0" # versions from 1.10.0 to 1.23.0 do not have a micro .0 - and info["version"] <= "1.19.9" - ): - # versions from 1.10.0 to 1.23.0 do not have a micro .0 - info["version"] = info["version"][:-2] - - # spell-checker: disable - if "mpy" in info and info["mpy"]: # mpy on some v1.11+ builds - sys_mpy = int(info["mpy"]) - # .mpy architecture - arch = [ - None, - "x86", - "x64", - "armv6", - "armv6m", - "armv7m", - "armv7em", - "armv7emsp", - "armv7emdp", - "xtensa", - "xtensawin", - ][sys_mpy >> 10] - if arch: - info["arch"] = arch - # .mpy version.minor - info["mpy"] = "v{}.{}".format(sys_mpy & 0xFF, sys_mpy >> 8 & 3) - if info["build"] and not info["version"].endswith("-preview"): - info["version"] = info["version"] + "-preview" - # simple to use version[-build] string - info["ver"] = f"{info['version']}-{info['build']}" if info["build"] else f"{info['version']}" - - return info - - -def version_str(version: tuple): # -> str: - v_str = ".".join([str(n) for n in version[:3]]) - if len(version) > 3 and version[3]: - v_str += "-" + version[3] - return v_str - - -def get_boardname() -> str: - "Read the board name from the boardname.py file that may have been created upfront" - try: - from boardname import BOARDNAME # type: ignore - - log.info("Found BOARDNAME: {}".format(BOARDNAME)) - except ImportError: - log.warning("BOARDNAME not found") - BOARDNAME = "" - return BOARDNAME - - -def get_root() -> str: # sourcery skip: use-assigned-variable - "Determine the root folder of the device" - try: - c = os.getcwd() - except (OSError, AttributeError): - # unix port - c = "." - r = c - for r in [c, "/sd", "/flash", "/", "."]: - try: - _ = os.stat(r) - break - except OSError: - continue - return r - - -def file_exists(filename: str): - try: - if os.stat(filename)[0] >> 14: - return True - return False - except OSError: - return False - - -def show_help(): - print("-p, --path path to store the stubs in, defaults to '.'") - sys.exit(1) - - -def read_path() -> str: - "get --path from cmdline. [unix/win]" - path = "" - if len(sys.argv) == 3: - cmd = (sys.argv[1]).lower() - if cmd in ("--path", "-p"): - path = sys.argv[2] - else: - show_help() - elif len(sys.argv) == 2: - show_help() - return path - - -def is_micropython() -> bool: - "runtime test to determine full or micropython" - # pylint: disable=unused-variable,eval-used - try: - # either test should fail on micropython - - # b) https://docs.micropython.org/en/latest/genrst/builtin_types.html#bytes-with-keywords-not-implemented - # Micropython: NotImplementedError - b = bytes("abc", encoding="utf8") # type: ignore # lgtm [py/unused-local-variable] - - # c) https://docs.micropython.org/en/latest/genrst/core_language.html#function-objects-do-not-have-the-module-attribute - # Micropython: AttributeError - c = is_micropython.__module__ # type: ignore # lgtm [py/unused-local-variable] - return False - except (NotImplementedError, AttributeError): - return True - - -def main(): - stubber = Stubber(path=read_path()) - # stubber = Stubber(path="/sd") - # Option: Specify a firmware name & version - # stubber = Stubber(firmware_id='HoverBot v1.2.1') - stubber.clean() - # there is no option to discover modules from micropython, need to hardcode - # below contains combined modules from Micropython ESP8622, ESP32, Loboris, Pycom and ulab , lvgl - # spell-checker: disable - # modules to stub : 131 - stubber.modules = [ - "WM8960", - "_OTA", - "_asyncio", - "_boot_fat", - "_coap", - "_espnow", - "_flash_control_OTA", - "_main_pybytes", - "_mqtt", - "_mqtt_core", - "_msg_handl", - "_onewire", - "_periodical_pin", - "_pybytes", - "_pybytes_ca", - "_pybytes_config", - "_pybytes_config_reader", - "_pybytes_connection", - "_pybytes_constants", - "_pybytes_debug", - "_pybytes_library", - "_pybytes_machine_learning", - "_pybytes_main", - "_pybytes_protocol", - "_pybytes_pyconfig", - "_pybytes_pymesh_config", - "_rp2", - "_terminal", - "_thread", - "_uasyncio", - "_urequest", - "adcfft", - "aioble/__init__", - "aioble/central", - "aioble/client", - "aioble/core", - "aioble/device", - "aioble/l2cap", - "aioble/peripheral", - "aioble/security", - "aioble/server", - "aioespnow", - "ak8963", - "apa102", - "apa106", - "argparse", - "array", - "asyncio/__init__", - "asyncio/core", - "asyncio/event", - "asyncio/funcs", - "asyncio/lock", - "asyncio/stream", - "binascii", - "bluetooth", - "breakout_as7262", - "breakout_bh1745", - "breakout_bme280", - "breakout_bme68x", - "breakout_bmp280", - "breakout_dotmatrix", - "breakout_encoder", - "breakout_icp10125", - "breakout_ioexpander", - "breakout_ltr559", - "breakout_matrix11x7", - "breakout_mics6814", - "breakout_msa301", - "breakout_paa5100", - "breakout_pmw3901", - "breakout_potentiometer", - "breakout_rgbmatrix5x5", - "breakout_rtc", - "breakout_scd41", - "breakout_sgp30", - "breakout_trackball", - "breakout_vl53l5cx", - "btree", - "cmath", - "collections", - "crypto", - "cryptolib", - "curl", - "deflate", - "dht", - "display", - "display_driver_utils", - "ds18x20", - "encoder", - "errno", - "esp", - "esp32", - "espidf", - "espnow", - "ffi", - "flashbdev", - "framebuf", - "freesans20", - "fs_driver", - "functools", - "galactic", - "gc", - "gfx_pack", - "gsm", - "hashlib", - "heapq", - "hub75", - "ili9341", - "ili9XXX", - "imagetools", - "inisetup", - "interstate75", - "io", - "jpegdec", - "js", - "jsffi", - "json", - "lcd160cr", - "lodepng", - "logging", - "lsm6dsox", - "lv_colors", - "lv_utils", - "lvgl", - "lwip", - "machine", - "math", - "microWebSocket", - "microWebSrv", - "microWebTemplate", - "micropython", - "mip", - "mip/__init__", - "mip/__main__", - "motor", - "mpu6500", - "mpu9250", - "neopixel", - "network", - "ntptime", - "onewire", - "openamp", - "os", - "pcf85063a", - "picoexplorer", - "picographics", - "picokeypad", - "picoscroll", - "picounicorn", - "picowireless", - "pimoroni", - "pimoroni_bus", - "pimoroni_i2c", - "plasma", - "platform", - "pyb", - "pycom", - "pye", - "qrcode", - "queue", - "random", - "requests", - "requests/__init__", - "rp2", - "rtch", - "samd", - "select", - "servo", - "socket", - "ssd1306", - "ssh", - "ssl", - "stm", - "struct", - "sys", - "termios", - "time", - "tls", - "tpcalib", - "uarray", - "uasyncio/__init__", - "uasyncio/core", - "uasyncio/event", - "uasyncio/funcs", - "uasyncio/lock", - "uasyncio/stream", - "uasyncio/tasks", - "ubinascii", - "ubluetooth", - "ucollections", - "ucrypto", - "ucryptolib", - "uctypes", - "uerrno", - "uftpd", - "uhashlib", - "uheapq", - "uio", - "ujson", - "ulab", - "ulab/approx", - "ulab/compare", - "ulab/fft", - "ulab/filter", - "ulab/linalg", - "ulab/numerical", - "ulab/poly", - "ulab/user", - "ulab/vector", - "umachine", - "umqtt/__init__", - "umqtt/robust", - "umqtt/simple", - "uos", - "uplatform", - "uqueue", - "urandom", - "ure", - "urequests", - "urllib/urequest", - "usb/device", - "usb/device/cdc", - "usb/device/hid", - "usb/device/keyboard", - "usb/device/midi", - "usb/device/mouse", - "uselect", - "usocket", - "ussl", - "ustruct", - "usys", - "utelnetserver", - "utime", - "utimeq", - "uwebsocket", - "uzlib", - "version", - "vfs", - "websocket", - "websocket_helper", - "wipy", - "writer", - "xpt2046", - "ymodem", - "zephyr", - "zlib", - ] # spell-checker: enable - - gc.collect() - - stubber.create_all_stubs() - - -if __name__ == "__main__" or is_micropython(): - if not file_exists("no_auto_stubber.txt"): - try: - gc.threshold(4 * 1024) # type: ignore - gc.enable() - except BaseException: - pass - main() + def __init__(B,path=D,firmware_id=D): + C=firmware_id + try: + if os.uname().release=='1.13.0'and os.uname().version<'v1.13-103':raise l('MicroPython 1.13.0 cannot be stubbed') + except I:pass + B.info=_info();A.info('Port: {}'.format(B.info[K]));A.info('Board: {}'.format(B.info[S]));F.collect() + if C:B._fwid=C.lower() + elif B.info[O]==b:B._fwid='{family}-v{version}-{port}-{board}'.format(**B.info).rstrip(T) + else:B._fwid='{family}-v{version}-{port}'.format(**B.info) + B._start_free=F.mem_free() + if path: + if path.endswith(G):path=path[:-1] + else:path=get_root() + B.path='{}/stubs/{}'.format(path,B.flat_fwid).replace('//',G) + try:W(path+G) + except E:A.error('error creating stub folder {}'.format(path)) + B.problematic=['upip','upysh','webrepl_setup','http_client','http_client_ssl','http_server','http_server_ssl'];B.excluded=['webrepl','_webrepl','port_diag','example_sub_led.py','example_pub_button.py'];B.modules=[];B._json_name=D;B._json_first=H + def get_obj_attributes(L,item_instance): + H=item_instance;C=[];K=[] + for A in M(H): + if A.startswith('__')and not A in L.modules:continue + try: + D=getattr(H,A) + try:E=Z(type(D)).split("'")[1] + except P:E=B + if E in{q,r,s,t,c,d,e}:G=1 + elif E in{u,v}:G=2 + elif E in'class':G=3 + else:G=4 + C.append((A,Z(D),Z(type(D)),D,G)) + except I as J:K.append("Couldn't get attribute '{}' from object '{}', Err: {}".format(A,H,J)) + except MemoryError as J:Y('MemoryError: {}'.format(J));sleep(1);reset() + C=m([A for A in C if not A[0].startswith('__')],key=lambda x:x[4]);F.collect();return C,K + def add_modules(A,modules):A.modules=m(set(A.modules)|set(modules)) + def create_all_stubs(B): + A.info('Start micropython-stubber {} on {}'.format(__version__,B._fwid));B.report_start();F.collect() + for C in B.modules:B.create_one_stub(C) + B.report_end();A.info('Finally done') + def create_one_stub(C,module_name): + B=module_name + if B in C.problematic:A.warning('Skip module: {:<25} : Known problematic'.format(B));return H + if B in C.excluded:A.warning('Skip module: {:<25} : Excluded'.format(B));return H + I='{}/{}.pyi'.format(C.path,B.replace(J,G));F.collect();D=H + try:D=C.create_module_stub(B,I) + except E:return H + F.collect();return D + def create_module_stub(K,module_name,file_name=D): + I=file_name;C=module_name + if I is D:L=C.replace(J,'_')+'.pyi';I=K.path+G+L + else:L=I.split(G)[-1] + if G in C:C=C.replace(G,J) + M=D + try:M=__import__(C,D,D,'*');P=F.mem_free();A.info('Stub module: {:<25} to file: {:<70} mem:{:>5}'.format(C,L,P)) + except N:return H + W(I) + with Q(I,'w')as O:R=str(K.info).replace('OrderedDict(',B).replace('})','}');S='"""\nModule: \'{0}\' on {1}\n"""\n# MCU: {2}\n# Stubber: {3}\n'.format(C,K._fwid,R,__version__);O.write(S);O.write('from __future__ import annotations\nfrom typing import Any, Generator\nfrom _typeshed import Incomplete\n\n');K.write_object_stub(O,M,C,B) + K.report_add(C,I) + if C not in{'os',w,x,'gc'}: + try:del M + except(E,n):A.warning('could not del new_module') + F.collect();return U + def write_object_stub(L,fp,object_expr,obj_name,indent,in_class=0): + Z=' at ...>';Y='generator';X='{0}{1}: {3} = {2}\n';W='bound_method';V='Incomplete';O=in_class;N='Exception';M=object_expr;K=' at ';J=fp;D=indent;F.collect() + if M in L.problematic:A.warning('SKIPPING problematic module:{}'.format(M));return + a,P=L.get_obj_attributes(M) + if P:A.error(P) + for(E,H,I,b,g)in a: + if E in['classmethod','staticmethod','BaseException',N]:continue + if E[0].isdigit():A.warning('NameError: invalid name {}'.format(E));continue + if I==""and R(D)<=A3*4: + Q=B;S=E.endswith(N)or E.endswith('Error')or E in['KeyboardInterrupt','StopIteration','SystemExit'] + if S:Q=N + C='\n{}class {}({}):\n'.format(D,E,Q) + if S:C+=D+' ...\n';J.write(C);continue + J.write(C);L.write_object_stub(J,b,'{0}.{1}'.format(obj_name,E),D+' ',O+1);C=D+' def __init__(self, *argv, **kwargs) -> None:\n';C+=D+' ...\n\n';J.write(C) + elif any(A in I for A in[v,u,'closure']): + T=V;U=B + if O>0:U='self, ' + if W in I or W in H:C='{}@classmethod\n'.format(D)+'{}def {}(cls, *args, **kwargs) -> {}:\n'.format(D,E,T) + else:C='{}def {}({}*args, **kwargs) -> {}:\n'.format(D,E,U,T) + C+=D+' ...\n\n';J.write(C) + elif I=="":0 + elif I.startswith("='1.10.0'and A[C]<='1.19.9':A[C]=A[C][:-2] + if F in A and A[F]: + G=int(A[F]);L=[D,'x86','x64','armv6','armv6m','armv7m','armv7em','armv7emsp','armv7emdp','xtensa','xtensawin'][G>>10] + if L:A[T]=L + A[F]='v{}.{}'.format(G&255,G>>8&3) + if A[E]and not A[C].endswith(V):A[C]=A[C]+V + A[Q]=f"{A[C]}-{A[E]}"if A[E]else f"{A[C]}";return A +def A4(version): + A=version;B=J.join([str(A)for A in A[:3]]) + if R(A)>3 and A[3]:B+=T+A[3] + return B +def A5(): + try:from boardname import BOARDNAME as C;A.info('Found BOARDNAME: {}'.format(C)) + except N:A.warning('BOARDNAME not found');C=B + return C +def get_root(): + try:A=os.getcwd() + except(E,I):A=J + B=A + for B in['/sd','/flash',G,A,J]: + try:C=os.stat(B);break + except E:continue + return B +def A6(filename): + try: + if os.stat(filename)[0]>>14:return U + return H + except E:return H +def j():Y("-p, --path path to store the stubs in, defaults to '.'");sys.exit(1) +def read_path(): + path=B + if R(sys.argv)==3: + A=sys.argv[1].lower() + if A in('--path','-p'):path=sys.argv[2] + else:j() + elif R(sys.argv)==2:j() + return path +def k(): + try:A=bytes('abc',encoding='utf8');B=k.__module__;return H + except(l,I):return U +def main():stubber=Stubber(path=read_path());stubber.clean();stubber.modules=['WM8960','_OTA','_asyncio','_boot_fat','_coap','_espnow','_flash_control_OTA','_main_pybytes','_mqtt','_mqtt_core','_msg_handl','_onewire','_periodical_pin','_pybytes','_pybytes_ca','_pybytes_config','_pybytes_config_reader','_pybytes_connection','_pybytes_constants','_pybytes_debug','_pybytes_library','_pybytes_machine_learning','_pybytes_main','_pybytes_protocol','_pybytes_pyconfig','_pybytes_pymesh_config','_rp2','_terminal','_thread','_uasyncio','_urequest','adcfft','aioble/__init__','aioble/central','aioble/client','aioble/core','aioble/device','aioble/l2cap','aioble/peripheral','aioble/security','aioble/server','aioespnow','ak8963','apa102','apa106','argparse','array','asyncio/__init__','asyncio/core','asyncio/event','asyncio/funcs','asyncio/lock','asyncio/stream','binascii','bluetooth','breakout_as7262','breakout_bh1745','breakout_bme280','breakout_bme68x','breakout_bmp280','breakout_dotmatrix','breakout_encoder','breakout_icp10125','breakout_ioexpander','breakout_ltr559','breakout_matrix11x7','breakout_mics6814','breakout_msa301','breakout_paa5100','breakout_pmw3901','breakout_potentiometer','breakout_rgbmatrix5x5','breakout_rtc','breakout_scd41','breakout_sgp30','breakout_trackball','breakout_vl53l5cx','btree','cc3200','cmath','collections','crypto','cryptolib','curl','deflate','dht','display','display_driver_utils','ds18x20','embed','encoder','errno','esp','esp32','esp8266','espidf','espnow','ffi','flashbdev','framebuf','freesans20','fs_driver','functools','galactic','gc','gfx_pack','gsm','hashlib','heapq','hub75','ili9341','ili9XXX','imagetools','inisetup','interstate75','io','jpegdec','js','jsffi','json','lcd160cr','lodepng',x,'lsm6dsox','lv_colors','lv_utils','lvgl','lwip','machine','math','microWebSocket','microWebSrv','microWebTemplate',b,'mimxrt','mip','mip/__init__','mip/__main__','motor','mpu6500','mpu9250','neopixel','network','nrf','ntptime','onewire','openamp','os','pcf85063a','pic16bit','picoexplorer','picographics','picokeypad','picoscroll','picounicorn','picowireless','pimoroni','pimoroni_bus','pimoroni_i2c','plasma','platform','powerpc','pyb',h,'pye','qemu','qrcode','queue','random','renesas','renesas-ra','requests','requests/__init__','rp2','rtch','samd','select','servo','socket','ssd1306','ssh','ssl','stm','stm32','struct',w,'termios','time','tls','tpcalib','uarray','uasyncio/__init__','uasyncio/core','uasyncio/event','uasyncio/funcs','uasyncio/lock','uasyncio/stream','uasyncio/tasks','ubinascii','ubluetooth','ucollections','ucrypto','ucryptolib','uctypes','uerrno','uftpd','uhashlib','uheapq','uio','ujson','ulab','ulab/approx','ulab/compare','ulab/fft','ulab/filter','ulab/linalg','ulab/numerical','ulab/poly','ulab/user','ulab/vector','umachine','umqtt/__init__','umqtt/robust','umqtt/simple',g,'uos','uplatform','uqueue','urandom','ure','urequests','urllib/urequest','usb/device','usb/device/cdc','usb/device/hid','usb/device/keyboard','usb/device/midi','usb/device/mouse','uselect','usocket','ussl','ustruct','usys','utelnetserver','utime','utimeq','uwebsocket','uzlib',C,'vfs','webassembly','websocket','websocket_helper',A1,'wipy','writer','xpt2046','ymodem','zephyr','zlib'];F.collect();stubber.create_all_stubs() +if __name__=='__main__'or k(): + if not A6('no_auto_stubber.txt'): + try:F.threshold(4096);F.enable() + except BaseException:pass + main() \ No newline at end of file diff --git a/mip/v5/createstubs_mpy.mpy b/mip/v5/createstubs_mpy.mpy index 2219ada98f1f31dba1a68e88da94fc052e764c3a..d5b983dafc33acc86cee777ee5cc5c906876ecc3 100644 GIT binary patch delta 6429 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 delta 6602 zcmZu$e^48DcK_~5LP7}f)oKx7?6B5KLO(zVA%*jR{I28@wGxJv8@5Q|YP5Rrtj zk2t&FaE%>L#_6V$w%2sro3y#kb*_@Z4({}F{uSG~OWoew&Geirb+6ORbf!P9p`HG5 z*O~TxSHi~5;gPia{l5L~`@ZjcpZ9sstBIA7mkw&^Chi?W%PFMYn#>BLc_Ejd9m{!V zPLGT@oz4M%Xox===8q0JY_>f2_I7WM`_|h_mL+ECjV0}pVac>qDReFwmzdwx`Q3a= z%!Z_BqxyK#Ldid+=4j-Q`{)*tiuY_oM@-1^Fw9DE2~%#Wv3@q0NvDNmK9!lyZBWb0!>Hb_}2KuFfBY$A<~gQZa-?^jv22-CUQtdN+$|4bF6scN}KZLz+tb2dG7$QO8<&E|OVRqnh_-~>+I zt9EQb^A_Dqb~3oN9q}W3yHYdQriwVXDn_Uxcfq0$YcT2l`(;#Bt9RgLIroqjMEgx#L8R8;=4rWd}SsTlAE{!XHXkf~AX z<(uq7HrK9QF5AJjmwkPp~3-vnUeGwyK zo^<>oOs@wZW}hJ&^*s#NN^z!1*6B{!qJ?@k@oEm@mbk|Nd53a0k;>-s(WC*+ym9$E zI+oJBZMe)t{C58T3jJ%H+bfmZvpg)Z?z~v%?{^&{ooR>xKV!Am< zEyV8hn25^Ghhd!*$B4QEup=J3iqR`rKatLi<}rF7qdgdXfKeKw-d62eSR*am4Q-dM zVmvWBtsoXQObHN$k z98rAaVfY!Tg5RKk*>W=la6S0mxJ`Jo|c^XTGW5a6;tV=@8PjtCdj9~r!=U#8 zZmdy&vHo)tM!Q(}&&g5`K?sV=^I>*~u)oVWq+ogyGIn{)2 z04y=c<)$BoYovH1oMbz%C1F=Oo;En1!$}PsPuueK8Wkn}zU^1FAJMgK(*JTUSNmA6 zt>@q%?`iMioS9A=*V3|mYQ$#iwK<(#lM`t}5H4gRWe}55vN5UeaK3`?gAy_v^bvH=LwZ5BZ z0r%AsyxEOW2Sz(Qs#(Ccv?|eH+hs&!$dIjq^5guE=valZ1#8-Iz`u$H<_^QoIe6+xz z=WS-rLT$kBCO|eO(;33dJgQd+;D?V&m_0C^%uLOsg}m@L;7tyEMfw?lGdARe^h68i zz_@-aGdm4PreL{UG_L`Z!qm03aGk^($hLwMU#)EK2SL^P{ZO^U8@16e}$-uPiW&(FM#*WHa9YLM!BP#XxFW#K4B9h3sfPlXYv>!W@yL9uSi;`!^;W zCY~uRX|kKI1vU3WVF@?DMs(b0o&(ci=^8;NATv@7Tmc5b751!uhE-2bs@6Z_!8YJL zHf602&0}}jM)2%Io`q?)>Sz${4UR}M2|4HSmFQa5GKbp!iI7TEU_B<=8%B<(4#r+|B$q(UXT!mV;1o0+PZ2Z)P^Km$&~bSX2O0NcZn zVR|06My?qB`0Uh7u7xU?t08bx*(pfc!dQS>5Fr%GLRj6R-;md~&@B|Rxe$c%uv8O5 ztyiwr#&8wJFO!@6>6x#sR$X3;R|wV7V?EBY;hUse2h0dIRYF-_4T8X28x`RDrF3r@(t!5-?+x!rF^q9AF(sORR&wO@xRCK=mF zHS-E{e59MDOhpLOR!CKXl#@AQe}*eL11Epp;84_G?A&45&|a7xuf6!gW~c8U=v`aZ z8$eS~&X2;iptAv(AYm5;X%Bk9PEo1yoh97Kb#WqEeX_CtGF9e8biIY`~^Ia=QGp!Dg1{pgAr zy&%Pya{d1xyh|#@k$&m~1PVM5?{SqM;G{bTSOiwuF8^Xn8)cGBjoZZ6UAA(CZo2qy zHruWir>({6v_b9DMba0Q1l-C@bA>fv37`?+)^-0X(W ztDMi%0{{4gjpv$9ICgN{o~GVbTMvII5ZQTXr*FJ-FYjvgg*lIBh<7`z&er{&NQ;AW z`dZQ%UvJZ*!ESqT=d=Ay0|*E!0|ZI7Z8eM6d+LaZf)B$+sM1tsm079WuPao@awrRp z3}HN+O6FTC3mbLi7}#c0w84#D>2oOK6%d7EP^aS=fYFIecB)j(LQux~d;1R^=`WYG zC1Ei+Gh4cvnmMgp=ti^2NeKKKMO>v69~CeGX0DR3K9`^B@E5UWIOLUzn2KTjTxz<* z|A0&y;c`4Pms6(e%G2r8^z12RS~okLI;G4ZDPloPxev2%8YpF!*=F{b?Ewnb94?pV zkFYgz0b!h&8cj~7rXdFU7_C_wpw^(aRIH_uTemfcH!l~leHdc(U96i+fCg$AEvpTpMP*n!9I{Gyo1!6k7^t0iNPkJ<_CzRnTLg9*E&iAf@IGY{woq4OF{Tg3JY&U<#sJ%VuL%fP|D2 zilAm`DW|fj%}Zg!%;_YwuP_v;5w{BK$?X)}RlK-w$gScLPhs3W+!4yAk|*3Mk1Ej{ zL_XE+Pwzl6FK#Ypu0*3(1M0g_B$V4AP$_mcNDDoREgfavU$$lFu1HM6(+{BJ$9lil z=k*n_3GAdPbx*p%lT0zFDyUd^r{YzF1gpJ1aLH!42Ll+|_j=pmxt~L;r99wm-{sx) z1;7Tmj}kUVP7}96G4_(ONcb@1gICC^0qR~t8FN1UuH-LV7W6&HZ;%(q(haTe$6zay35~_80x3UlDzYx07sw_k{ zMm|9r2rHq6go2R!DmZKsyTiq#O5VynBjyak$&OYCK4S6Q!ptsqbMNx0X5ppN9qn!e zaK@rZKUIjHg)Ikw=G}m@q7b0Y{tT#J;cN_wmm)#Sv$6Fr0Ur@nmEUJ%cc-DlN!a+F z%1ft9y$1tofk)qmW&t!EzA7~x79)WzPrAP9lEm@-$2?B?9%l_G%`_e9v+~gA8Y(FH zr)Mj1T_{=21l}I^0!Tj%Tvy(@JuopoZhO>rt-f@D<693ptpVOW;8CCw>PglBby#w4 zJczFMSjd7Kw2t(N8WpfC+$i7*=rLnMslN>A3u`=@M6V0oh?o#lDHpe!fe$LZrOv+> zDTTECR0J!ag^?XkG<$0q}V%Og=y(<5_$+<>nITR3Y;k|kW_yP z z5|gz(X2ORRCQQ`+16`ruyP!s|RbKj0hCAMw9pS9go!z8&TK>z!$Wxb-8v{@Lo{_Xo zO&1!PW~6GXb<*0jPzB%J*5}FiNvWnJ+jQOtW7bLdz{1LVUK^Pk>6{-KIe?gremA);0hr(1J}8k4!_)E|9R!3UW4p(bVA28C+8eN z`FjqR{0qlEOj6heqQSKwztCJSzuMeqFhKH|O+tkQ?F#vB^Oy2pINxi0lv*JkCvupX w6UK6x2eJ1d*#H0l diff --git a/mip/v5/modulelist.txt b/mip/v5/modulelist.txt index 9a2a9af5..e5da49b0 100644 --- a/mip/v5/modulelist.txt +++ b/mip/v5/modulelist.txt @@ -77,6 +77,7 @@ breakout_sgp30 breakout_trackball breakout_vl53l5cx btree +cc3200 cmath collections crypto @@ -87,10 +88,12 @@ dht display display_driver_utils ds18x20 +embed encoder errno esp esp32 +esp8266 espidf espnow ffi @@ -130,6 +133,7 @@ microWebSocket microWebSrv microWebTemplate micropython +mimxrt mip mip/__init__ mip/__main__ @@ -138,11 +142,13 @@ mpu6500 mpu9250 neopixel network +nrf ntptime onewire openamp os pcf85063a +pic16bit picoexplorer picographics picokeypad @@ -154,12 +160,16 @@ pimoroni_bus pimoroni_i2c plasma platform +powerpc pyb pycom pye +qemu qrcode queue random +renesas +renesas-ra requests requests/__init__ rp2 @@ -172,6 +182,7 @@ ssd1306 ssh ssl stm +stm32 struct sys termios @@ -212,6 +223,7 @@ umachine umqtt/__init__ umqtt/robust umqtt/simple +unix uos uplatform uqueue @@ -237,8 +249,10 @@ uwebsocket uzlib version vfs +webassembly websocket websocket_helper +windows wipy writer xpt2046 diff --git a/mip/v6/createstubs.py b/mip/v6/createstubs.py index 8c6410c4..42656793 100644 --- a/mip/v6/createstubs.py +++ b/mip/v6/createstubs.py @@ -24,7 +24,7 @@ except ImportError: from ucollections import OrderedDict # type: ignore -__version__ = "v1.23.0" +__version__ = "v1.24.0" ENOENT = 2 _MAX_CLASS_LEVEL = 2 # Max class nesting LIBS = ["lib", "/lib", "/sd/lib", "/flash/lib", "."] @@ -488,7 +488,7 @@ def ensure_folder(path: str): def _build(s): # extract build from sys.version or os.uname().version if available - # sys.version: 'MicroPython v1.23.0-preview.6.g3d0b6276f' + # sys.version: 'MicroPython v1.24.0-preview.6.g3d0b6276f' # sys.implementation.version: 'v1.13-103-gb137d064e' if not s: return "" @@ -595,10 +595,10 @@ def _info(): # type:() -> dict[str, str] if ( info["version"] and info["version"].endswith(".0") - and info["version"] >= "1.10.0" # versions from 1.10.0 to 1.23.0 do not have a micro .0 + and info["version"] >= "1.10.0" # versions from 1.10.0 to 1.24.0 do not have a micro .0 and info["version"] <= "1.19.9" ): - # versions from 1.10.0 to 1.23.0 do not have a micro .0 + # versions from 1.10.0 to 1.24.0 do not have a micro .0 info["version"] = info["version"][:-2] # spell-checker: disable @@ -657,7 +657,7 @@ def get_root() -> str: # sourcery skip: use-assigned-variable # unix port c = "." r = c - for r in [c, "/sd", "/flash", "/", "."]: + for r in ["/sd", "/flash", "/", c, "."]: try: _ = os.stat(r) break @@ -801,6 +801,7 @@ def main(): "breakout_trackball", "breakout_vl53l5cx", "btree", + "cc3200", "cmath", "collections", "crypto", @@ -811,10 +812,12 @@ def main(): "display", "display_driver_utils", "ds18x20", + "embed", "encoder", "errno", "esp", "esp32", + "esp8266", "espidf", "espnow", "ffi", @@ -854,6 +857,7 @@ def main(): "microWebSrv", "microWebTemplate", "micropython", + "mimxrt", "mip", "mip/__init__", "mip/__main__", @@ -862,11 +866,13 @@ def main(): "mpu9250", "neopixel", "network", + "nrf", "ntptime", "onewire", "openamp", "os", "pcf85063a", + "pic16bit", "picoexplorer", "picographics", "picokeypad", @@ -878,12 +884,16 @@ def main(): "pimoroni_i2c", "plasma", "platform", + "powerpc", "pyb", "pycom", "pye", + "qemu", "qrcode", "queue", "random", + "renesas", + "renesas-ra", "requests", "requests/__init__", "rp2", @@ -896,6 +906,7 @@ def main(): "ssh", "ssl", "stm", + "stm32", "struct", "sys", "termios", @@ -936,6 +947,7 @@ def main(): "umqtt/__init__", "umqtt/robust", "umqtt/simple", + "unix", "uos", "uplatform", "uqueue", @@ -961,8 +973,10 @@ def main(): "uzlib", "version", "vfs", + "webassembly", "websocket", "websocket_helper", + "windows", "wipy", "writer", "xpt2046", diff --git a/mip/v6/createstubs_db.py b/mip/v6/createstubs_db.py index 634433a4..d20cb87e 100644 --- a/mip/v6/createstubs_db.py +++ b/mip/v6/createstubs_db.py @@ -18,7 +18,7 @@ - cross compilation, using mpy-cross, to avoid the compilation step on the micropython device -This variant was generated from createstubs.py by micropython-stubber v1.23.0 +This variant was generated from createstubs.py by micropython-stubber v1.24.0 """ # Copyright (c) 2019-2024 Jos Verlinde @@ -43,7 +43,7 @@ except ImportError: from ucollections import OrderedDict # type: ignore -__version__ = "v1.23.0" +__version__ = "v1.24.0" ENOENT = 2 _MAX_CLASS_LEVEL = 2 # Max class nesting LIBS = ["lib", "/lib", "/sd/lib", "/flash/lib", "."] @@ -501,7 +501,7 @@ def ensure_folder(path: str): def _build(s): # extract build from sys.version or os.uname().version if available - # sys.version: 'MicroPython v1.23.0-preview.6.g3d0b6276f' + # sys.version: 'MicroPython v1.24.0-preview.6.g3d0b6276f' # sys.implementation.version: 'v1.13-103-gb137d064e' if not s: return "" @@ -606,10 +606,10 @@ def _info(): # type:() -> dict[str, str] if ( info["version"] and info["version"].endswith(".0") - and info["version"] >= "1.10.0" # versions from 1.10.0 to 1.23.0 do not have a micro .0 + and info["version"] >= "1.10.0" # versions from 1.10.0 to 1.24.0 do not have a micro .0 and info["version"] <= "1.19.9" ): - # versions from 1.10.0 to 1.23.0 do not have a micro .0 + # versions from 1.10.0 to 1.24.0 do not have a micro .0 info["version"] = info["version"][:-2] # spell-checker: disable @@ -668,7 +668,7 @@ def get_root() -> str: # sourcery skip: use-assigned-variable # unix port c = "." r = c - for r in [c, "/sd", "/flash", "/", "."]: + for r in ["/sd", "/flash", "/", c, "."]: try: _ = os.stat(r) break diff --git a/mip/v6/createstubs_db_min.py b/mip/v6/createstubs_db_min.py index 634433a4..b48f1711 100644 --- a/mip/v6/createstubs_db_min.py +++ b/mip/v6/createstubs_db_min.py @@ -1,825 +1,332 @@ -""" -Create stubs for (all) modules on a MicroPython board. - - This variant of the createstubs.py script is optimized for use on very-low-memory devices. - Note: this version has undergone limited testing. - - 1) reads the list of modules from a text file `modulelist.txt` that should be uploaded to the device. - 2) stored the already processed modules in a text file `modulelist.done` - 3) process the modules in the database: - - stub the module - - update the modulelist.done file - - reboots the device if it runs out of memory - 4) creates the modules.json - - If that cannot be found then only a single module (micropython) is stubbed. - In order to run this on low-memory devices two additional steps are recommended: - - minification, using python-minifierto reduce overall size, and remove logging overhead. - - cross compilation, using mpy-cross, to avoid the compilation step on the micropython device - - -This variant was generated from createstubs.py by micropython-stubber v1.23.0 -""" - -# Copyright (c) 2019-2024 Jos Verlinde - -import gc -import os -import sys +A2='No report file' +A1='Failed to create the report.' +A0='method' +z='function' +y='bool' +x='str' +w='float' +v='int' +u='micropython' +t='stubber' +s=Exception +r=KeyError +q=sorted +p=MemoryError +o=NotImplementedError +k=',\n' +j='modules.json' +i='{}/{}' +h='w' +g='dict' +f='list' +e='tuple' +d=TypeError +c=str +b=repr +W='-preview' +V='-' +U='board' +T=IndexError +S=print +R=True +Q='family' +P=len +O=ImportError +N=dir +M=open +K='port' +J='.' +I=AttributeError +H=False +G='/' +E=None +D=OSError +C='version' +B='' +import gc as F,os,sys from time import sleep - -try: - from ujson import dumps -except: - from json import dumps - -try: - from machine import reset # type: ignore -except ImportError: - pass - -try: - from collections import OrderedDict -except ImportError: - from ucollections import OrderedDict # type: ignore - -__version__ = "v1.23.0" -ENOENT = 2 -_MAX_CLASS_LEVEL = 2 # Max class nesting -LIBS = ["lib", "/lib", "/sd/lib", "/flash/lib", "."] - - -# our own logging module to avoid dependency on and interfering with logging module -class logging: - # DEBUG = 10 - INFO = 20 - WARNING = 30 - ERROR = 40 - level = INFO - prnt = print - - @staticmethod - def getLogger(name): - return logging() - - @classmethod - def basicConfig(cls, level): - cls.level = level - - # def debug(self, msg): - # if self.level <= logging.DEBUG: - # self.prnt("DEBUG :", msg) - - def info(self, msg): - if self.level <= logging.INFO: - self.prnt("INFO :", msg) - - def warning(self, msg): - if self.level <= logging.WARNING: - self.prnt("WARN :", msg) - - def error(self, msg): - if self.level <= logging.ERROR: - self.prnt("ERROR :", msg) - - -log = logging.getLogger("stubber") -logging.basicConfig(level=logging.INFO) -# logging.basicConfig(level=logging.DEBUG) - - +try:from ujson import dumps +except:from json import dumps +try:from machine import reset +except O:pass +try:from collections import OrderedDict as l +except O:from ucollections import OrderedDict as l +__version__='v1.24.0' +A3=2 +A4=2 +A5=['lib','/lib','/sd/lib','/flash/lib',J] +class L: + INFO=20;WARNING=30;ERROR=40;level=INFO;prnt=S + @staticmethod + def getLogger(name):return L() + @classmethod + def basicConfig(A,level):A.level=level + def info(A,msg): + if A.level<=L.INFO:A.prnt('INFO :',msg) + def warning(A,msg): + if A.level<=L.WARNING:A.prnt('WARN :',msg) + def error(A,msg): + if A.level<=L.ERROR:A.prnt('ERROR :',msg) +A=L.getLogger(t) +L.basicConfig(level=L.INFO) class Stubber: - "Generate stubs for modules in firmware" - - def __init__(self, path: str = None, firmware_id: str = None): # type: ignore - try: - if os.uname().release == "1.13.0" and os.uname().version < "v1.13-103": # type: ignore - raise NotImplementedError("MicroPython 1.13.0 cannot be stubbed") - except AttributeError: - pass # Allow testing on CPython 3.11 - self.info = _info() - log.info("Port: {}".format(self.info["port"])) - log.info("Board: {}".format(self.info["board"])) - gc.collect() - if firmware_id: - self._fwid = firmware_id.lower() - else: - if self.info["family"] == "micropython": - self._fwid = "{family}-v{version}-{port}-{board}".format(**self.info).rstrip("-") - else: - self._fwid = "{family}-v{version}-{port}".format(**self.info) - self._start_free = gc.mem_free() # type: ignore - - if path: - if path.endswith("/"): - path = path[:-1] - else: - path = get_root() - - self.path = "{}/stubs/{}".format(path, self.flat_fwid).replace("//", "/") - # log.debug(self.path) - try: - ensure_folder(path + "/") - except OSError: - log.error("error creating stub folder {}".format(path)) - self.problematic = [ - "upip", - "upysh", - "webrepl_setup", - "http_client", - "http_client_ssl", - "http_server", - "http_server_ssl", - ] - self.excluded = [ - "webrepl", - "_webrepl", - "port_diag", - "example_sub_led.py", - "example_pub_button.py", - ] - # there is no option to discover modules from micropython, list is read from an external file. - self.modules = [] # type: list[str] - self._json_name = None - self._json_first = False - - def get_obj_attributes(self, item_instance: object): - "extract information of the objects members and attributes" - # name_, repr_(value), type as text, item_instance - _result = [] - _errors = [] - # log.debug("get attributes {} {}".format(repr(item_instance), item_instance)) - for name in dir(item_instance): - if name.startswith("__") and not name in self.modules: - continue - # log.debug("get attribute {}".format(name)) - try: - val = getattr(item_instance, name) - # name , item_repr(value) , type as text, item_instance, order - # log.debug("attribute {}:{}".format(name, val)) - try: - type_text = repr(type(val)).split("'")[1] - except IndexError: - type_text = "" - if type_text in {"int", "float", "str", "bool", "tuple", "list", "dict"}: - order = 1 - elif type_text in {"function", "method"}: - order = 2 - elif type_text in ("class"): - order = 3 - else: - order = 4 - _result.append((name, repr(val), repr(type(val)), val, order)) - except AttributeError as e: - _errors.append("Couldn't get attribute '{}' from object '{}', Err: {}".format(name, item_instance, e)) - except MemoryError as e: - print("MemoryError: {}".format(e)) - sleep(1) - reset() - - # remove internal __ - # _result = sorted([i for i in _result if not (i[0].startswith("_"))], key=lambda x: x[4]) - _result = sorted([i for i in _result if not (i[0].startswith("__"))], key=lambda x: x[4]) - gc.collect() - return _result, _errors - - def add_modules(self, modules): - "Add additional modules to be exported" - self.modules = sorted(set(self.modules) | set(modules)) - - def create_all_stubs(self): - "Create stubs for all configured modules" - log.info("Start micropython-stubber {} on {}".format(__version__, self._fwid)) - self.report_start() - gc.collect() - for module_name in self.modules: - self.create_one_stub(module_name) - self.report_end() - log.info("Finally done") - - def create_one_stub(self, module_name: str): - if module_name in self.problematic: - log.warning("Skip module: {:<25} : Known problematic".format(module_name)) - return False - if module_name in self.excluded: - log.warning("Skip module: {:<25} : Excluded".format(module_name)) - return False - - file_name = "{}/{}.pyi".format(self.path, module_name.replace(".", "/")) - gc.collect() - result = False - try: - result = self.create_module_stub(module_name, file_name) - except OSError: - return False - gc.collect() - return result - - def create_module_stub(self, module_name: str, file_name: str = None) -> bool: # type: ignore - """Create a Stub of a single python module - - Args: - - module_name (str): name of the module to document. This module will be imported. - - file_name (Optional[str]): the 'path/filename.pyi' to write to. If omitted will be created based on the module name. - """ - if file_name is None: - fname = module_name.replace(".", "_") + ".pyi" - file_name = self.path + "/" + fname - else: - fname = file_name.split("/")[-1] - - if "/" in module_name: - # for nested modules - module_name = module_name.replace("/", ".") - - # import the module (as new_module) to examine it - new_module = None - try: - new_module = __import__(module_name, None, None, ("*")) - m1 = gc.mem_free() # type: ignore - log.info("Stub module: {:<25} to file: {:<70} mem:{:>5}".format(module_name, fname, m1)) - - except ImportError: - # log.debug("Skip module: {:<25} {:<79}".format(module_name, "Module not found.")) - return False - - # Start a new file - ensure_folder(file_name) - with open(file_name, "w") as fp: - info_ = str(self.info).replace("OrderedDict(", "").replace("})", "}") - s = '"""\nModule: \'{0}\' on {1}\n"""\n# MCU: {2}\n# Stubber: {3}\n'.format(module_name, self._fwid, info_, __version__) - fp.write(s) - fp.write("from __future__ import annotations\nfrom typing import Any, Generator\nfrom _typeshed import Incomplete\n\n") - self.write_object_stub(fp, new_module, module_name, "") - - self.report_add(module_name, file_name) - - if module_name not in {"os", "sys", "logging", "gc"}: - # try to unload the module unless we use it - try: - del new_module - except (OSError, KeyError): # lgtm [py/unreachable-statement] - log.warning("could not del new_module") - # do not try to delete from sys.modules - most times it does not work anyway - gc.collect() - return True - - def write_object_stub(self, fp, object_expr: object, obj_name: str, indent: str, in_class: int = 0): - "Write a module/object stub to an open file. Can be called recursive." - gc.collect() - if object_expr in self.problematic: - log.warning("SKIPPING problematic module:{}".format(object_expr)) - return - - # # log.debug("DUMP : {}".format(object_expr)) - items, errors = self.get_obj_attributes(object_expr) - - if errors: - log.error(errors) - - for item_name, item_repr, item_type_txt, item_instance, _ in items: - # name_, repr_(value), type as text, item_instance, order - if item_name in ["classmethod", "staticmethod", "BaseException", "Exception"]: - # do not create stubs for these primitives - continue - if item_name[0].isdigit(): - log.warning("NameError: invalid name {}".format(item_name)) - continue - # Class expansion only on first 3 levels (bit of a hack) - if ( - item_type_txt == "" - and len(indent) <= _MAX_CLASS_LEVEL * 4 - # and not obj_name.endswith(".Pin") - # avoid expansion of Pin.cpu / Pin.board to avoid crashes on most platforms - ): - # log.debug("{0}class {1}:".format(indent, item_name)) - superclass = "" - is_exception = ( - item_name.endswith("Exception") - or item_name.endswith("Error") - or item_name - in [ - "KeyboardInterrupt", - "StopIteration", - "SystemExit", - ] - ) - if is_exception: - superclass = "Exception" - s = "\n{}class {}({}):\n".format(indent, item_name, superclass) - # s += indent + " ''\n" - if is_exception: - s += indent + " ...\n" - fp.write(s) - continue - # write classdef - fp.write(s) - # first write the class literals and methods - # log.debug("# recursion over class {0}".format(item_name)) - self.write_object_stub( - fp, - item_instance, - "{0}.{1}".format(obj_name, item_name), - indent + " ", - in_class + 1, - ) - # end with the __init__ method to make sure that the literals are defined - # Add __init__ - s = indent + " def __init__(self, *argv, **kwargs) -> None:\n" - s += indent + " ...\n\n" - fp.write(s) - elif any(word in item_type_txt for word in ["method", "function", "closure"]): - # log.debug("# def {1} function/method/closure, type = '{0}'".format(item_type_txt, item_name)) - # module Function or class method - # will accept any number of params - # return type Any/Incomplete - ret = "Incomplete" - first = "" - # Self parameter only on class methods/functions - if in_class > 0: - first = "self, " - # class method - add function decoration - if "bound_method" in item_type_txt or "bound_method" in item_repr: - s = "{}@classmethod\n".format(indent) + "{}def {}(cls, *args, **kwargs) -> {}:\n".format(indent, item_name, ret) - else: - s = "{}def {}({}*args, **kwargs) -> {}:\n".format(indent, item_name, first, ret) - s += indent + " ...\n\n" - fp.write(s) - # log.debug("\n" + s) - elif item_type_txt == "": - # Skip imported modules - # fp.write("# import {}\n".format(item_name)) - pass - - elif item_type_txt.startswith("" - if " at " in item_repr: - item_repr = item_repr.split(" at ")[0] + " at ...>" - s = "{0}{1}: {2} ## {3} = {4}\n".format(indent, item_name, t, item_type_txt, item_repr) - fp.write(s) - # log.debug("\n" + s) - else: - # keep only the name - # log.debug("# all other, type = '{0}'".format(item_type_txt)) - fp.write("# all other, type = '{0}'\n".format(item_type_txt)) - - fp.write(indent + item_name + " # type: Incomplete\n") - - # del items - # del errors - # try: - # del item_name, item_repr, item_type_txt, item_instance # type: ignore - # except (OSError, KeyError, NameError): - # pass - - @property - def flat_fwid(self): - "Turn _fwid from 'v1.2.3' into '1_2_3' to be used in filename" - s = self._fwid - # path name restrictions - chars = " .()/\\:$" - for c in chars: - s = s.replace(c, "_") - return s - - def clean(self, path: str = None): # type: ignore - "Remove all files from the stub folder" - if path is None: - path = self.path - log.info("Clean/remove files in folder: {}".format(path)) - try: - os.stat(path) # TEMP workaround mpremote listdir bug - - items = os.listdir(path) - except (OSError, AttributeError): - # os.listdir fails on unix - return - for fn in items: - item = "{}/{}".format(path, fn) - try: - os.remove(item) - except OSError: - try: # folder - self.clean(item) - os.rmdir(item) - except OSError: - pass - - def report_start(self, filename: str = "modules.json"): - """Start a report of the modules that have been stubbed - "create json with list of exported modules""" - self._json_name = "{}/{}".format(self.path, filename) - self._json_first = True - ensure_folder(self._json_name) - log.info("Report file: {}".format(self._json_name)) - gc.collect() - try: - # write json by node to reduce memory requirements - with open(self._json_name, "w") as f: - f.write("{") - f.write(dumps({"firmware": self.info})[1:-1]) - f.write(",\n") - f.write(dumps({"stubber": {"version": __version__}, "stubtype": "firmware"})[1:-1]) - f.write(",\n") - f.write('"modules" :[\n') - - except OSError as e: - log.error("Failed to create the report.") - self._json_name = None - raise e - - def report_add(self, module_name: str, stub_file: str): - "Add a module to the report" - # write json by node to reduce memory requirements - if not self._json_name: - raise Exception("No report file") - try: - with open(self._json_name, "a") as f: - if not self._json_first: - f.write(",\n") - else: - self._json_first = False - line = '{{"module": "{}", "file": "{}"}}'.format(module_name, stub_file.replace("\\", "/")) - f.write(line) - - except OSError: - log.error("Failed to create the report.") - - def report_end(self): - if not self._json_name: - raise Exception("No report file") - with open(self._json_name, "a") as f: - f.write("\n]}") - # is used as sucess indicator - log.info("Path: {}".format(self.path)) - - -def ensure_folder(path: str): - "Create nested folders if needed" - i = start = 0 - while i != -1: - i = path.find("/", start) - if i != -1: - p = path[0] if i == 0 else path[:i] - # p = partial folder - try: - _ = os.stat(p) - except OSError as e: - # folder does not exist - if e.args[0] == ENOENT: - try: - os.mkdir(p) - except OSError as e2: - log.error("failed to create folder {}".format(p)) - raise e2 - # next level deep - start = i + 1 - - -def _build(s): - # extract build from sys.version or os.uname().version if available - # sys.version: 'MicroPython v1.23.0-preview.6.g3d0b6276f' - # sys.implementation.version: 'v1.13-103-gb137d064e' - if not s: - return "" - s = s.split(" on ", 1)[0] if " on " in s else s - if s.startswith("v"): - if not "-" in s: - return "" - b = s.split("-")[1] - return b - if not "-preview" in s: - return "" - b = s.split("-preview")[1].split(".")[1] - return b - - -def _info(): # type:() -> dict[str, str] - try: - fam = sys.implementation[0] # type: ignore - except TypeError: - # testing on CPython 3.11 - fam = sys.implementation.name - - info = OrderedDict( - { - "family": fam, - "version": "", - "build": "", - "ver": "", - "port": sys.platform, # port: esp32 / win32 / linux / stm32 - "board": "UNKNOWN", - "cpu": "", - "mpy": "", - "arch": "", - } - ) - # change port names to be consistent with the repo - if info["port"].startswith("pyb"): - info["port"] = "stm32" - elif info["port"] == "win32": - info["port"] = "windows" - elif info["port"] == "linux": - info["port"] = "unix" - try: - info["version"] = version_str(sys.implementation.version) # type: ignore - except AttributeError: - pass - try: - _machine = sys.implementation._machine if "_machine" in dir(sys.implementation) else os.uname().machine # type: ignore - # info["board"] = "with".join(_machine.split("with")[:-1]).strip() - info["board"] = _machine - info["cpu"] = _machine.split("with")[-1].strip() - info["mpy"] = ( - sys.implementation._mpy # type: ignore - if "_mpy" in dir(sys.implementation) - else sys.implementation.mpy if "mpy" in dir(sys.implementation) else "" # type: ignore - ) - except (AttributeError, IndexError): - pass - info["board"] = get_boardname() - - try: - if "uname" in dir(os): # old - # extract build from uname().version if available - info["build"] = _build(os.uname()[3]) # type: ignore - if not info["build"]: - # extract build from uname().release if available - info["build"] = _build(os.uname()[2]) # type: ignore - elif "version" in dir(sys): # new - # extract build from sys.version if available - info["build"] = _build(sys.version) - except (AttributeError, IndexError, TypeError): - pass - # avoid build hashes - # if info["build"] and len(info["build"]) > 5: - # info["build"] = "" - - if info["version"] == "" and sys.platform not in ("unix", "win32"): - try: - u = os.uname() # type: ignore - info["version"] = u.release - except (IndexError, AttributeError, TypeError): - pass - # detect families - for fam_name, mod_name, mod_thing in [ - ("pycopy", "pycopy", "const"), - ("pycom", "pycom", "FAT"), - ("ev3-pybricks", "pybricks.hubs", "EV3Brick"), - ]: - try: - _t = __import__(mod_name, None, None, (mod_thing)) - info["family"] = fam_name - del _t - break - except (ImportError, KeyError): - pass - - if info["family"] == "ev3-pybricks": - info["release"] = "2.0.0" - - if info["family"] == "micropython": - info["version"] - if ( - info["version"] - and info["version"].endswith(".0") - and info["version"] >= "1.10.0" # versions from 1.10.0 to 1.23.0 do not have a micro .0 - and info["version"] <= "1.19.9" - ): - # versions from 1.10.0 to 1.23.0 do not have a micro .0 - info["version"] = info["version"][:-2] - - # spell-checker: disable - if "mpy" in info and info["mpy"]: # mpy on some v1.11+ builds - sys_mpy = int(info["mpy"]) - # .mpy architecture - arch = [ - None, - "x86", - "x64", - "armv6", - "armv6m", - "armv7m", - "armv7em", - "armv7emsp", - "armv7emdp", - "xtensa", - "xtensawin", - ][sys_mpy >> 10] - if arch: - info["arch"] = arch - # .mpy version.minor - info["mpy"] = "v{}.{}".format(sys_mpy & 0xFF, sys_mpy >> 8 & 3) - if info["build"] and not info["version"].endswith("-preview"): - info["version"] = info["version"] + "-preview" - # simple to use version[-build] string - info["ver"] = f"{info['version']}-{info['build']}" if info["build"] else f"{info['version']}" - - return info - - -def version_str(version: tuple): # -> str: - v_str = ".".join([str(n) for n in version[:3]]) - if len(version) > 3 and version[3]: - v_str += "-" + version[3] - return v_str - - -def get_boardname() -> str: - "Read the board name from the boardname.py file that may have been created upfront" - try: - from boardname import BOARDNAME # type: ignore - - log.info("Found BOARDNAME: {}".format(BOARDNAME)) - except ImportError: - log.warning("BOARDNAME not found") - BOARDNAME = "" - return BOARDNAME - - -def get_root() -> str: # sourcery skip: use-assigned-variable - "Determine the root folder of the device" - try: - c = os.getcwd() - except (OSError, AttributeError): - # unix port - c = "." - r = c - for r in [c, "/sd", "/flash", "/", "."]: - try: - _ = os.stat(r) - break - except OSError: - continue - return r - - -def file_exists(filename: str): - try: - if os.stat(filename)[0] >> 14: - return True - return False - except OSError: - return False - - -def show_help(): - print("-p, --path path to store the stubs in, defaults to '.'") - sys.exit(1) - - -def read_path() -> str: - "get --path from cmdline. [unix/win]" - path = "" - if len(sys.argv) == 3: - cmd = (sys.argv[1]).lower() - if cmd in ("--path", "-p"): - path = sys.argv[2] - else: - show_help() - elif len(sys.argv) == 2: - show_help() - return path - - -def is_micropython() -> bool: - "runtime test to determine full or micropython" - # pylint: disable=unused-variable,eval-used - try: - # either test should fail on micropython - - # b) https://docs.micropython.org/en/latest/genrst/builtin_types.html#bytes-with-keywords-not-implemented - # Micropython: NotImplementedError - b = bytes("abc", encoding="utf8") # type: ignore # lgtm [py/unused-local-variable] - - # c) https://docs.micropython.org/en/latest/genrst/core_language.html#function-objects-do-not-have-the-module-attribute - # Micropython: AttributeError - c = is_micropython.__module__ # type: ignore # lgtm [py/unused-local-variable] - return False - except (NotImplementedError, AttributeError): - return True - - -SKIP_FILE = "modulelist.done" - - -def get_modules(skip=0): - # new - for p in LIBS: - fname = p + "/modulelist.txt" - if not file_exists(fname): - continue - try: - with open(fname) as f: - i = 0 - while True: - line = f.readline().strip() - if not line: - break - if len(line) > 0 and line[0] == "#": - continue - i += 1 - if i < skip: - continue - yield line - break - except OSError: - pass - - -def write_skip(done): - # write count of modules already processed to file - with open(SKIP_FILE, "w") as f: - f.write(str(done) + "\n") - - -def read_skip(): - # read count of modules already processed from file - done = 0 - try: - with open(SKIP_FILE) as f: - done = int(f.readline().strip()) - except OSError: - pass - return done - - + def __init__(B,path=E,firmware_id=E): + C=firmware_id + try: + if os.uname().release=='1.13.0'and os.uname().version<'v1.13-103':raise o('MicroPython 1.13.0 cannot be stubbed') + except I:pass + B.info=_info();A.info('Port: {}'.format(B.info[K]));A.info('Board: {}'.format(B.info[U]));F.collect() + if C:B._fwid=C.lower() + elif B.info[Q]==u:B._fwid='{family}-v{version}-{port}-{board}'.format(**B.info).rstrip(V) + else:B._fwid='{family}-v{version}-{port}'.format(**B.info) + B._start_free=F.mem_free() + if path: + if path.endswith(G):path=path[:-1] + else:path=get_root() + B.path='{}/stubs/{}'.format(path,B.flat_fwid).replace('//',G) + try:X(path+G) + except D:A.error('error creating stub folder {}'.format(path)) + B.problematic=['upip','upysh','webrepl_setup','http_client','http_client_ssl','http_server','http_server_ssl'];B.excluded=['webrepl','_webrepl','port_diag','example_sub_led.py','example_pub_button.py'];B.modules=[];B._json_name=E;B._json_first=H + def get_obj_attributes(L,item_instance): + H=item_instance;C=[];K=[] + for A in N(H): + if A.startswith('__')and not A in L.modules:continue + try: + D=getattr(H,A) + try:E=b(type(D)).split("'")[1] + except T:E=B + if E in{v,w,x,y,e,f,g}:G=1 + elif E in{z,A0}:G=2 + elif E in'class':G=3 + else:G=4 + C.append((A,b(D),b(type(D)),D,G)) + except I as J:K.append("Couldn't get attribute '{}' from object '{}', Err: {}".format(A,H,J)) + except p as J:S('MemoryError: {}'.format(J));sleep(1);reset() + C=q([A for A in C if not A[0].startswith('__')],key=lambda x:x[4]);F.collect();return C,K + def add_modules(A,modules):A.modules=q(set(A.modules)|set(modules)) + def create_all_stubs(B): + A.info('Start micropython-stubber {} on {}'.format(__version__,B._fwid));B.report_start();F.collect() + for C in B.modules:B.create_one_stub(C) + B.report_end();A.info('Finally done') + def create_one_stub(C,module_name): + B=module_name + if B in C.problematic:A.warning('Skip module: {:<25} : Known problematic'.format(B));return H + if B in C.excluded:A.warning('Skip module: {:<25} : Excluded'.format(B));return H + I='{}/{}.pyi'.format(C.path,B.replace(J,G));F.collect();E=H + try:E=C.create_module_stub(B,I) + except D:return H + F.collect();return E + def create_module_stub(K,module_name,file_name=E): + I=file_name;C=module_name + if I is E:L=C.replace(J,'_')+'.pyi';I=K.path+G+L + else:L=I.split(G)[-1] + if G in C:C=C.replace(G,J) + N=E + try:N=__import__(C,E,E,'*');Q=F.mem_free();A.info('Stub module: {:<25} to file: {:<70} mem:{:>5}'.format(C,L,Q)) + except O:return H + X(I) + with M(I,h)as P:S=c(K.info).replace('OrderedDict(',B).replace('})','}');T='"""\nModule: \'{0}\' on {1}\n"""\n# MCU: {2}\n# Stubber: {3}\n'.format(C,K._fwid,S,__version__);P.write(T);P.write('from __future__ import annotations\nfrom typing import Any, Generator\nfrom _typeshed import Incomplete\n\n');K.write_object_stub(P,N,C,B) + K.report_add(C,I) + if C not in{'os','sys','logging','gc'}: + try:del N + except(D,r):A.warning('could not del new_module') + F.collect();return R + def write_object_stub(L,fp,object_expr,obj_name,indent,in_class=0): + Z=' at ...>';Y='generator';X='{0}{1}: {3} = {2}\n';W='bound_method';V='Incomplete';O=in_class;N='Exception';M=object_expr;K=' at ';J=fp;D=indent;F.collect() + if M in L.problematic:A.warning('SKIPPING problematic module:{}'.format(M));return + a,Q=L.get_obj_attributes(M) + if Q:A.error(Q) + for(E,H,I,b,d)in a: + if E in['classmethod','staticmethod','BaseException',N]:continue + if E[0].isdigit():A.warning('NameError: invalid name {}'.format(E));continue + if I==""and P(D)<=A4*4: + R=B;S=E.endswith(N)or E.endswith('Error')or E in['KeyboardInterrupt','StopIteration','SystemExit'] + if S:R=N + C='\n{}class {}({}):\n'.format(D,E,R) + if S:C+=D+' ...\n';J.write(C);continue + J.write(C);L.write_object_stub(J,b,'{0}.{1}'.format(obj_name,E),D+' ',O+1);C=D+' def __init__(self, *argv, **kwargs) -> None:\n';C+=D+' ...\n\n';J.write(C) + elif any(A in I for A in[A0,z,'closure']): + T=V;U=B + if O>0:U='self, ' + if W in I or W in H:C='{}@classmethod\n'.format(D)+'{}def {}(cls, *args, **kwargs) -> {}:\n'.format(D,E,T) + else:C='{}def {}({}*args, **kwargs) -> {}:\n'.format(D,E,U,T) + C+=D+' ...\n\n';J.write(C) + elif I=="":0 + elif I.startswith("='1.10.0'and A[C]<='1.19.9':A[C]=A[C][:-2] + if F in A and A[F]: + G=int(A[F]);L=[E,'x86','x64','armv6','armv6m','armv7m','armv7em','armv7emsp','armv7emdp','xtensa','xtensawin'][G>>10] + if L:A[R]=L + A[F]='v{}.{}'.format(G&255,G>>8&3) + if A[D]and not A[C].endswith(W):A[C]=A[C]+W + A[M]=f"{A[C]}-{A[D]}"if A[D]else f"{A[C]}";return A +def A6(version): + A=version;B=J.join([c(A)for A in A[:3]]) + if P(A)>3 and A[3]:B+=V+A[3] + return B +def A7(): + try:from boardname import BOARDNAME as C;A.info('Found BOARDNAME: {}'.format(C)) + except O:A.warning('BOARDNAME not found');C=B + return C +def get_root(): + try:A=os.getcwd() + except(D,I):A=J + B=A + for B in['/sd','/flash',G,A,J]: + try:C=os.stat(B);break + except D:continue + return B +def Z(filename): + try: + if os.stat(filename)[0]>>14:return R + return H + except D:return H +def m():S("-p, --path path to store the stubs in, defaults to '.'");sys.exit(1) +def read_path(): + path=B + if P(sys.argv)==3: + A=sys.argv[1].lower() + if A in('--path','-p'):path=sys.argv[2] + else:m() + elif P(sys.argv)==2:m() + return path +def n(): + try:A=bytes('abc',encoding='utf8');B=n.__module__;return H + except(o,I):return R +a='modulelist.done' +def A8(skip=0): + for E in A5: + B=E+'/modulelist.txt' + if not Z(B):continue + try: + with M(B)as F: + C=0 + while R: + A=F.readline().strip() + if not A:break + if P(A)>0 and A[0]=='#':continue + C+=1 + if Ce|qzh=Q*Gj^e zVX@WMo~?OoHm>YeZB;6jO8(_lDZpmN9?#Ai+v9ocE0t7b*PF2ZHGh(9Hsi{lTrK!Jg>xxN};$oTkzzTQLQPh6c@4ygy$AB@nSNY zL943QIG4)Ciiix7`5MYPtK?B-yAc^zR=q2$h+9JB0GUyb;*MNixsp_t5Z8f>v)Nca zflPC;bTYM!47qH+h&T`0S93+l7wE|qmGf~_nJu8I!g2u_3n@j(Aww~lR**5Vn9c!h z@$~{Q8rZinuN0Ibs!7M<3(1Uvgj4y1l2;OPGG0VNJex`>OyUBnTYPa=bEV7U^Lsi` zRVq1)3|{(O<1HlE!0Me##R>~-%)N~Gd8PPrc77fd6lPnM=+iV@kQAq>y2B z^28}rGgY>Mn=dYaPz%`<=&594vnd5}=MiZ!6pCQ46=V8xBAG`qsh!%78!HP@oXBI=mUIUSj;4^BI8mr)9pisSU$dhs^YmtR0VcJRcYWb z&Mqe5%En|mmr~M71}>xaG-P66I-E;>7_Q%NJfJSgOLhlw0A zT`ek^LJaZR6J$oFD=VuWh&Bki4tP}3zu^EP;mYA�O6epOGhrCypbY#hs=KGjGjO zET2hc<`D+xM)TQh5t(2VUrL}V2m@r&LI82EATEsz%GG2M@sJjYXf6hp01wPxK_tp$ zP*rR;j5cxFvM6n;$oEttfIXZb#8&Hbz z_?a`O&Y&9hfVo5+(G3paA^5wxJGwf%5k3tf^ow9OK1frO4UN&crDOuBW}H^i(Yd?= zd8LV|O?XI;VwtC+((47KbIBYeW^TE#fP`E=3qhZT_=`hiDYGDR3PNgU#51iE$ru=4 zxf)L`CX@sua5k}+QVMVpv%_36Unn96bxwBn^=PbE%qM3T0hCZ>G>W(u1V)S%3TT;3 z39&>Xy0cv@n=Y10G1C zhigzx3UGjhjTkG69*^f3MTd-%j};-A>t?fy8IVOoOY11a1Wm@Gf<_ILACYRcZG;RP zkF(s5%wNVLeBc-(s#)oTNbXt%Fn|wuJe4gh<`rZrD5<%25%D{mMuZ2L?qUlfI-;+9 z^&+ZlZA0X;TF=krvu{9-03ueMhVfO`pQZy0)=oo0 z08p(UOe3zioP$XWaTidP@!~3k2}C`M4eJ2iP8B-_f}~>U*+dMCFhH$vHJ3jI0q=vq zF8J$2+#85nM%-1zEg}wpzJR7Uxc4ykEi}XBP?XCe?lR(DM_dwd3y7OX+#KQ*l;#qM ziz8Lf%_8m`;-(Q7L1FGJB1_y9;?5v0jL13eG@9T}AyUsxB9i7N5I2svF*MALA})lu zlZZQxVw{Y)5yS-%cLH%K2(M_l(m)th4tK+!AO3m}H;lYJ7(zFviu>C(JvMk zlroD4=}qO_@UViZuhpj1iyo$k-jc~iV~fQs3wJ2vp5oOa(l^X~^VB&gX-b}Ah2ErG z>F$66LP5WP^!s*(o(1R`klu2FCW5$&zbta}mfg9S$ri;q%7gSrI&$q|M+Zel2yylR zMGBBl3e$sXUJ#R+b}^yM#THY=0#&rd0}#OJtF( zy)tx*Ei0=nnjf^tXM}bUz)*{i+6g6{%`Y=>)F^i5B{5BHoMSfb&`e6BkTy*$7MWX8 z%c2&|o+-%DvLE4;{sCXlD#cFv=@-W{*(K)F-3p~|{(mFdgjwxznEkJe;hESwQ z$mYGBt0EN4{+0e?Jv2vNXhmC*zSnNI8z)$m>j%v{!4_13u2mylki?0R2%O?ug(1BN z@(`xot45@sXR#ZN&Mg+9B1EI2hD;(0GuGu5jEn_Pn+8L9c{sD&F76fpjU!5dy|4ga zQD*w8Mj7Fzx;XV5%g%(7qN!0XtVqv;#2_q_NgQN?B7M`;_~_}=&~(r&*|F%3iKuTH zCIL3f4ozmRK=#1tKw^%o*{NexsFq_$Z-zEbD{U*Qtt+c-{UA~o^&4cq2!NbP0vxw$ z1<^%2uy)bqx(tPDzR)Ii91|x2m+78;bPxT|$_n$^mDM43u2z|W;#^s!XTmk{Q~^$* zM||V3l~sC_w9B}%`un+dE3y_HRG0m`_VTTYl0;4Br_QYZ1|3|yyVf9y(6@+LfbV>} zNUZ`(EL32lRg@U1Uwpx5NH31iX40F7)B(hzu}HzPj0NB=a6;`F)@beoDp2;>%Q$Bj z`(K5##g&yZ#ojO4S61!qqMaU9o~^E;zf84%$myEd$KhyhcG8bFZFa(cl;U7i7&)39 zKA!&g!c$9VS_-vh4%_1ZzdxGDVRx7Ad6;lMIcLNa#bM9 zX7YwWRv*4_B3vV=I$SHLoLQ|9)Jn5nQ1xcDN>KM;ET{%- z7Sz3%7gVEJtrk?1S%qCSX9TqtTLcxGRaocEDvYgWb-$nrX7zxe)?url)?=7AnAL-V z+IU(}4`D%2o5F%>GpnMY9>&0D$8~}#mBI(>1=RtM2B87I4+;lMxY4CMc&M>aXq*Yv zlyDQwY>iDq)65v2(Was{)m^0Phhg2`cvv_*Ggf`htXiMRBQs;LR9nIlEIAq_L2aHH ztJBs_!x5C+Tqf%-VyB=wRY7fmzgFCWTX7q9nbih2n4|5i4`H{T6WnIEwcSke0iB?_ zVBCQ{X1B!~P|?g;pAL5dOQ(+${Jsj|sIO8O^67=NuS&@J_6S9vLAdJMD=hnr!iuk2 zxF&%=6D5~!svBHU;oB#WDqoF2_WEiC0;YE3uBRg>%-8%#&Y7=Dm44mGLTJBPby$7& zKSKfC3>|g{5L1_&EURlKMn9Sf$MMax2JC*fzh`t*mfV1M$F;3 z>4&*zCEXEHr%Lel(p?(0+ihOSHt4ancD761&HVx2#-osvZ?H}UkmVdE^-tyL^6UU6 z4ZoB_JXw*jU#CEz@@iw*bNrAWt<~ju)n(0Na?skpW`Rk4B%lLdm#K|qs&R+vuo4U* za9bX~ZCwq(esUQ#}IH1X=*fR3@9miVt$D20c3A~tr2 zxGqnvTQBfxQ$Q!5Tn}IOaFMOxalYtBTav}vzrJQ6hXb6I*fEhP7Y7GahfKVG9cIt{ zx|y*CQ0?$D`3w`iPqM-$rU|4ZCJs!RrTvm19gymzdiNgK?Zl)7lU7XHqz37rTMs0c zn=0hyRU15Nc=ZrG+Qaeh7eC;Aq{FTHORu!L{ZgyV-ZI$fw%c4b$=1C7(2X9s(PLf} zHvGEi_?NnmH?7Ao@qi{{n;^G)dn6ca4ZW@7)t-$_KldbbfLHhMYT!LTguZnU6K_CA zBA<-af(E8%@=4G@`UJ#&pMQxr@g&ESEU$9B3J0K$J=?NOJ`KVm$?zoI!NFYpG&u1- zCY><6@o6x4^V8c_(zOYfzzr{4_1;~V9$Y&%p#{OKpN*RD0HXv>-rTqssDQO___Nl% z7suS^c(VLVj(;{<&#N`kA#4A=0LVJSHxl}Nm}b1jsk<2b?lqn)`Os~@4ig__v#NW< zJj>$bj*E+Ps$tYb7D!)d0Sp`+=eO2Nk+O+Ky4JncV0-+M*+h~gS6W!R8HuZ{E=;;r z7jc)8a5hh7s2M>QGPCa2{nk(8$sLZr**eSj4+*kI27<(M51|b3)w*%Z` z76K5&Gz1RCAp~|MzZ3sK?uX_838?jIuX?1kcad zH}Y%XReBpHy#WrBBhNpkBG5e9eEuj1i91N;&|Qyw49`2;@`T0@soDTCz!6VE?Y!!_ z10(o{NuR&+2@?cz^%Kp`c5DBg&G%WzFqxtFeI>IWLID)0yUmm9e(vPtr@X2MK!8{$ zb_udqDkpM3CPxF@XOaUB0|^h^1J?yAKfh}wdp-b9(5KX_d2!(GdmxS!sGJF3xCrJN zyaVQ%xq}<SQDqE{G9N@{Ki+d(dfEd(YPB`U7Yw~Js{C4HvH>b&f zTkTW()uZZwI#~LS&C}Q6@pTU#vAJ42M{Ty|qpdERv$NOL?tx@K=69c!y1RYuCQM#> zg2~V)Qp=~941b16@bk@|U^4R4jh|s6|9t%ycbs_Fbw2{#Aauf-D6Q81AFnRxnwl}6R$cN4Yk{b@i4vXVJpu$-X#B+{%2gYRL`4`UmAA^e= z^&oHX@2>5RL9KxwJN9ETY3;ua@^F;>)bsn~c|bqoz*75jI0w#f zL7t}p-7q=ru6T`Nr2L!G2Tn*H$$9X8=~ptCA?!SOueoV^0XYQ6SusRy)1;M{2z^EdI)|{(iTTZuE;1p11F_{J`JOF;V zS?8ghorfHak@Dt$FF6`9IgiNiaJJwj6adzWn$h{v zyynq5B>ruNMq9zo_4qr6cPt_?sdiFb`rCGIpsU#x8H73x&~=<5)fSEBycF1};2{fi zGXaX%@FcIn;Nch#Mm!9?49)W60NRk zWb*BuQBynD4w>xaRr@SY^0OP5#D6chbOg2mT8_17`b8g)?q>kQlN79gxvBVflyLZQ zYvn~yJREbt;&k2{y?`%M{-?;s2 zcbm2#vcQ6K+JP)=Fqzj%ZW(0X!EfKu zTkF^VS^l@udI|DutrQ8KSPQR%2OfotH1ci-bdSeQX~I4!eLOm_Y3VIRc(vuJoMRkE zfMaINp>bSzGRiYMOM1XRCdGSTwGNul(Q zQj4$6-QmUqTWcdSpiX>!ZJWN_46c&^2XYOsJy-*LdI{j^JT%s8+Zq=zur`}S9&W^W z)$ldCfi{E7uq~f5j*Y7)KJKW`UJ8ehW zZLYQ+n_a4UfQPqm@F5;~gyqNh_{aFf6MXU$9QqWGeiquxAGC~>BA>IItb8Vq%}|16 z{BzKfSDV}Se!#1E7PMhut4jCi`2AU6dYM=2XYmBD8Y$^L`gNCnZ9-80W4Bx@vq?!PyU0ldGlX*ziR?*Af&f+L{8{kzj+ z7~%m+fr&yC0~bE)N9^p-1cpXZ;2Wp_3V&3)`bGrAy*GXTUS#Cd4o%f)!B;>Hb`{+* z0jmcsRJnW8!J#or`5s=abXAnEqH05gN>AlHu)cg7+Hh!)=D;#c%b)$oa!#`h-E3lV zezkdH1D|(Qtgqu4SH+sN2fyN~a92dfdpj$B{tG7#9fIEQ#{eJj4?2rVr}-l|3QxD1 zha%8Gzlqv^Z%x8b=F=yFBoY3(O!?De}E9Wx%pp048{)q3^gazTkx8z9rE2Oe3wI z2d!@qis$h+>+1NGTXl{Ox3|Sll>pO0Fn=4Y_f(G25#Sp92C=m+Rd36ql%Pf)z>fyY z@Om0NyUVRUl}~E4p|$vpkZibiOFR}j$dd@ZjtRnqzOp{xuUQBO1_v3zAY`T7TTp}4 z((VGPB$($H4;By~+ThSn}~EEH8j`n|>WMv*Vkk2qyZc(9lobAzwVcv-V3Ej%?1;i$@GY zXH{A%U+htWe*_JRdTG!^s?@GqV3|6eBzX3!Wnl%8zHZT%aRcq#V0Sov;G9t7}_9e;i51 zIEsUgFuMuc*`e)DxBJrJp%44gsbnA_JKZb>LXz$_eb|RAXlLqnnqIE}KX7`IS5} z-$j3$y7CESVCkAm#qtZvSnEbjsqFlGGBc0Z zdATqOV>ySKsK9X;SmUvLQVL`CVqi4mTr8bTt)Ql>axPEF2KBsp zm?ONHiWTOvxir!*W^-W1nembFiF4z?l#S&Qs9suJLiK5Ii$0c<7Et}-N*sJrNcVb> zVL6$BPZN9+*=2A`Dw$cjhV)CBN8nLxOesO1* zSVYEa1+a4rvFaB@MaHYeRd;a}8H%f&@X^6PYt1y#d;u&TJ^)^hD*7vuv;K*JDRF#Y zY!I<8sCvcZP0O)dhDHXadve)q0U2Q=EraPGn2=EoBxIdSrsSx6EtxOm5et#999@u8 z5Z6E|AQmzp5nYUdfxyi3R}qP}B=ga9Qp#l)R|*T@wE9?FLRij7*#x~#zf_nzjykRM z)^s+pl#=s^T-OT7vYbm6ynjcbAGn&o7i4e=Esg^;=QrjwL5)e7L3`7nMd5-HtP3H!t#)rqxr~^td z3{Fi=Ora*_19O3Tm!=*IIoQ+N+0)&N@FYmm$AJK>pGKZCG(_i?lL=Hd;k2BN&gEoC zZ&g}#!a|l7YCLtit}ZakBIs>cT3pF5AnRf-3z?RNWRM_ANu$g76AR2CAq+_hRh zNg`w)o?FT&kb{hA8Jw3uVDDHyk5md;lnzM7G+ZDvxS@ zlU`YB)UCE6?JD9`UxQo#aVp2QU*H-<8q2MLVKQJCRFGt5{tD*cKeyX$KuyJNNP?bK zq^BhCYbs082w8?9!YGOq066k;YOaGr&GGC~2BcPXVYkmPAbd*Ei*q8~g-b~1YNhy? zk#n&E02g~^XQ=051rA~Q3zwgUk=xbUb+OL|zzPXL(XOm9Ik@-z*=4cV8GU}smEDZg4iQr>T^xm*Pw1vr$UZf+4-YtE*+AxtAuSuz3y z1MDN5%tX~#TV|=g5)TD5Yx^F$aD>6Ji_WyUo;CB6C zI;W|T)d1N!7($U|vNAu`y~;s3>?`)2K1$_!so!-W<`~cOhB2jv^?~NyU<;~1&#Hkg z2;5j;22Sy;!jN7BI>NMf)qt3JC3d6HxupW_OQW2MaGVlmN<*19C@cWRG#F~j1DTZ$ zZU^gCjwr?J`~u)cjp;>IF~CjD67`&toe4QbQ=?WA5p#$_?<8~&G$FQ)w`~pTh6CdO zvo+r(Ggl!|;2rPjGN z+Ie+wZEaVe_RQy7xz5wvI6yevvzzXr|Iy+J^F77Ye&t-XC<4V%T%~8iHGubU3O(Xm zhZR@pQNj*marO6e?UYtE5I`40JyS>9Q>HFSlZ#QC4n`NxW+Ag0;wuF?mdnK;VHi3F z;AFx3;CRKq+^dSyDctH3^ku~8Xej_@NL(lp28O9u(*-V|?5nshtH)5K` zv$ctG23%S!)=uF2IKH^bcW^wtx;9%~MStq;ct=y(?{GLq`H2aBHo(tL*lo5f_ui5A z4EN)kYt}V(?d`Q)YsNLxT0^3Lt!a&w-)&A@UTa+IcDwktuuuvg)LOOhTW76j)$|!QyqrnG(yoF*y5iYmeal4VaLcp6kSXm&V%jt>XuO($ z95kD>mRI;Y$ft?G=#USoO7_*1G`;0Tk+6hs8ui@XTRy>NvkfJ=_w)%a!NG~vH}PI8 zng5~nz@J$O^AjuCWjbKpZz2m;QfDG3JjkoDT217*2QITVgAOs!Ar3m&!xD48L2vCT zoo4rXk+gWg*i7EqU-DNg&HKYrS>J|Zq)6T_4YyUy`&qEYm*PmpLh3NlRef3zsf^oj zTwxh&S6K+N!&Co)$FA^%w|RE$@aR>Z@1^wKgSRg9-}2sc$=prDP4>N>_ttJ1-nG8B z@1{xB@gV3J4!3Eid%?O59&pnk(1mn@GQndekM1v`4x}gx2A~^Zc}D z4vGpNOmh5!!xnU~br#Ww%t1^H&&1i-ue-G~8~#C7@}dpFVsTU} zX2SY_+l+|?n6#DVVz7}tT*XJWyqZYp0O<3^b8$)$*e>ja9g6&riJ0ug#41>YeL}Oa zUpUad3vS+rNi!zR>G#{?w(v6lw>KmFJ@L>F|D*EC`1zjt4#vHo`K5 z{u*fFtDKrk{_nrTmbD(V?$uz@0oh#EJffaeV&ra{R??RB!$xwE^p@^}k)tE*Mzu6k zGf|+Y+GX)~NS94Ua;dz#bicATBbB?`SkeiGZz=thgR|Lk9knCXr4DTTZ(bTtEn(^A z@qq)xO^T(DxT6l2tIeszt8m!jV990J(d5&DN)^j0MC-Oh^q}ZS;|Aabf*^_bdts!d z3^V}*a0TGUyO(F%2qML@uJoy^i+6STkGgn%+U}x(xNlPoQ|7pEWIN6#CAx5MXMumQ zfJqn4o??{-uM)dH?T&dS9|s%Z`tItwPy0BuTaDtu$fN}B-xm0;^vCDFXBsEnRGczX z`ttH+d-q6a=nBtwxQd+YXn(ca>6#dx;O!k_uJ!Ogh!<*ikshBG6VKLTxE>Pa?$#rJ zXdU7WlI;4-V|=8#DUK+tN3g}G-3UJkf&mw+;V>q>Ufq*gc7CiHMgW!W-dAEo5fm!j zwxEZ>^I*Q^b$r#UJrjD$5&^OwLYtTc8+O(5){DtepY{{M4hK=+d;mW3={|kmvJ9aW zfsf!&oJD-^->bqdT_k+*5*X(gHBO|8>#z>*#oA8Y=C8!dL7hvdW<5*ZY|}m$#}xm? z1t*;GlJTabzcBvi-Ve0I2iB`E?<(ud4Q0daM$YBxijN4xV^e%vm!ETG`vqt^kEAaP zwvga*2Il8l?Q@*n*;eegiT1&+vmLI`e4wK>FyD3Ne16_#f79;la(20s{p03sN3DM& zHe43Rx`IJr36wYl<8JNKPd*TbsX6T*P?e)2>$+~{)6bmdzy8GoOpar60+T*WPPXed zMZf>Z1IQ9`%7?bYtyRfF*y*pgn}xP#;vW*0YaHpK~{mmc$> z%>>8z|AYY5yD47jsKXZkQsbC}09@e%rnAQ#tjcX;ZKfG@$8SoobN|n&hHxnv2W2Kcq`*Gz)0Ac~nb`X5|E3DZUOr*l_^-i0IBs#+ z%}M~l?B0Vd;lvho%rA;zNkc9_>c`}D(o1@8ho-C3(<2R!*6nC>KH@(L&Cg^68Vgdq zeVZG!**j^jZD2C_Xgxa8^qA)RT}+W-!{1$%ZsA+zj<=z`xcy_!ZUdz27`5A5`Dxxc zT?Hf&0Xa6*{O{X_w4fQ93Z6nId`TDvk3uX(E@&xeCJq9ALI%QZ;$!>{MGc?!2^4E! zo&xViLTxI{#UnwsVtJdA=-RZhMjI0-hxmVbJuLme^-p!(t56N{xBs%g)9&hV z`8!*Ww;r~&F1Oj}4HR8zOK^RP7H;-%#e7`>B#P%J>GE~8nW@#J;38lZ5EZn#{Ak^> zjLBJ$0tW1^4h=vTCNpubhR`lVrDHO?!=UYee7lT$<9HuL40!k4@8K0r!5+Y{kf17c z;qkCZNqzy6GC~`TyK*@E*j0B4G=-Xj{zdB|#}t$|-hSF|ckyn=h`kp&tLp)1-A)Rp zp>+!eYQmHAfVCcgcJfMKQak$B#lOguwa2?sAWQW^iX^Q{kfP(AkoijjDv*FA?382#c25;@!)Cjw{-(J9_@j5YOA}cDob)EpQ#K zR`{PkFYr-2{5`}M?GS?eX!nq3w5Lnz@8z9sT>*~gNBK58@8}q89cs06j*ix3+8tUh zHQ0qguV>`&V6cJJnY&9f50xZLJr_d}N-+041bta!M?(dB;@Cyw)rGzE=V%-leE3)# zAIB#sp^yHYq(7%1lsBr-{e!j;q+$@ChS{t?PHFf%&w$Xc5W)&!fD-%)p+AV(i^|2l zUQHGE&VJ*K5lmu;+YDXzYBu2^LM06NgWzcTSZRE;Ud1P7X>T$}dlSo$4^?sBEI#wU zHl6XG$0z?6^`zgAT~&N?HiRJ_($GdzBvMd>eccOZotO=GgMmd zEc}}ZOm0)lHLCwL+^gJ0_l(1;&a7zXo%Q#J%(a_Xl4`4~T?UHJVAnG-3!FZIb}BO1 zMN#tcU2{;e3*DDhgnY42V1#;MS9@J_q^rB`$;VHFR%pcThr{oCb)P^pYsrk z1zV%FhDTA(zXuj)1pPB{2oG0r5cE*rU{|Rm&@}bVh*#(@GzFvJ&nO+^vA+|65eDO5 zieq#TrsWa_v-l+RgrAkbk~89?5=)NIkyrC+7*F6y9L7_48lS~8cov_-=i3_}-1>Uv zvk%3=53BgpERH~X!jtR2eemwrH-78WQg=|Zis$GRAOPe=U_`msy+tom7ANs*09C+1 zXFjbzgaJwD+y{O+I$M=)*iJNE?7g$r)76SCmP;N~3Eu!|z3@DR%9N{kH8*}Oj#qBX zh+u$D_-=g#38^8I1Im-*&YJS%XarsXo(}NV=#|!*z3l6EzR&R^kv2!LrG%sKH<`;V z(TBA+Km%Zz0wJMhYVhacWUaY00ODX5O{|LaU6g2%?)-@3+eRHc6wWahWMZ8q;X@CV z(AX}A@S3wIJ2om<#&Z~Y?RF+Q!fgb113RswkNT&H^7ezmHx%i&Y2bYSp{i8Ac9fkb z`8z-1JNZ$y>VjCMnIC*D`llp#BYg9{5SB#s;Rf}%Bj=ShFOKh4?g9W-hSID@lz5#E3g*|ho14G@zy2TME6!4z!{pxPb(UBI0q zSMPl3v^#memFL<7-UH~!+b3BfMMq?iWcSu1b{-xV@P6(J4$&8eS97NCaS4i9-iIhk ze0(3)5+L1uuLj!6(0ypP3eTW<9=}JvdUCJw1q=iCp)cCqf3{3(-^&e#|Hsf>l!LDt zm&mm{Tb*z|OJt=hFwqi6pE2;Hy+->k*cz5@oPVIjD|h~b=i4s|rH8@8>JE^}1mSh0 zx-FDf^YGhORir=A7rbv(w1X~T^p-xw2OJ^$IQ-2fH@v{vf-d;uW8*`19`2_AERL!@ zR}2WnMxo&xz{vpP)D$s|nf0|wKBBkkCHy44VU2ne5 z=I+wJN_d_G4bTuE+5?14;1PJ;55v>g0Q+g7sP#s7$yblrCD;-18)+C}7{NCBJ`PL& E12A8)X8-^I diff --git a/mip/v6/createstubs_mem.py b/mip/v6/createstubs_mem.py index ebe043c3..db59c6fd 100644 --- a/mip/v6/createstubs_mem.py +++ b/mip/v6/createstubs_mem.py @@ -9,7 +9,7 @@ - cross compilation, using mpy-cross, to avoid the compilation step on the micropython device -This variant was generated from createstubs.py by micropython-stubber v1.23.0 +This variant was generated from createstubs.py by micropython-stubber v1.24.0 """ # Copyright (c) 2019-2024 Jos Verlinde @@ -34,7 +34,7 @@ except ImportError: from ucollections import OrderedDict # type: ignore -__version__ = "v1.23.0" +__version__ = "v1.24.0" ENOENT = 2 _MAX_CLASS_LEVEL = 2 # Max class nesting LIBS = ["lib", "/lib", "/sd/lib", "/flash/lib", "."] @@ -492,7 +492,7 @@ def ensure_folder(path: str): def _build(s): # extract build from sys.version or os.uname().version if available - # sys.version: 'MicroPython v1.23.0-preview.6.g3d0b6276f' + # sys.version: 'MicroPython v1.24.0-preview.6.g3d0b6276f' # sys.implementation.version: 'v1.13-103-gb137d064e' if not s: return "" @@ -597,10 +597,10 @@ def _info(): # type:() -> dict[str, str] if ( info["version"] and info["version"].endswith(".0") - and info["version"] >= "1.10.0" # versions from 1.10.0 to 1.23.0 do not have a micro .0 + and info["version"] >= "1.10.0" # versions from 1.10.0 to 1.24.0 do not have a micro .0 and info["version"] <= "1.19.9" ): - # versions from 1.10.0 to 1.23.0 do not have a micro .0 + # versions from 1.10.0 to 1.24.0 do not have a micro .0 info["version"] = info["version"][:-2] # spell-checker: disable @@ -659,7 +659,7 @@ def get_root() -> str: # sourcery skip: use-assigned-variable # unix port c = "." r = c - for r in [c, "/sd", "/flash", "/", "."]: + for r in ["/sd", "/flash", "/", c, "."]: try: _ = os.stat(r) break diff --git a/mip/v6/createstubs_mem_min.py b/mip/v6/createstubs_mem_min.py index ebe043c3..dee8c794 100644 --- a/mip/v6/createstubs_mem_min.py +++ b/mip/v6/createstubs_mem_min.py @@ -1,766 +1,307 @@ -"""Create stubs for (all) modules on a MicroPython board. - - This variant of the createstubs.py script is optimised for use on low-memory devices, and reads the list of modules from a text file - `modulelist.txt` in the root or `libs` folder that should be uploaded to the device. - If that cannot be found then only a single module (micropython) is stubbed. - In order to run this on low-memory devices two additional steps are recommended: - - minifification, using python-minifier - to reduce overall size, and remove logging overhead. - - cross compilation, using mpy-cross, - to avoid the compilation step on the micropython device - -This variant was generated from createstubs.py by micropython-stubber v1.23.0 -""" - -# Copyright (c) 2019-2024 Jos Verlinde - -import gc -import os -import sys +x='No report file' +w='Failed to create the report.' +v='{}/{}' +u='method' +t='function' +s='bool' +r='str' +q='float' +p='int' +o='stubber' +n=Exception +m=KeyError +l=sorted +k=NotImplementedError +f=',\n' +e='dict' +d='list' +c='tuple' +b='micropython' +a=TypeError +Z=repr +W='-preview' +V='-' +U='board' +T=IndexError +S=print +R=True +Q='family' +P=len +O=open +N=ImportError +M=dir +K='port' +J='.' +I=AttributeError +H=False +G='/' +F=OSError +E=None +C='version' +B='' +import gc as D,os,sys from time import sleep - -try: - from ujson import dumps -except: - from json import dumps - -try: - from machine import reset # type: ignore -except ImportError: - pass - -try: - from collections import OrderedDict -except ImportError: - from ucollections import OrderedDict # type: ignore - -__version__ = "v1.23.0" -ENOENT = 2 -_MAX_CLASS_LEVEL = 2 # Max class nesting -LIBS = ["lib", "/lib", "/sd/lib", "/flash/lib", "."] - - -# our own logging module to avoid dependency on and interfering with logging module -class logging: - # DEBUG = 10 - INFO = 20 - WARNING = 30 - ERROR = 40 - level = INFO - prnt = print - - @staticmethod - def getLogger(name): - return logging() - - @classmethod - def basicConfig(cls, level): - cls.level = level - - # def debug(self, msg): - # if self.level <= logging.DEBUG: - # self.prnt("DEBUG :", msg) - - def info(self, msg): - if self.level <= logging.INFO: - self.prnt("INFO :", msg) - - def warning(self, msg): - if self.level <= logging.WARNING: - self.prnt("WARN :", msg) - - def error(self, msg): - if self.level <= logging.ERROR: - self.prnt("ERROR :", msg) - - -log = logging.getLogger("stubber") -logging.basicConfig(level=logging.INFO) -# logging.basicConfig(level=logging.DEBUG) - - +try:from ujson import dumps +except:from json import dumps +try:from machine import reset +except N:pass +try:from collections import OrderedDict as g +except N:from ucollections import OrderedDict as g +__version__='v1.24.0' +y=2 +z=2 +A0=['lib','/lib','/sd/lib','/flash/lib',J] +class L: + INFO=20;WARNING=30;ERROR=40;level=INFO;prnt=S + @staticmethod + def getLogger(name):return L() + @classmethod + def basicConfig(A,level):A.level=level + def info(A,msg): + if A.level<=L.INFO:A.prnt('INFO :',msg) + def warning(A,msg): + if A.level<=L.WARNING:A.prnt('WARN :',msg) + def error(A,msg): + if A.level<=L.ERROR:A.prnt('ERROR :',msg) +A=L.getLogger(o) +L.basicConfig(level=L.INFO) class Stubber: - "Generate stubs for modules in firmware" - - def __init__(self, path: str = None, firmware_id: str = None): # type: ignore - try: - if os.uname().release == "1.13.0" and os.uname().version < "v1.13-103": # type: ignore - raise NotImplementedError("MicroPython 1.13.0 cannot be stubbed") - except AttributeError: - pass # Allow testing on CPython 3.11 - self.info = _info() - log.info("Port: {}".format(self.info["port"])) - log.info("Board: {}".format(self.info["board"])) - gc.collect() - if firmware_id: - self._fwid = firmware_id.lower() - else: - if self.info["family"] == "micropython": - self._fwid = "{family}-v{version}-{port}-{board}".format(**self.info).rstrip("-") - else: - self._fwid = "{family}-v{version}-{port}".format(**self.info) - self._start_free = gc.mem_free() # type: ignore - - if path: - if path.endswith("/"): - path = path[:-1] - else: - path = get_root() - - self.path = "{}/stubs/{}".format(path, self.flat_fwid).replace("//", "/") - # log.debug(self.path) - try: - ensure_folder(path + "/") - except OSError: - log.error("error creating stub folder {}".format(path)) - self.problematic = [ - "upip", - "upysh", - "webrepl_setup", - "http_client", - "http_client_ssl", - "http_server", - "http_server_ssl", - ] - self.excluded = [ - "webrepl", - "_webrepl", - "port_diag", - "example_sub_led.py", - "example_pub_button.py", - ] - # there is no option to discover modules from micropython, list is read from an external file. - self.modules = [] # type: list[str] - self._json_name = None - self._json_first = False - - def get_obj_attributes(self, item_instance: object): - "extract information of the objects members and attributes" - # name_, repr_(value), type as text, item_instance - _result = [] - _errors = [] - # log.debug("get attributes {} {}".format(repr(item_instance), item_instance)) - for name in dir(item_instance): - if name.startswith("__") and not name in self.modules: - continue - # log.debug("get attribute {}".format(name)) - try: - val = getattr(item_instance, name) - # name , item_repr(value) , type as text, item_instance, order - # log.debug("attribute {}:{}".format(name, val)) - try: - type_text = repr(type(val)).split("'")[1] - except IndexError: - type_text = "" - if type_text in {"int", "float", "str", "bool", "tuple", "list", "dict"}: - order = 1 - elif type_text in {"function", "method"}: - order = 2 - elif type_text in ("class"): - order = 3 - else: - order = 4 - _result.append((name, repr(val), repr(type(val)), val, order)) - except AttributeError as e: - _errors.append("Couldn't get attribute '{}' from object '{}', Err: {}".format(name, item_instance, e)) - except MemoryError as e: - print("MemoryError: {}".format(e)) - sleep(1) - reset() - - # remove internal __ - # _result = sorted([i for i in _result if not (i[0].startswith("_"))], key=lambda x: x[4]) - _result = sorted([i for i in _result if not (i[0].startswith("__"))], key=lambda x: x[4]) - gc.collect() - return _result, _errors - - def add_modules(self, modules): - "Add additional modules to be exported" - self.modules = sorted(set(self.modules) | set(modules)) - - def create_all_stubs(self): - "Create stubs for all configured modules" - log.info("Start micropython-stubber {} on {}".format(__version__, self._fwid)) - self.report_start() - gc.collect() - for module_name in self.modules: - self.create_one_stub(module_name) - self.report_end() - log.info("Finally done") - - def create_one_stub(self, module_name: str): - if module_name in self.problematic: - log.warning("Skip module: {:<25} : Known problematic".format(module_name)) - return False - if module_name in self.excluded: - log.warning("Skip module: {:<25} : Excluded".format(module_name)) - return False - - file_name = "{}/{}.pyi".format(self.path, module_name.replace(".", "/")) - gc.collect() - result = False - try: - result = self.create_module_stub(module_name, file_name) - except OSError: - return False - gc.collect() - return result - - def create_module_stub(self, module_name: str, file_name: str = None) -> bool: # type: ignore - """Create a Stub of a single python module - - Args: - - module_name (str): name of the module to document. This module will be imported. - - file_name (Optional[str]): the 'path/filename.pyi' to write to. If omitted will be created based on the module name. - """ - if file_name is None: - fname = module_name.replace(".", "_") + ".pyi" - file_name = self.path + "/" + fname - else: - fname = file_name.split("/")[-1] - - if "/" in module_name: - # for nested modules - module_name = module_name.replace("/", ".") - - # import the module (as new_module) to examine it - new_module = None - try: - new_module = __import__(module_name, None, None, ("*")) - m1 = gc.mem_free() # type: ignore - log.info("Stub module: {:<25} to file: {:<70} mem:{:>5}".format(module_name, fname, m1)) - - except ImportError: - # log.debug("Skip module: {:<25} {:<79}".format(module_name, "Module not found.")) - return False - - # Start a new file - ensure_folder(file_name) - with open(file_name, "w") as fp: - info_ = str(self.info).replace("OrderedDict(", "").replace("})", "}") - s = '"""\nModule: \'{0}\' on {1}\n"""\n# MCU: {2}\n# Stubber: {3}\n'.format(module_name, self._fwid, info_, __version__) - fp.write(s) - fp.write("from __future__ import annotations\nfrom typing import Any, Generator\nfrom _typeshed import Incomplete\n\n") - self.write_object_stub(fp, new_module, module_name, "") - - self.report_add(module_name, file_name) - - if module_name not in {"os", "sys", "logging", "gc"}: - # try to unload the module unless we use it - try: - del new_module - except (OSError, KeyError): # lgtm [py/unreachable-statement] - log.warning("could not del new_module") - # do not try to delete from sys.modules - most times it does not work anyway - gc.collect() - return True - - def write_object_stub(self, fp, object_expr: object, obj_name: str, indent: str, in_class: int = 0): - "Write a module/object stub to an open file. Can be called recursive." - gc.collect() - if object_expr in self.problematic: - log.warning("SKIPPING problematic module:{}".format(object_expr)) - return - - # # log.debug("DUMP : {}".format(object_expr)) - items, errors = self.get_obj_attributes(object_expr) - - if errors: - log.error(errors) - - for item_name, item_repr, item_type_txt, item_instance, _ in items: - # name_, repr_(value), type as text, item_instance, order - if item_name in ["classmethod", "staticmethod", "BaseException", "Exception"]: - # do not create stubs for these primitives - continue - if item_name[0].isdigit(): - log.warning("NameError: invalid name {}".format(item_name)) - continue - # Class expansion only on first 3 levels (bit of a hack) - if ( - item_type_txt == "" - and len(indent) <= _MAX_CLASS_LEVEL * 4 - # and not obj_name.endswith(".Pin") - # avoid expansion of Pin.cpu / Pin.board to avoid crashes on most platforms - ): - # log.debug("{0}class {1}:".format(indent, item_name)) - superclass = "" - is_exception = ( - item_name.endswith("Exception") - or item_name.endswith("Error") - or item_name - in [ - "KeyboardInterrupt", - "StopIteration", - "SystemExit", - ] - ) - if is_exception: - superclass = "Exception" - s = "\n{}class {}({}):\n".format(indent, item_name, superclass) - # s += indent + " ''\n" - if is_exception: - s += indent + " ...\n" - fp.write(s) - continue - # write classdef - fp.write(s) - # first write the class literals and methods - # log.debug("# recursion over class {0}".format(item_name)) - self.write_object_stub( - fp, - item_instance, - "{0}.{1}".format(obj_name, item_name), - indent + " ", - in_class + 1, - ) - # end with the __init__ method to make sure that the literals are defined - # Add __init__ - s = indent + " def __init__(self, *argv, **kwargs) -> None:\n" - s += indent + " ...\n\n" - fp.write(s) - elif any(word in item_type_txt for word in ["method", "function", "closure"]): - # log.debug("# def {1} function/method/closure, type = '{0}'".format(item_type_txt, item_name)) - # module Function or class method - # will accept any number of params - # return type Any/Incomplete - ret = "Incomplete" - first = "" - # Self parameter only on class methods/functions - if in_class > 0: - first = "self, " - # class method - add function decoration - if "bound_method" in item_type_txt or "bound_method" in item_repr: - s = "{}@classmethod\n".format(indent) + "{}def {}(cls, *args, **kwargs) -> {}:\n".format(indent, item_name, ret) - else: - s = "{}def {}({}*args, **kwargs) -> {}:\n".format(indent, item_name, first, ret) - s += indent + " ...\n\n" - fp.write(s) - # log.debug("\n" + s) - elif item_type_txt == "": - # Skip imported modules - # fp.write("# import {}\n".format(item_name)) - pass - - elif item_type_txt.startswith("" - if " at " in item_repr: - item_repr = item_repr.split(" at ")[0] + " at ...>" - s = "{0}{1}: {2} ## {3} = {4}\n".format(indent, item_name, t, item_type_txt, item_repr) - fp.write(s) - # log.debug("\n" + s) - else: - # keep only the name - # log.debug("# all other, type = '{0}'".format(item_type_txt)) - fp.write("# all other, type = '{0}'\n".format(item_type_txt)) - - fp.write(indent + item_name + " # type: Incomplete\n") - - # del items - # del errors - # try: - # del item_name, item_repr, item_type_txt, item_instance # type: ignore - # except (OSError, KeyError, NameError): - # pass - - @property - def flat_fwid(self): - "Turn _fwid from 'v1.2.3' into '1_2_3' to be used in filename" - s = self._fwid - # path name restrictions - chars = " .()/\\:$" - for c in chars: - s = s.replace(c, "_") - return s - - def clean(self, path: str = None): # type: ignore - "Remove all files from the stub folder" - if path is None: - path = self.path - log.info("Clean/remove files in folder: {}".format(path)) - try: - os.stat(path) # TEMP workaround mpremote listdir bug - - items = os.listdir(path) - except (OSError, AttributeError): - # os.listdir fails on unix - return - for fn in items: - item = "{}/{}".format(path, fn) - try: - os.remove(item) - except OSError: - try: # folder - self.clean(item) - os.rmdir(item) - except OSError: - pass - - def report_start(self, filename: str = "modules.json"): - """Start a report of the modules that have been stubbed - "create json with list of exported modules""" - self._json_name = "{}/{}".format(self.path, filename) - self._json_first = True - ensure_folder(self._json_name) - log.info("Report file: {}".format(self._json_name)) - gc.collect() - try: - # write json by node to reduce memory requirements - with open(self._json_name, "w") as f: - f.write("{") - f.write(dumps({"firmware": self.info})[1:-1]) - f.write(",\n") - f.write(dumps({"stubber": {"version": __version__}, "stubtype": "firmware"})[1:-1]) - f.write(",\n") - f.write('"modules" :[\n') - - except OSError as e: - log.error("Failed to create the report.") - self._json_name = None - raise e - - def report_add(self, module_name: str, stub_file: str): - "Add a module to the report" - # write json by node to reduce memory requirements - if not self._json_name: - raise Exception("No report file") - try: - with open(self._json_name, "a") as f: - if not self._json_first: - f.write(",\n") - else: - self._json_first = False - line = '{{"module": "{}", "file": "{}"}}'.format(module_name, stub_file.replace("\\", "/")) - f.write(line) - - except OSError: - log.error("Failed to create the report.") - - def report_end(self): - if not self._json_name: - raise Exception("No report file") - with open(self._json_name, "a") as f: - f.write("\n]}") - # is used as sucess indicator - log.info("Path: {}".format(self.path)) - - -def ensure_folder(path: str): - "Create nested folders if needed" - i = start = 0 - while i != -1: - i = path.find("/", start) - if i != -1: - p = path[0] if i == 0 else path[:i] - # p = partial folder - try: - _ = os.stat(p) - except OSError as e: - # folder does not exist - if e.args[0] == ENOENT: - try: - os.mkdir(p) - except OSError as e2: - log.error("failed to create folder {}".format(p)) - raise e2 - # next level deep - start = i + 1 - - -def _build(s): - # extract build from sys.version or os.uname().version if available - # sys.version: 'MicroPython v1.23.0-preview.6.g3d0b6276f' - # sys.implementation.version: 'v1.13-103-gb137d064e' - if not s: - return "" - s = s.split(" on ", 1)[0] if " on " in s else s - if s.startswith("v"): - if not "-" in s: - return "" - b = s.split("-")[1] - return b - if not "-preview" in s: - return "" - b = s.split("-preview")[1].split(".")[1] - return b - - -def _info(): # type:() -> dict[str, str] - try: - fam = sys.implementation[0] # type: ignore - except TypeError: - # testing on CPython 3.11 - fam = sys.implementation.name - - info = OrderedDict( - { - "family": fam, - "version": "", - "build": "", - "ver": "", - "port": sys.platform, # port: esp32 / win32 / linux / stm32 - "board": "UNKNOWN", - "cpu": "", - "mpy": "", - "arch": "", - } - ) - # change port names to be consistent with the repo - if info["port"].startswith("pyb"): - info["port"] = "stm32" - elif info["port"] == "win32": - info["port"] = "windows" - elif info["port"] == "linux": - info["port"] = "unix" - try: - info["version"] = version_str(sys.implementation.version) # type: ignore - except AttributeError: - pass - try: - _machine = sys.implementation._machine if "_machine" in dir(sys.implementation) else os.uname().machine # type: ignore - # info["board"] = "with".join(_machine.split("with")[:-1]).strip() - info["board"] = _machine - info["cpu"] = _machine.split("with")[-1].strip() - info["mpy"] = ( - sys.implementation._mpy # type: ignore - if "_mpy" in dir(sys.implementation) - else sys.implementation.mpy if "mpy" in dir(sys.implementation) else "" # type: ignore - ) - except (AttributeError, IndexError): - pass - info["board"] = get_boardname() - - try: - if "uname" in dir(os): # old - # extract build from uname().version if available - info["build"] = _build(os.uname()[3]) # type: ignore - if not info["build"]: - # extract build from uname().release if available - info["build"] = _build(os.uname()[2]) # type: ignore - elif "version" in dir(sys): # new - # extract build from sys.version if available - info["build"] = _build(sys.version) - except (AttributeError, IndexError, TypeError): - pass - # avoid build hashes - # if info["build"] and len(info["build"]) > 5: - # info["build"] = "" - - if info["version"] == "" and sys.platform not in ("unix", "win32"): - try: - u = os.uname() # type: ignore - info["version"] = u.release - except (IndexError, AttributeError, TypeError): - pass - # detect families - for fam_name, mod_name, mod_thing in [ - ("pycopy", "pycopy", "const"), - ("pycom", "pycom", "FAT"), - ("ev3-pybricks", "pybricks.hubs", "EV3Brick"), - ]: - try: - _t = __import__(mod_name, None, None, (mod_thing)) - info["family"] = fam_name - del _t - break - except (ImportError, KeyError): - pass - - if info["family"] == "ev3-pybricks": - info["release"] = "2.0.0" - - if info["family"] == "micropython": - info["version"] - if ( - info["version"] - and info["version"].endswith(".0") - and info["version"] >= "1.10.0" # versions from 1.10.0 to 1.23.0 do not have a micro .0 - and info["version"] <= "1.19.9" - ): - # versions from 1.10.0 to 1.23.0 do not have a micro .0 - info["version"] = info["version"][:-2] - - # spell-checker: disable - if "mpy" in info and info["mpy"]: # mpy on some v1.11+ builds - sys_mpy = int(info["mpy"]) - # .mpy architecture - arch = [ - None, - "x86", - "x64", - "armv6", - "armv6m", - "armv7m", - "armv7em", - "armv7emsp", - "armv7emdp", - "xtensa", - "xtensawin", - ][sys_mpy >> 10] - if arch: - info["arch"] = arch - # .mpy version.minor - info["mpy"] = "v{}.{}".format(sys_mpy & 0xFF, sys_mpy >> 8 & 3) - if info["build"] and not info["version"].endswith("-preview"): - info["version"] = info["version"] + "-preview" - # simple to use version[-build] string - info["ver"] = f"{info['version']}-{info['build']}" if info["build"] else f"{info['version']}" - - return info - - -def version_str(version: tuple): # -> str: - v_str = ".".join([str(n) for n in version[:3]]) - if len(version) > 3 and version[3]: - v_str += "-" + version[3] - return v_str - - -def get_boardname() -> str: - "Read the board name from the boardname.py file that may have been created upfront" - try: - from boardname import BOARDNAME # type: ignore - - log.info("Found BOARDNAME: {}".format(BOARDNAME)) - except ImportError: - log.warning("BOARDNAME not found") - BOARDNAME = "" - return BOARDNAME - - -def get_root() -> str: # sourcery skip: use-assigned-variable - "Determine the root folder of the device" - try: - c = os.getcwd() - except (OSError, AttributeError): - # unix port - c = "." - r = c - for r in [c, "/sd", "/flash", "/", "."]: - try: - _ = os.stat(r) - break - except OSError: - continue - return r - - -def file_exists(filename: str): - try: - if os.stat(filename)[0] >> 14: - return True - return False - except OSError: - return False - - -def show_help(): - print("-p, --path path to store the stubs in, defaults to '.'") - sys.exit(1) - - -def read_path() -> str: - "get --path from cmdline. [unix/win]" - path = "" - if len(sys.argv) == 3: - cmd = (sys.argv[1]).lower() - if cmd in ("--path", "-p"): - path = sys.argv[2] - else: - show_help() - elif len(sys.argv) == 2: - show_help() - return path - - -def is_micropython() -> bool: - "runtime test to determine full or micropython" - # pylint: disable=unused-variable,eval-used - try: - # either test should fail on micropython - - # b) https://docs.micropython.org/en/latest/genrst/builtin_types.html#bytes-with-keywords-not-implemented - # Micropython: NotImplementedError - b = bytes("abc", encoding="utf8") # type: ignore # lgtm [py/unused-local-variable] - - # c) https://docs.micropython.org/en/latest/genrst/core_language.html#function-objects-do-not-have-the-module-attribute - # Micropython: AttributeError - c = is_micropython.__module__ # type: ignore # lgtm [py/unused-local-variable] - return False - except (NotImplementedError, AttributeError): - return True - - + def __init__(B,path=E,firmware_id=E): + C=firmware_id + try: + if os.uname().release=='1.13.0'and os.uname().version<'v1.13-103':raise k('MicroPython 1.13.0 cannot be stubbed') + except I:pass + B.info=_info();A.info('Port: {}'.format(B.info[K]));A.info('Board: {}'.format(B.info[U]));D.collect() + if C:B._fwid=C.lower() + elif B.info[Q]==b:B._fwid='{family}-v{version}-{port}-{board}'.format(**B.info).rstrip(V) + else:B._fwid='{family}-v{version}-{port}'.format(**B.info) + B._start_free=D.mem_free() + if path: + if path.endswith(G):path=path[:-1] + else:path=get_root() + B.path='{}/stubs/{}'.format(path,B.flat_fwid).replace('//',G) + try:X(path+G) + except F:A.error('error creating stub folder {}'.format(path)) + B.problematic=['upip','upysh','webrepl_setup','http_client','http_client_ssl','http_server','http_server_ssl'];B.excluded=['webrepl','_webrepl','port_diag','example_sub_led.py','example_pub_button.py'];B.modules=[];B._json_name=E;B._json_first=H + def get_obj_attributes(L,item_instance): + H=item_instance;C=[];K=[] + for A in M(H): + if A.startswith('__')and not A in L.modules:continue + try: + E=getattr(H,A) + try:F=Z(type(E)).split("'")[1] + except T:F=B + if F in{p,q,r,s,c,d,e}:G=1 + elif F in{t,u}:G=2 + elif F in'class':G=3 + else:G=4 + C.append((A,Z(E),Z(type(E)),E,G)) + except I as J:K.append("Couldn't get attribute '{}' from object '{}', Err: {}".format(A,H,J)) + except MemoryError as J:S('MemoryError: {}'.format(J));sleep(1);reset() + C=l([A for A in C if not A[0].startswith('__')],key=lambda x:x[4]);D.collect();return C,K + def add_modules(A,modules):A.modules=l(set(A.modules)|set(modules)) + def create_all_stubs(B): + A.info('Start micropython-stubber {} on {}'.format(__version__,B._fwid));B.report_start();D.collect() + for C in B.modules:B.create_one_stub(C) + B.report_end();A.info('Finally done') + def create_one_stub(C,module_name): + B=module_name + if B in C.problematic:A.warning('Skip module: {:<25} : Known problematic'.format(B));return H + if B in C.excluded:A.warning('Skip module: {:<25} : Excluded'.format(B));return H + I='{}/{}.pyi'.format(C.path,B.replace(J,G));D.collect();E=H + try:E=C.create_module_stub(B,I) + except F:return H + D.collect();return E + def create_module_stub(K,module_name,file_name=E): + I=file_name;C=module_name + if I is E:L=C.replace(J,'_')+'.pyi';I=K.path+G+L + else:L=I.split(G)[-1] + if G in C:C=C.replace(G,J) + M=E + try:M=__import__(C,E,E,'*');Q=D.mem_free();A.info('Stub module: {:<25} to file: {:<70} mem:{:>5}'.format(C,L,Q)) + except N:return H + X(I) + with O(I,'w')as P:S=str(K.info).replace('OrderedDict(',B).replace('})','}');T='"""\nModule: \'{0}\' on {1}\n"""\n# MCU: {2}\n# Stubber: {3}\n'.format(C,K._fwid,S,__version__);P.write(T);P.write('from __future__ import annotations\nfrom typing import Any, Generator\nfrom _typeshed import Incomplete\n\n');K.write_object_stub(P,M,C,B) + K.report_add(C,I) + if C not in{'os','sys','logging','gc'}: + try:del M + except(F,m):A.warning('could not del new_module') + D.collect();return R + def write_object_stub(L,fp,object_expr,obj_name,indent,in_class=0): + Z=' at ...>';Y='generator';X='{0}{1}: {3} = {2}\n';W='bound_method';V='Incomplete';O=in_class;N='Exception';M=object_expr;K=' at ';J=fp;E=indent;D.collect() + if M in L.problematic:A.warning('SKIPPING problematic module:{}'.format(M));return + a,Q=L.get_obj_attributes(M) + if Q:A.error(Q) + for(F,H,I,b,g)in a: + if F in['classmethod','staticmethod','BaseException',N]:continue + if F[0].isdigit():A.warning('NameError: invalid name {}'.format(F));continue + if I==""and P(E)<=z*4: + R=B;S=F.endswith(N)or F.endswith('Error')or F in['KeyboardInterrupt','StopIteration','SystemExit'] + if S:R=N + C='\n{}class {}({}):\n'.format(E,F,R) + if S:C+=E+' ...\n';J.write(C);continue + J.write(C);L.write_object_stub(J,b,'{0}.{1}'.format(obj_name,F),E+' ',O+1);C=E+' def __init__(self, *argv, **kwargs) -> None:\n';C+=E+' ...\n\n';J.write(C) + elif any(A in I for A in[u,t,'closure']): + T=V;U=B + if O>0:U='self, ' + if W in I or W in H:C='{}@classmethod\n'.format(E)+'{}def {}(cls, *args, **kwargs) -> {}:\n'.format(E,F,T) + else:C='{}def {}({}*args, **kwargs) -> {}:\n'.format(E,F,U,T) + C+=E+' ...\n\n';J.write(C) + elif I=="":0 + elif I.startswith("='1.10.0'and A[C]<='1.19.9':A[C]=A[C][:-2] + if F in A and A[F]: + G=int(A[F]);L=[E,'x86','x64','armv6','armv6m','armv7m','armv7em','armv7emsp','armv7emdp','xtensa','xtensawin'][G>>10] + if L:A[R]=L + A[F]='v{}.{}'.format(G&255,G>>8&3) + if A[D]and not A[C].endswith(W):A[C]=A[C]+W + A[O]=f"{A[C]}-{A[D]}"if A[D]else f"{A[C]}";return A +def A1(version): + A=version;B=J.join([str(A)for A in A[:3]]) + if P(A)>3 and A[3]:B+=V+A[3] + return B +def A2(): + try:from boardname import BOARDNAME as C;A.info('Found BOARDNAME: {}'.format(C)) + except N:A.warning('BOARDNAME not found');C=B + return C +def get_root(): + try:A=os.getcwd() + except(F,I):A=J + B=A + for B in['/sd','/flash',G,A,J]: + try:C=os.stat(B);break + except F:continue + return B +def h(filename): + try: + if os.stat(filename)[0]>>14:return R + return H + except F:return H +def i():S("-p, --path path to store the stubs in, defaults to '.'");sys.exit(1) +def read_path(): + path=B + if P(sys.argv)==3: + A=sys.argv[1].lower() + if A in('--path','-p'):path=sys.argv[2] + else:i() + elif P(sys.argv)==2:i() + return path +def j(): + try:A=bytes('abc',encoding='utf8');B=j.__module__;return H + except(k,I):return R def main(): - stubber = Stubber(path=read_path()) - # stubber = Stubber(path="/sd") - # Option: Specify a firmware name & version - # stubber = Stubber(firmware_id='HoverBot v1.2.1') - stubber.clean() - - # Read stubs from modulelist in the current folder or in /libs - # fall back to default modules - def get_modulelist(stubber): - # new - gc.collect() - stubber.modules = [] # avoid duplicates - for p in LIBS: - fname = p + "/modulelist.txt" - if not file_exists(fname): - continue - with open(fname) as f: - # print("DEBUG: list of modules: " + p + "/modulelist.txt") - while True: - line = f.readline().strip() - if not line: - break - if len(line) > 0 and line[0] != "#": - stubber.modules.append(line) - gc.collect() - print("BREAK") - break - - if not stubber.modules: - stubber.modules = ["micropython"] - # _log.warn("Could not find modulelist.txt, using default modules") - gc.collect() - - stubber.modules = [] # avoid duplicates - get_modulelist(stubber) - - gc.collect() - - stubber.create_all_stubs() - - -if __name__ == "__main__" or is_micropython(): - if not file_exists("no_auto_stubber.txt"): - try: - gc.threshold(4 * 1024) # type: ignore - gc.enable() - except BaseException: - pass - main() + stubber=Stubber(path=read_path());stubber.clean() + def A(stubber): + D.collect();stubber.modules=[] + for C in A0: + B=C+'/modulelist.txt' + if not h(B):continue + with O(B)as E: + while R: + A=E.readline().strip() + if not A:break + if P(A)>0 and A[0]!='#':stubber.modules.append(A) + D.collect();S('BREAK');break + if not stubber.modules:stubber.modules=[b] + D.collect() + stubber.modules=[];A(stubber);D.collect();stubber.create_all_stubs() +if __name__=='__main__'or j(): + if not h('no_auto_stubber.txt'): + try:D.threshold(4096);D.enable() + except BaseException:pass + main() \ No newline at end of file diff --git a/mip/v6/createstubs_mem_mpy.mpy b/mip/v6/createstubs_mem_mpy.mpy index 1b8fd59ad09f34e2799916705bb7cdcb80b33b91..837bb668fea9ba593db0021f8817d103480919fc 100644 GIT binary patch literal 9142 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 Tudh*2TGzkfW4GyT$(Zs#hg(6x literal 8874 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 bool: # type: ignore - """Create a Stub of a single python module - - Args: - - module_name (str): name of the module to document. This module will be imported. - - file_name (Optional[str]): the 'path/filename.pyi' to write to. If omitted will be created based on the module name. - """ - if file_name is None: - fname = module_name.replace(".", "_") + ".pyi" - file_name = self.path + "/" + fname - else: - fname = file_name.split("/")[-1] - - if "/" in module_name: - # for nested modules - module_name = module_name.replace("/", ".") - - # import the module (as new_module) to examine it - new_module = None - try: - new_module = __import__(module_name, None, None, ("*")) - m1 = gc.mem_free() # type: ignore - log.info("Stub module: {:<25} to file: {:<70} mem:{:>5}".format(module_name, fname, m1)) - - except ImportError: - # log.debug("Skip module: {:<25} {:<79}".format(module_name, "Module not found.")) - return False - - # Start a new file - ensure_folder(file_name) - with open(file_name, "w") as fp: - info_ = str(self.info).replace("OrderedDict(", "").replace("})", "}") - s = '"""\nModule: \'{0}\' on {1}\n"""\n# MCU: {2}\n# Stubber: {3}\n'.format( - module_name, self._fwid, info_, __version__ - ) - fp.write(s) - fp.write( - "from __future__ import annotations\nfrom typing import Any, Generator\nfrom _typeshed import Incomplete\n\n" - ) - self.write_object_stub(fp, new_module, module_name, "") - - self.report_add(module_name, file_name) - - if module_name not in {"os", "sys", "logging", "gc"}: - # try to unload the module unless we use it - try: - del new_module - except (OSError, KeyError): # lgtm [py/unreachable-statement] - log.warning("could not del new_module") - # do not try to delete from sys.modules - most times it does not work anyway - gc.collect() - return True - - def write_object_stub(self, fp, object_expr: object, obj_name: str, indent: str, in_class: int = 0): - "Write a module/object stub to an open file. Can be called recursive." - gc.collect() - if object_expr in self.problematic: - log.warning("SKIPPING problematic module:{}".format(object_expr)) - return - - # # log.debug("DUMP : {}".format(object_expr)) - items, errors = self.get_obj_attributes(object_expr) - - if errors: - log.error(errors) - - for item_name, item_repr, item_type_txt, item_instance, _ in items: - # name_, repr_(value), type as text, item_instance, order - if item_name in ["classmethod", "staticmethod", "BaseException", "Exception"]: - # do not create stubs for these primitives - continue - if item_name[0].isdigit(): - log.warning("NameError: invalid name {}".format(item_name)) - continue - # Class expansion only on first 3 levels (bit of a hack) - if ( - item_type_txt == "" - and len(indent) <= _MAX_CLASS_LEVEL * 4 - # and not obj_name.endswith(".Pin") - # avoid expansion of Pin.cpu / Pin.board to avoid crashes on most platforms - ): - # log.debug("{0}class {1}:".format(indent, item_name)) - superclass = "" - is_exception = ( - item_name.endswith("Exception") - or item_name.endswith("Error") - or item_name - in [ - "KeyboardInterrupt", - "StopIteration", - "SystemExit", - ] - ) - if is_exception: - superclass = "Exception" - s = "\n{}class {}({}):\n".format(indent, item_name, superclass) - # s += indent + " ''\n" - if is_exception: - s += indent + " ...\n" - fp.write(s) - continue - # write classdef - fp.write(s) - # first write the class literals and methods - # log.debug("# recursion over class {0}".format(item_name)) - self.write_object_stub( - fp, - item_instance, - "{0}.{1}".format(obj_name, item_name), - indent + " ", - in_class + 1, - ) - # end with the __init__ method to make sure that the literals are defined - # Add __init__ - s = indent + " def __init__(self, *argv, **kwargs) -> None:\n" - s += indent + " ...\n\n" - fp.write(s) - elif any(word in item_type_txt for word in ["method", "function", "closure"]): - # log.debug("# def {1} function/method/closure, type = '{0}'".format(item_type_txt, item_name)) - # module Function or class method - # will accept any number of params - # return type Any/Incomplete - ret = "Incomplete" - first = "" - # Self parameter only on class methods/functions - if in_class > 0: - first = "self, " - # class method - add function decoration - if "bound_method" in item_type_txt or "bound_method" in item_repr: - s = "{}@classmethod\n".format(indent) + "{}def {}(cls, *args, **kwargs) -> {}:\n".format( - indent, item_name, ret - ) - else: - s = "{}def {}({}*args, **kwargs) -> {}:\n".format(indent, item_name, first, ret) - s += indent + " ...\n\n" - fp.write(s) - # log.debug("\n" + s) - elif item_type_txt == "": - # Skip imported modules - # fp.write("# import {}\n".format(item_name)) - pass - - elif item_type_txt.startswith("" - if " at " in item_repr: - item_repr = item_repr.split(" at ")[0] + " at ...>" - s = "{0}{1}: {2} ## {3} = {4}\n".format(indent, item_name, t, item_type_txt, item_repr) - fp.write(s) - # log.debug("\n" + s) - else: - # keep only the name - # log.debug("# all other, type = '{0}'".format(item_type_txt)) - fp.write("# all other, type = '{0}'\n".format(item_type_txt)) - - fp.write(indent + item_name + " # type: Incomplete\n") - - # del items - # del errors - # try: - # del item_name, item_repr, item_type_txt, item_instance # type: ignore - # except (OSError, KeyError, NameError): - # pass - - @property - def flat_fwid(self): - "Turn _fwid from 'v1.2.3' into '1_2_3' to be used in filename" - s = self._fwid - # path name restrictions - chars = " .()/\\:$" - for c in chars: - s = s.replace(c, "_") - return s - - def clean(self, path: str = None): # type: ignore - "Remove all files from the stub folder" - if path is None: - path = self.path - log.info("Clean/remove files in folder: {}".format(path)) - try: - os.stat(path) # TEMP workaround mpremote listdir bug - - items = os.listdir(path) - except (OSError, AttributeError): - # os.listdir fails on unix - return - for fn in items: - item = "{}/{}".format(path, fn) - try: - os.remove(item) - except OSError: - try: # folder - self.clean(item) - os.rmdir(item) - except OSError: - pass - - def report_start(self, filename: str = "modules.json"): - """Start a report of the modules that have been stubbed - "create json with list of exported modules""" - self._json_name = "{}/{}".format(self.path, filename) - self._json_first = True - ensure_folder(self._json_name) - log.info("Report file: {}".format(self._json_name)) - gc.collect() - try: - # write json by node to reduce memory requirements - with open(self._json_name, "w") as f: - f.write("{") - f.write(dumps({"firmware": self.info})[1:-1]) - f.write(",\n") - f.write(dumps({"stubber": {"version": __version__}, "stubtype": "firmware"})[1:-1]) - f.write(",\n") - f.write('"modules" :[\n') - - except OSError as e: - log.error("Failed to create the report.") - self._json_name = None - raise e - - def report_add(self, module_name: str, stub_file: str): - "Add a module to the report" - # write json by node to reduce memory requirements - if not self._json_name: - raise Exception("No report file") - try: - with open(self._json_name, "a") as f: - if not self._json_first: - f.write(",\n") - else: - self._json_first = False - line = '{{"module": "{}", "file": "{}"}}'.format(module_name, stub_file.replace("\\", "/")) - f.write(line) - - except OSError: - log.error("Failed to create the report.") - - def report_end(self): - if not self._json_name: - raise Exception("No report file") - with open(self._json_name, "a") as f: - f.write("\n]}") - # is used as sucess indicator - log.info("Path: {}".format(self.path)) - - -def ensure_folder(path: str): - "Create nested folders if needed" - i = start = 0 - while i != -1: - i = path.find("/", start) - if i != -1: - p = path[0] if i == 0 else path[:i] - # p = partial folder - try: - _ = os.stat(p) - except OSError as e: - # folder does not exist - if e.args[0] == ENOENT: - try: - os.mkdir(p) - except OSError as e2: - log.error("failed to create folder {}".format(p)) - raise e2 - # next level deep - start = i + 1 - - -def _build(s): - # extract build from sys.version or os.uname().version if available - # sys.version: 'MicroPython v1.23.0-preview.6.g3d0b6276f' - # sys.implementation.version: 'v1.13-103-gb137d064e' - if not s: - return "" - s = s.split(" on ", 1)[0] if " on " in s else s - if s.startswith("v"): - if not "-" in s: - return "" - b = s.split("-")[1] - return b - if not "-preview" in s: - return "" - b = s.split("-preview")[1].split(".")[1] - return b - - -def _info(): # type:() -> dict[str, str] - try: - fam = sys.implementation[0] # type: ignore - except TypeError: - # testing on CPython 3.11 - fam = sys.implementation.name - - info = OrderedDict( - { - "family": fam, - "version": "", - "build": "", - "ver": "", - "port": sys.platform, # port: esp32 / win32 / linux / stm32 - "board": "UNKNOWN", - "cpu": "", - "mpy": "", - "arch": "", - } - ) - # change port names to be consistent with the repo - if info["port"].startswith("pyb"): - info["port"] = "stm32" - elif info["port"] == "win32": - info["port"] = "windows" - elif info["port"] == "linux": - info["port"] = "unix" - try: - info["version"] = version_str(sys.implementation.version) # type: ignore - except AttributeError: - pass - try: - _machine = ( - sys.implementation._machine if "_machine" in dir(sys.implementation) else os.uname().machine # type: ignore - ) - # info["board"] = "with".join(_machine.split("with")[:-1]).strip() - info["board"] = _machine - info["cpu"] = _machine.split("with")[-1].strip() - info["mpy"] = ( - sys.implementation._mpy # type: ignore - if "_mpy" in dir(sys.implementation) - else sys.implementation.mpy if "mpy" in dir(sys.implementation) else "" # type: ignore - ) - except (AttributeError, IndexError): - pass - info["board"] = get_boardname() - - try: - if "uname" in dir(os): # old - # extract build from uname().version if available - info["build"] = _build(os.uname()[3]) # type: ignore - if not info["build"]: - # extract build from uname().release if available - info["build"] = _build(os.uname()[2]) # type: ignore - elif "version" in dir(sys): # new - # extract build from sys.version if available - info["build"] = _build(sys.version) - except (AttributeError, IndexError, TypeError): - pass - # avoid build hashes - # if info["build"] and len(info["build"]) > 5: - # info["build"] = "" - - if info["version"] == "" and sys.platform not in ("unix", "win32"): - try: - u = os.uname() # type: ignore - info["version"] = u.release - except (IndexError, AttributeError, TypeError): - pass - # detect families - for fam_name, mod_name, mod_thing in [ - ("pycopy", "pycopy", "const"), - ("pycom", "pycom", "FAT"), - ("ev3-pybricks", "pybricks.hubs", "EV3Brick"), - ]: - try: - _t = __import__(mod_name, None, None, (mod_thing)) - info["family"] = fam_name - del _t - break - except (ImportError, KeyError): - pass - - if info["family"] == "ev3-pybricks": - info["release"] = "2.0.0" - - if info["family"] == "micropython": - info["version"] - if ( - info["version"] - and info["version"].endswith(".0") - and info["version"] >= "1.10.0" # versions from 1.10.0 to 1.23.0 do not have a micro .0 - and info["version"] <= "1.19.9" - ): - # versions from 1.10.0 to 1.23.0 do not have a micro .0 - info["version"] = info["version"][:-2] - - # spell-checker: disable - if "mpy" in info and info["mpy"]: # mpy on some v1.11+ builds - sys_mpy = int(info["mpy"]) - # .mpy architecture - arch = [ - None, - "x86", - "x64", - "armv6", - "armv6m", - "armv7m", - "armv7em", - "armv7emsp", - "armv7emdp", - "xtensa", - "xtensawin", - ][sys_mpy >> 10] - if arch: - info["arch"] = arch - # .mpy version.minor - info["mpy"] = "v{}.{}".format(sys_mpy & 0xFF, sys_mpy >> 8 & 3) - if info["build"] and not info["version"].endswith("-preview"): - info["version"] = info["version"] + "-preview" - # simple to use version[-build] string - info["ver"] = f"{info['version']}-{info['build']}" if info["build"] else f"{info['version']}" - - return info - - -def version_str(version: tuple): # -> str: - v_str = ".".join([str(n) for n in version[:3]]) - if len(version) > 3 and version[3]: - v_str += "-" + version[3] - return v_str - - -def get_boardname() -> str: - "Read the board name from the boardname.py file that may have been created upfront" - try: - from boardname import BOARDNAME # type: ignore - - log.info("Found BOARDNAME: {}".format(BOARDNAME)) - except ImportError: - log.warning("BOARDNAME not found") - BOARDNAME = "" - return BOARDNAME - - -def get_root() -> str: # sourcery skip: use-assigned-variable - "Determine the root folder of the device" - try: - c = os.getcwd() - except (OSError, AttributeError): - # unix port - c = "." - r = c - for r in [c, "/sd", "/flash", "/", "."]: - try: - _ = os.stat(r) - break - except OSError: - continue - return r - - -def file_exists(filename: str): - try: - if os.stat(filename)[0] >> 14: - return True - return False - except OSError: - return False - - -def show_help(): - print("-p, --path path to store the stubs in, defaults to '.'") - sys.exit(1) - - -def read_path() -> str: - "get --path from cmdline. [unix/win]" - path = "" - if len(sys.argv) == 3: - cmd = (sys.argv[1]).lower() - if cmd in ("--path", "-p"): - path = sys.argv[2] - else: - show_help() - elif len(sys.argv) == 2: - show_help() - return path - - -def is_micropython() -> bool: - "runtime test to determine full or micropython" - # pylint: disable=unused-variable,eval-used - try: - # either test should fail on micropython - - # b) https://docs.micropython.org/en/latest/genrst/builtin_types.html#bytes-with-keywords-not-implemented - # Micropython: NotImplementedError - b = bytes("abc", encoding="utf8") # type: ignore # lgtm [py/unused-local-variable] - - # c) https://docs.micropython.org/en/latest/genrst/core_language.html#function-objects-do-not-have-the-module-attribute - # Micropython: AttributeError - c = is_micropython.__module__ # type: ignore # lgtm [py/unused-local-variable] - return False - except (NotImplementedError, AttributeError): - return True - - -def main(): - stubber = Stubber(path=read_path()) - # stubber = Stubber(path="/sd") - # Option: Specify a firmware name & version - # stubber = Stubber(firmware_id='HoverBot v1.2.1') - stubber.clean() - # there is no option to discover modules from micropython, need to hardcode - # below contains combined modules from Micropython ESP8622, ESP32, Loboris, Pycom and ulab , lvgl - # spell-checker: disable - # modules to stub : 131 - stubber.modules = [ - "WM8960", - "_OTA", - "_asyncio", - "_boot_fat", - "_coap", - "_espnow", - "_flash_control_OTA", - "_main_pybytes", - "_mqtt", - "_mqtt_core", - "_msg_handl", - "_onewire", - "_periodical_pin", - "_pybytes", - "_pybytes_ca", - "_pybytes_config", - "_pybytes_config_reader", - "_pybytes_connection", - "_pybytes_constants", - "_pybytes_debug", - "_pybytes_library", - "_pybytes_machine_learning", - "_pybytes_main", - "_pybytes_protocol", - "_pybytes_pyconfig", - "_pybytes_pymesh_config", - "_rp2", - "_terminal", - "_thread", - "_uasyncio", - "_urequest", - "adcfft", - "aioble/__init__", - "aioble/central", - "aioble/client", - "aioble/core", - "aioble/device", - "aioble/l2cap", - "aioble/peripheral", - "aioble/security", - "aioble/server", - "aioespnow", - "ak8963", - "apa102", - "apa106", - "argparse", - "array", - "asyncio/__init__", - "asyncio/core", - "asyncio/event", - "asyncio/funcs", - "asyncio/lock", - "asyncio/stream", - "binascii", - "bluetooth", - "breakout_as7262", - "breakout_bh1745", - "breakout_bme280", - "breakout_bme68x", - "breakout_bmp280", - "breakout_dotmatrix", - "breakout_encoder", - "breakout_icp10125", - "breakout_ioexpander", - "breakout_ltr559", - "breakout_matrix11x7", - "breakout_mics6814", - "breakout_msa301", - "breakout_paa5100", - "breakout_pmw3901", - "breakout_potentiometer", - "breakout_rgbmatrix5x5", - "breakout_rtc", - "breakout_scd41", - "breakout_sgp30", - "breakout_trackball", - "breakout_vl53l5cx", - "btree", - "cmath", - "collections", - "crypto", - "cryptolib", - "curl", - "deflate", - "dht", - "display", - "display_driver_utils", - "ds18x20", - "encoder", - "errno", - "esp", - "esp32", - "espidf", - "espnow", - "ffi", - "flashbdev", - "framebuf", - "freesans20", - "fs_driver", - "functools", - "galactic", - "gc", - "gfx_pack", - "gsm", - "hashlib", - "heapq", - "hub75", - "ili9341", - "ili9XXX", - "imagetools", - "inisetup", - "interstate75", - "io", - "jpegdec", - "js", - "jsffi", - "json", - "lcd160cr", - "lodepng", - "logging", - "lsm6dsox", - "lv_colors", - "lv_utils", - "lvgl", - "lwip", - "machine", - "math", - "microWebSocket", - "microWebSrv", - "microWebTemplate", - "micropython", - "mip", - "mip/__init__", - "mip/__main__", - "motor", - "mpu6500", - "mpu9250", - "neopixel", - "network", - "ntptime", - "onewire", - "openamp", - "os", - "pcf85063a", - "picoexplorer", - "picographics", - "picokeypad", - "picoscroll", - "picounicorn", - "picowireless", - "pimoroni", - "pimoroni_bus", - "pimoroni_i2c", - "plasma", - "platform", - "pyb", - "pycom", - "pye", - "qrcode", - "queue", - "random", - "requests", - "requests/__init__", - "rp2", - "rtch", - "samd", - "select", - "servo", - "socket", - "ssd1306", - "ssh", - "ssl", - "stm", - "struct", - "sys", - "termios", - "time", - "tls", - "tpcalib", - "uarray", - "uasyncio/__init__", - "uasyncio/core", - "uasyncio/event", - "uasyncio/funcs", - "uasyncio/lock", - "uasyncio/stream", - "uasyncio/tasks", - "ubinascii", - "ubluetooth", - "ucollections", - "ucrypto", - "ucryptolib", - "uctypes", - "uerrno", - "uftpd", - "uhashlib", - "uheapq", - "uio", - "ujson", - "ulab", - "ulab/approx", - "ulab/compare", - "ulab/fft", - "ulab/filter", - "ulab/linalg", - "ulab/numerical", - "ulab/poly", - "ulab/user", - "ulab/vector", - "umachine", - "umqtt/__init__", - "umqtt/robust", - "umqtt/simple", - "uos", - "uplatform", - "uqueue", - "urandom", - "ure", - "urequests", - "urllib/urequest", - "usb/device", - "usb/device/cdc", - "usb/device/hid", - "usb/device/keyboard", - "usb/device/midi", - "usb/device/mouse", - "uselect", - "usocket", - "ussl", - "ustruct", - "usys", - "utelnetserver", - "utime", - "utimeq", - "uwebsocket", - "uzlib", - "version", - "vfs", - "websocket", - "websocket_helper", - "wipy", - "writer", - "xpt2046", - "ymodem", - "zephyr", - "zlib", - ] # spell-checker: enable - - gc.collect() - - stubber.create_all_stubs() - - -if __name__ == "__main__" or is_micropython(): - if not file_exists("no_auto_stubber.txt"): - try: - gc.threshold(4 * 1024) # type: ignore - gc.enable() - except BaseException: - pass - main() + def __init__(B,path=D,firmware_id=D): + C=firmware_id + try: + if os.uname().release=='1.13.0'and os.uname().version<'v1.13-103':raise l('MicroPython 1.13.0 cannot be stubbed') + except I:pass + B.info=_info();A.info('Port: {}'.format(B.info[K]));A.info('Board: {}'.format(B.info[S]));F.collect() + if C:B._fwid=C.lower() + elif B.info[O]==b:B._fwid='{family}-v{version}-{port}-{board}'.format(**B.info).rstrip(T) + else:B._fwid='{family}-v{version}-{port}'.format(**B.info) + B._start_free=F.mem_free() + if path: + if path.endswith(G):path=path[:-1] + else:path=get_root() + B.path='{}/stubs/{}'.format(path,B.flat_fwid).replace('//',G) + try:W(path+G) + except E:A.error('error creating stub folder {}'.format(path)) + B.problematic=['upip','upysh','webrepl_setup','http_client','http_client_ssl','http_server','http_server_ssl'];B.excluded=['webrepl','_webrepl','port_diag','example_sub_led.py','example_pub_button.py'];B.modules=[];B._json_name=D;B._json_first=H + def get_obj_attributes(L,item_instance): + H=item_instance;C=[];K=[] + for A in M(H): + if A.startswith('__')and not A in L.modules:continue + try: + D=getattr(H,A) + try:E=Z(type(D)).split("'")[1] + except P:E=B + if E in{q,r,s,t,c,d,e}:G=1 + elif E in{u,v}:G=2 + elif E in'class':G=3 + else:G=4 + C.append((A,Z(D),Z(type(D)),D,G)) + except I as J:K.append("Couldn't get attribute '{}' from object '{}', Err: {}".format(A,H,J)) + except MemoryError as J:Y('MemoryError: {}'.format(J));sleep(1);reset() + C=m([A for A in C if not A[0].startswith('__')],key=lambda x:x[4]);F.collect();return C,K + def add_modules(A,modules):A.modules=m(set(A.modules)|set(modules)) + def create_all_stubs(B): + A.info('Start micropython-stubber {} on {}'.format(__version__,B._fwid));B.report_start();F.collect() + for C in B.modules:B.create_one_stub(C) + B.report_end();A.info('Finally done') + def create_one_stub(C,module_name): + B=module_name + if B in C.problematic:A.warning('Skip module: {:<25} : Known problematic'.format(B));return H + if B in C.excluded:A.warning('Skip module: {:<25} : Excluded'.format(B));return H + I='{}/{}.pyi'.format(C.path,B.replace(J,G));F.collect();D=H + try:D=C.create_module_stub(B,I) + except E:return H + F.collect();return D + def create_module_stub(K,module_name,file_name=D): + I=file_name;C=module_name + if I is D:L=C.replace(J,'_')+'.pyi';I=K.path+G+L + else:L=I.split(G)[-1] + if G in C:C=C.replace(G,J) + M=D + try:M=__import__(C,D,D,'*');P=F.mem_free();A.info('Stub module: {:<25} to file: {:<70} mem:{:>5}'.format(C,L,P)) + except N:return H + W(I) + with Q(I,'w')as O:R=str(K.info).replace('OrderedDict(',B).replace('})','}');S='"""\nModule: \'{0}\' on {1}\n"""\n# MCU: {2}\n# Stubber: {3}\n'.format(C,K._fwid,R,__version__);O.write(S);O.write('from __future__ import annotations\nfrom typing import Any, Generator\nfrom _typeshed import Incomplete\n\n');K.write_object_stub(O,M,C,B) + K.report_add(C,I) + if C not in{'os',w,x,'gc'}: + try:del M + except(E,n):A.warning('could not del new_module') + F.collect();return U + def write_object_stub(L,fp,object_expr,obj_name,indent,in_class=0): + Z=' at ...>';Y='generator';X='{0}{1}: {3} = {2}\n';W='bound_method';V='Incomplete';O=in_class;N='Exception';M=object_expr;K=' at ';J=fp;D=indent;F.collect() + if M in L.problematic:A.warning('SKIPPING problematic module:{}'.format(M));return + a,P=L.get_obj_attributes(M) + if P:A.error(P) + for(E,H,I,b,g)in a: + if E in['classmethod','staticmethod','BaseException',N]:continue + if E[0].isdigit():A.warning('NameError: invalid name {}'.format(E));continue + if I==""and R(D)<=A3*4: + Q=B;S=E.endswith(N)or E.endswith('Error')or E in['KeyboardInterrupt','StopIteration','SystemExit'] + if S:Q=N + C='\n{}class {}({}):\n'.format(D,E,Q) + if S:C+=D+' ...\n';J.write(C);continue + J.write(C);L.write_object_stub(J,b,'{0}.{1}'.format(obj_name,E),D+' ',O+1);C=D+' def __init__(self, *argv, **kwargs) -> None:\n';C+=D+' ...\n\n';J.write(C) + elif any(A in I for A in[v,u,'closure']): + T=V;U=B + if O>0:U='self, ' + if W in I or W in H:C='{}@classmethod\n'.format(D)+'{}def {}(cls, *args, **kwargs) -> {}:\n'.format(D,E,T) + else:C='{}def {}({}*args, **kwargs) -> {}:\n'.format(D,E,U,T) + C+=D+' ...\n\n';J.write(C) + elif I=="":0 + elif I.startswith("='1.10.0'and A[C]<='1.19.9':A[C]=A[C][:-2] + if F in A and A[F]: + G=int(A[F]);L=[D,'x86','x64','armv6','armv6m','armv7m','armv7em','armv7emsp','armv7emdp','xtensa','xtensawin'][G>>10] + if L:A[T]=L + A[F]='v{}.{}'.format(G&255,G>>8&3) + if A[E]and not A[C].endswith(V):A[C]=A[C]+V + A[Q]=f"{A[C]}-{A[E]}"if A[E]else f"{A[C]}";return A +def A4(version): + A=version;B=J.join([str(A)for A in A[:3]]) + if R(A)>3 and A[3]:B+=T+A[3] + return B +def A5(): + try:from boardname import BOARDNAME as C;A.info('Found BOARDNAME: {}'.format(C)) + except N:A.warning('BOARDNAME not found');C=B + return C +def get_root(): + try:A=os.getcwd() + except(E,I):A=J + B=A + for B in['/sd','/flash',G,A,J]: + try:C=os.stat(B);break + except E:continue + return B +def A6(filename): + try: + if os.stat(filename)[0]>>14:return U + return H + except E:return H +def j():Y("-p, --path path to store the stubs in, defaults to '.'");sys.exit(1) +def read_path(): + path=B + if R(sys.argv)==3: + A=sys.argv[1].lower() + if A in('--path','-p'):path=sys.argv[2] + else:j() + elif R(sys.argv)==2:j() + return path +def k(): + try:A=bytes('abc',encoding='utf8');B=k.__module__;return H + except(l,I):return U +def main():stubber=Stubber(path=read_path());stubber.clean();stubber.modules=['WM8960','_OTA','_asyncio','_boot_fat','_coap','_espnow','_flash_control_OTA','_main_pybytes','_mqtt','_mqtt_core','_msg_handl','_onewire','_periodical_pin','_pybytes','_pybytes_ca','_pybytes_config','_pybytes_config_reader','_pybytes_connection','_pybytes_constants','_pybytes_debug','_pybytes_library','_pybytes_machine_learning','_pybytes_main','_pybytes_protocol','_pybytes_pyconfig','_pybytes_pymesh_config','_rp2','_terminal','_thread','_uasyncio','_urequest','adcfft','aioble/__init__','aioble/central','aioble/client','aioble/core','aioble/device','aioble/l2cap','aioble/peripheral','aioble/security','aioble/server','aioespnow','ak8963','apa102','apa106','argparse','array','asyncio/__init__','asyncio/core','asyncio/event','asyncio/funcs','asyncio/lock','asyncio/stream','binascii','bluetooth','breakout_as7262','breakout_bh1745','breakout_bme280','breakout_bme68x','breakout_bmp280','breakout_dotmatrix','breakout_encoder','breakout_icp10125','breakout_ioexpander','breakout_ltr559','breakout_matrix11x7','breakout_mics6814','breakout_msa301','breakout_paa5100','breakout_pmw3901','breakout_potentiometer','breakout_rgbmatrix5x5','breakout_rtc','breakout_scd41','breakout_sgp30','breakout_trackball','breakout_vl53l5cx','btree','cc3200','cmath','collections','crypto','cryptolib','curl','deflate','dht','display','display_driver_utils','ds18x20','embed','encoder','errno','esp','esp32','esp8266','espidf','espnow','ffi','flashbdev','framebuf','freesans20','fs_driver','functools','galactic','gc','gfx_pack','gsm','hashlib','heapq','hub75','ili9341','ili9XXX','imagetools','inisetup','interstate75','io','jpegdec','js','jsffi','json','lcd160cr','lodepng',x,'lsm6dsox','lv_colors','lv_utils','lvgl','lwip','machine','math','microWebSocket','microWebSrv','microWebTemplate',b,'mimxrt','mip','mip/__init__','mip/__main__','motor','mpu6500','mpu9250','neopixel','network','nrf','ntptime','onewire','openamp','os','pcf85063a','pic16bit','picoexplorer','picographics','picokeypad','picoscroll','picounicorn','picowireless','pimoroni','pimoroni_bus','pimoroni_i2c','plasma','platform','powerpc','pyb',h,'pye','qemu','qrcode','queue','random','renesas','renesas-ra','requests','requests/__init__','rp2','rtch','samd','select','servo','socket','ssd1306','ssh','ssl','stm','stm32','struct',w,'termios','time','tls','tpcalib','uarray','uasyncio/__init__','uasyncio/core','uasyncio/event','uasyncio/funcs','uasyncio/lock','uasyncio/stream','uasyncio/tasks','ubinascii','ubluetooth','ucollections','ucrypto','ucryptolib','uctypes','uerrno','uftpd','uhashlib','uheapq','uio','ujson','ulab','ulab/approx','ulab/compare','ulab/fft','ulab/filter','ulab/linalg','ulab/numerical','ulab/poly','ulab/user','ulab/vector','umachine','umqtt/__init__','umqtt/robust','umqtt/simple',g,'uos','uplatform','uqueue','urandom','ure','urequests','urllib/urequest','usb/device','usb/device/cdc','usb/device/hid','usb/device/keyboard','usb/device/midi','usb/device/mouse','uselect','usocket','ussl','ustruct','usys','utelnetserver','utime','utimeq','uwebsocket','uzlib',C,'vfs','webassembly','websocket','websocket_helper',A1,'wipy','writer','xpt2046','ymodem','zephyr','zlib'];F.collect();stubber.create_all_stubs() +if __name__=='__main__'or k(): + if not A6('no_auto_stubber.txt'): + try:F.threshold(4096);F.enable() + except BaseException:pass + main() \ No newline at end of file diff --git a/mip/v6/createstubs_mpy.mpy b/mip/v6/createstubs_mpy.mpy index 5cbaeab225b351125c67f828511ae2561449739c..6ae739e0dbb5c90378619ab2adb03a7af057e12c 100644 GIT binary patch delta 7303 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 nECIbj5