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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. {micropython_stubber-1.16.3.dist-info → micropython_stubber-1.17.0.dist-info}/METADATA +1 -1
  2. {micropython_stubber-1.16.3.dist-info → micropython_stubber-1.17.0.dist-info}/RECORD +48 -49
  3. stubber/__init__.py +1 -1
  4. stubber/basicgit.py +11 -13
  5. stubber/board/createstubs.py +138 -97
  6. stubber/board/createstubs_db.py +211 -239
  7. stubber/board/createstubs_db_min.py +322 -844
  8. stubber/board/createstubs_db_mpy.mpy +0 -0
  9. stubber/board/createstubs_lvgl.py +91 -137
  10. stubber/board/createstubs_lvgl_min.py +87 -129
  11. stubber/board/createstubs_lvgl_mpy.mpy +0 -0
  12. stubber/board/createstubs_mem.py +164 -199
  13. stubber/board/createstubs_mem_min.py +297 -791
  14. stubber/board/createstubs_mem_mpy.mpy +0 -0
  15. stubber/board/createstubs_min.py +286 -1009
  16. stubber/board/createstubs_mpy.mpy +0 -0
  17. stubber/board/modulelist.txt +1 -2
  18. stubber/codemod/_partials/__init__.py +1 -1
  19. stubber/codemod/_partials/db_main.py +90 -72
  20. stubber/codemod/_partials/modules_reader.py +29 -17
  21. stubber/codemod/board.py +2 -4
  22. stubber/codemod/enrich.py +1 -1
  23. stubber/commands/build_cmd.py +6 -4
  24. stubber/commands/get_docstubs_cmd.py +6 -11
  25. stubber/commands/get_frozen_cmd.py +6 -11
  26. stubber/commands/switch_cmd.py +6 -4
  27. stubber/freeze/freeze_manifest_2.py +2 -1
  28. stubber/freeze/get_frozen.py +28 -13
  29. stubber/minify.py +51 -38
  30. stubber/publish/candidates.py +15 -23
  31. stubber/publish/defaults.py +2 -2
  32. stubber/publish/merge_docstubs.py +5 -7
  33. stubber/publish/missing_class_methods.py +2 -2
  34. stubber/publish/pathnames.py +2 -2
  35. stubber/publish/publish.py +2 -1
  36. stubber/publish/stubpackage.py +20 -41
  37. stubber/rst/lookup.py +9 -7
  38. stubber/rst/reader.py +2 -1
  39. stubber/stubber.py +5 -6
  40. stubber/update_fallback.py +3 -1
  41. stubber/utils/__init__.py +1 -1
  42. stubber/utils/config.py +7 -9
  43. stubber/utils/repos.py +6 -5
  44. stubber/utils/versions.py +48 -7
  45. stubber/variants.py +3 -3
  46. stubber/board/logging.py +0 -99
  47. {micropython_stubber-1.16.3.dist-info → micropython_stubber-1.17.0.dist-info}/LICENSE +0 -0
  48. {micropython_stubber-1.16.3.dist-info → micropython_stubber-1.17.0.dist-info}/WHEEL +0 -0
  49. {micropython_stubber-1.16.3.dist-info → micropython_stubber-1.17.0.dist-info}/entry_points.txt +0 -0
@@ -18,12 +18,11 @@ 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.16.3
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
29
28
  from time import sleep
@@ -43,26 +42,49 @@ try:
43
42
  except ImportError:
44
43
  from ucollections import OrderedDict # type: ignore
45
44
 
46
- try:
47
- from nope_machine import WDT
45
+ __version__ = "v1.17.0"
46
+ ENOENT = 2
47
+ _MAX_CLASS_LEVEL = 2 # Max class nesting
48
+ LIBS = ["lib", "/lib", "/sd/lib", "/flash/lib", "."]
48
49
 
49
- wdt = WDT()
50
50
 
51
- except ImportError:
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
52
59
 
