micropython-stubber 1.16.3__py3-none-any.whl → 1.17.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. {micropython_stubber-1.16.3.dist-info → micropython_stubber-1.17.0.dist-info}/METADATA +1 -1
  2. {micropython_stubber-1.16.3.dist-info → micropython_stubber-1.17.0.dist-info}/RECORD +48 -49
  3. stubber/__init__.py +1 -1
  4. stubber/basicgit.py +11 -13
  5. stubber/board/createstubs.py +138 -97
  6. stubber/board/createstubs_db.py +211 -239
  7. stubber/board/createstubs_db_min.py +322 -844
  8. stubber/board/createstubs_db_mpy.mpy +0 -0
  9. stubber/board/createstubs_lvgl.py +91 -137
  10. stubber/board/createstubs_lvgl_min.py +87 -129
  11. stubber/board/createstubs_lvgl_mpy.mpy +0 -0
  12. stubber/board/createstubs_mem.py +164 -199
  13. stubber/board/createstubs_mem_min.py +297 -791
  14. stubber/board/createstubs_mem_mpy.mpy +0 -0
  15. stubber/board/createstubs_min.py +286 -1009
  16. stubber/board/createstubs_mpy.mpy +0 -0
  17. stubber/board/modulelist.txt +1 -2
  18. stubber/codemod/_partials/__init__.py +1 -1
  19. stubber/codemod/_partials/db_main.py +90 -72
  20. stubber/codemod/_partials/modules_reader.py +29 -17
  21. stubber/codemod/board.py +2 -4
  22. stubber/codemod/enrich.py +1 -1
  23. stubber/commands/build_cmd.py +6 -4
  24. stubber/commands/get_docstubs_cmd.py +6 -11
  25. stubber/commands/get_frozen_cmd.py +6 -11
  26. stubber/commands/switch_cmd.py +6 -4
  27. stubber/freeze/freeze_manifest_2.py +2 -1
  28. stubber/freeze/get_frozen.py +28 -13
  29. stubber/minify.py +51 -38
  30. stubber/publish/candidates.py +15 -23
  31. stubber/publish/defaults.py +2 -2
  32. stubber/publish/merge_docstubs.py +5 -7
  33. stubber/publish/missing_class_methods.py +2 -2
  34. stubber/publish/pathnames.py +2 -2
  35. stubber/publish/publish.py +2 -1
  36. stubber/publish/stubpackage.py +20 -41
  37. stubber/rst/lookup.py +9 -7
  38. stubber/rst/reader.py +2 -1
  39. stubber/stubber.py +5 -6
  40. stubber/update_fallback.py +3 -1
  41. stubber/utils/__init__.py +1 -1
  42. stubber/utils/config.py +7 -9
  43. stubber/utils/repos.py +6 -5
  44. stubber/utils/versions.py +48 -7
  45. stubber/variants.py +3 -3
  46. stubber/board/logging.py +0 -99
  47. {micropython_stubber-1.16.3.dist-info → micropython_stubber-1.17.0.dist-info}/LICENSE +0 -0
  48. {micropython_stubber-1.16.3.dist-info → micropython_stubber-1.17.0.dist-info}/WHEEL +0 -0
  49. {micropython_stubber-1.16.3.dist-info → micropython_stubber-1.17.0.dist-info}/entry_points.txt +0 -0
@@ -1,847 +1,325 @@
1
- """
2
- Create stubs for (all) modules on a MicroPython board.
3
-
4
- This variant of the createstubs.py script is optimized for use on very-low-memory devices.
5
- Note: this version has undergone limited testing.
6
-
7
- 1) reads the list of modules from a text file `modulelist.txt` that should be uploaded to the device.
8
- 2) stored the already processed modules in a text file `modulelist.done`
9
- 3) process the modules in the database:
10
- - stub the module
11
- - update the modulelist.done file
12
- - reboots the device if it runs out of memory
13
- 4) creates the modules.json
14
-
15
- If that cannot be found then only a single module (micropython) is stubbed.
16
- In order to run this on low-memory devices two additional steps are recommended:
17
- - minification, using python-minifierto reduce overall size, and remove logging overhead.
18
- - cross compilation, using mpy-cross, to avoid the compilation step on the micropython device
19
-
20
-
21
- This variant was generated from createstubs.py by micropython-stubber v1.16.3
22
- """
23
- # Copyright (c) 2019-2023 Jos Verlinde
24
-
25
- import gc
26
- # import logging
27
- import os
28
- import sys
1
+ A2='No report file'
2
+ A1='Failed to create the report.'
3
+ A0='method'
4
+ z='function'
5
+ y='bool'
6
+ x='str'
7
+ w='float'
8
+ v='int'
9
+ u='micropython'
10
+ t='stubber'
11
+ s=TypeError
12
+ r=Exception
13
+ q=KeyError
14
+ p=sorted
15
+ o=MemoryError
16
+ n=NotImplementedError
17
+ j=',\n'
18
+ i='modules.json'
19
+ h='{}/{}'
20
+ g='w'
21
+ f='dict'
22
+ e='list'
23
+ d='tuple'
24
+ c=str
25
+ b=repr
26
+ W='-preview'
27
+ V='-'
28
+ U='board'
29
+ T=IndexError
30
+ S=print
31
+ R=True
32
+ Q='family'
33
+ P=len
34
+ O=ImportError
35
+ N=dir
36
+ M=open
37
+ K='port'
38
+ J='.'
39
+ I=AttributeError
40
+ H=False
41
+ G='/'
42
+ E=None
43
+ D=OSError
44
+ C='version'
45
+ B=''
46
+ import gc as F,os,sys
29
47
  from time import sleep
