예제 #1
0
    def create_console(self, script):
        usage_sections = parse_section('usage:', script.__doc__)
        if len(usage_sections) == 0:
            raise DocoptLanguageError('"usage:" (case-insensitive) not found.')
        if len(usage_sections) > 1:
            raise DocoptLanguageError('More than one "usage:" (case-insensitive).')
        DocoptExit.usage = usage_sections[0]
        pattern = parse_pattern(formal_usage(DocoptExit.usage), parse_defaults(script.__doc__))

        paths = []

        paths.append({
            "flags": [opt for opt in parse_defaults(script.__doc__) if not opt.argcount and opt.name not in ["--help", "--version"]],
            "extras": [opt for opt in parse_defaults(script.__doc__) if not opt.argcount and opt.name in ["--help", "--version"]],
            "options": [opt for opt in parse_defaults(script.__doc__) if opt.argcount and not opt.value],
            "default_options": [opt for opt in parse_defaults(script.__doc__) if opt.value],
            "arguments": [arg.name for arg in pattern.flat(Argument)],
        })

        return {
            "name": script.__name__,
            "file": script.__file__,
            "doc": script.__doc__,
            "paths": paths,
        }
예제 #2
0
파일: importer.py 프로젝트: ramou/boutiques
    def __init__(self, docopt_str, base_descriptor):
        with open(base_descriptor, "r") as base_desc:
            self.descriptor = collections.OrderedDict(json.load(base_desc))

        del self.descriptor['groups']
        del self.descriptor['inputs']
        del self.descriptor['output-files']
        self.docopt_str = docopt_str
        self.dependencies = collections.OrderedDict()
        self.all_desc_and_type = collections.OrderedDict()
        self.unique_ids = []

        try:
            # docopt code snippet to extract args tree (pattern)
            # should run if docopt script is valid
            options = parse_defaults(docopt_str)

            self.pattern = parse_pattern(
                formal_usage(self._parse_section('usage:', docopt_str)[0]),
                options)

            argv = parse_argv(TokenStream(sys.argv[1:], DocoptLanguageError),
                              list(options), False)
            pattern_options = set(self.pattern.flat(Option))

            for options_shortcut in self.pattern.flat(AnyOptions):
                doc_options = parse_defaults(docopt_str)
                options_shortcut.children = list(
                    set(doc_options) - pattern_options)
            matched, left, collected = self.pattern.fix().match(argv)
        except Exception:
            os.remove(base_descriptor)
            raise_error(ImportError, "Invalid docopt script")
예제 #3
0
def docopt(doc, argv=None, help=True, version=None, options_first=False):  # @ReservedAssignment help
    """Re-implementation of docopt.docopt() function to parse ANYTHING at
    the end (for proxying django options)."""
    if argv is None:
        argv = sys.argv[1:]

    DocoptExit.usage = printable_usage(doc)
    options = parse_defaults(doc)
    pattern = parse_pattern(formal_usage(DocoptExit.usage), options)
    argv = parse_argv(TokenStream(argv, DocoptExit), list(options), options_first)
    pattern_options = set(pattern.flat(Option))
    for ao in pattern.flat(AnyOptions):
        doc_options = parse_defaults(doc)
        ao.children = list(set(doc_options) - pattern_options)
    extras(help, version, argv, doc)
    __matched, __left, collected = pattern.fix().match(argv)

    # if matched and left == []:  # better error message if left?
    if collected:  # better error message if left?
        result = Dict((a.name, a.value) for a in (pattern.flat() + collected))
        collected_django_options = len(result.get("DJANGO_OPTIONS", []))
        result["DJANGO_OPTIONS"] = (
            result.get("DJANGO_OPTIONS", []) + sys.argv[len(collected) + (collected_django_options or 1) :]
        )
        # If any of the collected arguments are also in the DJANGO_OPTIONS,
        # then exit because we don't want users to have put options for kalite
        # at the end of the command
        if any(map(lambda x: x.name in map(lambda x: x.split("=")[0], result["DJANGO_OPTIONS"]), collected)):
            sys.stderr.write(
                "Cannot mix django manage command options with kalite options. "
                "Always put django management options last.\n\n"
            )
            raise DocoptExit()
        return result
    raise DocoptExit()
예제 #4
0
def parse_params(cmd):
    # this function creates a parameter tree for the target docopt tool.
    # a parameter tree is a CommandParams instance, see the documentation of the class
    # this function also returns a second parameter, which is a dictionary of option->option help string
    from docopt import parse_defaults, parse_pattern, formal_usage, printable_usage
    usage = get_usage(cmd)
    options = parse_defaults(usage)
    pattern = parse_pattern(formal_usage(printable_usage(usage)), options)
    param_tree = CommandParams()
    build_command_tree(pattern, param_tree)
    return param_tree, dict(list(get_options_descriptions(usage)))
예제 #5
0
def parse_params(cmd, given_usage=None):
    # This creates a parameter tree (CommandParams object) for the target docopt tool.
    # Also returns a second parameter, a dict of:
    #   option->option-help-string
    from docopt import parse_defaults, parse_pattern, formal_usage, printable_usage
    usage = get_usage(cmd) if given_usage is None else given_usage
    options = parse_defaults(usage)
    pattern = parse_pattern(formal_usage(printable_usage(usage)), options)
    param_tree = CommandParams()
    build_command_tree(pattern, param_tree)
    return param_tree, dict(list(get_options_descriptions(usage)))
