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.
Files changed (55) hide show
  1. {micropython_stubber-1.16.2.dist-info → micropython_stubber-1.17.0.dist-info}/METADATA +2 -1
  2. {micropython_stubber-1.16.2.dist-info → micropython_stubber-1.17.0.dist-info}/RECORD +54 -54
  3. stubber/__init__.py +1 -1
  4. stubber/basicgit.py +27 -33
  5. stubber/board/board_info.csv +137 -103
  6. stubber/board/createstubs.py +222 -189
  7. stubber/board/createstubs_db.py +284 -214
  8. stubber/board/createstubs_db_min.py +286 -265
  9. stubber/board/createstubs_db_mpy.mpy +0 -0
  10. stubber/board/createstubs_lvgl.py +171 -113
  11. stubber/board/createstubs_lvgl_min.py +738 -275
  12. stubber/board/createstubs_lvgl_mpy.mpy +0 -0
  13. stubber/board/createstubs_mem.py +237 -174
  14. stubber/board/createstubs_mem_min.py +263 -247
  15. stubber/board/createstubs_mem_mpy.mpy +0 -0
  16. stubber/board/createstubs_min.py +242 -227
  17. stubber/board/createstubs_mpy.mpy +0 -0
  18. stubber/board/fw_info.py +135 -0
  19. stubber/board/modulelist.txt +1 -2
  20. stubber/codemod/_partials/__init__.py +1 -1
  21. stubber/codemod/_partials/db_main.py +90 -72
  22. stubber/codemod/_partials/modules_reader.py +29 -17
  23. stubber/codemod/board.py +2 -4
  24. stubber/codemod/enrich.py +1 -1
  25. stubber/commands/build_cmd.py +6 -4
  26. stubber/commands/get_docstubs_cmd.py +6 -11
  27. stubber/commands/get_frozen_cmd.py +6 -11
  28. stubber/commands/switch_cmd.py +6 -4
  29. stubber/data/board_info.csv +134 -101
  30. stubber/data/board_info.json +1357 -901
  31. stubber/freeze/freeze_manifest_2.py +2 -1
  32. stubber/freeze/get_frozen.py +28 -13
  33. stubber/minify.py +56 -43
  34. stubber/publish/candidates.py +15 -23
  35. stubber/publish/defaults.py +2 -2
  36. stubber/publish/merge_docstubs.py +5 -7
  37. stubber/publish/missing_class_methods.py +2 -2
  38. stubber/publish/pathnames.py +2 -2
  39. stubber/publish/publish.py +2 -1
  40. stubber/publish/stubpackage.py +20 -40
  41. stubber/rst/lookup.py +9 -7
  42. stubber/rst/reader.py +2 -1
  43. stubber/stubber.py +5 -6
  44. stubber/update_fallback.py +3 -1
  45. stubber/update_module_list.py +1 -1
  46. stubber/utils/__init__.py +1 -1
  47. stubber/utils/config.py +7 -9
  48. stubber/utils/post.py +1 -1
  49. stubber/utils/repos.py +10 -7
  50. stubber/utils/versions.py +48 -7
  51. stubber/variants.py +3 -3
  52. stubber/board/logging.py +0 -99
  53. {micropython_stubber-1.16.2.dist-info → micropython_stubber-1.17.0.dist-info}/LICENSE +0 -0
  54. {micropython_stubber-1.16.2.dist-info → micropython_stubber-1.17.0.dist-info}/WHEEL +0 -0
  55. {micropython_stubber-1.16.2.dist-info → micropython_stubber-1.17.0.dist-info}/entry_points.txt +0 -0
@@ -3,16 +3,19 @@ Create stubs for the lvgl modules on a MicroPython board.
3
3
 
4
4
  Note that the stubs can be very large, and it may be best to directly store them on an SD card if your device supports this.
5
5
 
