Coder Social home page Coder Social logo

docopt's Issues

--help and --help-commands

I see that this works better in the current master. Still, there is an issue:

 $ script.py --help

will always trigger the --help-commands action, when I would expect it to show the help.

setup.py installer

Hi,
docopt looks really nice!
How about a setup.py file to make it easily installable?

I could provide you one via a pull request but it needs contact informations and other infos that you would probably prefer to specify yourself.

Also it would be awesome if you published it on pypi but the README would be better if it was in rst format since that's what is supported by pypi.

Thanks

Multi-word program name

There might be a need to allow multi-word program names as follows

Usage: python program.py [options]

or

Usage: python3 program.py [options]

or

Usage: python program.zip [options] 

Even something like:

Usage: python -v program.py [options]

or

Usage: python -m module [options]

There is no obvious way to do it right now in docopt. Any feedback is appreciated.

  • Is this needed?
  • If yes, what should API look like?

Default action (no arguments)

Using 0.3, this docstring:

Usage:
   script
   script --flag

when given no arguments, show the usage text. I would expect it to return a dictionary if no options set.

Support for counted short flags, a-la ssh -vvv?

There's another idiom I've seen around the place where a short can be multiplied to increase its weight. The only one that springs to mind right this second is ssh:

 -t      Force pseudo-tty allocation.  Blah blah blah. Multiple -t options force 
         tty allocation, etc.

 -v      Verbose mode. Yada yada yada. Multiple -v options increase the
         verbosity.  The maximum is 3.

Would this be something docopt could support, or do you think simply recommending people do -v 3 is enough?

Add support for enumerations

We can already do this:

Usage: go (north | west | east | south)

But this uses subcommands, which have an awkward access syntax, and issues #42 and #4 suggest to me they're meant for something rather more heavy-duty. Moreover, the set of legal values might be too verbose or too large to enumerate in an usage pattern. In such cases, something like this would be more useful:

Usage: go <direction>

  <direction>  The direction to go in (north, west, east, south)

Flag schema problem.

Below is four examples, and IMO it's hard to predict parse result schema.

In the first three examples some flags are interpret as repeated flags.
Particulary in second example (which is IMO almost the right way) -t and -x are repeated, but -c is not.

Also the value of -f is different in all examples: wrapped in array, scalar and wrapped twice in array. Looks like there's some bug somewhere, especially the double array. Neither example accept multiple -f flags thought, so value of -f should be scalar in all examples.

But I agree the right way is to use commands instead of -crutx flags, and then there is still -f problem, see example 4.

Example 1

cat example1.py 

python
"""
Usage:
example -c [options] ...
example (-r | -u) -f=ARCHIVE [options] ...
example (-t | -x) [options] [...]

Options:
--help Print this message
-v Produce verbose output.
-z (c mode only) Compress the resulting archive with gzip(1).
-Z (c mode only) Compress the resulting archive with compress(1).
-j (c mode only) Compress the resulting archive with bzip2(1).
-c Create a new archive containing the specified items.
-r Like -c, but new entries are appended to the archive.
-u Like -r, but new entries are added only if they have a modification date newer than the corresponding entry in the archive.
-b BLOCKSIZE Specify the block size, in 512-byte records, for tape drive I/O.
-f ARCHIVE Read the archive from or write the archive to the specified file.
-t List archive contents to stdout.
-x Extract to disk from the archive.
"""

from docopt import docopt

if name == 'main':
arguments = docopt(doc, version='0.0.1')
print(arguments)


