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_mem.py
CHANGED
@@ -9,16 +9,19 @@
|
|
9
9
|
- cross compilation, using mpy-cross,
|
10
10
|
to avoid the compilation step on the micropython device
|
11
11
|
|
12
|
-
This variant was generated from createstubs.py by micropython-stubber v1.
|
12
|
+
This variant was generated from createstubs.py by micropython-stubber v1.17.0
|
13
13
|
"""
|
14
14
|
# Copyright (c) 2019-2023 Jos Verlinde
|
15
15
|
|
16
16
|
import gc
|
17
|
-
import logging
|
18
17
|
import os
|
19
18
|
import sys
|
19
|
+
from time import sleep
|
20
20
|
|
21
|
-
|
21
|
+
try:
|
22
|
+
from ujson import dumps
|
23
|
+
except:
|
24
|
+
from json import dumps
|
22
25
|
|
23
26
|
try:
|
24
27
|
from machine import reset # type: ignore
|
@@ -30,11 +33,49 @@ try:
|
|
30
33
|
except ImportError:
|
31
34
|
from ucollections import OrderedDict # type: ignore
|
32
35
|
|
33
|
-
__version__ = "v1.
|
36
|
+
__version__ = "v1.17.0"
|
34
37
|
ENOENT = 2
|
35
38
|
_MAX_CLASS_LEVEL = 2 # Max class nesting
|
36
|
-
LIBS = ["
|
37
|
-
|
39
|
+
LIBS = ["lib", "/lib", "/sd/lib", "/flash/lib", "."]
|
40
|
+
|
41
|
+
|
42
|
+
# our own logging module to avoid dependency on and interfering with logging module
|
43
|
+
class logging:
|
44
|
+
# DEBUG = 10
|
45
|
+
INFO = 20
|
46
|
+
WARNING = 30
|
47
|
+
ERROR = 40
|
48
|
+
level = INFO
|
49
|
+
prnt = print
|
50
|
+
|
51
|
+
@staticmethod
|
52
|
+
def getLogger(name):
|
53
|
+
return logging()
|
54
|
+
|
55
|
+
@classmethod
|
56
|
+
def basicConfig(cls, level):
|
57
|
+
cls.level = level
|
58
|
+
|
59
|
+
# def debug(self, msg):
|
60
|
+
# if self.level <= logging.DEBUG:
|
61
|
+
# self.prnt("DEBUG :", msg)
|
62
|
+
|
63
|
+
def info(self, msg):
|
64
|
+
if self.level <= logging.INFO:
|
65
|
+
self.prnt("INFO :", msg)
|
66
|
+
|
67
|
+
def warning(self, msg):
|
68
|
+
if self.level <= logging.WARNING:
|
69
|
+
self.prnt("WARN :", msg)
|
70
|
+
|
71
|
+
def error(self, msg):
|
72
|
+
if self.level <= logging.ERROR:
|
73
|
+
self.prnt("ERROR :", msg)
|
74
|
+
|
75
|
+
|
76
|
+
log = logging.getLogger("stubber")
|
77
|
+
logging.basicConfig(level=logging.INFO)
|
78
|
+
# logging.basicConfig(level=logging.DEBUG)
|
38
79
|
|
39
80
|
|
40
81
|
class Stubber:
|
@@ -42,24 +83,21 @@ class Stubber:
|
|
42
83
|
|
43
84
|
def __init__(self, path: str = None, firmware_id: str = None): # type: ignore
|
44
85
|
try:
|
45
|
-
if os.uname().release == "1.13.0" and os.uname().version < "v1.13-103":
|
86
|
+
if os.uname().release == "1.13.0" and os.uname().version < "v1.13-103": # type: ignore
|
46
87
|
raise NotImplementedError("MicroPython 1.13.0 cannot be stubbed")
|
47
88
|
except AttributeError:
|
48
89
|
pass
|
49
|
-
self.log = None
|
50
|
-
self.log = logging.getLogger("stubber")
|
51
|
-
self._report = [] # type: list[str]
|
52
90
|
self.info = _info()
|
53
|
-
|
54
|
-
|
91
|
+
log.info("Port: {}".format(self.info["port"]))
|
92
|
+
log.info("Board: {}".format(self.info["board"]))
|
55
93
|
gc.collect()
|
56
94
|
if firmware_id:
|
57
95
|
self._fwid = firmware_id.lower()
|
58
96
|
else:
|
59
97
|
if self.info["family"] == "micropython":
|
60
|
-
self._fwid = "{family}-{
|
98
|
+
self._fwid = "{family}-v{version}-{port}-{board}".format(**self.info).rstrip("-")
|
61
99
|
else:
|
62
|
-
self._fwid = "{family}-{
|
100
|
+
self._fwid = "{family}-v{version}-{port}".format(**self.info)
|
63
101
|
self._start_free = gc.mem_free() # type: ignore
|
64
102
|
|
65
103
|
if path:
|
@@ -69,11 +107,11 @@ class Stubber:
|
|
69
107
|
path = get_root()
|
70
108
|
|
71
109
|
self.path = "{}/stubs/{}".format(path, self.flat_fwid).replace("//", "/")
|
72
|
-
|
110
|
+
# log.debug(self.path)
|
73
111
|
try:
|
74
112
|
ensure_folder(path + "/")
|
75
113
|
except OSError:
|
76
|
-
|
114
|
+
log.error("error creating stub folder {}".format(path))
|
77
115
|
self.problematic = [
|
78
116
|
"upip",
|
79
117
|
"upysh",
|
@@ -92,20 +130,23 @@ class Stubber:
|
|
92
130
|
]
|
93
131
|
# there is no option to discover modules from micropython, list is read from an external file.
|
94
132
|
self.modules = [] # type: list[str]
|
133
|
+
self._json_name = None
|
134
|
+
self._json_first = False
|
95
135
|
|
96
136
|
def get_obj_attributes(self, item_instance: object):
|
97
137
|
"extract information of the objects members and attributes"
|
98
138
|
# name_, repr_(value), type as text, item_instance
|
99
139
|
_result = []
|
100
140
|
_errors = []
|
101
|
-
|
141
|
+
# log.debug("get attributes {} {}".format(repr(item_instance), item_instance))
|
102
142
|
for name in dir(item_instance):
|
103
|
-
if name.startswith("
|
143
|
+
if name.startswith("__") and not name in self.modules:
|
104
144
|
continue
|
105
|
-
|
145
|
+
# log.debug("get attribute {}".format(name))
|
106
146
|
try:
|
107
147
|
val = getattr(item_instance, name)
|
108
148
|
# name , item_repr(value) , type as text, item_instance, order
|
149
|
+
# log.debug("attribute {}:{}".format(name, val))
|
109
150
|
try:
|
110
151
|
type_text = repr(type(val)).split("'")[1]
|
111
152
|
except IndexError:
|
@@ -138,21 +179,23 @@ class Stubber:
|
|
138
179
|
|
139
180
|
def create_all_stubs(self):
|
140
181
|
"Create stubs for all configured modules"
|
141
|
-
|
182
|
+
log.info("Start micropython-stubber {} on {}".format(__version__, self._fwid))
|
183
|
+
self.report_start()
|
142
184
|
gc.collect()
|
143
185
|
for module_name in self.modules:
|
144
186
|
self.create_one_stub(module_name)
|
145
|
-
self.
|
187
|
+
self.report_end()
|
188
|
+
log.info("Finally done")
|
146
189
|
|
147
190
|
def create_one_stub(self, module_name: str):
|
148
191
|
if module_name in self.problematic:
|
149
|
-
|
192
|
+
log.warning("Skip module: {:<25} : Known problematic".format(module_name))
|
150
193
|
return False
|
151
194
|
if module_name in self.excluded:
|
152
|
-
|
195
|
+
log.warning("Skip module: {:<25} : Excluded".format(module_name))
|
153
196
|
return False
|
154
197
|
|
155
|
-
file_name = "{}/{}.
|
198
|
+
file_name = "{}/{}.pyi".format(self.path, module_name.replace(".", "/"))
|
156
199
|
gc.collect()
|
157
200
|
result = False
|
158
201
|
try:
|
@@ -167,10 +210,10 @@ class Stubber:
|
|
167
210
|
|
168
211
|
Args:
|
169
212
|
- module_name (str): name of the module to document. This module will be imported.
|
170
|
-
- file_name (Optional[str]): the 'path/filename.
|
213
|
+
- file_name (Optional[str]): the 'path/filename.pyi' to write to. If omitted will be created based on the module name.
|
171
214
|
"""
|
172
215
|
if file_name is None:
|
173
|
-
fname = module_name.replace(".", "_") + ".
|
216
|
+
fname = module_name.replace(".", "_") + ".pyi"
|
174
217
|
file_name = self.path + "/" + fname
|
175
218
|
else:
|
176
219
|
fname = file_name.split("/")[-1]
|
@@ -184,10 +227,10 @@ class Stubber:
|
|
184
227
|
try:
|
185
228
|
new_module = __import__(module_name, None, None, ("*"))
|
186
229
|
m1 = gc.mem_free() # type: ignore
|
187
|
-
|
230
|
+
log.info("Stub module: {:<25} to file: {:<70} mem:{:>5}".format(module_name, fname, m1))
|
188
231
|
|
189
232
|
except ImportError:
|
190
|
-
|
233
|
+
# log.debug("Skip module: {:<25} {:<79}".format(module_name, "Module not found."))
|
191
234
|
return False
|
192
235
|
|
193
236
|
# Start a new file
|
@@ -197,21 +240,18 @@ class Stubber:
|
|
197
240
|
info_ = str(self.info).replace("OrderedDict(", "").replace("})", "}")
|
198
241
|
s = '"""\nModule: \'{0}\' on {1}\n"""\n# MCU: {2}\n# Stubber: {3}\n'.format(module_name, self._fwid, info_, __version__)
|
199
242
|
fp.write(s)
|
200
|
-
fp.write("from typing import Any\nfrom _typeshed import Incomplete\n\n")
|
243
|
+
fp.write("from __future__ import annotations\nfrom typing import Any, Generator\nfrom _typeshed import Incomplete\n\n")
|
201
244
|
self.write_object_stub(fp, new_module, module_name, "")
|
202
245
|
|
203
|
-
self.
|
246
|
+
self.report_add(module_name, file_name)
|
204
247
|
|
205
248
|
if module_name not in {"os", "sys", "logging", "gc"}:
|
206
249
|
# try to unload the module unless we use it
|
207
250
|
try:
|
208
251
|
del new_module
|
209
252
|
except (OSError, KeyError): # lgtm [py/unreachable-statement]
|
210
|
-
|
211
|
-
try
|
212
|
-
del sys.modules[module_name]
|
213
|
-
except KeyError:
|
214
|
-
self.log.debug("could not del sys.modules[{}]".format(module_name))
|
253
|
+
log.warning("could not del new_module")
|
254
|
+
# do not try to delete from sys.modules - most times it does not work anyway
|
215
255
|
gc.collect()
|
216
256
|
return True
|
217
257
|
|
@@ -219,14 +259,14 @@ class Stubber:
|
|
219
259
|
"Write a module/object stub to an open file. Can be called recursive."
|
220
260
|
gc.collect()
|
221
261
|
if object_expr in self.problematic:
|
222
|
-
|
262
|
+
log.warning("SKIPPING problematic module:{}".format(object_expr))
|
223
263
|
return
|
224
264
|
|
225
|
-
#
|
265
|
+
# # log.debug("DUMP : {}".format(object_expr))
|
226
266
|
items, errors = self.get_obj_attributes(object_expr)
|
227
267
|
|
228
268
|
if errors:
|
229
|
-
|
269
|
+
log.error(errors)
|
230
270
|
|
231
271
|
for item_name, item_repr, item_type_txt, item_instance, _ in items:
|
232
272
|
# name_, repr_(value), type as text, item_instance, order
|
@@ -234,11 +274,16 @@ class Stubber:
|
|
234
274
|
# do not create stubs for these primitives
|
235
275
|
continue
|
236
276
|
if item_name[0].isdigit():
|
237
|
-
|
277
|
+
log.warning("NameError: invalid name {}".format(item_name))
|
238
278
|
continue
|
239
279
|
# Class expansion only on first 3 levels (bit of a hack)
|
240
|
-
if
|
241
|
-
|
280
|
+
if (
|
281
|
+
item_type_txt == "<class 'type'>"
|
282
|
+
and len(indent) <= _MAX_CLASS_LEVEL * 4
|
283
|
+
# and not obj_name.endswith(".Pin")
|
284
|
+
# avoid expansion of Pin.cpu / Pin.board to avoid crashes on most platforms
|
285
|
+
):
|
286
|
+
# log.debug("{0}class {1}:".format(indent, item_name))
|
242
287
|
superclass = ""
|
243
288
|
is_exception = (
|
244
289
|
item_name.endswith("Exception")
|
@@ -257,11 +302,11 @@ class Stubber:
|
|
257
302
|
if is_exception:
|
258
303
|
s += indent + " ...\n"
|
259
304
|
fp.write(s)
|
260
|
-
|
305
|
+
continue
|
261
306
|
# write classdef
|
262
307
|
fp.write(s)
|
263
308
|
# first write the class literals and methods
|
264
|
-
|
309
|
+
# log.debug("# recursion over class {0}".format(item_name))
|
265
310
|
self.write_object_stub(
|
266
311
|
fp,
|
267
312
|
item_instance,
|
@@ -275,7 +320,7 @@ class Stubber:
|
|
275
320
|
s += indent + " ...\n\n"
|
276
321
|
fp.write(s)
|
277
322
|
elif any(word in item_type_txt for word in ["method", "function", "closure"]):
|
278
|
-
|
323
|
+
# log.debug("# def {1} function/method/closure, type = '{0}'".format(item_type_txt, item_name))
|
279
324
|
# module Function or class method
|
280
325
|
# will accept any number of params
|
281
326
|
# return type Any/Incomplete
|
@@ -291,7 +336,7 @@ class Stubber:
|
|
291
336
|
s = "{}def {}({}*args, **kwargs) -> {}:\n".format(indent, item_name, first, ret)
|
292
337
|
s += indent + " ...\n\n"
|
293
338
|
fp.write(s)
|
294
|
-
|
339
|
+
# log.debug("\n" + s)
|
295
340
|
elif item_type_txt == "<class 'module'>":
|
296
341
|
# Skip imported modules
|
297
342
|
# fp.write("# import {}\n".format(item_name))
|
@@ -301,36 +346,42 @@ class Stubber:
|
|
301
346
|
t = item_type_txt[8:-2]
|
302
347
|
s = ""
|
303
348
|
|
304
|
-
if t in
|
349
|
+
if t in ("str", "int", "float", "bool", "bytearray", "bytes"):
|
305
350
|
# known type: use actual value
|
306
|
-
s = "{0}{1} = {2} # type: {3}\n".format(indent, item_name, item_repr, t)
|
307
|
-
|
351
|
+
# s = "{0}{1} = {2} # type: {3}\n".format(indent, item_name, item_repr, t)
|
352
|
+
s = "{0}{1}: {3} = {2}\n".format(indent, item_name, item_repr, t)
|
353
|
+
elif t in ("dict", "list", "tuple"):
|
308
354
|
# dict, list , tuple: use empty value
|
309
355
|
ev = {"dict": "{}", "list": "[]", "tuple": "()"}
|
310
|
-
s = "{0}{1} = {2} # type: {3}\n".format(indent, item_name, ev[t], t)
|
356
|
+
# s = "{0}{1} = {2} # type: {3}\n".format(indent, item_name, ev[t], t)
|
357
|
+
s = "{0}{1}: {3} = {2}\n".format(indent, item_name, ev[t], t)
|
311
358
|
else:
|
312
359
|
# something else
|
313
|
-
if t
|
314
|
-
# Possibly default others to item_instance object ?
|
360
|
+
if t in ("object", "set", "frozenset", "Pin", "generator"): # "FileIO"
|
315
361
|
# https://docs.python.org/3/tutorial/classes.html#item_instance-objects
|
362
|
+
# use these types for the attribute
|
363
|
+
if t == "generator":
|
364
|
+
t = "Generator"
|
365
|
+
s = "{0}{1}: {2} ## = {4}\n".format(indent, item_name, t, item_type_txt, item_repr)
|
366
|
+
else:
|
367
|
+
# Requires Python 3.6 syntax, which is OK for the stubs/pyi
|
316
368
|
t = "Incomplete"
|
317
|
-
|
318
|
-
s = "{0}{1} : {2} ## {3} = {4}\n".format(indent, item_name, t, item_type_txt, item_repr)
|
369
|
+
s = "{0}{1}: {2} ## {3} = {4}\n".format(indent, item_name, t, item_type_txt, item_repr)
|
319
370
|
fp.write(s)
|
320
|
-
|
371
|
+
# log.debug("\n" + s)
|
321
372
|
else:
|
322
373
|
# keep only the name
|
323
|
-
|
374
|
+
# log.debug("# all other, type = '{0}'".format(item_type_txt))
|
324
375
|
fp.write("# all other, type = '{0}'\n".format(item_type_txt))
|
325
376
|
|
326
377
|
fp.write(indent + item_name + " # type: Incomplete\n")
|
327
378
|
|
328
|
-
del items
|
329
|
-
del errors
|
330
|
-
try:
|
331
|
-
|
332
|
-
except (OSError, KeyError, NameError):
|
333
|
-
|
379
|
+
# del items
|
380
|
+
# del errors
|
381
|
+
# try:
|
382
|
+
# del item_name, item_repr, item_type_txt, item_instance # type: ignore
|
383
|
+
# except (OSError, KeyError, NameError):
|
384
|
+
# pass
|
334
385
|
|
335
386
|
@property
|
336
387
|
def flat_fwid(self):
|
@@ -346,7 +397,7 @@ class Stubber:
|
|
346
397
|
"Remove all files from the stub folder"
|
347
398
|
if path is None:
|
348
399
|
path = self.path
|
349
|
-
|
400
|
+
log.info("Clean/remove files in folder: {}".format(path))
|
350
401
|
try:
|
351
402
|
os.stat(path) # TEMP workaround mpremote listdir bug -
|
352
403
|
items = os.listdir(path)
|
@@ -364,41 +415,53 @@ class Stubber:
|
|
364
415
|
except OSError:
|
365
416
|
pass
|
366
417
|
|
367
|
-
def
|
368
|
-
"
|
369
|
-
|
370
|
-
|
371
|
-
self.
|
418
|
+
def report_start(self, filename: str = "modules.json"):
|
419
|
+
"""Start a report of the modules that have been stubbed
|
420
|
+
"create json with list of exported modules"""
|
421
|
+
self._json_name = "{}/{}".format(self.path, filename)
|
422
|
+
self._json_first = True
|
423
|
+
ensure_folder(self._json_name)
|
424
|
+
log.info("Report file: {}".format(self._json_name))
|
372
425
|
gc.collect()
|
373
426
|
try:
|
374
427
|
# write json by node to reduce memory requirements
|
375
|
-
with open(
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
self.
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
428
|
+
with open(self._json_name, "w") as f:
|
429
|
+
f.write("{")
|
430
|
+
f.write(dumps({"firmware": self.info})[1:-1])
|
431
|
+
f.write(",\n")
|
432
|
+
f.write(dumps({"stubber": {"version": __version__}, "stubtype": "firmware"})[1:-1])
|
433
|
+
f.write(",\n")
|
434
|
+
f.write('"modules" :[\n')
|
435
|
+
|
436
|
+
except OSError as e:
|
437
|
+
log.error("Failed to create the report.")
|
438
|
+
self._json_name = None
|
439
|
+
raise e
|
440
|
+
|
441
|
+
def report_add(self, module_name: str, stub_file: str):
|
442
|
+
"Add a module to the report"
|
443
|
+
# write json by node to reduce memory requirements
|
444
|
+
if not self._json_name:
|
445
|
+
raise Exception("No report file")
|
446
|
+
try:
|
447
|
+
with open(self._json_name, "a") as f:
|
448
|
+
if not self._json_first:
|
449
|
+
f.write(",\n")
|
450
|
+
else:
|
451
|
+
self._json_first = False
|
452
|
+
line = '{{"module": "{}", "file": "{}"}}'.format(module_name, stub_file.replace("\\", "/"))
|
453
|
+
f.write(line)
|
394
454
|
|
395
|
-
|
396
|
-
|
397
|
-
f.write(",\n")
|
398
|
-
f.write(n)
|
455
|
+
except OSError:
|
456
|
+
log.error("Failed to create the report.")
|
399
457
|
|
400
|
-
def
|
401
|
-
|
458
|
+
def report_end(self):
|
459
|
+
if not self._json_name:
|
460
|
+
raise Exception("No report file")
|
461
|
+
with open(self._json_name, "a") as f:
|
462
|
+
f.write("\n]}")
|
463
|
+
# is used as sucess indicator
|
464
|
+
log.info("Path: {}".format(self.path))
|
402
465
|
|
403
466
|
|
404
467
|
def ensure_folder(path: str):
|
@@ -424,23 +487,32 @@ def ensure_folder(path: str):
|
|
424
487
|
|
425
488
|
|
426
489
|
def _build(s):
|
427
|
-
# extract
|
490
|
+
# extract build from sys.version or os.uname().version if available
|
491
|
+
# sys.version: 'MicroPython v1.23.0-preview.6.g3d0b6276f'
|
492
|
+
# sys.implementation.version: 'v1.13-103-gb137d064e'
|
428
493
|
if not s:
|
429
494
|
return ""
|
430
|
-
if " on " in s
|
431
|
-
|
432
|
-
|
495
|
+
s = s.split(" on ", 1)[0] if " on " in s else s
|
496
|
+
if s.startswith("v"):
|
497
|
+
if not "-" in s:
|
498
|
+
return ""
|
499
|
+
b = s.split("-")[1]
|
500
|
+
return b
|
501
|
+
if not "-preview" in s:
|
502
|
+
return ""
|
503
|
+
b = s.split("-preview")[1].split(".")[1]
|
504
|
+
return b
|
433
505
|
|
434
506
|
|
435
507
|
def _info(): # type:() -> dict[str, str]
|
436
508
|
info = OrderedDict(
|
437
509
|
{
|
438
|
-
"family": sys.implementation.name,
|
510
|
+
"family": sys.implementation.name, # type: ignore
|
439
511
|
"version": "",
|
440
512
|
"build": "",
|
441
513
|
"ver": "",
|
442
514
|
"port": sys.platform, # port: esp32 / win32 / linux / stm32
|
443
|
-
"board": "
|
515
|
+
"board": "UNKNOWN",
|
444
516
|
"cpu": "",
|
445
517
|
"mpy": "",
|
446
518
|
"arch": "",
|
@@ -454,56 +526,44 @@ def _info(): # type:() -> dict[str, str]
|
|
454
526
|
elif info["port"] == "linux":
|
455
527
|
info["port"] = "unix"
|
456
528
|
try:
|
457
|
-
info["version"] =
|
529
|
+
info["version"] = version_str(sys.implementation.version) # type: ignore
|
458
530
|
except AttributeError:
|
459
531
|
pass
|
460
532
|
try:
|
461
|
-
|
462
|
-
info["board"] =
|
463
|
-
info["
|
533
|
+
_machine = sys.implementation._machine if "_machine" in dir(sys.implementation) else os.uname().machine # type: ignore
|
534
|
+
# info["board"] = "with".join(_machine.split("with")[:-1]).strip()
|
535
|
+
info["board"] = _machine
|
536
|
+
info["cpu"] = _machine.split("with")[-1].strip()
|
464
537
|
info["mpy"] = (
|
465
|
-
sys.implementation._mpy
|
538
|
+
sys.implementation._mpy # type: ignore
|
466
539
|
if "_mpy" in dir(sys.implementation)
|
467
|
-
else sys.implementation.mpy
|
540
|
+
else sys.implementation.mpy # type: ignore
|
468
541
|
if "mpy" in dir(sys.implementation)
|
469
542
|
else ""
|
470
543
|
)
|
471
544
|
except (AttributeError, IndexError):
|
472
545
|
pass
|
473
|
-
|
474
|
-
for filename in [d + "/board_info.csv" for d in LIBS]:
|
475
|
-
# print("look up the board name in the file", filename)
|
476
|
-
if file_exists(filename):
|
477
|
-
# print("Found board info file: {}".format(filename))
|
478
|
-
b = info["board"].strip()
|
479
|
-
if find_board(info, b, filename):
|
480
|
-
break
|
481
|
-
if "with" in b:
|
482
|
-
b = b.split("with")[0].strip()
|
483
|
-
if find_board(info, b, filename):
|
484
|
-
break
|
485
|
-
info["board"] = "GENERIC"
|
486
|
-
info["board"] = info["board"].replace(" ", "_")
|
487
|
-
gc.collect()
|
546
|
+
info["board"] = get_boardname()
|
488
547
|
|
489
548
|
try:
|
490
|
-
|
491
|
-
|
492
|
-
|
493
|
-
|
494
|
-
|
495
|
-
|
496
|
-
|
497
|
-
|
498
|
-
|
549
|
+
if "uname" in dir(os): # old
|
550
|
+
# extract build from uname().version if available
|
551
|
+
info["build"] = _build(os.uname()[3]) # type: ignore
|
552
|
+
if not info["build"]:
|
553
|
+
# extract build from uname().release if available
|
554
|
+
info["build"] = _build(os.uname()[2]) # type: ignore
|
555
|
+
elif "version" in dir(sys): # new
|
556
|
+
# extract build from sys.version if available
|
557
|
+
info["build"] = _build(sys.version)
|
558
|
+
except (AttributeError, IndexError, TypeError):
|
499
559
|
pass
|
500
560
|
# avoid build hashes
|
501
|
-
if info["build"] and len(info["build"]) > 5:
|
502
|
-
|
561
|
+
# if info["build"] and len(info["build"]) > 5:
|
562
|
+
# info["build"] = ""
|
503
563
|
|
504
564
|
if info["version"] == "" and sys.platform not in ("unix", "win32"):
|
505
565
|
try:
|
506
|
-
u = os.uname()
|
566
|
+
u = os.uname() # type: ignore
|
507
567
|
info["version"] = u.release
|
508
568
|
except (IndexError, AttributeError, TypeError):
|
509
569
|
pass
|
@@ -525,13 +585,14 @@ def _info(): # type:() -> dict[str, str]
|
|
525
585
|
info["release"] = "2.0.0"
|
526
586
|
|
527
587
|
if info["family"] == "micropython":
|
588
|
+
info["version"]
|
528
589
|
if (
|
529
590
|
info["version"]
|
530
591
|
and info["version"].endswith(".0")
|
531
592
|
and info["version"] >= "1.10.0" # versions from 1.10.0 to 1.20.0 do not have a micro .0
|
532
593
|
and info["version"] <= "1.19.9"
|
533
594
|
):
|
534
|
-
#
|
595
|
+
# versions from 1.10.0 to 1.20.0 do not have a micro .0
|
535
596
|
info["version"] = info["version"][:-2]
|
536
597
|
|
537
598
|
# spell-checker: disable
|
@@ -555,25 +616,31 @@ def _info(): # type:() -> dict[str, str]
|
|
555
616
|
info["arch"] = arch
|
556
617
|
# .mpy version.minor
|
557
618
|
info["mpy"] = "v{}.{}".format(sys_mpy & 0xFF, sys_mpy >> 8 & 3)
|
619
|
+
if info["build"] and not info["version"].endswith("-preview"):
|
620
|
+
info["version"] = info["version"] + "-preview"
|
558
621
|
# simple to use version[-build] string
|
559
|
-
info["ver"] = f"
|
622
|
+
info["ver"] = f"{info['version']}-{info['build']}" if info["build"] else f"{info['version']}"
|
560
623
|
|
561
624
|
return info
|
562
625
|
|
563
626
|
|
564
|
-
def
|
565
|
-
"
|
566
|
-
|
567
|
-
|
568
|
-
|
569
|
-
|
570
|
-
|
571
|
-
|
572
|
-
|
573
|
-
|
574
|
-
|
575
|
-
|
576
|
-
|
627
|
+
def version_str(version: tuple): # -> str:
|
628
|
+
v_str = ".".join([str(n) for n in version[:3]])
|
629
|
+
if len(version) > 3 and version[3]:
|
630
|
+
v_str += "-" + version[3]
|
631
|
+
return v_str
|
632
|
+
|
633
|
+
|
634
|
+
def get_boardname() -> str:
|
635
|
+
"Read the board name from the boardname.py file that may have been created upfront"
|
636
|
+
try:
|
637
|
+
from boardname import BOARDNAME # type: ignore
|
638
|
+
|
639
|
+
log.info("Found BOARDNAME: {}".format(BOARDNAME))
|
640
|
+
except ImportError:
|
641
|
+
log.warning("BOARDNAME not found")
|
642
|
+
BOARDNAME = ""
|
643
|
+
return BOARDNAME
|
577
644
|
|
578
645
|
|
579
646
|
def get_root() -> str: # sourcery skip: use-assigned-variable
|
@@ -626,10 +693,6 @@ def is_micropython() -> bool:
|
|
626
693
|
# pylint: disable=unused-variable,eval-used
|
627
694
|
try:
|
628
695
|
# either test should fail on micropython
|
629
|
-
# a) https://docs.micropython.org/en/latest/genrst/syntax.html#spaces
|
630
|
-
# Micropython : SyntaxError
|
631
|
-
# a = eval("1and 0") # lgtm [py/unused-local-variable]
|
632
|
-
# Eval blocks some minification aspects
|
633
696
|
|
634
697
|
# b) https://docs.micropython.org/en/latest/genrst/builtin_types.html#bytes-with-keywords-not-implemented
|
635
698
|
# Micropython: NotImplementedError
|
@@ -651,40 +714,40 @@ def main():
|
|
651
714
|
stubber.clean()
|
652
715
|
# Read stubs from modulelist in the current folder or in /libs
|
653
716
|
# fall back to default modules
|
654
|
-
stubber
|
655
|
-
|
656
|
-
|
657
|
-
|
658
|
-
|
659
|
-
|
660
|
-
|
661
|
-
|
662
|
-
|
717
|
+
def get_modulelist(stubber):
|
718
|
+
# new
|
719
|
+
gc.collect()
|
720
|
+
stubber.modules = [] # avoid duplicates
|
721
|
+
for p in LIBS:
|
722
|
+
fname = p + "/modulelist.txt"
|
723
|
+
if not file_exists(fname):
|
724
|
+
continue
|
725
|
+
with open(fname) as f:
|
726
|
+
# print("DEBUG: list of modules: " + p + "/modulelist.txt")
|
727
|
+
while True:
|
728
|
+
line = f.readline().strip()
|
729
|
+
if not line:
|
730
|
+
break
|
663
731
|
if len(line) > 0 and line[0] != "#":
|
664
732
|
stubber.modules.append(line)
|
665
|
-
|
666
|
-
|
667
|
-
print("Debug: Used memory to load modulelist.txt: " + str(_1 - gc.mem_free()) + " bytes") # type: ignore
|
733
|
+
gc.collect()
|
734
|
+
print("BREAK")
|
668
735
|
break
|
669
|
-
|
670
|
-
|
671
|
-
|
672
|
-
|
673
|
-
|
736
|
+
|
737
|
+
if not stubber.modules:
|
738
|
+
stubber.modules = ["micropython"]
|
739
|
+
# _log.warn("Could not find modulelist.txt, using default modules")
|
740
|
+
gc.collect()
|
741
|
+
|
742
|
+
stubber.modules = [] # avoid duplicates
|
743
|
+
get_modulelist(stubber)
|
674
744
|
|
675
745
|
gc.collect()
|
676
746
|
|
677
747
|
stubber.create_all_stubs()
|
678
|
-
stubber.report()
|
679
748
|
|
680
749
|
|
681
750
|
if __name__ == "__main__" or is_micropython():
|
682
|
-
try:
|
683
|
-
log = logging.getLogger("stubber")
|
684
|
-
logging.basicConfig(level=logging.INFO)
|
685
|
-
# logging.basicConfig(level=logging.DEBUG)
|
686
|
-
except NameError:
|
687
|
-
pass
|
688
751
|
if not file_exists("no_auto_stubber.txt"):
|
689
752
|
try:
|
690
753
|
gc.threshold(4 * 1024) # type: ignore
|