6
- This variant was generated from createstubs.py by micropython-stubber v1.16.2
6
+ This variant was generated from createstubs.py by micropython-stubber v1.16.3
7
7
  """
8
8
  # Copyright (c) 2019-2023 Jos Verlinde
9
9
 
10
10
  import gc
11
- import logging
12
11
  import os
13
12
  import sys
13
+ from time import sleep
14
14
 
15
- from ujson import dumps
15
+ try:
16
+ from ujson import dumps
17
+ except:
18
+ from json import dumps
16
19
 
17
20
  try:
18
21
  from machine import reset # type: ignore
@@ -24,11 +27,61 @@ try:
24
27
  except ImportError:
25
28
  from ucollections import OrderedDict # type: ignore
26
29
 
27
- __version__ = "v1.16.2"
30
+ __version__ = "v1.16.3"
28
31
  ENOENT = 2
29
32
  _MAX_CLASS_LEVEL = 2 # Max class nesting
30
- LIBS = [".", "/lib", "/sd/lib", "/flash/lib", "lib"]
31
- from time import sleep
33
+ LIBS = ["lib", "/lib", "/sd/lib", "/flash/lib", "."]
34
+
35
+
36
+ # our own logging module to avoid dependency on and interfering with logging module
37
+ class logging:
38
+ DEBUG = 10
39
+ TRACE = 15
40
+ INFO = 20
41
+ WARNING = 30
42
+ ERROR = 40
43
+ CRITICAL = 50
44
+ level = INFO
45
+ prnt = print
46
+
47
+ @staticmethod
48
+ def getLogger(name):
49
+ return logging()
50
+
51
+ @classmethod
52
+ def basicConfig(cls, level):
53
+ cls.level = level
54
+ pass
55
+
56
+ def trace(self, msg):
57
+ if self.level <= logging.TRACE:
58
+ self.prnt("TRACE :", msg)
59
+
60
+ def debug(self, msg):
61
+ if self.level <= logging.DEBUG:
62
+ self.prnt("DEBUG :", msg)
63
+
64
+ def info(self, msg):
65
+ if self.level <= logging.INFO:
66
+ self.prnt("INFO :", msg)
67
+
68
+ def warning(self, msg):
69
+ if self.level <= logging.WARNING:
70
+ self.prnt("WARN :", msg)
71
+
72
+ def error(self, msg):
73
+ if self.level <= logging.ERROR:
74
+ self.prnt("ERROR :", msg)
75
+
76
+ def critical(self, msg):
77
+ if self.level <= logging.CRITICAL:
78
+ self.prnt("CRIT :", msg)
79
+
80
+
81
+ log = logging.getLogger("stubber")
82
+ logging.basicConfig(level=logging.INFO)
83
+ # logging.basicConfig(level=logging.TRACE)
84
+ # logging.basicConfig(level=logging.DEBUG)
32
85
 
33
86
 
34
87
  class Stubber:
@@ -36,24 +89,22 @@ class Stubber:
36
89
 
37
90
  def __init__(self, path: str = None, firmware_id: str = None): # type: ignore
38
91
  try:
39
- if os.uname().release == "1.13.0" and os.uname().version < "v1.13-103":
92
+ if os.uname().release == "1.13.0" and os.uname().version < "v1.13-103": # type: ignore
40
93
  raise NotImplementedError("MicroPython 1.13.0 cannot be stubbed")
41
94
  except AttributeError:
42
95
  pass
43
- self.log = None
44
- self.log = logging.getLogger("stubber")
45
96
  self._report = [] # type: list[str]
46
97
  self.info = _info()
47
- self.log.info("Port: {}".format(self.info["port"]))
48
- self.log.info("Board: {}".format(self.info["board"]))
98
+ log.info("Port: {}".format(self.info["port"]))
99
+ log.info("Board: {}".format(self.info["board"]))
49
100
  gc.collect()
50
101
  if firmware_id:
51
102
  self._fwid = firmware_id.lower()
52
103
  else:
53
104
  if self.info["family"] == "micropython":
54
- self._fwid = "{family}-{ver}-{port}-{board}".format(**self.info)
105
+ self._fwid = "{family}-v{version}-{port}-{board}".format(**self.info).rstrip("-")
55
106
  else:
56
- self._fwid = "{family}-{ver}-{port}".format(**self.info)
107
+ self._fwid = "{family}-v{version}-{port}".format(**self.info)
57
108
  self._start_free = gc.mem_free() # type: ignore
58
109
 
59
110
  if path:
@@ -63,11 +114,11 @@ class Stubber:
63
114
  path = get_root()
64
115
 
65
116
  self.path = "{}/stubs/{}".format(path, self.flat_fwid).replace("//", "/")
66
- self.log.debug(self.path)
117
+ log.debug(self.path)
67
118
  try:
68
119
  ensure_folder(path + "/")
69
120
  except OSError:
70
- self.log.error("error creating stub folder {}".format(path))
121
+ log.error("error creating stub folder {}".format(path))
71
122
  self.problematic = [
72
123
  "upip",
73
124
  "upysh",
@@ -92,14 +143,15 @@ class Stubber:
92
143
  # name_, repr_(value), type as text, item_instance
93
144
  _result = []
94
145
  _errors = []
95
- self.log.debug("get attributes {} {}".format(repr(item_instance), item_instance))
146
+ log.debug("get attributes {} {}".format(repr(item_instance), item_instance))
96
147
  for name in dir(item_instance):
97
148
  if name.startswith("_") and not name in self.modules:
98
149
  continue
99
- self.log.debug("get attribute {}".format(name))
150
+ log.debug("get attribute {}".format(name))
100
151
  try:
101
152
  val = getattr(item_instance, name)
102
153
  # name , item_repr(value) , type as text, item_instance, order
154
+ log.debug("attribute {}:{}".format(name, val))
103
155
  try:
104
156
  type_text = repr(type(val)).split("'")[1]
105
157
  except IndexError:
@@ -132,18 +184,18 @@ class Stubber:
132
184
 
133
185
  def create_all_stubs(self):
134
186
  "Create stubs for all configured modules"
135
- self.log.info("Start micropython-stubber v{} on {}".format(__version__, self._fwid))
187
+ log.info("Start micropython-stubber v{} on {}".format(__version__, self._fwid))
136
188
  gc.collect()
137
189
  for module_name in self.modules:
138
190
  self.create_one_stub(module_name)
139
- self.log.info("Finally done")
191
+ log.info("Finally done")
140
192
 
141
193
  def create_one_stub(self, module_name: str):
142
194
  if module_name in self.problematic:
143
- self.log.warning("Skip module: {:<25} : Known problematic".format(module_name))
195
+ log.warning("Skip module: {:<25} : Known problematic".format(module_name))
144
196
  return False
145
197
  if module_name in self.excluded:
146
- self.log.warning("Skip module: {:<25} : Excluded".format(module_name))
198
+ log.warning("Skip module: {:<25} : Excluded".format(module_name))
147
199
  return False
148
200
 
149
201
  file_name = "{}/{}.py".format(self.path, module_name.replace(".", "/"))
@@ -178,10 +230,10 @@ class Stubber:
178
230
  try:
179
231
  new_module = __import__(module_name, None, None, ("*"))
180
232
  m1 = gc.mem_free() # type: ignore
181
- self.log.info("Stub module: {:<25} to file: {:<70} mem:{:>5}".format(module_name, fname, m1))
233
+ log.info("Stub module: {:<25} to file: {:<70} mem:{:>5}".format(module_name, fname, m1))
182
234
 
183
235
  except ImportError:
184
- self.log.warning("Skip module: {:<25} {:<79}".format(module_name, "Module not found."))
236
+ log.trace("Skip module: {:<25} {:<79}".format(module_name, "Module not found."))
185
237
  return False
186
238
 
187
239
  # Start a new file
@@ -191,7 +243,7 @@ class Stubber:
191
243
  info_ = str(self.info).replace("OrderedDict(", "").replace("})", "}")
192
244
  s = '"""\nModule: \'{0}\' on {1}\n"""\n# MCU: {2}\n# Stubber: {3}\n'.format(module_name, self._fwid, info_, __version__)