30
-
31
- try:
32
- from ujson import dumps
33
- except:
34
- from json import dumps
35
-
36
- try:
37
- from machine import reset # type: ignore
38
- except ImportError:
39
- pass
40
-
41
- try:
42
- from collections import OrderedDict
43
- except ImportError:
44
- from ucollections import OrderedDict # type: ignore
45
-
46
- try:
47
- from nope_machine import WDT
48
-
49
- wdt = WDT()
50
-
51
- except ImportError:
52
-
53
- class _WDT:
54
- def feed(self):
55
- pass
56
-
57
- wdt = _WDT()
58
-
59
-
60
- wdt.feed()
61
-
62
- __version__ = "v1.16.3"
63
- ENOENT = 2
64
- _MAX_CLASS_LEVEL = 2 # Max class nesting
65
- LIBS = [".", "/lib", "/sd/lib", "/flash/lib", "lib"]
66
-
67
-
48
+ try:from ujson import dumps
49
+ except:from json import dumps
50
+ try:from machine import reset
51
+ except O:pass
52
+ try:from collections import OrderedDict as k
53
+ except O:from ucollections import OrderedDict as k
54
+ __version__='v1.17.0'
55
+ A3=2
56
+ A4=2
57
+ A5=['lib','/lib','/sd/lib','/flash/lib',J]
58
+ class L:
59
+ INFO=20;WARNING=30;ERROR=40;level=INFO;prnt=S
60
+ @staticmethod
61
+ def getLogger(name):return L()
62
+ @classmethod
63
+ def basicConfig(A,level):A.level=level
64
+ def info(A,msg):
65
+ if A.level<=L.INFO:A.prnt('INFO :',msg)
66
+ def warning(A,msg):
67
+ if A.level<=L.WARNING:A.prnt('WARN :',msg)
68
+ def error(A,msg):
69
+ if A.level<=L.ERROR:A.prnt('ERROR :',msg)
70
+ A=L.getLogger(t)
71
+ L.basicConfig(level=L.INFO)
68
72
  class Stubber:
69
- "Generate stubs for modules in firmware"
70
-
71
- def __init__(self, path: str = None, firmware_id: str = None): # type: ignore
72
- try:
73
- if os.uname().release == "1.13.0" and os.uname().version < "v1.13-103": # type: ignore
74
- raise NotImplementedError("MicroPython 1.13.0 cannot be stubbed")
75
- except AttributeError:
76
- pass
77
- # self.log = logging.getLogger("stubber")
78
- self._report = [] # type: list[str]
79
- self.info = _info()
80
- # self.log.info("Port: {}".format(self.info["port"]))
81
- # self.log.info("Board: {}".format(self.info["board"]))
82
- gc.collect()
83
- wdt.feed()
84
- if firmware_id:
85
- self._fwid = firmware_id.lower()
86
- else:
87
- if self.info["family"] == "micropython":
88
- self._fwid = "{family}-v{version}-{port}-{board}".format(**self.info).rstrip("-")
89
- else:
90
- self._fwid = "{family}-v{version}-{port}".format(**self.info)
91
- self._start_free = gc.mem_free() # type: ignore
92
-
93
- if path:
94
- if path.endswith("/"):
95
- path = path[:-1]
96
- else:
97
- path = get_root()
98
-
99
- self.path = "{}/stubs/{}".format(path, self.flat_fwid).replace("//", "/")
100
- # self.log.debug(self.path)
101
- try:
102
- ensure_folder(path + "/")
103
- except OSError:
104
- print("error creating stub folder {}".format(path))
105
- self.problematic = [
106
- "upip",
107
- "upysh",
108
- "webrepl_setup",
109
- "http_client",
110
- "http_client_ssl",
111
- "http_server",
112
- "http_server_ssl",
113
- ]
114
- self.excluded = [
115
- "webrepl",
116
- "_webrepl",
117
- "port_diag",
118
- "example_sub_led.py",
119
- "example_pub_button.py",
120
- ]
121
- # there is no option to discover modules from micropython, list is read from an external file.
122
- self.modules = [] # type: list[str]
123
-
124
- def get_obj_attributes(self, item_instance: object):
125
- "extract information of the objects members and attributes"
126
- # name_, repr_(value), type as text, item_instance
127
- _result = []
128
- _errors = []
129
- # self.log.debug("get attributes {} {}".format(repr(item_instance), item_instance))
130
- for name in dir(item_instance):
131
- if name.startswith("_") and not name in self.modules:
132
- continue
133
- # self.log.debug("get attribute {}".format(name))
134
- try:
135
- val = getattr(item_instance, name)
136
- # name , item_repr(value) , type as text, item_instance, order
137
- # self.log.debug("attribute {}:{}".format(name, val))
138
- try:
139
- type_text = repr(type(val)).split("'")[1]
140
- except IndexError:
141
- type_text = ""
142
- if type_text in {"int", "float", "str", "bool", "tuple", "list", "dict"}:
143
- order = 1
144
- elif type_text in {"function", "method"}:
145
- order = 2
146
- elif type_text in ("class"):
147
- order = 3
148
- else:
149
- order = 4
150
- _result.append((name, repr(val), repr(type(val)), val, order))
151
- except AttributeError as e:
152
- _errors.append("Couldn't get attribute '{}' from object '{}', Err: {}".format(name, item_instance, e))
153
- except MemoryError as e:
154
- # print("MemoryError: {}".format(e))
155
- sleep(1)
156
- reset()
157
-
158
- # remove internal __
159
- # _result = sorted([i for i in _result if not (i[0].startswith("_"))], key=lambda x: x[4])
160
- _result = sorted([i for i in _result if not (i[0].startswith("__"))], key=lambda x: x[4])
161
- gc.collect()
162
- return _result, _errors
163
-
164
- def add_modules(self, modules):
165
- "Add additional modules to be exported"
166
- self.modules = sorted(set(self.modules) | set(modules))
167
-
168
- def create_all_stubs(self):
169
- "Create stubs for all configured modules"
170
- # self.log.info("Start micropython-stubber v{} on {}".format(__version__, self._fwid))
171
- gc.collect()
172
- for module_name in self.modules:
173
- self.create_one_stub(module_name)
174
- # self.log.info("Finally done")
175
-
176
- def create_one_stub(self, module_name: str):
177
- wdt.feed()
178
- if module_name in self.problematic:
179
- # self.log.warning("Skip module: {:<25} : Known problematic".format(module_name))
180
- return False
181
- if module_name in self.excluded:
182
- # self.log.warning("Skip module: {:<25} : Excluded".format(module_name))
183
- return False
184
-
185
- file_name = "{}/{}.py".format(self.path, module_name.replace(".", "/"))
186
- gc.collect()
187
- result = False
188
- try:
189
- result = self.create_module_stub(module_name, file_name)
190
- except OSError:
191
- return False
192
- gc.collect()
193
- return result
194
-
195
- def create_module_stub(self, module_name: str, file_name: str = None) -> bool: # type: ignore
196
- """Create a Stub of a single python module
197
-
198
- Args:
199
- - module_name (str): name of the module to document. This module will be imported.
200
- - file_name (Optional[str]): the 'path/filename.py' to write to. If omitted will be created based on the module name.
201
- """
202
- if file_name is None:
203
- fname = module_name.replace(".", "_") + ".py"
204
- file_name = self.path + "/" + fname
205
- else:
206
- fname = file_name.split("/")[-1]
207
-
208
- if "/" in module_name:
209
- # for nested modules
210
- module_name = module_name.replace("/", ".")
211
-
212
- # import the module (as new_module) to examine it
213
- new_module = None
214
- try:
215
- new_module = __import__(module_name, None, None, ("*"))
216
- m1 = gc.mem_free() # type: ignore
217
- # self.log.info("Stub module: {:<25} to file: {:<70} mem:{:>5}".format(module_name, fname, m1))
218
-
219
- except ImportError:
220
- # self.log.warning("Skip module: {:<25} {:<79}".format(module_name, "Module not found."))
221
- return False
222
-
223
- # Start a new file
224
- ensure_folder(file_name)
225
- with open(file_name, "w") as fp:
226
- # todo: improve header
227
- info_ = str(self.info).replace("OrderedDict(", "").replace("})", "}")
228
- s = '"""\nModule: \'{0}\' on {1}\n"""\n# MCU: {2}\n# Stubber: {3}\n'.format(module_name, self._fwid, info_, __version__)
229
- fp.write(s)
230
- fp.write("from __future__ import annotations\nfrom typing import Any\nfrom _typeshed import Incomplete\n\n")
231
- self.write_object_stub(fp, new_module, module_name, "")
232
-
233
- self._report.append('{{"module": "{}", "file": "{}"}}'.format(module_name, file_name.replace("\\", "/")))
234
-
235
- if module_name not in {"os", "sys", "logging", "gc"}:
236
- # try to unload the module unless we use it
237
- try:
238
- del new_module
239
- except (OSError, KeyError): # lgtm [py/unreachable-statement]
240
- pass
241
- # lets not try - most times it does not work anyway
242
- # try:
243
- # del sys.modules[module_name]
244
- # except KeyError:
245
- pass
246
- gc.collect()
247
- return True
248
-
249
- def write_object_stub(self, fp, object_expr: object, obj_name: str, indent: str, in_class: int = 0):
250
- "Write a module/object stub to an open file. Can be called recursive."
251
- gc.collect()
252
- if object_expr in self.problematic:
253
- # self.log.warning("SKIPPING problematic module:{}".format(object_expr))
254
- return
255
-
256
- # # self.log.debug("DUMP : {}".format(object_expr))
257
- items, errors = self.get_obj_attributes(object_expr)
258
-
259
- if errors:
260
- print(errors)
261
-
262
- for item_name, item_repr, item_type_txt, item_instance, _ in items:
263
- # name_, repr_(value), type as text, item_instance, order
264
- if item_name in ["classmethod", "staticmethod", "BaseException", "Exception"]:
265
- # do not create stubs for these primitives
266
- continue
267
- if item_name[0].isdigit():
268
- # self.log.warning("NameError: invalid name {}".format(item_name))
269
- continue
270
- # Class expansion only on first 3 levels (bit of a hack)
271
- if (
272
- item_type_txt == "<class 'type'>"
273
- and len(indent) <= _MAX_CLASS_LEVEL * 4
274
- # and not obj_name.endswith(".Pin")
275
- # avoid expansion of Pin.cpu / Pin.board to avoid crashes on most platforms
276
- ):
277
- # self.log.info("{0}class {1}:".format(indent, item_name))
278
- superclass = ""
279
- is_exception = (
280
- item_name.endswith("Exception")
281
- or item_name.endswith("Error")
282
- or item_name
283
- in [
284
- "KeyboardInterrupt",
285
- "StopIteration",
286
- "SystemExit",
287
- ]
288
- )
289
- if is_exception:
290
- superclass = "Exception"
291
- s = "\n{}class {}({}):\n".format(indent, item_name, superclass)
292
- # s += indent + " ''\n"
293
- if is_exception:
294
- s += indent + " ...\n"
295
- fp.write(s)
296
- continue
297
- # write classdef
298
- fp.write(s)
299
- # first write the class literals and methods
300
- # self.log.debug("# recursion over class {0}".format(item_name))
301
- self.write_object_stub(
302
- fp,
303
- item_instance,
304
- "{0}.{1}".format(obj_name, item_name),
305
- indent + " ",
306
- in_class + 1,
307
- )
308
- # end with the __init__ method to make sure that the literals are defined
309
- # Add __init__
310
- s = indent + " def __init__(self, *argv, **kwargs) -> None:\n"
311
- s += indent + " ...\n\n"
312
- fp.write(s)
313
- elif any(word in item_type_txt for word in ["method", "function", "closure"]):
314
- # self.log.debug("# def {1} function/method/closure, type = '{0}'".format(item_type_txt, item_name))
315
- # module Function or class method
316
- # will accept any number of params
317
- # return type Any/Incomplete
318
- ret = "Incomplete"
319
- first = ""
320
- # Self parameter only on class methods/functions
321
- if in_class > 0:
322
- first = "self, "
323
- # class method - add function decoration
324
- if "bound_method" in item_type_txt or "bound_method" in item_repr:
325
- s = "{}@classmethod\n".format(indent) + "{}def {}(cls, *args, **kwargs) -> {}:\n".format(indent, item_name, ret)
326
- else:
327
- s = "{}def {}({}*args, **kwargs) -> {}:\n".format(indent, item_name, first, ret)
328
- s += indent + " ...\n\n"
329
- fp.write(s)
330
- # self.log.debug("\n" + s)
331
- elif item_type_txt == "<class 'module'>":
332
- # Skip imported modules
333
- # fp.write("# import {}\n".format(item_name))
334
- pass
335
-
336
- elif item_type_txt.startswith("<class '"):
337
- t = item_type_txt[8:-2]
338
- s = ""
339
-
340
- if t in ["str", "int", "float", "bool", "bytearray", "bytes"]:
341
- # known type: use actual value
342
- s = "{0}{1} = {2} # type: {3}\n".format(indent, item_name, item_repr, t)
343
- elif t in ["dict", "list", "tuple"]:
344
- # dict, list , tuple: use empty value
345
- ev = {"dict": "{}", "list": "[]", "tuple": "()"}
346
- s = "{0}{1} = {2} # type: {3}\n".format(indent, item_name, ev[t], t)
347
- else:
348
- # something else
349
- if t in ["object", "set", "frozenset", "Pin", "FileIO"]:
350
- # https://docs.python.org/3/tutorial/classes.html#item_instance-objects
351
- # use these types for the attribute
352
- s = "{0}{1} : {2} ## = {4}\n".format(indent, item_name, t, item_type_txt, item_repr)
353
- else:
354
- # Requires Python 3.6 syntax, which is OK for the stubs/pyi
355
- t = "Incomplete"
356
- s = "{0}{1} : {2} ## {3} = {4}\n".format(indent, item_name, t, item_type_txt, item_repr)
357
- fp.write(s)
358
- # self.log.debug("\n" + s)
359
- else:
360
- # keep only the name
361
- # self.log.debug("# all other, type = '{0}'".format(item_type_txt))
362
- fp.write("# all other, type = '{0}'\n".format(item_type_txt))
363
-
364
- fp.write(indent + item_name + " # type: Incomplete\n")
365
-
366
- # del items
367
- # del errors
368
- # try:
369
- # del item_name, item_repr, item_type_txt, item_instance # type: ignore
370
- # except (OSError, KeyError, NameError):
371
- # pass
372
-
373
- @property
374
- def flat_fwid(self):
375
- "Turn _fwid from 'v1.2.3' into '1_2_3' to be used in filename"
376
- s = self._fwid
377
- # path name restrictions
378
- chars = " .()/\\:$"
379
- for c in chars:
380
- s = s.replace(c, "_")
381
- return s
382
-
383
- def clean(self, path: str = None): # type: ignore
384
- "Remove all files from the stub folder"
385
- wdt.feed()
386
- if path is None:
387
- path = self.path
388
- # self.log.info("Clean/remove files in folder: {}".format(path))
389
- try:
390
- os.stat(path) # TEMP workaround mpremote listdir bug -
391
- items = os.listdir(path)
392
- except (OSError, AttributeError):
393
- # os.listdir fails on unix
394
- return
395
- for fn in items:
396
- item = "{}/{}".format(path, fn)
397
- try:
398
- os.remove(item)
399
- except OSError:
400
- try: # folder
401
- self.clean(item)
402
- os.rmdir(item)
403
- except OSError:
404
- pass
405
-
406
- def report(self, filename: str = "modules.json"):
407
- "create json with list of exported modules"
408
- wdt.feed()
409
- # self.log.info("Created stubs for {} modules on board {}\nPath: {}".format(len(self._report), self._fwid, self.path))
410
- f_name = "{}/{}".format(self.path, filename)
411
- # self.log.info("Report file: {}".format(f_name))
412
- gc.collect()
413
- try:
414
- # write json by node to reduce memory requirements
415
- with open(f_name, "w") as f:
416
- self.write_json_header(f)
417
- first = True
418
- for n in self._report:
419
- self.write_json_node(f, n, first)
420
- first = False
421
- self.write_json_end(f)
422
- used = self._start_free - gc.mem_free() # type: ignore
423
- # self.log.info("Memory used: {0} Kb".format(used // 1024))
424
- except OSError:
425
- print("Failed to create the report.")
426
-
427
- def write_json_header(self, f):
428
- f.write("{")
429
- f.write(dumps({"firmware": self.info})[1:-1])
430
- f.write(",\n")
431
- f.write(dumps({"stubber": {"version": __version__}, "stubtype": "firmware"})[1:-1])
432
- f.write(",\n")
433
- f.write('"modules" :[\n')
434
-
435
- def write_json_node(self, f, n, first):
436
- if not first:
437
- f.write(",\n")
438
- f.write(n)
439
-
440
- def write_json_end(self, f):
441
- f.write("\n]}")
442
-
443
-
444
- def ensure_folder(path: str):
445
- "Create nested folders if needed"
446
- i = start = 0
447
- while i != -1:
448
- i = path.find("/", start)
449
- if i != -1:
450
- p = path[0] if i == 0 else path[:i]
451
- # p = partial folder
452
- try:
453
- _ = os.stat(p)
454
- except OSError as e:
455
- # folder does not exist
456
- if e.args[0] == ENOENT:
457
- try:
458
- os.mkdir(p)
459
- except OSError as e2:
460
- print("failed to create folder {}".format(p))
461
- raise e2
462
- # next level deep
463
- start = i + 1
464
-
465
-
466
- def _build(s):
467
- # extract build from sys.version or os.uname().version if available
468
- # sys.version: 'MicroPython v1.23.0-preview.6.g3d0b6276f'
469
- # sys.implementation.version: 'v1.13-103-gb137d064e'
470
- if not s:
471
- return ""
472
- s = s.split(" on ", 1)[0] if " on " in s else s
473
- if s.startswith("v"):
474
- if not "-" in s:
475
- return ""
476
- b = s.split("-")[1]
477
- return b
478
- if not "-preview" in s:
479
- return ""
480
- b = s.split("-preview")[1].split(".")[1]
481
- return b
482
-
483
-
484
- def _info(): # type:() -> dict[str, str]
485
- info = OrderedDict(
486
- {
487
- "family": sys.implementation.name,
488
- "version": "",
489
- "build": "",
490
- "ver": "",
491
- "port": sys.platform, # port: esp32 / win32 / linux / stm32
492
- "board": "UNKNOWN",
493
- "cpu": "",
494
- "mpy": "",
495
- "arch": "",
496
- }
497
- )
498
- # change port names to be consistent with the repo
499
- if info["port"].startswith("pyb"):
500
- info["port"] = "stm32"
501
- elif info["port"] == "win32":
502
- info["port"] = "windows"
503
- elif info["port"] == "linux":
504
- info["port"] = "unix"
505
- try:
506
- info["version"] = version_str(sys.implementation.version) # type: ignore
507
- except AttributeError:
508
- pass
509
- try:
510
- _machine = sys.implementation._machine if "_machine" in dir(sys.implementation) else os.uname().machine # type: ignore
511
- # info["board"] = "with".join(_machine.split("with")[:-1]).strip()
512
- info["board"] = _machine
513
- info["cpu"] = _machine.split("with")[-1].strip()
514
- info["mpy"] = (
515
- sys.implementation._mpy
516
- if "_mpy" in dir(sys.implementation)
517
- else sys.implementation.mpy
518
- if "mpy" in dir(sys.implementation)
519
- else ""
520
- )
521
- except (AttributeError, IndexError):
522
- pass
523
- gc.collect()
524
- read_boardname(info)
525
- gc.collect()
526
-
527
- try:
528
- if "uname" in dir(os): # old
529
- # extract build from uname().version if available
530
- info["build"] = _build(os.uname()[3]) # type: ignore
531
- if not info["build"]:
532
- # extract build from uname().release if available
533
- info["build"] = _build(os.uname()[2]) # type: ignore
534
- elif "version" in dir(sys): # new
535
- # extract build from sys.version if available
536
- info["build"] = _build(sys.version)
537
- except (AttributeError, IndexError, TypeError):
538
- pass
539
- # avoid build hashes
540
- # if info["build"] and len(info["build"]) > 5:
541
- # info["build"] = ""
542
-
543
- if info["version"] == "" and sys.platform not in ("unix", "win32"):
544
- try:
545
- u = os.uname() # type: ignore
546
- info["version"] = u.release
547
- except (IndexError, AttributeError, TypeError):
548
- pass
549
- # detect families
550
- for fam_name, mod_name, mod_thing in [
551
- ("pycopy", "pycopy", "const"),
552
- ("pycom", "pycom", "FAT"),
553
- ("ev3-pybricks", "pybricks.hubs", "EV3Brick"),
554
- ]:
555
- try:
556
- _t = __import__(mod_name, None, None, (mod_thing))
557
- info["family"] = fam_name
558
- del _t
559
- break
560
- except (ImportError, KeyError):
561
- pass
562
-
563
- if info["family"] == "ev3-pybricks":
564
- info["release"] = "2.0.0"
565
-
566
- if info["family"] == "micropython":
567
- info["version"]
568
- if (
569
- info["version"]
570
- and info["version"].endswith(".0")
571
- and info["version"] >= "1.10.0" # versions from 1.10.0 to 1.20.0 do not have a micro .0
572
- and info["version"] <= "1.19.9"
573
- ):
574
- # versions from 1.10.0 to 1.20.0 do not have a micro .0
575
- info["version"] = info["version"][:-2]
576
-
577
- # spell-checker: disable
578
- if "mpy" in info and info["mpy"]: # mpy on some v1.11+ builds
579
- sys_mpy = int(info["mpy"])
580
- # .mpy architecture
581
- arch = [
582
- None,
583
- "x86",
584
- "x64",
585
- "armv6",
586
- "armv6m",
587
- "armv7m",
588
- "armv7em",
589
- "armv7emsp",
590
- "armv7emdp",
591
- "xtensa",
592
- "xtensawin",
593
- ][sys_mpy >> 10]
594
- if arch:
595
- info["arch"] = arch
596
- # .mpy version.minor
597
- info["mpy"] = "v{}.{}".format(sys_mpy & 0xFF, sys_mpy >> 8 & 3)
598
- if info["build"] and not info["version"].endswith("-preview"):
599
- info["version"] = info["version"] + "-preview"
600
- # simple to use version[-build] string
601
- info["ver"] = f"{info['version']}-{info['build']}" if info["build"] else f"{info['version']}"
602
-
603
- return info
604
-
605
-
606
- def version_str(version: tuple): # -> str:
607
- v_str = ".".join([str(n) for n in version[:3]])
608
- if len(version) > 3 and version[3]:
609
- v_str += "-" + version[3]
610
- return v_str
611
-
612
-
613
- def read_boardname(info, desc: str = ""):
614
- info["board"] = info["board"].replace(" ", "_")
615
- found = False
616
- for filename in [d + "/board_name.txt" for d in LIBS]:
617
- wdt.feed()
618
- # # print("look up the board name in the file", filename)
619
- if file_exists(filename):
620
- with open(filename, "r") as file:
621
- data = file.read()
622
- if data:
623
- info["board"] = data.strip()
624
- found = True
625
- break
626
- if not found:
627
- # print("Board not found, guessing board name")
628
- descr = ""
629
- # descr = desc or info["board"].strip()
630
- # if "with " + info["cpu"].upper() in descr:
631
- # # remove the with cpu part
632
- # descr = descr.split("with " + info["cpu"].upper())[0].strip()
633
- info["board"] = descr
634
-
635
-
636
- # def read_boardname(info, desc: str = ""):
637
- # wdt.feed()
638
- # # # print("look up the board name in the file", filename)
639
- # if file_exists(filename):
640
- # descr = desc or info["board"].strip()
641
- # pos = descr.rfind(" with")
642
- # if pos != -1:
643
- # short_descr = descr[:pos].strip()
644
- # else:
645
- # short_descr = ""
646
- # # print("searching info file: {} for: '{}' or '{}'".format(filename, descr, short_descr))
647
- # if find_board(info, descr, filename, short_descr):
648
- # found = True
649
- # break
650
- # if not found:
651
- # # print("Board not found, guessing board name")
652
- # descr = desc or info["board"].strip()
653
- # if "with " + info["cpu"].upper() in descr:
654
- # # remove the with cpu part
655
- # descr = descr.split("with " + info["cpu"].upper())[0].strip()
656
- # info["board"] = descr
657
- # info["board"] = info["board"].replace(" ", "_")
658
- # gc.collect()
659
-
660
-
661
- # def find_board(info: dict, descr: str, filename: str, short_descr: str):
662
- # "Find the board in the provided board_info.csv file"
663
- # short_hit = ""
664
- # with open(filename, "r") as file:
665
- # # ugly code to make testable in python and micropython
666
- # # TODO: This is VERY slow on micropython whith MPREMOTE mount on esp32 (2-3 minutes to read file)
667
- # while 1:
668
- # line = file.readline()
669
- # if not line:
670
- # break
671
- # descr_, board_ = line.split(",")[0].strip(), line.split(",")[1].strip()
672
- # if descr_ == descr:
673
- # info["board"] = board_
674
- # return True
675
- # elif short_descr and descr_ == short_descr:
676
- # if "with" in short_descr:
677
- # # Good enough - no need to trawl the entire file
678
- # info["board"] = board_
679
- # return True
680
- # # good enough if not found in the rest of the file (but slow)
681
- # short_hit = board_
682
- # if short_hit:
683
- # info["board"] = short_hit
684
- # return True
685
- # return False
686
-
687
-
688
- def get_root() -> str: # sourcery skip: use-assigned-variable
689
- "Determine the root folder of the device"
690
- try:
691
- c = os.getcwd()
692
- except (OSError, AttributeError):
693
- # unix port
694
- c = "."
695
- r = c
696
- for r in [c, "/sd", "/flash", "/", "."]:
697
- try:
698
- _ = os.stat(r)
699
- break
700
- except OSError:
701
- continue
702
- return r
703
-
704
-
705
- def file_exists(filename: str):
706
- try:
707
- if os.stat(filename)[0] >> 14:
708
- return True
709
- return False
710
- except OSError:
711
- return False
712
-
713
-
714
- def show_help():
715
- # print("-p, --path path to store the stubs in, defaults to '.'")
716
- sys.exit(1)
717
-
718
-
719
- def read_path() -> str:
720
- "get --path from cmdline. [unix/win]"
721
- path = ""
722
- if len(sys.argv) == 3:
723
- cmd = (sys.argv[1]).lower()
724
- if cmd in ("--path", "-p"):
725
- path = sys.argv[2]
726
- else:
727
- show_help()
728
- elif len(sys.argv) == 2:
729
- show_help()
730
- return path
731
-
732
-
733
- def is_micropython() -> bool:
734
- "runtime test to determine full or micropython"
735
- # pylint: disable=unused-variable,eval-used
736
- try:
737
- # either test should fail on micropython
738
- # a) https://docs.micropython.org/en/latest/genrst/syntax.html#spaces
739
- # Micropython : SyntaxError
740
- # a = eval("1and 0") # lgtm [py/unused-local-variable]
741
- # Eval blocks some minification aspects
742
-
743
- # b) https://docs.micropython.org/en/latest/genrst/builtin_types.html#bytes-with-keywords-not-implemented
744
- # Micropython: NotImplementedError
745
- b = bytes("abc", encoding="utf8") # type: ignore # lgtm [py/unused-local-variable]
746
-
747
- # c) https://docs.micropython.org/en/latest/genrst/core_language.html#function-objects-do-not-have-the-module-attribute
748
- # Micropython: AttributeError
749
- c = is_micropython.__module__ # type: ignore # lgtm [py/unused-local-variable]
750
- return False
751
- except (NotImplementedError, AttributeError):
752
- return True
753
-
754
-
73
+ def __init__(B,path=E,firmware_id=E):
74
+ C=firmware_id
75
+ try:
76
+ if os.uname().release=='1.13.0'and os.uname().version<'v1.13-103':raise n('MicroPython 1.13.0 cannot be stubbed')
77
+ except I:pass
78
+ B.info=_info();A.info('Port: {}'.format(B.info[K]));A.info('Board: {}'.format(B.info[U]));F.collect()
79
+ if C:B._fwid=C.lower()
80
+ elif B.info[Q]==u:B._fwid='{family}-v{version}-{port}-{board}'.format(**B.info).rstrip(V)
81
+ else:B._fwid='{family}-v{version}-{port}'.format(**B.info)
82
+ B._start_free=F.mem_free()
83
+ if path:
84
+ if path.endswith(G):path=path[:-1]
85
+ else:path=get_root()
86
+ B.path='{}/stubs/{}'.format(path,B.flat_fwid).replace('//',G)
87
+ try:X(path+G)
88
+ except D:A.error('error creating stub folder {}'.format(path))
89
+ 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
90
+ def get_obj_attributes(L,item_instance):
91
+ H=item_instance;C=[];K=[]
92
+ for A in N(H):
93
+ if A.startswith('__')and not A in L.modules:continue
94
+ try:
95
+ D=getattr(H,A)
96
+ try:E=b(type(D)).split("'")[1]
97
+ except T:E=B
98
+ if E in{v,w,x,y,d,e,f}:G=1
99
+ elif E in{z,A0}:G=2
100
+ elif E in'class':G=3
101
+ else:G=4
102
+ C.append((A,b(D),b(type(D)),D,G))
103
+ except I as J:K.append("Couldn't get attribute '{}' from object '{}', Err: {}".format(A,H,J))
104
+ except o as J:S('MemoryError: {}'.format(J));sleep(1);reset()
105
+ C=p([A for A in C if not A[0].startswith('__')],key=lambda x:x[4]);F.collect();return C,K
106
+ def add_modules(A,modules):A.modules=p(set(A.modules)|set(modules))
107
+ def create_all_stubs(B):
108
+ A.info('Start micropython-stubber {} on {}'.format(__version__,B._fwid));B.report_start();F.collect()
109
+ for C in B.modules:B.create_one_stub(C)
110
+ B.report_end();A.info('Finally done')
111
+ def create_one_stub(C,module_name):
112
+ B=module_name
113
+ if B in C.problematic:A.warning('Skip module: {:<25} : Known problematic'.format(B));return H
114
+ if B in C.excluded:A.warning('Skip module: {:<25} : Excluded'.format(B));return H
115
+ I='{}/{}.pyi'.format(C.path,B.replace(J,G));F.collect();E=H
116
+ try:E=C.create_module_stub(B,I)
117
+ except D:return H
118
+ F.collect();return E
119
+ def create_module_stub(K,module_name,file_name=E):
120
+ I=file_name;C=module_name
121
+ if I is E:L=C.replace(J,'_')+'.pyi';I=K.path+G+L
122
+ else:L=I.split(G)[-1]
123
+ if G in C:C=C.replace(G,J)
124
+ N=E
125
+ try:N=__import__(C,E,E,'*');Q=F.mem_free();A.info('Stub module: {:<25} to file: {:<70} mem:{:>5}'.format(C,L,Q))
126
+ except O:return H
127
+ X(I)
128
+ with M(I,g)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)
129
+ K.report_add(C,I)
130
+ if C not in{'os','sys','logging','gc'}:
131
+ try:del N
132
+ except(D,q):A.warning('could not del new_module')
133
+ F.collect();return R
134
+ def write_object_stub(K,fp,object_expr,obj_name,indent,in_class=0):
135
+ X='generator';W='{0}{1}: {3} = {2}\n';V='bound_method';U='Incomplete';N=in_class;M='Exception';L=object_expr;I=fp;D=indent;F.collect()
136
+ if L in K.problematic:A.warning('SKIPPING problematic module:{}'.format(L));return
137
+ Y,O=K.get_obj_attributes(L)
138
+ if O:A.error(O)
139
+ for(E,J,H,Z,b)in Y:
140
+ if E in['classmethod','staticmethod','BaseException',M]:continue
141
+ if E[0].isdigit():A.warning('NameError: invalid name {}'.format(E));continue
142
+ if H=="<class 'type'>"and P(D)<=A4*4:
143
+ Q=B;R=E.endswith(M)or E.endswith('Error')or E in['KeyboardInterrupt','StopIteration','SystemExit']
144
+ if R:Q=M
145
+ C='\n{}class {}({}):\n'.format(D,E,Q)
146
+ if R:C+=D+' ...\n';I.write(C);continue
147
+ I.write(C);K.write_object_stub(I,Z,'{0}.{1}'.format(obj_name,E),D+' ',N+1);C=D+' def __init__(self, *argv, **kwargs) -> None:\n';C+=D+' ...\n\n';I.write(C)
148
+ elif any(A in H for A in[A0,z,'closure']):
149
+ S=U;T=B
150
+ if N>0:T='self, '
151
+ if V in H or V in J:C='{}@classmethod\n'.format(D)+'{}def {}(cls, *args, **kwargs) -> {}:\n'.format(D,E,S)
152
+ else:C='{}def {}({}*args, **kwargs) -> {}:\n'.format(D,E,T,S)
153
+ C+=D+' ...\n\n';I.write(C)
154
+ elif H=="<class 'module'>":0
155
+ elif H.startswith("<class '"):
156
+ G=H[8:-2];C=B
157
+ if G in(x,v,w,y,'bytearray','bytes'):C=W.format(D,E,J,G)
158
+ elif G in(f,e,d):a={f:'{}',e:'[]',d:'()'};C=W.format(D,E,a[G],G)
159
+ elif G in('object','set','frozenset','Pin',X):
160
+ if G==X:G='Generator'
161
+ C='{0}{1}: {2} ## = {4}\n'.format(D,E,G,H,J)
162
+ else:G=U;C='{0}{1}: {2} ## {3} = {4}\n'.format(D,E,G,H,J)
163
+ I.write(C)
164
+ else:I.write("# all other, type = '{0}'\n".format(H));I.write(D+E+' # type: Incomplete\n')
165
+ @property
166
+ def flat_fwid(self):
167
+ A=self._fwid;B=' .()/\\:$'
168
+ for C in B:A=A.replace(C,'_')
169
+ return A
170
+ def clean(C,path=E):
171
+ if path is E:path=C.path
172
+ A.info('Clean/remove files in folder: {}'.format(path))
173
+ try:os.stat(path);F=os.listdir(path)
174
+ except(D,I):return
175
+ for G in F:
176
+ B=h.format(path,G)
177
+ try:os.remove(B)
178
+ except D:
179
+ try:C.clean(B);os.rmdir(B)
180
+ except D:pass
181
+ def report_start(B,filename=i):
182
+ H='firmware';B._json_name=h.format(B.path,filename);B._json_first=R;X(B._json_name);A.info('Report file: {}'.format(B._json_name));F.collect()
183
+ try:
184
+ with M(B._json_name,g)as G:G.write('{');G.write(dumps({H:B.info})[1:-1]);G.write(j);G.write(dumps({t:{C:__version__},'stubtype':H})[1:-1]);G.write(j);G.write('"modules" :[\n')
185
+ except D as I:A.error(A1);B._json_name=E;raise I
186
+ def report_add(B,module_name,stub_file):
187
+ if not B._json_name:raise r(A2)
188
+ try:
189
+ with M(B._json_name,'a')as C:
190
+ if not B._json_first:C.write(j)
191
+ else:B._json_first=H
192
+ E='{{"module": "{}", "file": "{}"}}'.format(module_name,stub_file.replace('\\',G));C.write(E)
193
+ except D:A.error(A1)
194
+ def report_end(B):
195
+ if not B._json_name:raise r(A2)
196
+ with M(B._json_name,'a')as C:C.write('\n]}')
197
+ A.info('Path: {}'.format(B.path))
198
+ def X(path):
199
+ B=E=0
200
+ while B!=-1:
201
+ B=path.find(G,E)
202
+ if B!=-1:
203
+ C=path[0]if B==0 else path[:B]
204
+ try:I=os.stat(C)
205
+ except D as F:
206
+ if F.args[0]==A3:
207
+ try:os.mkdir(C)
208
+ except D as H:A.error('failed to create folder {}'.format(C));raise H
209
+ E=B+1
210
+ def Y(s):
211
+ C=' on '
212
+ if not s:return B
213
+ s=s.split(C,1)[0]if C in s else s
214
+ if s.startswith('v'):
215
+ if not V in s:return B
216
+ A=s.split(V)[1];return A
217
+ if not W in s:return B
218
+ A=s.split(W)[1].split(J)[1];return A
219
+ def _info():
220
+ Z='ev3-pybricks';X='pycom';V='pycopy';S='unix';R='win32';P='arch';M='cpu';L='ver';F='mpy';D='build';A=k({Q:sys.implementation.name,C:B,D:B,L:B,K:sys.platform,U:'UNKNOWN',M:B,F:B,P:B})
221
+ if A[K].startswith('pyb'):A[K]='stm32'
222
+ elif A[K]==R:A[K]='windows'
223
+ elif A[K]=='linux':A[K]=S
224
+ try:A[C]=A6(sys.implementation.version)
225
+ except I:pass
226
+ try:H=sys.implementation._machine if'_machine'in N(sys.implementation)else os.uname().machine;A[U]=H;A[M]=H.split('with')[-1].strip();A[F]=sys.implementation._mpy if'_mpy'in N(sys.implementation)else sys.implementation.mpy if F in N(sys.implementation)else B
227
+ except(I,T):pass
228
+ A[U]=A7()
229
+ try:
230
+ if'uname'in N(os):
231
+ A[D]=Y(os.uname()[3])
232
+ if not A[D]:A[D]=Y(os.uname()[2])
233
+ elif C in N(sys):A[D]=Y(sys.version)
234
+ except(I,T,s):pass
235
+ if A[C]==B and sys.platform not in(S,R):
236
+ try:a=os.uname();A[C]=a.release
237
+ except(T,I,s):pass
238
+ for(b,c,d)in[(V,V,'const'),(X,X,'FAT'),(Z,'pybricks.hubs','EV3Brick')]:
239
+ try:e=__import__(c,E,E,d);A[Q]=b;del e;break
240
+ except(O,q):pass
241
+ if A[Q]==Z:A['release']='2.0.0'
242
+ if A[Q]==u:
243
+ A[C]
244
+ if A[C]and A[C].endswith('.0')and A[C]>='1.10.0'and A[C]<='1.19.9':A[C]=A[C][:-2]
245
+ if F in A and A[F]:
246
+ G=int(A[F]);J=[E,'x86','x64','armv6','armv6m','armv7m','armv7em','armv7emsp','armv7emdp','xtensa','xtensawin'][G>>10]
247
+ if J:A[P]=J
248
+ A[F]='v{}.{}'.format(G&255,G>>8&3)
249
+ if A[D]and not A[C].endswith(W):A[C]=A[C]+W
250
+ A[L]=f"{A[C]}-{A[D]}"if A[D]else f"{A[C]}";return A
251
+ def A6(version):
252
+ A=version;B=J.join([c(A)for A in A[:3]])
253
+ if P(A)>3 and A[3]:B+=V+A[3]
254
+ return B
255
+ def A7():
256
+ try:from boardname import BOARDNAME as C;A.info('Found BOARDNAME: {}'.format(C))
257
+ except O:A.warning('BOARDNAME not found');C=B
258
+ return C
259
+ def get_root():
260
+ try:A=os.getcwd()
261
+ except(D,I):A=J
262
+ B=A
263
+ for B in[A,'/sd','/flash',G,J]:
264
+ try:C=os.stat(B);break
265
+ except D:continue
266
+ return B
267
+ def Z(filename):
268
+ try:
269
+ if os.stat(filename)[0]>>14:return R
270
+ return H
271
+ except D:return H
272
+ def l():S("-p, --path path to store the stubs in, defaults to '.'");sys.exit(1)
273
+ def read_path():
274
+ path=B
275
+ if P(sys.argv)==3:
276
+ A=sys.argv[1].lower()
277
+ if A in('--path','-p'):path=sys.argv[2]
278
+ else:l()
279
+ elif P(sys.argv)==2:l()
280
+ return path
281
+ def m():
282
+ try:A=bytes('abc',encoding='utf8');B=m.__module__;return H
283
+ except(n,I):return R
284
+ a='modulelist.done'
285
+ def A8(skip=0):
286
+ for E in A5:
287
+ B=E+'/modulelist.txt'
288
+ if not Z(B):continue
289
+ try:
290
+ with M(B)as F:
291
+ C=0
292
+ while R:
293
+ A=F.readline().strip()
294
+ if not A:break
295
+ if P(A)>0 and A[0]=='#':continue
296
+ C+=1
297
+ if C<skip:continue
298
+ yield A
299
+ break
300
+ except D:pass
301
+ def A9(done):
302
+ with M(a,g)as A:A.write(c(done)+'\n')
303
+ def AA():
304
+ A=0
305
+ try:
306
+ with M(a)as B:A=int(B.readline().strip())
307
+ except D:pass
308
+ return A
755
309
  def main():