예제 #6
0
def parse_params(cmd):
    # This creates a parameter tree (CommandParams object) for the target docopt tool.
    # Also returns a second parameter, a dict of:
    #   option->option-help-string
    from docopt import parse_defaults, parse_pattern, formal_usage, printable_usage
    usage = get_usage(cmd)
    options = parse_defaults(usage)
    pattern = parse_pattern(formal_usage(printable_usage(usage)), options)
    param_tree = CommandParams()
    build_command_tree(pattern, param_tree)
    return param_tree, dict(list(get_options_descriptions(usage)))
예제 #7
0
    def pattern(self):
        """Returns a docopt match pattern."""
        try:
            from docopt import parse_defaults, formal_usage, parse_pattern
        except ImportError:
            LOGGER.warning('docopt not installed.')
            LOGGER.warning('Command help pattern generation unavailable.')
            return None

        usage = self.usage
        options = parse_defaults(usage)
        return parse_pattern(formal_usage(usage), options)
예제 #8
0
def parse_atom(tokens, options):
    if len(tokens) > 3 and (tokens[0], tokens[2]) == ('[', ']') and \
        tokens[1].startswith('git-') and tokens[1].endswith('-options'):
            token = tokens[1][4:-8]
            tokens.move(); tokens.move(); tokens.move()
            ret = []
            for opt in known_options[token]:
                opt = docopt.parse_pattern(opt, []).children[0]
                opt = GitOption(opt.short, opt.long, opt.argcount, opt.value)
                ret.append(opt)
                options.append(opt)
            return ret
    return docopt.orig_parse_atom(tokens, options)
예제 #9
0
def parse_atom(tokens, options):
    if len(tokens) > 3 and (tokens[0], tokens[2]) == ('[', ']') and \
        tokens[1].startswith('git-') and tokens[1].endswith('-options'):
            token = tokens[1][4:-8]
            tokens.move(); tokens.move(); tokens.move()
            ret = []
            for opt in known_options[token]:
                opt = docopt.parse_pattern(opt, []).children[0]
                opt = GitOption(opt.short, opt.long, opt.argcount, opt.value)
                ret.append(opt)
                options.append(opt)
            return ret
    return docopt.orig_parse_atom(tokens, options)
예제 #10
0
def settable_options(doc, argv, ignore, options_first):
    """Determine which options we can set, which ones are boolean, and which ones are repeatable.

    All set items are option long names.

    :param str doc: Docstring from docoptcfg().
    :param iter argv: CLI arguments from docoptcfg().
    :param iter ignore: Options to ignore from docoptcfg().
    :param bool options_first: docopt argument from docoptcfg().

    :return: Settable options, boolean options, repeatable options, and short to long option name mapping.
    :rtype: tuple
    """
    settable, booleans, repeatable, short_map = set(), set(), set(), dict()

    # Determine which options are settable by docoptcfg and which ones are flags/booleans.
    options = docopt.parse_defaults(doc)
    short_map.update((o.short, o.long) for o in options)
    parsed_argv = docopt.parse_argv(
        docopt.TokenStream(argv, docopt.DocoptExit), list(options),
        options_first)
    overridden = [o.long for o in parsed_argv if hasattr(o, 'long')]
    for option in options:
        if option.long in overridden or (option.long in ignore or option.short
                                         in ignore) or option.long is None:
            continue
        if option.argcount == 0:
            booleans.add(option.long)
        settable.add(option.long)

    # Determine which options are repeatable.
    if settable and '...' in doc:
        pattern = docopt.parse_pattern(
            docopt.formal_usage(docopt.DocoptExit.usage), options)
        for option in pattern.fix().flat():
            if not hasattr(option, 'long'):
                continue  # Positional argument or sub-command.
            if getattr(option, 'long') not in settable:
                continue  # Don't care about this if we can't set it.
            if getattr(option, 'long') in booleans and getattr(
                    option, 'value') == 0:
                repeatable.add(getattr(option, 'long'))
            elif hasattr(getattr(option, 'value'), '__iter__'):
                repeatable.add(getattr(option, 'long'))

    return settable, booleans, repeatable, short_map
예제 #11
0
def docopt(doc,
           argv=None,
           help=True,
           version=None,
           options_first=False):  # @ReservedAssignment help
    """Re-implementation of docopt.docopt() function to parse ANYTHING at
    the end (for proxying django options)."""
    if argv is None:
        argv = sys.argv[1:]

    DocoptExit.usage = printable_usage(doc)
    options = parse_defaults(doc)
    pattern = parse_pattern(formal_usage(DocoptExit.usage), options)
    argv = parse_argv(TokenStream(argv, DocoptExit), list(options),
                      options_first)
    pattern_options = set(pattern.flat(Option))
    for ao in pattern.flat(AnyOptions):
        doc_options = parse_defaults(doc)
        ao.children = list(set(doc_options) - pattern_options)
    extras(help, version, argv, doc)
    __matched, __left, collected = pattern.fix().match(argv)

    # if matched and left == []:  # better error message if left?
    if collected:  # better error message if left?
        result = Dict((a.name, a.value) for a in (pattern.flat() + collected))
        collected_django_options = len(result.get('DJANGO_OPTIONS', []))
        result['DJANGO_OPTIONS'] = (result.get('DJANGO_OPTIONS', []) +
                                    sys.argv[len(collected) +
                                             (collected_django_options or 1):])
        # If any of the collected arguments are also in the DJANGO_OPTIONS,
        # then exit because we don't want users to have put options for kalite
        # at the end of the command
        if any(
                map(
                    lambda x: x.name in map(lambda x: x.split("=")[0], result[
                        'DJANGO_OPTIONS']), collected)):
            sys.stderr.write(
                "Cannot mix django manage command options with kalite options. "
                "Always put django management options last.\n\n")
            raise DocoptExit()
        return result
    raise DocoptExit()
