Skip to content

Commit c03da53

Browse files
committed
Merge branch 'simplify_createstubs' of https://github.com/Josverl/micropython-stubber into simplify_createstubs
Signed-off-by: Jos Verlinde <jos_verlinde@hotmail.com>
2 parents c53d1fe + 14f055c commit c03da53

35 files changed

+2685
-1293
lines changed

mip/v5/createstubs.py

Lines changed: 120 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import logging
88
import os
99
import sys
10+
from time import sleep
1011

1112
try:
1213
from ujson import dumps
@@ -23,11 +24,26 @@
2324
except ImportError:
2425
from ucollections import OrderedDict # type: ignore
2526

27+
try:
28+
from nope_machine import WDT
29+
30+
wdt = WDT()
31+
32+
except ImportError:
33+
34+
class _WDT:
35+
def feed(self):
36+
pass
37+
38+
wdt = _WDT()
39+
40+
41+
wdt.feed()
42+
2643
__version__ = "v1.16.2"
2744
ENOENT = 2
2845
_MAX_CLASS_LEVEL = 2 # Max class nesting
2946
LIBS = [".", "/lib", "/sd/lib", "/flash/lib", "lib"]
30-
from time import sleep
3147

3248

3349
class Stubber:
@@ -45,11 +61,12 @@ def __init__(self, path: str = None, firmware_id: str = None): # type: ignore
4561
self.log.info("Port: {}".format(self.info["port"]))
4662
self.log.info("Board: {}".format(self.info["board"]))
4763
gc.collect()
64+
wdt.feed()
4865
if firmware_id:
4966
self._fwid = firmware_id.lower()
5067
else:
5168
if self.info["family"] == "micropython":
52-
self._fwid = "{family}-v{version}-{port}-{board}".format(**self.info)
69+
self._fwid = "{family}-v{version}-{port}-{board}".format(**self.info).rstrip("-")
5370
else:
5471
self._fwid = "{family}-v{version}-{port}".format(**self.info)
5572
self._start_free = gc.mem_free() # type: ignore
@@ -98,6 +115,7 @@ def get_obj_attributes(self, item_instance: object):
98115
try:
99116
val = getattr(item_instance, name)
100117
# name , item_repr(value) , type as text, item_instance, order
118+
self.log.debug("attribute {}:{}".format(name, val))
101119
try:
102120
type_text = repr(type(val)).split("'")[1]
103121
except IndexError:
@@ -137,6 +155,7 @@ def create_all_stubs(self):
137155
self.log.info("Finally done")
138156

139157
def create_one_stub(self, module_name: str):
158+
wdt.feed()
140159
if module_name in self.problematic:
141160
self.log.warning("Skip module: {:<25} : Known problematic".format(module_name))
142161
return False
@@ -191,7 +210,7 @@ def create_module_stub(self, module_name: str, file_name: str = None) -> bool:
191210
module_name, self._fwid, info_, __version__
192211
)
193212
fp.write(s)
194-
fp.write("from typing import Any\nfrom _typeshed import Incomplete\n\n")
213+
fp.write("from __future__ import annotations\nfrom typing import Any\nfrom _typeshed import Incomplete\n\n")
195214
self.write_object_stub(fp, new_module, module_name, "")
196215

197216
self._report.append('{{"module": "{}", "file": "{}"}}'.format(module_name, file_name.replace("\\", "/")))
@@ -202,10 +221,11 @@ def create_module_stub(self, module_name: str, file_name: str = None) -> bool:
202221
del new_module
203222
except (OSError, KeyError): # lgtm [py/unreachable-statement]
204223
self.log.warning("could not del new_module")
205-
try:
206-
del sys.modules[module_name]
207-
except KeyError:
208-
self.log.debug("could not del sys.modules[{}]".format(module_name))
224+
# lets not try - most times it does not work anyway
225+
# try:
226+
# del sys.modules[module_name]
227+
# except KeyError:
228+
# self.log.warning("could not del sys.modules[{}]".format(module_name))
209229
gc.collect()
210230
return True
211231

