EzDev.org

docopt

Pythonic command line arguments parser, that will make you smile docopt—language for description of command-line interfaces


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

I'm sure that the answer for this is out there, but I've read the site info, I've watched the video they made and I've tried to find a really basic tutorial but I can't. I've been messing about with this for most of the day and It's not really making sense to me.

Here's my error:

vco@geoHP:~$ python3 a_blah.py "don't scare the cats" magic
Traceback (most recent call last):
  File "a_blah.py", line 20, in <module>
    arguments = docopt.docopt(__doc__)
  File "/usr/lib/python3/dist-packages/docopt.py", line 579, in docopt
    raise DocoptExit()
docopt.DocoptExit: Usage: 
    a_blah.py <start>... <end>

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "a_blah.py", line 33, in <module>
    except DocoptExit:
NameError: name 'DocoptExit' is not defined

line 20 - I don't see why that line is creating an error, it worked before and I've seen that exact line in others programmes?

I don't know why the line 570 of docopt is creating an error - I've seen others use DocoptExit(), isn't this something that's just part of Docopt? Do I have to write my own exit function for this? (I've not seen anyone else do that)

here's the code

import docopt

if __name__ == '__main__':

    try:
        arguments = docopt.docopt(__doc__)

        print(arguments['<start>'])

        print("that was that")

        print(arguments['<end>'])       

    except docopt.DocoptExit:
        print("this hasn't worked")

What I'm trying to make this for is a script that I've written that moves files from one place to another based on their extension.

So the arguments at the command line will be file type, start directory, destination directory, and an option to delete them from the start directory after they've been moved.

I'm trying (and failing) to get docopt working on it's own prior to including it in the other script though.


Source: (StackOverflow)

Cronjob with docopt

I have a really simple code with docopt which creates a directory. The program works perfectly like this:

dbb create_dir

I need to run this using crontab in ubuntu 12.04. I used crontab -e and added this line:

0 14 * * * dbb create_dir

which should run the code on 2pm every day. My problem is this doesn't work. I checked

0 14 * * * mkdir test_dir

and it worked. So I thought the problem is not with the cron and as I could run the code without cron, I guess the main problem is the combiniation of these two. Is there any way to fix this? Thanx


Source: (StackOverflow)

Docopt isn't setting defaults

I have a bash script that uses docopts. It works beautifully on my Debian machine, but fails to set defaults on my Ubuntu laptop. Here's the docopts code:

eval "$(docopts -A args -V - -h - : "$@" <<EOF
Usage: cmus_select.sh [--list <tag>] [--random] [--structure=</alt/dir/structure>] [--dir=/path/to/music]

  -h --help                Show help
  -r --random              Randomize selection instead of using a dmenu
  -l --list TAG            List music by tag.  Unless you use -s, genre, artist, album, and song are expected. [default: song]
  -s --structure STRUCT    Directory structure for your music.  [default: genre/artist/album/song]
  -d --dir DIR             Location of music [default: $HOME/Music/]
----
cmus_select.sh 0.0.1
EOF
)"
  • I found the two spaces requirement and already checked that (not sure if stackoverflow formatting will eat the spaces.)
  • Both machines use docopts 0.6.1+fix. The debian machine uses bash 4.2.37 and python 2.7.3. The ubuntu machine is on 4.2.45 and 2.7.5+.
  • I tried a variety of ways to describe the options. Different order of -l/--list. = sign between the option and its variable. Var name in angle brackets. Etc. It reliably works in debian and not in Ubuntu.

-- followup--

I encountered the same problem on a debian testing machine. Docopts is looking for a new maintainer so I gave up. As an alternative I wrote https://raw.github.com/sagotsky/.dotfiles/612fe9e5c4aa7e1fae268810b24f8f80960a6d66/scripts/argh.sh which is smaller than docopts but does what I need.


Source: (StackOverflow)

docopt.go weird error message

using docopt.go to refactor an old project and minimalise code the program looks like this

package main

import (
    "fmt"
    "github.com/docopt/docopt.go"
)

const Version = `2.0`
const Usage = `
Usage:
    serve [--port] <dir>
    serve help | --help
    serve --version 

Options:
    -p, --port       port for the sever to listen on
    -h, --help       display help information
    -v, --version    display Version
`

func check(err error) {
    if err != nil {
        panic(err)
    }
}

func main() {
    args, err := docopt.Parse(Usage, nil, true, Version, false)
    check(err)

    port := args["[--port]"].(string)

    fmt.Println(args)
    fmt.Println(port)v
}

however when I run the program go run ./serve.go help expecting the help message i get this