예제 #12
0
def settable_options(doc, argv, ignore, options_first):
    """Determine which options we can set, which ones are boolean, and which ones are repeatable.

    All set items are option long names.

    :param str doc: Docstring from docoptcfg().
    :param iter argv: CLI arguments from docoptcfg().
    :param iter ignore: Options to ignore from docoptcfg().
    :param bool options_first: docopt argument from docoptcfg().

    :return: Settable options, boolean options, repeatable options, and short to long option name mapping.
    :rtype: tuple
    """
    settable, booleans, repeatable, short_map = set(), set(), set(), dict()

    # Determine which options are settable by docoptcfg and which ones are flags/booleans.
    options = docopt.parse_defaults(doc)
    short_map.update((o.short, o.long) for o in options)
    parsed_argv = docopt.parse_argv(docopt.TokenStream(argv, docopt.DocoptExit), list(options), options_first)
    overridden = [o.long for o in parsed_argv if hasattr(o, 'long')]
    for option in options:
        if option.long in overridden or (option.long in ignore or option.short in ignore):
            continue
        if option.argcount == 0:
            booleans.add(option.long)
        settable.add(option.long)

    # Determine which options are repeatable.
    if settable and '...' in doc:
        pattern = docopt.parse_pattern(docopt.formal_usage(docopt.DocoptExit.usage), options)
        for option in pattern.fix().flat():
            if not hasattr(option, 'long'):
                continue  # Positional argument or sub-command.
            if getattr(option, 'long') not in settable:
                continue  # Don't care about this if we can't set it.
            if getattr(option, 'long') in booleans and getattr(option, 'value') == 0:
                repeatable.add(getattr(option, 'long'))
            elif hasattr(getattr(option, 'value'), '__iter__'):
                repeatable.add(getattr(option, 'long'))

    return settable, booleans, repeatable, short_map
예제 #13
0
def docopt_cmd_completion(func, **kwargs):
    options = parse_defaults(func.__doc__)
    pattern = parse_pattern(formal_usage(printable_usage(func.__doc__)),
                            options).children[0]

    def get_state(it, pattern):
        try:
            value = next(it)
        except StopIteration:
            return pattern
        res = []
        for x in pattern:
            if ((type(x[0]) == list and value in flatten(x[0]))
                    or value == x[0]):
                res.append(x[1:])
        if res:
            return get_state(it, res)
        return []

    def wrapper(self, text, line, begidx, endidx):
        argv = shlex.split(line[:endidx])[1:]
        if not line[endidx - 1].isspace():
            target = argv[-1]
            argv = argv[:-1]
        else:
            target = ''
        state = get_state(iter(argv), pattern.noflat())
        res = []
        for x in state:
            if type(x[0]) == list:
                res.extend(flatten(x[0]))
            else:
                res.append(x[0])
        return list(set(x for x in res if x.startswith(target)))

    wrapper.__name__ = str('complete_' + func.__name__[3:])
    wrapper.__module__ = func.__module__
    wrapper.__doc__ = func.__doc__
    return wrapper
예제 #14
0
def docopt_cmd_completion(func, **kwargs):
    options = parse_defaults(func.__doc__)
    pattern = parse_pattern(formal_usage(printable_usage(func.__doc__)),
                            options).children[0]

    def get_state(it, pattern):
        try:
            value = next(it)
        except StopIteration:
            return pattern
        res = []
        for x in pattern:
            if ((type(x[0]) == list and value in flatten(x[0])) or
                value == x[0]):
                res.append(x[1:])
        if res:
            return get_state(it, res)
        return []

    def wrapper(self, text, line, begidx, endidx):
        argv = shlex.split(line[:endidx])[1:]
        if not line[endidx - 1].isspace():
            target = argv[-1]
            argv = argv[:-1]
        else:
            target = ''
        state = get_state(iter(argv), pattern.noflat())
        res = []
        for x in state:
            if type(x[0]) == list:
                res.extend(flatten(x[0]))
            else:
                res.append(x[0])
        return list(set(x for x in res if x.startswith(target)))

    wrapper.__name__ = str('complete_' + func.__name__[3:])
    wrapper.__module__ = func.__module__
    wrapper.__doc__ = func.__doc__
    return wrapper
예제 #15
0
def test_parse_pattern():
    o = [Option("-h"), Option("-v", "--verbose"), Option("-f", "--file", 1)]
    assert parse_pattern("[ -h ]",
                         options=o) == Required(NotRequired(Option("-h")))
    assert parse_pattern("[ ARG ... ]", options=o) == Required(
        NotRequired(OneOrMore(Argument("ARG"))))
    assert parse_pattern("[ -h | -v ]", options=o) == Required(
        NotRequired(Either(Option("-h"), Option("-v", "--verbose"))))
    assert parse_pattern("( -h | -v [ --file <f> ] )", options=o) == Required(
        Required(
            Either(
                Option("-h"),
                Required(Option("-v", "--verbose"),
                         NotRequired(Option("-f", "--file", 1, None))))))
    assert parse_pattern("(-h|-v[--file=<f>]N...)", options=o) == Required(
        Required(
            Either(
                Option("-h"),
                Required(Option("-v", "--verbose"),
                         NotRequired(Option("-f", "--file", 1, None)),
                         OneOrMore(Argument("N"))))))
    assert parse_pattern("(N [M | (K | L)] | O P)", options=[]) == Required(
        Required(
            Either(
                Required(
                    Argument("N"),
                    NotRequired(
                        Either(Argument("M"),
                               Required(Either(Argument("K"),
                                               Argument("L")))))),
                Required(Argument("O"), Argument("P")),
            )))
    assert parse_pattern("[ -h ] [N]",
                         options=o) == Required(NotRequired(Option("-h")),
                                                NotRequired(Argument("N")))
    assert parse_pattern("[options]",
                         options=o) == Required(NotRequired(OptionsShortcut()))
    assert parse_pattern("[options] A",
                         options=o) == Required(NotRequired(OptionsShortcut()),
                                                Argument("A"))
    assert parse_pattern("-v [options]",
                         options=o) == Required(Option("-v", "--verbose"),
                                                NotRequired(OptionsShortcut()))
    assert parse_pattern("ADD", options=o) == Required(Argument("ADD"))
    assert parse_pattern("<add>", options=o) == Required(Argument("<add>"))
    assert parse_pattern("add", options=o) == Required(Command("add"))
