Skip to content

Commit 42e6c22

Browse files
committed
Refactor: Minor refactor and fixups for typos.
- main.py: Minor fixup for usage string. - firmware_fileio.py: Minor clarification of debugging statement. - logger.py: One line typo in comment. - argparse_typed.py: Minor refactor to improve clarity and maintainability.
1 parent 5ffeb30 commit 42e6c22

File tree

4 files changed

+40
-34
lines changed

4 files changed

+40
-34
lines changed

src/mp_image_tool_esp32/argparse_typed.py

Lines changed: 34 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -46,19 +46,21 @@ def __init__(self, parser: ArgumentParser, typed_namespace: Namespace | None):
4646
# `typed_namespace` may also contain a type conversion function for some types
4747
self.type_conversions = getattr(typed_namespace, "_type_conversions", {})
4848

49-
def _get_argument_type(self, name: str) -> Any:
50-
# Get the field name by replacing "-" with "_" in the last word of options
51-
name = name.lstrip("-").replace("-", "_")
52-
argtype = self.argument_types.get(name) # Get the argument type hint
53-
if not argtype:
54-
raise ValueError(f"Argument `{name}` not found in {self.typed_namespace}")
49+
def _get_argument_type(self, argument_name: str) -> Any:
50+
# Get the argument type hint from the typed_namespace
51+
argument_type = self.argument_types.get(argument_name)
52+
if not argument_type:
53+
raise ValueError(
54+
f"Argument `{argument_name}` not found in {self.typed_namespace}"
55+
)
5556
# The type_conversions map may contain a function to convert the argument type
56-
return self.type_conversions.get(argtype, argtype)
57+
return self.type_conversions.get(argument_type, argument_type)
5758

