Rectangle 27 7

Sample solution using docopt (file managelog.py):

argparse
  • explain the usage to the user in a way which is easy to understand
  • allow combining with other parameters (like file name or names).
$ python managelog.py
Usage:
    managelog.py [options] process -- <logfile>...
    managelog.py [options] upload -- <logfile>...
    managelog.py [options] process upload -- <logfile>...
    managelog.py -h
$ python managelog.py -h
Manage logfiles
Usage:
    managelog.py [options] process -- <logfile>...
    managelog.py [options] upload -- <logfile>...
    managelog.py [options] process upload -- <logfile>...
    managelog.py -h

Options:
    -V, --verbose      Be verbose
    -U, --user <user>  Username
    -P, --pswd <pswd>  P    managelog.py [options] upload -- <logfile>...

Manage log file by processing and/or uploading it.
If upload requires authentication, you shall specify <user> and <password>
$ python managelog.py -V -U user -P secret upload -- alfa.log beta.log
{'--': True,
 '--pswd': 'secret',
 '--user': 'user',
 '--verbose': True,
 '-h': False,
 '<logfile>': ['alfa.log', 'beta.log'],
 'process': False,
 'upload': True}
"""Manage logfiles
Usage:
    short.py [options] (process|upload)... -- <logfile>...
    short.py -h

Options:
    -V, --verbose      Be verbose
    -U, --user <user>  Username
    -P, --pswd <pswd>  Password

Manage log file by processing and/or uploading it.
If upload requires authentication, you shall specify <user> and <password>
"""
if __name__ == "__main__":
    from docopt import docopt
    args = docopt(__doc__)
    print args
$ python short.py -V process upload  -- alfa.log beta.log
{'--': True,
 '--pswd': None,
 '--user': None,
 '--verbose': True,
 '-h': False,
 '<logfile>': ['alfa.log', 'beta.log'],
 'process': 1,
 'upload': 1}

Note, that instead of boolean values for "process" and "upload" keys there are counters.

It turns out, we cannot prevent duplication of these words:

$ python short.py -V process process upload  -- alfa.log beta.log
{'--': True,
 '--pswd': None,
 '--user': None,
 '--verbose': True,
 '-h': False,
 '<logfile>': ['alfa.log', 'beta.log'],
 'process': 2,
 'upload': 1}

Designing good command line interface can be challenging sometime.

There are multiple aspects of command line based program:

argparse offers a lot, but restricts possible scenarios and can become very complex.

With docopt things go much shorter while preserving readability and offering high degree of flexibility. If you manage getting parsed arguments from dictionary and do some of conversions (to integer, opening files..) manually (or by other library called schema), you may find docopt good fit for command line parsing.

Never heard of docopt, great suggestion!

@TonvandenHeuvel Good. I just want to confirm, I am still using it as my preferred solution for command line interfaces.

Python argparse: Make at least one argument required - Stack Overflow

python argparse
Rectangle 27 33

This should get more attention.

while this is a worthwhile comment, it still is a comment more than an answer.. no downvote but no upvote for me either! Expand your answer with a valuable summary of the article to make it into a real answer!: meta.stackexchange.com/a/8259/172394

python - Why use argparse rather than optparse? - Stack Overflow

python command-line optparse getopt argparse
Rectangle 27 33

This should get more attention.

while this is a worthwhile comment, it still is a comment more than an answer.. no downvote but no upvote for me either! Expand your answer with a valuable summary of the article to make it into a real answer!: meta.stackexchange.com/a/8259/172394

python - Why use argparse rather than optparse? - Stack Overflow

python command-line optparse getopt argparse
Rectangle 27 2

The exception you want is in docopt's namespace. You never import it into your global namespace, so you can't refer to it simply with it's name. You need to import it separately or refer to it through the module. You also shouldn't use parenthesis after the exception.

import docopt

try:
    # stuff
except docopt.DocoptExit:
    # other stuff
import docopt
from docopt import DocoptExit

try:
    # stuff
except DocoptExit:
    # other stuff

