Parses command line parameters
            A string can be passed to simulate a cli for test purpose

def start(self, param_string=None):
        """ Parses command line parameters
            A string can be passed to simulate a cli for test purpose
        """
        external_opt = {}
        self.get_options_from_environ(external_opt)
        self.get_options_from_file(external_opt)
        # construct optional args, required args and variable args as we find then in the command line
        optargs = {}
        reqargs, varargs = [], []

        # get parameters from command line, or from parameter string (latter essentially for tests)
        if param_string is None:
            argv = sys.argv[1:]
        else:
            import shlex
            argv = shlex.split(param_string)

        self._eval_variables()
        i = 0
        while i < len(argv):
            # get next parameter
            x = argv[i]
            # check for help
            if x in self._help_options:
                self._print_help()
                return
            # check for version
            if x in self._version_options and self._get_variable('VERSION'):
                self._print_version()
                return
            # parameter is an option
            if x in self.options:
                o_x = self.options[x]
                oe_x = self.options_equ[x]
                # check for duplicates
                if oe_x in optargs:
                    raise RunnerError("Option '%s' found twice" % x)
                # proceed with lists or tuples
                if isinstance(o_x, (list, tuple)):
                    argpos = i
                    optargs[oe_x] = []
                    i += 1
                    # iterate till end of parameters list, or to next option occurrence
                    while i < len(argv) and argv[i] not in self.options:
                        # try to convert element to expected type, then store it
                        try:
                            optargs[oe_x].append(type(o_x[0])(argv[i]))
                        except ValueError:
                            raise RunnerErrorWithUsage("Argument %d of option %s has wrong type (%s expected)" %
                                                       (i - argpos, x, self._format_type(o_x[0])))
                        # if no expected type, just store element
                        except IndexError:
                            optargs[oe_x].append(argv[i])
                        i += 1
                    # check that list option is not empty
                    if not len(optargs[oe_x]) and not len(o_x):
                        raise RunnerErrorWithUsage("Option '%s' should be followed by a list of values" % x)
                    # check number of element if default list/tuple is not empty
                    if len(o_x) and len(optargs[oe_x]) != len(o_x):
                        raise RunnerErrorWithUsage("Option '%s' should be followed by a list of %d %s, found %d" %
                                                   (x, len(o_x), self._format_type(o_x[0]), len(optargs[oe_x])))
                # proceed boolean
                elif type(o_x) is bool:
                    optargs[oe_x] = True
                    i += 1
                # proceed other types (string, integer, float)
                else:
                    i += 1
                    # check that option is given a value
                    if i >= len(argv) or argv[i] in self.options:
                        raise RunnerErrorWithUsage("Option '%s' should be followed by a %s" %
                                                   (x, self._format_type(o_x)))
                    # try to convert element to expected type, then store it
                    try:
                        optargs[oe_x] = type(o_x)(argv[i])
                    except ValueError:
                        raise RunnerErrorWithUsage("Argument of option %s has wrong type (%s expected)" %
                                                   (x, self._format_type(o_x)))
                    i += 1
            # parameter may be a required or a variable parameter, or unrecognized
            else:
                if x.startswith('-'):
                    raise RunnerErrorWithUsage("Unrecognized option '%s'" % argv[i])
                elif len(reqargs) < len(self.reqargs):
                    reqargs.append(argv[i])
                elif self.varargs:
                    varargs.append(argv[i])
                else:
                    raise RunnerErrorWithUsage("Unrecognized parameter '%s'" % argv[i])
                i += 1
        # check number of required parameters
        if self.reqargs and len(reqargs) < len(self.reqargs):
            raise RunnerErrorWithUsage("Too few parameters (%d required)" % len(self.reqargs))
        # merge required, optional args and options in allargs
        options = OrderedDict(self.python_options)
        options.update(external_opt)
        options.update(optargs)
        allargs = reqargs
        allargs.extend(options.values())
        allargs.extend(varargs)
        if DEBUG:
            print('clize call parameters:', allargs)
        # all parameters are filled, call wrapped function
        return self.func(*allargs)