From 3fca16c8744e00ad59714ff693c0ca67504a1ed7 Mon Sep 17 00:00:00 2001 From: Emmanuel Garette Date: Thu, 11 Jun 2026 22:24:49 +0200 Subject: [PATCH] feat: allow undefined option --- tests/test_boolean.py | 22 ++++++------ tests/test_choice.py | 8 ++--- tests/test_help.py | 4 +-- tests/test_leadership.py | 18 +++++----- tests/test_readme.py | 56 ++++++++++++++--------------- tests/test_shortarg.py | 32 ++++++++--------- tiramisu_cmdline_parser/__init__.py | 2 +- tiramisu_cmdline_parser/api.py | 50 ++++++++++++++++++-------- 8 files changed, 107 insertions(+), 85 deletions(-) diff --git a/tests/test_boolean.py b/tests/test_boolean.py index 34c43bd..0051065 100644 --- a/tests/test_boolean.py +++ b/tests/test_boolean.py @@ -41,7 +41,7 @@ root: --root.verbosity increase output verbosity (default: False) --root.no-verbosity """ - parser = TiramisuCmdlineParser(get_config(has_tree=True), 'prog.py', formatter_class=TestHelpFormatter) + parser = TiramisuCmdlineParser(get_config(has_tree=True), 'prog.py', formatter_class=TestHelpFormatter, color=False) f = StringIO() with redirect_stdout(f): parser.print_help() @@ -56,7 +56,7 @@ options: --verbosity increase output verbosity (default: False) --no-verbosity """ - parser = TiramisuCmdlineParser(get_config(), 'prog.py', formatter_class=TestHelpFormatter) + parser = TiramisuCmdlineParser(get_config(), 'prog.py', formatter_class=TestHelpFormatter, color=False) f = StringIO() with redirect_stdout(f): parser.print_help() @@ -71,7 +71,7 @@ options: --verbosity increase output verbosity (default: True) --no-verbosity """ - parser = TiramisuCmdlineParser(get_config(default_verbosity=True), 'prog.py', formatter_class=TestHelpFormatter) + parser = TiramisuCmdlineParser(get_config(default_verbosity=True), 'prog.py', formatter_class=TestHelpFormatter, color=False) f = StringIO() with redirect_stdout(f): parser.print_help() @@ -80,47 +80,47 @@ options: def test_boolean_true(): config = get_config(default_verbosity=True) - parser = TiramisuCmdlineParser(config, 'prog.py', formatter_class=TestHelpFormatter) + parser = TiramisuCmdlineParser(config, 'prog.py', formatter_class=TestHelpFormatter, color=False) assert to_dict(config.value.get()) == {'verbosity': True} def test_boolean_false(): config = get_config() - parser = TiramisuCmdlineParser(config, 'prog.py', formatter_class=TestHelpFormatter) + parser = TiramisuCmdlineParser(config, 'prog.py', formatter_class=TestHelpFormatter, color=False) assert to_dict(config.value.get()) == {'verbosity': False} def test_boolean_true_to_false(): config = get_config(default_verbosity=True) - parser = TiramisuCmdlineParser(config, 'prog.py', formatter_class=TestHelpFormatter) + parser = TiramisuCmdlineParser(config, 'prog.py', formatter_class=TestHelpFormatter, color=False) parser.parse_args(['--no-verbosity']) assert to_dict(config.value.get()) == {'verbosity': False} def test_boolean_true_to_true(): config = get_config(default_verbosity=True) - parser = TiramisuCmdlineParser(config, 'prog.py', formatter_class=TestHelpFormatter) + parser = TiramisuCmdlineParser(config, 'prog.py', formatter_class=TestHelpFormatter, color=False) parser.parse_args(['--verbosity']) assert to_dict(config.value.get()) == {'verbosity': True} def test_boolean_false_to_true(): config = get_config() - parser = TiramisuCmdlineParser(config, 'prog.py', formatter_class=TestHelpFormatter) + parser = TiramisuCmdlineParser(config, 'prog.py', formatter_class=TestHelpFormatter, color=False) parser.parse_args(['--verbosity']) assert to_dict(config.value.get()) == {'verbosity': True} def test_boolean_false_to_false(): config = get_config() - parser = TiramisuCmdlineParser(config, 'prog.py', formatter_class=TestHelpFormatter) + parser = TiramisuCmdlineParser(config, 'prog.py', formatter_class=TestHelpFormatter, color=False) parser.parse_args(['--verbosity']) assert to_dict(config.value.get()) == {'verbosity': True} def test_boolean_disabled(): config = get_config(default_verbosity=True) - parser = TiramisuCmdlineParser(config, 'prog.py', formatter_class=TestHelpFormatter) + parser = TiramisuCmdlineParser(config, 'prog.py', formatter_class=TestHelpFormatter, color=False) f = StringIO() with redirect_stderr(f): try: @@ -134,7 +134,7 @@ prog.py: error: unrecognized arguments: --disabled (cannot access to option "dis def test_boolean_no_disabled(): config = get_config(default_verbosity=True) - parser = TiramisuCmdlineParser(config, 'prog.py', formatter_class=TestHelpFormatter) + parser = TiramisuCmdlineParser(config, 'prog.py', formatter_class=TestHelpFormatter, color=False) f = StringIO() with redirect_stderr(f): try: diff --git a/tests/test_choice.py b/tests/test_choice.py index 9d0a241..39bed08 100644 --- a/tests/test_choice.py +++ b/tests/test_choice.py @@ -58,7 +58,7 @@ prog.py: error: argument positional: invalid choice: 'error' (choose from str, l prog.py: error: argument positional_int: invalid choice: '4' (choose from 1, 2, 3) ''' config = get_config(json) - parser = TiramisuCmdlineParser(config, 'prog.py', formatter_class=TestHelpFormatter) + parser = TiramisuCmdlineParser(config, 'prog.py', formatter_class=TestHelpFormatter, color=False) parser.parse_args(['str', '1']) assert to_dict(config.value.get()) == {'positional': 'str', 'positional_int': 1, @@ -91,7 +91,7 @@ def test_choice_str(json): prog.py: error: argument --str: invalid choice: 'error' (choose from str1, str2, str3) """ config = get_config(json) - parser = TiramisuCmdlineParser(config, 'prog.py', formatter_class=TestHelpFormatter) + parser = TiramisuCmdlineParser(config, 'prog.py', formatter_class=TestHelpFormatter, color=False) parser.parse_args(['str', '1', '--str', 'str1']) assert to_dict(config.value.get()) == {'positional': 'str', 'positional_int': 1, @@ -131,7 +131,7 @@ def test_choice_int(json): prog.py: error: argument --int: invalid choice: '4' (choose from 1, 2, 3) """ config = get_config(json) - parser = TiramisuCmdlineParser(config, 'prog.py', formatter_class=TestHelpFormatter) + parser = TiramisuCmdlineParser(config, 'prog.py', formatter_class=TestHelpFormatter, color=False) parser.parse_args(['str', '1', '--int', '1']) assert to_dict(config.value.get()) == {'positional': 'str', 'positional_int': 1, @@ -159,7 +159,7 @@ def test_choice_int_multi(json): prog.py: error: argument --int_multi: invalid choice: '4' (choose from 1, 2, 3) """ config = get_config(json) - parser = TiramisuCmdlineParser(config, 'prog.py', formatter_class=TestHelpFormatter) + parser = TiramisuCmdlineParser(config, 'prog.py', formatter_class=TestHelpFormatter, color=False) parser.parse_args(['str', '1', '--int_multi', '1', '2']) assert to_dict(config.value.get()) == {'positional': 'str', 'positional_int': 1, diff --git a/tests/test_help.py b/tests/test_help.py index 6a44020..d828810 100644 --- a/tests/test_help.py +++ b/tests/test_help.py @@ -51,7 +51,7 @@ options: od: {str,list,int,none} choice the sub argument """ - parser = TiramisuCmdlineParser(get_config(json), 'prog.py', formatter_class=TestHelpFormatter) + parser = TiramisuCmdlineParser(get_config(json), 'prog.py', formatter_class=TestHelpFormatter, color=False) f = StringIO() with redirect_stdout(f): parser.print_help() @@ -69,7 +69,7 @@ od: two line """ - parser = TiramisuCmdlineParser(get_config(json), 'prog.py', epilog="\ntwo\nline", formatter_class=TestHelpFormatter) + parser = TiramisuCmdlineParser(get_config(json), 'prog.py', epilog="\ntwo\nline", formatter_class=TestHelpFormatter, color=False) f = StringIO() with redirect_stdout(f): parser.print_help() diff --git a/tests/test_leadership.py b/tests/test_leadership.py index 4195b1b..f47baac 100644 --- a/tests/test_leadership.py +++ b/tests/test_leadership.py @@ -78,7 +78,7 @@ leader: --leader.follower_mandatory INDEX FOLLOWER_MANDATORY Follower mandatory """ - parser = TiramisuCmdlineParser(get_config(json, with_mandatory=True), 'prog.py', formatter_class=TestHelpFormatter) + parser = TiramisuCmdlineParser(get_config(json, with_mandatory=True), 'prog.py', formatter_class=TestHelpFormatter, color=False) f = StringIO() with redirect_stdout(f): parser.print_help() @@ -107,7 +107,7 @@ leader: --leader.follower_mandatory INDEX FOLLOWER_MANDATORY Follower mandatory """ - parser = TiramisuCmdlineParser(get_config(json, with_mandatory=True), 'prog.py', add_extra_options=False, formatter_class=TestHelpFormatter) + parser = TiramisuCmdlineParser(get_config(json, with_mandatory=True), 'prog.py', add_extra_options=False, formatter_class=TestHelpFormatter, color=False) f = StringIO() with redirect_stdout(f): parser.print_help() @@ -124,7 +124,7 @@ leader: -l, --leader.leader [LEADER ...] Leader var """ - parser = TiramisuCmdlineParser(get_config(json, with_mandatory=True, with_symlink=True, with_default_value=False), 'prog.py', add_extra_options=False, formatter_class=TestHelpFormatter) + parser = TiramisuCmdlineParser(get_config(json, with_mandatory=True, with_symlink=True, with_default_value=False), 'prog.py', add_extra_options=False, formatter_class=TestHelpFormatter, color=False) f = StringIO() with redirect_stdout(f): parser.print_help() @@ -153,7 +153,7 @@ leader: --leader.follower_mandatory INDEX FOLLOWER_MANDATORY Follower mandatory """ - parser = TiramisuCmdlineParser(get_config(json, with_mandatory=True, with_symlink=True), 'prog.py', add_extra_options=False, formatter_class=TestHelpFormatter) + parser = TiramisuCmdlineParser(get_config(json, with_mandatory=True, with_symlink=True), 'prog.py', add_extra_options=False, formatter_class=TestHelpFormatter, color=False) f = StringIO() with redirect_stdout(f): parser.print_help() @@ -194,7 +194,7 @@ prog.py: error: unrecognized arguments: 255.255.255.0 """ config = get_config(json) - parser = TiramisuCmdlineParser(config, 'prog.py', formatter_class=TestHelpFormatter) + parser = TiramisuCmdlineParser(config, 'prog.py', formatter_class=TestHelpFormatter, color=False) f = StringIO() with redirect_stderr(f): try: @@ -309,7 +309,7 @@ def test_leadership_modif_follower_choice_unknown(json): 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) + parser = TiramisuCmdlineParser(config, 'prog.py', formatter_class=TestHelpFormatter, color=False) f = StringIO() with redirect_stderr(f): try: @@ -327,7 +327,7 @@ prog.py: error: index must be a number, not a """ config = get_config(json) - parser = TiramisuCmdlineParser(config, 'prog.py', formatter_class=TestHelpFormatter) + parser = TiramisuCmdlineParser(config, 'prog.py', formatter_class=TestHelpFormatter, color=False) f = StringIO() with redirect_stderr(f): try: @@ -384,7 +384,7 @@ def test_leadership_modif_mandatory(json): prog.py: error: the following arguments are required: --leader.follower_submulti""" config = get_config(json, with_mandatory=True) - parser = TiramisuCmdlineParser(config, 'prog.py', formatter_class=TestHelpFormatter) + parser = TiramisuCmdlineParser(config, 'prog.py', formatter_class=TestHelpFormatter, color=False) f = StringIO() with redirect_stderr(f): try: @@ -422,7 +422,7 @@ def test_leadership_modif_mandatory_remove(json): prog.py: error: the following arguments are required: --leader.follower_submulti""" config = get_config(json, with_mandatory=True) - parser = TiramisuCmdlineParser(config, 'prog.py', display_modified_value=False, formatter_class=TestHelpFormatter) + parser = TiramisuCmdlineParser(config, 'prog.py', display_modified_value=False, formatter_class=TestHelpFormatter, color=False) f = StringIO() with redirect_stderr(f): try: diff --git a/tests/test_readme.py b/tests/test_readme.py index 8a005b3..848220d 100644 --- a/tests/test_readme.py +++ b/tests/test_readme.py @@ -99,7 +99,7 @@ options: -v, --verbosity increase output verbosity (default: False) -nv, --no-verbosity """ - parser = TiramisuCmdlineParser(get_config(json), 'prog.py', formatter_class=TestHelpFormatter) + parser = TiramisuCmdlineParser(get_config(json), 'prog.py', formatter_class=TestHelpFormatter, color=False) f = StringIO() with redirect_stdout(f): parser.print_help() @@ -117,7 +117,7 @@ root: -v, --root.verbosity increase output verbosity (default: False) -nv, --root.no-verbosity """ - parser = TiramisuCmdlineParser(get_config(json, True), 'prog.py', formatter_class=TestHelpFormatter) + parser = TiramisuCmdlineParser(get_config(json, True), 'prog.py', formatter_class=TestHelpFormatter, color=False) f = StringIO() with redirect_stdout(f): parser.print_help() @@ -135,7 +135,7 @@ root: -v, --verbosity increase output verbosity (default: False) -nv, --no-verbosity """ - parser = TiramisuCmdlineParser(get_config(json, True), 'prog.py', fullpath=False, formatter_class=TestHelpFormatter) + parser = TiramisuCmdlineParser(get_config(json, True), 'prog.py', fullpath=False, formatter_class=TestHelpFormatter, color=False) f = StringIO() with redirect_stdout(f): parser.print_help() @@ -154,7 +154,7 @@ options: -nv, --no-verbosity --str STR string option """ - parser = TiramisuCmdlineParser(get_config(json), 'prog.py', formatter_class=TestHelpFormatter) + parser = TiramisuCmdlineParser(get_config(json), 'prog.py', formatter_class=TestHelpFormatter, color=False) f = StringIO() with redirect_stdout(f): try: @@ -175,7 +175,7 @@ options: -nv, --no-verbosity --str STR string option """ - parser = TiramisuCmdlineParser(get_config(json), 'prog.py', display_modified_value=False, formatter_class=TestHelpFormatter) + parser = TiramisuCmdlineParser(get_config(json), 'prog.py', display_modified_value=False, formatter_class=TestHelpFormatter, color=False) f = StringIO() with redirect_stdout(f): try: @@ -199,7 +199,7 @@ options: -nv, --no-verbosity --str STR string option """ - parser = TiramisuCmdlineParser(get_config(json), 'prog.py', formatter_class=TestHelpFormatter) + parser = TiramisuCmdlineParser(get_config(json), 'prog.py', formatter_class=TestHelpFormatter, color=False) f = StringIO() with redirect_stdout(f): try: @@ -219,7 +219,7 @@ options: -v, --verbosity increase output verbosity (default: False) -nv, --no-verbosity """ - parser = TiramisuCmdlineParser(get_config(json), 'prog.py', display_modified_value=False, formatter_class=TestHelpFormatter) + parser = TiramisuCmdlineParser(get_config(json), 'prog.py', display_modified_value=False, formatter_class=TestHelpFormatter, color=False) f = StringIO() with redirect_stdout(f): try: @@ -243,7 +243,7 @@ options: -nv, --no-verbosity --str STR string option """ - parser = TiramisuCmdlineParser(get_config(json), 'prog.py', formatter_class=TestHelpFormatter) + parser = TiramisuCmdlineParser(get_config(json), 'prog.py', formatter_class=TestHelpFormatter, color=False) f = StringIO() with redirect_stdout(f): try: @@ -264,7 +264,7 @@ options: -nv, --no-verbosity increase output verbosity (default: False) --str STR string option """ - parser = TiramisuCmdlineParser(get_config(json), 'prog.py', display_modified_value=False, formatter_class=TestHelpFormatter) + parser = TiramisuCmdlineParser(get_config(json), 'prog.py', display_modified_value=False, formatter_class=TestHelpFormatter, color=False) f = StringIO() with redirect_stdout(f): try: @@ -288,7 +288,7 @@ options: -nv, --no-verbosity --str STR string option """ - parser = TiramisuCmdlineParser(get_config(json), 'prog.py', formatter_class=TestHelpFormatter) + parser = TiramisuCmdlineParser(get_config(json), 'prog.py', formatter_class=TestHelpFormatter, color=False) f = StringIO() with redirect_stdout(f): try: @@ -308,7 +308,7 @@ options: -v, --verbosity increase output verbosity (default: False) --str STR string option """ - parser = TiramisuCmdlineParser(get_config(json), 'prog.py', display_modified_value=False, formatter_class=TestHelpFormatter) + parser = TiramisuCmdlineParser(get_config(json), 'prog.py', display_modified_value=False, formatter_class=TestHelpFormatter, color=False) f = StringIO() with redirect_stdout(f): try: @@ -324,7 +324,7 @@ def test_readme_positional_mandatory(json): output = """usage: prog.py [-h] [-v] [-nv] {str,list,int,none} prog.py: error: the following arguments are required: cmd """ - parser = TiramisuCmdlineParser(get_config(json), 'prog.py', formatter_class=TestHelpFormatter) + parser = TiramisuCmdlineParser(get_config(json), 'prog.py', formatter_class=TestHelpFormatter, color=False) f = StringIO() with redirect_stderr(f): try: @@ -340,7 +340,7 @@ def test_readme_positional_mandatory_tree(json): output = """usage: prog.py [-h] [-v] [-nv] {str,list,int,none} prog.py: error: the following arguments are required: root.cmd """ - parser = TiramisuCmdlineParser(get_config(json, True), 'prog.py', formatter_class=TestHelpFormatter) + parser = TiramisuCmdlineParser(get_config(json, True), 'prog.py', formatter_class=TestHelpFormatter, color=False) f = StringIO() with redirect_stderr(f): try: @@ -356,7 +356,7 @@ def test_readme_positional_mandatory_tree_flatten(json): output = """usage: prog.py [-h] [-v] [-nv] {str,list,int,none} prog.py: error: the following arguments are required: cmd """ - parser = TiramisuCmdlineParser(get_config(json, True), 'prog.py', fullpath=False, formatter_class=TestHelpFormatter) + parser = TiramisuCmdlineParser(get_config(json, True), 'prog.py', fullpath=False, formatter_class=TestHelpFormatter, color=False) f = StringIO() with redirect_stderr(f): try: @@ -372,7 +372,7 @@ def test_readme_mandatory(json): output = """usage: prog.py "str" [-h] [-v] [-nv] --str STR {str,list,int,none} prog.py: error: the following arguments are required: --str """ - parser = TiramisuCmdlineParser(get_config(json), 'prog.py', formatter_class=TestHelpFormatter) + parser = TiramisuCmdlineParser(get_config(json), 'prog.py', formatter_class=TestHelpFormatter, color=False) f = StringIO() with redirect_stderr(f): try: @@ -388,7 +388,7 @@ def test_readme_mandatory_remove(json): output = """usage: prog.py "str" [-h] [-v] [-nv] --str STR prog.py: error: the following arguments are required: --str """ - parser = TiramisuCmdlineParser(get_config(json), 'prog.py', display_modified_value=False, formatter_class=TestHelpFormatter) + parser = TiramisuCmdlineParser(get_config(json), 'prog.py', display_modified_value=False, formatter_class=TestHelpFormatter, color=False) f = StringIO() with redirect_stderr(f): try: @@ -404,7 +404,7 @@ def test_readme_mandatory_tree(json): output = """usage: prog.py "str" [-h] [-v] [-nv] --root.str STR {str,list,int,none} prog.py: error: the following arguments are required: --root.str """ - parser = TiramisuCmdlineParser(get_config(json, True), 'prog.py', formatter_class=TestHelpFormatter) + parser = TiramisuCmdlineParser(get_config(json, True), 'prog.py', formatter_class=TestHelpFormatter, color=False) f = StringIO() with redirect_stderr(f): try: @@ -420,7 +420,7 @@ def test_readme_mandatory_tree_remove(json): output = """usage: prog.py "str" [-h] [-v] [-nv] --root.str STR prog.py: error: the following arguments are required: --root.str """ - parser = TiramisuCmdlineParser(get_config(json, True), 'prog.py', display_modified_value=False, formatter_class=TestHelpFormatter) + parser = TiramisuCmdlineParser(get_config(json, True), 'prog.py', display_modified_value=False, formatter_class=TestHelpFormatter, color=False) f = StringIO() with redirect_stderr(f): try: @@ -436,7 +436,7 @@ def test_readme_mandatory_tree_flatten(json): output = """usage: prog.py "str" [-h] [-v] [-nv] --str STR {str,list,int,none} prog.py: error: the following arguments are required: --str """ - parser = TiramisuCmdlineParser(get_config(json, True), 'prog.py', fullpath=False, formatter_class=TestHelpFormatter) + parser = TiramisuCmdlineParser(get_config(json, True), 'prog.py', fullpath=False, formatter_class=TestHelpFormatter, color=False) f = StringIO() with redirect_stderr(f): try: @@ -452,7 +452,7 @@ def test_readme_mandatory_tree_flatten_remove(json): output = """usage: prog.py "str" [-h] [-v] [-nv] --str STR prog.py: error: the following arguments are required: --str """ - parser = TiramisuCmdlineParser(get_config(json, True), 'prog.py', fullpath=False, display_modified_value=False, formatter_class=TestHelpFormatter) + parser = TiramisuCmdlineParser(get_config(json, True), 'prog.py', fullpath=False, display_modified_value=False, formatter_class=TestHelpFormatter, color=False) f = StringIO() with redirect_stderr(f): try: @@ -468,7 +468,7 @@ def test_readme_cross(json): output = """usage: prog.py "none" [-h] [-v] [-nv] {str,list,int,none} prog.py: error: unrecognized arguments: --int (cannot access to option "int option" because has property "disabled") """ - parser = TiramisuCmdlineParser(get_config(json), 'prog.py', formatter_class=TestHelpFormatter) + parser = TiramisuCmdlineParser(get_config(json), 'prog.py', formatter_class=TestHelpFormatter, color=False) f = StringIO() with redirect_stderr(f): try: @@ -484,7 +484,7 @@ def test_readme_cross_remove(json): output = """usage: prog.py "none" [-h] [-v] [-nv] prog.py: error: unrecognized arguments: --int (cannot access to option "int option" because has property "disabled") """ - parser = TiramisuCmdlineParser(get_config(json), 'prog.py', display_modified_value=False, formatter_class=TestHelpFormatter) + parser = TiramisuCmdlineParser(get_config(json), 'prog.py', display_modified_value=False, formatter_class=TestHelpFormatter, color=False) f = StringIO() with redirect_stderr(f): try: @@ -500,7 +500,7 @@ def test_readme_cross_tree(json): output = """usage: prog.py "none" [-h] [-v] [-nv] {str,list,int,none} prog.py: error: unrecognized arguments: --root.int (cannot access to option "int option" because has property "disabled") """ - parser = TiramisuCmdlineParser(get_config(json, True), 'prog.py', formatter_class=TestHelpFormatter) + parser = TiramisuCmdlineParser(get_config(json, True), 'prog.py', formatter_class=TestHelpFormatter, color=False) f = StringIO() with redirect_stderr(f): try: @@ -516,7 +516,7 @@ def test_readme_cross_tree_remove(json): output = """usage: prog.py "none" [-h] [-v] [-nv] prog.py: error: unrecognized arguments: --root.int (cannot access to option "int option" because has property "disabled") """ - parser = TiramisuCmdlineParser(get_config(json, True), 'prog.py', display_modified_value=False, formatter_class=TestHelpFormatter) + parser = TiramisuCmdlineParser(get_config(json, True), 'prog.py', display_modified_value=False, formatter_class=TestHelpFormatter, color=False) f = StringIO() with redirect_stderr(f): try: @@ -532,7 +532,7 @@ def test_readme_cross_tree_flatten(json): output = """usage: prog.py "none" [-h] [-v] [-nv] {str,list,int,none} prog.py: error: unrecognized arguments: --int (cannot access to option "int option" because has property "disabled") """ - parser = TiramisuCmdlineParser(get_config(json, True), 'prog.py', fullpath=False, formatter_class=TestHelpFormatter) + parser = TiramisuCmdlineParser(get_config(json, True), 'prog.py', fullpath=False, formatter_class=TestHelpFormatter, color=False) f = StringIO() with redirect_stderr(f): try: @@ -548,7 +548,7 @@ def test_readme_cross_tree_flatten_remove(json): output = """usage: prog.py "none" [-h] [-v] [-nv] prog.py: error: unrecognized arguments: --int (cannot access to option "int option" because has property "disabled") """ - parser = TiramisuCmdlineParser(get_config(json, True), 'prog.py', fullpath=False, display_modified_value=False, formatter_class=TestHelpFormatter) + parser = TiramisuCmdlineParser(get_config(json, True), 'prog.py', fullpath=False, display_modified_value=False, formatter_class=TestHelpFormatter, color=False) f = StringIO() with redirect_stderr(f): try: @@ -564,7 +564,7 @@ def test_readme_unknown(json): output = """usage: prog.py [-h] [-v] [-nv] {str,list,int,none} prog.py: error: argument root.cmd: invalid choice: 'unknown' (choose from str, list, int, none) """ - parser = TiramisuCmdlineParser(get_config(json, True), 'prog.py', fullpath=False, formatter_class=TestHelpFormatter) + parser = TiramisuCmdlineParser(get_config(json, True), 'prog.py', fullpath=False, formatter_class=TestHelpFormatter, color=False) f = StringIO() with redirect_stderr(f): try: @@ -879,7 +879,7 @@ prog.py: error: unrecognized arguments: --unknown output2 = """usage: prog.py "list" -v --list "a" [-h] [-v] [-nv] --list LIST [LIST ...] {str,list,int,none} prog.py: error: unrecognized arguments: --root.unknown """ - parser = TiramisuCmdlineParser(get_config(json, True), 'prog.py', fullpath=False, formatter_class=TestHelpFormatter) + parser = TiramisuCmdlineParser(get_config(json, True), 'prog.py', fullpath=False, formatter_class=TestHelpFormatter, color=False) f = StringIO() with redirect_stderr(f): try: diff --git a/tests/test_shortarg.py b/tests/test_shortarg.py index 20a6860..a3ee9ac 100644 --- a/tests/test_shortarg.py +++ b/tests/test_shortarg.py @@ -39,19 +39,19 @@ def test_short(json): # output = {'list': None, 'l': None} config = get_config() - parser = TiramisuCmdlineParser(config, 'prog.py') + parser = TiramisuCmdlineParser(config, 'prog.py', color=False) parser.parse_args([]) assert to_dict(config.value.get()) == output # output = {'list': 'a', 'l': 'a'} config = get_config() - parser = TiramisuCmdlineParser(config, 'prog.py') + parser = TiramisuCmdlineParser(config, 'prog.py', color=False) parser.parse_args(['--list', 'a']) assert to_dict(config.value.get()) == output # output = {'list': 'a', 'l': 'a'} config = get_config() - parser = TiramisuCmdlineParser(config, 'prog.py') + parser = TiramisuCmdlineParser(config, 'prog.py', color=False) parser.parse_args(['-l', 'a']) assert to_dict(config.value.get()) == output # @@ -81,7 +81,7 @@ def test_short_mandatory(json): prog.py: error: the following arguments are required: --list """ config = get_config() - parser = TiramisuCmdlineParser(config, 'prog.py') + parser = TiramisuCmdlineParser(config, 'prog.py', color=False) f = StringIO() with redirect_stderr(f): try: @@ -94,13 +94,13 @@ prog.py: error: the following arguments are required: --list # output = {'list': 'a', 'l': 'a'} config = get_config() - parser = TiramisuCmdlineParser(config, 'prog.py') + parser = TiramisuCmdlineParser(config, 'prog.py', color=False) parser.parse_args(['--list', 'a']) assert to_dict(config.value.get()) == output # output = {'list': 'a', 'l': 'a'} config = get_config() - parser = TiramisuCmdlineParser(config, 'prog.py') + parser = TiramisuCmdlineParser(config, 'prog.py', color=False) parser.parse_args(['-l', 'a']) assert to_dict(config.value.get()) == output @@ -124,31 +124,31 @@ def test_short_multi(json): # output = {'list': [], 'l': []} config = get_config() - parser = TiramisuCmdlineParser(config, 'prog.py') + parser = TiramisuCmdlineParser(config, 'prog.py', color=False) parser.parse_args([]) assert to_dict(config.value.get()) == output # output = {'list': ['a'], 'l': ['a']} config = get_config() - parser = TiramisuCmdlineParser(config, 'prog.py') + parser = TiramisuCmdlineParser(config, 'prog.py', color=False) parser.parse_args(['--list', 'a']) assert to_dict(config.value.get()) == output # output = {'list': ['a', 'b'], 'l': ['a', 'b']} config = get_config() - parser = TiramisuCmdlineParser(config, 'prog.py') + parser = TiramisuCmdlineParser(config, 'prog.py', color=False) parser.parse_args(['--list', 'a', 'b']) assert to_dict(config.value.get()) == output # output = {'list': ['a'], 'l': ['a']} config = get_config() - parser = TiramisuCmdlineParser(config, 'prog.py') + parser = TiramisuCmdlineParser(config, 'prog.py', color=False) parser.parse_args(['-l', 'a']) assert to_dict(config.value.get()) == output # output = {'list': ['a', 'b'], 'l': ['a', 'b']} config = get_config() - parser = TiramisuCmdlineParser(config, 'prog.py') + parser = TiramisuCmdlineParser(config, 'prog.py', color=False) parser.parse_args(['-l', 'a', 'b']) assert to_dict(config.value.get()) == output @@ -175,7 +175,7 @@ def test_short_multi_mandatory(json): prog.py: error: the following arguments are required: --list """ config = get_config() - parser = TiramisuCmdlineParser(config, 'prog.py') + parser = TiramisuCmdlineParser(config, 'prog.py', color=False) f = StringIO() with redirect_stderr(f): try: @@ -188,24 +188,24 @@ prog.py: error: the following arguments are required: --list # output = {'list': ['a'], 'l': ['a']} config = get_config() - parser = TiramisuCmdlineParser(config, 'prog.py') + parser = TiramisuCmdlineParser(config, 'prog.py', color=False) parser.parse_args(['--list', 'a']) assert to_dict(config.value.get()) == output # output = {'list': ['a', 'b'], 'l': ['a', 'b']} config = get_config() - parser = TiramisuCmdlineParser(config, 'prog.py') + parser = TiramisuCmdlineParser(config, 'prog.py', color=False) parser.parse_args(['--list', 'a', 'b']) assert to_dict(config.value.get()) == output # output = {'list': ['a'], 'l': ['a']} config = get_config() - parser = TiramisuCmdlineParser(config, 'prog.py') + parser = TiramisuCmdlineParser(config, 'prog.py', color=False) parser.parse_args(['-l', 'a']) assert to_dict(config.value.get()) == output # output = {'list': ['a', 'b'], 'l': ['a', 'b']} config = get_config() - parser = TiramisuCmdlineParser(config, 'prog.py') + parser = TiramisuCmdlineParser(config, 'prog.py', color=False) parser.parse_args(['-l', 'a', 'b']) assert to_dict(config.value.get()) == output diff --git a/tiramisu_cmdline_parser/__init__.py b/tiramisu_cmdline_parser/__init__.py index a243da6..a417fa6 100644 --- a/tiramisu_cmdline_parser/__init__.py +++ b/tiramisu_cmdline_parser/__init__.py @@ -1,4 +1,4 @@ -# Copyright (C) 2018-2019 Team tiramisu (see AUTHORS for all contributors) +# Copyright (C) 2018-2026 Team tiramisu (see AUTHORS for all contributors) # # This program is free software: you can redistribute it and/or modify it # under the terms of the GNU Lesser General Public License as published by the diff --git a/tiramisu_cmdline_parser/api.py b/tiramisu_cmdline_parser/api.py index e8b8cf2..e3f61b5 100644 --- a/tiramisu_cmdline_parser/api.py +++ b/tiramisu_cmdline_parser/api.py @@ -27,7 +27,7 @@ from gettext import gettext as _ # try: from tiramisu import Config -from tiramisu.error import PropertiesOptionError, LeadershipError, ConfigError +from tiramisu.error import PropertiesOptionError, LeadershipError, ConfigError, AttributeOptionError def get_choice_list(config, properties, display): @@ -110,6 +110,12 @@ class TiramisuNamespace(Namespace): else: true_key = key option = self._config.option(true_key) + try: + option.get() + except AttributeOptionError: + # We are in this case when we call a parent ArgumentParser not present in current config + # it's useful to dispatch attribute in differents configs + return if option.isfollower(): _setattr = self._setattr_follower index = value[0] @@ -337,6 +343,7 @@ class TiramisuCmdlineParser(ArgumentParser): self.display_modified_value = display_modified_value self.short_name_max_len = short_name_max_len self.add_help = add_help + self.kwargs = kwargs.copy() if TiramisuHelpFormatter not in formatter_class.__mro__: formatter_class = type( "TiramisuHelpFormatter", (TiramisuHelpFormatter, formatter_class), {} @@ -395,6 +402,10 @@ class TiramisuCmdlineParser(ArgumentParser): except (ValueError, LeadershipError, AttributeError) as err: self.error(err) if args != args_ and args_ and args_[0].startswith(self.prefix_chars): + kwargs = self.kwargs + if "epilog" in kwargs: + kwargs = kwargs.copy() + del kwargs["epilog"] # option that was disabled are no more disable # so create a new parser new_parser = TiramisuCmdlineParser( @@ -412,6 +423,7 @@ class TiramisuCmdlineParser(ArgumentParser): short_name_max_len=self.short_name_max_len, fullpath=self.fullpath, add_help=self.add_help, + **kwargs, ) namespace_, args_ = new_parser._parse_known_args( args_, new_parser.namespace, *others @@ -694,15 +706,22 @@ class TiramisuCmdlineParser(ArgumentParser): args, kwargs = value.get() group.add_argument(*args, **kwargs) - # def _valid_mandatory(self): - # pass - # def parse_args(self, *args, valid_mandatory=True, **kwargs): + namespaces, unknown = self.parse_known_args(*args, valid_mandatory=valid_mandatory, **kwargs) + if unknown: + msg_unknown = 'unrecognized arguments: %s' % ' '.join(unknown) + if self.exit_on_error: + self.error(msg_unknown) + else: + err = ArgumentError(None, msg_unknown) + err.unknown = unknown + raise err + return namespaces + + def parse_known_args(self, *args, valid_mandatory=True, **kwargs): kwargs["namespace"] = self.namespace try: 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() @@ -745,16 +764,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 + return namespaces, unknown def format_usage(self, *args, **kwargs): + kwargs_ = self.kwargs + if "epilog" in kwargs_: + kwargs_ = kwargs_.copy() + del kwargs_["epilog"] help_formatter = TiramisuCmdlineParser( self.config, self.prog, @@ -768,12 +784,17 @@ class TiramisuCmdlineParser(ArgumentParser): epilog=self.epilog, description=self.description, _forhelp=True, + **kwargs_, ) return super(TiramisuCmdlineParser, help_formatter).format_usage( *args, **kwargs ) def format_help(self): + kwargs = self.kwargs + if "epilog" in kwargs: + kwargs = kwargs.copy() + del kwargs["epilog"] help_formatter = TiramisuCmdlineParser( self.config, self.prog, @@ -787,6 +808,7 @@ class TiramisuCmdlineParser(ArgumentParser): epilog=self.epilog, description=self.description, _forhelp=True, + **kwargs, ) return super(TiramisuCmdlineParser, help_formatter).format_help()