예제 #16
0
            args['--template'] = f.read()
        if args['--header']:
            with open(template_h_path, 'r') as f:
                template_h = f.read()
    except IOError as e:
        sys.exit(e)

    doc = args['<docopt>']
    usage = docopt.parse_section('usage:', doc)
    s = ['More than one ', '"usage:" (case-insensitive)', ' not found.']
    usage = {0: s[1:], 1: usage[0] if usage else None}.get(len(usage), s[:2])
    if isinstance(usage, list):
        raise docopt.DocoptLanguageError(''.join(usage))

    all_options = docopt.parse_defaults(doc)
    pattern = docopt.parse_pattern(docopt.formal_usage(usage), all_options)
    leafs, commands, arguments, flags, options = parse_leafs(
        pattern, all_options)

    t_commands = ';\n    '.join('int %s' % c_name(cmd.name)
                                for cmd in commands)
    t_commands = (('\n    /* commands */\n    ' + t_commands +
                   ';') if t_commands != '' else '')
    t_arguments = ';\n    '.join('char *%s' % c_name(arg.name)
                                 for arg in arguments)
    t_arguments = (('\n    /* arguments */\n    ' + t_arguments +
                    ';') if t_arguments != '' else '')
    t_flags = ';\n    '.join('int %s' % c_name(flag.long or flag.short)
                             for flag in flags)
    t_flags = (('\n    /* options without arguments */\n    ' + t_flags +
                ';') if t_flags != '' else '')
예제 #17
0
def _parse_docopt(doc):
    options = docopt.parse_defaults(doc)
    pure_doc = docopt.formal_usage(docopt.printable_usage(doc))
    pattern = docopt.parse_pattern(pure_doc, options)
    return pattern
예제 #18
0
    return t % (('long' if o.long else 'short'), to_c(
        o.long or o.short), c_name(o.long or o.short))


def c_if_not_flag(o):
    t = """ else if (o->option.argument && strcmp(o->option.o%s, %s) == 0) {
            args.%s = o->option.argument;\n        }"""
    return t % (('long' if o.long else 'short'), to_c(
        o.long or o.short), c_name(o.long or o.short))


