def test_dump_skip_default(self): class MyCalendar(Calendar): def __init__(self, *args, param: str = '0', **kwargs): super().__init__(*args, **kwargs) with mock_module(MyCalendar) as module: parser = ArgumentParser() parser.add_argument('--g1.op1', default=123) parser.add_argument('--g1.op2', default='abc') parser.add_argument('--g2.op1', default=4.5) parser.add_argument('--g2.op2', type=Calendar, default=lazy_instance(Calendar, firstweekday=2)) cfg = parser.get_defaults() dump = parser.dump(cfg, skip_default=True) self.assertEqual(dump, '{}\n') cfg.g2.op2.class_path = f'{module}.MyCalendar' dump = parser.dump(cfg, skip_default=True) self.assertEqual( dump, 'g2:\n op2:\n class_path: jsonargparse_tests.MyCalendar\n init_args:\n firstweekday: 2\n' ) cfg.g2.op2.init_args.firstweekday = 0 dump = parser.dump(cfg, skip_default=True) self.assertEqual( dump, 'g2:\n op2:\n class_path: jsonargparse_tests.MyCalendar\n')
def test_ActionPath_dump(self): parser = ArgumentParser() parser.add_argument('--path', action=ActionPath(mode='fc')) cfg = parser.parse_string('path: path') self.assertEqual(parser.dump(cfg), 'path: path\n') parser = ArgumentParser() parser.add_argument('--paths', nargs='+', action=ActionPath(mode='fc')) cfg = parser.parse_args(['--paths', 'path1', 'path2']) self.assertEqual(parser.dump(cfg), 'paths:\n- path1\n- path2\n')
def test_enum(self): class MyEnum(Enum): A = 1 B = 2 C = 3 parser = ArgumentParser(error_handler=None) parser.add_argument('--enum', type=MyEnum, default=MyEnum.C, help='Description') for val in ['A', 'B', 'C']: self.assertEqual(MyEnum[val], parser.parse_args(['--enum=' + val]).enum) for val in ['X', 'b', 2]: self.assertRaises( ParserError, lambda: parser.parse_args(['--enum=' + str(val)])) cfg = parser.parse_args(['--enum=C'], with_meta=False) self.assertEqual('enum: C\n', parser.dump(cfg)) help_str = StringIO() parser.print_help(help_str) self.assertIn('Description (type: MyEnum, default: C)', help_str.getvalue())
def test_class_type_with_default_config_files(self): config = { 'class_path': 'calendar.Calendar', 'init_args': { 'firstweekday': 3 }, } config_path = os.path.join(self.tmpdir, 'config.yaml') with open(config_path, 'w') as f: json.dump({'data': {'cal': config}}, f) class MyClass: def __init__(self, cal: Optional[Calendar] = None, val: int = 2): self.cal = cal parser = ArgumentParser(error_handler=None, default_config_files=[config_path]) parser.add_argument('--op', default='from default') parser.add_class_arguments(MyClass, 'data') cfg = parser.get_defaults() self.assertEqual(config_path, str(cfg['__default_config__'])) self.assertEqual(cfg.data.cal.as_dict(), config) dump = parser.dump(cfg) self.assertIn('class_path: calendar.Calendar\n', dump) self.assertIn('firstweekday: 3\n', dump) cfg = parser.parse_args([]) self.assertEqual(cfg.data.cal.as_dict(), config) cfg = parser.parse_args(['--data.cal.class_path=calendar.Calendar'], defaults=False) self.assertEqual(cfg.data.cal, Namespace(class_path='calendar.Calendar'))
def test_dict_union(self): class MyEnum(Enum): ab = 1 parser = ArgumentParser(error_handler=None) parser.add_argument('--dict1', type=Dict[int, Optional[Union[float, MyEnum]]]) parser.add_argument('--dict2', type=Dict[str, Union[bool, Path_fc]]) cfg = parser.parse_args( ['--dict1={"2":4.5, "6":"ab"}', '--dict2={"a":true, "b":"f"}']) self.assertEqual({2: 4.5, 6: MyEnum.ab}, cfg['dict1']) self.assertEqual({'a': True, 'b': 'f'}, cfg['dict2']) self.assertIsInstance(cfg['dict2']['b'], Path) self.assertEqual({5: None}, parser.parse_args(['--dict1={"5":null}'])['dict1']) self.assertRaises(ParserError, lambda: parser.parse_args(['--dict1=["a", "b"]'])) cfg = yaml.safe_load(parser.dump(cfg)) self.assertEqual( { 'dict1': { '2': 4.5, '6': 'ab' }, 'dict2': { 'a': True, 'b': 'f' } }, cfg)
def _test_typehint_non_parameterized_types(self, type): parser = ArgumentParser(error_handler=None) ActionTypeHint.is_supported_typehint(type, full=True) parser.add_argument('--type', type=type) cfg = parser.parse_args(['--type=uuid.UUID']) self.assertEqual(cfg.type, uuid.UUID) self.assertEqual(parser.dump(cfg), 'type: uuid.UUID\n')
def test_ActionPath_skip_check(self): parser = ArgumentParser(error_handler=None) parser.add_argument('--file', action=ActionPath(mode='fr', skip_check=True)) cfg = parser.parse_args(['--file=not-exist']) self.assertIsInstance(cfg.file, Path) self.assertEqual(str(cfg.file), 'not-exist') self.assertEqual(parser.dump(cfg), 'file: not-exist\n') self.assertTrue(repr(cfg.file).startswith('Path_fr_skip_check'))
def _test_typehint_parameterized_types(self, type): parser = ArgumentParser(error_handler=None) ActionTypeHint.is_supported_typehint(type, full=True) parser.add_argument('--cal', type=type[Calendar]) cfg = parser.parse_args(['--cal=calendar.Calendar']) self.assertEqual(cfg.cal, Calendar) self.assertEqual(parser.dump(cfg), 'cal: calendar.Calendar\n') self.assertRaises(ParserError, lambda: parser.parse_args(['--cal=uuid.UUID']))
def test_default_path_unregistered_type(self): parser = ArgumentParser() parser.add_argument('--path', type=path_type('drw', skip_check=True), default=Path('test', mode='drw', skip_check=True)) cfg = parser.parse_args([]) self.assertEqual('path: test\n', parser.dump(cfg)) out = StringIO() parser.print_help(out) self.assertIn('(type: Path_drw_skip_check, default: test)', out.getvalue())
def test_set_dumper_custom_yaml(self): parser = ArgumentParser(error_handler=None) parser.add_argument('--list', type=List[int]) def custom_yaml_dump(data) -> str: return yaml.safe_dump(data, default_flow_style=True) with unittest.mock.patch.dict('jsonargparse.loaders_dumpers.dumpers'): set_dumper('yaml_custom', custom_yaml_dump) cfg = parser.parse_args(['--list=[1,2,3]']) dump = parser.dump(cfg, format='yaml_custom') self.assertEqual(dump, '{list: [1, 2, 3]}\n')
def test_register_type(self): def serializer(v): return v.isoformat() def deserializer(v): return datetime.strptime(v, '%Y-%m-%dT%H:%M:%S') register_type(datetime, serializer, deserializer) parser = ArgumentParser(error_handler=None) parser.add_argument('--datetime', type=datetime) cfg = parser.parse_args(['--datetime=2008-09-03T20:56:35']) self.assertEqual(cfg.datetime, datetime(2008, 9, 3, 20, 56, 35)) self.assertEqual(parser.dump(cfg), "datetime: '2008-09-03T20:56:35'\n") self.assertRaises(ValueError, lambda: register_type(datetime)) register_type(uuid.UUID)
def test_uuid(self): id1 = uuid.uuid4() id2 = uuid.uuid4() parser = ArgumentParser(error_handler=None) parser.add_argument('--uuid', type=uuid.UUID) parser.add_argument('--uuids', type=List[uuid.UUID]) cfg = parser.parse_args([ '--uuid=' + str(id1), '--uuids=["' + str(id1) + '", "' + str(id2) + '"]' ]) self.assertEqual(cfg.uuid, id1) self.assertEqual(cfg.uuids, [id1, id2]) self.assertEqual( 'uuid: ' + str(id1) + '\nuuids:\n- ' + str(id1) + '\n- ' + str(id2) + '\n', parser.dump(cfg))
def test_Callable_with_function_path(self): parser = ArgumentParser(error_handler=None) parser.add_argument('--callable', type=Callable, default=lazy_instance) parser.add_argument('--list', type=List[Callable]) cfg = parser.parse_args(['--callable=jsonargparse.CLI']) self.assertEqual(CLI, cfg.callable) self.assertEqual(parser.dump(cfg), 'callable: jsonargparse.CLI\n') self.assertEqual([CLI], parser.parse_args(['--list=[jsonargparse.CLI]']).list) self.assertRaises( ParserError, lambda: parser.parse_args(['--callable=jsonargparse.not_exist'])) out = StringIO() parser.print_help(out) self.assertIn('(type: Callable, default: jsonargparse.lazy_instance)', out.getvalue())
def test_ActionEnum(self): class MyEnum(Enum): A = 1 B = 2 C = 3 parser = ArgumentParser(error_handler=None) action = ActionEnum(enum=MyEnum) parser.add_argument('--enum', action=action, default=MyEnum.C, help='Description') for val in ['A', 'B', 'C']: self.assertEqual(MyEnum[val], parser.parse_args(['--enum=' + val]).enum) for val in ['X', 'b', 2]: self.assertRaises( ParserError, lambda: parser.parse_args(['--enum=' + str(val)])) cfg = parser.parse_args(['--enum=C'], with_meta=False) self.assertEqual('enum: C\n', parser.dump(cfg)) help_str = StringIO() parser.print_help(help_str) self.assertIn('Description (type: MyEnum, default: C)', help_str.getvalue()) def func(a1: MyEnum = MyEnum['A']): return a1 parser = ArgumentParser() parser.add_function_arguments(func) self.assertEqual(MyEnum['A'], parser.get_defaults().a1) self.assertEqual(MyEnum['B'], parser.parse_args(['--a1=B']).a1) self.assertRaises(ValueError, lambda: ActionEnum()) self.assertRaises(ValueError, lambda: ActionEnum(enum=object)) self.assertRaises( ValueError, lambda: parser.add_argument('--bad1', type=MyEnum, action=True)) self.assertRaises( ValueError, lambda: parser.add_argument('--bad2', type=float, action=action))
def test_parser_mode_omegaconf(self): parser = ArgumentParser(error_handler=None, parser_mode='omegaconf') parser.add_argument('--server.host', type=str) parser.add_argument('--server.port', type=int) parser.add_argument('--client.url', type=str) parser.add_argument('--config', action=ActionConfigFile) config = { 'server': { 'host': 'localhost', 'port': 80, }, 'client': { 'url': 'http://${server.host}:${server.port}/', } } cfg = parser.parse_args([f'--config={yaml_dump(config)}']) self.assertEqual(cfg.client.url, 'http://localhost:80/') self.assertIn('url: http://localhost:80/', parser.dump(cfg))
def test_Callable_with_class_path(self): class MyFunc1: def __init__(self, p1: int = 1): self.p1 = p1 def __call__(self): return self.p1 class MyFunc2(MyFunc1): pass parser = ArgumentParser(error_handler=None) parser.add_argument('--callable', type=Callable) with mock_module(MyFunc1, MyFunc2) as module: value = {'class_path': f'{module}.MyFunc2', 'init_args': {'p1': 1}} cfg = parser.parse_args([f'--callable={module}.MyFunc2']) self.assertEqual(cfg.callable.as_dict(), value) value = {'class_path': f'{module}.MyFunc1', 'init_args': {'p1': 2}} cfg = parser.parse_args([f'--callable={json.dumps(value)}']) self.assertEqual(cfg.callable.as_dict(), value) self.assertEqual( yaml.safe_load(parser.dump(cfg))['callable'], value) cfg_init = parser.instantiate_classes(cfg) self.assertIsInstance(cfg_init.callable, MyFunc1) self.assertEqual(cfg_init.callable(), 2) self.assertRaises(ParserError, lambda: parser.parse_args(['--callable={}'])) self.assertRaises( ParserError, lambda: parser.parse_args( ['--callable=jsonargparse.SUPPRESS'])) self.assertRaises( ParserError, lambda: parser.parse_args(['--callable=calendar.Calendar'])) value = {'class_path': f'{module}.MyFunc1', 'key': 'val'} self.assertRaises( ParserError, lambda: parser.parse_args([f'--callable={json.dumps(value)}']))
def test_complex_number(self): parser = ArgumentParser(error_handler=None) parser.add_argument('--complex', type=complex) cfg = parser.parse_args(['--complex=(2+3j)']) self.assertEqual(cfg.complex, 2 + 3j) self.assertEqual(parser.dump(cfg), 'complex: (2+3j)\n')
def test_dump_header_yaml(self): parser = ArgumentParser() parser.add_argument('--int', type=int, default=1) parser.dump_header = ['line 1', 'line 2'] dump = parser.dump(parser.get_defaults()) self.assertEqual(dump, '# line 1\n# line 2\nint: 1\n')
def test_ActionParser(self): parser_lv3 = ArgumentParser(prog='lv3', default_env=False) parser_lv3.add_argument('--opt3', default='opt3_def') parser_lv2 = ArgumentParser(prog='lv2', default_env=False) parser_lv2.add_argument('--opt2', default='opt2_def') parser_lv2.add_argument('--inner3', action=ActionParser(parser=parser_lv3)) parser = ArgumentParser(prog='lv1', default_env=True, error_handler=None) parser.add_argument('--opt1', default='opt1_def') parser.add_argument('--inner2', action=ActionParser(parser=parser_lv2)) tmpdir = os.path.join(self.tmpdir, 'subdir') os.mkdir(tmpdir) yaml_main_file = os.path.join(tmpdir, 'main.yaml') yaml_inner2_file = os.path.join(tmpdir, 'inner2.yaml') yaml_inner3_file = os.path.join(tmpdir, 'inner3.yaml') with open(yaml_main_file, 'w') as output_file: output_file.write('opt1: opt1_yaml\ninner2: inner2.yaml\n') with open(yaml_inner2_file, 'w') as output_file: output_file.write('opt2: opt2_yaml\ninner3: inner3.yaml\n') with open(yaml_inner3_file, 'w') as output_file: output_file.write('opt3: opt3_yaml\n') ## Check defaults cfg = parser.get_defaults() self.assertEqual('opt1_def', cfg.opt1) self.assertEqual('opt2_def', cfg.inner2.opt2) self.assertEqual('opt3_def', cfg.inner2.inner3.opt3) ## Check ActionParser with parse_path expected = { 'opt1': 'opt1_yaml', 'inner2': { 'opt2': 'opt2_yaml', 'inner3': { 'opt3': 'opt3_yaml' } } } cfg = parser.parse_path(yaml_main_file, with_meta=False) self.assertEqual(expected, cfg.as_dict()) with open(yaml_main_file, 'w') as output_file: output_file.write(parser.dump(cfg)) cfg2 = parser.parse_path(yaml_main_file, with_meta=False) self.assertEqual(expected, cfg2.as_dict()) ## Check ActionParser inner environment variables self.assertEqual( 'opt2_env', parser.parse_env({ 'LV1_INNER2__OPT2': 'opt2_env' }).inner2.opt2) self.assertEqual( 'opt3_env', parser.parse_env({ 'LV1_INNER2__INNER3__OPT3': 'opt3_env' }).inner2.inner3.opt3) expected = { 'opt1': 'opt1_def', 'inner2': { 'opt2': 'opt2_def', 'inner3': { 'opt3': 'opt3_yaml' } } } cfg = parser.parse_env({'LV1_INNER2__INNER3': yaml_inner3_file}, with_meta=False) self.assertEqual(expected, cfg.as_dict()) parser.parse_env({'LV1_INNER2': yaml_inner2_file}) self.assertEqual( 'opt2_yaml', parser.parse_env({ 'LV1_INNER2': yaml_inner2_file }).inner2.opt2) ## Check ActionParser as argument path expected = { 'opt1': 'opt1_arg', 'inner2': { 'opt2': 'opt2_yaml', 'inner3': { 'opt3': 'opt3_yaml' } } } cfg = parser.parse_args( ['--opt1', 'opt1_arg', '--inner2', yaml_inner2_file], with_meta=False) self.assertEqual(expected, cfg.as_dict()) expected = { 'opt1': 'opt1_def', 'inner2': { 'opt2': 'opt2_arg', 'inner3': { 'opt3': 'opt3_yaml' } } } cfg = parser.parse_args( ['--inner2.opt2', 'opt2_arg', '--inner2.inner3', yaml_inner3_file], with_meta=False) self.assertEqual(expected, cfg.as_dict()) expected = { 'opt1': 'opt1_def', 'inner2': { 'opt2': 'opt2_def', 'inner3': { 'opt3': 'opt3_arg' } } } cfg = parser.parse_args([ '--inner2.inner3', yaml_inner3_file, '--inner2.inner3.opt3', 'opt3_arg' ], with_meta=False) self.assertEqual(expected, cfg.as_dict()) ## Check ActionParser as argument string expected = {'opt2': 'opt2_str', 'inner3': {'opt3': 'opt3_str'}} cfg = parser.parse_args(['--inner2', json.dumps(expected)], with_meta=False) self.assertEqual(expected, cfg.as_dict()['inner2']) expected = {'opt3': 'opt3_str'} cfg = parser.parse_args( ['--inner2.inner3', json.dumps(expected)], with_meta=False) self.assertEqual(expected, cfg.as_dict()['inner2']['inner3']) ## Check ActionParser with ActionConfigFile parser.add_argument('--cfg', action=ActionConfigFile) expected = { 'opt1': 'opt1_yaml', 'inner2': { 'opt2': 'opt2_yaml', 'inner3': { 'opt3': 'opt3_yaml' } } } cfg = parser.parse_args(['--cfg', yaml_main_file], with_meta=False) delattr(cfg, 'cfg') self.assertEqual(expected, cfg.as_dict()) cfg = parser.parse_args([ '--cfg', yaml_main_file, '--inner2.opt2', 'opt2_arg', '--inner2.inner3.opt3', 'opt3_arg' ]) self.assertEqual('opt2_arg', cfg.inner2.opt2) self.assertEqual('opt3_arg', cfg.inner2.inner3.opt3)
def test_dump_header_json(self): parser = ArgumentParser() parser.add_argument('--int', type=int, default=1) parser.dump_header = ['line 1', 'line 2'] dump = parser.dump(parser.get_defaults(), format='json') self.assertEqual(dump, '{"int":1}')