756
- import machine # type: ignore
757
-
758
- try:
759
- f = open("modulelist.done", "r+b")
760
- was_running = True
761
- # print("Opened existing db")
762
- except OSError:
763
- f = open("modulelist.done", "w+b")
764
- # print("created new db")
765
- was_running = False
766
- stubber = Stubber(path=read_path())
767
-
768
- # f_name = "{}/{}".format(stubber.path, "modules.json")
769
- if not was_running:
770
- # Only clean folder if this is a first run
771
- stubber.clean()
772
- # get list of modules to process
773
- get_modulelist(stubber)
774
- # remove the ones that are already done
775
- modules_done = {} # type: dict[str, str]
776
- try:
777
- with open("modulelist.done") as f:
778
- # not optimal , but works on mpremote and esp8266
779
- for line in f.read().split("\n"):
780
- line = line.strip()
781
- gc.collect()
782
- if len(line) > 0:
783
- key, value = line.split("=", 1)
784
- modules_done[key] = value
785
- except (OSError, SyntaxError):
786
- pass
787
- gc.collect()
788
- # see if we can continue from where we left off
789
- modules = [m for m in stubber.modules if m not in modules_done.keys()]
790
- gc.collect()
791
- for modulename in modules:
792
- # ------------------------------------
793
- # do epic shit
794
- # but sometimes things fail / run out of memory and reboot
795
- ok = False
796
- try:
797
- ok = stubber.create_one_stub(modulename)
798
- except MemoryError:
799
- # RESET AND HOPE THAT IN THE NEXT CYCLE WE PROGRESS FURTHER
800
- machine.reset()
801
- # -------------------------------------
802
- gc.collect()
803
- modules_done[modulename] = str(stubber._report[-1] if ok else "failed")
804
- with open("modulelist.done", "a") as f:
805
- f.write("{}={}\n".format(modulename, "ok" if ok else "failed"))
806
-
807
- # Finished processing - load all the results , and remove the failed ones
808
- if modules_done:
809
- # stubber.write_json_end(mod_fp)
810
- stubber._report = [v for _, v in modules_done.items() if v != "failed"]
811
- stubber.report()
812
-
813
-
814
- def get_modulelist(stubber):
815
- stubber.modules = [] # avoid duplicates
816
- for p in LIBS:
817
- try:
818
- with open(p + "/modulelist.txt") as f:
819
- print ("DEBUG: list of modules: " + p + "/modulelist.txt")
820
- for line in f.read().split("\n"):
821
- line = line.strip()
822
- if len(line) > 0 and line[0] != "#":
823
- stubber.modules.append(line)
824
- gc.collect()
825
- break
826
- except OSError:
827
- pass
828
- if not stubber.modules:
829
- stubber.modules = ["micropython"]
830
- _log.warn("Could not find modulelist.txt, using default modules")
831
- gc.collect()
832
-
833
-
834
- if __name__ == "__main__" or is_micropython():
835
- try:
836
- log = logging.getLogger("stubber")
837
- logging.basicConfig(level=logging.INFO)
838
- # logging.basicConfig(level=logging.DEBUG)
839
- except NameError:
840
- pass
841
- if not file_exists("no_auto_stubber.txt"):
842
- try:
843
- gc.threshold(4 * 1024) # type: ignore
844
- gc.enable()
845
- except BaseException:
846
- pass
847
- main()
310
+ import machine as D;C=Z(a)
311
+ if C:A.info('Continue from last run')
312
+ else:A.info('Starting new run')
313
+ stubber=Stubber(path=read_path());B=0
314
+ if not C:stubber.clean();stubber.report_start(i)
315
+ else:B=AA();stubber._json_name=h.format(stubber.path,i)
316
+ for E in A8(B):
317
+ try:stubber.create_one_stub(E)
318
+ except o:D.reset()
319
+ F.collect();B+=1;A9(B)
320
+ S('All modules have been processed, Finalizing report');stubber.report_end()
321
+ if __name__=='__main__'or m():
322
+ if not Z('no_auto_stubber.txt'):
323
+ try:F.threshold(4*1024);F.enable()
324
+ except BaseException:pass
325
+ main()