if __name__ == '__main__':
    help_message = sys.stdin.read()
    usage_pattern = printable_usage(help_message)
    options = parse_doc_options(help_message)
    formal_pattern = parse_pattern(formal_usage(usage_pattern),
                                   options=options)
    formal_pattern.fix()

    out = __doc__
    out = out.replace(
        '<<<flag_options>>>',
        ';\n    '.join('int %s' % c_name(o.long or o.short) for o in options
                       if o.argcount == 0))
    out = out.replace(
        '<<<options_with_arguments>>>',
        ';\n    '.join('char *%s' % c_name(o.long or o.short) for o in options
                       if o.argcount == 1))
    out = out.replace('<<<help_message>>>', to_c(help_message))
    out = out.replace('<<<usage_pattern>>>', to_c(usage_pattern))
    out = out.replace(
        '<<<defaults>>>', ', '.join(
예제 #19
0
파일: docopt_c.py 프로젝트: docopt/docopt.c
        if args["--template"] is None:
            args["--template"] = os.path.join(os.path.dirname(os.path.realpath(__file__)), "template.c")
        with open(args["--template"], "r") as f:
            args["--template"] = f.read()
    except IOError as e:
        sys.exit(e)

    doc = args["<docopt>"]
    usage = docopt.parse_section("usage:", doc)
    s = ["More than one ", '"usage:" (case-insensitive)', " not found."]
    usage = {0: s[1:], 1: usage[0] if usage else None}.get(len(usage), s[:2])
    if isinstance(usage, list):
        raise docopt.DocoptLanguageError("".join(usage))

    all_options = docopt.parse_defaults(doc)
    pattern = docopt.parse_pattern(docopt.formal_usage(usage), all_options)
    leafs, commands, arguments, flags, options = parse_leafs(pattern, all_options)

    t_commands = ";\n    ".join("int %s" % c_name(cmd.name) for cmd in commands)
    t_commands = ("\n    /* commands */\n    " + t_commands + ";") if t_commands != "" else ""
    t_arguments = ";\n    ".join("char *%s" % c_name(arg.name) for arg in arguments)
    t_arguments = ("\n    /* arguments */\n    " + t_arguments + ";") if t_arguments != "" else ""
    t_flags = ";\n    ".join("int %s" % c_name(flag.long or flag.short) for flag in flags)
    t_flags = ("\n    /* options without arguments */\n    " + t_flags + ";") if t_flags != "" else ""
    t_options = ";\n    ".join("char *%s" % c_name(opt.long or opt.short) for opt in options)
    t_options = ("\n    /* options with arguments */\n    " + t_options + ";") if t_options != "" else ""
    t_defaults = ", ".join(to_c(leaf.value) for leaf in leafs)
    t_defaults = re.sub(r'"(.*?)"', r'(char*) "\1"', t_defaults)
    t_defaults = "\n        ".join(textwrap.wrap(t_defaults, 72))
    t_defaults = ("\n        " + t_defaults + ",") if t_defaults != "" else ""
    t_elems_cmds = ",\n        ".join([c_command(cmd) for cmd in (commands)])
예제 #20
0
def test_parse_pattern():
    o = [Option('-h'), Option('-v', '--verbose'), Option('-f', '--file', 1)]
    assert parse_pattern('[ -h ]', options=o) == \
               Required(Optional(Option('-h')))
    assert parse_pattern('[ ARG ... ]', options=o) == \
               Required(Optional(OneOrMore(Argument('ARG'))))
    assert parse_pattern('[ -h | -v ]', options=o) == \
               Required(Optional(Either(Option('-h'),
                                Option('-v', '--verbose'))))
    assert parse_pattern('( -h | -v [ --file <f> ] )', options=o) == \
               Required(Required(
                   Either(Option('-h'),
                          Required(Option('-v', '--verbose'),
                               Optional(Option('-f', '--file', 1, None))))))
    assert parse_pattern('(-h|-v[--file=<f>]N...)', options=o) == \
               Required(Required(Either(Option('-h'),
                              Required(Option('-v', '--verbose'),
                                  Optional(Option('-f', '--file', 1, None)),
                                     OneOrMore(Argument('N'))))))
    assert parse_pattern('(N [M | (K | L)] | O P)', options=[]) == \
               Required(Required(Either(
                   Required(Argument('N'),
                            Optional(Either(Argument('M'),
                                            Required(Either(Argument('K'),
                                                            Argument('L')))))),
                   Required(Argument('O'), Argument('P')))))
    assert parse_pattern('[ -h ] [N]', options=o) == \
               Required(Optional(Option('-h')),
                        Optional(Argument('N')))
    assert parse_pattern('[options]', options=o) == \
            Required(Optional(OptionsShortcut()))
    assert parse_pattern('[options] A', options=o) == \
            Required(Optional(OptionsShortcut()),
                     Argument('A'))
    assert parse_pattern('-v [options]', options=o) == \
            Required(Option('-v', '--verbose'),
                     Optional(OptionsShortcut()))
    assert parse_pattern('ADD', options=o) == Required(Argument('ADD'))
    assert parse_pattern('<add>', options=o) == Required(Argument('<add>'))
    assert parse_pattern('add', options=o) == Required(Command('add'))
예제 #21
0
def main():
    args = docopt.docopt(__doc__)

    try:
        if args['<docopt>'] is not None:
            with open(args['<docopt>'], 'r') as f:
                args['<docopt>'] = f.read()
        elif args['<docopt>'] is None and sys.stdin.isatty():
            print(__doc__.strip("\n"))
            sys.exit("")
        else:
            args['<docopt>'] = sys.stdin.read()
    except IOError as e:
        sys.exit(e)

    doc = args['<docopt>']
    usage = parse_section('usage:', doc)
    s = ['More than one ', '"usage:" (case-insensitive)', ' not found.']
    usage = {0: s[1:], 1: usage[0] if usage else None}.get(len(usage), s[:2])
    if isinstance(usage, list):
        raise docopt.DocoptLanguageError(''.join(usage))

    options = docopt.parse_defaults(doc)

    pattern = docopt.parse_pattern(docopt.formal_usage(usage), options)

    fsm = ragel_ast(pattern)
    leafs, commands, arguments, flags, options = parse_leafs(pattern)

    command_fields = '\n    '.join(
        map(lambda c: 'int {0};'.format(clean_name(c)), commands))
    flag_fields = '\n    '.join(
        map(lambda c: 'int {0};'.format(clean_name(c)), flags))
    option_fields = '\n    '.join(
        map(lambda c: 'char* {0};'.format(clean_name(c)), options))
    argument_fields = '\n    '.join(
        map(lambda c: 'char* {0};'.format(clean_name(c)), arguments))

    command_actions = '\n    '.join(
        map(
            lambda c: 'action command_{0}{{ fsm->opt->{0} = 1; }}'.format(
                clean_name(c)), commands))
    flag_actions = '\n    '.join(
        map(
            lambda c: 'action option_{0}{{ fsm->opt->{0} = 1; }}'.format(
                clean_name(c)), flags))
    option_actions = '\n    '.join(
        map(
            lambda c:
            'action option_{0}{{ fsm->opt->{0} = strdup(fsm->buffer); }}'.
            format(clean_name(c)), options))
    argument_actions = '\n    '.join(
        map(
            lambda c:
            'action argument_{0}{{ fsm->opt->{0} = strdup(fsm->buffer); }}'.
            format(clean_name(c)), arguments))

    options_with_defaults = filter(lambda x: x.value is not None, options)
    option_defaults = '\n    '.join(
        map(
            lambda c: 'fsm->opt->{0} = strdup("{1}");'.format(
                clean_name(c), c.value), options_with_defaults))

    usage = '\n    '.join(
        map(lambda l: 'fprintf(stdout, "{0}\\n");'.format(l), doc.split('\n')))

    file = os.path.join(os.path.dirname(os.path.realpath(__file__)),
                        "template.rl")
    print(
        Template(open(file).read()).safe_substitute(
            fsm=fsm,
            usage=usage,
            command_fields=command_fields,
            flag_fields=flag_fields,
            option_fields=option_fields,
            argument_fields=argument_fields,
            command_actions=command_actions,
            flag_actions=flag_actions,
            option_actions=option_actions,
            argument_actions=argument_actions,
            option_defaults=option_defaults,
        ))
예제 #22
0
def test_parse_pattern():
    o = [Option('-h'), Option('-v', '--verbose'), Option('-f', '--file', 1)]
    assert parse_pattern('[ -h ]', options=o) == \
               Required(Optional(Option('-h', None, 0, True)))
    assert parse_pattern('[ ARG ... ]', options=o) == \
               Required(Optional(OneOrMore(Argument('ARG'))))
    assert parse_pattern('[ -h | -v ]', options=o) == \
               Required(Optional(Either(Option('-h', None, 0, True),
                                Option('-v', '--verbose', 0, True))))
    assert parse_pattern('( -h | -v [ --file f.txt ] )', options=o) == \
               Required(Required(
                   Either(Option('-h', None, 0, True),
                          Required(Option('-v', '--verbose', 0, True),
                               Optional(Option('-f', '--file', 1, 'f.txt'))))))
    assert parse_pattern('(-h|-v[--file=f.txt]N...)', options=o) == \
               Required(Required(Either(Option('-h', None, 0, True),
                              Required(Option('-v', '--verbose', 0, True),
                                  Optional(Option('-f', '--file', 1, 'f.txt')),
                                     OneOrMore(Argument('N'))))))
    assert parse_pattern('(N [M | (K | L)] | O P)', options=[]) == \
               Required(Required(Either(
                   Required(Argument('N'),
                            Optional(Either(Argument('M'),
                                            Required(Either(Argument('K'),
                                                            Argument('L')))))),
                   Required(Argument('O'), Argument('P')))))
    assert parse_pattern('[ -h ] [N]', options=o) == \
               Required(Optional(Option('-h', None, 0, True)),
                        Optional(Argument('N')))
    assert parse_pattern('[options]', options=o) == Required(
                Optional(AnyOptions()))
    assert parse_pattern('[options] A', options=o) == Required(
                Optional(AnyOptions()),
                Argument('A'))
    assert parse_pattern('-v [options]', options=o) == Required(
                Option('-v', '--verbose', 0, True),
                Optional(AnyOptions()))

    assert parse_pattern('ADD', options=o) == Required(Argument('ADD'))
    assert parse_pattern('<add>', options=o) == Required(Argument('<add>'))
    assert parse_pattern('add', options=o) == Required(Command('add'))
예제 #23
0
def main():
    assert __doc__ is not None
    args = docopt.docopt(__doc__)

    try:
        if args['<docopt>'] is not None:
            with open(args['<docopt>'], 'r') as f:
                args['<docopt>'] = f.read()
        elif args['<docopt>'] is None and sys.stdin.isatty():
            print(__doc__.strip("\n"))
            sys.exit("")
        else:
            args['<docopt>'] = sys.stdin.read()
        if args['--template'] is None:
            args['--template'] = template_c
        else:
            with open(args['--template'], 'rt') as f:
                args['--template'] = f.read()
        if args['--template-header'] is None:
            args['--template-header'] = template_h
        else:
            with open(args['--template-header'], 'rt') as f:
                args['--template-header'] = f.read()
    except IOError as e:
        sys.exit(e)

    doc = args['<docopt>']
    usage = docopt.parse_section('usage:', doc)
    error_str_l = 'More than one ', '"usage:" (case-insensitive)', ' not found.'
    usage = {0: error_str_l[1:], 1: usage[0] if usage else None}.get(len(usage), error_str_l[:2])
    if isinstance(usage, list):
        raise docopt.DocoptLanguageError(''.join(usage))

    all_options = docopt.parse_defaults(doc)
    pattern = docopt.parse_pattern(docopt.formal_usage(usage), all_options)
    leafs, commands, arguments, flags, options = parse_leafs(pattern, all_options)

    _indent = ' ' * 4

    t_commands = ';\n{indent}'.format(indent=_indent).join('size_t {!s}'.format(c_name(cmd.name))
                                                           for cmd in commands)
    t_commands = '\n{indent}/* commands */\n{indent}{t_commands};'.format(indent=_indent, t_commands=t_commands) \
        if t_commands != '' else ''
    t_arguments = ';\n{indent}'.join('char *{!s}'.format(c_name(arg.name))
                                     for arg in arguments)
    t_arguments = '\n{indent}/* arguments */\n{indent}{t_arguments};'.format(indent=_indent, t_arguments=t_arguments) \
        if t_arguments != '' else ''
    t_flags = ';\n{indent}'.format(indent=_indent).join('size_t {!s}'.format(c_name(flag.long or flag.short))
                                                        for flag in flags)
    t_flags = '\n{indent}/* options without arguments */\n{indent}{t_flags};'.format(indent=_indent, t_flags=t_flags) \
        if t_flags != '' else ''
    t_options = ';\n{indent}'.format(indent=_indent).join('char *{!s}'.format(c_name(opt.long or opt.short))
                                                          for opt in options)
    t_options = '\n{indent}/* options with arguments */\n{indent}{t_options};'.format(indent=_indent,
                                                                                      t_options=t_options) \
        if t_options != '' else ''
    t_defaults = ', '.join(to_c(leaf.value) for leaf in leafs)
    t_defaults = re.sub(r'"(.*?)"', r'(char *) "\1"', t_defaults)
    t_defaults = '\n{indent}'.format(indent=_indent * 2).join(textwrap.wrap(t_defaults, 72))
    t_defaults = '\n{indent}{t_defaults},'.format(indent=_indent * 2, t_defaults=t_defaults) if t_defaults != '' else ''
    t_elems_cmds = ',\n{indent}'.format(indent=_indent * 2).join(c_command(cmd) for cmd in commands)
    t_elems_cmds = '\n{indent}{t_elems_cmds}'.format(indent=_indent * 2,
                                                     t_elems_cmds=t_elems_cmds) if t_elems_cmds != '' else ''
    t_elems_args = ',\n{indent}'.format(indent=_indent * 2).join(c_argument(arg) for arg in arguments)
    t_elems_args = '\n{indent}{t_elems_args}'.format(indent=_indent * 2,
                                                     t_elems_args=t_elems_args) if t_elems_args != '' else ''
    t_elems_opts = ',\n{indent}'.format(indent=_indent * 2).join(c_option(o) for o in (flags + options))
    t_elems_opts = '\n{indent}{t_elems_opts}'.format(indent=_indent * 2,
                                                     t_elems_opts=t_elems_opts) if t_elems_opts != '' else ''

    '''
    t_elems_n_commands = str(len(commands))
    t_elems_n_arguments = str(len(arguments))
    t_elems_n_options = str(len(flags + options))
    t_elems_n_cmds = str(len(commands))
    t_elems_n = ', '.join(str(len(l)) for l in (commands, arguments, (flags + options)))
    print(
        't_elems_n_commands:', t_elems_n_commands, ';\n',
        't_elems_n_arguments:', t_elems_n_arguments, ';\n',
        't_elems_n_options:', t_elems_n_options, ';\n',
        't_elems_n_cmds:', t_elems_n_cmds, ';\n',
        't_elems_n:', t_elems_n, ';'
    )
    '''

    t_if_command = ' else '.join(c_if_command(command) for command in commands)
    t_if_command = '\n{indent}{t_if_command}'.format(indent=_indent * 2,
                                                     t_if_command=t_if_command) if t_if_command != '' else ''
    t_if_argument = ' else '.join(c_if_argument(arg) for arg in arguments)
    t_if_argument = '\n{indent}{t_if_argument}'.format(
        indent=_indent * 2,
        t_if_argument='\n{indent}'.format(indent=_indent * 2).join(t_if_argument.splitlines())
    ) if t_if_argument != '' else ''
    t_if_flag = ''.join('\n{indent}'.format(indent=_indent * 2).join(c_if_flag(flag).splitlines())
                        for flag in flags)
    t_if_option = ''.join(
        '\n{indent}'.format(indent=_indent * 2).join(c_if_option(opt).splitlines())
        for opt in options
    )

    if not args['--output-name']:
        header_output_name = '<stdout>'
    else:
        base, ext = os.path.splitext(args['--output-name'])
        if ext not in frozenset(('.h', '.c')):
            base = args['--output-name']

        args['--output-name'] = "{base}.c".format(base=base)
        header_output_name = "{base}.h".format(base=base)

    header_name = os.path.basename(header_output_name)

    doc = doc.splitlines()
    doc_n = len(doc)

    template_out = Template(args['--template']).safe_substitute(
        help_message='\n{indent}'.format(indent=_indent).join(to_initializer(doc).splitlines()),
        help_message_n=doc_n,
        usage_pattern='\n{indent}'.format(indent=_indent * 2).join(to_c(usage).splitlines()),
        if_flag=t_if_flag,
        if_option=t_if_option,
        if_command=t_if_command,
        if_argument=t_if_argument,
        defaults=t_defaults,
        elems_cmds=null_if_zero(t_elems_cmds),
        elems_args=null_if_zero(t_elems_args),
        elems_opts=null_if_zero(t_elems_opts),
        t_elems_n_commands=str(len(commands)),
        t_elems_n_arguments=str(len(arguments)),
        t_elems_n_options=str(len(flags + options)),
        header_name=header_name
    )

    template_header_out = Template(args['--template-header']).safe_substitute(
        commands=t_commands,
        arguments=t_arguments,
        flags=t_flags,
        options=t_options,
        help_message_n=doc_n,
        # nargs=t_nargs
    ).replace('$header_no_ext', os.path.splitext(header_name)[0].upper())

    if args['--output-name'] is None:
        print(template_out.strip(), '\n')
    else:
        try:
            with open(sys.stdout if args['--output-name'] in (None, "<stdout>") else args['--output-name'], 'w') as f:
                f.write(template_out.strip() + '\n')

            with open(sys.stdout if header_output_name == "<stdout>" else header_output_name, 'w') as f:
                f.write(template_header_out.strip() + '\n')

        except IOError as e:
            sys.exit(str(e))
def test_parse_pattern():
    o = [Option("-h"), Option("-v", "--verbose"), Option("-f", "--file", 1)]
    assert parse_pattern("[ -h ]", options=o) == Required(Optional(Option("-h")))
    assert parse_pattern("[ ARG ... ]", options=o) == Required(Optional(OneOrMore(Argument("ARG"))))
    assert parse_pattern("[ -h | -v ]", options=o) == Required(
        Optional(Either(Option("-h"), Option("-v", "--verbose")))
    )
    assert parse_pattern("( -h | -v [ --file <f> ] )", options=o) == Required(
        Required(Either(Option("-h"), Required(Option("-v", "--verbose"), Optional(Option("-f", "--file", 1, None)))))
    )
    assert parse_pattern("(-h|-v[--file=<f>]N...)", options=o) == Required(
        Required(
            Either(
                Option("-h"),
                Required(
                    Option("-v", "--verbose"), Optional(Option("-f", "--file", 1, None)), OneOrMore(Argument("N"))
                ),
            )
        )
    )
    assert parse_pattern("(N [M | (K | L)] | O P)", options=[]) == Required(
        Required(
            Either(
                Required(
                    Argument("N"), Optional(Either(Argument("M"), Required(Either(Argument("K"), Argument("L")))))
                ),
                Required(Argument("O"), Argument("P")),
            )
        )
    )
    assert parse_pattern("[ -h ] [N]", options=o) == Required(Optional(Option("-h")), Optional(Argument("N")))
    assert parse_pattern("[options]", options=o) == Required(Optional(AnyOptions()))
    assert parse_pattern("[options] A", options=o) == Required(Optional(AnyOptions()), Argument("A"))
    assert parse_pattern("-v [options]", options=o) == Required(Option("-v", "--verbose"), Optional(AnyOptions()))
    assert parse_pattern("ADD", options=o) == Required(Argument("ADD"))
    assert parse_pattern("<add>", options=o) == Required(Argument("<add>"))
    assert parse_pattern("add", options=o) == Required(Command("add"))
예제 #25
0
def main():
    args = docopt.docopt(__doc__, version='none')

    with open(args['<docopt_file>'], 'r') as f:
        args['<docopt_file>'] = f.read()

    template_h_name = args['--template_h']
    template_c_name = args['--template_c']

    args['template_h_obj'] = read_template_file_contents(args['--template_h'])
    args['template_c_obj'] = read_template_file_contents(args['--template_c'])

    doc = args['<docopt_file>']
    usage = docopt.printable_usage(doc)
    all_options = docopt.parse_defaults(doc)
    pattern = docopt.parse_pattern(docopt.formal_usage(usage), all_options)
    prompt = usage.split()[1].strip()

    usage_lines = [x.replace(prompt, "") for x in usage.split('\n')[1:]]

    tokens = []
    commands = []
    # I'm not sure why we have to reach in here, but it "works"
    required_commands = pattern.children[0].children
    for idx, required in enumerate(required_commands):
        parts = [
            o.name for o in required.children if isinstance(o, docopt.Command)
        ]
        if not parts:
            continue
        # "help" is a special case? So exclude?
        if "help" in parts:
            continue
        tokens.extend(parts)
        docopt_text = usage_lines[idx].strip(
        ) if idx < len(usage_lines) else None
        commands.append(Command(parts, docopt_text))

    if args['--short'] is not None:
        doc = doc.replace(prompt + " ", args['--short'] + " ")

    rendering = Rendering(args['<module_name>'], commands, prompt, doc,
                          args['--multithreaded'])

    if len(rendering.tokens) > 64:
        raise docopt.DocoptExit(
            'Too many unique tokens ({}) for Docopt μC (max:64)'.format(
                len(rendering.tokens)))

    too_long_commands = []
    for cmd in rendering.commands:
        if len(cmd.parts) > 6:
            too_long_commands.append(cmd)

    if too_long_commands:
        summaries = [
            ' > {}'.format(" ".join(p for p in c.parts))
            for c in too_long_commands
        ]

        raise docopt.DocoptExit('\n'.join([
            'The following commands are too long for Docopt μC (max: 6 long):'
        ] + summaries))

    output_h_filename = args['--template_h'].replace(args['--template_prefix'],
                                                     rendering.include_name)
    output_c_filename = args['--template_c'].replace(args['--template_prefix'],
                                                     rendering.include_name)

    output_h_filename = os.path.join(args['--output_dir'], output_h_filename)
    output_c_filename = os.path.join(args['--output_dir'], output_c_filename)

    with open(output_h_filename, 'w') as f:
        f.write(args['template_h_obj'].render(rendering=rendering))

    with open(output_c_filename, 'w') as f:
        f.write(args['template_c_obj'].render(rendering=rendering))

    if args["--no-docopt-args-h"] is False:
        # copy the docopt header file to the output directory
        docopt_args = pkg_resources.resource_filename(
            __name__, 'templates/docopt_args.h')
        shutil.copy2(docopt_args, args['--output_dir'])
예제 #26
0
                c_name(o.long or o.short))


def c_if_not_flag(o):
    t = """ else if (o->option.argument && strcmp(o->option.o%s, %s) == 0) {
            args.%s = o->option.argument;\n        }"""
    return t % (('long' if o.long else 'short'),
                to_c(o.long or o.short),
                c_name(o.long or o.short))


if __name__ == '__main__':
    help_message=sys.stdin.read()
    usage_pattern = printable_usage(help_message)
    options = parse_doc_options(help_message)
    formal_pattern = parse_pattern(formal_usage(usage_pattern), options=options)
    formal_pattern.fix()

    out = __doc__
    out = out.replace('<<<flag_options>>>',
                      ';\n    '.join('int %s' % c_name(o.long or o.short)
                                     for o in options if o.argcount == 0))
    out = out.replace('<<<options_with_arguments>>>',
                      ';\n    '.join('char *%s' % c_name(o.long or o.short)
                                     for o in options if o.argcount == 1))
    out = out.replace('<<<help_message>>>', to_c(help_message))
    out = out.replace('<<<usage_pattern>>>', to_c(usage_pattern))
    out = out.replace('<<<defaults>>>',
                      ', '.join(to_c(o.value) for o in
                                sorted(options, key=lambda o: o.argcount)))
    out = out.replace('<<<options>>>',