5859
def add_argument(
59-
self, options: Sequence[str], metavars: Sequence[str], action: str, help: str
60+
self, arguments: Sequence[str], metavars: Sequence[str], action: str, help: str
6061
) -> None:
6162
kwargs: dict[str, Any] = {}
63+
# Sort out the metavar options first
6264
if len(metavars) > 1:
6365
if metavars[-1] == "...":
6466
kwargs["metavar"] = metavars[0]
@@ -70,15 +72,11 @@ def add_argument(
7072
kwargs["metavar"] = metavars[0]
7173

7274
# Get the type hint for the argument from the typed_namespace
73-
argtype = self._get_argument_type(options[-1])
74-
if (
75-
argtype
76-
and argtype is not bool
77-
and argtype is not str
78-
and len(metavars) == 1
79-
):
80-
kwargs["type"] = argtype
81-
elif argtype is bool and not action:
75+
argument_name = arguments[-1].lstrip("-").replace("-", "_")
76+
argument_type = self._get_argument_type(argument_name)
77+
if argument_type and argument_type not in (bool, str) and len(metavars) == 1:
78+
kwargs["type"] = argument_type
79+
elif argument_type is bool and not action:
8280
# default for bool, unless action or fun have been set
8381
action = "store_true"
8482

@@ -87,7 +85,7 @@ def add_argument(
8785
if help:
8886
kwargs["help"] = help
8987

90-
self.parser.add_argument(*options, **kwargs)
88+
self.parser.add_argument(*arguments, **kwargs)
9189

9290

9391
# usage is a multiline string of the form:
@@ -131,21 +129,29 @@ def parser(usage: str, typed_namespace: Namespace | None = None) -> ArgumentPars
131129
prog, description, arguments, epilog = (
132130
paragraph.strip() for paragraph in f"{usage}\n\n".split("\n\n", 3)
133131
)
134-
typed_parser = TypedArgumentParser(
135-
ArgumentParser(prog=prog, description=description, epilog=epilog),
136-
typed_namespace,
137-
)
132+
133+
# Construct a regular argparse ArgumentParser
134+
argparser = ArgumentParser(prog=prog, description=description, epilog=epilog)
135+
# Construct a TypedArgumentParser using the regular parser and the typed_namespace
136+
typed_parser = TypedArgumentParser(argparser, typed_namespace)
138137

139138
# Process each of the arguments in the `arguments` string (one per line)
140139
for line in arguments.splitlines():
140+
# Split the line into parts: ARGUMENTS | HELP STRING | ACTION
141+
# eg. "-i --ignore | Ignore file | T"
141142
argstr, help, action, *_ = (s.strip() for s in f"{line}|||".split("|", 3))
142143

143144
# options contains leading words starting with "-" if any, else all words.
144-
# eg. "-i --input FILE" -> opts = ["-i", "--input"], metavars = ["FILE"]
145-
# eg. "filename" -> opts = ["filename"], metavars = []
146-
words = argstr.split()
147-
options = list(takewhile(lambda s: s.startswith("-"), words)) or words
148-
metavars = words[len(options) :] # trailing words not in options.
149-
typed_parser.add_argument(options, metavars, action, help)
145+
# eg. "-i --input FILE" -> options = ["-i", "--input"], metavars = ["FILE"]
146+
# eg. "filename" -> options = ["filename"], metavars = []
147+
argument_names = argstr.split()
148+
option_names = list(takewhile(lambda s: s.startswith("-"), argument_names))
149+
if not option_names:
150+
# There are no options, so all words are argument names.
151+
typed_parser.add_argument(argument_names, [], action, help)
152+
else:
153+
# If an option is provided, the metavars are the rest of the words.
154+
metavars = argument_names[len(option_names) :]
155+
typed_parser.add_argument(option_names, metavars, action, help)
150156

151157
return typed_parser.parser

src/mp_image_tool_esp32/firmware_fileio.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ def __enter__(self) -> FirmwareDeviceIO:
140140

141141
def read(self, size: int | None = None) -> bytes:
142142
size = size if size is not None else self._end - self._pos
143-
log.debug(f"Reading {size:#x} bytes from {self._pos:#x}...")
143+
log.debug(f"Reading {size:#x} bytes from offset {self._pos:#x}...")
144144
data = self.esptool.read_flash(self._pos, size)
145145
if len(data) != size:
146146
raise ValueError(f"Read {len(data)} bytes from device, expected {size}.")

src/mp_image_tool_esp32/logger.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ def render_message(
4747
console=console,
4848
highlighter=NullHighlighter(),
4949
markup=True,
50-
show_time=False, # Don't show the timem level or path in log messages
50+
show_time=False, # Don't show the time, level or path in log messages
5151
show_level=False,
5252
show_path=False,
5353
rich_tracebacks=True,

src/mp_image_tool_esp32/main.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -124,15 +124,15 @@ class TypedNamespace(argparse.Namespace):
124124
"--table default" (default (non-OTA) partition table),\
125125
"--table nvs=7B,factory=2M,vfs=0". \
126126
SUBTYPE is optional in most cases (inferred from name).
127-
--delete NAME1[,NAME2] | delete the named partitions
127+
--delete NAME1[,NAME2,...] | delete the named partitions
128128
--add NAME1:SUBTYPE:OFFSET:SIZE[,NAME2,...] \
129129
| add new partitions to table
130-
--resize NAME1=SIZE1[,NAME2=SIZE2] \
130+
--resize NAME1=SIZE1[,NAME2=SIZE2,...] \
131131
| resize partitions \
132132
eg. --resize factory=2M,nvs=5B,vfs=0. \
133133
If SIZE is 0, expand partition to available space
134-
--erase NAME1[,NAME2] | erase the named partitions
135-
--erase-fs NAME1[,NAME2] \
134+
--erase NAME1[,NAME2,...] | erase the named partitions
135+
--erase-fs NAME1[,NAME2,...] \
136136
| erase first 4 blocks of a partition on flash storage.\
137137
Micropython will initialise filesystem on next boot.
138138
--read NAME1=FILE1[,NAME2=FILE2,bootloader=FILE,...] \

0 commit comments

Comments
 (0)