From cd783b4d8dc7e5685d146821dff2573ebcd7e072 Mon Sep 17 00:00:00 2001 From: Jordan Yates Date: Thu, 16 Apr 2026 16:39:31 +1000 Subject: [PATCH 1/4] util: argparse: reject directories from `ValidFile` Update `ValidFile` to reject directories. Signed-off-by: Jordan Yates --- src/infuse_iot/util/argparse.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/infuse_iot/util/argparse.py b/src/infuse_iot/util/argparse.py index aefbeea..9eb7794 100644 --- a/src/infuse_iot/util/argparse.py +++ b/src/infuse_iot/util/argparse.py @@ -12,12 +12,15 @@ class ValidFile: - """Filesystem path that exists""" + """Filesystem file that exists""" def __new__(cls, string) -> pathlib.Path: # type: ignore p = pathlib.Path(string) if p.exists(): - return p + if p.is_dir(): + raise argparse.ArgumentTypeError(f"{string} is a directory") + else: + return p else: raise argparse.ArgumentTypeError(f"{string} does not exist") From de64f4b279e15792e34ad03c13bdf08b93ac5023 Mon Sep 17 00:00:00 2001 From: Jordan Yates Date: Thu, 16 Apr 2026 17:21:18 +1000 Subject: [PATCH 2/4] tests: util: argparse: added Add tests for the argparse utilities. Signed-off-by: Jordan Yates --- tests/util/test_argparse.py | 46 +++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 tests/util/test_argparse.py diff --git a/tests/util/test_argparse.py b/tests/util/test_argparse.py new file mode 100644 index 0000000..060bebf --- /dev/null +++ b/tests/util/test_argparse.py @@ -0,0 +1,46 @@ +import argparse +import os +import pathlib + +import pytest + +from infuse_iot.util.argparse import BtLeAddress, ValidDir, ValidFile + +assert "TOXTEMPDIR" in os.environ, "you must run these tests using tox" + + +def test_valid_file(): + test_file = __file__ + test_dir = str(pathlib.Path(test_file).parent) + + with pytest.raises(argparse.ArgumentTypeError): + ValidFile("random_file_doesnt_exist.txt") + with pytest.raises(argparse.ArgumentTypeError): + ValidFile(test_dir) + parsed = ValidFile(test_file) + assert isinstance(parsed, pathlib.Path) + + +def test_valid_directory(): + test_file = __file__ + test_dir = str(pathlib.Path(test_file).parent) + + with pytest.raises(argparse.ArgumentTypeError): + ValidDir("random_folder_doesnt_exist") + with pytest.raises(argparse.ArgumentTypeError): + ValidDir(test_file) + parsed = ValidDir(test_dir) + assert isinstance(parsed, pathlib.Path) + + +def test_bt_le_address(): + with pytest.raises(argparse.ArgumentTypeError): + BtLeAddress("NotAnAddress") + with pytest.raises(argparse.ArgumentTypeError): + BtLeAddress("XX:XX:XX:XX:XX:XX") + with pytest.raises(argparse.ArgumentTypeError): + BtLeAddress("12:34:56:aa:FF") + addr = BtLeAddress("12:34:56:aa:FF:4A") + assert isinstance(addr, int) + addr = BtLeAddress("123456aaFF4A") + assert isinstance(addr, int) From a47467e3438406635a70252388d28ad4486ce6ce Mon Sep 17 00:00:00 2001 From: Jordan Yates Date: Thu, 16 Apr 2026 17:21:52 +1000 Subject: [PATCH 3/4] util: argparse: remove `-` string replace Addresses with `-` won't pass the regex, so no need to handle. Signed-off-by: Jordan Yates --- src/infuse_iot/util/argparse.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/infuse_iot/util/argparse.py b/src/infuse_iot/util/argparse.py index 9eb7794..662e035 100644 --- a/src/infuse_iot/util/argparse.py +++ b/src/infuse_iot/util/argparse.py @@ -58,7 +58,7 @@ def __new__(cls, string) -> int: # type: ignore pattern = r"((([0-9a-fA-F]{2}):){5})([0-9a-fA-F]{2})" if re.match(pattern, string): - mac_cleaned = string.replace(":", "").replace("-", "") + mac_cleaned = string.replace(":", "") addr = int(mac_cleaned, 16) else: try: From b4fa00f25ee3a6e9e6a66dcffc743b601f1d11ec Mon Sep 17 00:00:00 2001 From: Jordan Yates Date: Thu, 16 Apr 2026 17:23:59 +1000 Subject: [PATCH 4/4] commands: add alternate return type to `request_struct` Command implementations can validly return a `bytes` object from `request_struct`. Signed-off-by: Jordan Yates --- src/infuse_iot/commands.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/infuse_iot/commands.py b/src/infuse_iot/commands.py index f82c828..c41557f 100644 --- a/src/infuse_iot/commands.py +++ b/src/infuse_iot/commands.py @@ -60,7 +60,7 @@ def auth_level(self) -> Auth: """Authentication level to run command with""" return Auth.DEVICE - def request_struct(self) -> ctypes.LittleEndianStructure: + def request_struct(self) -> ctypes.LittleEndianStructure | bytes: """RPC_CMD request structure""" raise NotImplementedError