193
245
  fp.write(s)
194
- fp.write("from typing import Any\nfrom _typeshed import Incomplete\n\n")
246
+ fp.write("from __future__ import annotations\nfrom typing import Any\nfrom _typeshed import Incomplete\n\n")
195
247
  self.write_object_stub(fp, new_module, module_name, "")
196
248
 
197
249
  self._report.append('{{"module": "{}", "file": "{}"}}'.format(module_name, file_name.replace("\\", "/")))
@@ -201,11 +253,12 @@ class Stubber:
201
253
  try:
202
254
  del new_module
203
255
  except (OSError, KeyError): # lgtm [py/unreachable-statement]
204
- self.log.warning("could not del new_module")
205
- try:
206
- del sys.modules[module_name]
207
- except KeyError:
208
- self.log.debug("could not del sys.modules[{}]".format(module_name))
256
+ log.warning("could not del new_module")
257
+ # lets not try - most times it does not work anyway
258
+ # try:
259
+ # del sys.modules[module_name]
260
+ # except KeyError:
261
+ # log.warning("could not del sys.modules[{}]".format(module_name))
209
262
  gc.collect()
210
263
  return True
211
264
 
@@ -213,14 +266,14 @@ class Stubber:
213
266
  "Write a module/object stub to an open file. Can be called recursive."