53
- class _WDT:
54
- def feed(self):
55
- pass
60
+ @staticmethod
61
+ def getLogger(name):
62
+ return logging()
56
63
 
57
- wdt = _WDT()
64
+ @classmethod
65
+ def basicConfig(cls, level):
66
+ cls.level = level
58
67
 
68
+ # def debug(self, msg):
69
+ # if self.level <= logging.DEBUG:
70
+ # self.prnt("DEBUG :", msg)
59
71
 
60
- wdt.feed()
72
+ def info(self, msg):
73
+ if self.level <= logging.INFO:
74
+ self.prnt("INFO :", msg)
61
75
 
62
- __version__ = "v1.16.3"
63
- ENOENT = 2
64
- _MAX_CLASS_LEVEL = 2 # Max class nesting
65
- LIBS = [".", "/lib", "/sd/lib", "/flash/lib", "lib"]
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)
66
88
 
67
89
 
68
90
  class Stubber:
@@ -74,13 +96,10 @@ class Stubber:
74
96
  raise NotImplementedError("MicroPython 1.13.0 cannot be stubbed")
75
97
  except AttributeError:
76
98
  pass
77
- self.log = logging.getLogger("stubber")
78
- self._report = [] # type: list[str]
79
99
  self.info = _info()
80
- self.log.info("Port: {}".format(self.info["port"]))
81
- self.log.info("Board: {}".format(self.info["board"]))
100
+ log.info("Port: {}".format(self.info["port"]))
101
+ log.info("Board: {}".format(self.info["board"]))
82
102
  gc.collect()
83
- wdt.feed()
84
103
  if firmware_id:
85
104
  self._fwid = firmware_id.lower()
86
105
  else:
@@ -97,11 +116,11 @@ class Stubber:
97
116
  path = get_root()
98
117
 
99
118
  self.path = "{}/stubs/{}".format(path, self.flat_fwid).replace("//", "/")
100
- self.log.debug(self.path)
119
+ # log.debug(self.path)
101
120
  try:
102
121
  ensure_folder(path + "/")
103
122
  except OSError:
104
- self.log.error("error creating stub folder {}".format(path))
123
+ log.error("error creating stub folder {}".format(path))
105
124
  self.problematic = [
106
125
  "upip",
107
126
  "upysh",
@@ -120,21 +139,23 @@ class Stubber:
120
139
  ]
121
140
  # there is no option to discover modules from micropython, list is read from an external file.
122
141
  self.modules = [] # type: list[str]
142
+ self._json_name = None
143
+ self._json_first = False
123
144
 
124
145
  def get_obj_attributes(self, item_instance: object):
125
146
  "extract information of the objects members and attributes"
126
147
  # name_, repr_(value), type as text, item_instance
127
148
  _result = []
128
149
  _errors = []
129
- self.log.debug("get attributes {} {}".format(repr(item_instance), item_instance))
150
+ # log.debug("get attributes {} {}".format(repr(item_instance), item_instance))
130
151
  for name in dir(item_instance):
131
- if name.startswith("_") and not name in self.modules:
152
+ if name.startswith("__") and not name in self.modules:
132
153
  continue
133
- self.log.debug("get attribute {}".format(name))
154
+ # log.debug("get attribute {}".format(name))
134
155
  try:
135
156
  val = getattr(item_instance, name)
136
157
  # name , item_repr(value) , type as text, item_instance, order
137
- self.log.debug("attribute {}:{}".format(name, val))
158
+ # log.debug("attribute {}:{}".format(name, val))
138
159
  try:
139
160
  type_text = repr(type(val)).split("'")[1]
140
161
  except IndexError:
@@ -167,22 +188,23 @@ class Stubber:
167
188
 
168
189
  def create_all_stubs(self):
169
190
  "Create stubs for all configured modules"
170
- self.log.info("Start micropython-stubber v{} on {}".format(__version__, self._fwid))
191
+ log.info("Start micropython-stubber {} on {}".format(__version__, self._fwid))
192
+ self.report_start()
171
193
  gc.collect()
