micropython-stubber 1.20.5__py3-none-any.whl → 1.20.6__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.20.5.dist-info → micropython_stubber-1.20.6.dist-info}/LICENSE +30 -30
- {micropython_stubber-1.20.5.dist-info → micropython_stubber-1.20.6.dist-info}/METADATA +1 -1
- micropython_stubber-1.20.6.dist-info/RECORD +159 -0
- mpflash/README.md +184 -184
- mpflash/libusb_flash.ipynb +203 -203
- mpflash/mpflash/add_firmware.py +98 -98
- mpflash/mpflash/ask_input.py +236 -236
- mpflash/mpflash/bootloader/__init__.py +37 -36
- mpflash/mpflash/bootloader/manual.py +102 -102
- mpflash/mpflash/bootloader/micropython.py +10 -10
- mpflash/mpflash/bootloader/touch1200.py +45 -45
- mpflash/mpflash/cli_download.py +129 -129
- mpflash/mpflash/cli_flash.py +219 -219
- mpflash/mpflash/cli_group.py +98 -98
- mpflash/mpflash/cli_list.py +81 -81
- mpflash/mpflash/cli_main.py +41 -41
- mpflash/mpflash/common.py +164 -164
- mpflash/mpflash/config.py +47 -47
- mpflash/mpflash/connected.py +74 -74
- mpflash/mpflash/download.py +360 -360
- mpflash/mpflash/downloaded.py +129 -129
- mpflash/mpflash/errors.py +9 -9
- mpflash/mpflash/flash.py +52 -52
- mpflash/mpflash/flash_esp.py +59 -59
- mpflash/mpflash/flash_stm32.py +24 -24
- mpflash/mpflash/flash_stm32_cube.py +111 -111
- mpflash/mpflash/flash_stm32_dfu.py +101 -101
- mpflash/mpflash/flash_uf2.py +67 -67
- mpflash/mpflash/flash_uf2_boardid.py +15 -15
- mpflash/mpflash/flash_uf2_linux.py +123 -123
- mpflash/mpflash/flash_uf2_macos.py +34 -34
- mpflash/mpflash/flash_uf2_windows.py +34 -34
- mpflash/mpflash/list.py +89 -89
- mpflash/mpflash/logger.py +41 -41
- mpflash/mpflash/mpboard_id/__init__.py +93 -93
- mpflash/mpflash/mpboard_id/add_boards.py +255 -255
- mpflash/mpflash/mpboard_id/board.py +37 -37
- mpflash/mpflash/mpboard_id/board_id.py +86 -86
- mpflash/mpflash/mpboard_id/store.py +43 -43
- mpflash/mpflash/mpremoteboard/__init__.py +221 -221
- mpflash/mpflash/mpremoteboard/mpy_fw_info.py +141 -141
- mpflash/mpflash/mpremoteboard/runner.py +140 -140
- mpflash/mpflash/uf2disk.py +12 -12
- mpflash/mpflash/vendor/basicgit.py +288 -288
- mpflash/mpflash/vendor/click_aliases.py +91 -91
- mpflash/mpflash/vendor/dfu.py +165 -165
- mpflash/mpflash/vendor/pydfu.py +605 -605
- mpflash/mpflash/vendor/readme.md +2 -2
- mpflash/mpflash/vendor/versions.py +119 -117
- mpflash/mpflash/worklist.py +170 -170
- mpflash/poetry.lock +1588 -1588
- mpflash/pyproject.toml +60 -60
- mpflash/stm32_udev_rules.md +62 -62
- stubber/__init__.py +3 -3
- stubber/basicgit.py +294 -288
- stubber/board/board_info.csv +193 -193
- stubber/board/boot.py +34 -34
- stubber/board/createstubs.py +986 -986
- stubber/board/createstubs_db.py +825 -825
- stubber/board/createstubs_db_min.py +331 -331
- stubber/board/createstubs_db_mpy.mpy +0 -0
- stubber/board/createstubs_lvgl.py +741 -741
- stubber/board/createstubs_lvgl_min.py +741 -741
- stubber/board/createstubs_mem.py +766 -766
- stubber/board/createstubs_mem_min.py +306 -306
- stubber/board/createstubs_mem_mpy.mpy +0 -0
- stubber/board/createstubs_min.py +294 -294
- stubber/board/createstubs_mpy.mpy +0 -0
- stubber/board/fw_info.py +141 -141
- stubber/board/info.py +183 -183
- stubber/board/main.py +19 -19
- stubber/board/modulelist.txt +247 -247
- stubber/board/pyrightconfig.json +34 -34
- stubber/bulk/mcu_stubber.py +454 -454
- stubber/codemod/_partials/__init__.py +48 -48
- stubber/codemod/_partials/db_main.py +147 -147
- stubber/codemod/_partials/lvgl_main.py +77 -77
- stubber/codemod/_partials/modules_reader.py +80 -80
- stubber/codemod/add_comment.py +53 -53
- stubber/codemod/add_method.py +65 -65
- stubber/codemod/board.py +317 -317
- stubber/codemod/enrich.py +145 -145
- stubber/codemod/merge_docstub.py +284 -284
- stubber/codemod/modify_list.py +54 -54
- stubber/codemod/utils.py +57 -57
- stubber/commands/build_cmd.py +94 -94
- stubber/commands/cli.py +51 -51
- stubber/commands/clone_cmd.py +66 -66
- stubber/commands/config_cmd.py +29 -29
- stubber/commands/enrich_folder_cmd.py +70 -70
- stubber/commands/get_core_cmd.py +69 -69
- stubber/commands/get_docstubs_cmd.py +87 -87
- stubber/commands/get_frozen_cmd.py +112 -112
- stubber/commands/get_mcu_cmd.py +56 -56
- stubber/commands/merge_cmd.py +66 -66
- stubber/commands/publish_cmd.py +119 -119
- stubber/commands/stub_cmd.py +30 -30
- stubber/commands/switch_cmd.py +54 -54
- stubber/commands/variants_cmd.py +48 -48
- stubber/cst_transformer.py +178 -178
- stubber/data/board_info.csv +193 -193
- stubber/data/board_info.json +1729 -1729
- stubber/data/micropython_tags.csv +15 -15
- stubber/data/requirements-core-micropython.txt +38 -38
- stubber/data/requirements-core-pycopy.txt +39 -39
- stubber/downloader.py +36 -36
- stubber/freeze/common.py +68 -68
- stubber/freeze/freeze_folder.py +69 -69
- stubber/freeze/freeze_manifest_2.py +113 -113
- stubber/freeze/get_frozen.py +127 -127
- stubber/get_cpython.py +101 -101
- stubber/get_lobo.py +59 -59
- stubber/minify.py +418 -418
- stubber/publish/bump.py +86 -86
- stubber/publish/candidates.py +262 -262
- stubber/publish/database.py +18 -18
- stubber/publish/defaults.py +45 -45
- stubber/publish/enums.py +24 -24
- stubber/publish/helpers.py +29 -29
- stubber/publish/merge_docstubs.py +130 -130
- stubber/publish/missing_class_methods.py +49 -49
- stubber/publish/package.py +146 -146
- stubber/publish/pathnames.py +51 -51
- stubber/publish/publish.py +120 -120
- stubber/publish/pypi.py +38 -38
- stubber/publish/stubpackage.py +1029 -1029
- stubber/rst/__init__.py +9 -9
- stubber/rst/classsort.py +77 -77
- stubber/rst/lookup.py +530 -530
- stubber/rst/output_dict.py +401 -401
- stubber/rst/reader.py +822 -822
- stubber/rst/report_return.py +69 -69
- stubber/rst/rst_utils.py +540 -540
- stubber/stubber.py +38 -38
- stubber/stubs_from_docs.py +90 -90
- stubber/tools/manifestfile.py +610 -610
- stubber/tools/readme.md +5 -5
- stubber/update_fallback.py +117 -117
- stubber/update_module_list.py +123 -123
- stubber/utils/__init__.py +5 -5
- stubber/utils/config.py +127 -127
- stubber/utils/makeversionhdr.py +54 -54
- stubber/utils/manifest.py +92 -92
- stubber/utils/post.py +79 -79
- stubber/utils/repos.py +157 -154
- stubber/utils/stubmaker.py +139 -139
- stubber/utils/typed_config_toml.py +77 -77
- stubber/utils/versions.py +128 -120
- stubber/variants.py +106 -106
- micropython_stubber-1.20.5.dist-info/RECORD +0 -159
- {micropython_stubber-1.20.5.dist-info → micropython_stubber-1.20.6.dist-info}/WHEEL +0 -0
- {micropython_stubber-1.20.5.dist-info → micropython_stubber-1.20.6.dist-info}/entry_points.txt +0 -0
@@ -1,80 +1,80 @@
|
|
1
|
-
"""partial used to read the modulelist.txt file"""
|
2
|
-
from typing import TYPE_CHECKING, List, type_check_only
|
3
|
-
|
4
|
-
if TYPE_CHECKING:
|
5
|
-
import gc
|
6
|
-
import logging
|
7
|
-
|
8
|
-
@type_check_only
|
9
|
-
class Stubber:
|
10
|
-
path: str
|
11
|
-
_report: List[str]
|
12
|
-
modules = []
|
13
|
-
|
14
|
-
def __init__(self, path: str = "", firmware_id: str = "") -> None:
|
15
|
-
...
|
16
|
-
|
17
|
-
def clean(self) -> None:
|
18
|
-
...
|
19
|
-
|
20
|
-
def create_one_stub(self, modulename: str) -> bool:
|
21
|
-
...
|
22
|
-
|
23
|
-
def report(self, filename: str = "modules.json"):
|
24
|
-
...
|
25
|
-
|
26
|
-
def create_all_stubs(self):
|
27
|
-
...
|
28
|
-
|
29
|
-
@type_check_only
|
30
|
-
def read_path() -> str:
|
31
|
-
...
|
32
|
-
|
33
|
-
def file_exists(f: str) -> bool:
|
34
|
-
...
|
35
|
-
|
36
|
-
@type_check_only
|
37
|
-
class _gc:
|
38
|
-
def collect(self) -> None:
|
39
|
-
...
|
40
|
-
|
41
|
-
_log = logging.getLogger("stubber")
|
42
|
-
|
43
|
-
# help type checker
|
44
|
-
stubber: Stubber = None # type: ignore
|
45
|
-
LIBS: List[str] = [".", "lib"]
|
46
|
-
|
47
|
-
|
48
|
-
# sourcery skip: use-named-expression
|
49
|
-
###PARTIAL###
|
50
|
-
# Read stubs from modulelist in the current folder or in /libs
|
51
|
-
# fall back to default modules
|
52
|
-
def get_modulelist(stubber):
|
53
|
-
# new
|
54
|
-
gc.collect()
|
55
|
-
stubber.modules = [] # avoid duplicates
|
56
|
-
for p in LIBS:
|
57
|
-
fname = p + "/modulelist.txt"
|
58
|
-
if not file_exists(fname):
|
59
|
-
continue
|
60
|
-
with open(fname) as f:
|
61
|
-
# print("DEBUG: list of modules: " + p + "/modulelist.txt")
|
62
|
-
while True:
|
63
|
-
line = f.readline().strip()
|
64
|
-
if not line:
|
65
|
-
break
|
66
|
-
if len(line) > 0 and line[0] != "#":
|
67
|
-
stubber.modules.append(line)
|
68
|
-
gc.collect()
|
69
|
-
print("BREAK")
|
70
|
-
break
|
71
|
-
|
72
|
-
if not stubber.modules:
|
73
|
-
stubber.modules = ["micropython"]
|
74
|
-
# _log.warn("Could not find modulelist.txt, using default modules")
|
75
|
-
gc.collect()
|
76
|
-
|
77
|
-
|
78
|
-
stubber.modules = [] # avoid duplicates
|
79
|
-
get_modulelist(stubber)
|
80
|
-
###PARTIALEND###
|
1
|
+
"""partial used to read the modulelist.txt file"""
|
2
|
+
from typing import TYPE_CHECKING, List, type_check_only
|
3
|
+
|
4
|
+
if TYPE_CHECKING:
|
5
|
+
import gc
|
6
|
+
import logging
|
7
|
+
|
8
|
+
@type_check_only
|
9
|
+
class Stubber:
|
10
|
+
path: str
|
11
|
+
_report: List[str]
|
12
|
+
modules = []
|
13
|
+
|
14
|
+
def __init__(self, path: str = "", firmware_id: str = "") -> None:
|
15
|
+
...
|
16
|
+
|
17
|
+
def clean(self) -> None:
|
18
|
+
...
|
19
|
+
|
20
|
+
def create_one_stub(self, modulename: str) -> bool:
|
21
|
+
...
|
22
|
+
|
23
|
+
def report(self, filename: str = "modules.json"):
|
24
|
+
...
|
25
|
+
|
26
|
+
def create_all_stubs(self):
|
27
|
+
...
|
28
|
+
|
29
|
+
@type_check_only
|
30
|
+
def read_path() -> str:
|
31
|
+
...
|
32
|
+
|
33
|
+
def file_exists(f: str) -> bool:
|
34
|
+
...
|
35
|
+
|
36
|
+
@type_check_only
|
37
|
+
class _gc:
|
38
|
+
def collect(self) -> None:
|
39
|
+
...
|
40
|
+
|
41
|
+
_log = logging.getLogger("stubber")
|
42
|
+
|
43
|
+
# help type checker
|
44
|
+
stubber: Stubber = None # type: ignore
|
45
|
+
LIBS: List[str] = [".", "lib"]
|
46
|
+
|
47
|
+
|
48
|
+
# sourcery skip: use-named-expression
|
49
|
+
###PARTIAL###
|
50
|
+
# Read stubs from modulelist in the current folder or in /libs
|
51
|
+
# fall back to default modules
|
52
|
+
def get_modulelist(stubber):
|
53
|
+
# new
|
54
|
+
gc.collect()
|
55
|
+
stubber.modules = [] # avoid duplicates
|
56
|
+
for p in LIBS:
|
57
|
+
fname = p + "/modulelist.txt"
|
58
|
+
if not file_exists(fname):
|
59
|
+
continue
|
60
|
+
with open(fname) as f:
|
61
|
+
# print("DEBUG: list of modules: " + p + "/modulelist.txt")
|
62
|
+
while True:
|
63
|
+
line = f.readline().strip()
|
64
|
+
if not line:
|
65
|
+
break
|
66
|
+
if len(line) > 0 and line[0] != "#":
|
67
|
+
stubber.modules.append(line)
|
68
|
+
gc.collect()
|
69
|
+
print("BREAK")
|
70
|
+
break
|
71
|
+
|
72
|
+
if not stubber.modules:
|
73
|
+
stubber.modules = ["micropython"]
|
74
|
+
# _log.warn("Could not find modulelist.txt, using default modules")
|
75
|
+
gc.collect()
|
76
|
+
|
77
|
+
|
78
|
+
stubber.modules = [] # avoid duplicates
|
79
|
+
get_modulelist(stubber)
|
80
|
+
###PARTIALEND###
|
stubber/codemod/add_comment.py
CHANGED
@@ -1,53 +1,53 @@
|
|
1
|
-
"""Add comment(s) to each file"""
|
2
|
-
# sourcery skip: snake-case-functions
|
3
|
-
|
4
|
-
import argparse
|
5
|
-
from typing import List
|
6
|
-
from libcst import Module, Comment
|
7
|
-
from libcst.codemod import CodemodContext, VisitorBasedCodemodCommand
|
8
|
-
from libcst.helpers.module import insert_header_comments
|
9
|
-
|
10
|
-
import re
|
11
|
-
from typing import Pattern
|
12
|
-
|
13
|
-
|
14
|
-
class AddComment(VisitorBasedCodemodCommand):
|
15
|
-
DESCRIPTION: str = "Add comment(s) to each file"
|
16
|
-
|
17
|
-
@staticmethod
|
18
|
-
def add_args(arg_parser: argparse.ArgumentParser) -> None:
|
19
|
-
"""Add command-line args that a user can specify for running this codemod."""
|
20
|
-
arg_parser.add_argument(
|
21
|
-
"-c",
|
22
|
-
"--comment",
|
23
|
-
dest="comments",
|
24
|
-
action="extend",
|
25
|
-
nargs="+",
|
26
|
-
metavar="COMMENT",
|
27
|
-
help="Comment statement(s) to add to each file",
|
28
|
-
type=str,
|
29
|
-
required=True,
|
30
|
-
)
|
31
|
-
|
32
|
-
def __init__(self, context: CodemodContext, comments: List[str]) -> None:
|
33
|
-
"""
|
34
|
-
Initialize the base class with context, and save our args. Remember, the
|
35
|
-
"dest" for each argument we added above must match a parameter name in
|
36
|
-
this init.
|
37
|
-
"""
|
38
|
-
super().__init__(context)
|
39
|
-
self.comments = [c if c[0] == "#" else f"# {c}" for c in comments]
|
40
|
-
# regex only checks for the first line of the comment
|
41
|
-
self._regex_pattern: Pattern[str] = re.compile(rf"^{self.comments[0]}\s*$")
|
42
|
-
self.needs_add = True
|
43
|
-
|
44
|
-
def visit_Comment(self, node: Comment) -> None:
|
45
|
-
"""
|
46
|
-
connect comments from the source
|
47
|
-
"""
|
48
|
-
if self._regex_pattern.search(node.value):
|
49
|
-
self.needs_add = False
|
50
|
-
|
51
|
-
def leave_Module(self, original_node: Module, updated_node: Module) -> Module:
|
52
|
-
"""If the tag already exists, don't modify the file."""
|
53
|
-
return insert_header_comments(updated_node, self.comments) if self.needs_add else updated_node
|
1
|
+
"""Add comment(s) to each file"""
|
2
|
+
# sourcery skip: snake-case-functions
|
3
|
+
|
4
|
+
import argparse
|
5
|
+
from typing import List
|
6
|
+
from libcst import Module, Comment
|
7
|
+
from libcst.codemod import CodemodContext, VisitorBasedCodemodCommand
|
8
|
+
from libcst.helpers.module import insert_header_comments
|
9
|
+
|
10
|
+
import re
|
11
|
+
from typing import Pattern
|
12
|
+
|
13
|
+
|
14
|
+
class AddComment(VisitorBasedCodemodCommand):
|
15
|
+
DESCRIPTION: str = "Add comment(s) to each file"
|
16
|
+
|
17
|
+
@staticmethod
|
18
|
+
def add_args(arg_parser: argparse.ArgumentParser) -> None:
|
19
|
+
"""Add command-line args that a user can specify for running this codemod."""
|
20
|
+
arg_parser.add_argument(
|
21
|
+
"-c",
|
22
|
+
"--comment",
|
23
|
+
dest="comments",
|
24
|
+
action="extend",
|
25
|
+
nargs="+",
|
26
|
+
metavar="COMMENT",
|
27
|
+
help="Comment statement(s) to add to each file",
|
28
|
+
type=str,
|
29
|
+
required=True,
|
30
|
+
)
|
31
|
+
|
32
|
+
def __init__(self, context: CodemodContext, comments: List[str]) -> None:
|
33
|
+
"""
|
34
|
+
Initialize the base class with context, and save our args. Remember, the
|
35
|
+
"dest" for each argument we added above must match a parameter name in
|
36
|
+
this init.
|
37
|
+
"""
|
38
|
+
super().__init__(context)
|
39
|
+
self.comments = [c if c[0] == "#" else f"# {c}" for c in comments]
|
40
|
+
# regex only checks for the first line of the comment
|
41
|
+
self._regex_pattern: Pattern[str] = re.compile(rf"^{self.comments[0]}\s*$")
|
42
|
+
self.needs_add = True
|
43
|
+
|
44
|
+
def visit_Comment(self, node: Comment) -> None:
|
45
|
+
"""
|
46
|
+
connect comments from the source
|
47
|
+
"""
|
48
|
+
if self._regex_pattern.search(node.value):
|
49
|
+
self.needs_add = False
|
50
|
+
|
51
|
+
def leave_Module(self, original_node: Module, updated_node: Module) -> Module:
|
52
|
+
"""If the tag already exists, don't modify the file."""
|
53
|
+
return insert_header_comments(updated_node, self.comments) if self.needs_add else updated_node
|
stubber/codemod/add_method.py
CHANGED
@@ -1,65 +1,65 @@
|
|
1
|
-
"""Codemod to add methods to a classes.
|
2
|
-
|
3
|
-
Used to add methods that are documented, but are not reported by the firmware,
|
4
|
-
so they are also not present in the MCU stubs.
|
5
|
-
"""
|
6
|
-
|
7
|
-
|
8
|
-
from typing import Optional
|
9
|
-
import libcst as cst
|
10
|
-
from libcst import matchers as m
|
11
|
-
|
12
|
-
|
13
|
-
# there is no simple way to re-use the code from multiple classes / methods
|
14
|
-
# but could be added https://stackoverflow.com/questions/17522706/how-to-pass-an-instance-variable-to-a-decorator-inside-class-definition?noredirect=1&lq=1
|
15
|
-
# so for now, just copy the code, or use a module scoped variable - but that is not thread safe
|
16
|
-
|
17
|
-
|
18
|
-
class CallFinder(m.MatcherDecoratableTransformer):
|
19
|
-
"""Find the Pin.__call__ method and extract it from a (machine) module."""
|
20
|
-
|
21
|
-
class_name: str = "Pin" # class name
|
22
|
-
method_name: str = "__call__" # method name
|
23
|
-
|
24
|
-
def __init__(self):
|
25
|
-
super().__init__()
|
26
|
-
self.call_meth: Optional[cst.FunctionDef] = None
|
27
|
-
|
28
|
-
@m.call_if_inside(m.ClassDef(name=m.Name(class_name)))
|
29
|
-
@m.visit(m.FunctionDef(name=m.Name(method_name)))
|
30
|
-
def detect_call(self, node: cst.FunctionDef) -> None:
|
31
|
-
"""find the __call__ method and store it."""
|
32
|
-
self.call_meth = node
|
33
|
-
|
34
|
-
|
35
|
-
class CallAdder(m.MatcherDecoratableTransformer):
|
36
|
-
"""Add a __call__ method to a class if it is missing."""
|
37
|
-
|
38
|
-
class_name = "Pin" # class name
|
39
|
-
has_call = 0 # number of __call__ methods found
|
40
|
-
|
41
|
-
def __init__(self, call_meth: cst.FunctionDef) -> None:
|
42
|
-
super().__init__()
|
43
|
-
self.call_meth = call_meth
|
44
|
-
|
45
|
-
@m.call_if_inside(m.ClassDef(name=m.Name(class_name)))
|
46
|
-
@m.visit(m.FunctionDef(name=m.Name("__call__")))
|
47
|
-
def detect_call(self, node: cst.FunctionDef) -> None:
|
48
|
-
"""Detect if the class already has a __call__ method."""
|
49
|
-
self.has_call += 1
|
50
|
-
|
51
|
-
@m.leave(m.ClassDef(name=m.Name(class_name)))
|
52
|
-
def add_call(self, original_node: cst.ClassDef, updated_node: cst.ClassDef) -> cst.ClassDef:
|
53
|
-
"""Add the __call__ method to the class if it is not already there."""
|
54
|
-
if self.has_call:
|
55
|
-
# no change needed
|
56
|
-
return updated_node
|
57
|
-
assert isinstance(updated_node.body, cst.IndentedBlock), "Class body is not indented"
|
58
|
-
# Add it to the end of the body & keep other body items
|
59
|
-
new_body = cst.IndentedBlock(
|
60
|
-
body=list(updated_node.body.body) + [self.call_meth],
|
61
|
-
header=updated_node.body.header,
|
62
|
-
footer=updated_node.body.footer,
|
63
|
-
indent=updated_node.body.indent,
|
64
|
-
)
|
65
|
-
return updated_node.with_changes(body=new_body)
|
1
|
+
"""Codemod to add methods to a classes.
|
2
|
+
|
3
|
+
Used to add methods that are documented, but are not reported by the firmware,
|
4
|
+
so they are also not present in the MCU stubs.
|
5
|
+
"""
|
6
|
+
|
7
|
+
|
8
|
+
from typing import Optional
|
9
|
+
import libcst as cst
|
10
|
+
from libcst import matchers as m
|
11
|
+
|
12
|
+
|
13
|
+
# there is no simple way to re-use the code from multiple classes / methods
|
14
|
+
# but could be added https://stackoverflow.com/questions/17522706/how-to-pass-an-instance-variable-to-a-decorator-inside-class-definition?noredirect=1&lq=1
|
15
|
+
# so for now, just copy the code, or use a module scoped variable - but that is not thread safe
|
16
|
+
|
17
|
+
|
18
|
+
class CallFinder(m.MatcherDecoratableTransformer):
|
19
|
+
"""Find the Pin.__call__ method and extract it from a (machine) module."""
|
20
|
+
|
21
|
+
class_name: str = "Pin" # class name
|
22
|
+
method_name: str = "__call__" # method name
|
23
|
+
|
24
|
+
def __init__(self):
|
25
|
+
super().__init__()
|
26
|
+
self.call_meth: Optional[cst.FunctionDef] = None
|
27
|
+
|
28
|
+
@m.call_if_inside(m.ClassDef(name=m.Name(class_name)))
|
29
|
+
@m.visit(m.FunctionDef(name=m.Name(method_name)))
|
30
|
+
def detect_call(self, node: cst.FunctionDef) -> None:
|
31
|
+
"""find the __call__ method and store it."""
|
32
|
+
self.call_meth = node
|
33
|
+
|
34
|
+
|
35
|
+
class CallAdder(m.MatcherDecoratableTransformer):
|
36
|
+
"""Add a __call__ method to a class if it is missing."""
|
37
|
+
|
38
|
+
class_name = "Pin" # class name
|
39
|
+
has_call = 0 # number of __call__ methods found
|
40
|
+
|
41
|
+
def __init__(self, call_meth: cst.FunctionDef) -> None:
|
42
|
+
super().__init__()
|
43
|
+
self.call_meth = call_meth
|
44
|
+
|
45
|
+
@m.call_if_inside(m.ClassDef(name=m.Name(class_name)))
|
46
|
+
@m.visit(m.FunctionDef(name=m.Name("__call__")))
|
47
|
+
def detect_call(self, node: cst.FunctionDef) -> None:
|
48
|
+
"""Detect if the class already has a __call__ method."""
|
49
|
+
self.has_call += 1
|
50
|
+
|
51
|
+
@m.leave(m.ClassDef(name=m.Name(class_name)))
|
52
|
+
def add_call(self, original_node: cst.ClassDef, updated_node: cst.ClassDef) -> cst.ClassDef:
|
53
|
+
"""Add the __call__ method to the class if it is not already there."""
|
54
|
+
if self.has_call:
|
55
|
+
# no change needed
|
56
|
+
return updated_node
|
57
|
+
assert isinstance(updated_node.body, cst.IndentedBlock), "Class body is not indented"
|
58
|
+
# Add it to the end of the body & keep other body items
|
59
|
+
new_body = cst.IndentedBlock(
|
60
|
+
body=list(updated_node.body.body) + [self.call_meth],
|
61
|
+
header=updated_node.body.header,
|
62
|
+
footer=updated_node.body.footer,
|
63
|
+
indent=updated_node.body.indent,
|
64
|
+
)
|
65
|
+
return updated_node.with_changes(body=new_body)
|