feat: do not exit() with exit_on_error to False
This commit is contained in:
parent
1ca99df30e
commit
44378162b2
2 changed files with 36 additions and 9 deletions
|
|
@ -306,7 +306,7 @@ def test_leadership_modif_follower_choice(json):
|
|||
|
||||
def test_leadership_modif_follower_choice_unknown(json):
|
||||
output = """usage: prog.py [-h] [--leader.leader [LEADER ...]] [--leader.pop-leader INDEX] [--leader.follower INDEX [FOLLOWER]] [--leader.follower_submulti INDEX [FOLLOWER_SUBMULTI ...]] [--leader.follower_integer INDEX [FOLLOWER_INTEGER]] [--leader.follower_boolean INDEX] [--leader.no-follower_boolean INDEX] [--leader.follower_choice INDEX [{opt1,opt2}]]
|
||||
prog.py: error: argument --leader.follower_choice: invalid choice: 'opt_unknown' (choose from 'opt1', 'opt2')
|
||||
prog.py: error: argument --leader.follower_choice: invalid choice: 'opt_unknown' (choose from opt1, opt2)
|
||||
"""
|
||||
config = get_config(json)
|
||||
parser = TiramisuCmdlineParser(config, 'prog.py', formatter_class=TestHelpFormatter)
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@
|
|||
from typing import Union, List, Dict, Tuple, Optional, Any
|
||||
from argparse import (
|
||||
ArgumentParser,
|
||||
ArgumentError,
|
||||
Namespace,
|
||||
SUPPRESS,
|
||||
_HelpAction,
|
||||
|
|
@ -123,11 +124,13 @@ class TiramisuNamespace(Namespace):
|
|||
option = self._config.option(true_key)
|
||||
if option.isfollower():
|
||||
_setattr = self._setattr_follower
|
||||
if not value[0].isdecimal():
|
||||
raise ValueError("index must be a number, not {}".format(value[0]))
|
||||
index = int(value[0])
|
||||
index = value[0]
|
||||
if isinstance(index, str):
|
||||
if not value[0].isdecimal():
|
||||
raise ValueError("index must be a number, not {}".format(value[0]))
|
||||
index = int(index)
|
||||
option = self._config.option(true_key, index)
|
||||
true_value = ",".join(value[1:])
|
||||
true_value = ",".join([str(v) for v in value[1:]])
|
||||
else:
|
||||
_setattr = self._setattr
|
||||
true_value = value
|
||||
|
|
@ -168,7 +171,7 @@ class TiramisuNamespace(Namespace):
|
|||
"argument {}: invalid choice: '{}' (choose from {})".format(
|
||||
self.arguments[key],
|
||||
display_value,
|
||||
", ".join([f"'{val}'" for val in choices]),
|
||||
", ".join([f"{val}" for val in choices]),
|
||||
)
|
||||
)
|
||||
else:
|
||||
|
|
@ -177,6 +180,12 @@ class TiramisuNamespace(Namespace):
|
|||
def _setattr(self, option: "Option", true_key: str, key: str, value: Any) -> None:
|
||||
if option.ismulti() and value is not None and not isinstance(value, list):
|
||||
value = [value]
|
||||
if option.isleader():
|
||||
# set value for a leader, it began to remove all values!
|
||||
len_leader = option.value.len()
|
||||
if len_leader:
|
||||
for idx in range(len_leader - 1, -1, -1):
|
||||
option.value.pop(idx)
|
||||
try:
|
||||
option.value.set(value)
|
||||
except PropertiesOptionError as err:
|
||||
|
|
@ -400,6 +409,7 @@ class TiramisuCmdlineParser(ArgumentParser):
|
|||
self.config,
|
||||
self.prog,
|
||||
root=self.root,
|
||||
exit_on_error=self.exit_on_error,
|
||||
remove_empty_od=self.remove_empty_od,
|
||||
display_modified_value=self.display_modified_value,
|
||||
formatter_class=self.formatter_class,
|
||||
|
|
@ -654,7 +664,7 @@ class TiramisuCmdlineParser(ArgumentParser):
|
|||
kwargs["nargs"] = 2
|
||||
if _forhelp and "mandatory" not in properties:
|
||||
metavar = "[{}]".format(metavar)
|
||||
if option.type() == "choice":
|
||||
if _forhelp and option.type() == "choice":
|
||||
# do not manage choice with argparse there is problem with integer problem
|
||||
kwargs["metavar"] = (
|
||||
"INDEX",
|
||||
|
|
@ -673,13 +683,15 @@ class TiramisuCmdlineParser(ArgumentParser):
|
|||
if _forhelp and option.type() == "boolean":
|
||||
kwargs["metavar"] = "INDEX"
|
||||
kwargs["nargs"] = 1
|
||||
elif option.type() == "choice" and not option.isfollower():
|
||||
elif _forhelp and option.type() == "choice" and not option.isfollower():
|
||||
# do not manage choice with argparse there is problem with integer problem
|
||||
kwargs["choices"] = get_choice_list(option, properties, False)
|
||||
elif option.type() == "float":
|
||||
kwargs["type"] = float
|
||||
else:
|
||||
pass
|
||||
if not _forhelp and option.type() != "boolean" and "nargs" not in kwargs.kwargs:
|
||||
kwargs["nargs"] = "?"
|
||||
actions.setdefault(kwargs.ga_name, []).append(kwargs)
|
||||
|
||||
for option_is_not_default in options_is_not_default.values():
|
||||
|
|
@ -696,7 +708,9 @@ class TiramisuCmdlineParser(ArgumentParser):
|
|||
def parse_args(self, *args, valid_mandatory=True, **kwargs):
|
||||
kwargs["namespace"] = self.namespace
|
||||
try:
|
||||
namespaces = super().parse_args(*args, **kwargs)
|
||||
namespaces, unknown = super().parse_known_args(*args, **kwargs)
|
||||
if unknown:
|
||||
msg_unknown = 'unrecognized arguments: %s' % ' '.join(unknown)
|
||||
except PropertiesOptionError as err:
|
||||
name = err._subconfig.path
|
||||
properties = self.config.option(name).property.get()
|
||||
|
|
@ -739,6 +753,13 @@ class TiramisuCmdlineParser(ArgumentParser):
|
|||
self.error(
|
||||
"the following arguments are required: {}".format(", ".join(errors))
|
||||
)
|
||||
if unknown:
|
||||
if self.exit_on_error:
|
||||
self.error(msg_unknown)
|
||||
else:
|
||||
err = ArgumentError(None, msg_unknown)
|
||||
err.unknown = unknown
|
||||
raise err
|
||||
return namespaces
|
||||
|
||||
def format_usage(self, *args, **kwargs):
|
||||
|
|
@ -779,3 +800,9 @@ class TiramisuCmdlineParser(ArgumentParser):
|
|||
|
||||
def get_config(self):
|
||||
return self.config
|
||||
|
||||
def error(self, msg):
|
||||
if self.exit_on_error:
|
||||
super().error(msg)
|
||||
else:
|
||||
raise ArgumentError(None, msg)
|
||||
|
|
|
|||
Loading…
Reference in a new issue