172
194
  for module_name in self.modules:
173
195
  self.create_one_stub(module_name)
174
- self.log.info("Finally done")
196
+ self.report_end()
197
+ log.info("Finally done")
175
198
 
176
199
  def create_one_stub(self, module_name: str):
177
- wdt.feed()
178
200
  if module_name in self.problematic:
179
- self.log.warning("Skip module: {:<25} : Known problematic".format(module_name))
201
+ log.warning("Skip module: {:<25} : Known problematic".format(module_name))
180
202
  return False
181
203
  if module_name in self.excluded:
182
- self.log.warning("Skip module: {:<25} : Excluded".format(module_name))
204
+ log.warning("Skip module: {:<25} : Excluded".format(module_name))
183
205
  return False
184
206
 
185
- file_name = "{}/{}.py".format(self.path, module_name.replace(".", "/"))
207
+ file_name = "{}/{}.pyi".format(self.path, module_name.replace(".", "/"))
186
208
  gc.collect()
187
209
  result = False
188
210
  try:
@@ -197,10 +219,10 @@ class Stubber:
197
219
 
198
220
  Args:
199
221
  - module_name (str): name of the module to document. This module will be imported.
200
- - file_name (Optional[str]): the 'path/filename.py' to write to. If omitted will be created based on the module name.
222
+ - file_name (Optional[str]): the 'path/filename.pyi' to write to. If omitted will be created based on the module name.
201
223
  """
202
224
  if file_name is None:
203
- fname = module_name.replace(".", "_") + ".py"
225
+ fname = module_name.replace(".", "_") + ".pyi"
204
226
  file_name = self.path + "/" + fname
205
227
  else:
206
228
  fname = file_name.split("/")[-1]
@@ -214,10 +236,10 @@ class Stubber:
214
236
  try:
215
237
  new_module = __import__(module_name, None, None, ("*"))
216
238
  m1 = gc.mem_free() # type: ignore
217
- self.log.info("Stub module: {:<25} to file: {:<70} mem:{:>5}".format(module_name, fname, m1))
239
+ log.info("Stub module: {:<25} to file: {:<70} mem:{:>5}".format(module_name, fname, m1))
218
240
 
219
241
  except ImportError:
220
- self.log.warning("Skip module: {:<25} {:<79}".format(module_name, "Module not found."))
242
+ # log.debug("Skip module: {:<25} {:<79}".format(module_name, "Module not found."))
221
243
  return False
222
244
 
223
245
  # Start a new file
@@ -227,22 +249,18 @@ class Stubber:
227
249
  info_ = str(self.info).replace("OrderedDict(", "").replace("})", "}")
228
250
  s = '"""\nModule: \'{0}\' on {1}\n"""\n# MCU: {2}\n# Stubber: {3}\n'.format(module_name, self._fwid, info_, __version__)
229
251
  fp.write(s)
230
- fp.write("from __future__ import annotations\nfrom 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")
231
253
  self.write_object_stub(fp, new_module, module_name, "")
232
254
 
233
- self._report.append('{{"module": "{}", "file": "{}"}}'.format(module_name, file_name.replace("\\", "/")))
255
+ self.report_add(module_name, file_name)
234
256
 
235
257
  if module_name not in {"os", "sys", "logging", "gc"}:
236
258
  # try to unload the module unless we use it
237
259
  try:
238
260
  del new_module
239
261
  except (OSError, KeyError): # lgtm [py/unreachable-statement]
240
- self.log.warning("could not del new_module")
241
- # lets not try - most times it does not work anyway
242
- # try:
243
- # del sys.modules[module_name]
244
- # except KeyError:
245
- # self.log.warning("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
246
264
  gc.collect()
247
265
  return True
248
266
 
@@ -250,14 +268,14 @@ class Stubber:
250
268
  "Write a module/object stub to an open file. Can be called recursive."
251
269
  gc.collect()