Cheers Roger, I actually had that setup originally, can't remember why I changed... But that parts working now thanks, It prints 'this hasn't worked' which is what I told it to (not sure if there's a built in error message) I'm still not sure how to add multiple compulsory arguments though. I've updated the code to how It currently looks

@user3130747 It's probably best if you leave the code as it originally was. Changing it will confuse anyone else coming here afterwards with a similar question. If you have other questions related the code, it is best to make a new question and describe the new issue there.

Oh right, good point... The questions were part of the OP though, I'm struggling to work out how to set up the arguments, should I make another post for this? Cheers

@user3130747 I suggest reverting the code to how it was and perhaps editing the question to be specifically about the DocoptExit error. That's how I read the question at least. Then making a separate question about the other issue, with specific examples of how you tried to accomplish it and issues you've been having.

Agreed with Roger. I didn't even realize you were having other issues until I read this comment, @user3130747

Docopt - Errors, exit undefined - CLI interface for Python programme -...

python command-line-interface docopt
Rectangle 27 6

argparse is in the python default library, so this doesn't add any extra dependencies to your program. The differences are mainly the way of writing your code. Using argparse it is possible to add hooks for plugins so they can add their own argumnets to your program. For example flake8 uses this.

docopt is a third party module provides a simple way of parsing arguments. I personally like docopt because of its simplicity, but I'm not saying it is the best to use in all cases. In their documentation they mention that using docopt it is possible to use more combinations of argument passing than when using argparse.

command line arguments - Python - Difference between docopt and argpar...

python command-line-arguments argparse docopt
Rectangle 27 6

argparse is in the python default library, so this doesn't add any extra dependencies to your program. The differences are mainly the way of writing your code. Using argparse it is possible to add hooks for plugins so they can add their own argumnets to your program. For example flake8 uses this.

docopt is a third party module provides a simple way of parsing arguments. I personally like docopt because of its simplicity, but I'm not saying it is the best to use in all cases. In their documentation they mention that using docopt it is possible to use more combinations of argument passing than when using argparse.

command line arguments - Python - Difference between docopt and argpar...

python command-line-arguments argparse docopt
Rectangle 27 1

#![allow(unstable)]

extern crate docopt;

use docopt::Docopt;

static USAGE: &'static str = "
Naval Fate.

Usage:
    naval_fate ship --dir=FILE [--speed <kn>]
    naval_fate (-h | --help)

Options:
    -h --help     Show this screen.
    --speed <kn>  Speed in knots [default: 10].
    --dir=FILE    Moored (anchored) mine.
";

fn main() {
    let args = Docopt::new(USAGE)
                      .and_then(|d| d.parse())
                      .unwrap_or_else(|e| e.exit());
    println!("Type of 'ship': {:?}", args.find("ship"));
    println!("Type of '--dir': {:?}", args.find("--dir"));
    println!("Type of '--speed': {:?}", args.find("--speed"));
}
$ ./target/scratch ship --dir /tmp --speed 1234                                        
Type of 'ship': Some(Switch(true))                                                                       
Type of '--dir': Some(Plain(Some("/tmp")))                                                               
Type of '--speed': Some(Plain(Some("1234")))

The key is that the return type of find is Value, which is an algebraic data type: http://burntsushi.net/rustdoc/docopt/enum.Value.html --- So by construction, you get the "type" of the argument for free.

Note that this will work for any "argument" in the Docopt usage string, even if it isn't passed into the argument list.

Note that this does not tell you whether the argument was a DIR or FILE...

Maybe I misinterpreted the question? The OP just wants the string of the argument?

Yes, I think we mean the same thing. I am indeed looking for determine that the options are DIR and FILE. For future readers: Note that I've simplified the original example, hence why BurntSushi5's example does not correspond 100% to the question.

python - Parsing docopt argument types (any language) - Stack Overflow

python go rust docopt
Rectangle 27 1

You can specify them in a separate part of the __doc__ , as an Example -

Test Control Program

Usage: 
  test.py bitwrite ([--off=<bits>...][--on=<bits>...])
  test.py regwrite ([regA | regB]<value>)

Options:
  -o <bits>... --off <bits>...  #Turn bits off
  -i <bits>... --on <bits>...   #Turns bits on

Arguments:

      bits: 1 - on
            0 - off

Please note Arguments is not any special name recognized by docopt , its just any name, you can use any such appropriate name you want.

In the above the Arguments section would show the valid values for bits, and other arguments .

Then when running the above doc with --help option, you would get result as -

>>>> python a.py --help
Test Control Program

Usage:
  test.py bitwrite ([--off=<bits>...][--on=<bits>...])
  test.py regwrite ([regA | regB]<value>)

Options:
  -o <bits>... --off <bits>...  #Turn bits off
  -i <bits>... --on <bits>...   #Turns bits on

Arguments:

      bits: 1 - on
            0 - off

If you want to show the complete __doc__ without having to specify the --help or -h option, you can catch DocoptExit exception when calling the docopt() function and print the __doc__ at that time.

"""Test Control Program

Usage: 
  test.py bitwrite ([--off=<bits>...][--on=<bits>...])
  test.py regwrite ([regA | regB]<value>)

Options:
  -o <bits>... --off <bits>...  #Turn bits off
  -i <bits>... --on <bits>...   #Turns bits on

Arguments:

      bits: 1 - on
            0 - off

"""
from docopt import docopt, DocoptExit


if __name__ == '__main__':
    try:
        arguments = docopt(__doc__, version='Test Control Program')
        print(arguments)
    except DocoptExit:
        print(__doc__)

python - Specify valid values for arguments using docopt - Stack Overf...

python docopt
Rectangle 27 2

I'd suggest to use http://docopt.org/. There's a scala-port but the Java implementation https://github.com/docopt/docopt.java works just fine and seems to be better maintained. Here's an example:

import org.docopt.Docopt

import scala.collection.JavaConversions._
import scala.collection.JavaConverters._

val doc =
"""
Usage: my_program [options] <input>

Options:
 --sorted   fancy sorting
""".stripMargin.trim

//def args = "--sorted test.dat".split(" ").toList
var results = new Docopt(doc).
  parse(args()).
  map {case(key, value)=>key ->value.toString}

val inputFile = new File(results("<input>"))
val sorted = results("--sorted").toBoolean

scala - Best way to parse command-line parameters? - Stack Overflow

scala command-line command-line-parsing
Rectangle 27 2

I'd suggest to use http://docopt.org/. There's a scala-port but the Java implementation https://github.com/docopt/docopt.java works just fine and seems to be better maintained. Here's an example:

import org.docopt.Docopt

import scala.collection.JavaConversions._
import scala.collection.JavaConverters._

val doc =
"""
Usage: my_program [options] <input>

Options:
 --sorted   fancy sorting
""".stripMargin.trim

//def args = "--sorted test.dat".split(" ").toList
var results = new Docopt(doc).
  parse(args()).
  map {case(key, value)=>key ->value.toString}

val inputFile = new File(results("<input>"))
val sorted = results("--sorted").toBoolean

scala - Best way to parse command-line parameters? - Stack Overflow

scala command-line command-line-parsing
Rectangle 27 1

You'll not get docopt to do this, as the comma separated list is just considered a optional argument. But you could easily do it yourself afterwards:

"""
Example of program with many options using docopt.

Usage:
  myprogram.py -a NUMBERS

Options:
  -h --help            show this help message and exit
  -a NUMBERS           Comma separated list of numbers
"""

from docopt import docopt

if __name__ == '__main__':
    args = docopt(__doc__, version='1.0.0rc2')
    args['-a'] = [int(x) for x in args['-a'].split(',')]
    print(args)

python - How do I make an argument with unknown n number of values sto...

python command-line command-line-interface docopt
Rectangle 27 1

You'll not get docopt to do this, as the comma separated list is just considered a optional argument. But you could easily do it yourself afterwards:

"""
Example of program with many options using docopt.

Usage:
  myprogram.py -a NUMBERS

Options:
  -h --help            show this help message and exit
  -a NUMBERS           Comma separated list of numbers
"""

from docopt import docopt

if __name__ == '__main__':
    args = docopt(__doc__, version='1.0.0rc2')
    args['-a'] = [int(x) for x in args['-a'].split(',')]
    print(args)

python - How do I make an argument with unknown n number of values sto...

python command-line command-line-interface docopt
Rectangle 27 4

For reference, the official docs can be found here at github.

To answer your specific question, you can use an ellipse ... with your optional option [--my-option] and specify that your option takes an argument.

[--my-option=ARG]...
[--my-option=<arg>]...
"""
Usage:
    my_program [--comment=ARG]... FILE

Arguments:
    FILE       An argument for passing in a file.

Options:
    --comment  Zero or more comments
"""

By specifying it as [--comment=<arg>]... you ensure that opt['--comment'] is a list of all the specified comments.

my_program --comment=ASDF --comment=QWERTY my_file
if __name__ == '__main__':
    opts = docopt(__doc__)
    opts['--comment'] == ['ASDF', 'QWERTY']
    opts['FILE'] == 'my_file'

python - How to specify one optional argument several times in docopt ...

python docopt
Rectangle 27 10

At first I was as reluctant as @fmark to switch from optparse to argparse, because:

  • I thought the difference was not that huge.

Then I saw this doc, argparse outperforms optparse, especially when talking about generating meaningful help message: http://argparse.googlecode.com/svn/trunk/doc/argparse-vs-optparse.html

And then I saw "argparse vs. optparse" by @Nicholas, saying we can have argparse available in python <2.7 (Yep, I didn't know that before.)

Now my two concerns are well addressed. I wrote this hoping it will help others with a similar mindset.

python - Why use argparse rather than optparse? - Stack Overflow

python command-line optparse getopt argparse
Rectangle 27 10

At first I was as reluctant as @fmark to switch from optparse to argparse, because:

  • I thought the difference was not that huge.

Then I saw this doc, argparse outperforms optparse, especially when talking about generating meaningful help message: http://argparse.googlecode.com/svn/trunk/doc/argparse-vs-optparse.html

And then I saw "argparse vs. optparse" by @Nicholas, saying we can have argparse available in python <2.7 (Yep, I didn't know that before.)

Now my two concerns are well addressed. I wrote this hoping it will help others with a similar mindset.

python - Why use argparse rather than optparse? - Stack Overflow

python command-line optparse getopt argparse
Rectangle 27 0

Refer the below example :-

% python prog.py '1 2 4 5'
import sys
my_list = sys.argv[1].split() 
print my_list

python - How do I make an argument with unknown n number of values sto...

python command-line command-line-interface docopt
Rectangle 27 0

At the time being, here's a solution I'm thinking of being like:

"""\
This is the docstring
"""

import docopt
if __name__ == "__main__":
    try:
        args = docopt.docopt(_("{docstring}").format(docstring=__doc__))
    except KeyError:
        args = docopt.docopt(_("{docstring}")) # string which will be replaced by the i18ned one.

I don't find that elegant, because even though exceptions are ok in python, I think that they should be kept for something exceptional not something in the use case of the application.

It's also being a pretty naughty hack that will get the docstring format in the gettext instead of the __docopt__ text which won't help translators as they will have to get back to source code...

python - How to have the docstring respect the PEP257, while usable wi...

python internationalization gettext docstring docopt
Rectangle 27 0

if __name__ == "__main__":
    if hasattr(vars()['__builtins__'], '_') and not 'NullTranslations' in str(_):
        args = docopt.docopt(_("USAGE MESSAGE"))
    else:
        args = docopt.docopt(__doc__)

which is not using an exception, but tests for typing using the string representation of a method, and looksup that method in the builtins module... Which is not really better than the other option.

And that one is also a pretty bad and unelegant hack, because translators will have to refer to the source code to look up the doc string. Or I'll have to have two times the contents of the docstring in the code.

python - How to have the docstring respect the PEP257, while usable wi...

python internationalization gettext docstring docopt
Rectangle 27 0

Sample solution using docopt (file managelog.py):

argparse
  • explain the usage to the user in a way which is easy to understand
  • allow combining with other parameters (like file name or names).
$ python managelog.py
Usage:
    managelog.py [options] process -- <logfile>...
    managelog.py [options] upload -- <logfile>...
    managelog.py [options] process upload -- <logfile>...
    managelog.py -h
$ python managelog.py -h
Manage logfiles
Usage:
    managelog.py [options] process -- <logfile>...
    managelog.py [options] upload -- <logfile>...
    managelog.py [options] process upload -- <logfile>...
    managelog.py -h

Options:
    -V, --verbose      Be verbose
    -U, --user <user>  Username
    -P, --pswd <pswd>  P    managelog.py [options] upload -- <logfile>...

Manage log file by processing and/or uploading it.
If upload requires authentication, you shall specify <user> and <password>
$ python managelog.py -V -U user -P secret upload -- alfa.log beta.log
{'--': True,
 '--pswd': 'secret',
 '--user': 'user',
 '--verbose': True,
 '-h': False,
 '<logfile>': ['alfa.log', 'beta.log'],
 'process': False,
 'upload': True}
"""Manage logfiles
Usage:
    short.py [options] (process|upload)... -- <logfile>...
    short.py -h

Options:
    -V, --verbose      Be verbose
    -U, --user <user>  Username
    -P, --pswd <pswd>  Password

Manage log file by processing and/or uploading it.
If upload requires authentication, you shall specify <user> and <password>
"""
if __name__ == "__main__":
    from docopt import docopt
    args = docopt(__doc__)
    print args
$ python short.py -V process upload  -- alfa.log beta.log
{'--': True,
 '--pswd': None,
 '--user': None,
 '--verbose': True,
 '-h': False,
 '<logfile>': ['alfa.log', 'beta.log'],
 'process': 1,
 'upload': 1}

Note, that instead of boolean values for "process" and "upload" keys there are counters.

It turns out, we cannot prevent duplication of these words:

$ python short.py -V process process upload  -- alfa.log beta.log
{'--': True,
 '--pswd': None,
 '--user': None,
 '--verbose': True,
 '-h': False,
 '<logfile>': ['alfa.log', 'beta.log'],
 'process': 2,
 'upload': 1}

Designing good command line interface can be challenging sometime.

There are multiple aspects of command line based program:

argparse offers a lot, but restricts possible scenarios and can become very complex.

With docopt things go much shorter while preserving readability and offering high degree of flexibility. If you manage getting parsed arguments from dictionary and do some of conversions (to integer, opening files..) manually (or by other library called schema), you may find docopt good fit for command line parsing.

Never heard of docopt, great suggestion!

@TonvandenHeuvel Good. I just want to confirm, I am still using it as my preferred solution for command line interfaces.

Python argparse: Make at least one argument required - Stack Overflow

python argparse
Rectangle 27 0

How to use docopt [Python]

"""Usage: print.py --count=N [--caps] TEXT...

Arguments:
    TEXT  Message to be printed

Options:
    --count=N  number of times the message will be output
    --caps  convert the text to upper case
"""

# Docopt is a library for parsing command line arguments
import docopt

if __name__ == '__main__':
    print "This example demonstrates basic usage of docopt"
    print "You can run this script manually by using:"
    print "  python app.py --caps --count=3 Hello world"
    print ""

    try:
        # Parse arguments, use file docstring as a parameter definition
        arguments = docopt.docopt(__doc__)

        # Count is a mandatory option, caps is optional
        count = int(arguments['--count'])
        caps = arguments['--caps']

        for i in range(count):
            # In the definition, we expect one or more TEXT parameters
            # Each parameter is a word, or a text in quotes: "something like this"
            # If the user forgets about the quote, the program would print only "something"
            # Thus, we merge all the specified parameters with space
            text = ' '.join(arguments['TEXT'])
            if(caps):
                print text.upper()
            else:
                print text

    # Handle invalid options
    except docopt.DocoptExit as e:
        print e.message
Python docopt