EzDevInfo.com

docopt

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

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)

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)

Advertisements

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 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)

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)

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)

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 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)

How to prevent docopt from swallowing an option?

I'm trying to create a command-line interface using docopt. Here is a simplified version of my file:

#!/usr/bin/env python
"""
Test program.

Usage:
  test.py [options]

Options:
  -a <input>    
  -b
  -c
  -d
"""
import docopt

print docopt.docopt(__doc__)

I essentially want to be able to specify any of the options, in any order. However, if I forget to specify the argument for the -a flag, then I get an output like this:

$ python test.py -a -b -c
{"-a": "-b",
 "-b": False,
 "-c": True,
 "-d": False}

Docopt is treating the -b flag as the argument for the -a flag, instead of rejecting the input as invalid. Is there some easy way to detect this, or make docopt refuse to accept this sort of malformed input?


Source: (StackOverflow)

How to pass more than one arguments with docopt

I want to pass two mandatory argument, one optional argument to my program using docopt. The code I am using is:

"""Setup

Usage: myprog.py server_name config [--help] [options] 

Arguments:
    SERVER_NAME        Server Name (a1, a2)
    CONFIG             Config file with full path

Options:
    -h --help
    -r --start      Start the server if yes [default: 'no']
"""

from docopt import docopt

class ServerSetup(object):
    def __init__(self, server_name, config_file, start_server):
        self.server = server_name
        self.config = config_file
        self.start_server = start_server

    def print_msg(self):
        print self.server
        print self.config
        print self.start_server

if __name__ == '__main__':
    args = docopt(__doc__)
    setup = ServerSetup(server_name=args['SERVER_NAME']),
                        config=args['CONFIG']
                        start_rig=args['-r'])
    setup.print_msg()

$python myprog.py a1 /abc/file1.txt

When I run above program using above command, I get error message displaying usage that I've written. What is going wrong here, how can I use more than one 'Arguments'?


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 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)

Optional parameter not working on schema

I am adding validation using schema for CLI that uses docopt, but I cannot seem to get optional to work. I want to validate that:

  • the input file exists
  • valid options are used
  • if the PATH is added that the directory exists.

Here is app so far

"""DVget

Usage:
    DVget [-s] FILE [PATH]

    Process a file, return data based on selection
    and write results to PATH/output-file

Arguments:
    FILE        specify input file
    PATH        specify output directory (default: ./)

Options:
    -s          returns sections
    -p          returns name-sets
    -m          returns modules

"""
import os

from docopt import docopt
from schema import Schema, And, Use, Optional, SchemaError

# START OF SCRIPT
if __name__ == "__main__":

    arguments = docopt(__doc__, version="0.1")

    #print(arguments)

    schema = Schema({
        'FILE': [Use(open, error='FILE should be readable')],
        Optional('PATH'): And(os.path.exists, error='PATH should exist'),
        '-': And(str, lambda s: s in ('s', 'p', 'm'))})

    try:
        arguments = schema.validate(arguments)
        # process(arguments)
    except SchemaError as e:
        exit(e)

running DVget -s "c:\test.txt" gives me the error message 'PATH should exist' even when using Optional in schema and docopt. Any suggestions?


Source: (StackOverflow)