7
7
import logging
8
8
import os
9
9
import sys
10
+ from time import sleep
10
11
11
12
try :
12
13
from ujson import dumps
23
24
except ImportError :
24
25
from ucollections import OrderedDict # type: ignore
25
26
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
+
26
43
__version__ = "v1.16.2"
27
44
ENOENT = 2
28
45
_MAX_CLASS_LEVEL = 2 # Max class nesting
29
46
LIBS = ["." , "/lib" , "/sd/lib" , "/flash/lib" , "lib" ]
30
- from time import sleep
31
47
32
48
33
49
class Stubber :
@@ -45,11 +61,12 @@ def __init__(self, path: str = None, firmware_id: str = None): # type: ignore
45
61
self .log .info ("Port: {}" .format (self .info ["port" ]))
46
62
self .log .info ("Board: {}" .format (self .info ["board" ]))
47
63
gc .collect ()
64
+ wdt .feed ()
48
65
if firmware_id :
49
66
self ._fwid = firmware_id .lower ()
50
67
else :
51
68
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 ( "-" )
53
70
else :
54
71
self ._fwid = "{family}-v{version}-{port}" .format (** self .info )
55
72
self ._start_free = gc .mem_free () # type: ignore
@@ -98,6 +115,7 @@ def get_obj_attributes(self, item_instance: object):
98
115
try :
99
116
val = getattr (item_instance , name )
100
117
# name , item_repr(value) , type as text, item_instance, order
118
+ self .log .debug ("attribute {}:{}" .format (name , val ))
101
119
try :
102
120
type_text = repr (type (val )).split ("'" )[1 ]
103
121
except IndexError :
@@ -137,6 +155,7 @@ def create_all_stubs(self):
137
155
self .log .info ("Finally done" )
138
156
139
157
def create_one_stub (self , module_name : str ):
158
+ wdt .feed ()
140
159
if module_name in self .problematic :
141
160
self .log .warning ("Skip module: {:<25} : Known problematic" .format (module_name ))
142
161
return False
@@ -191,7 +210,7 @@ def create_module_stub(self, module_name: str, file_name: str = None) -> bool:
191
210
module_name , self ._fwid , info_ , __version__
192
211
)
193
212
fp .write (s )
194
- fp .write ("from typing import Any\n from _typeshed import Incomplete\n \n " )
213
+ fp .write ("from __future__ import annotations \n from typing import Any\n from _typeshed import Incomplete\n \n " )
195
214
self .write_object_stub (fp , new_module , module_name , "" )
196
215
197
216
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:
202
221
del new_module
203
222
except (OSError , KeyError ): # lgtm [py/unreachable-statement]
204
223
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))
209
229
gc .collect ()
210
230
return True
211
231
@@ -231,8 +251,13 @@ def write_object_stub(self, fp, object_expr: object, obj_name: str, indent: str,
231
251
self .log .warning ("NameError: invalid name {}" .format (item_name ))
232
252
continue
233
253
# 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 ))
236
261
superclass = ""
237
262
is_exception = (
238
263
item_name .endswith ("Exception" )
@@ -306,12 +331,14 @@ def write_object_stub(self, fp, object_expr: object, obj_name: str, indent: str,
306
331
s = "{0}{1} = {2} # type: {3}\n " .format (indent , item_name , ev [t ], t )
307
332
else :
308
333
# 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" ]:
311
335
# 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
312
340
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 )
315
342
fp .write (s )
316
343
self .log .debug ("\n " + s )
317
344
else :
@@ -321,12 +348,12 @@ def write_object_stub(self, fp, object_expr: object, obj_name: str, indent: str,
321
348
322
349
fp .write (indent + item_name + " # type: Incomplete\n " )
323
350
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
330
357
331
358
@property
332
359
def flat_fwid (self ):
@@ -340,6 +367,7 @@ def flat_fwid(self):
340
367
341
368
def clean (self , path : str = None ): # type: ignore
342
369
"Remove all files from the stub folder"
370
+ wdt .feed ()
343
371
if path is None :
344
372
path = self .path
345
373
self .log .info ("Clean/remove files in folder: {}" .format (path ))
@@ -362,6 +390,7 @@ def clean(self, path: str = None): # type: ignore
362
390
363
391
def report (self , filename : str = "modules.json" ):
364
392
"create json with list of exported modules"
393
+ wdt .feed ()
365
394
self .log .info (
366
395
"Created stubs for {} modules on board {}\n Path: {}" .format (len (self ._report ), self ._fwid , self .path )
367
396
)
@@ -423,13 +452,19 @@ def ensure_folder(path: str):
423
452
424
453
def _build (s ):
425
454
# 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 '
428
457
if not s :
429
458
return ""
430
459
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 ]
433
468
return b
434
469
435
470
@@ -565,56 +600,78 @@ def version_str(version: tuple): # -> str:
565
600
566
601
567
602
def read_boardname (info , desc : str = "" ):
603
+ info ["board" ] = info ["board" ].replace (" " , "_" )
568
604
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 ()
570
607
# print("look up the board name in the file", filename)
571
608
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 ()
580
613
found = True
581
614
break
582
615
if not found :
583
616
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()
588
622
info ["board" ] = descr
589
- info ["board" ] = info ["board" ].replace (" " , "_" )
590
- gc .collect ()
591
623
592
624
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
618
675
619
676
620
677
def get_root () -> str : # sourcery skip: use-assigned-variable
0 commit comments