5

I've been trying to use docopt to make a simple CLI, but for some reason my default parameters are not appearing. Below is my test code. I am using the latest version of docopt.py from the github repository.

"""
Usage:  scrappy <path> ... [options]

-a --auto           Automatically scrape and rename without user interaction.
-l --lang           Specify language code [default: en].
--scan-individual   Evaluate series information individually for each file.
-c --cfg            User alternate config file [default: ../scrappy.conf]
-t --test           Test run.  Do not modify files.
-v --verbose        Print verbose output
"""

from docopt import docopt
arguments = docopt(__doc__, version='0.1.0 alpha')
print arguments  # DEBUG

Here's my output when I run $ scrappy/scrappy.py first_path_parameter second/path/parameter

{'--auto': None,
 '--cfg': None,
 '--lang': None,
 '--scan-individual': None,
 '--test': None,
 '--verbose': None,
 '<path>': ['first_path_parameter', 'second/path/parameter']}

Anybody know what's going on?

EDIT:

I updated my code, but I'm still getting similar output. What's more, when I try to pass --scan-individual, I get an error according to which it requires an argument. Again, in case it matters, I'm running docopt having simply copied docopt.py into the working directory of my project. What's going on, here?

#!/usr/bin/env python

"""Scrappy:  Rename media files based on scraped information.

Usage:  scrappy <path> ... [options]

-a --auto               Automatically scrape and rename without user interaction.
-l LANG --lang LANG     Specify language code [default: en].
--scan-individual       Evaluate series information individually for each file.
-c CONF --cfg CONF      User alternate config file [default: ../scrappy.conf]
-t --test               Test run.  Do not modify files.
-v --verbose            Print verbose output
"""

from docopt import docopt
arguments = docopt(__doc__, version='0.1.0 alpha')
print arguments  # DEBUG

Output:

$ scrappy/scrappy.py first_path_parameter second/path/parameter --scan-individual
--scan-individual requires argument
Usage:  scrappy <path> ... [options]
Louis Thibault
  • 20,240
  • 25
  • 83
  • 152

4 Answers4

6

By looking at the examples, it seems that if you want to pass a default value you may have to specify a target variable, e.g.

naval_fate.py:  --speed=<kn>  Speed in knots [default: 10].
options_example.py-  --exclude=PATTERNS   exclude files or directories which match these comma
options_example.py:                       separated patterns [default: .svn,CVS,.bzr,.hg,.git]
options_example.py-  -f NAME --file=NAME  when parsing directories, only check filenames matching
options_example.py:                       these comma separated patterns [default: *.py]

So in your case,

-l LANG --lang LANG  Specify language code [default: en].
-c CONFIG            User alternate config file [default: ../scrappy.conf]

produces

localhost-2:coding $ python doc.py --auto a b c
{'--auto': True,
 '--lang': 'en',
 '--scan-individual': False,
 '--test': False,
 '--verbose': False,
 '-c': '../scrappy.conf',
 '<path>': ['a', 'b', 'c']}

Edit: the updated code the OP posted works just fine for me, with the github version I downloaded about half an hour ago:

localhost-2:coding $ ./scrappy.py first_path_parameter second/path/parameter --scan-individual
{'--auto': False,
 '--cfg': '../scrappy.conf',
 '--lang': 'en',
 '--scan-individual': True,
 '--test': False,
 '--verbose': False,
 '<path>': ['first_path_parameter', 'second/path/parameter']}

So I'm at a loss.

