casperdcl / argopt

convert docopt to argparse
https://pypi.python.org/pypi/argopt
Other
21 stars 2 forks source link

Errors with a complicated docstring #2

Closed GhostofGoes closed 6 years ago

GhostofGoes commented 6 years ago

I've been evaluating argopt, and while it's worked great for most of the scripts, the main entry point has been throwing some errors.

Full docstring:


"""ADLES: Automated Deployment of Lab Environments System.
Uses formal YAML specifications to create virtual environments for educational purposes.

Usage:
    adles [options] [-]
    adles [options] [-t TYPE] -c SPEC [-]
    adles [options] (-m | -d) [-p] -s SPEC [-]
    adles [options] (--cleanup-masters | --cleanup-enviro) [--nets] -s SPEC [-]

Arguments:
    -n, --no-color          Do not color terminal output
    -v, --verbose           Emit debugging logs to terminal
    -c, --validate SPEC     Validates syntax of an exercise specification
    -t, --type TYPE         Type of specification to validate: exercise, package, infra
    -s, --spec SPEC         Name of a YAML specification file
    -i, --infra FILE        Override infra spec with the one in FILE
    -p, --package           Build environment from package specification
    -m, --masters           Master creation phase of specification
    -d, --deploy            Environment deployment phase of specification
    --cleanup-masters       Cleanup masters created by a specification
    --cleanup-enviro        Cleanup environment created by a specification
    --nets                  Cleanup networks created during either phase
    --print-spec NAME       Prints the named specification: exercise, package, infrastructure
    --list-examples         Prints the list of examples available
    --print-example NAME    Prints the named example
    -h, --help              Shows this help
    --version               Prints current version

Examples:
    adles --list-examples
    adles -c examples/tutorial.yaml
    adles --verbose --masters --spec examples/experiment.yaml
    adles -vds examples/competition.yaml
    adles --cleanup-masters --nets -s examples/competition.yaml
    adles --print-example competition | adles -v -c -

License:    Apache 2.0
Author:     Christopher Goes <goesc@acm.org>
Project:    https://github.com/GhostofGoes/ADLES

"""

This will throw the following error:


cmd>adles --help
Traceback (most recent call last):
  File "C:\Users\goesc\AppData\Local\Programs\Python\Python36-32\Scripts\adles-script.py", line 11, in <module>
    load_entry_point('ADLES==1.4.1', 'console_scripts', 'adles')()
  File "C:\Users\goesc\AppData\Local\Programs\Python\Python36-32\lib\site-packages\adles-1.4.1-py3.6.egg\adles\scripts\adles_main.py", line 72, in main
    args = get_args(__doc__, __version__, 'adles.log')
  File "C:\Users\goesc\AppData\Local\Programs\Python\Python36-32\lib\site-packages\adles-1.4.1-py3.6.egg\adles\utils.py", line 47, in wrapper
    ret = func(*args, **kwargs)
  File "C:\Users\goesc\AppData\Local\Programs\Python\Python36-32\lib\site-packages\adles-1.4.1-py3.6.egg\adles\utils.py", line 285, in get_args
    parser = argopt(docstring, version=version)
  File "C:\Users\goesc\AppData\Local\Programs\Python\Python36-32\lib\site-packages\argopt\_argopt.py", line 141, in argopt
    args, opts = docopt_parser(doc, **_kwargs)
  File "C:\Users\goesc\AppData\Local\Programs\Python\Python36-32\lib\site-packages\argopt\_argopt.py", line 59, in docopt_parser
    str_pattern = str(pattern)
  File "C:\Users\goesc\AppData\Local\Programs\Python\Python36-32\lib\site-packages\argopt\_docopt.py", line 152, in __repr__
    ', '.join(repr(a) for a in self.children))
  File "C:\Users\goesc\AppData\Local\Programs\Python\Python36-32\lib\site-packages\argopt\_docopt.py", line 152, in <genexpr>
    ', '.join(repr(a) for a in self.children))
  File "C:\Users\goesc\AppData\Local\Programs\Python\Python36-32\lib\site-packages\argopt\_docopt.py", line 152, in __repr__
    ', '.join(repr(a) for a in self.children))
  File "C:\Users\goesc\AppData\Local\Programs\Python\Python36-32\lib\site-packages\argopt\_docopt.py", line 152, in <genexpr>
    ', '.join(repr(a) for a in self.children))
  File "C:\Users\goesc\AppData\Local\Programs\Python\Python36-32\lib\site-packages\argopt\_docopt.py", line 152, in __repr__
    ', '.join(repr(a) for a in self.children))
  File "C:\Users\goesc\AppData\Local\Programs\Python\Python36-32\lib\site-packages\argopt\_docopt.py", line 152, in <genexpr>
    ', '.join(repr(a) for a in self.children))
  File "C:\Users\goesc\AppData\Local\Programs\Python\Python36-32\lib\site-packages\argopt\_docopt.py", line 152, in __repr__
    ', '.join(repr(a) for a in self.children))
  File "C:\Users\goesc\AppData\Local\Programs\Python\Python36-32\lib\site-packages\argopt\_docopt.py", line 152, in <genexpr>
    ', '.join(repr(a) for a in self.children))
  File "C:\Users\goesc\AppData\Local\Programs\Python\Python36-32\lib\site-packages\argopt\_docopt.py", line 120, in __repr__
    self.value, self.type)