``` sh
python example1.py -tf example
{'--help': False,
 '-Z': False,
 '-b': None,
 '-c': False,
 '-f': ['example'],
 '-j': False,
 '-r': 0,
 '-t': 1,
 '-u': 0,
 '-v': False,
 '-x': 0,
 '-z': False,
 '<files>': [],
 '<patterns>': []}

Example 2

cat example2.py
"""
Usage:
example -c [options] <files>...
example (-r | -u) -f=ARCHIVE <files>...
example (-t | -x) [options] [<patterns>...]

Options:
   --help        Print this message
   -v            Produce verbose output.
   -z            (c mode only) Compress the resulting archive with gzip(1).
   -Z            (c mode only) Compress the resulting archive with compress(1).
   -j            (c mode only) Compress the resulting archive with bzip2(1).
   -c            Create a new archive containing the specified items.
   -r            Like -c, but new entries are appended to the archive.
   -u            Like -r, but new entries are added only if they have a modification date newer than the corresponding entry in the archive.
   -b BLOCKSIZE  Specify the block size, in 512-byte records, for tape drive I/O.
   -f ARCHIVE    Read the archive from or write the archive to the specified file.
   -t            List archive contents to stdout.
   -x            Extract to disk from the archive.
"""

from docopt import docopt

if __name__ == '__main__':
  arguments = docopt(__doc__, version='0.0.1')
  print(arguments)
python example2.py -tf example
{'--help': False,
 '-Z': False,
 '-b': None,
 '-c': False,
 '-f': 'example',
 '-j': False,
 '-r': False,
 '-t': 1,
 '-u': False,
 '-v': False,
 '-x': 0,
 '-z': False,
 '<files>': [],
 '<patterns>': []}

Example 3

cat example3.py
"""
Usage:
example -c [options] <files>...
example [-r | -u] -f=ARCHIVE [options] <files>...
example [-t | -x] [options] [<patterns>...]

Options:
   --help        Print this message
   -v            Produce verbose output.
   -z            (c mode only) Compress the resulting archive with gzip(1).
   -Z            (c mode only) Compress the resulting archive with compress(1).
   -j            (c mode only) Compress the resulting archive with bzip2(1).
   -c            Create a new archive containing the specified items.
   -r            Like -c, but new entries are appended to the archive.
   -u            Like -r, but new entries are added only if they have a modification date newer than the corresponding entry in the archive.
   -b BLOCKSIZE  Specify the block size, in 512-byte records, for tape drive I/O.
   -f ARCHIVE    Read the archive from or write the archive to the specified file.
   -t            List archive contents to stdout.
   -x            Extract to disk from the archive.
"""

from docopt import docopt

if __name__ == '__main__':
  arguments = docopt(__doc__, version='0.0.1')
  print(arguments)
python example3.py -tf example
{'--help': False,
 '-Z': False,
 '-b': None,
 '-c': False,
 '-f': [['example']],
 '-j': False,
 '-r': 0,
 '-t': 1,
 '-u': 0,
 '-v': False,
 '-x': 0,
 '-z': False,
 '<files>': [],
 '<patterns>': []}

Example 4

cat example4.py 
"""
Usage:
example create [options] <files>...
example ( append | newer ) -f=ARCHIVE [options] <files>...
example ( test | extract ) [options] [<patterns>...]

Commands:
  create         Create a new archive containing the specified items.
  append         Like create, but new entries are appended to the archive.
  newer          Like append, but new entries are added only if they have a
                 modification date newer than the corresponding entry in the
                 archive.
  test           List archive contents to stdout.
  extract        Extract to disk from the archive.

Options:
   --help        Print this message
   -v            Produce verbose output.
   -z            (c mode only) Compress the resulting archive with gzip(1).
   -Z            (c mode only) Compress the resulting archive with compress(1).
   -j            (c mode only) Compress the resulting archive with bzip2(1).
   -b BLOCKSIZE  Specify the block size, in 512-byte records, for tape drive I/O.
   -f ARCHIVE    Read the archive from or write the archive to the specified file.
"""

from docopt import docopt

if __name__ == '__main__':
  arguments = docopt(__doc__, version='0.0.1')
  print(arguments)
python example4.py test -f example example1.txt
{'--help': False,
 '-Z': False,
 '-b': None,
 '-f': ['example'],
 '-j': False,
 '-v': False,
 '-z': False,
 '<files>': [],
 '<patterns>': [],
 'append': False,
 'create': False,
 'extract': False,
 'newer': False,
 'test': True}

Deprecate and remove ARG convention in favor of <arg>

What do you think on removing upper-case positional arguments convention?

It has several problems:

  • each language has it's own understanding on what is .isupper()
  • each person has his own understanding on what is upper-case
  • "there should be one obvious way to do it"
  • <arg> is easier to parse and less ambiguous

Type conversions

I thought about what docopt does right and where that approach has its drawbacks.

I came to the conclusion that it’s a little too fast for its own good when it comes to the speed at which you get something (the dictionary) out of it: docopt is designed to be used in 1 function call on 1 docstring you wrote, but since that one also needs to be human readable, it has its shortcomings.


My problem is type conversions: Though roundabout, after using argparse you have an object containing ints, files, and everything you can instantiate by feeding it strings.

Compare argparse’s options.x with docopt’s int(options["<x>"]). docopt is beautiful and easy until you have the dict, but ugly afterwards.

The other problem is “break early and often”: if you convert stuff whenever it is needed, it is there where your program will break if fed invalid options. If you decide to do this as early as possible (e.g. by converting your dictionary into a set of variables), you have to do if-else branches again and handle missing arguments (e.g. if an optional path to a file is not given, you have to do f = file(options['--path']) if options['--path'] else None)


so what do i want?

  • a way to easily typeconvert and validate while directly after docopting.

what is “easy”?

  • not doing it manually, but letting docopt do it. either by another function, or by another keyword argument. This should of course handle lists by just mapping the conversion onto them.

    (e.g. docopt(__doc__, conversions={'<x>': int, '<y>': int})

  • letting docopt handle missing optional arguments: if something isn’t given, it will yield None in the dict, which docopt shouldn’t typeconvert, as mist constructors do silly stuff or break when given None. (for lists, that’s easy. map(int, []) ist still [])

Make it possible to write 'xargs'

I have this test of options parsers, and almost every one fails, including docopt: Can I write 'xargs'?

Here's a simplified usage string:

"""Usage:
  xargs.py [options] [COMMAND [ARG...]]

Options:
  --null,-0               Input items terminated by 0
"""

The problem is that Docopt allows interspersed options, per the GNU(?) convention. (This is a good default! I don't dispute that.) This means that the command line xargs.py foo -0 produces this option dictionary:

{'--null': True,
 'ARG': [],
 'COMMAND': 'foo'}

instead of this one:

{'--null': False,
 'ARG': ['-0'],
 'COMMAND': 'foo'}

Obviously I could require that the user enter -- in there, but that is both obnoxious and not the typical situation for a program which runs another command passed on the command line. (E.g. time, valgrind, env, etc.)

(Incidentally, -- handling IMO doesn't seem very good either: If I run xargs.py -- foo what I get is

{'--null': False,
 'ARG': ['foo'],
 'COMMAND': '--'}

while standard convention is that the -- is basically transparent to the program's meaning and thus it seems like it should be transparent to the program's code, so forcing the programmer to manually shift the positional arguments down (or explicitly list a variant of the command with --) seems wrong.)

Repeated mutually exclusive args give nested lists... sometimes.

Docopt is really cool. It fits the way I write tools; I like.

I'm trying to express "at least one arg from each of two sets". I think I can do this with repeated "mutually exclusive" args:

Usage:  foo (--x=x|--y=y)... (--a=a|--b=b)...

But, with docopt 0.5.0 and git fce1ee7, I run into a slight issue:

docopt("Usage:  foo (--x=x|--y=y)...", "--x=1 --y=2")
{'--x': ['1'],
 '--y': [['2']]}

I believe it should be:

{'--x': ['1'],
 '--y': ['2']}

And If there's a better way of achieving my goal, I'm all ears.

DocoptExit raised when doc string is unicode

I'm generating the doc string and using appdirs to show where my application searches for configuration files.

Usage: main.py [options] failes when my doc string converts to unicode because of appdirs returning a unicode string.
It seemed that the parse_atom method got each letter instead of each word, and so the elif token =='options': was never true.

Add support for [no-]options

It's common pattern to use boolean options like --[no-]paginate. They are missing in docopt. Does it have any reasons not to include such functionality or it's just not yet implemented?

Repeat arguments affect return value for other subcommands

This usage:

Usage:
  prog ship new <name>...
  prog ship [<name>] move

Can return the following output:

{'<name>': ['Guardian'],
 'move': True,
 'new': False,
 'ship': True}

Note that the <name> attribute is a list, even though subcommand ship move has only one occurrence of <name>. This seems likely to cause problems when projects grow larger and new commands are added or the docstring is split.

Change the docopt error message format

Currently, docopt reports errors as follows:

-o is not recognized
--opt is not recognized
--o requires argument
--opt requires argument
--opt is not a unique prefix: --option, --optimum?
--opt must not have an argument

All followed by a listing of the usage patterns. However, a cursory sample of command-line utilities on my box use the following format:

program: invalid option -- 'o'
program: unrecognised option '--o'
program: option requires an argument -- 'o'
program: option '--option' requires an argument
program: option '--opt' is ambiguous; possibilities: '--option' '--optimum'
program: option '--option' doesn't allow an argument

All followed by Try 'program --help' for more information., which I think looks way better (although that might just be my Ubuntu bias talking.) At the very least, I think docopt should prefix program: to the error messages it outputs, though this might cause some complications if #41 ever gets implemented. Opinions?

Another request for type annotations and conversions

I just learned about docopt from your video featured in Python Weekly, and I must say it looks amazing! However, I was surprised to find that there is no functionality provided for annotating or converting the types of arguments. Even though this has been raised and closed twice before --

#8
#58

-- I think it is an important feature and I want to revisit it to add my perspective and support.

The main arguments against adding this functionality seem to be:

  1. Simplicity is valuable.
  2. You can easily perform conversions elsewhere using Schema

I will address each of these in turn:

  1. Yes, simplicity is valuable and one of the most compelling aspects of docopt. To preserve simplicity, let's consider allowing only the following type annotations: int, float, and string. Everything is a string unless otherwise annotated. This drastically reduces both implementation complexity and usage complexity as compared to a more featureful approach that would allow conversions to arbitrary, possibly user-defined Python objects.

    I think int and float would cover a large fraction of use cases. The only other types I would even consider supporting would be boolean and maybe file. Since docopt is presenting a generic command line interface, it makes sense to me that it would only support data types that are somehow "native" to the Unix ecosystem rather than arbitrary Python-specific types that have no Unix analogue. Ranges or sets of the supported primitives would also be candidates for inclusion -- I think they would be worth adding, but I agree they add complexity (both implementation-wise and in the DSL). So, start with just the really simple stuff!

  2. If an argument is required to be a particular type, I would like the command line help text to reflect that. If I've already specified the type in the usage message, why should I need to manually create a schema re-specifying portions of the interface?

    Schema looks like a very nice tool! What if docopt used the information it parsed from the usage string to automatically create the Schema and perform validations/conversions for me (behind the scenes)? That would be big win for clarity and usability and incur only minor implementation complexity.

Anyway, I just wanted to add my two cents. Again, great job with docopt!

PHP port, all tests pass

You know when you see something that you don't know how you ever lived without... We do mostly PHP where I work so rather than keep living without docopt I whipped up a quick and dirty transliteration.

It passes all of the tests in the language_agnostic_parser, but it hasn't really been given much of a workout yet and there could be some issues I haven't found.

https://github.com/shabbyrobe/docopt.php

The main issue at the moment is that DocoptExit doesn't quite work in PHP like it should - SystemExit has no obvious analog in PHP so it currently requires a catch block, but I'm working on that.

Thanks again for such a fantastic library, and a very, very big thanks for the language agnostic tester.

empty arguments are turned into True

IMHO empty arguments on the command line should be turned into empty strings in docopt's result dictionary, i.e. the following test should not fail:

def test_empty_value():
    assert docopt('usage: prog --long=', '--long=') == \
            {'--long': ['']}

Currently the result of parsing these options is:
{"--long": True}

Or is there a good reason why it's being converted to a boolean?

Optional argument groupings match if any of the arguments in the group match

I would like to be able to specify that either no arguments, or a pair of arguments are required. Something like: """ Usage: prog [<a> <b>] """ would seem to make sense, but the parser allows prog one to match, as well as prog one two and prog.

I have found that """ Usage: prog [(<a> <b>)] """ gives the behaviour I would like, but it seems like the extra parentheses shouldn't be required.

I've tried adjusting the matching of the Optional type, but it breaks a whole load of other things.

def test_paired_arguments:
    with raises(DocoptExit):
        docopt('usage: prog [<a> <b>]', 'one')

Mac.app -psn argument "not recognized"

When a program is invoked as a MacOS app, it is being passed an extra argument (process serial number "PSN") by the OS like so:

-psn_0_2740893

It is not in the common format --option=value thus can not be easily caught or anticipated, causing a

-p is not recognized

error.
[options] does not help in this case either, as it expects the listed options.

More generally, can our programs not break when given truly unanticipated arguments?

Repeatable commands with optional arguments doesn't work in experimental branch

It feels like #4 will solve this problem (though a solution for #4 does indeed seem like it will be anything but trivial), but when I try to provide optional arguments to a repeatable subcommand, the indexing makes it impossible to work out which command each argument belongs to.

The following example raises an IndexError on the third iteration because the --speed 999 gets interpreted as part of the second go command rather than the third:

import docopt
arguments = docopt.docopt(
    "usage: prog (go <direction> [--speed=<km/h>])...",
    "go forwardnotbackward --speed 123  go upwardnotforward  go twirling --speed 999"
)

for i in xrange(0, arguments['go']):
    print arguments['<direction>'][i]
    print arguments['--speed'][i]

Make -- really separate options and args

When handling this definition

Usage: 
  fubar [-f LEVEL] [--] <items>...

and call it thus:

% fubar -f -- 1 2 

I'd expect the result to be an error since -f didn't receive an argument, right?

Seems like this is supported, but I can't get multiple arguments to work

This is the docstring for punt.

I would like to have multiple --watch options, but I can't figure out a syntax that supports it.

"""Watches current path (or another path) for changes and executes
command(s) when a change is detected.  Uses watchdog to track file changes.

Usage:
    punt [-w <path> ...] [-l] [--] <commands>...
    punt (-h | --help)
    punt --version

Options:
    -w <path> ..., --watch <path> ...  Which path to watch [default: current directory]
    -l, --local                        Only tracks local files (disables recusive)
"""
# blablabla
arguments = docopt(__doc__, version='punt v1.6')
print repr(arguments)
> punt -w dir1 dir2  -- make
{'--': False,
 '--help': False,
 '--local': False,
 '--version': False,
 '--watch': 'dir1',
 '-h': False,
 '<commands>': ['dir2', '--', 'make']}

> punt -w dir1 -w dir2  -- make
{'--': True,
 '--help': False,
 '--local': False,
 '--version': False,
 '--watch': 'dir2',
 '-h': False,
 '<commands>': ['make']}

Default value for argument gets assigned to option

"""
Usage:
    bug.py [--opt num] [ARG]

Options:
    --opt num   An option with a value

Arguments:
    ARG         An arg with a default [default: A]
"""

from docopt import docopt
arguments = docopt(__doc__)
print arguments

I expect this to show:

{'--opt': None, 'ARG': 'A'}

What actually happens:

{'--opt': 'A', 'ARG': None}

I'll take a look into a fix tomorrow if I can.

IndexError on simple parser declaration

I'm experiencing IndexError while trying to produce parser (actually provide test case for issue #8) from simple docstring:

"""usage: serve

Options:

    -p, --port PORT         serve an app on specified port [default: 8000]
"""

from docopt import docopt
print docopt(__doc__)

gives me

Traceback (most recent call last):
  File "test.py", line 9, in <module>
    print docopt(__doc__)
  File "/Users/andreypopp/.virtualenvs/.../lib/python2.7/site-packages/docopt.py", line 483, in docopt
    if type(formal_pattern.children[0]) is Either:
IndexError: list index out of range

docopt should evaluate sys.argv when being called, not when being imported

The current code uses:

def docopt(doc, argv=sys.argv[1:], help=True, version=None, any_options=False):
....

It should evaluate sys.argv when being called:

def docopt(doc, argv=None, help=True, version=None, any_options=False):
    if argv is None:
        argv = sys.argv[1:]

I've got some legacy code that calls into a programs main and sets up sys.argv before.

Regexps in DSL

I was thinking about how powerful that would be if docopt validated arguments based on regular expressions:

"""Usage: my_program <host> <port> --timeout=<s>

<host>  /\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/
<port>  /\d{1,5}/

--timeout=<s>  /\d{1,5}/

"""

But this is just wrong.

PyCon UK, Ireland, Finland

I applied for a 20 minute talk about docopt at PyCon UK, Ireland and Finland, hoping that I will be accepted at at-least one of them. To my surprise the talk was accepted at all of them.

Highlighted are the days I'm giving the talk.

I still didn't get UK visa—but it's likely that I will get it in time.

It would be great to meet you guys there (at a conference, or after one), especially if you live close to the location.

/cc @alexspeller @ansible07 @sonwell @njoh @raskug @shabbyrobe @sonwell @Met48

Complex option arguments

It'd be nice to write options like:
--background <A> <C> <G> <T>
so that call
my_tool --background 1 2 3 4
yielded options { '--background' => {'A'=>1, 'C'=>2, 'G'=>3, 'T' => 4}} (sorry for ruby-like hash-notation)
or at least {'--background' => [1 ,2, 3, 4]}

It's very frustrating that I cannot specify multiple required arguments for an option.

Raise an exception on --help and --version

In some use cases (namely, my own docopts), it would be useful to handle the --help and --version options specially, but let docopt worry about parsing them. At present, when docopt() encounters --help or --version, it simply dumps the relevant string to standard output and calls sys.exit(). A better approach would be to raise some derivative of SystemExit with the relevant string as its argument; SystemExit itself won't do, as it interprets all string arguments as failure conditions, and DocoptExit tacks the usage pattern list to its arguments.

One could just invoke docopt() with help=False and version=None and handle the --help and --version entries in the return dictionary manually, but then they no longer get preferential treatment; e.g., with the following interface description:

Usage: prog

--help
--version

The following two invocations work if help=True and version="Some version message here":

prog gekki gukki gakki --help
prog ooga booga --version

Whereas they don't if help=False and version=None.

alternate syntax for [default: ...]?

It would be nice if an alternate syntax were available for an option's default value. Some of my options are long (urls and file paths), so I try to remove every character possible in order to avoid line wrap. Personally I could live with just square brackets, but if that causes trouble for some, perhaps double them up, [[..]]?

Options:
    -i,--ini=FILE      use alternate setup.ini [[O:/etc/setup/setup.ini]]
    -m,--mirror=URL    use alternate mirror [[http://download.example.org/beta_release/testing/RC2]]

(aside: 'usage' is mispelt 'ussage' in a couple places in the docs)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.