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):
|
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}]]
|
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)
|
config = get_config(json)
|
||||||
parser = TiramisuCmdlineParser(config, 'prog.py', formatter_class=TestHelpFormatter)
|
parser = TiramisuCmdlineParser(config, 'prog.py', formatter_class=TestHelpFormatter)
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@
|
||||||
from typing import Union, List, Dict, Tuple, Optional, Any
|
from typing import Union, List, Dict, Tuple, Optional, Any
|
||||||
from argparse import (
|
from argparse import (
|
||||||
ArgumentParser,
|
ArgumentParser,
|
||||||
|
ArgumentError,
|
||||||
Namespace,
|
Namespace,
|
||||||
SUPPRESS,
|
SUPPRESS,
|
||||||
_HelpAction,
|
_HelpAction,
|
||||||
|
|
@ -123,11 +124,13 @@ class TiramisuNamespace(Namespace):
|
||||||
option = self._config.option(true_key)
|
option = self._config.option(true_key)
|
||||||
if option.isfollower():
|
if option.isfollower():
|
||||||
_setattr = self._setattr_follower
|
_setattr = self._setattr_follower
|
||||||
if not value[0].isdecimal():
|
index = value[0]
|
||||||
raise ValueError("index must be a number, not {}".format(value[0]))
|
if isinstance(index, str):
|
||||||
index = int(value[0])
|
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)
|
option = self._config.option(true_key, index)
|
||||||
true_value = ",".join(value[1:])
|
true_value = ",".join([str(v) for v in value[1:]])
|
||||||
else:
|
else:
|
||||||
_setattr = self._setattr
|
_setattr = self._setattr
|
||||||
true_value = value
|
true_value = value
|
||||||
|
|
@ -168,7 +171,7 @@ class TiramisuNamespace(Namespace):
|
||||||
"argument {}: invalid choice: '{}' (choose from {})".format(
|
"argument {}: invalid choice: '{}' (choose from {})".format(
|
||||||
self.arguments[key],
|
self.arguments[key],
|
||||||
display_value,
|
display_value,
|
||||||
", ".join([f"'{val}'" for val in choices]),
|
", ".join([f"{val}" for val in choices]),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
|
|
@ -177,6 +180,12 @@ class TiramisuNamespace(Namespace):
|
||||||
def _setattr(self, option: "Option", true_key: str, key: str, value: Any) -> None:
|
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):
|
if option.ismulti() and value is not None and not isinstance(value, list):
|
||||||
value = [value]
|
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:
|
try:
|
||||||
option.value.set(value)
|
option.value.set(value)
|
||||||
except PropertiesOptionError as err:
|
except PropertiesOptionError as err:
|
||||||
|
|
@ -400,6 +409,7 @@ class TiramisuCmdlineParser(ArgumentParser):
|
||||||
self.config,
|
self.config,
|
||||||
self.prog,
|
self.prog,
|
||||||
root=self.root,
|
root=self.root,
|
||||||
|
exit_on_error=self.exit_on_error,
|
||||||
remove_empty_od=self.remove_empty_od,
|
remove_empty_od=self.remove_empty_od,
|
||||||
display_modified_value=self.display_modified_value,
|
display_modified_value=self.display_modified_value,
|
||||||
formatter_class=self.formatter_class,
|
formatter_class=self.formatter_class,
|
||||||
|
|
@ -654,7 +664,7 @@ class TiramisuCmdlineParser(ArgumentParser):
|
||||||
kwargs["nargs"] = 2
|
kwargs["nargs"] = 2
|
||||||
if _forhelp and "mandatory" not in properties:
|
if _forhelp and "mandatory" not in properties:
|
||||||
metavar = "[{}]".format(metavar)
|
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
|
# do not manage choice with argparse there is problem with integer problem
|
||||||
kwargs["metavar"] = (
|
kwargs["metavar"] = (
|
||||||
"INDEX",
|
"INDEX",
|
||||||
|
|
@ -673,13 +683,15 @@ class TiramisuCmdlineParser(ArgumentParser):
|
||||||
if _forhelp and option.type() == "boolean":
|
if _forhelp and option.type() == "boolean":
|
||||||
kwargs["metavar"] = "INDEX"
|
kwargs["metavar"] = "INDEX"
|
||||||
kwargs["nargs"] = 1
|
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
|
# do not manage choice with argparse there is problem with integer problem
|
||||||
kwargs["choices"] = get_choice_list(option, properties, False)
|
kwargs["choices"] = get_choice_list(option, properties, False)
|
||||||
elif option.type() == "float":
|
elif option.type() == "float":
|
||||||
kwargs["type"] = float
|
kwargs["type"] = float
|
||||||
else:
|
else:
|
||||||
pass
|
pass
|
||||||
|
if not _forhelp and option.type() != "boolean" and "nargs" not in kwargs.kwargs:
|
||||||
|
kwargs["nargs"] = "?"
|
||||||
actions.setdefault(kwargs.ga_name, []).append(kwargs)
|
actions.setdefault(kwargs.ga_name, []).append(kwargs)
|
||||||
|
|
||||||
for option_is_not_default in options_is_not_default.values():
|
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):
|
def parse_args(self, *args, valid_mandatory=True, **kwargs):
|
||||||
kwargs["namespace"] = self.namespace
|
kwargs["namespace"] = self.namespace
|
||||||
try:
|
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:
|
except PropertiesOptionError as err:
|
||||||
name = err._subconfig.path
|
name = err._subconfig.path
|
||||||
properties = self.config.option(name).property.get()
|
properties = self.config.option(name).property.get()
|
||||||
|
|
@ -739,6 +753,13 @@ class TiramisuCmdlineParser(ArgumentParser):
|
||||||
self.error(
|
self.error(
|
||||||
"the following arguments are required: {}".format(", ".join(errors))
|
"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
|
return namespaces
|
||||||
|
|
||||||
def format_usage(self, *args, **kwargs):
|
def format_usage(self, *args, **kwargs):
|
||||||
|
|
@ -779,3 +800,9 @@ class TiramisuCmdlineParser(ArgumentParser):
|
||||||
|
|
||||||
def get_config(self):
|
def get_config(self):
|
||||||
return self.config
|
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