AttributeError: 'Command' object has no attribute 'type'

I tried removing the [-] at the end of each option string, changing the usage section to this:


Usage:
    adles [options]
    adles [options] [-t TYPE] -c SPEC
    adles [options] (-m | -d) [-p] -s SPEC
    adles [options] (--cleanup-masters | --cleanup-enviro) [--nets] -s SPEC

This causes get the following error:


Traceback (most recent call last):
  File "C:\Users\goesc\AppData\Local\Programs\Python\Python36-32\Scripts\adles-script.py", line 11, in <module>
    load_entry_point('ADLES==1.4.1', 'console_scripts', 'adles')()
  File "C:\Users\goesc\AppData\Local\Programs\Python\Python36-32\lib\site-packages\adles-1.4.1-py3.6.egg\adles\scripts\adles_main.py", line 72, in main
    args = get_args(__doc__, __version__, 'adles.log')
  File "C:\Users\goesc\AppData\Local\Programs\Python\Python36-32\lib\site-packages\adles-1.4.1-py3.6.egg\adles\utils.py", line 47, in wrapper
    ret = func(*args, **kwargs)
  File "C:\Users\goesc\AppData\Local\Programs\Python\Python36-32\lib\site-packages\adles-1.4.1-py3.6.egg\adles\utils.py", line 285, in get_args
    parser = argopt(docstring, version=version)
  File "C:\Users\goesc\AppData\Local\Programs\Python\Python36-32\lib\site-packages\argopt\_argopt.py", line 181, in argopt
    parser.add_argument(o.short, o.name, **k)
  File "C:\Users\goesc\AppData\Local\Programs\Python\Python36-32\lib\argparse.py", line 1348, in add_argument
    return self._add_action(action)
  File "C:\Users\goesc\AppData\Local\Programs\Python\Python36-32\lib\argparse.py", line 1711, in _add_action
    self._optionals._add_action(action)
  File "C:\Users\goesc\AppData\Local\Programs\Python\Python36-32\lib\argparse.py", line 1552, in _add_action
    action = super(_ArgumentGroup, self)._add_action(action)
  File "C:\Users\goesc\AppData\Local\Programs\Python\Python36-32\lib\argparse.py", line 1362, in _add_action
    self._check_conflict(action)
  File "C:\Users\goesc\AppData\Local\Programs\Python\Python36-32\lib\argparse.py", line 1501, in _check_conflict
    conflict_handler(action, confl_optionals)
  File "C:\Users\goesc\AppData\Local\Programs\Python\Python36-32\lib\argparse.py", line 1510, in _handle_conflict_error
    raise ArgumentError(action, message % conflict_string)
argparse.ArgumentError: argument -v/--verbose: conflicting option strings: -v, --verbose

The actual string it errors on will vary between "-t, --type", "-n, --no-color", and a few others.

Changing the usage to this:

Usage:
    adles [options]

Works without issues, and gives the following (mostly) correct output:


