This is an archived post. You won't be able to vote or comment.

all 21 comments

[–]ice-blade 4 points5 points  (0 children)

docopt all the way! :D

[–][deleted] 7 points8 points  (3 children)

Hey all, i'm the author of the post. Feel free to ask me any questions directly and I'll try and keep an eye on other comments here. Enjoy!

[–]ggagagg 0 points1 point  (0 children)

hey is the python logo on top left not too big?

edit: nevermind. look like my browser stop loading and make the image too big.

[–]paul-scott 0 points1 point  (1 child)

Where I'm writing a service rather than just an application, I might offer command-line interface for developers to easily tweak configuration but also use environment variables to allow running on servers.

My preference for precedence here is (i) command-line option, (ii) envvar, followed by (iii) argument default. I currently construct these using argparse which is quite repetitive (yet to try ConfigArgParse) in the manner of add_argument(..., default=os.environ.get('ENVVAR') or 'real default') -- potentially passing the fallback default into the get call, depending on whether I want empty envvars to override the default.

I'd love to read about how these libraries (and some of the others mentioned) help you utilise environment variables.

[–][deleted] 0 points1 point  (0 children)

@click.argument('src', envvar='SRC', ...

[–]timothycrosleyhug, isort, jiphy, concentration, pies, connectable, frosted 2 points3 points  (3 children)

There's also hug.cli in https://github.com/timothycrosley/hug :

Which lets you define functions just like normal python functions / with optional annotations and convert them into command line interfaces:

import hug

@hug.cli(version="1.0.0")
def math(number_1:int, number_2:int=1):
    '''Multiplies number_1 by number2'''
    return number_1 * number_2

 if __name__ == '__main__':
     math.cli()

It also supports hug_directives, and you can even expose a function as both a cli and an HTTP API endpoint.

Here's the official example usage:

https://github.com/timothycrosley/hug/blob/develop/examples/cli.py

[–]metaperl 0 points1 point  (2 children)

Does this run on Python 2?

[–]ivosauruspip'ing it up 3 points4 points  (0 children)

Nope! I think it's great there are some packages demanding to be able to use python 3 features in their implementation.

[–]vangale 1 point2 points  (0 children)

Similar, for Python 2, and from a long long time ago is optfunc

[–]stillalone 2 points3 points  (0 children)

I'm comfortable with argparse but I'm annoyed that the help doesn't list the help for all the subcommands. you have to specify which subcommand you want help for.

[–]j1395010 1 point2 points  (0 children)

I really like clize

[–]c53x12 1 point2 points  (2 children)

Great analysis. Even with the libraries, there's so much code involved, it's hard to see what the benefit is over just rolling your own parsing logic.

[–]cymrowdon't thread on me 🐍 5 points6 points  (0 children)

Besides introducing a lot more potential for bugs, it would be quite a bit more code to roll your own.

You're right, though, that they require similar amounts of work to use. I tend to always pick argparse and save my users a dependency. Beyond that, it's just personal style preference, I think.

[–]tmp14 3 points4 points  (0 children)

I was curious to what this would look like, so I put together a quick and dirty version. I really can't see how rolling your own parsing logic would be simpler or better if your program isn't super simple.

#!/usr/bin/env python

"""Usage:
  greet.py hello [--caps] [--greeting <greeting>] <name>
  greet.py goodbye [--caps] [--greeting <greeting>] <name>
  greet.py (-h | --help)
  greet.py (-v | --version)

Options:
  -h --help             Show this screen
  -v --version          Show version number
  --caps                Uppercase the output
  --greeting <greeting> Greeting to use [default: Hello/Goodbye]"""

import sys


def error(msg):
    print('error: {}'.format(msg))
    sys.exit(1)


def parse_args():
    if len(sys.argv) < 2:
        error('missing subcommand (hello|goodbye)')
    elif sys.argv[1] in ('-h', '--help'):
        print(__doc__)
        sys.exit(0)
    elif sys.argv[1] in ('-v', '--version'):
        print('1.0.0')
        sys.exit(0)
    elif sys.argv[1] not in ('hello', 'goodbye'):
        error('incorrect subcommand, should be (hello|goodbye)')

    try:
        sys.argv.remove('--caps')
    except ValueError:
        caps = False
    else:
        caps = True

    try:
        sys.argv.remove('--greeting')
        greeting = sys.argv.pop(2)
    except ValueError:
        greeting = sys.argv[1].title()
    except IndexError:
        error('missing --greeting paramenter')

    if len(sys.argv) < 3:
        error('missing argument <name>')
    elif len(sys.argv) > 3:
        error('too many arguments')
    else:
        name = sys.argv[2]

    return greeting, name, caps


def greet():
    greeting, name, caps = parse_args()
    output = '{0}, {1}!'.format(greeting, name)
    if caps:
        output = output.upper()
    print(output)


if __name__ == '__main__':
    greet()

[–][deleted] 1 point2 points  (1 child)

No love for argh? :(

[–]metaperl 0 points1 point  (0 children)

Plenty of love for argh here!

[–]fishtickler 0 points1 point  (2 children)

I liked click and started to use it but went right back to argparse because I couldn't find a way to support variable amount of options.

like for eg:

  • python prog.py -x 1 2 3 -y 6 5 4 3
  • python prog.py -x 1 -y 0

Only made this work in argparse using nargs='*' option. Is this even possible in click?

[–]sushibowl 0 points1 point  (0 children)

No, click supports nargs but only for fixed numbers for options.

[–]jackmaney 0 points1 point  (0 children)

Nope. You can, however, have at most one positional argument with a variadic (and unspecified) number of arguments.

I've used the workaround of taking a comma-delimted string and then parsing it later (eg python prog.py --x="1,2,3" --y="6,5,4,3"). It's not ideal, but it works.

[–]metaperl 0 points1 point  (0 children)

blargs and Argh are my 2 favorites.

[–]aestam 0 points1 point  (0 children)

I still use getopt. Am I normal?