コード例 #1
0
    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))
コード例 #2
0
    def _adapt_types(val,
                     annotation,
                     subschemas,
                     reverse=False,
                     instantiate_classes=False):
        def validate_adapt(v, subschema):
            if subschema is not None:
                subannotation, subvalidator, subsubschemas = subschema
                if reverse:
                    v = ActionJsonSchema._adapt_types(v, subannotation,
                                                      subsubschemas, reverse,
                                                      instantiate_classes)
                else:
                    try:
                        if subvalidator is not None and not instantiate_classes:
                            subvalidator.validate(v)
                        v = ActionJsonSchema._adapt_types(
                            v, subannotation, subsubschemas, reverse,
                            instantiate_classes)
                    except jsonschemaValidationError:
                        pass
            return v

        if subschemas is None:
            subschemas = []

        if _issubclass(annotation, Enum):
            if reverse and isinstance(val, annotation):
                val = val.name
            elif not reverse and val in annotation.__members__:
                val = annotation[val]

        elif _issubclass(annotation, Path):
            if reverse and isinstance(val, annotation):
                val = str(val)
            elif not reverse:
                val = annotation(val)

        elif not hasattr(annotation, '__origin__'):
            if not reverse and \
               not _issubclass(annotation, (str, int, float)) and \
               isinstance(val, dict) and \
               'class_path' in val:
                try:
                    val_class = import_object(val['class_path'])
                    assert _issubclass(
                        val_class,
                        annotation), 'Not a subclass of ' + annotation.__name__
                    if 'init_args' in val:
                        from jsonargparse import ArgumentParser
                        parser = ArgumentParser(error_handler=None,
                                                parse_as_dict=True)
                        parser.add_class_arguments(val_class)
                        parser.check_config(val['init_args'])
                        if instantiate_classes:
                            init_args = parser.instantiate_subclasses(
                                val['init_args'])
                            val = val_class(**init_args)  # pylint: disable=not-a-mapping
                    elif instantiate_classes:
                        val = val_class()
                except (ImportError, ModuleNotFound, AttributeError,
                        AssertionError, ParserError) as ex:
                    raise ParserError('Problem with given class_path "' +
                                      val['class_path'] + '" :: ' +
                                      str(ex)) from ex
            return val

        elif annotation.__origin__ == Union:
            for subschema in subschemas:
                val = validate_adapt(val, subschema)

        elif annotation.__origin__ in {Tuple, tuple, Set, set} and isinstance(
                val, (list, tuple, set)):
            if reverse:
                val = list(val)
            for n, v in enumerate(val):
                if n < len(subschemas) and subschemas[n] is not None:
                    for subschema in subschemas[n]:
                        val[n] = validate_adapt(v, subschema)
            if not reverse:
                val = tuple(val) if annotation.__origin__ in {Tuple, tuple
                                                              } else set(val)

        elif annotation.__origin__ in {
                List, list, Set, set, Iterable, Sequence
        } and isinstance(val, list):
            for n, v in enumerate(val):
                for subschema in subschemas:
                    val[n] = validate_adapt(v, subschema)

        elif annotation.__origin__ in {Dict, dict} and isinstance(val, dict):
            if annotation.__args__[0] == int:
                cast = str if reverse else int
                val = {cast(k): v for k, v in val.items()}
            if annotation.__args__[1] not in typesmap:
                for k, v in val.items():
                    for subschema in subschemas:
                        val[k] = validate_adapt(v, subschema)

        return val