From e6c8234ba03b26cda2e70413272cdea8389a89ec Mon Sep 17 00:00:00 2001 From: Anqi Xu Date: Thu, 29 May 2025 19:16:25 +0000 Subject: [PATCH 1/4] - for optional-typed field, parse string literal "None" into `None` - added unit tests --- simple_parsing/wrappers/field_parsing.py | 8 ++++++-- test/test_optional.py | 20 ++++++++++++++++++++ 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/simple_parsing/wrappers/field_parsing.py b/simple_parsing/wrappers/field_parsing.py index 5208a6ec..da593b5d 100644 --- a/simple_parsing/wrappers/field_parsing.py +++ b/simple_parsing/wrappers/field_parsing.py @@ -200,11 +200,15 @@ def parse_optional(t: type[T]) -> Callable[[Optional[Any]], Optional[T]]: parse = get_parsing_fn(t) def _parse_optional(val: Optional[Any]) -> Optional[T]: - return val if val is None else parse(val) + if val is None: + return val + elif type(val) is str and val == "None": + return None + else: + return parse(val) return _parse_optional - def parse_tuple(tuple_item_types: tuple[type[T], ...]) -> Callable[[list[T]], tuple[T, ...]]: """Makes a parsing function for creating tuples from the command-line args. diff --git a/test/test_optional.py b/test/test_optional.py index fc3226d5..8450523d 100644 --- a/test/test_optional.py +++ b/test/test_optional.py @@ -31,6 +31,26 @@ def test_optional_seed(): assert config == Config(123) +@dataclass +class Config2: + var_with_default: Optional[int] = 42 + + +def test_optional_with_default_value(): + """Test that a value marked as Optional with a default value can be overridden to None. + """ + parser = ArgumentParser() + parser.add_arguments(Config2, dest="config") + + args = parser.parse_args("".split()) + config: Config2 = args.config + assert config == Config2(var_with_default=42) + + args = parser.parse_args("--var_with_default".split()) + config: Config2 = args.config + assert config == Config2(var_with_default=None) + + @dataclass class Child: name: str = "Kevin" From 653e88f923f97da9698a1808876a4f9685eea570 Mon Sep 17 00:00:00 2001 From: Anqi Xu Date: Tue, 10 Jun 2025 21:37:03 -0700 Subject: [PATCH 2/4] switch from comparing type() to isinstance() --- simple_parsing/wrappers/field_parsing.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/simple_parsing/wrappers/field_parsing.py b/simple_parsing/wrappers/field_parsing.py index da593b5d..0cd36703 100644 --- a/simple_parsing/wrappers/field_parsing.py +++ b/simple_parsing/wrappers/field_parsing.py @@ -202,7 +202,7 @@ def parse_optional(t: type[T]) -> Callable[[Optional[Any]], Optional[T]]: def _parse_optional(val: Optional[Any]) -> Optional[T]: if val is None: return val - elif type(val) is str and val == "None": + elif isinstance(val, str) and val == "None": return None else: return parse(val) From fadda1e50b0ce3e46cb204ddc98135438facdd3c Mon Sep 17 00:00:00 2001 From: Anqi Xu Date: Thu, 12 Jun 2025 21:44:16 -0700 Subject: [PATCH 3/4] revert unintentionally deleted newline --- simple_parsing/wrappers/field_parsing.py | 1 + 1 file changed, 1 insertion(+) diff --git a/simple_parsing/wrappers/field_parsing.py b/simple_parsing/wrappers/field_parsing.py index 0cd36703..3734ed32 100644 --- a/simple_parsing/wrappers/field_parsing.py +++ b/simple_parsing/wrappers/field_parsing.py @@ -209,6 +209,7 @@ def _parse_optional(val: Optional[Any]) -> Optional[T]: return _parse_optional + def parse_tuple(tuple_item_types: tuple[type[T], ...]) -> Callable[[list[T]], tuple[T, ...]]: """Makes a parsing function for creating tuples from the command-line args. From 6e16dcfe4bf49f6fb2a1c4307ba3699d68db5ab3 Mon Sep 17 00:00:00 2001 From: Fabrice Normandin Date: Fri, 29 Aug 2025 11:01:33 -0400 Subject: [PATCH 4/4] Add test case for passing "None" from command-line --- test/test_optional.py | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/test/test_optional.py b/test/test_optional.py index 8450523d..9dcc16c5 100644 --- a/test/test_optional.py +++ b/test/test_optional.py @@ -42,13 +42,9 @@ def test_optional_with_default_value(): parser = ArgumentParser() parser.add_arguments(Config2, dest="config") - args = parser.parse_args("".split()) - config: Config2 = args.config - assert config == Config2(var_with_default=42) - - args = parser.parse_args("--var_with_default".split()) - config: Config2 = args.config - assert config == Config2(var_with_default=None) + assert parser.parse_args([]).config == Config2(var_with_default=42) + assert parser.parse_args(["--var_with_default"]).config == Config2(var_with_default=None) + assert parser.parse_args("--var_with_default None".split()).config == Config2(var_with_default=None) @dataclass