def test_ActionJsonSchema(self):
        parser = ArgumentParser(prog='app', default_meta=False, error_handler=None)
        parser.add_argument('--op1',
            action=ActionJsonSchema(schema=schema1))
        parser.add_argument('--op2',
            action=ActionJsonSchema(schema=schema2))
        parser.add_argument('--op3',
            action=ActionJsonSchema(schema=schema3))
        parser.add_argument('--cfg',
            action=ActionConfigFile)

        op1_val = [1, 2, 3, 4]
        op2_val = {'k1': 'one', 'k2': 2, 'k3': 3.3}

        self.assertEqual(op1_val, parser.parse_args(['--op1', str(op1_val)]).op1)
        self.assertRaises(ParserError, lambda: parser.parse_args(['--op1', '[1, "two"]']))
        self.assertRaises(ParserError, lambda: parser.parse_args(['--op1', '[1.5, 2]']))

        self.assertEqual(op2_val, parser.parse_args(['--op2', str(op2_val)]).op2)
        self.assertEqual(17, parser.parse_args(['--op2', '{"k2": 2}']).op2['k3'])
        self.assertRaises(ParserError, lambda: parser.parse_args(['--op2', '{"k1": 1}']))
        self.assertRaises(ParserError, lambda: parser.parse_args(['--op2', '{"k2": "2"}']))
        self.assertRaises(ParserError, lambda: parser.parse_args(['--op2', '{"k4": 4}']))

        op1_file = os.path.join(self.tmpdir, 'op1.json')
        op2_file = os.path.join(self.tmpdir, 'op2.json')
        cfg1_file = os.path.join(self.tmpdir, 'cfg1.yaml')
        cfg3_file = os.path.join(self.tmpdir, 'cfg3.yaml')
        cfg2_str = 'op1:\n  '+str(op1_val)+'\nop2:\n  '+str(op2_val)+'\n'
        with open(op1_file, 'w') as f:
            f.write(str(op1_val))
        with open(op2_file, 'w') as f:
            f.write(str(op2_val))
        with open(cfg1_file, 'w') as f:
            f.write('op1:\n  '+op1_file+'\nop2:\n  '+op2_file+'\n')
        with open(cfg3_file, 'w') as f:
            f.write('op3:\n  n1:\n  - '+str(op2_val)+'\n')

        cfg = parser.parse_path(cfg1_file)
        self.assertEqual(op1_val, cfg['op1'])
        self.assertEqual(op2_val, cfg['op2'])

        cfg = parser.parse_string(cfg2_str)
        self.assertEqual(op1_val, cfg['op1'])
        self.assertEqual(op2_val, cfg['op2'])

        cfg = parser.parse_args(['--cfg', cfg3_file])
        self.assertEqual(op2_val, cfg.op3['n1'][0])
        parser.check_config(cfg, skip_none=True)

        if os.name == 'posix' and platform.python_implementation() == 'CPython':
            os.chmod(op1_file, 0)
            self.assertRaises(ParserError, lambda: parser.parse_path(cfg1_file))
    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)