Skip to content

Commit b53a16c

Browse files
committed
fix: Fix --port-filter argument parsing
Closes espressif#1101 Closes espressif#1103
1 parent 977ff44 commit b53a16c

File tree

2 files changed

+48
-14
lines changed

2 files changed

+48
-14
lines changed

esptool/cli_util.py

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -300,7 +300,7 @@ def add_to_parser(self, parser, ctx):
300300
def parser_process(value, state):
301301
# Method to hook into the parser.process
302302
done = False
303-
value = [value]
303+
values = [value]
304304
# Grab everything up to the next option/command
305305
while state.rargs and not done:
306306
for prefix in self._eat_all_parser.prefixes:
@@ -310,10 +310,16 @@ def parser_process(value, state):
310310
if state.rargs[0] in self._commands_list:
311311
done = True
312312
if not done:
313-
value.append(state.rargs.pop(0))
313+
values.append(state.rargs.pop(0))
314314

315315
# Call the original parser process method on the rest of the arguments
316-
self._previous_parser_process(value, state)
316+
if self.multiple:
317+
# If multiple options can be used, Click does not support extending the
318+
# value; as the 'value' is list, we need to process each item separately
319+
for v in values:
320+
self._previous_parser_process(v, state)
321+
else:
322+
self._previous_parser_process(values, state)
317323

318324
retval = super(OptionEatAll, self).add_to_parser(parser, ctx)
319325
for name in self.opts:
@@ -379,7 +385,7 @@ def arg_auto_int(x: str) -> int:
379385

380386

381387
def parse_port_filters(
382-
value: list[str],
388+
value: tuple[str],
383389
) -> tuple[list[int], list[int], list[str], list[str]]:
384390
"""Parse port filter arguments into separate lists for each filter type"""
385391
filterVids = []
@@ -389,7 +395,7 @@ def parse_port_filters(
389395
for f in value:
390396
kvp = f.split("=")
391397
if len(kvp) != 2:
392-
FatalError("Option --port-filter argument must consist of key=value.")
398+
raise FatalError("Option --port-filter argument must consist of key=value.")
393399
if kvp[0] == "vid":
394400
filterVids.append(arg_auto_int(kvp[1]))
395401
elif kvp[0] == "pid":

test/test_esptool.py

Lines changed: 37 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,9 @@ def run_espsecure(self, args):
152152
print(e.output)
153153
raise e
154154

155-
def run_esptool(self, args, baud=None, chip=None, port=None, preload=True):
155+
def run_esptool(
156+
self, args, baud=arg_baud, chip=arg_chip, port=arg_port, preload=True
157+
):
156158
"""
157159
Run esptool with the specified arguments. --chip, --port and --baud
158160
are filled in automatically from the command line.
@@ -189,12 +191,12 @@ def run_esptool_process(cmd):
189191
esptool = ["-m", "esptool"]
190192
trace_arg = ["--trace"] if arg_trace else []
191193
base_cmd = [sys.executable] + esptool + trace_arg
192-
if chip or arg_chip is not None and chip != "auto":
193-
base_cmd += ["--chip", chip or arg_chip]
194-
if port or arg_port is not None:
195-
base_cmd += ["--port", port or arg_port]
196-
if baud or arg_baud is not None:
197-
base_cmd += ["--baud", str(baud or arg_baud)]
194+
if chip and chip != "auto":
195+
base_cmd += ["--chip", chip]
196+
if port:
197+
base_cmd += ["--port", port]
198+
if baud:
199+
base_cmd += ["--baud", str(baud)]
198200
usb_jtag_serial_reset = ["--before", "usb-reset"] if arg_preload_port else []
199201
usb_otg_dont_reset = (
200202
["--after", "no-reset-stub"] if "ESPTOOL_TEST_USB_OTG" in os.environ else []
@@ -206,6 +208,7 @@ def run_esptool_process(cmd):
206208
# Preload a dummy binary to disable the RTC watchdog, needed in USB-JTAG/Serial
207209
if (
208210
preload
211+
and port
209212
and arg_preload_port
210213
and arg_chip
211214
in [
@@ -240,15 +243,15 @@ def run_esptool_process(cmd):
240243

241244
return output
242245

243-
def run_esptool_error(self, args, baud=None, chip=None):
246+
def run_esptool_error(self, args, baud=arg_baud, chip=arg_chip, port=arg_port):
244247
"""
245248
Run esptool similar to run_esptool, but expect an error.
246249
247250
Verifies the error is an expected error not an unhandled exception,
248251
and returns the output from esptool as a string.
249252
"""
250253
with pytest.raises(subprocess.CalledProcessError) as fail:
251-
self.run_esptool(args, baud, chip)
254+
self.run_esptool(args, baud, chip, port)
252255
failure = fail.value
253256
assert failure.returncode in [1, 2] # UnsupportedCmdError and FatalError codes
254257
return failure.output.decode("utf-8")
@@ -1913,3 +1916,28 @@ def test_esp_rfc2217_server_py(self):
19131916
decoded = output.decode("utf-8")
19141917
assert "esp_rfc2217_server.py" in decoded
19151918
assert "DEPRECATED" in decoded
1919+
1920+
1921+
@pytest.mark.host_test
1922+
class TestPortFilter(EsptoolTestCase):
1923+
def test_port_filter_name(self):
1924+
"""Test CLI with --port-filter non-existent name option"""
1925+
output = self.run_esptool_error(
1926+
"--port-filter name=NonExistentChip flash-id", port=None
1927+
)
1928+
# The command should fail due to no device found, not due to parsing error
1929+
assert "Option --port-filter argument key not recognized" not in output
1930+
# Should fail with device connection error instead
1931+
assert "Found 0 serial ports..." in output
1932+
1933+
def test_port_filter_invalid_key_error(self):
1934+
"""Test CLI with invalid --port-filter key still shows correct error"""
1935+
output = self.run_esptool_error(
1936+
"--port-filter invalidkey=123 flash-id", port=None
1937+
)
1938+
assert "Option --port-filter argument key not recognized" in output
1939+
1940+
def test_port_filter_missing_equal_sign(self):
1941+
"""Test CLI with missing equal sign in --port-filter option"""
1942+
output = self.run_esptool_error("--port-filter name123 flash-id", port=None)
1943+
assert "Option --port-filter argument must consist of key=value." in output

0 commit comments

Comments
 (0)