252
270
  if object_expr in self.problematic:
253
- self.log.warning("SKIPPING problematic module:{}".format(object_expr))
271
+ log.warning("SKIPPING problematic module:{}".format(object_expr))
254
272
  return
255
273
 
256
- # self.log.debug("DUMP : {}".format(object_expr))
274
+ # # log.debug("DUMP : {}".format(object_expr))
257
275
  items, errors = self.get_obj_attributes(object_expr)
258
276
 
259
277
  if errors:
260
- self.log.error(errors)
278
+ log.error(errors)
261
279
 
262
280
  for item_name, item_repr, item_type_txt, item_instance, _ in items:
263
281
  # name_, repr_(value), type as text, item_instance, order
@@ -265,7 +283,7 @@ class Stubber:
265
283
  # do not create stubs for these primitives
266
284
  continue
267
285
  if item_name[0].isdigit():
268
- self.log.warning("NameError: invalid name {}".format(item_name))
286
+ log.warning("NameError: invalid name {}".format(item_name))
269
287
  continue
270
288
  # Class expansion only on first 3 levels (bit of a hack)
271
289
  if (
@@ -274,7 +292,7 @@ class Stubber:
274
292
  # and not obj_name.endswith(".Pin")
275
293
  # avoid expansion of Pin.cpu / Pin.board to avoid crashes on most platforms
276
294
  ):
277
- self.log.info("{0}class {1}:".format(indent, item_name))
295
+ # log.debug("{0}class {1}:".format(indent, item_name))
278
296
  superclass = ""
279
297
  is_exception = (
280
298
  item_name.endswith("Exception")
@@ -297,7 +315,7 @@ class Stubber:
297
315
  # write classdef
298
316
  fp.write(s)
299
317
  # first write the class literals and methods
300
- self.log.debug("# recursion over class {0}".format(item_name))
318
+ # log.debug("# recursion over class {0}".format(item_name))
301
319
  self.write_object_stub(
302
320
  fp,
303
321
  item_instance,
@@ -311,7 +329,7 @@ class Stubber:
311
329
  s += indent + " ...\n\n"
312
330
  fp.write(s)
313
331
  elif any(word in item_type_txt for word in ["method", "function", "closure"]):
314
- self.log.debug("# def {1} function/method/closure, type = '{0}'".format(item_type_txt, item_name))
332
+ # log.debug("# def {1} function/method/closure, type = '{0}'".format(item_type_txt, item_name))
315
333
  # module Function or class method
316
334
  # will accept any number of params
317
335
  # return type Any/Incomplete
@@ -327,7 +345,7 @@ class Stubber:
327
345
  s = "{}def {}({}*args, **kwargs) -> {}:\n".format(indent, item_name, first, ret)
328
346
  s += indent + " ...\n\n"
329
347
  fp.write(s)
330
- self.log.debug("\n" + s)
348
+ # log.debug("\n" + s)
331
349
  elif item_type_txt == "<class 'module'>":
332
350
  # Skip imported modules
333
351
  # fp.write("# import {}\n".format(item_name))
@@ -337,28 +355,32 @@ class Stubber:
337
355
  t = item_type_txt[8:-2]
338
356
  s = ""
339
357
 
340
- if t in ["str", "int", "float", "bool", "bytearray", "bytes"]:
358
+ if t in ("str", "int", "float", "bool", "bytearray", "bytes"):
341
359
  # known type: use actual value
342
- s = "{0}{1} = {2} # type: {3}\n".format(indent, item_name, item_repr, t)
343
- elif t in ["dict", "list", "tuple"]:
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"):
344
363
  # dict, list , tuple: use empty value
345
364
  ev = {"dict": "{}", "list": "[]", "tuple": "()"}
346
- 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)
347
367
  else:
348
368
  # something else
349
- if t in ["object", "set", "frozenset", "Pin", "FileIO"]:
369
+ if t in ("object", "set", "frozenset", "Pin", "generator"): # "FileIO"
350
370
  # https://docs.python.org/3/tutorial/classes.html#item_instance-objects
351
- # use these types for the attribute
352
- s = "{0}{1} : {2} ## = {4}\n".format(indent, item_name, t, item_type_txt, item_repr)
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)
353
375
  else:
354
376
  # Requires Python 3.6 syntax, which is OK for the stubs/pyi
355
377
  t = "Incomplete"
356
- 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)
357
379
  fp.write(s)
358
- self.log.debug("\n" + s)
380
+ # log.debug("\n" + s)
359
381
  else:
360
382
  # keep only the name
361
- self.log.debug("# all other, type = '{0}'".format(item_type_txt))
383
+ # log.debug("# all other, type = '{0}'".format(item_type_txt))
362
384
  fp.write("# all other, type = '{0}'\n".format(item_type_txt))
363
385
 
364
386
  fp.write(indent + item_name + " # type: Incomplete\n")
@@ -382,10 +404,9 @@ class Stubber:
382
404
 
383
405
  def clean(self, path: str = None): # type: ignore
384
406
  "Remove all files from the stub folder"
385
- wdt.feed()
386
407
  if path is None:
387
408
  path = self.path
388
- self.log.info("Clean/remove files in folder: {}".format(path))
409
+ log.info("Clean/remove files in folder: {}".format(path))
389
410
  try:
390
411
  os.stat(path) # TEMP workaround mpremote listdir bug -
391
412
  items = os.listdir(path)
@@ -403,42 +424,53 @@ class Stubber:
403
424
  except OSError:
404
425
  pass
405
426
 
406
- def report(self, filename: str = "modules.json"):
407
- "create json with list of exported modules"
408
- wdt.feed()
409
- self.log.info("Created stubs for {} modules on board {}\nPath: {}".format(len(self._report), self._fwid, self.path))
410
- f_name = "{}/{}".format(self.path, filename)
411
- self.log.info("Report file: {}".format(f_name))
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))
412
434
  gc.collect()
413
435
  try:
414
436
  # write json by node to reduce memory requirements
415
- with open(f_name, "w") as f:
416
- self.write_json_header(f)
417
- first = True
418
- for n in self._report:
419
- self.write_json_node(f, n, first)
420
- first = False
421
- self.write_json_end(f)
422
- used = self._start_free - gc.mem_free() # type: ignore
423
- self.log.info("Memory used: {0} Kb".format(used // 1024))
424
- except OSError:
425
- self.log.error("Failed to create the report.")
426
-
427
- def write_json_header(self, f):
428
- f.write("{")
429
- f.write(dumps({"firmware": self.info})[1:-1])
430
- f.write(",\n")
431
- f.write(dumps({"stubber": {"version": __version__}, "stubtype": "firmware"})[1:-1])
432
- f.write(",\n")
433
- f.write('"modules" :[\n')
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)
434
463
 
435
- def write_json_node(self, f, n, first):
436
- if not first:
437
- f.write(",\n")
438
- f.write(n)
464
+ except OSError:
465
+ log.error("Failed to create the report.")
439
466
 
440
- def write_json_end(self, f):
441
- f.write("\n]}")
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))
442
474
 
443
475
 
444
476
  def ensure_folder(path: str):
@@ -484,7 +516,7 @@ def _build(s):
484
516
  def _info(): # type:() -> dict[str, str]