DSM
  • 342,061
  • 65
  • 592
  • 494
  • 2
    oh... sheesh... that should have been obvious! Thank you! – Louis Thibault Dec 21 '12 at 18:50
  • So it seems that your solution isn't quite working for me. I'm still not getting my default values, and what's more, when I try to pass a command like `--scan-individual`, I get an error according to which it requires an argument. Am I missing something obvious, again? I've updated the code in the original question. – Louis Thibault Dec 21 '12 at 19:05
  • @blz: it works just fine for me. Could you edit your post to include the full traceback from your error message? – DSM Dec 21 '12 at 19:10
  • @blz: I'm stumped, then, unless something has changed recently in `git`. Could you clone from trunk and compare? – DSM Dec 21 '12 at 19:14
  • forgive me but I'm not quite sure what you mean by "clone from trunk"? I know how to clone, but what does "trunk" mean? The `docopty.py` file I have is the latest version on the public github repo, if that's what you're referring to. – Louis Thibault Dec 21 '12 at 19:16
  • @blz: I meant something like "git clone https://github.com/docopt/docopt.git". I'm assuming that you used the `zip` version? .. although, wait. If you're using a recent version, why are you specifying `0.1.0 alpha`? [Oh, scratch that -- you mean it's 0.1.0 alpha of `scrappy`.] – DSM Dec 21 '12 at 19:20
  • this may be unorthodox, but I just did a `wget` of the individual file from the github raw text page. Other than that, yes, `0.1.0 alpha` refers to my own project. Maybe I should file a bug report? – Louis Thibault Dec 21 '12 at 19:26
  • @blz: well, I'm at a loss as to why it works for me and not for you. If we're using the same `docopt` and the same code, then (modulo OS and Python version issues which shouldn't play a role here) I can't see why we're getting different results. It's probably something so obvious we can't see it (e.g. I'd run `python -tt docopt.py` on your code to make sure the whitespace is consistent, etc.) – DSM Dec 21 '12 at 19:45
  • It was, indeed, a whitespace issue -- how freaking embarassing! Anyway, I'm accepting your answer. Thanks for the help! – Louis Thibault Dec 21 '12 at 19:53
3

I just ran into the same issue -- and I only resolved it after reading the last two comments by @DSM and @blz.

To reiterate, as it may help others, to get the defaults variables parsed you have to make sure there are at least two spaces between end of the variables for the options and the text description of the option.

From the docs:

Use two spaces to separate options with their informal description:

--verbose More text.   # BAD, will be treated as if verbose option had
                   # an argument "More", so use 2 spaces instead
-q        Quit.        # GOOD
-o FILE   Output file. # GOOD
--stdout  Use stdout.  # GOOD, 2 spaces

So without two spaces the option parser interprets the description text as variables and does not process the [default: ...] part.

hargriffle
  • 196
  • 2
3

I just ran across this issue in my own code and tested (using the other answers here from hargriffle and DSM) until I figured the following out.

Note this is as of docopt 0.6.1

When running this file:

#! /usr/bin/env python
"""scans.py

Usage:
  scans.py [<args>...]

Options:
  -h --help           Show this screen.
  --version           Show version.
  -L INT --limit=INT  Query response row limit [default: 10]

"""

from docopt import docopt

if __name__ == '__main__':
    print docopt(__doc__)

I receive the following output

{'<args>': []}

BUT if I specifically write in that the argument is optional in the usage line, like so:

Usage:
  scans.py [-L INT | --limit=INT] [<args>...]

I received what I was hoping for:

{'--limit': '10',
 '<args>': []}
KingsRook
  • 113
  • 1
  • 8
1

Same problem with me.

In my particular case I noticed that doc-opt is sensitive to lines starting with tabs vs starting with spaces

#!/usr/bin/env python
"""Sample Application.

Usage:
    sample [options] me
    sample --version

Options:
  --host HOST     words here  [default: 5]
  --version  Version identifier

"""

vs

#!/usr/bin/env python
"""Sample Application.

Usage:
    sample [options] me
    sample --version

Options:
    --host HOST     words here  [default: 5]
    --version  Version identifier

"""

where there is a single tab before --host and --version in the Options: list. The second case doesn't parse the defaults correctly, the first with spaces for the initial indent, does.

Engr Waseem Arain
  • 1,163
  • 1
  • 17
  • 36