Skip to content

Instantly share code, notes, and snippets.

@shabbyrobe
Last active December 15, 2015 23:49
Show Gist options
  • Save shabbyrobe/5342871 to your computer and use it in GitHub Desktop.
Save shabbyrobe/5342871 to your computer and use it in GitHub Desktop.
Mostly converts the existing testcases.docopt file into format proposed by RFC.
import re
import json
import sys
def read_doc(h, line):
doc = line
if re.search(r"\"\"\"\s*$", doc):
return doc
for line in h:
doc += line
if re.search(r"(?<!r)\"\"\"\s*$", line):
break
doc = re.sub(r"\s*\"\"\"\s*$", "\1\n\"\"\"", doc)
return doc
def read_case(h, line):
test = line.strip()
if test.startswith('$ prog '):
test = test[7:]
return (test, read_expect(h))
def read_expect(h):
expect = ""
for line in h:
if line.rstrip() == '':
break
else:
expect += line
return expect.rstrip()
if __name__ == "__main__":
tokens = []
with open(sys.argv[1]) as h:
for line in h:
if re.match(r"^\s*#", line):
tokens.append(('comment', line))
elif re.match(r'^r"""', line):
tokens.append(('doc', read_doc(h, line)))
elif re.match(r'^\$', line):
tokens.append(('case', read_case(h, line)))
else:
if line.rstrip() != '':
raise RuntimeError("Line was not empty: %s" % line.rstrip())
for name, value in tokens:
if name == 'comment':
print value.strip()
if name == 'doc':
print
print value.strip()
elif name == 'case':
test, expect = value
print "docopt %s" % json.dumps({'argv': test})
print "expect %s" % (json.dumps({'DocoptExit': True}) if expect == '"user-error"' else expect)
print
r"""Usage: prog
"""
docopt {"argv": "$ prog"}
expect {}
docopt {"argv": "--xxx"}
expect {"DocoptExit": true}
r"""Usage: prog [options]
Options: -a All.
"""
docopt {"argv": "$ prog"}
expect {"-a": false}
docopt {"argv": "-a"}
expect {"-a": true}
docopt {"argv": "-x"}
expect {"DocoptExit": true}
r"""Usage: prog [options]
Options: --all All.
"""
docopt {"argv": "$ prog"}
expect {"--all": false}
docopt {"argv": "--all"}
expect {"--all": true}
docopt {"argv": "--xxx"}
expect {"DocoptExit": true}
r"""Usage: prog [options]
Options: -v, --verbose Verbose.
"""
docopt {"argv": "--verbose"}
expect {"--verbose": true}
docopt {"argv": "--ver"}
expect {"--verbose": true}
docopt {"argv": "-v"}
expect {"--verbose": true}
r"""Usage: prog [options]
Options: -p PATH
"""
docopt {"argv": "-p home/"}
expect {"-p": "home/"}
docopt {"argv": "-phome/"}
expect {"-p": "home/"}
docopt {"argv": "-p"}
expect {"DocoptExit": true}
r"""Usage: prog [options]
Options: --path <path>
"""
docopt {"argv": "--path home/"}
expect {"--path": "home/"}
docopt {"argv": "--path=home/"}
expect {"--path": "home/"}
docopt {"argv": "--pa home/"}
expect {"--path": "home/"}
docopt {"argv": "--pa=home/"}
expect {"--path": "home/"}
docopt {"argv": "--path"}
expect {"DocoptExit": true}
r"""Usage: prog [options]
Options: -p PATH, --path=<path> Path to files.
"""
docopt {"argv": "-proot"}
expect {"--path": "root"}
r"""Usage: prog [options]
Options: -p --path PATH Path to files.
"""
docopt {"argv": "-p root"}
expect {"--path": "root"}
docopt {"argv": "--path root"}
expect {"--path": "root"}
r"""Usage: prog [options]
Options:
-p PATH Path to files [default: ./]
"""
docopt {"argv": "$ prog"}
expect {"-p": "./"}
docopt {"argv": "-phome"}
expect {"-p": "home"}
r"""UsAgE: prog [options]
OpTiOnS: --path=<files> Path to files
[dEfAuLt: /root]
"""
docopt {"argv": "$ prog"}
expect {"--path": "/root"}
docopt {"argv": "--path=home"}
expect {"--path": "home"}
r"""usage: prog [options]
options:
-a Add
-r Remote
-m <msg> Message
"""
docopt {"argv": "-a -r -m Hello"}
expect {"-a": true,
"-r": true,
"-m": "Hello"}
docopt {"argv": "-armyourass"}
expect {"-a": true,
"-r": true,
"-m": "yourass"}
docopt {"argv": "-a -r"}
expect {"-a": true,
"-r": true,
"-m": null}
r"""Usage: prog [options]
Options: --version
--verbose
"""
docopt {"argv": "--version"}
expect {"--version": true,
"--verbose": false}
docopt {"argv": "--verbose"}
expect {"--version": false,
"--verbose": true}
docopt {"argv": "--ver"}
expect {"DocoptExit": true}
docopt {"argv": "--verb"}
expect {"--version": false,
"--verbose": true}
r"""usage: prog [-a -r -m <msg>]
options:
-a Add
-r Remote
-m <msg> Message
"""
docopt {"argv": "-armyourass"}
expect {"-a": true,
"-r": true,
"-m": "yourass"}
r"""usage: prog [-armmsg]
options: -a Add
-r Remote
-m <msg> Message
"""
docopt {"argv": "-a -r -m Hello"}
expect {"-a": true,
"-r": true,
"-m": "Hello"}
r"""usage: prog -a -b
options:
-a
-b
"""
docopt {"argv": "-a -b"}
expect {"-a": true, "-b": true}
docopt {"argv": "-b -a"}
expect {"-a": true, "-b": true}
docopt {"argv": "-a"}
expect {"DocoptExit": true}
docopt {"argv": "$ prog"}
expect {"DocoptExit": true}
r"""usage: prog (-a -b)
options: -a
-b
"""
docopt {"argv": "-a -b"}
expect {"-a": true, "-b": true}
docopt {"argv": "-b -a"}
expect {"-a": true, "-b": true}
docopt {"argv": "-a"}
expect {"DocoptExit": true}
docopt {"argv": "$ prog"}
expect {"DocoptExit": true}
r"""usage: prog [-a] -b
options: -a
-b
"""
docopt {"argv": "-a -b"}
expect {"-a": true, "-b": true}
docopt {"argv": "-b -a"}
expect {"-a": true, "-b": true}
docopt {"argv": "-a"}
expect {"DocoptExit": true}
docopt {"argv": "-b"}
expect {"-a": false, "-b": true}
docopt {"argv": "$ prog"}
expect {"DocoptExit": true}
r"""usage: prog [(-a -b)]
options: -a
-b
"""
docopt {"argv": "-a -b"}
expect {"-a": true, "-b": true}
docopt {"argv": "-b -a"}
expect {"-a": true, "-b": true}
docopt {"argv": "-a"}
expect {"DocoptExit": true}
docopt {"argv": "-b"}
expect {"DocoptExit": true}
docopt {"argv": "$ prog"}
expect {"-a": false, "-b": false}
r"""usage: prog (-a|-b)
options: -a
-b
"""
docopt {"argv": "-a -b"}
expect {"DocoptExit": true}
docopt {"argv": "$ prog"}
expect {"DocoptExit": true}
docopt {"argv": "-a"}
expect {"-a": true, "-b": false}
docopt {"argv": "-b"}
expect {"-a": false, "-b": true}
r"""usage: prog [ -a | -b ]
options: -a
-b
"""
docopt {"argv": "-a -b"}
expect {"DocoptExit": true}
docopt {"argv": "$ prog"}
expect {"-a": false, "-b": false}
docopt {"argv": "-a"}
expect {"-a": true, "-b": false}
docopt {"argv": "-b"}
expect {"-a": false, "-b": true}
r"""usage: prog <arg>"""
docopt {"argv": "10"}
expect {"<arg>": "10"}
docopt {"argv": "10 20"}
expect {"DocoptExit": true}
docopt {"argv": "$ prog"}
expect {"DocoptExit": true}
r"""usage: prog [<arg>]"""
docopt {"argv": "10"}
expect {"<arg>": "10"}
docopt {"argv": "10 20"}
expect {"DocoptExit": true}
docopt {"argv": "$ prog"}
expect {"<arg>": null}
r"""usage: prog <kind> <name> <type>"""
docopt {"argv": "10 20 40"}
expect {"<kind>": "10", "<name>": "20", "<type>": "40"}
docopt {"argv": "10 20"}
expect {"DocoptExit": true}
docopt {"argv": "$ prog"}
expect {"DocoptExit": true}
r"""usage: prog <kind> [<name> <type>]"""
docopt {"argv": "10 20 40"}
expect {"<kind>": "10", "<name>": "20", "<type>": "40"}
docopt {"argv": "10 20"}
expect {"<kind>": "10", "<name>": "20", "<type>": null}
docopt {"argv": "$ prog"}
expect {"DocoptExit": true}
r"""usage: prog [<kind> | <name> <type>]"""
docopt {"argv": "10 20 40"}
expect {"DocoptExit": true}
docopt {"argv": "20 40"}
expect {"<kind>": null, "<name>": "20", "<type>": "40"}
docopt {"argv": "$ prog"}
expect {"<kind>": null, "<name>": null, "<type>": null}
r"""usage: prog (<kind> --all | <name>)
options:
--all
"""
docopt {"argv": "10 --all"}
expect {"<kind>": "10", "--all": true, "<name>": null}
docopt {"argv": "10"}
expect {"<kind>": null, "--all": false, "<name>": "10"}
docopt {"argv": "$ prog"}
expect {"DocoptExit": true}
r"""usage: prog [<name> <name>]"""
docopt {"argv": "10 20"}
expect {"<name>": ["10", "20"]}
docopt {"argv": "10"}
expect {"<name>": ["10"]}
docopt {"argv": "$ prog"}
expect {"<name>": []}
r"""usage: prog [(<name> <name>)]"""
docopt {"argv": "10 20"}
expect {"<name>": ["10", "20"]}
docopt {"argv": "10"}
expect {"DocoptExit": true}
docopt {"argv": "$ prog"}
expect {"<name>": []}
r"""usage: prog NAME..."""
docopt {"argv": "10 20"}
expect {"NAME": ["10", "20"]}
docopt {"argv": "10"}
expect {"NAME": ["10"]}
docopt {"argv": "$ prog"}
expect {"DocoptExit": true}
r"""usage: prog [NAME]..."""
docopt {"argv": "10 20"}
expect {"NAME": ["10", "20"]}
docopt {"argv": "10"}
expect {"NAME": ["10"]}
docopt {"argv": "$ prog"}
expect {"NAME": []}
r"""usage: prog [NAME...]"""
docopt {"argv": "10 20"}
expect {"NAME": ["10", "20"]}
docopt {"argv": "10"}
expect {"NAME": ["10"]}
docopt {"argv": "$ prog"}
expect {"NAME": []}
r"""usage: prog [NAME [NAME ...]]"""
docopt {"argv": "10 20"}
expect {"NAME": ["10", "20"]}
docopt {"argv": "10"}
expect {"NAME": ["10"]}
docopt {"argv": "$ prog"}
expect {"NAME": []}
r"""usage: prog (NAME | --foo NAME)
options: --foo
"""
docopt {"argv": "10"}
expect {"NAME": "10", "--foo": false}
docopt {"argv": "--foo 10"}
expect {"NAME": "10", "--foo": true}
docopt {"argv": "--foo=10"}
expect {"DocoptExit": true}
r"""usage: prog (NAME | --foo) [--bar | NAME]
options: --foo
options: --bar
"""
docopt {"argv": "10"}
expect {"NAME": ["10"], "--foo": false, "--bar": false}
docopt {"argv": "10 20"}
expect {"NAME": ["10", "20"], "--foo": false, "--bar": false}
docopt {"argv": "--foo --bar"}
expect {"NAME": [], "--foo": true, "--bar": true}
r"""Naval Fate.
Usage:
prog ship new <name>...
prog ship [<name>] move <x> <y> [--speed=<kn>]
prog ship shoot <x> <y>
prog mine (set|remove) <x> <y> [--moored|--drifting]
prog -h | --help
prog --version
Options:
-h --help Show this screen.
--version Show version.
--speed=<kn> Speed in knots [default: 10].
--moored Mored (anchored) mine.
--drifting Drifting mine.
"""
docopt {"argv": "ship Guardian move 150 300 --speed=20"}
expect {"--drifting": false,
"--help": false,
"--moored": false,
"--speed": "20",
"--version": false,
"<name>": ["Guardian"],
"<x>": "150",
"<y>": "300",
"mine": false,
"move": true,
"new": false,
"remove": false,
"set": false,
"ship": true,
"shoot": false}
r"""usage: prog --hello"""
docopt {"argv": "--hello"}
expect {"--hello": true}
r"""usage: prog [--hello=<world>]"""
docopt {"argv": "$ prog"}
expect {"--hello": null}
docopt {"argv": "--hello wrld"}
expect {"--hello": "wrld"}
r"""usage: prog [-o]"""
docopt {"argv": "$ prog"}
expect {"-o": false}
docopt {"argv": "-o"}
expect {"-o": true}
r"""usage: prog [-opr]"""
docopt {"argv": "-op"}
expect {"-o": true, "-p": true, "-r": false}
r"""usage: prog --aabb | --aa"""
docopt {"argv": "--aa"}
expect {"--aabb": false, "--aa": true}
docopt {"argv": "--a"}
expect "user-error" # not a unique prefix
#
# Counting number of flags
#
r"""Usage: prog -v"""
docopt {"argv": "-v"}
expect {"-v": true}
r"""Usage: prog [-v -v]"""
docopt {"argv": "$ prog"}
expect {"-v": 0}
docopt {"argv": "-v"}
expect {"-v": 1}
docopt {"argv": "-vv"}
expect {"-v": 2}
r"""Usage: prog -v ..."""
docopt {"argv": "$ prog"}
expect {"DocoptExit": true}
docopt {"argv": "-v"}
expect {"-v": 1}
docopt {"argv": "-vv"}
expect {"-v": 2}
docopt {"argv": "-vvvvvv"}
expect {"-v": 6}
r"""Usage: prog [-v | -vv | -vvv]
This one is probably most readable user-friednly variant.
"""
docopt {"argv": "$ prog"}
expect {"-v": 0}
docopt {"argv": "-v"}
expect {"-v": 1}
docopt {"argv": "-vv"}
expect {"-v": 2}
docopt {"argv": "-vvvv"}
expect {"DocoptExit": true}
r"""usage: prog [--ver --ver]"""
docopt {"argv": "--ver --ver"}
expect {"--ver": 2}
#
# Counting commands
#
r"""usage: prog [go]"""
docopt {"argv": "go"}
expect {"go": true}
r"""usage: prog [go go]"""
docopt {"argv": "$ prog"}
expect {"go": 0}
docopt {"argv": "go"}
expect {"go": 1}
docopt {"argv": "go go"}
expect {"go": 2}
docopt {"argv": "go go go"}
expect {"DocoptExit": true}
r"""usage: prog go..."""
docopt {"argv": "go go go go go"}
expect {"go": 5}
#
# Test [options] shourtcut
#
r"""Usage: prog [options] A
Options:
-q Be quiet
-v Be verbose.
"""
docopt {"argv": "arg"}
expect {"A": "arg", "-v": false, "-q": false}
docopt {"argv": "-v arg"}
expect {"A": "arg", "-v": true, "-q": false}
docopt {"argv": "-q arg"}
expect {"A": "arg", "-v": false, "-q": true}
#
# Test single dash
#
r"""usage: prog [-]"""
docopt {"argv": "-"}
expect {"-": true}
docopt {"argv": "$ prog"}
expect {"-": false}
#
# If argument is repeated, its value should always be a list
#
r"""usage: prog [NAME [NAME ...]]"""
docopt {"argv": "a b"}
expect {"NAME": ["a", "b"]}
docopt {"argv": "$ prog"}
expect {"NAME": []}
#
# Option's argument defaults to null/None
#
r"""usage: prog [options]
options:
-a Add
-m <msg> Message
"""
docopt {"argv": "-a"}
expect {"-m": null, "-a": true}
#
# Test options without description
#
r"""usage: prog --hello"""
docopt {"argv": "--hello"}
expect {"--hello": true}
r"""usage: prog [--hello=<world>]"""
docopt {"argv": "$ prog"}
expect {"--hello": null}
docopt {"argv": "--hello wrld"}
expect {"--hello": "wrld"}
r"""usage: prog [-o]"""
docopt {"argv": "$ prog"}
expect {"-o": false}
docopt {"argv": "-o"}
expect {"-o": true}
r"""usage: prog [-opr]"""
docopt {"argv": "-op"}
expect {"-o": true, "-p": true, "-r": false}
r"""usage: git [-v | --verbose]"""
docopt {"argv": "-v"}
expect {"-v": true, "--verbose": false}
r"""usage: git remote [-v | --verbose]"""
docopt {"argv": "remote -v"}
expect {"remote": true, "-v": true, "--verbose": false}
#
# Test empty usage pattern
#
r"""usage: prog"""
docopt {"argv": "$ prog"}
expect {}
r"""usage: prog
prog <a> <b>
"""
docopt {"argv": "1 2"}
expect {"<a>": "1", "<b>": "2"}
docopt {"argv": "$ prog"}
expect {"<a>": null, "<b>": null}
r"""usage: prog <a> <b>
prog
"""
docopt {"argv": "$ prog"}
expect {"<a>": null, "<b>": null}
#
# Option's argument should not capture default value from usage pattern
#
r"""usage: prog [--file=<f>]"""
docopt {"argv": "$ prog"}
expect {"--file": null}
r"""usage: prog [--file=<f>]
options: --file <a>
"""
docopt {"argv": "$ prog"}
expect {"--file": null}
r"""Usage: prog [-a <host:port>]
Options: -a, --address <host:port> TCP address [default: localhost:6283].
"""
docopt {"argv": "$ prog"}
expect {"--address": "localhost:6283"}
#
# If option with argument could be repeated,
# its arguments should be accumulated into a list
#
r"""usage: prog --long=<arg> ..."""
docopt {"argv": "--long one"}
expect {"--long": ["one"]}
docopt {"argv": "--long one --long two"}
expect {"--long": ["one", "two"]}
#
# Test multiple elements repeated at once
#
r"""usage: prog (go <direction> --speed=<km/h>)..."""
docopt {"argv": " go left --speed=5 go right --speed=9"}
expect {"go": 2, "<direction>": ["left", "right"], "--speed": ["5", "9"]}
#
# Required options should work with option shortcut
#
r"""usage: prog [options] -a
options: -a
"""
docopt {"argv": "-a"}
expect {"-a": true}
#
# If option could be repeated its defaults should be split into a list
#
r"""usage: prog [-o <o>]...
options: -o <o> [default: x]
"""
docopt {"argv": "-o this -o that"}
expect {"-o": ["this", "that"]}
docopt {"argv": "$ prog"}
expect {"-o": ["x"]}
r"""usage: prog [-o <o>]...
options: -o <o> [default: x y]
"""
docopt {"argv": "-o this"}
expect {"-o": ["this"]}
docopt {"argv": "$ prog"}
expect {"-o": ["x", "y"]}
#
# Test stacked option's argument
#
r"""usage: prog -pPATH
options: -p PATH
"""
docopt {"argv": "-pHOME"}
expect {"-p": "HOME"}
#
# Issue 56: Repeated mutually exclusive args give nested lists sometimes
#
r"""Usage: foo (--xx=x|--yy=y)..."""
docopt {"argv": "--xx=1 --yy=2"}
expect {"--xx": ["1"], "--yy": ["2"]}
#
# POSIXly correct tokenization
#
r"""usage: prog [<input file>]"""
docopt {"argv": "f.txt"}
expect {"<input file>": "f.txt"}
r"""usage: prog [--input=<file name>]..."""
docopt {"argv": "--input a.txt --input=b.txt"}
expect {"--input": ["a.txt", "b.txt"]}
#
# Issue 85: `[options]` shourtcut with multiple subcommands
#
r"""usage: prog good [options]
prog fail [options]
options: --loglevel=N
"""
docopt {"argv": "fail --loglevel 5"}
expect {"--loglevel": "5", "fail": true, "good": false}
#
# Usage-section syntax
#
r"""usage:prog --foo"""
docopt {"argv": "--foo"}
expect {"--foo": true}
r"""PROGRAM USAGE: prog --foo"""
docopt {"argv": "--foo"}
expect {"--foo": true}
r"""Usage: prog --foo
prog --bar
NOT PART OF SECTION
"""
docopt {"argv": "--foo"}
expect {"--foo": true, "--bar": false}
r"""Usage:
prog --foo
prog --bar
NOT PART OF SECTION
"""
docopt {"argv": "--foo"}
expect {"--foo": true, "--bar": false}
r"""Usage:
prog --foo
prog --bar
NOT PART OF SECTION
"""
docopt {"argv": "--foo"}
expect {"--foo": true, "--bar": false}
#
# Options-section syntax
#
r"""Usage: prog [options]
global options: --foo
local options: --baz
--bar
other options:
--egg
--spam
-not-an-option-
"""
docopt {"argv": "--baz --egg"}
expect {"--foo": false, "--baz": true, "--bar": false, "--egg": true, "--spam": false}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment