Skip to content

Commit 788dd04

Browse files
authored
Detect types in _parse_additonal_config (#1328)
* detect types in _parse_additonal_config * check argument format * fix typo * recognize extra_args * fix typo again
1 parent b9d9d01 commit 788dd04

File tree

4 files changed

+81
-13
lines changed

4 files changed

+81
-13
lines changed

can/logger.py

+29-8
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,12 @@
1313
1414
Dynamic Controls 2010
1515
"""
16-
16+
import re
1717
import sys
1818
import argparse
1919
from datetime import datetime
2020
import errno
21-
from typing import Any, Dict, List, Union
21+
from typing import Any, Dict, List, Union, Sequence, Tuple
2222

2323
import can
2424
from . import Bus, BusState, Logger, SizedRotatingLogger
@@ -134,11 +134,32 @@ def _parse_filters(parsed_args: Any) -> CanFilters:
134134
return can_filters
135135

136136

137-
def _parse_additonal_config(unknown_args):
138-
return dict(
139-
(arg.split("=", 1)[0].lstrip("--").replace("-", "_"), arg.split("=", 1)[1])
140-
for arg in unknown_args
141-
)
137+
def _parse_additional_config(
138+
unknown_args: Sequence[str],
139+
) -> Dict[str, Union[str, int, float, bool]]:
140+
for arg in unknown_args:
141+
if not re.match(r"^--[a-zA-Z\-]*?=\S*?$", arg):
142+
raise ValueError(f"Parsing argument {arg} failed")
143+
144+
def _split_arg(_arg: str) -> Tuple[str, str]:
145+
left, right = _arg.split("=", 1)
146+
return left.lstrip("--").replace("-", "_"), right
147+
148+
args: Dict[str, Union[str, int, float, bool]] = {}
149+
for key, string_val in map(_split_arg, unknown_args):
150+
if re.match(r"^[-+]?\d+$", string_val):
151+
# value is integer
152+
args[key] = int(string_val)
153+
elif re.match(r"^[-+]?\d*\.\d+$", string_val):
154+
# value is float
155+
args[key] = float(string_val)
156+
elif re.match(r"^(?:True|False)$", string_val):
157+
# value is bool
158+
args[key] = string_val == "True"
159+
else:
160+
# value is string
161+
args[key] = string_val
162+
return args
142163

143164

144165
def main() -> None:
@@ -202,7 +223,7 @@ def main() -> None:
202223
raise SystemExit(errno.EINVAL)
203224

204225
results, unknown_args = parser.parse_known_args()
205-
additional_config = _parse_additonal_config(unknown_args)
226+
additional_config = _parse_additional_config(unknown_args)
206227
bus = _create_bus(results, can_filters=_parse_filters(results), **additional_config)
207228

208229
if results.active:

can/player.py

+4-3
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313

1414
from can import LogReader, Message, MessageSync
1515

16-
from .logger import _create_base_argument_parser, _create_bus
16+
from .logger import _create_base_argument_parser, _create_bus, _parse_additional_config
1717

1818

1919
def main() -> None:
@@ -78,13 +78,14 @@ def main() -> None:
7878
parser.print_help(sys.stderr)
7979
raise SystemExit(errno.EINVAL)
8080

81-
results = parser.parse_args()
81+
results, unknown_args = parser.parse_known_args()
82+
additional_config = _parse_additional_config(unknown_args)
8283

8384
verbosity = results.verbosity
8485

8586
error_frames = results.error_frames
8687

87-
with _create_bus(results) as bus:
88+
with _create_bus(results, **additional_config) as bus:
8889
with LogReader(results.infile) as reader:
8990

9091
in_sync = MessageSync(

can/viewer.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@
3535
_parse_filters,
3636
_append_filter_argument,
3737
_create_base_argument_parser,
38-
_parse_additonal_config,
38+
_parse_additional_config,
3939
)
4040

4141

@@ -540,7 +540,7 @@ def parse_args(args):
540540
else:
541541
data_structs[key] = struct.Struct(fmt)
542542

543-
additional_config = _parse_additonal_config(unknown_args)
543+
additional_config = _parse_additional_config(unknown_args)
544544
return parsed_args, can_filters, data_structs, additional_config
545545

546546

test/test_logger.py

+46
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@
1010
import gzip
1111
import os
1212
import sys
13+
14+
import pytest
15+
1316
import can
1417
import can.logger
1518

@@ -105,6 +108,49 @@ def test_log_virtual_sizedlogger(self):
105108
self.assertSuccessfullCleanup()
106109
self.mock_logger_sized.assert_called_once()
107110

111+
def test_parse_additional_config(self):
112+
unknown_args = [
113+
"--app-name=CANalyzer",
114+
"--serial=5555",
115+
"--receive-own-messages=True",
116+
"--false-boolean=False",
117+
"--offset=1.5",
118+
]
119+
parsed_args = can.logger._parse_additional_config(unknown_args)
120+
121+
assert "app_name" in parsed_args
122+
assert parsed_args["app_name"] == "CANalyzer"
123+
124+
assert "serial" in parsed_args
125+
assert parsed_args["serial"] == 5555
126+
127+
assert "receive_own_messages" in parsed_args
128+
assert (
129+
isinstance(parsed_args["receive_own_messages"], bool)
130+
and parsed_args["receive_own_messages"] is True
131+
)
132+
133+
assert "false_boolean" in parsed_args
134+
assert (
135+
isinstance(parsed_args["false_boolean"], bool)
136+
and parsed_args["false_boolean"] is False
137+
)
138+
139+
assert "offset" in parsed_args
140+
assert parsed_args["offset"] == 1.5
141+
142+
with pytest.raises(ValueError):
143+
can.logger._parse_additional_config(["--wrong-format"])
144+
145+
with pytest.raises(ValueError):
146+
can.logger._parse_additional_config(["-wrongformat=value"])
147+
148+
with pytest.raises(ValueError):
149+
can.logger._parse_additional_config(["--wrongformat=value1 value2"])
150+
151+
with pytest.raises(ValueError):
152+
can.logger._parse_additional_config(["wrongformat="])
153+
108154

109155
class TestLoggerCompressedFile(unittest.TestCase):
110156
def setUp(self) -> None:

0 commit comments

Comments
 (0)