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