panic: interface conversion: interface is nil, not string

goroutine 1 [running]:
main.main()
    /Users/jburns/Development/Gopath/src/github.com/nyumal/serve/serve.go:31 +0x148

goroutine 2 [runnable]:
runtime.forcegchelper()
    /usr/local/Cellar/go/1.4.1/libexec/src/runtime/proc.go:90
runtime.goexit()
    /usr/local/Cellar/go/1.4.1/libexec/src/runtime/asm_amd64.s:2232 +0x1

goroutine 3 [runnable]:
runtime.bgsweep()
    /usr/local/Cellar/go/1.4.1/libexec/src/runtime/mgc0.go:82
runtime.goexit()
    /usr/local/Cellar/go/1.4.1/libexec/src/runtime/asm_amd64.s:2232 +0x1

goroutine 4 [runnable]:
runtime.runfinq()
    /usr/local/Cellar/go/1.4.1/libexec/src/runtime/malloc.go:712
runtime.goexit()
    /usr/local/Cellar/go/1.4.1/libexec/src/runtime/asm_amd64.s:2232 +0x1
exit status 2

and running go run ./serve.go --port 5000 it returns the same thing however running go run ./serve.go --port 5000 . return

Usage:
    serve [--port] <dir>
    serve help | --help
    serve --version
exit status 1

where did i go wrong?


Source: (StackOverflow)

docopt arguments parsing: how to avoid spaghetti code?

It's the first time I use docopt and I'm struggling with the args parsing for a small command line program I'm trying to realize.

    '''Usage:
    ovh_mails.py list [--ugly]
    ovh_mails.py add (<address> [--pswd=<password>][--description=<description>] | --file <filename>)
    ovh_mails.py remove (<address> | --file <filename>)
    ovh_mails.py (-h | --help)

Arguments:
    <password>                        Password to access the mailbox (if not provided it's random generated)
    <filename>                        Name of the files to process. Check README to see how to format it

Options: 
    -h, --help                        Show this help message
    -u, --ugly                        Print without nice tables
    -p, --pswd=<password>  Set the password to the one provided

Commands:
    list                              list all the email addresses currently configured
    add                               add one or more (configured in <filename>) email addresses
    remove                            remove one ore more (configured in <filename>) email addresses'''

The parsing of the arguments I have at the moment is:

if __name__ == '__main__':
args = docopt(__doc__)
#Validate args ---- TODO

# 'List' command parsing
if args['list']:
    if args['--ugly']:
        eman = EmailManager(niceoutput=False)
    else:
        eman = EmailManager()
    eman.list_emails()
# 'Add' command parsing
elif args['add']:
    if args['<address>']:
        eman = EmailManager()
        emails = (
                  {
                   'address': args['<address>'],
                   'password': None,
                   'description': None,
                   },
                  )
        if args['--description']:
            emails[0]['description'] = args['<description>']
        if args['--pswd']:
            emails[0]['password'] = args['<password>']
    if args['--file']:
        raise NotImplemented


    eman.add_emails(emails)


# 'remove' command parsing       
elif args['remove']:
    if args['<address>']:
        eman = EmailManager()
        emails = (
                  {
                   'address': args['<address>'],
                   },
                  )
    eman.remove_emails(emails)
    if args['--file']:
        raise NotImplemented

Is there a better, more pythonic ore more elegant way, to do this?


Source: (StackOverflow)

Using docopt double dash option with optional parameter?

Using docopt, is there a way to make a double-dashed parameter that works with and without an equals sign?

I want both of the following commands to make --tls be true:

cmd --tls
cmd --tls=true

I seem to only be able to get one or the other to work by using

Options:
  --tls

or

Options:
  --tls=false                  

Separating them by a comma does not seem to work

Options:
  --tls, --tls=false                  

Source: (StackOverflow)

Parsing Docopt commands into components

I have a command which I use in docopt which looks like this:

cli.py argument_test (--required_id=<required_id> | --required_name=<required_name>) (--required=<required>) (--repeat=<repeat>)... (--required_named=<required_named> | <required_named>) (--thisflag | --thatflag) [--optionalflag] [--optional_named=<optional_named>]

I need some way of parsing this into a structure which could present the information like this (on a web page for example)

RequiredArguments: required_id or requiredname, required, repeat(list), required_named, thisflag(bool) or thatflag(bool)

OptionalArguments: optionalflag(bool), optionalnamed

bad ms paint image of what command might look like on a webpage

Docopt parses the pattern into an object with children which looks like the following:

Required(Command('argument_test', False), Required(Either(Option(None, '--required_id', 1, None), Option(None, '--required_name', 1, None))), Required(Option(None, '--required', 1, None)), OneOrMore(Required(Option(None, '--repeat', 1, []))), Required(Either(Option(None, '--required_named', 1, None), Argument('<required_named>', None))), Required(Either(Option(None, '--thisflag', 0, False), Option(None, '--thatflag', 0, False))), Optional(Option(None, '--optionalflag', 0, False)), Optional(Option(None, '--optional_named', 1, None)))))

I'm pretty stumped where to go from here in how I should go about parsing these. Any advice is appreciated!


Source: (StackOverflow)

how to get docopt default args when script loaded as module

I'm working on a large project with multiple authors, so I'm trying to avoid making too many changes. I have one script which uses docopt to pass options, and sets some of them to default values.

I loaded a class from that script by importing it as a module, but when I called a method, it failed because it expected a default option to be set by docopt, of which there are many. Is there a way to pull in the default options from docopt?


Source: (StackOverflow)

Docopt - Golang - How to access repeated arguments?

I'm trying to understand how to access multiple input arguments from docopt.Parse() output.

Example:

package main

import (
    "fmt"
    "github.com/docopt/docopt-go"
)

func main() {
    usage := `blah.go

  Usage: 
    blah.go read <file> ...
    blah.go -h | --help | --version`

    arguments, _ := docopt.Parse(usage, nil, true, "blah 1.0", false)
    x := arguments["<file>"]
    fmt.Println(x)
    fmt.Println(x)
}

Command Line:

$ go run blah.go read file1 file2
[file1 file2]
[file1 file2]

I'd like to print out only file1 or file2.

When I try adding:

fmt.Println(x[0])

I get the following error:

$ go run blah.go read file1 file2
# command-line-arguments
./blah.go:19: invalid operation: x[0] (index of type interface {})

https://github.com/docopt/docopt.go


Source: (StackOverflow)

Docopt accepts multi args in middle?

I want my script accepts command line args like "cp" command does:

'''
Usage:
cp.py <source>... <directory>
cp.py -t <directory> <source>...
cp.py -s <source>... -t <directory>
'''

Those command line

$ python cp.py src/path/1 src/path/2 target/path
$ python cp.py -t target/path src/path/1 src/path/2
$ python cp.py -s src/path/1 src/path/2 -t target/path

will get the same result:

{'<source>':['src/path/1', 'src/path/2'],'<directory>': 'target/path'}

Thx very much. And sorry for my English:)


Source: (StackOverflow)

How can text in the options configuration of Docopt be wrapped?

I have a few detailed option specifications in the docstring used for configuration of Docopt. Some of the items are quite lengthy. Is there a way of wrapping the text to make it more legible or to make it fit to a line width more easily?

Let's say the relevant bit of text in the docstring is the following:

Usage:
    program [options]

Options:
    -h, --help                      Show this help message.
    -c, --configuration=CONF        Configuration (file) [default: None]
    -f, --files=FILESLIST           Comma-delimited list of input data files [default: 169888_ttH_el.root]
    -v, --variables=VARIABLESLIST   Comma-delimited list of variables to plot [default: trk_pt]
    -t, --tree=TREE                 Tree in input data files [default: mini]
    -u, --username=USERNAME         Username
    -t, --topanalysis=DIRECTORY     Directory of TopRootCore or TopAnalysis [default: /home/user/Dropbox/TopAnalysis]
    -s, --superlongoption=TEST      This is a very long option that requires a bit of text to explain it. [default: 101001011011101010010100110101010]
    --version                       Show the version and exit.

Would it be possible wrap the text in a style something like the following?

Usage:
    program [options]

Options:
    -h, --help                      Show this help message.
    -c, --configuration=CONF        Configuration (file) [default: None]
    -f, --files=FILESLIST           Comma-delimited list of input data files
                                    [default: 169888_ttH_el.root]
    -v, --variables=VARIABLESLIST   Comma-delimited list of variables to plot
                                    [default: trk_pt]
    -t, --tree=TREE                 Tree in input data files [default: mini]
    -u, --username=USERNAME         Username
    -t, --topanalysis=DIRECTORY     Directory of TopRootCore or TopAnalysis
                                    [default: /home/user/Dropbox/TopAnalysis]
    -s, --superlongoption=TEST      This is a very long option that requires a
                                    bit of text to explain it.
                                    [default: 101001011011101010010100110101010]
    --version                       Show the version and exit.

Source: (StackOverflow)

docopt in python3 argumentes definitions

I'm trying to use docopt.

