micropython-stubber 1.16.2__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.
- {micropython_stubber-1.16.2.dist-info → micropython_stubber-1.17.0.dist-info}/METADATA +2 -1
- {micropython_stubber-1.16.2.dist-info → micropython_stubber-1.17.0.dist-info}/RECORD +54 -54
- stubber/__init__.py +1 -1
- stubber/basicgit.py +27 -33
- stubber/board/board_info.csv +137 -103
- stubber/board/createstubs.py +222 -189
- stubber/board/createstubs_db.py +284 -214
- stubber/board/createstubs_db_min.py +286 -265
- stubber/board/createstubs_db_mpy.mpy +0 -0
- stubber/board/createstubs_lvgl.py +171 -113
- stubber/board/createstubs_lvgl_min.py +738 -275
- stubber/board/createstubs_lvgl_mpy.mpy +0 -0
- stubber/board/createstubs_mem.py +237 -174
- stubber/board/createstubs_mem_min.py +263 -247
- stubber/board/createstubs_mem_mpy.mpy +0 -0
- stubber/board/createstubs_min.py +242 -227
- stubber/board/createstubs_mpy.mpy +0 -0
- stubber/board/fw_info.py +135 -0
- stubber/board/modulelist.txt +1 -2
- stubber/codemod/_partials/__init__.py +1 -1
- stubber/codemod/_partials/db_main.py +90 -72
- stubber/codemod/_partials/modules_reader.py +29 -17
- stubber/codemod/board.py +2 -4
- stubber/codemod/enrich.py +1 -1
- stubber/commands/build_cmd.py +6 -4
- stubber/commands/get_docstubs_cmd.py +6 -11
- stubber/commands/get_frozen_cmd.py +6 -11
- stubber/commands/switch_cmd.py +6 -4
- stubber/data/board_info.csv +134 -101
- stubber/data/board_info.json +1357 -901
- stubber/freeze/freeze_manifest_2.py +2 -1
- stubber/freeze/get_frozen.py +28 -13
- stubber/minify.py +56 -43
- stubber/publish/candidates.py +15 -23
- stubber/publish/defaults.py +2 -2
- stubber/publish/merge_docstubs.py +5 -7
- stubber/publish/missing_class_methods.py +2 -2
- stubber/publish/pathnames.py +2 -2
- stubber/publish/publish.py +2 -1
- stubber/publish/stubpackage.py +20 -40
- stubber/rst/lookup.py +9 -7
- stubber/rst/reader.py +2 -1
- stubber/stubber.py +5 -6
- stubber/update_fallback.py +3 -1
- stubber/update_module_list.py +1 -1
- stubber/utils/__init__.py +1 -1
- stubber/utils/config.py +7 -9
- stubber/utils/post.py +1 -1
- stubber/utils/repos.py +10 -7
- stubber/utils/versions.py +48 -7
- stubber/variants.py +3 -3
- stubber/board/logging.py +0 -99
- {micropython_stubber-1.16.2.dist-info → micropython_stubber-1.17.0.dist-info}/LICENSE +0 -0
- {micropython_stubber-1.16.2.dist-info → micropython_stubber-1.17.0.dist-info}/WHEEL +0 -0
- {micropython_stubber-1.16.2.dist-info → micropython_stubber-1.17.0.dist-info}/entry_points.txt +0 -0
stubber/board/createstubs_db.py
CHANGED
@@ -18,16 +18,19 @@ Create stubs for (all) modules on a MicroPython board.
|
|
18
18
|
- cross compilation, using mpy-cross, to avoid the compilation step on the micropython device
|
19
19
|
|
20
20
|
|
21
|
-
This variant was generated from createstubs.py by micropython-stubber v1.
|
21
|
+
This variant was generated from createstubs.py by micropython-stubber v1.17.0
|
22
22
|
"""
|
23
23
|
# Copyright (c) 2019-2023 Jos Verlinde
|
24
24
|
|
25
25
|
import gc
|
26
|
-
import logging
|
27
26
|
import os
|
28
27
|
import sys
|
28
|
+
from time import sleep
|
29
29
|
|
30
|
-
|
30
|
+
try:
|
31
|
+
from ujson import dumps
|
32
|
+
except:
|
33
|
+
from json import dumps
|
31
34
|
|
32
35
|
try:
|
33
36
|
from machine import reset # type: ignore
|
@@ -39,11 +42,49 @@ try:
|
|
39
42
|
except ImportError:
|
40
43
|
from ucollections import OrderedDict # type: ignore
|
41
44
|
|
42
|
-
__version__ = "v1.
|
45
|
+
__version__ = "v1.17.0"
|
43
46
|
ENOENT = 2
|
44
47
|
_MAX_CLASS_LEVEL = 2 # Max class nesting
|
45
|
-
LIBS = ["
|
46
|
-
|
48
|
+
LIBS = ["lib", "/lib", "/sd/lib", "/flash/lib", "."]
|
49
|
+
|
50
|
+
|
51
|
+
# our own logging module to avoid dependency on and interfering with logging module
|
52
|
+
class logging:
|
53
|
+
# DEBUG = 10
|
54
|
+
INFO = 20
|
55
|
+
WARNING = 30
|
56
|
+
ERROR = 40
|
57
|
+
level = INFO
|
58
|
+
prnt = print
|
59
|
+
|
60
|
+
@staticmethod
|
61
|
+
def getLogger(name):
|
62
|
+
return logging()
|
63
|
+
|
64
|
+
@classmethod
|
65
|
+
def basicConfig(cls, level):
|
66
|
+
cls.level = level
|
67
|
+
|
68
|
+
# def debug(self, msg):
|
69
|
+
# if self.level <= logging.DEBUG:
|
70
|
+
# self.prnt("DEBUG :", msg)
|
71
|
+
|
72
|
+
def info(self, msg):
|
73
|
+
if self.level <= logging.INFO:
|
74
|
+
self.prnt("INFO :", msg)
|
75
|
+
|
76
|
+
def warning(self, msg):
|
77
|
+
if self.level <= logging.WARNING:
|
78
|
+
self.prnt("WARN :", msg)
|
79
|
+
|
80
|
+
def error(self, msg):
|
81
|
+
if self.level <= logging.ERROR:
|
82
|
+
self.prnt("ERROR :", msg)
|
83
|
+
|
84
|
+
|
85
|
+
log = logging.getLogger("stubber")
|
86
|
+
logging.basicConfig(level=logging.INFO)
|
87
|
+
# logging.basicConfig(level=logging.DEBUG)
|
47
88
|
|
48
89
|
|
49
90
|
class Stubber:
|
@@ -51,24 +92,21 @@ class Stubber:
|
|
51
92
|
|
52
93
|
def __init__(self, path: str = None, firmware_id: str = None): # type: ignore
|
53
94
|
try:
|
54
|
-
if os.uname().release == "1.13.0" and os.uname().version < "v1.13-103":
|
95
|
+
if os.uname().release == "1.13.0" and os.uname().version < "v1.13-103": # type: ignore
|
55
96
|
raise NotImplementedError("MicroPython 1.13.0 cannot be stubbed")
|
56
97
|
except AttributeError:
|
57
98
|
pass
|
58
|
-
self.log = None
|
59
|
-
self.log = logging.getLogger("stubber")
|
60
|
-
self._report = [] # type: list[str]
|
61
99
|
self.info = _info()
|
62
|
-
|
63
|
-
|
100
|
+
log.info("Port: {}".format(self.info["port"]))
|
101
|
+
log.info("Board: {}".format(self.info["board"]))
|
64
102
|
gc.collect()
|
65
103
|
if firmware_id:
|
66
104
|
self._fwid = firmware_id.lower()
|
67
105
|
else:
|
68
106
|
if self.info["family"] == "micropython":
|
69
|
-
self._fwid = "{family}-{
|
107
|
+
self._fwid = "{family}-v{version}-{port}-{board}".format(**self.info).rstrip("-")
|
70
108
|
else:
|
71
|
-
self._fwid = "{family}-{
|
109
|
+
self._fwid = "{family}-v{version}-{port}".format(**self.info)
|
72
110
|
self._start_free = gc.mem_free() # type: ignore
|
73
111
|
|
74
112
|
if path:
|
@@ -78,11 +116,11 @@ class Stubber:
|
|
78
116
|
path = get_root()
|
79
117
|
|
80
118
|
self.path = "{}/stubs/{}".format(path, self.flat_fwid).replace("//", "/")
|
81
|
-
|
119
|
+
# log.debug(self.path)
|
82
120
|
try:
|
83
121
|
ensure_folder(path + "/")
|
84
122
|
except OSError:
|
85
|
-
|
123
|
+
log.error("error creating stub folder {}".format(path))
|
86
124
|
self.problematic = [
|
87
125
|
"upip",
|
88
126
|
"upysh",
|
@@ -101,20 +139,23 @@ class Stubber:
|
|
101
139
|
]
|
102
140
|
# there is no option to discover modules from micropython, list is read from an external file.
|
103
141
|
self.modules = [] # type: list[str]
|
142
|
+
self._json_name = None
|
143
|
+
self._json_first = False
|
104
144
|
|
105
145
|
def get_obj_attributes(self, item_instance: object):
|
106
146
|
"extract information of the objects members and attributes"
|
107
147
|
# name_, repr_(value), type as text, item_instance
|
108
148
|
_result = []
|
109
149
|
_errors = []
|
110
|
-
|
150
|
+
# log.debug("get attributes {} {}".format(repr(item_instance), item_instance))
|
111
151
|
for name in dir(item_instance):
|
112
|
-
if name.startswith("
|
152
|
+
if name.startswith("__") and not name in self.modules:
|
113
153
|
continue
|
114
|
-
|
154
|
+
# log.debug("get attribute {}".format(name))
|
115
155
|
try:
|
116
156
|
val = getattr(item_instance, name)
|
117
157
|
# name , item_repr(value) , type as text, item_instance, order
|
158
|
+
# log.debug("attribute {}:{}".format(name, val))
|
118
159
|
try:
|
119
160
|
type_text = repr(type(val)).split("'")[1]
|
120
161
|
except IndexError:
|
@@ -147,21 +188,23 @@ class Stubber:
|
|
147
188
|
|
148
189
|
def create_all_stubs(self):
|
149
190
|
"Create stubs for all configured modules"
|
150
|
-
|
191
|
+
log.info("Start micropython-stubber {} on {}".format(__version__, self._fwid))
|
192
|
+
self.report_start()
|
151
193
|
gc.collect()
|
152
194
|
for module_name in self.modules:
|
153
195
|
self.create_one_stub(module_name)
|
154
|
-
self.
|
196
|
+
self.report_end()
|
197
|
+
log.info("Finally done")
|
155
198
|
|
156
199
|
def create_one_stub(self, module_name: str):
|
157
200
|
if module_name in self.problematic:
|
158
|
-
|
201
|
+
log.warning("Skip module: {:<25} : Known problematic".format(module_name))
|
159
202
|
return False
|
160
203
|
if module_name in self.excluded:
|
161
|
-
|
204
|
+
log.warning("Skip module: {:<25} : Excluded".format(module_name))
|
162
205
|
return False
|
163
206
|
|
164
|
-
file_name = "{}/{}.
|
207
|
+
file_name = "{}/{}.pyi".format(self.path, module_name.replace(".", "/"))
|
165
208
|
gc.collect()
|
166
209
|
result = False
|
167
210
|
try:
|
@@ -176,10 +219,10 @@ class Stubber:
|
|
176
219
|
|
177
220
|
Args:
|
178
221
|
- module_name (str): name of the module to document. This module will be imported.
|
179
|
-
- file_name (Optional[str]): the 'path/filename.
|
222
|
+
- file_name (Optional[str]): the 'path/filename.pyi' to write to. If omitted will be created based on the module name.
|
180
223
|
"""
|
181
224
|
if file_name is None:
|
182
|
-
fname = module_name.replace(".", "_") + ".
|
225
|
+
fname = module_name.replace(".", "_") + ".pyi"
|
183
226
|
file_name = self.path + "/" + fname
|
184
227
|
else:
|
185
228
|
fname = file_name.split("/")[-1]
|
@@ -193,10 +236,10 @@ class Stubber:
|
|
193
236
|
try:
|
194
237
|
new_module = __import__(module_name, None, None, ("*"))
|
195
238
|
m1 = gc.mem_free() # type: ignore
|
196
|
-
|
239
|
+
log.info("Stub module: {:<25} to file: {:<70} mem:{:>5}".format(module_name, fname, m1))
|
197
240
|
|
198
241
|
except ImportError:
|
199
|
-
|
242
|
+
# log.debug("Skip module: {:<25} {:<79}".format(module_name, "Module not found."))
|
200
243
|
return False
|
201
244
|
|
202
245
|
# Start a new file
|
@@ -206,21 +249,18 @@ class Stubber:
|
|
206
249
|
info_ = str(self.info).replace("OrderedDict(", "").replace("})", "}")
|
207
250
|
s = '"""\nModule: \'{0}\' on {1}\n"""\n# MCU: {2}\n# Stubber: {3}\n'.format(module_name, self._fwid, info_, __version__)
|
208
251
|
fp.write(s)
|
209
|
-
fp.write("from typing import Any\nfrom _typeshed import Incomplete\n\n")
|
252
|
+
fp.write("from __future__ import annotations\nfrom typing import Any, Generator\nfrom _typeshed import Incomplete\n\n")
|
210
253
|
self.write_object_stub(fp, new_module, module_name, "")
|
211
254
|
|
212
|
-
self.
|
255
|
+
self.report_add(module_name, file_name)
|
213
256
|
|
214
257
|
if module_name not in {"os", "sys", "logging", "gc"}:
|
215
258
|
# try to unload the module unless we use it
|
216
259
|
try:
|
217
260
|
del new_module
|
218
261
|
except (OSError, KeyError): # lgtm [py/unreachable-statement]
|
219
|
-
|
220
|
-
try
|
221
|
-
del sys.modules[module_name]
|
222
|
-
except KeyError:
|
223
|
-
self.log.debug("could not del sys.modules[{}]".format(module_name))
|
262
|
+
log.warning("could not del new_module")
|
263
|
+
# do not try to delete from sys.modules - most times it does not work anyway
|
224
264
|
gc.collect()
|
225
265
|
return True
|
226
266
|
|
@@ -228,14 +268,14 @@ class Stubber:
|
|
228
268
|
"Write a module/object stub to an open file. Can be called recursive."
|
229
269
|
gc.collect()
|
230
270
|
if object_expr in self.problematic:
|
231
|
-
|
271
|
+
log.warning("SKIPPING problematic module:{}".format(object_expr))
|
232
272
|
return
|
233
273
|
|
234
|
-
#
|
274
|
+
# # log.debug("DUMP : {}".format(object_expr))
|
235
275
|
items, errors = self.get_obj_attributes(object_expr)
|
236
276
|
|
237
277
|
if errors:
|
238
|
-
|
278
|
+
log.error(errors)
|
239
279
|
|
240
280
|
for item_name, item_repr, item_type_txt, item_instance, _ in items:
|
241
281
|
# name_, repr_(value), type as text, item_instance, order
|
@@ -243,11 +283,16 @@ class Stubber:
|
|
243
283
|
# do not create stubs for these primitives
|
244
284
|
continue
|
245
285
|
if item_name[0].isdigit():
|
246
|
-
|
286
|
+
log.warning("NameError: invalid name {}".format(item_name))
|
247
287
|
continue
|
248
288
|
# Class expansion only on first 3 levels (bit of a hack)
|
249
|
-
if
|
250
|
-
|
289
|
+
if (
|
290
|
+
item_type_txt == "<class 'type'>"
|
291
|
+
and len(indent) <= _MAX_CLASS_LEVEL * 4
|
292
|
+
# and not obj_name.endswith(".Pin")
|
293
|
+
# avoid expansion of Pin.cpu / Pin.board to avoid crashes on most platforms
|
294
|
+
):
|
295
|
+
# log.debug("{0}class {1}:".format(indent, item_name))
|
251
296
|
superclass = ""
|
252
297
|
is_exception = (
|
253
298
|
item_name.endswith("Exception")
|
@@ -266,11 +311,11 @@ class Stubber:
|
|
266
311
|
if is_exception:
|
267
312
|
s += indent + " ...\n"
|
268
313
|
fp.write(s)
|
269
|
-
|
314
|
+
continue
|
270
315
|
# write classdef
|
271
316
|
fp.write(s)
|
272
317
|
# first write the class literals and methods
|
273
|
-
|
318
|
+
# log.debug("# recursion over class {0}".format(item_name))
|
274
319
|
self.write_object_stub(
|
275
320
|
fp,
|
276
321
|
item_instance,
|
@@ -284,7 +329,7 @@ class Stubber:
|
|
284
329
|
s += indent + " ...\n\n"
|
285
330
|
fp.write(s)
|
286
331
|
elif any(word in item_type_txt for word in ["method", "function", "closure"]):
|
287
|
-
|
332
|
+
# log.debug("# def {1} function/method/closure, type = '{0}'".format(item_type_txt, item_name))
|
288
333
|
# module Function or class method
|
289
334
|
# will accept any number of params
|
290
335
|
# return type Any/Incomplete
|
@@ -300,7 +345,7 @@ class Stubber:
|
|
300
345
|
s = "{}def {}({}*args, **kwargs) -> {}:\n".format(indent, item_name, first, ret)
|
301
346
|
s += indent + " ...\n\n"
|
302
347
|
fp.write(s)
|
303
|
-
|
348
|
+
# log.debug("\n" + s)
|
304
349
|
elif item_type_txt == "<class 'module'>":
|
305
350
|
# Skip imported modules
|
306
351
|
# fp.write("# import {}\n".format(item_name))
|
@@ -310,36 +355,42 @@ class Stubber:
|
|
310
355
|
t = item_type_txt[8:-2]
|
311
356
|
s = ""
|
312
357
|
|
313
|
-
if t in
|
358
|
+
if t in ("str", "int", "float", "bool", "bytearray", "bytes"):
|
314
359
|
# known type: use actual value
|
315
|
-
s = "{0}{1} = {2} # type: {3}\n".format(indent, item_name, item_repr, t)
|
316
|
-
|
360
|
+
# s = "{0}{1} = {2} # type: {3}\n".format(indent, item_name, item_repr, t)
|
361
|
+
s = "{0}{1}: {3} = {2}\n".format(indent, item_name, item_repr, t)
|
362
|
+
elif t in ("dict", "list", "tuple"):
|
317
363
|
# dict, list , tuple: use empty value
|
318
364
|
ev = {"dict": "{}", "list": "[]", "tuple": "()"}
|
319
|
-
s = "{0}{1} = {2} # type: {3}\n".format(indent, item_name, ev[t], t)
|
365
|
+
# s = "{0}{1} = {2} # type: {3}\n".format(indent, item_name, ev[t], t)
|
366
|
+
s = "{0}{1}: {3} = {2}\n".format(indent, item_name, ev[t], t)
|
320
367
|
else:
|
321
368
|
# something else
|
322
|
-
if t
|
323
|
-
# Possibly default others to item_instance object ?
|
369
|
+
if t in ("object", "set", "frozenset", "Pin", "generator"): # "FileIO"
|
324
370
|
# https://docs.python.org/3/tutorial/classes.html#item_instance-objects
|
371
|
+
# use these types for the attribute
|
372
|
+
if t == "generator":
|
373
|
+
t = "Generator"
|
374
|
+
s = "{0}{1}: {2} ## = {4}\n".format(indent, item_name, t, item_type_txt, item_repr)
|
375
|
+
else:
|
376
|
+
# Requires Python 3.6 syntax, which is OK for the stubs/pyi
|
325
377
|
t = "Incomplete"
|
326
|
-
|
327
|
-
s = "{0}{1} : {2} ## {3} = {4}\n".format(indent, item_name, t, item_type_txt, item_repr)
|
378
|
+
s = "{0}{1}: {2} ## {3} = {4}\n".format(indent, item_name, t, item_type_txt, item_repr)
|
328
379
|
fp.write(s)
|
329
|
-
|
380
|
+
# log.debug("\n" + s)
|
330
381
|
else:
|
331
382
|
# keep only the name
|
332
|
-
|
383
|
+
# log.debug("# all other, type = '{0}'".format(item_type_txt))
|
333
384
|
fp.write("# all other, type = '{0}'\n".format(item_type_txt))
|
334
385
|
|
335
386
|
fp.write(indent + item_name + " # type: Incomplete\n")
|
336
387
|
|
337
|
-
del items
|
338
|
-
del errors
|
339
|
-
try:
|
340
|
-
|
341
|
-
except (OSError, KeyError, NameError):
|
342
|
-
|
388
|
+
# del items
|
389
|
+
# del errors
|
390
|
+
# try:
|
391
|
+
# del item_name, item_repr, item_type_txt, item_instance # type: ignore
|
392
|
+
# except (OSError, KeyError, NameError):
|
393
|
+
# pass
|
343
394
|
|
344
395
|
@property
|
345
396
|
def flat_fwid(self):
|
@@ -355,7 +406,7 @@ class Stubber:
|
|
355
406
|
"Remove all files from the stub folder"
|
356
407
|
if path is None:
|
357
408
|
path = self.path
|
358
|
-
|
409
|
+
log.info("Clean/remove files in folder: {}".format(path))
|
359
410
|
try:
|
360
411
|
os.stat(path) # TEMP workaround mpremote listdir bug -
|
361
412
|
items = os.listdir(path)
|
@@ -373,41 +424,53 @@ class Stubber:
|
|
373
424
|
except OSError:
|
374
425
|
pass
|
375
426
|
|
376
|
-
def
|
377
|
-
"
|
378
|
-
|
379
|
-
|
380
|
-
self.
|
427
|
+
def report_start(self, filename: str = "modules.json"):
|
428
|
+
"""Start a report of the modules that have been stubbed
|
429
|
+
"create json with list of exported modules"""
|
430
|
+
self._json_name = "{}/{}".format(self.path, filename)
|
431
|
+
self._json_first = True
|
432
|
+
ensure_folder(self._json_name)
|
433
|
+
log.info("Report file: {}".format(self._json_name))
|
381
434
|
gc.collect()
|
382
435
|
try:
|
383
436
|
# write json by node to reduce memory requirements
|
384
|
-
with open(
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
self.
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
437
|
+
with open(self._json_name, "w") as f:
|
438
|
+
f.write("{")
|
439
|
+
f.write(dumps({"firmware": self.info})[1:-1])
|
440
|
+
f.write(",\n")
|
441
|
+
f.write(dumps({"stubber": {"version": __version__}, "stubtype": "firmware"})[1:-1])
|
442
|
+
f.write(",\n")
|
443
|
+
f.write('"modules" :[\n')
|
444
|
+
|
445
|
+
except OSError as e:
|
446
|
+
log.error("Failed to create the report.")
|
447
|
+
self._json_name = None
|
448
|
+
raise e
|
449
|
+
|
450
|
+
def report_add(self, module_name: str, stub_file: str):
|
451
|
+
"Add a module to the report"
|
452
|
+
# write json by node to reduce memory requirements
|
453
|
+
if not self._json_name:
|
454
|
+
raise Exception("No report file")
|
455
|
+
try:
|
456
|
+
with open(self._json_name, "a") as f:
|
457
|
+
if not self._json_first:
|
458
|
+
f.write(",\n")
|
459
|
+
else:
|
460
|
+
self._json_first = False
|
461
|
+
line = '{{"module": "{}", "file": "{}"}}'.format(module_name, stub_file.replace("\\", "/"))
|
462
|
+
f.write(line)
|
403
463
|
|
404
|
-
|
405
|
-
|
406
|
-
f.write(",\n")
|
407
|
-
f.write(n)
|
464
|
+
except OSError:
|
465
|
+
log.error("Failed to create the report.")
|
408
466
|
|
409
|
-
def
|
410
|
-
|
467
|
+
def report_end(self):
|
468
|
+
if not self._json_name:
|
469
|
+
raise Exception("No report file")
|
470
|
+
with open(self._json_name, "a") as f:
|
471
|
+
f.write("\n]}")
|
472
|
+
# is used as sucess indicator
|
473
|
+
log.info("Path: {}".format(self.path))
|
411
474
|
|
412
475
|
|
413
476
|
def ensure_folder(path: str):
|
@@ -433,23 +496,32 @@ def ensure_folder(path: str):
|
|
433
496
|
|
434
497
|
|
435
498
|
def _build(s):
|
436
|
-
# extract
|
499
|
+
# extract build from sys.version or os.uname().version if available
|
500
|
+
# sys.version: 'MicroPython v1.23.0-preview.6.g3d0b6276f'
|
501
|
+
# sys.implementation.version: 'v1.13-103-gb137d064e'
|
437
502
|
if not s:
|
438
503
|
return ""
|
439
|
-
if " on " in s
|
440
|
-
|
441
|
-
|
504
|
+
s = s.split(" on ", 1)[0] if " on " in s else s
|
505
|
+
if s.startswith("v"):
|
506
|
+
if not "-" in s:
|
507
|
+
return ""
|
508
|
+
b = s.split("-")[1]
|
509
|
+
return b
|
510
|
+
if not "-preview" in s:
|
511
|
+
return ""
|
512
|
+
b = s.split("-preview")[1].split(".")[1]
|
513
|
+
return b
|
442
514
|
|
443
515
|
|
444
516
|
def _info(): # type:() -> dict[str, str]
|
445
517
|
info = OrderedDict(
|
446
518
|
{
|
447
|
-
"family": sys.implementation.name,
|
519
|
+
"family": sys.implementation.name, # type: ignore
|
448
520
|
"version": "",
|
449
521
|
"build": "",
|
450
522
|
"ver": "",
|
451
523
|
"port": sys.platform, # port: esp32 / win32 / linux / stm32
|
452
|
-
"board": "
|
524
|
+
"board": "UNKNOWN",
|
453
525
|
"cpu": "",
|
454
526
|
"mpy": "",
|
455
527
|
"arch": "",
|
@@ -463,56 +535,44 @@ def _info(): # type:() -> dict[str, str]
|
|
463
535
|
elif info["port"] == "linux":
|
464
536
|
info["port"] = "unix"
|
465
537
|
try:
|
466
|
-
info["version"] =
|
538
|
+
info["version"] = version_str(sys.implementation.version) # type: ignore
|
467
539
|
except AttributeError:
|
468
540
|
pass
|
469
541
|
try:
|
470
|
-
|
471
|
-
info["board"] =
|
472
|
-
info["
|
542
|
+
_machine = sys.implementation._machine if "_machine" in dir(sys.implementation) else os.uname().machine # type: ignore
|
543
|
+
# info["board"] = "with".join(_machine.split("with")[:-1]).strip()
|
544
|
+
info["board"] = _machine
|
545
|
+
info["cpu"] = _machine.split("with")[-1].strip()
|
473
546
|
info["mpy"] = (
|
474
|
-
sys.implementation._mpy
|
547
|
+
sys.implementation._mpy # type: ignore
|
475
548
|
if "_mpy" in dir(sys.implementation)
|
476
|
-
else sys.implementation.mpy
|
549
|
+
else sys.implementation.mpy # type: ignore
|
477
550
|
if "mpy" in dir(sys.implementation)
|
478
551
|
else ""
|
479
552
|
)
|
480
553
|
except (AttributeError, IndexError):
|
481
554
|
pass
|
482
|
-
|
483
|
-
for filename in [d + "/board_info.csv" for d in LIBS]:
|
484
|
-
# print("look up the board name in the file", filename)
|
485
|
-
if file_exists(filename):
|
486
|
-
# print("Found board info file: {}".format(filename))
|
487
|
-
b = info["board"].strip()
|
488
|
-
if find_board(info, b, filename):
|
489
|
-
break
|
490
|
-
if "with" in b:
|
491
|
-
b = b.split("with")[0].strip()
|
492
|
-
if find_board(info, b, filename):
|
493
|
-
break
|
494
|
-
info["board"] = "GENERIC"
|
495
|
-
info["board"] = info["board"].replace(" ", "_")
|
496
|
-
gc.collect()
|
555
|
+
info["board"] = get_boardname()
|
497
556
|
|
498
557
|
try:
|
499
|
-
|
500
|
-
|
501
|
-
|
502
|
-
|
503
|
-
|
504
|
-
|
505
|
-
|
506
|
-
|
507
|
-
|
558
|
+
if "uname" in dir(os): # old
|
559
|
+
# extract build from uname().version if available
|
560
|
+
info["build"] = _build(os.uname()[3]) # type: ignore
|
561
|
+
if not info["build"]:
|
562
|
+
# extract build from uname().release if available
|
563
|
+
info["build"] = _build(os.uname()[2]) # type: ignore
|
564
|
+
elif "version" in dir(sys): # new
|
565
|
+
# extract build from sys.version if available
|
566
|
+
info["build"] = _build(sys.version)
|
567
|
+
except (AttributeError, IndexError, TypeError):
|
508
568
|
pass
|
509
569
|
# avoid build hashes
|
510
|
-
if info["build"] and len(info["build"]) > 5:
|
511
|
-
|
570
|
+
# if info["build"] and len(info["build"]) > 5:
|
571
|
+
# info["build"] = ""
|
512
572
|
|
513
573
|
if info["version"] == "" and sys.platform not in ("unix", "win32"):
|
514
574
|
try:
|
515
|
-
u = os.uname()
|
575
|
+
u = os.uname() # type: ignore
|
516
576
|
info["version"] = u.release
|
517
577
|
except (IndexError, AttributeError, TypeError):
|
518
578
|
pass
|
@@ -534,13 +594,14 @@ def _info(): # type:() -> dict[str, str]
|
|
534
594
|
info["release"] = "2.0.0"
|
535
595
|
|
536
596
|
if info["family"] == "micropython":
|
597
|
+
info["version"]
|
537
598
|
if (
|
538
599
|
info["version"]
|
539
600
|
and info["version"].endswith(".0")
|
540
601
|
and info["version"] >= "1.10.0" # versions from 1.10.0 to 1.20.0 do not have a micro .0
|
541
602
|
and info["version"] <= "1.19.9"
|
542
603
|
):
|
543
|
-
#
|
604
|
+
# versions from 1.10.0 to 1.20.0 do not have a micro .0
|
544
605
|
info["version"] = info["version"][:-2]
|
545
606
|
|
546
607
|
# spell-checker: disable
|
@@ -564,25 +625,31 @@ def _info(): # type:() -> dict[str, str]
|
|
564
625
|
info["arch"] = arch
|
565
626
|
# .mpy version.minor
|
566
627
|
info["mpy"] = "v{}.{}".format(sys_mpy & 0xFF, sys_mpy >> 8 & 3)
|
628
|
+
if info["build"] and not info["version"].endswith("-preview"):
|
629
|
+
info["version"] = info["version"] + "-preview"
|
567
630
|
# simple to use version[-build] string
|
568
|
-
info["ver"] = f"
|
631
|
+
info["ver"] = f"{info['version']}-{info['build']}" if info["build"] else f"{info['version']}"
|
569
632
|
|
570
633
|
return info
|
571
634
|
|
572
635
|
|
573
|
-
def
|
574
|
-
"
|
575
|
-
|
576
|
-
|
577
|
-
|
578
|
-
|
579
|
-
|
580
|
-
|
581
|
-
|
582
|
-
|
583
|
-
|
584
|
-
|
585
|
-
|
636
|
+
def version_str(version: tuple): # -> str:
|
637
|
+
v_str = ".".join([str(n) for n in version[:3]])
|
638
|
+
if len(version) > 3 and version[3]:
|
639
|
+
v_str += "-" + version[3]
|
640
|
+
return v_str
|
641
|
+
|
642
|
+
|
643
|
+
def get_boardname() -> str:
|
644
|
+
"Read the board name from the boardname.py file that may have been created upfront"
|
645
|
+
try:
|
646
|
+
from boardname import BOARDNAME # type: ignore
|
647
|
+
|
648
|
+
log.info("Found BOARDNAME: {}".format(BOARDNAME))
|
649
|
+
except ImportError:
|
650
|
+
log.warning("BOARDNAME not found")
|
651
|
+
BOARDNAME = ""
|
652
|
+
return BOARDNAME
|
586
653
|
|
587
654
|
|
588
655
|
def get_root() -> str: # sourcery skip: use-assigned-variable
|
@@ -635,10 +702,6 @@ def is_micropython() -> bool:
|
|
635
702
|
# pylint: disable=unused-variable,eval-used
|
636
703
|
try:
|
637
704
|
# either test should fail on micropython
|
638
|
-
# a) https://docs.micropython.org/en/latest/genrst/syntax.html#spaces
|
639
|
-
# Micropython : SyntaxError
|
640
|
-
# a = eval("1and 0") # lgtm [py/unused-local-variable]
|
641
|
-
# Eval blocks some minification aspects
|
642
705
|
|
643
706
|
# b) https://docs.micropython.org/en/latest/genrst/builtin_types.html#bytes-with-keywords-not-implemented
|
644
707
|
# Micropython: NotImplementedError
|
@@ -652,92 +715,99 @@ def is_micropython() -> bool:
|
|
652
715
|
return True
|
653
716
|
|
654
717
|
|
655
|
-
|
656
|
-
|
718
|
+
SKIP_FILE = "modulelist.done"
|
719
|
+
|
657
720
|
|
721
|
+
def get_modules(skip=0):
|
722
|
+
# new
|
723
|
+
for p in LIBS:
|
724
|
+
fname = p + "/modulelist.txt"
|
725
|
+
if not file_exists(fname):
|
726
|
+
continue
|
727
|
+
try:
|
728
|
+
with open(fname) as f:
|
729
|
+
i = 0
|
730
|
+
while True:
|
731
|
+
line = f.readline().strip()
|
732
|
+
if not line:
|
733
|
+
break
|
734
|
+
if len(line) > 0 and line[0] == "#":
|
735
|
+
continue
|
736
|
+
i += 1
|
737
|
+
if i < skip:
|
738
|
+
continue
|
739
|
+
yield line
|
740
|
+
break
|
741
|
+
except OSError:
|
742
|
+
pass
|
743
|
+
|
744
|
+
|
745
|
+
def write_skip(done):
|
746
|
+
# write count of modules already processed to file
|
747
|
+
with open(SKIP_FILE, "w") as f:
|
748
|
+
f.write(str(done) + "\n")
|
749
|
+
|
750
|
+
|
751
|
+
def read_skip():
|
752
|
+
# read count of modules already processed from file
|
753
|
+
done = 0
|
658
754
|
try:
|
659
|
-
|
660
|
-
|
661
|
-
print("Opened existing db")
|
755
|
+
with open(SKIP_FILE) as f:
|
756
|
+
done = int(f.readline().strip())
|
662
757
|
except OSError:
|
663
|
-
|
664
|
-
|
665
|
-
|
758
|
+
pass
|
759
|
+
return done
|
760
|
+
|
761
|
+
|
762
|
+
def main():
|
763
|
+
import machine # type: ignore
|
764
|
+
|
765
|
+
was_running = file_exists(SKIP_FILE)
|
766
|
+
if was_running:
|
767
|
+
log.info("Continue from last run")
|
768
|
+
else:
|
769
|
+
log.info("Starting new run")
|
770
|
+
# try:
|
771
|
+
# f = open("modulelist.done", "r+b")
|
772
|
+
# was_running = True
|
773
|
+
# print("Continue from last run")
|
774
|
+
# except OSError:
|
775
|
+
# f = open("modulelist.done", "w+b")
|
776
|
+
# was_running = False
|
666
777
|
stubber = Stubber(path=read_path())
|
667
778
|
|
668
779
|
# f_name = "{}/{}".format(stubber.path, "modules.json")
|
780
|
+
skip = 0
|
669
781
|
if not was_running:
|
670
782
|
# Only clean folder if this is a first run
|
671
783
|
stubber.clean()
|
672
|
-
|
673
|
-
|
674
|
-
|
675
|
-
|
676
|
-
|
677
|
-
|
678
|
-
# not optimal , but works on mpremote and esp8266
|
679
|
-
for line in f.read().split("\n"):
|
680
|
-
line = line.strip()
|
681
|
-
gc.collect()
|
682
|
-
if len(line) > 0:
|
683
|
-
key, value = line.split("=", 1)
|
684
|
-
modules_done[key] = value
|
685
|
-
except (OSError, SyntaxError):
|
686
|
-
pass
|
687
|
-
gc.collect()
|
688
|
-
# see if we can continue from where we left off
|
689
|
-
modules = [m for m in stubber.modules if m not in modules_done.keys()]
|
690
|
-
gc.collect()
|
691
|
-
for modulename in modules:
|
784
|
+
stubber.report_start("modules.json")
|
785
|
+
else:
|
786
|
+
skip = read_skip()
|
787
|
+
stubber._json_name = "{}/{}".format(stubber.path, "modules.json")
|
788
|
+
|
789
|
+
for modulename in get_modules(skip):
|
692
790
|
# ------------------------------------
|
693
791
|
# do epic shit
|
694
792
|
# but sometimes things fail / run out of memory and reboot
|
695
|
-
ok = False
|
696
793
|
try:
|
697
|
-
|
794
|
+
stubber.create_one_stub(modulename)
|
698
795
|
except MemoryError:
|
699
796
|
# RESET AND HOPE THAT IN THE NEXT CYCLE WE PROGRESS FURTHER
|
700
797
|
machine.reset()
|
701
798
|
# -------------------------------------
|
702
799
|
gc.collect()
|
703
|
-
modules_done[modulename] = str(stubber._report[-1] if ok else "failed")
|
704
|
-
with open("modulelist.done", "a") as f:
|
705
|
-
|
800
|
+
# modules_done[modulename] = str(stubber._report[-1] if ok else "failed")
|
801
|
+
# with open("modulelist.done", "a") as f:
|
802
|
+
# f.write("{}={}\n".format(modulename, "ok" if ok else "failed"))
|
803
|
+
skip += 1
|
804
|
+
write_skip(skip)
|
706
805
|
|
707
|
-
|
708
|
-
|
709
|
-
# stubber.write_json_end(mod_fp)
|
710
|
-
stubber._report = [v for _, v in modules_done.items() if v != "failed"]
|
711
|
-
stubber.report()
|
712
|
-
|
713
|
-
|
714
|
-
def get_modulelist(stubber):
|
715
|
-
stubber.modules = [] # avoid duplicates
|
716
|
-
for p in LIBS:
|
717
|
-
try:
|
718
|
-
with open(p + "/modulelist.txt") as f:
|
719
|
-
print("DEBUG: list of modules: " + p + "/modulelist.txt")
|
720
|
-
for line in f.read().split("\n"):
|
721
|
-
line = line.strip()
|
722
|
-
if len(line) > 0 and line[0] != "#":
|
723
|
-
stubber.modules.append(line)
|
724
|
-
gc.collect()
|
725
|
-
break
|
726
|
-
except OSError:
|
727
|
-
pass
|
728
|
-
if not stubber.modules:
|
729
|
-
stubber.modules = ["micropython"]
|
730
|
-
_log.warn("Could not find modulelist.txt, using default modules")
|
731
|
-
gc.collect()
|
806
|
+
print("All modules have been processed, Finalizing report")
|
807
|
+
stubber.report_end()
|
732
808
|
|
733
809
|
|
734
810
|
if __name__ == "__main__" or is_micropython():
|
735
|
-
try:
|
736
|
-
log = logging.getLogger("stubber")
|
737
|
-
logging.basicConfig(level=logging.INFO)
|
738
|
-
# logging.basicConfig(level=logging.DEBUG)
|
739
|
-
except NameError:
|
740
|
-
pass
|
741
811
|
if not file_exists("no_auto_stubber.txt"):
|
742
812
|
try:
|
743
813
|
gc.threshold(4 * 1024) # type: ignore
|