Skip to content

Commit 94e8243

Browse files
committed
added fix_default for ChoiceMap custom input; added doc entry for strict_default
1 parent 0a9eec8 commit 94e8243

8 files changed

Lines changed: 35 additions & 4 deletions

File tree

bin/argparse_to_command.py

100644100755
File mode changed.

bin/build_docs.py

100644100755
File mode changed.

bin/tag.py

100644100755
File mode changed.

docs/_src/parameters.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,9 @@ Common parameters that are supported when initializing most Parameters:
7474
values. By default, no transformation is performed, and values will be strings. If not specified, but a type
7575
annotation is detected, then that annotation will be used as if it was provided here. When both are present, this
7676
argument takes precedence.
77+
:strict_default: Whether default values should be processed as if provided via CLI (this happens when
78+
``strict_default=False``, the default), or used as-is (``strict_default=True``). Only applies to :doc:`inputs`
79+
that have a :meth:`~.InputType.fix_default` method.
7780

7881

7982
Options

lib/cli_command_parser/inputs/choices.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,12 @@ def __call__(self, value: str) -> T:
147147

148148
return self._case_insensitive_map_choice(value)
149149

150+
def fix_default(self, value: Any) -> T:
151+
if value in self.choices.values():
152+
return value
153+
else:
154+
return self(value)
155+
150156

151157
class EnumChoices(_ChoicesBase[EnumT]):
152158
"""

lib/cli_command_parser/parameters/actions.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,8 @@ def get_default(self, command: CommandObj | None = None, missing_default=_NotSet
145145
return self.default
146146

147147
def finalize_default(self, value):
148+
if self.param.strict_default:
149+
return value
148150
if (type_func := self.param.type) and isinstance(type_func, InputType):
149151
return type_func.fix_default(value)
150152
return value

lib/cli_command_parser/testing.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -94,9 +94,6 @@ class ParserTest(TestCase):
9494
def assert_dict_equal(self, d1, d2, msg: str = None):
9595
self.assertIsInstance(d1, dict, 'First argument is not a dictionary')
9696
self.assertIsInstance(d2, dict, 'Second argument is not a dictionary')
97-
self._assert_dict_equal(d1, d2, msg)
98-
99-
def _assert_dict_equal(self, d1, d2, msg: str = None):
10097
if d1 != d2:
10198
self.fail(self._formatMessage(msg, f'{d1} != {d2}\n{format_dict_diff(d1, d2)}'))
10299

@@ -105,7 +102,9 @@ def assert_raises_contains_str(self, expected_exc: Type[BaseException], expected
105102

106103
def assert_parse_results(self, cmd_cls: CommandCls, argv: Argv, expected: Expected, msg: str = None) -> Command:
107104
cmd = cmd_cls.parse(argv)
108-
self._assert_dict_equal(expected, cmd.ctx.get_parsed(cmd, exclude=EXCLUDE_ACTIONS), msg)
105+
parsed = cmd.ctx.get_parsed(cmd, exclude=EXCLUDE_ACTIONS)
106+
if expected != parsed:
107+
self.fail(msg or f'Expected results ({expected}) != {parsed=}\n{format_dict_diff(expected, parsed)}')
109108
return cmd
110109

111110
def assert_parse_results_cases(self, cmd_cls: CommandCls, cases: Iterable[Case], msg: str = None):

tests/test_inputs/test_choice_inputs.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,27 @@ class Foo(Command):
201201
self.assert_parse_results_cases(Foo, success_cases)
202202
self.assert_parse_fails_cases(Foo, fail_cases, UsageError)
203203

204+
def test_choice_map_default_fixed(self):
205+
class Foo(Command):
206+
bar = Option('-b', default='a', type=ChoiceMap({'a': 'ABC', 'x': 'XYZ'}))
207+
208+
success_cases = [([], {'bar': 'ABC'}), (['-b', 'a'], {'bar': 'ABC'}), (['-b', 'x'], {'bar': 'XYZ'})]
209+
self.assert_parse_results_cases(Foo, success_cases)
210+
211+
def test_choice_map_default_in_values(self):
212+
class Foo(Command):
213+
bar = Option('-b', default='ABC', type=ChoiceMap({'a': 'ABC', 'x': 'XYZ'}))
214+
215+
success_cases = [([], {'bar': 'ABC'}), (['-b', 'a'], {'bar': 'ABC'}), (['-b', 'x'], {'bar': 'XYZ'})]
216+
self.assert_parse_results_cases(Foo, success_cases)
217+
218+
def test_choice_map_default_not_fixed(self):
219+
class Foo(Command):
220+
bar = Option('-b', default='a', type=ChoiceMap({'a': 'ABC', 'x': 'XYZ'}), strict_default=True)
221+
222+
success_cases = [([], {'bar': 'a'}), (['-b', 'a'], {'bar': 'ABC'}), (['-b', 'x'], {'bar': 'XYZ'})]
223+
self.assert_parse_results_cases(Foo, success_cases)
224+
204225

205226
if __name__ == '__main__':
206227
# import logging

0 commit comments

Comments
 (0)