485
517
  info = OrderedDict(
486
518
  {
487
- "family": sys.implementation.name,
519
+ "family": sys.implementation.name, # type: ignore
488
520
  "version": "",
489
521
  "build": "",
490
522
  "ver": "",
@@ -512,9 +544,9 @@ def _info(): # type:() -> dict[str, str]
512
544
  info["board"] = _machine
513
545
  info["cpu"] = _machine.split("with")[-1].strip()
514
546
  info["mpy"] = (
515
- sys.implementation._mpy
547
+ sys.implementation._mpy # type: ignore
516
548
  if "_mpy" in dir(sys.implementation)
517
- else sys.implementation.mpy
549
+ else sys.implementation.mpy # type: ignore
518
550
  if "mpy" in dir(sys.implementation)
519
551
  else ""
520
552
  )
@@ -608,79 +640,16 @@ def version_str(version: tuple): # -> str:
608
640
  return v_str
609
641
 
610
642
 
611
- def read_boardname(info, desc: str = ""):
612
- info["board"] = info["board"].replace(" ", "_")
613
- found = False
614
- for filename in [d + "/board_name.txt" for d in LIBS]:
615
- wdt.feed()
616
- # print("look up the board name in the file", filename)
617
- if file_exists(filename):
618
- with open(filename, "r") as file:
619
- data = file.read()
620
- if data:
621
- info["board"] = data.strip()
622
- found = True
623
- break
624
- if not found:
625
- print("Board not found, guessing board name")
626
- descr = ""
627
- # descr = desc or info["board"].strip()
628
- # if "with " + info["cpu"].upper() in descr:
629
- # # remove the with cpu part
630
- # descr = descr.split("with " + info["cpu"].upper())[0].strip()
631
- info["board"] = descr
632
-
633
-
634
- # def read_boardname(info, desc: str = ""):
635
- # wdt.feed()
636
- # # print("look up the board name in the file", filename)
637
- # if file_exists(filename):
638
- # descr = desc or info["board"].strip()
639
- # pos = descr.rfind(" with")
640
- # if pos != -1:
641
- # short_descr = descr[:pos].strip()
642
- # else:
643
- # short_descr = ""
644
- # print("searching info file: {} for: '{}' or '{}'".format(filename, descr, short_descr))
645
- # if find_board(info, descr, filename, short_descr):
646
- # found = True
647
- # break
648
- # if not found:
649
- # print("Board not found, guessing board name")
650
- # descr = desc or info["board"].strip()
651
- # if "with " + info["cpu"].upper() in descr:
652
- # # remove the with cpu part
653
- # descr = descr.split("with " + info["cpu"].upper())[0].strip()
654
- # info["board"] = descr
655
- # info["board"] = info["board"].replace(" ", "_")
656
- # gc.collect()
657
-
658
-
659
- # def find_board(info: dict, descr: str, filename: str, short_descr: str):
660
- # "Find the board in the provided board_info.csv file"
661
- # short_hit = ""
662
- # with open(filename, "r") as file:
663
- # # ugly code to make testable in python and micropython
664
- # # TODO: This is VERY slow on micropython whith MPREMOTE mount on esp32 (2-3 minutes to read file)
665
- # while 1:
666
- # line = file.readline()
667
- # if not line:
668
- # break
669
- # descr_, board_ = line.split(",")[0].strip(), line.split(",")[1].strip()
670
- # if descr_ == descr:
671
- # info["board"] = board_
672
- # return True
673
- # elif short_descr and descr_ == short_descr:
674
- # if "with" in short_descr:
675
- # # Good enough - no need to trawl the entire file
676
- # info["board"] = board_
677
- # return True
678
- # # good enough if not found in the rest of the file (but slow)
679
- # short_hit = board_
680
- # if short_hit:
681
- # info["board"] = short_hit
682
- # return True
683
- # return False
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
684
653
 
685
654
 
686
655
  def get_root() -> str: # sourcery skip: use-assigned-variable
@@ -733,10 +702,6 @@ def is_micropython() -> bool:
733
702
  # pylint: disable=unused-variable,eval-used
734
703
  try:
735
704
  # either test should fail on micropython
736
- # a) https://docs.micropython.org/en/latest/genrst/syntax.html#spaces
737
- # Micropython : SyntaxError
738
- # a = eval("1and 0") # lgtm [py/unused-local-variable]
739
- # Eval blocks some minification aspects
740
705
 
741
706
  # b) https://docs.micropython.org/en/latest/genrst/builtin_types.html#bytes-with-keywords-not-implemented
742
707
  # Micropython: NotImplementedError
@@ -750,92 +715,99 @@ def is_micropython() -> bool:
750
715
  return True
751
716
 
752
717
 
753
- def main():
754
- import machine # type: ignore
718
+ SKIP_FILE = "modulelist.done"
719
+
755
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
756
754
  try:
757
- f = open("modulelist.done", "r+b")
758
- was_running = True
759
- print("Opened existing db")
755
+ with open(SKIP_FILE) as f:
756
+ done = int(f.readline().strip())
760
757
  except OSError:
761
- f = open("modulelist.done", "w+b")
762
- print("created new db")
763
- was_running = False
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
764
777
  stubber = Stubber(path=read_path())
765
778
 
766
779
  # f_name = "{}/{}".format(stubber.path, "modules.json")
780
+ skip = 0
767
781
  if not was_running:
768
782
  # Only clean folder if this is a first run
769
783
  stubber.clean()
770
- # get list of modules to process
771
- get_modulelist(stubber)
772
- # remove the ones that are already done
773
- modules_done = {} # type: dict[str, str]
774
- try:
775
- with open("modulelist.done") as f:
776
- # not optimal , but works on mpremote and esp8266
777
- for line in f.read().split("\n"):
778
- line = line.strip()
779
- gc.collect()
780
- if len(line) > 0:
781
- key, value = line.split("=", 1)
782
- modules_done[key] = value
783
- except (OSError, SyntaxError):
784
- pass
785
- gc.collect()
786
- # see if we can continue from where we left off
787
- modules = [m for m in stubber.modules if m not in modules_done.keys()]
788
- gc.collect()
789
- 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):
790
790
  # ------------------------------------
791
791
  # do epic shit
792
792
  # but sometimes things fail / run out of memory and reboot
793
- ok = False
794
793
  try:
795
- ok = stubber.create_one_stub(modulename)
794
+ stubber.create_one_stub(modulename)
796
795
  except MemoryError:
797
796
  # RESET AND HOPE THAT IN THE NEXT CYCLE WE PROGRESS FURTHER
798
797
  machine.reset()
799
798
  # -------------------------------------
800
799
  gc.collect()
801
- modules_done[modulename] = str(stubber._report[-1] if ok else "failed")
802
- with open("modulelist.done", "a") as f:
803
- f.write("{}={}\n".format(modulename, "ok" if ok else "failed"))
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)
804
805
 