@@ -231,8 +251,13 @@ def write_object_stub(self, fp, object_expr: object, obj_name: str, indent: str,
231251
self.log.warning("NameError: invalid name {}".format(item_name))
232252
continue
233253
# Class expansion only on first 3 levels (bit of a hack)
234-
if item_type_txt == "<class 'type'>" and len(indent) <= _MAX_CLASS_LEVEL * 4:
235-
self.log.debug("{0}class {1}:".format(indent, item_name))
254+
if (
255+
item_type_txt == "<class 'type'>"
256+
and len(indent) <= _MAX_CLASS_LEVEL * 4
257+
# and not obj_name.endswith(".Pin")
258+
# avoid expansion of Pin.cpu / Pin.board to avoid crashes on most platforms
259+
):
260+
self.log.info("{0}class {1}:".format(indent, item_name))
236261
superclass = ""
237262
is_exception = (
238263
item_name.endswith("Exception")
@@ -306,12 +331,14 @@ def write_object_stub(self, fp, object_expr: object, obj_name: str, indent: str,
306331
s = "{0}{1} = {2} # type: {3}\n".format(indent, item_name, ev[t], t)
307332
else:
308333
# something else
309-
if t not in ["object", "set", "frozenset"]:
310-
# Possibly default others to item_instance object ?
334+
if t in ["object", "set", "frozenset", "Pin", "FileIO"]:
311335
# https://docs.python.org/3/tutorial/classes.html#item_instance-objects
336+
# use these types for the attribute
337+
s = "{0}{1} : {2} ## = {4}\n".format(indent, item_name, t, item_type_txt, item_repr)
338+
else:
339+
# Requires Python 3.6 syntax, which is OK for the stubs/pyi
312340
t = "Incomplete"
313-
# Requires Python 3.6 syntax, which is OK for the stubs/pyi
314-
s = "{0}{1} : {2} ## {3} = {4}\n".format(indent, item_name, t, item_type_txt, item_repr)
341+
s = "{0}{1} : {2} ## {3} = {4}\n".format(indent, item_name, t, item_type_txt, item_repr)
315342
fp.write(s)
316343
self.log.debug("\n" + s)
317344
else:
@@ -321,12 +348,12 @@ def write_object_stub(self, fp, object_expr: object, obj_name: str, indent: str,
321348

322349
fp.write(indent + item_name + " # type: Incomplete\n")
323350

324-
del items
325-
del errors
326-
try:
327-
del item_name, item_repr, item_type_txt, item_instance # type: ignore
328-
except (OSError, KeyError, NameError):
329-
pass
351+
# del items
352+
# del errors
353+
# try:
354+
# del item_name, item_repr, item_type_txt, item_instance # type: ignore
355+
# except (OSError, KeyError, NameError):
356+
# pass
330357

331358
@property
332359
def flat_fwid(self):
@@ -340,6 +367,7 @@ def flat_fwid(self):
340367

341368
def clean(self, path: str = None): # type: ignore
342369
"Remove all files from the stub folder"
370+
wdt.feed()
343371
if path is None:
344372
path = self.path
345373
self.log.info("Clean/remove files in folder: {}".format(path))
@@ -362,6 +390,7 @@ def clean(self, path: str = None): # type: ignore
362390

363391
def report(self, filename: str = "modules.json"):
364392
"create json with list of exported modules"
393+
wdt.feed()
365394
self.log.info(
366395
"Created stubs for {} modules on board {}\nPath: {}".format(len(self._report), self._fwid, self.path)
367396
)
@@ -423,13 +452,19 @@ def ensure_folder(path: str):
423452

424453
def _build(s):
425454
# extract build from sys.version or os.uname().version if available
426-
# 'v1.13-103-gb137d064e'
427-
# 'MicroPython v1.23.0-preview.6.g3d0b6276f'
455+
# sys.version: 'MicroPython v1.23.0-preview.6.g3d0b6276f'
456+
# sys.implementation.version: 'v1.13-103-gb137d064e'
428457
if not s:
429458
return ""
430459
s = s.split(" on ", 1)[0] if " on " in s else s
431-
s = s.split("; ", 1)[1] if "; " in s else s
432-
b = s.split("-")[1] if s.startswith("v") else s.split("-", 1)[-1].split(".")[1]
460+
if s.startswith("v"):
461+
if not "-" in s:
462+
return ""
463+
b = s.split("-")[1]
464+
return b
465+
if not "-preview" in s:
466+
return ""
467+
b = s.split("-preview")[1].split(".")[1]
433468
return b
434469

435470

@@ -565,56 +600,78 @@ def version_str(version: tuple): # -> str:
565600

566601

567602
def read_boardname(info, desc: str = ""):
603+
info["board"] = info["board"].replace(" ", "_")
568604
found = False
569-
for filename in [d + "/board_info.csv" for d in LIBS]:
605+
for filename in [d + "/board_name.txt" for d in LIBS]:
606+
wdt.feed()
570607
# print("look up the board name in the file", filename)
571608
if file_exists(filename):
572-
descr = desc or info["board"].strip()
573-
pos = descr.rfind(" with")
574-
if pos != -1:
575-
short_descr = descr[:pos].strip()
576-
else:
577-
short_descr = ""
578-
print("searching info file: {} for: '{}' or '{}'".format(filename, descr, short_descr))
579-
if find_board(info, descr, filename, short_descr):
609+
with open(filename, "r") as file:
610+
data = file.read()
611+
if data:
612+
info["board"] = data.strip()
580613
found = True
581614
break
582615
if not found:
583616
print("Board not found, guessing board name")
584-
descr = desc or info["board"].strip()
585-
if "with " + info["cpu"].upper() in descr:
586-
# remove the with cpu part
587-
descr = descr.split("with " + info["cpu"].upper())[0].strip()
617+
descr = ""
618+
# descr = desc or info["board"].strip()
619+
# if "with " + info["cpu"].upper() in descr:
620+
# # remove the with cpu part
621+
# descr = descr.split("with " + info["cpu"].upper())[0].strip()
588622
info["board"] = descr
589-
info["board"] = info["board"].replace(" ", "_")
590-
gc.collect()
591623

592624

593-
def find_board(info: dict, descr: str, filename: str, short_descr: str):
594-
"Find the board in the provided board_info.csv file"
595-
short_hit = ""
596-
with open(filename, "r") as file:
597-
# ugly code to make testable in python and micropython
598-
# TODO: This is VERY slow on micropython whith MPREMOTE mount on esp32 (2-3 minutes to read file)
599-
while 1:
600-
line = file.readline()
601-
if not line:
602-
break
603-
descr_, board_ = line.split(",")[0].strip(), line.split(",")[1].strip()
604-
if descr_ == descr:
605-
info["board"] = board_
606-
return True
607-
elif short_descr and descr_ == short_descr:
608-
if "with" in short_descr:
609-
# Good enough - no need to trawl the entire file
610-
info["board"] = board_
611-
return True
612-
# good enough if not found in the rest of the file (but slow)
613-
short_hit = board_
614-
if short_hit:
615-
info["board"] = short_hit
616-
return True
617-
return False
625+
# def read_boardname(info, desc: str = ""):
626+
# wdt.feed()
627+
# # print("look up the board name in the file", filename)
628+
# if file_exists(filename):
629+
# descr = desc or info["board"].strip()
630+
# pos = descr.rfind(" with")
631+
# if pos != -1:
632+
# short_descr = descr[:pos].strip()
633+
# else:
634+
# short_descr = ""
635+
# print("searching info file: {} for: '{}' or '{}'".format(filename, descr, short_descr))
636+
# if find_board(info, descr, filename, short_descr):
637+
# found = True
638+
# break
639+
# if not found:
640+
# print("Board not found, guessing board name")
641+
# descr = desc or info["board"].strip()
642+
# if "with " + info["cpu"].upper() in descr:
643+
# # remove the with cpu part
644+
# descr = descr.split("with " + info["cpu"].upper())[0].strip()
645+
# info["board"] = descr
646+
# info["board"] = info["board"].replace(" ", "_")
647+
# gc.collect()
648+
649+
650+
# def find_board(info: dict, descr: str, filename: str, short_descr: str):
651+
# "Find the board in the provided board_info.csv file"
652+
# short_hit = ""
653+
# with open(filename, "r") as file:
654+
# # ugly code to make testable in python and micropython
655+
# # TODO: This is VERY slow on micropython whith MPREMOTE mount on esp32 (2-3 minutes to read file)
656+
# while 1:
657+
# line = file.readline()
658+
# if not line:
659+
# break
660+
# descr_, board_ = line.split(",")[0].strip(), line.split(",")[1].strip()
661+
# if descr_ == descr:
662+
# info["board"] = board_
663+
# return True
664+
# elif short_descr and descr_ == short_descr:
665+
# if "with" in short_descr:
666+
# # Good enough - no need to trawl the entire file
667+
# info["board"] = board_
668+
# return True
669+
# # good enough if not found in the rest of the file (but slow)
670+
# short_hit = board_
671+
# if short_hit:
672+
# info["board"] = short_hit
673+
# return True
674+
# return False
618675

619676

620677
def get_root() -> str: # sourcery skip: use-assigned-variable

0 commit comments

Comments
 (0)