def test_add_function_arguments(self): def func(a1='1', a2: float = 2.0, a3: bool = False, a4=None): """func short description Args: a1: a1 description a2: a2 description a4: a4 description """ return a1 parser = ArgumentParser() parser.add_function_arguments(func) self.assertRaises(ValueError, lambda: parser.add_function_arguments('func')) self.assertIn('func', parser.groups) for key in ['a1', 'a2', 'a3']: self.assertIsNotNone(_find_action(parser, key), key + ' should be in parser but is not') self.assertIsNone(_find_action(parser, 'a4'), 'a4 should not be in parser but is') cfg = namespace_to_dict(parser.parse_args(['--a1=x'], with_meta=False)) self.assertEqual(cfg, {'a1': 'x', 'a2': 2.0, 'a3': False}) self.assertEqual('x', func(**cfg)) if docstring_parser_support: self.assertEqual('func short description', parser.groups['func'].title) for key in ['a1', 'a2']: self.assertEqual(key + ' description', _find_action(parser, key).help)
def test_skip(self): def func(a1='1', a2: float = 2.0, a3: bool = False, a4: int = 4): return a1 parser = ArgumentParser() parser.add_function_arguments(func, skip={'a2', 'a4'}) for key in ['a1', 'a3']: self.assertIsNotNone(_find_action(parser, key), key + ' should be in parser but is not') for key in ['a2', 'a4']: self.assertIsNone(_find_action(parser, key), key + ' should not be in parser but is')
def test_add_method_arguments(self): class MyClass: def mymethod(self, a1='1', a2: float = 2.0, a3: bool = False, a4=None): """mymethod short description Args: a1: a1 description a2: a2 description a4: a4 description """ return a1 @staticmethod def mystaticmethod(a1: str, a2: float = 2.0, a3=None): return a1 parser = ArgumentParser() parser.add_method_arguments(MyClass, 'mymethod', 'm') parser.add_method_arguments(MyClass, 'mystaticmethod', 's') self.assertRaises( ValueError, lambda: parser.add_method_arguments('MyClass', 'mymethod')) self.assertRaises( ValueError, lambda: parser.add_method_arguments(MyClass, 'mymethod3')) self.assertIn('m', parser.groups) self.assertIn('s', parser.groups) for key in ['m.a1', 'm.a2', 'm.a3', 's.a1', 's.a2']: self.assertIsNotNone(_find_action(parser, key), key + ' should be in parser but is not') for key in ['m.a4', 's.a3']: self.assertIsNone(_find_action(parser, key), key + ' should not be in parser but is') cfg = namespace_to_dict( parser.parse_args(['--m.a1=x', '--s.a1=y'], with_meta=False)) self.assertEqual(cfg, { 'm': { 'a1': 'x', 'a2': 2.0, 'a3': False }, 's': { 'a1': 'y', 'a2': 2.0 } }) self.assertEqual('x', MyClass().mymethod(**cfg['m'])) self.assertEqual('y', MyClass.mystaticmethod(**cfg['s'])) if docstring_parser_support: self.assertEqual('mymethod short description', parser.groups['m'].title) self.assertEqual(str(MyClass.mystaticmethod), parser.groups['s'].title) for key in ['m.a1', 'm.a2']: self.assertEqual( key.split('.')[1] + ' description', _find_action(parser, key).help) for key in ['m.a3', 's.a1', 's.a2']: self.assertIsNone( _find_action(parser, key).help, 'expected help for ' + key + ' to be None')
def test_add_class_arguments(self): class Class0: def __init__(self, c0_a0: Optional[str] = '0'): pass class Class1(Class0): def __init__(self, c1_a1: str, c1_a2: Any = 2.0, c1_a3=None, c1_a4: int = 4, c1_a5: str = '5'): """Class1 short description Args: c1_a3: c1_a3 description """ super().__init__() self.c1_a1 = c1_a1 def __call__(self): return self.c1_a1 class Class2(Class1): """Class2 short description Args: c1_a2: c1_a2 description """ def __init__(self, c2_a0, c3_a4, *args, **kwargs): super().__init__(c3_a4, *args, **kwargs) class Class3(Class2): def __init__(self, c3_a0: Any, c3_a1='1', c3_a2: float = 2.0, c3_a3: bool = False, c3_a4: Optional[str] = None, c3_a5: Union[int, float, str, List[int], Dict[str, float]] = 5, c3_a6: Optional[Class1] = None, c3_a7: Tuple[str, int, float] = ('7', 7, 7.0), c3_a8: Tuple[str, Class1] = None, c1_a5: str = 'five', **kwargs): """Class3 short description Args: c3_a0: c3_a0 description c3_a1: c3_a1 description c3_a2: c3_a2 description c3_a4: c3_a4 description c3_a5: c3_a5 description """ super().__init__(None, c3_a4, **kwargs) ## Test without nesting ## parser = ArgumentParser(error_handler=None) parser.add_class_arguments(Class3) self.assertRaises(ValueError, lambda: parser.add_class_arguments('Class3')) self.assertIn('Class3', parser.groups) for key in [ 'c3_a0', 'c3_a1', 'c3_a2', 'c3_a3', 'c3_a4', 'c3_a5', 'c3_a6', 'c3_a7', 'c3_a8', 'c1_a2', 'c1_a4', 'c1_a5' ]: self.assertIsNotNone(_find_action(parser, key), key + ' should be in parser but is not') for key in ['c2_a0', 'c1_a1', 'c1_a3', 'c0_a0']: self.assertIsNone(_find_action(parser, key), key + ' should not be in parser but is') cfg = parser.parse_args(['--c3_a0=0', '--c3_a3=true', '--c3_a4=a'], with_meta=False) self.assertEqual( namespace_to_dict(cfg), { 'c1_a2': 2.0, 'c1_a4': 4, 'c1_a5': 'five', 'c3_a0': 0, 'c3_a1': '1', 'c3_a2': 2.0, 'c3_a3': True, 'c3_a4': 'a', 'c3_a5': 5, 'c3_a6': None, 'c3_a7': ('7', 7, 7.0), 'c3_a8': None }) self.assertEqual([1, 2], parser.parse_args(['--c3_a0=0', '--c3_a5=[1,2]']).c3_a5) self.assertEqual({'k': 5.0}, namespace_to_dict( parser.parse_args( ['--c3_a0=0', '--c3_a5={"k": 5.0}']).c3_a5)) self.assertEqual( ('3', 3, 3.0), parser.parse_args(['--c3_a0=0', '--c3_a7=["3", 3, 3.0]']).c3_a7) self.assertEqual('a', Class3(**namespace_to_dict(cfg))()) self.assertRaises(ParserError, lambda: parser.parse_args([])) # c3_a0 is required self.assertRaises(ParserError, lambda: parser.parse_args( ['--c3_a0=0', '--c3_a4=4.0'])) # c3_a4 is str or None self.assertRaises(ParserError, lambda: parser.parse_args( ['--c3_a0=0', '--c3_a7=["3", "3", 3.0]'])) # tuple[1] is int if docstring_parser_support: self.assertEqual('Class3 short description', parser.groups['Class3'].title) for key in ['c3_a0', 'c3_a1', 'c3_a2', 'c3_a4', 'c3_a5', 'c1_a2']: self.assertEqual(key + ' description', _find_action(parser, key).help) for key in ['c3_a3', 'c3_a7', 'c1_a4']: self.assertIsNone( _find_action(parser, key).help, 'expected help for ' + key + ' to be None') ## Test nested and as_group=False ## parser = ArgumentParser() parser.add_class_arguments(Class3, 'g', as_group=False) self.assertNotIn('g', parser.groups) for key in [ 'c3_a0', 'c3_a1', 'c3_a2', 'c3_a3', 'c3_a4', 'c3_a5', 'c3_a6', 'c3_a7', 'c3_a8', 'c1_a2', 'c1_a4', 'c1_a5' ]: self.assertIsNotNone(_find_action(parser, 'g.' + key), key + ' should be in parser but is not') for key in ['c2_a0', 'c1_a1', 'c1_a3', 'c0_a0']: self.assertIsNone(_find_action(parser, 'g.' + key), key + ' should not be in parser but is') ## Test default group title ## parser = ArgumentParser() parser.add_class_arguments(Class0) self.assertEqual(str(Class0), parser.groups['Class0'].title) ## Test positional without type ## self.assertRaises(ValueError, lambda: parser.add_class_arguments(Class2)) ## Test no arguments added ## class NoValidArgs: def __init__(self, a0=None): pass self.assertEqual(0, parser.add_class_arguments(NoValidArgs)) def func(a1: Union[int, Dict[int, int]] = 1): pass parser = ArgumentParser() parser.add_function_arguments(func) parser.get_defaults() cfg = parser.parse_args(['--a1={"2": 7, "4": 9}']) self.assertEqual({ 2: 7, 4: 9 }, parser.parse_args(['--a1={"2": 7, "4": 9}']).a1)