i want to call my program like this:

python3 my_script -p argum1 -d argum2 -u faculm

The -u is not mandatory, but "-p" and "-d" are mandatory.

i have allready made this:

""" 
Usage:
    passwdcrack.py -p=<password>, 
    passwdcrack.py -d=<dicionario>       
    passwdcrack.py [-u=<user>]        

Options:
    -h --help       mostra este ecrã
    --version       Mostra a versão
    -p=<password>   indicar o caminho para o ficheiro tipo */etc/shadow
    -d=<dicionario> indicar o caminho para o ficheiro com lista de Passw
    -u=<user>       indica o utilizador para ser analisado
"""
import docopt

if __name__ == '__main__':
    arguments = docopt.docopt(__doc__, version='0.0001')
    print (arguments)

but when i call it it gives me this:

$ python3 passwdcrack.py -d papa -d pfpf -u madona Traceback (most recent call last): File "passwdcrack.py", line 17, in arguments = docopt.docopt(doc, version='0.0001') AttributeError: 'module' object has no attribute 'docopt'

Can some one help me? thanks


Source: (StackOverflow)

How do I make a custom system command out of my Python program?

If I have a command-line program written in Python (specifically using docopt which uses argparse I think), and I want to run it as my-program command1 args instead of python my-program.py command1 args, what do I have to do? For now, this is for Debian-based OS (e.g Ubuntu).

I normally make my module a package so I already have setup.py but that doesn't grant me a free command.

Thanks!


EDIT

@pyrospade gave a very good link below. I am going to share my result.

Suppose we have

top-level-directory
    setup.py
    package/
         __init__.py
         cli.py

You can use scripts=['package/cli.py'] if you want to access cli.py in the shell.

If you want to run as my-cli, you can use

entry_points={
    'console_scripts':
        ['my-cli=package.cli:main']
}

Since I use docopt, I have this

def dispatcher(...)
def fun1(....)


def main():    
    arguments = docopt(COMMAND, version="xxxx")
    dispatcher(arguments)

if __name__ == '__main__':
    main()

You can even put it under __init__.py by saying ['my-cli=package:main'] but again, you need a function called main(). But you can name it whatever you want. Just saying.


Source: (StackOverflow)

docopt positional arguments not working

When followint the docopt README, I would expect the following file to produce some valid output:

#!/usr/bin/env python
"""Example file.

Usage:

  test_docopt.py test
  test_docopt.py (-h | --help)
  test_docopt.py --version

Options:
  -h --help                       Show this screen
  --version                       Show version.

"""

import pkg_resources
pkg_resources.require("docopt==0.6.1")
from docopt import docopt

if __name__ == '__main__':
    args = docopt(__doc__, version="Extend limb profiles 0.1")
    print(args)

However, when I call test_docopt.py, I only get a meaningless/empty Usage statement:

$ python test_docopt.py test
Usage:

My two questions are:

  • Why is docopt apparently failing to recognize the test command?
  • Why isn't the Usage pattern filled with the actual usage pattern?

Source: (StackOverflow)

Make docopt parse arguments containing spaces in unit tests

I am having issues getting docopt to parse arguments that contain spaces into a proper dictionary object for use with my unit tests.

Here is the code I'm currently using to construct the argument list for docopt to parse:

testargs = []

def clear_args():
    testargs[:] = []
    return

def add_testfiles(file1='defaultfile1.txt', file2='defaultfile2.txt'):
    clear_args()
    testargs.append('--debug')
    testargs.append(file1)
    testargs.append(file2)
    return

def parse_args(optlist):
    argstr = ' '.join(optlist)
    return docopt(downpost.__doc__, argv=argstr)

The code I am writing unit tests for has 2 tests that are separately given the following arguments:

-t <title>  # <title> can be any string (with spaces) inside quotation marks
"A Filename with Spaces.txt"  # any filename as long as it's in quotation marks

To add, for example, the -t argument, I would do:

def test_exampleunittest(self):
    add_testfiles()
    testargs.append('-t "This is the title I want"')
    self.args = parse_args(testargs)
    self.post = myPythonScript.process(self.args)
    self.assertEqual(self.post['Subject'], 'This is the title I want')

If I run the script I'm testing by itself with the said arguments, they are accepted without any problems and the output is as expected.

However, if I run the unit tests which use arguments containing spaces, I get the following:

DocoptExit: Usage: myPythonScript [options] <file_1> <file_2>

Other unit tests that require the same dict object (containing the same arguments) work fine.

What should I change in my code to make docopt parse the arguments as it normally does?


Source: (StackOverflow)