def test_create_two_with_different_type_component(): """ Create two component with different type with the following cli : --sub toto --name titi --sub tutu --name tete test if the result is : {sub:{'titi' : {'type': 'toto'}, 'tete': {'type': 'tutu'}}} """ parser = MainParser(help_arg=False) subparser = ComponentSubParser('toto') subparser.add_argument('n', 'name') parser.add_actor_subparser('sub', subparser) subparser = ComponentSubParser('tutu') subparser.add_argument('n', 'name') parser.add_actor_subparser('sub', subparser) check_parsing_result( parser, '--sub toto --name titi --sub tutu --name tete', {'sub': { 'titi': { 'type': 'toto' }, 'tete': { 'type': 'tutu' } }})
def test_create_two_component(): """ Create two component of the same type with the following cli : --sub toto --name titi --sub toto -b --name tutu test if the result is : {sub:{'titi' : {'type': 'toto'}, 'tutu': {'type': 'toto', 'b':True}}} """ parser = MainParser(help_arg=False) subparser = ComponentSubParser('toto') subparser.add_argument('b', flag=True, action=store_true) subparser.add_argument('n', 'name') parser.add_actor_subparser('sub', subparser) check_parsing_result(parser, '--sub toto --name titi --sub toto -b --name tutu', { 'sub': { 'titi': { 'type': 'toto' }, 'tutu': { 'type': 'toto', 'b': True } } })
def test_add_component_subparser_that_aldready_exists2(): """ Add a component_subparser with no argument 'name' test if a SubParserWithoutNameArgumentException is raised """ parser = MainParser(help_arg=False) subparser = ComponentSubParser('titi') with pytest.raises(SubParserWithoutNameArgumentException): parser.add_actor_subparser('toto', subparser)
def test_add_actor_subparser_that_aldready_exists(): """ Add a component_subparser that already exists to a parser and test if an AlreadyAddedArgumentException is raised """ parser = MainParser(help_arg=False) subparser = ComponentSubParser('titi') subparser.add_argument('n', 'name') parser.add_actor_subparser('toto', subparser) subparser2 = ComponentSubParser('titi') subparser2.add_argument('n', 'name') with pytest.raises(AlreadyAddedArgumentException): parser.add_actor_subparser('toto', subparser2)
def test_actor_subparser(): """ test to parse strings with a parser and retrieve the following results : - "" : {} - "-z" : UnknowArgException(z) - "-a" : {a: True} - "-a --sub toto -b" : NoNameSpecifiedForComponentException - "-a --sub toto -b --name titi" : {a:True, sub: { titi: { 'type': 'toto', b: True}}} - "-b" : BadContextException(b, [toto]) Parser description : - base parser arguments : -a - subparser toto binded to the argument sub with sub arguments : -b and --name """ parser = MainParser(help_arg=False) parser.add_argument('a', flag=True, action=store_true) subparser = ComponentSubParser('toto') subparser.add_argument('b', flag=True, action=store_true) subparser.add_argument('n', 'name') parser.add_actor_subparser('sub', subparser) check_parsing_result(parser, '', {}) with pytest.raises(UnknowArgException): check_parsing_result(parser, '-z', None) check_parsing_result(parser, '-a', {'a': True}) with pytest.raises(NoNameSpecifiedForComponentException): check_parsing_result(parser, '-a --sub toto -b', {}) check_parsing_result(parser, '-a --sub toto -b --name titi', { 'a': True, 'sub': { 'titi': { 'type': 'toto', 'b': True } } }) with pytest.raises(BadContextException): check_parsing_result(parser, '-b', None)
def test_create_component_that_already_exist(): """ Create two component with the same name with the following cli --sub toto --name titi --sub toto --name titi test if an ComponentAlreadyExistException is raised """ parser = MainParser(help_arg=False) subparser = ComponentSubParser('toto') subparser.add_argument('b', flag=True, action=store_true) subparser.add_argument('n', 'name') parser.add_actor_subparser('sub', subparser) with pytest.raises(ComponentAlreadyExistException): check_parsing_result(parser, '--sub toto --name titi --sub toto --name titi', None)
def test_add_actor_subparser_with_two_name(): """ add a component subparser with one short name and one long name parse a string and test if the value is only bind to the long name """ parser = MainParser(help_arg=False) subparser = ComponentSubParser('titi') subparser.add_argument('a', 'aaa', flag=True, action=store_true, default=False) subparser.add_argument('n', 'name') parser.add_actor_subparser('sub', subparser) check_parsing_result(parser, '--sub titi -a --name tutu', {'sub': { 'tutu': { 'aaa': True, 'type': 'titi' } }})
class MainConfigParser(ConfigParser): """ Parser abstraction for the configuration """ def __init__(self): ConfigParser.__init__(self) self.subparser = {} self.cli_parser = MainParser() def add_subparser(self, name, subparser: SubConfigParser, help=''): """ Add a SubParser to call when <name> is encoutered When name is encoutered, the subarpser such as subparser.name match conf[name].type """ if name in self.subparser: if subparser.name in list(self.subparser[name]): raise AlreadyAddedSubparserException(name) else: self.subparser[name] = {} self.subparser[name][subparser.name] = subparser self.cli_parser.add_actor_subparser(name, subparser.cli_parser, help) def _parse_cli(self, cli_line): return self.cli_parser.parse(cli_line) @staticmethod def _parse_file(filename): config_file = open(filename, 'r') conf = json.load(config_file) return conf def _validate(self, conf: Dict): """ Check the parsed configuration""" # Check that all the mandatory arguments are precised mandatory_args = self._get_mandatory_args() for arg in mandatory_args: if arg not in conf: raise MissingArgumentException(arg) # check types for args, value in conf.items(): is_an_arg = False if args in self.subparser: for _, dic_value in value.items(): self.subparser[args][dic_value["type"]].validate(dic_value) is_an_arg = True for _, waited_value in self.args.items(): if args in waited_value.names: is_an_arg = True # check type if not isinstance( value, waited_value.type) and not waited_value.is_flag: raise BadTypeException(args, waited_value.type) if not is_an_arg: raise UnknowArgException(args) for args, value in self.args.items(): is_precised = False for name in value.names: if name in conf: is_precised = True break if not is_precised and value.default_value is not None: conf[args] = value.default_value return conf def parse(self, args=None): """ Find the configuration method (CLI or config file) Call the method to produce a configuration dictionnary check the configuration """ if args is None: args = sys.argv i = 0 filename = None for s in args: if s == '--config-file': if i + 1 == len(args): logging.error( "CLI Error: config file path needed with argument --config-file" ) sys.exit(-1) filename = args[i + 1] i += 1 try: if filename is not None: conf = self._parse_file(filename) else: conf = self._parse_cli(args[1:]) conf = self._validate(conf) except MissingValueException as exn: msg = 'CLI error: argument ' + exn.argument_name + ': expect a value' logging.error(msg) sys.exit(-1) except BadTypeException as exn: msg = "Configuration error: " + exn.msg logging.error(msg) sys.exit(-1) except UnknowArgException as exn: msg = 'Configuration error: unknow argument ' + exn.argument_name logging.error(msg) sys.exit(-1) except BadContextException as exn: msg = 'CLI error: argument ' + exn.argument_name msg += ' not used in the correct context\nUse it with the following arguments:' for main_arg_name, context_name in exn.context_list: msg += '\n --' + main_arg_name + ' ' + context_name logging.error(msg) sys.exit(-1) except FileNotFoundError: logging.error("Configuration Error: configuration file not found") sys.exit(-1) except json.JSONDecodeError as exn: logging.error('Configuration Error: JSON Error: ' + exn.msg + ' at line' + exn.lineno + ' colomn ' + exn.colno) sys.exit(-1) except MissingArgumentException as exn: logging.error("Configuration Error: " + exn.msg) sys.exit(-1) return conf