214
267
  gc.collect()
215
268
  if object_expr in self.problematic:
216
- self.log.warning("SKIPPING problematic module:{}".format(object_expr))
269
+ log.warning("SKIPPING problematic module:{}".format(object_expr))
217
270
  return
218
271
 
219
- # self.log.debug("DUMP : {}".format(object_expr))
272
+ # log.debug("DUMP : {}".format(object_expr))
220
273
  items, errors = self.get_obj_attributes(object_expr)
221
274
 
222
275
  if errors:
223
- self.log.error(errors)
276
+ log.error(errors)
224
277
 
225
278
  for item_name, item_repr, item_type_txt, item_instance, _ in items:
226
279
  # name_, repr_(value), type as text, item_instance, order
@@ -228,11 +281,16 @@ class Stubber:
228
281
  # do not create stubs for these primitives
229
282
  continue
230
283
  if item_name[0].isdigit():
231
- self.log.warning("NameError: invalid name {}".format(item_name))
284
+ log.warning("NameError: invalid name {}".format(item_name))
232
285
  continue
233
286
  # Class expansion only on first 3 levels (bit of a hack)
234
- if item_type_txt == "<class 'type'>" and len(indent) <= _MAX_CLASS_LEVEL * 4:
235
- self.log.debug("{0}class {1}:".format(indent, item_name))
287
+ if (
288
+ item_type_txt == "<class 'type'>"
289
+ and len(indent) <= _MAX_CLASS_LEVEL * 4
290
+ # and not obj_name.endswith(".Pin")
291
+ # avoid expansion of Pin.cpu / Pin.board to avoid crashes on most platforms
292
+ ):
293
+ log.trace("{0}class {1}:".format(indent, item_name))
236
294
  superclass = ""