cmd>adles --help
usage: adles [-h] [--print-example NAME] [-i FILE] [-t TYPE]
             [--print-spec NAME] [-c SPEC] [--version] [--nets] [-p] [-s SPEC]
             [--list-examples] [-n] [-m] [-d] [--cleanup-enviro]
             [--cleanup-masters] [-v]

ADLES: Automated Deployment of Lab Environments System. Uses formal YAML
specifications to create virtual environments for educational purposes.

optional arguments:
  -h, --help            show this help message and exit
  --print-example NAME  Prints the named example
  -i FILE, --infra FILE
                        Override infra spec with the one in FILE
  -t TYPE, --type TYPE  Type of specification to validate: exercise, package,
                        infra
  --print-spec NAME     Prints the named specification: exercise, package,
                        infrastructure
  -c SPEC, --validate SPEC
                        Validates syntax of an exercise specification
  --version             show program's version number and exit
  --nets                Cleanup networks created during either phase
  -p, --package         Build environment from package specification
  -s SPEC, --spec SPEC  Name of a YAML specification file
  --list-examples       Prints the list of examples available
  -n, --no-color        Do not color terminal output
  -m, --masters         Master creation phase of specification
  -d, --deploy          Environment deployment phase of specification
  --cleanup-enviro      Cleanup environment created by a specification
  --cleanup-masters     Cleanup masters created by a specification
  -v, --verbose         Emit debugging logs to terminal

The code that does argument handling:


def get_args(docstring, version, logging_filename):
    """
    Handles commandline argument parsing and logging setup.

    :param str docstring: docopt-formatting docstring
    :param str version: version string
    :param str logging_filename: Name of file to save logs to
    :return: Commandline arguments the user provided
    :rtype: dict
    """
    # from docopt import docopt
    from argopt import argopt

    # Handle case where user provides no arguments
    if len(sys.argv) == 1:
        sys.argv.append("--help")

    # Get and process commandline arguments
    # args = docopt(docstring, version=version, help=True)
    parser = argopt(docstring, version=version)
    args = parser.parse_args()
    print(args)
    exit(0)

    # Set if console output should be colored
    # colors = (False if args["--no-color"] else True)
    colors = (False if args.no_color else True)

    # Configure logging globally
    setup_logging(filename=logging_filename, colors=colors,
                  console_verbose=args.verbose)  # args["--verbose"]
    return args

If helpful, the project source code is available here: https://github.com/GhostofGoes/ADLES

I've had zero issues with docopt, and it's (as far as I know) valid syntax.

Is this a bug with argopt, or am I simply not using the library properly?

casperdcl commented 6 years ago

Interesting. What version of docopt was working for you? argopt should be a superset of docopt 0.6.2

GhostofGoes commented 6 years ago

I'm working with docopt 0.6.2

casperdcl commented 6 years ago

Just tried and tested this and I observe the same behaviour. But it seems all expected behaviour to me.

Works without issues, and gives the following (mostly) correct output:

What's incorrect/unexpected with the output? What would "the correct" output be?

GhostofGoes commented 6 years ago

There should be an epilog with the examples and project information that follow the optional arguments section.

This is the text that should be there:

Examples:
    adles --list-examples
    adles -c examples/tutorial.yaml
    adles --verbose --masters --spec examples/experiment.yaml
    adles -vds examples/competition.yaml
    adles --cleanup-masters --nets -s examples/competition.yaml
    adles --print-example competition | adles -v -c -

License:    Apache 2.0
Author:     Christopher Goes <goesc@acm.org>
Project:    https://github.com/GhostofGoes/ADLES
casperdcl commented 6 years ago

ok fixed in the devel branch now. Could you try it out (e.g.: pip install -e git+https://github.com/casperdcl/argopt.git@devel#egg=argopt)?

You'll still just require

Usage:
    adles [options]

or at least remove the [-] at the end of your usages.

GhostofGoes commented 6 years ago

Sorry for the delay, had the flu for the past week. I'll give it a try when I get a chance. And yeah, agree on removing the [-].

casperdcl commented 6 years ago

it's merged in the latest release

GhostofGoes commented 6 years ago

Just tested against latest release. It works like a charm after removing the [-]. Thank you!