def test_int_type_remainder(): definition = { 'arguments': [{ 'names': ['--arg'], 'nargs': sargeparse.remainder, 'default': [100, 200], 'type': int, }], } parser = sargeparse.Sarge(definition) sys.argv = shlex.split('test --arg 10 20') args = parser.parse() assert args == ChainMap( {}, { 'arg': [10, 20], }, {}, {}, {}, { 'arg': sargeparse.unset, }, ) sys.argv = shlex.split('test') args = parser.parse() assert args == ChainMap( {}, {}, {}, {}, { 'arg': [100, 200], }, { 'arg': sargeparse.unset, }, )
def test_help_subcommand_when_disabled(capsys): parser = sargeparse.Sarge({ 'help_subcommand': False, 'subcommands': [ { 'name': 'sub', 'help': 'SUBC', }, ], }) with pytest.raises(SystemExit) as ex: sys.argv = shlex.split('test help') parser.parse() assert ex.value.code == 2 captured = capsys.readouterr() assert "invalid choice: 'help'" in captured.err
def test_print_help_and_exit_if_last(capsys): parser = sargeparse.Sarge({ 'print_help_and_exit_if_last': True, 'subcommands': [{ 'name': 'sub2', 'print_help_and_exit_if_last': False, 'subcommands': [{ 'name': 'sub3', 'print_help_and_exit_if_last': True, }] }] }) with pytest.raises(SystemExit) as ex: sys.argv = shlex.split('test sub2 sub3') args = parser.parse() args.dispatch() assert ex.value.code == 0 captured = capsys.readouterr() assert re.search(r'\s*usage:\s+test sub2 sub3.*$', captured.err, re.MULTILINE) # Shouldn't exit even though no callback was added sys.argv = shlex.split('test sub2') args = parser.parse() args.dispatch() with pytest.raises(SystemExit) as ex: sys.argv = shlex.split('test') args = parser.parse() args.dispatch() assert ex.value.code == 0 captured = capsys.readouterr() assert re.search(r'\s*usage:\s+test.*$', captured.err, re.MULTILINE)
def test_help_subcommand(capsys): parser = sargeparse.Sarge({ 'subcommands': [ { 'name': 'sub1', 'help': 'SUBC1', 'add_usage_to_parent_command_desc': True, 'arguments': [ { 'names': ['-a1'] }, { 'names': ['b1'] }, ] }, { 'name': 'sub2', 'help': 'SUBC2', 'add_usage_to_parent_command_desc': True, 'arguments': [ { 'names': ['-a2'] }, { 'names': ['b2'] }, ] }, { 'name': 'sub3', 'help': 'SUBC3', 'arguments': [ { 'names': ['-a3'] }, { 'names': ['b3'] }, ] }, ], }) with pytest.raises(SystemExit) as ex: sys.argv = shlex.split('test help') parser.parse() assert ex.value.code == 0 captured = capsys.readouterr() assert re.search(r'^\s*test\s+sub1\s*\[\s*-a1\s+A1\s*\].+?b1$', captured.out, re.MULTILINE) assert re.search(r'^\s*test\s+sub2\s*\[\s*-a2\s+A2\s*\].+?b2$', captured.out, re.MULTILINE) assert not re.search(r'^\s*test\s+sub3\s*\[\s*-a2\s+A3\s*\].+?b3$', captured.out, re.MULTILINE) assert re.search(r'^\s*sub1\s+SUBC1', captured.out, re.MULTILINE) assert re.search(r'^\s*sub2\s+SUBC2', captured.out, re.MULTILINE) assert re.search(r'^\s*sub3\s+SUBC3', captured.out, re.MULTILINE)
def test_show_default_and_help(capsys): class CustomObject: def __init__(self, value): self.value = value def __repr__(self): return '<CustomObject {}>'.format(self.value) def __str__(self): return 'custom_object -> {}'.format(self.value) def __eq__(self, other): if isinstance(other, CustomObject): return self.value == other.value return super().__eq__(other) parser = sargeparse.Sarge({ 'arguments': [ { 'names': ['--arg1'], 'default': 1, 'type': str, 'show_default': True, }, { 'names': ['--arg2'], 'default': '2', 'type': int, 'show_default': True, }, { 'names': ['--arg3'], 'default': '3', 'help': None, 'show_default': True, }, { 'names': ['--arg4'], 'default': 4, 'help': '', 'show_default': True, }, { 'names': ['--arg5'], 'default': 5, 'help': sargeparse.suppress, 'show_default': True, }, { 'names': ['--arg6'], 'default': 6, 'help': None, 'type': CustomObject, 'show_default': True, }, { 'names': ['--arg7'], 'default': CustomObject(7), 'type': repr, 'help': None, 'show_default': True, }, ], }) with pytest.raises(SystemExit) as ex: sys.argv = shlex.split('test -h') parser.parse() assert ex.value.code == 0 captured = capsys.readouterr() assert re.search(r'^ +--arg1.*(?<=WARNING).*(default: 1)', captured.out, re.MULTILINE) assert re.search(r'^ +--arg2.*(?<=WARNING).*(default: 2)', captured.out, re.MULTILINE) assert re.search(r'^ +--arg3.*(?<!WARNING).*(default: 3)', captured.out, re.MULTILINE) assert re.search(r'^ +--arg4.*(?<!WARNING).*(default: 4)', captured.out, re.MULTILINE) assert re.search(r'^ +--arg5', captured.out, re.MULTILINE) is None assert re.search(r'^ +--arg6.*(default: 6)', captured.out, re.MULTILINE) assert re.search(r'^ +--arg7.*(default: custom_object -> 7)', captured.out, re.MULTILINE) sys.argv = shlex.split('test') args = parser.parse() assert args == ChainMap( {}, {}, {}, {}, { 'arg1': '1', 'arg2': 2, 'arg3': '3', 'arg4': 4, 'arg5': 5, 'arg6': CustomObject(6), 'arg7': '<CustomObject 7>', }, { 'arg1': sargeparse.unset, 'arg2': sargeparse.unset, 'arg3': sargeparse.unset, 'arg4': sargeparse.unset, 'arg5': sargeparse.unset, 'arg6': sargeparse.unset, 'arg7': sargeparse.unset, }, )
def test_envvar_default_config_same_name_many_subcommands(): parser = sargeparse.Sarge({}) parser.add_subcommands( { 'name': 'suba', 'arguments': [ { 'names': ['--arg1'], 'envvar': 'VARA', }, { 'names': ['--arg2'], 'default': '2A', }, { 'names': ['--arg3'], 'config_path': 'confA', }, ], }, { 'name': 'subb', 'arguments': [ { 'names': ['--arg1'], 'envvar': 'VARB', }, { 'names': ['--arg2'], 'default': '2B', }, { 'names': ['--arg3'], 'config_path': 'confB', }, ], }) def get_config(_args): return { 'confA': '3A', 'confB': '3B', } argv = shlex.split('suba') os.environ['VARA'] = '1A' os.environ['VARB'] = '1B' args = parser.parse(argv=argv, read_config=get_config) assert args == ChainMap({}, {}, { 'arg1': '1A', }, { 'arg3': '3A', }, { 'arg2': '2A', }, { 'arg1': sargeparse.unset, 'arg2': sargeparse.unset, })
def test_full_ok(caplog): def fn_main(): pass def fn_run(): pass def fn_subc(): pass parser = sargeparse.Sarge({ 'description': 'MAIN_DESCRIPTION', 'epilog': 'MAIN_EPILOG', 'callback': fn_main, 'arguments': [ { 'names': ['--debug'], 'action': 'store_true', 'default': False, 'global': True, 'envvar': 'DEBUG', 'config_path': 'path_doesnt_exists_but_thats_ok', }, { 'names': ['-x'], 'action': 'store_true', 'default': False, 'mutex_group': 1, 'required': False, 'group': 'X or Y', }, { 'names': ['-y'], 'help': 'Yes!', 'action': 'store_true', 'default': False, 'mutex_group': 1, 'required': False, 'group': 'X or Y', }, ], 'group_descriptions': { 'X or Y': 'just a mutex group', }, 'defaults': { 'extra': 'EXTRA_ARG', } }) parser.add_defaults({ 'extra2': 'EXTRA_ARG2', }) parser.add_arguments( { 'names': ['-a', '--arg'], 'help': 'ARG_HELP', 'config_path': ['args', 'arg'], 'default': 'argdef', }, { 'names': ['-b', '--barg'], 'help': 'BARG_HELP', 'default': 'bargdef', 'config_path': 'args/barg', }) parser.add_subcommands({ 'name': 'run', 'help': 'just a subcommand', 'callback': fn_run, 'arguments': [{ 'names': ['--flag'], 'default': 'flagdef', }, { 'names': ['--boss'], 'help': "Who's the boss?", 'envvar': 'BOSS', 'config_path': 'boss', }], }) subc = sargeparse.SubCommand({ 'name': 'subc', 'callback': fn_subc, }) parser.add_subcommand(subc) def get_config(_args): return { 'boss': 'configboss', 'args': { 'arg': 'configarg', 'barg': 'configbarg', } } sys.argv = shlex.split('test -y run --flag "flag cli"') os.environ['BOSS'] = 'ENVBOSS' args = parser.parse(read_config=get_config) assert args.callbacks == [fn_main, fn_run] assert args == ChainMap({}, { 'flag': 'flag cli', 'y': True, }, { 'boss': 'ENVBOSS', }, { 'arg': 'configarg', 'barg': 'configbarg', 'boss': 'configboss', }, { 'arg': 'argdef', 'barg': 'bargdef', 'debug': False, 'extra': 'EXTRA_ARG', 'extra2': 'EXTRA_ARG2', 'flag': 'flagdef', 'x': False, 'y': False, }, { 'arg': sargeparse.unset, 'barg': sargeparse.unset, 'boss': sargeparse.unset, 'debug': sargeparse.unset, 'flag': sargeparse.unset, 'x': sargeparse.unset, 'y': sargeparse.unset, }) for param in ['debug', 'x', 'flag']: assert "Missing 'help' in {}".format(param) in caplog.text sys.argv = shlex.split('test subc') args = parser.parse() assert args.callbacks == [fn_main, fn_subc]