805
- # Finished processing - load all the results , and remove the failed ones
806
- if modules_done:
807
- # stubber.write_json_end(mod_fp)
808
- stubber._report = [v for _, v in modules_done.items() if v != "failed"]
809
- stubber.report()
810
-
811
-
812
- def get_modulelist(stubber):
813
- stubber.modules = [] # avoid duplicates
814
- for p in LIBS:
815
- try:
816
- with open(p + "/modulelist.txt") as f:
817
- print("DEBUG: list of modules: " + p + "/modulelist.txt")
818
- for line in f.read().split("\n"):
819
- line = line.strip()
820
- if len(line) > 0 and line[0] != "#":
821
- stubber.modules.append(line)
822
- gc.collect()
823
- break
824
- except OSError:
825
- pass
826
- if not stubber.modules:
827
- stubber.modules = ["micropython"]
828
- _log.warn("Could not find modulelist.txt, using default modules")
829
- gc.collect()
806
+ print("All modules have been processed, Finalizing report")
807
+ stubber.report_end()
830
808
 
831
809
 
832
810
  if __name__ == "__main__" or is_micropython():
833
- try:
834
- log = logging.getLogger("stubber")
835
- logging.basicConfig(level=logging.INFO)
836
- # logging.basicConfig(level=logging.DEBUG)
837
- except NameError:
838
- pass
839
811
  if not file_exists("no_auto_stubber.txt"):
840
812
  try:
841
813
  gc.threshold(4 * 1024) # type: ignore