237
295
  is_exception = (
238
296
  item_name.endswith("Exception")
@@ -251,11 +309,11 @@ class Stubber:
251
309
  if is_exception:
252
310
  s += indent + " ...\n"
253
311
  fp.write(s)
254
- return
312
+ continue
255
313
  # write classdef
256
314
  fp.write(s)
257
315
  # first write the class literals and methods
258
- self.log.debug("# recursion over class {0}".format(item_name))
316
+ log.debug("# recursion over class {0}".format(item_name))
259
317
  self.write_object_stub(
260
318
  fp,
261
319
  item_instance,
@@ -269,7 +327,7 @@ class Stubber:
269
327
  s += indent + " ...\n\n"
270
328
  fp.write(s)
271
329
  elif any(word in item_type_txt for word in ["method", "function", "closure"]):
272
- self.log.debug("# def {1} function/method/closure, type = '{0}'".format(item_type_txt, item_name))
330
+ log.debug("# def {1} function/method/closure, type = '{0}'".format(item_type_txt, item_name))
273
331
  # module Function or class method
274
332
  # will accept any number of params
275
333
  # return type Any/Incomplete
@@ -285,7 +343,7 @@ class Stubber:
285
343
  s = "{}def {}({}*args, **kwargs) -> {}:\n".format(indent, item_name, first, ret)
286
344
  s += indent + " ...\n\n"
287
345
  fp.write(s)
288
- self.log.debug("\n" + s)
346
+ log.debug("\n" + s)
289
347
  elif item_type_txt == "<class 'module'>":
290
348
  # Skip imported modules
291
349
  # fp.write("# import {}\n".format(item_name))
@@ -304,27 +362,29 @@ class Stubber:
304
362
  s = "{0}{1} = {2} # type: {3}\n".format(indent, item_name, ev[t], t)
305
363
  else:
306
364
  # something else
307
- if t not in ["object", "set", "frozenset"]:
308
- # Possibly default others to item_instance object ?
365
+ if t in ["object", "set", "frozenset", "Pin", "FileIO"]:
309
366
  # https://docs.python.org/3/tutorial/classes.html#item_instance-objects
367
+ # use these types for the attribute
368
+ s = "{0}{1} : {2} ## = {4}\n".format(indent, item_name, t, item_type_txt, item_repr)
369
+ else:
370
+ # Requires Python 3.6 syntax, which is OK for the stubs/pyi
310
371
  t = "Incomplete"
311
- # Requires Python 3.6 syntax, which is OK for the stubs/pyi
312
- s = "{0}{1} : {2} ## {3} = {4}\n".format(indent, item_name, t, item_type_txt, item_repr)
372
+ s = "{0}{1} : {2} ## {3} = {4}\n".format(indent, item_name, t, item_type_txt, item_repr)
313
373
  fp.write(s)
314
- self.log.debug("\n" + s)
374
+ log.debug("\n" + s)
315
375
  else:
316
376
  # keep only the name
317
- self.log.debug("# all other, type = '{0}'".format(item_type_txt))
377
+ log.debug("# all other, type = '{0}'".format(item_type_txt))
318
378
  fp.write("# all other, type = '{0}'\n".format(item_type_txt))
319
379
 
320
380
  fp.write(indent + item_name + " # type: Incomplete\n")
321
381
 
322
- del items
323
- del errors
324
- try:
325
- del item_name, item_repr, item_type_txt, item_instance # type: ignore
326
- except (OSError, KeyError, NameError):
327
- pass
382
+ # del items
383
+ # del errors
384
+ # try:
385
+ # del item_name, item_repr, item_type_txt, item_instance # type: ignore
386
+ # except (OSError, KeyError, NameError):
387
+ # pass
328
388
 
329
389
  @property
330
390
  def flat_fwid(self):
@@ -340,7 +400,7 @@ class Stubber:
340
400
  "Remove all files from the stub folder"
341
401
  if path is None:
342
402
  path = self.path
343
- self.log.info("Clean/remove files in folder: {}".format(path))
403
+ log.info("Clean/remove files in folder: {}".format(path))
344
404
  try:
345
405
  os.stat(path) # TEMP workaround mpremote listdir bug -
346
406
  items = os.listdir(path)
@@ -360,9 +420,9 @@ class Stubber:
360
420
 
361
421
  def report(self, filename: str = "modules.json"):
362
422
  "create json with list of exported modules"
363
- self.log.info("Created stubs for {} modules on board {}\nPath: {}".format(len(self._report), self._fwid, self.path))
423
+ log.info("Created stubs for {} modules on board {}\nPath: {}".format(len(self._report), self._fwid, self.path))
364
424
  f_name = "{}/{}".format(self.path, filename)
365
- self.log.info("Report file: {}".format(f_name))
425
+ log.info("Report file: {}".format(f_name))
366
426
  gc.collect()
367
427
  try:
368
428
  # write json by node to reduce memory requirements
@@ -374,9 +434,9 @@ class Stubber:
374
434
  first = False
375
435
  self.write_json_end(f)
376
436
  used = self._start_free - gc.mem_free() # type: ignore
377
- self.log.info("Memory used: {0} Kb".format(used // 1024))
437
+ log.trace("Memory used: {0} Kb".format(used // 1024))
378
438
  except OSError:
379
- self.log.error("Failed to create the report.")
439
+ log.error("Failed to create the report.")
380
440
 
381
441
  def write_json_header(self, f):
382
442
  f.write("{")
@@ -418,12 +478,21 @@ def ensure_folder(path: str):
418
478
 
419
479
 
420
480
  def _build(s):
421
- # extract a build nr from a string
481
+ # extract build from sys.version or os.uname().version if available
482
+ # sys.version: 'MicroPython v1.23.0-preview.6.g3d0b6276f'
483
+ # sys.implementation.version: 'v1.13-103-gb137d064e'
422
484
  if not s:
423
485
  return ""
424
- if " on " in s:
425
- s = s.split(" on ", 1)[0]
426
- return s.split("-")[1] if "-" in s else ""
486
+ s = s.split(" on ", 1)[0] if " on " in s else s
487
+ if s.startswith("v"):
488
+ if not "-" in s:
489
+ return ""
490
+ b = s.split("-")[1]
491
+ return b
492
+ if not "-preview" in s:
493
+ return ""
494
+ b = s.split("-preview")[1].split(".")[1]
495
+ return b
427
496
 
428
497
 
429
498
  def _info(): # type:() -> dict[str, str]
@@ -434,7 +503,7 @@ def _info(): # type:() -> dict[str, str]
434
503
  "build": "",
435
504
  "ver": "",
436
505
  "port": sys.platform, # port: esp32 / win32 / linux / stm32
437
- "board": "GENERIC",
506
+ "board": "UNKNOWN",
438
507
  "cpu": "",
439
508
  "mpy": "",
440
509
  "arch": "",
@@ -448,13 +517,14 @@ def _info(): # type:() -> dict[str, str]
448
517
  elif info["port"] == "linux":
449
518
  info["port"] = "unix"
450
519
  try:
451
- info["version"] = ".".join([str(n) for n in sys.implementation.version])
520
+ info["version"] = version_str(sys.implementation.version) # type: ignore
452
521
  except AttributeError:
453
522
  pass
454
523
  try:
455
- machine = sys.implementation._machine if "_machine" in dir(sys.implementation) else os.uname().machine
456
- info["board"] = machine.strip()
457
- info["cpu"] = machine.split("with")[1].strip()
524
+ _machine = sys.implementation._machine if "_machine" in dir(sys.implementation) else os.uname().machine # type: ignore
525
+ # info["board"] = "with".join(_machine.split("with")[:-1]).strip()
526
+ info["board"] = _machine
527
+ info["cpu"] = _machine.split("with")[-1].strip()
458
528
  info["mpy"] = (
459
529
  sys.implementation._mpy
460
530
  if "_mpy" in dir(sys.implementation)
@@ -464,40 +534,27 @@ def _info(): # type:() -> dict[str, str]
464
534
  )
465
535
  except (AttributeError, IndexError):
466
536
  pass
467
- gc.collect()
468
- for filename in [d + "/board_info.csv" for d in LIBS]:
469
- # print("look up the board name in the file", filename)
470
- if file_exists(filename):
471
- # print("Found board info file: {}".format(filename))
472
- b = info["board"].strip()
473
- if find_board(info, b, filename):
474
- break
475
- if "with" in b:
476
- b = b.split("with")[0].strip()
477
- if find_board(info, b, filename):
478
- break
479
- info["board"] = "GENERIC"
480
- info["board"] = info["board"].replace(" ", "_")
481
- gc.collect()
537
+ info["board"] = get_boardname()
482
538
 
483
539
  try:
484
- # extract build from uname().version if available
485
- info["build"] = _build(os.uname()[3])
486
- if not info["build"]:
487
- # extract build from uname().release if available
488
- info["build"] = _build(os.uname()[2])
489
- if not info["build"] and ";" in sys.version:
490
- # extract build from uname().release if available
491
- info["build"] = _build(sys.version.split(";")[1])
492
- except (AttributeError, IndexError):
540
+ if "uname" in dir(os): # old
541
+ # extract build from uname().version if available
542
+ info["build"] = _build(os.uname()[3]) # type: ignore
543
+ if not info["build"]:
544
+ # extract build from uname().release if available
545
+ info["build"] = _build(os.uname()[2]) # type: ignore
546
+ elif "version" in dir(sys): # new
547
+ # extract build from sys.version if available
548
+ info["build"] = _build(sys.version)
549
+ except (AttributeError, IndexError, TypeError):
493
550
  pass
494
551
  # avoid build hashes
495
- if info["build"] and len(info["build"]) > 5:
496
- info["build"] = ""
552
+ # if info["build"] and len(info["build"]) > 5:
553
+ # info["build"] = ""
497
554
 
498
555
  if info["version"] == "" and sys.platform not in ("unix", "win32"):
499
556
  try:
500
- u = os.uname()
557
+ u = os.uname() # type: ignore
501
558
  info["version"] = u.release
502
559
  except (IndexError, AttributeError, TypeError):
503
560
  pass
@@ -519,13 +576,14 @@ def _info(): # type:() -> dict[str, str]
519
576
  info["release"] = "2.0.0"
520
577
 
521
578
  if info["family"] == "micropython":
579
+ info["version"]
522
580
  if (
523
581
  info["version"]
524
582
  and info["version"].endswith(".0")
525
583
  and info["version"] >= "1.10.0" # versions from 1.10.0 to 1.20.0 do not have a micro .0
526
584
  and info["version"] <= "1.19.9"
527
585
  ):
528
- # drop the .0 for newer releases
586
+ # versions from 1.10.0 to 1.20.0 do not have a micro .0
529
587
  info["version"] = info["version"][:-2]
530
588
 
531
589
  # spell-checker: disable
@@ -549,25 +607,31 @@ def _info(): # type:() -> dict[str, str]
549
607
  info["arch"] = arch
550
608
  # .mpy version.minor
551
609
  info["mpy"] = "v{}.{}".format(sys_mpy & 0xFF, sys_mpy >> 8 & 3)
610
+ if info["build"] and not info["version"].endswith("-preview"):
611
+ info["version"] = info["version"] + "-preview"
552
612
  # simple to use version[-build] string
553
- info["ver"] = f"v{info['version']}-{info['build']}" if info["build"] else f"v{info['version']}"
613
+ info["ver"] = f"{info['version']}-{info['build']}" if info["build"] else f"{info['version']}"
554
614
 
555
615
  return info
556
616
 
557
617
 
558
- def find_board(info: dict, board_descr: str, filename: str):
559
- "Find the board in the provided board_info.csv file"
560
- with open(filename, "r") as file:
561
- # ugly code to make testable in python and micropython
562
- while 1:
563
- line = file.readline()
564
- if not line:
565
- break
566
- descr_, board_ = line.split(",")[0].strip(), line.split(",")[1].strip()
567
- if descr_ == board_descr:
568
- info["board"] = board_
569
- return True
570
- return False
618
+ def version_str(version: tuple): # -> str:
619
+ v_str = ".".join([str(n) for n in version[:3]])
620
+ if len(version) > 3 and version[3]:
621
+ v_str += "-" + version[3]
622
+ return v_str
623
+
624
+
625
+ def get_boardname() -> str:
626
+ "Read the board name from the boardname.py file that may have been created upfront"
627
+ try:
628
+ from boardname import BOARDNAME # type: ignore
629
+
630
+ log.info("Found BOARDNAME: {}".format(BOARDNAME))
631
+ except ImportError:
632
+ log.warning("BOARDNAME not found")
633
+ BOARDNAME = ""
634
+ return BOARDNAME
571
635
 
572
636
 
573
637
  def get_root() -> str: # sourcery skip: use-assigned-variable
@@ -668,12 +732,6 @@ def main():
668
732
 
669
733
 
670
734
  if __name__ == "__main__" or is_micropython():
671
- try:
672
- log = logging.getLogger("stubber")
673
- logging.basicConfig(level=logging.INFO)
674
- # logging.basicConfig(level=logging.DEBUG)
675
- except NameError:
676
- pass
677
735
  if not file_exists("no_auto_stubber.txt"):
678
736
  try:
679
737
  gc.threshold(4 * 1024) # type: ignore