Humane command line arguments parser. Now with maintenance, typehints, and complete test coverage.

Overview

docopt-ng creates magic command-line interfaces

image

codecov

image

Jazzband

CHANGELOG

New in version 0.7.2:

  • Complete MyPy typehints - ZERO errors. Required refactoring class implementations, adding typing stubs, but not changing tests. :)
  • 100% code coverage. Required the addition of a few tests. Removed unused codepaths. Tagged typing stubs pragma: no cover as they are definitionally exercised.

New in version 0.7.1:

  • Add magic() and magic_docopt() aliases for docopt() allowing easier use of new features.

New in version 0.7.0:

  • "MORE MAGIC"
  • First argument is now optional - docopt() will look for __doc__ defined in parent scopes.
  • Dot access is supported on resulting arguments object, ignoring angle brackets and leading dashes.
  • more_magic parameter added to docopt() defaults False.
  • If more_magic enabled, arguments variable created and populated in calling scope with results.
  • If more_magic enabled, fuzzy (levenshtein) autocorrect enabled for long-args.
  • Lots of typehints.
  • README moved to Markdown.

New in version 0.6.3:

  • Catch up on ~two years of pull requests.
  • Fork docopt to docopt-ng.
  • Add levenshtein based autocorrect from string-dist.
  • Add better debug / error messages.
  • Linting (via black and flake8).

New in version 0.6.2:

  • Bugfixes

New in version 0.6.1:

  • Fix issue #85 which caused improper handling of [options] shortcut if it was present several times.

New in version 0.6.0:

  • New argument options_first, disallows interspersing options and arguments. If you supply options_first=True to docopt, it will interpret all arguments as positional arguments after first positional argument.
  • If option with argument could be repeated, its default value will be interpreted as space-separated list. E.g. with [default: ./here ./there] will be interpreted as ['./here', './there'].

docopt-ng helps you create beautiful command-line interfaces magically:

... naval_fate.py ship move [--speed= ] naval_fate.py ship shoot naval_fate.py mine (set|remove) [--moored | --drifting] naval_fate.py (-h | --help) naval_fate.py --version Options: -h --help Show this screen. --version Show version. --speed= Speed in knots [default: 10]. --moored Moored (anchored) mine. --drifting Drifting mine. """ from docopt import docopt if __name__ == '__main__': arguments = docopt(__doc__, version='Naval Fate 2.0') print(arguments)">
"""Naval Fate.

Usage:
  naval_fate.py ship new 
            
             ...
  naval_fate.py ship 
             
               move 
               
               
                 [--speed=
                
                 ] naval_fate.py ship shoot 
                  
                  
                    naval_fate.py mine (set|remove) 
                    
                    
                      [--moored | --drifting] naval_fate.py (-h | --help) naval_fate.py --version Options: -h --help Show this screen. --version Show version. --speed=
                     
                       Speed in knots [default: 10]. --moored Moored (anchored) mine. --drifting Drifting mine. """ from docopt import docopt if __name__ == '__main__': arguments = docopt(__doc__, version='Naval Fate 2.0') print(arguments) 
                     
                    
                   
                  
                 
                
               
              
             
            

Beat that! The option parser is generated based on the docstring above that is passed to docopt function. docopt parses the usage pattern ("Usage: ...") and option descriptions (lines starting with dash "-") and ensures that the program invocation matches the usage pattern; it parses options, arguments and commands based on that. The basic idea is that a good help message has all necessary information in it to make a parser.

Also, PEP 257 recommends putting help message in the module docstrings.

Installation

Use pip or easy_install:

pip install docopt-ng

Alternatively, you can just drop docopt.py file into your project--it is self-contained.

docopt-ng is tested with Python 3.6 and 3.7.

Testing

You can run unit tests using the command:

python setup.py test

API

from docopt import docopt
docopt(docstring=None, argv=None, help=True, version=None, options_first=False, more_magic=False)

docopt takes 6 optional arguments:

  • docstring could be a module docstring (__doc__) or some other string that contains a help message that will be parsed to create the option parser. The simple rules of how to write such a help message are given in next sections. Here is a quick example of such a string:
"""Usage: my_program.py [-hso FILE] [--quiet | --verbose] [INPUT ...]

-h --help    show this
-s --sorted  sorted output
-o FILE      specify output file [default: ./test.txt]
--quiet      print less text
--verbose    print more text

"""
If it is None (not provided) - the calling scope will be interrogated for a docstring.
  • argv is an optional argument vector; by default docopt uses the argument vector passed to your program (sys.argv[1:]). Alternatively you can supply a list of strings like ['--verbose', '-o', 'hai.txt'].

  • help, by default True, specifies whether the parser should automatically print the help message (supplied as doc) and terminate, in case -h or --help option is encountered (options should exist in usage pattern, more on that below). If you want to handle -h or --help options manually (as other options), set help=False.

  • version, by default None, is an optional argument that specifies the version of your program. If supplied, then, (assuming --version option is mentioned in usage pattern) when parser encounters the --version option, it will print the supplied version and terminate. version could be any printable object, but most likely a string, e.g. "2.1.0rc1".

    Note, when docopt is set to automatically handle -h, --help and --version options, you still need to mention them in usage pattern for this to work. Also, for your users to know about them.

  • options_first, by default False. If set to True will disallow mixing options and positional argument. I.e. after first positional argument, all arguments will be interpreted as positional even if the look like options. This can be used for strict compatibility with POSIX, or if you want to dispatch your arguments to other programs.

  • more_magic, by default False. If set to True more advanced efforts will be made to correct --long_form arguments, ie: --hlep will be corrected to --help. Additionally, if not already defined, the variable arguments will be created and populated in the calling scope. more_magic is also set True if docopt() is is aliased to a name containing magic ie) by built-infrom docopt import magic or user-defined from docopt import docopt as magic_docopt_wrapper for convenience.

The return value is a simple dictionary with options, arguments and commands as keys, spelled exactly like in your help message. Long versions of options are given priority. Furthermore, dot notation is supported, with preceeding dashes (-) and surrounding brackets (<>) ignored. For example, if you invoke the top example as:

naval_fate.py ship Guardian move 100 150 --speed=15

the return dictionary will be:

{'--drifting': False,    'mine': False,
 '--help': False,        'move': True,
 '--moored': False,      'new': False,
 '--speed': '15',        'remove': False,
 '--version': False,     'set': False,
 '
   
    ': ['Guardian'], 'ship': True,
 '
    
     ': '100',           'shoot': False,
 '
     
      ': '150'}

     
    
   

...and properties can be accessed with arguments.drifting or arguments.x.

Help message format

Help message consists of 2 parts:

  • Usage pattern, e.g.:

    Usage: my_program.py [-hso FILE] [--quiet | --verbose] [INPUT ...]
    
  • Option descriptions, e.g.:

    -h --help    show this
    -s --sorted  sorted output
    -o FILE      specify output file [default: ./test.txt]
    --quiet      print less text
    --verbose    print more text
    

Their format is described below; other text is ignored.

Usage pattern format

Usage pattern is a substring of doc that starts with usage: (case insensitive) and ends with a visibly empty line. Minimum example:

"""Usage: my_program.py

"""

The first word after usage: is interpreted as your program's name. You can specify your program's name several times to signify several exclusive patterns:

"""Usage: my_program.py FILE
          my_program.py COUNT FILE

"""

Each pattern can consist of the following elements:

  • , ARGUMENTS. Arguments are specified as either upper-case words, e.g. my_program.py CONTENT-PATH or words surrounded by angular brackets: my_program.py .
  • --options. Options are words started with dash (-), e.g. --output, -o. You can "stack" several of one-letter options, e.g. -oiv which will be the same as -o -i -v. The options can have arguments, e.g. --input=FILE or -i FILE or even -iFILE. However it is important that you specify option descriptions if you want your option to have an argument, a default value, or specify synonymous short/long versions of the option (see next section on option descriptions).
  • commands are words that do not follow the described above conventions of --options or or ARGUMENTS, plus two special commands: dash "-" and double dash "--" (see below).

Use the following constructs to specify patterns:

  • [ ] (brackets) optional elements. e.g.: my_program.py [-hvqo FILE]
  • ( ) (parens) required elements. All elements that are not put in [ ] are also required, e.g.: my_program.py --path= ... is the same as my_program.py (--path= ...) . (Note, "required options" might be not a good idea for your users).
  • | (pipe) mutually exclusive elements. Group them using ( ) if one of the mutually exclusive elements is required: my_program.py (--clockwise | --counter-clockwise) TIME. Group them using [ ] if none of the mutually-exclusive elements are required: my_program.py [--left | --right].
  • ... (ellipsis) one or more elements. To specify that arbitrary number of repeating elements could be accepted, use ellipsis (...), e.g. my_program.py FILE ... means one or more FILE-s are accepted. If you want to accept zero or more elements, use brackets, e.g.: my_program.py [FILE ...]. Ellipsis works as a unary operator on the expression to the left.
  • [options] (case sensitive) shortcut for any options. You can use it if you want to specify that the usage pattern could be provided with any options defined below in the option-descriptions and do not want to enumerate them all in usage-pattern.
  • "[--]". Double dash "--" is used by convention to separate positional arguments that can be mistaken for options. In order to support this convention add "[--]" to your usage patterns.
  • "[-]". Single dash "-" is used by convention to signify that stdin is used instead of a file. To support this add "[-]" to your usage patterns. "-" acts as a normal command.

If your pattern allows to match argument-less option (a flag) several times:

Usage: my_program.py [-v | -vv | -vvv]

then number of occurrences of the option will be counted. I.e. args['-v'] will be 2 if program was invoked as my_program -vv. Same works for commands.

If your usage patterns allows to match same-named option with argument or positional argument several times, the matched arguments will be collected into a list:

Usage: my_program.py 
    
    
      --path=
     
      ...

     
    
   

I.e. invoked with my_program.py file1 file2 --path=./here --path=./there the returned dict will contain args[' '] == ['file1', 'file2'] and args['--path'] == ['./here', './there'].

Option descriptions format

Option descriptions consist of a list of options that you put below your usage patterns.

It is necessary to list option descriptions in order to specify:

  • synonymous short and long options,
  • if an option has an argument,
  • if option's argument has a default value.

The rules are as follows:

  • Every line in doc that starts with - or -- (not counting spaces) is treated as an option description, e.g.:

    Options:
      --verbose   # GOOD
      -o FILE     # GOOD
    Other: --bad  # BAD, line does not start with dash "-"
    
  • To specify that option has an argument, put a word describing that argument after space (or equals "=" sign) as shown below. Follow either or UPPER-CASE convention for options' arguments. You can use comma if you want to separate options. In the example below, both lines are valid, however you are recommended to stick to a single style.:

    , --input # with comma, without "=" sign">
    -o FILE --output=FILE       # without comma, with "=" sign
    -i 
          
           , --input 
           
               # with comma, without "=" sign
    
           
          
  • 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
    
  • If you want to set a default value for an option with an argument, put it into the option-description, in form [default: ] :

    --coefficient=K  The K coefficient [default: 2.95]
    --output=FILE    Output file [default: test.txt]
    --directory=DIR  Some directory [default: ./]
    
  • If the option is not repeatable, the value inside [default: ...] will be interpreted as string. If it is repeatable, it will be splited into a list on whitespace:

    Usage: my_program.py [--repeatable=
         
           --repeatable=
          
           ]
                         [--another-repeatable=
           
            ]...
                         [--not-repeatable=
            
             ]
    
    # will be ['./here', './there']
    --repeatable=
             
               [default: ./here ./there] # will be ['./here'] --another-repeatable=
              
                [default: ./here] # will be './here ./there', because it is not repeatable --not-repeatable=
               
                 [default: ./here ./there] 
               
              
             
            
           
          
         

Examples

We have an extensive list of examples which cover every aspect of functionality of docopt-ng. Try them out, read the source if in doubt.

Development

We would love to hear what you think about docopt-ng on our issues page

Make pull requests, report bugs, suggest ideas and discuss docopt-ng.

Comments
  • Is docopt-ng dead?

    Is docopt-ng dead?

    This question was previously asked about docopt, but now docopt-ng seems to have ended up in the same situation - unmerged/unanswered PRs and issues. It would be really great to have a 'live' docopt for Python.

    opened by lhupfeldt 19
  • Restore compatibility with docopt 0.6.2 docstrings

    Restore compatibility with docopt 0.6.2 docstrings

    This is my proposal to fix #33. (With the assumption that compatibility with docopt is a goal of docopt-ng.)

    This PR adds two new functions, parse_docstring_sections() and parse_options(); and uses them to parse docstrings accepted by docopt 0.6.2, while retaining docopt-ng's improvements to supported syntax.

    Currently, docopt-ng parses option-defaults using a strategy that was in docopt's master branch, but considered unstable by the author, and was not released in docopt. It looks for option descriptions in an "options:" section, which is ended on the first blank line. This has the side-effect that options defined in a man-page style — with blank lines in-between — are not found. Neither are options outside an options: section (docopt allows options to follow the usage with no section heading).

    parse_docstring_sections() is used to separate the usage section from the rest of the docstring. The text before the usage is ignored. The usage body (without its header) is parsed for the argument pattern and the usage header with its body is used to print the usage summary help. The text following the usage is parsed for options descriptions, using parse_options(), which supports option the description syntax of both docopt and the current docopt-ng.

    Note that docopt 0.6.2 recognises option descriptions in the text prior to the usage section, but this change does not, as it seems like an unintended side-effect of the previous parser's implementation, and seems unlikely to be used in practice.

    The testcases have two cases added for docopt 0.6.2 compatibility.

    The first commit ("Fix test for missing arg before --") could be merged separately, but my final commit's tests depends on it.

    opened by h4l 17
  • Assert error message content in tests

    Assert error message content in tests

    I'm going to have a crack at making the error messages a little more user-friendly, to resolve #5. Especially the Warning: found unmatched (duplicate?) arguments [Argument(None, '.\\10. PowerShell.ps1')] that occurs in response to an end user passing incorrect or too many arguments when running a program using docopt-ng. I need that to be resolved before I can use docopt-ng in place of docopt really.

    Before making changes there, I'd like to ensure the current messages are tested, so I can be sure I don't change messages unexpectedly.

    This PR mostly adds exception message assertions to all the places where tests trigger an exception or SystemExit with usage.

    The first 3 commits are unrelated to these messages assertions — small improvements to the dev experience using this repo. They could go into a separate PR if you prefer, but I've already opened a few, so I didn't want to swamp with too many!

    opened by h4l 10
  • Implement Jazzband guidelines for docopt-ng

    Implement Jazzband guidelines for docopt-ng

    This issue tracks the implementation of the Jazzband guidelines for the project docopt-ng

    It was initiated by @itdaniher who was automatically assigned in addition to the Jazzband roadies.

    See the TODO list below for the generally required tasks, but feel free to update it in case the project requires it.

    Feel free to ping a Jazzband roadie if you have any question.

    TODOs

    • [x] Fix all links in the docs (and README file etc) from old to new repo
    • [x] Add the Jazzband badge to the README file
    • [x] Add the Jazzband contributing guideline to the CONTRIBUTING.md or CONTRIBUTING.rst file
    • [x] Port Travis config to GitHub Actions following previous examples (see linked GitHub project board)
    • [x] Port test coverage testing to Codecov if needed (Codecov)
    • [x] Add jazzband account to PyPI project as maintainer role (e.g. URL: https://pypi.org/manage/project/docopt-ng/collaboration/)
    • N/A Add jazzband-bot as maintainer to the Read the Docs project (e.g. URL: https://readthedocs.org/dashboard/docopt-ng/users/)
    • N/A Add incoming GitHub webhook integration to Read the Docs project (e.g. URL: https://readthedocs.org/dashboard/docopt-ng/integrations/)
    • [x] Fix project URL in GitHub project description
    • [x] Review project if other services are used and port them to Jazzband
    • [x] Decide who is project lead for the project (if at all)
    • [x] Set up CI for Jazzband project releases if needed and open ticket if yes

    Project details

    Description Humane command line arguments parser. Now with maintenance, typehints, and complete test coverage.
    Homepage
    Stargazers 36
    Open issues 9
    Forks 6
    Default branch master
    Is a fork False
    Has Wiki False
    Has Pages False
    opened by jazzband-bot 10
  • Make PEP561 compatible (allow mypy to actually find type hints)

    Make PEP561 compatible (allow mypy to actually find type hints)

    My project https://github.com/staticjinja/staticjinja uses mypy, but it can't actually use the type hints defined here because we aren't following https://mypy.readthedocs.io/en/stable/installed_packages.html#creating-pep-561-compatible-packages

    PR to follow

    opened by NickCrews 8
  • Question: auto formatting & sorting imports

    Question: auto formatting & sorting imports

    @NickCrews would you be OK with auto sorting/formatting imports (probably with isort)?

    When I was rebasing the error message PR just now, and a few other branches I've got, probably 3/4 of my merge conflicts were just imports. I'm thinking it would help to use isort with the single line option, so that instead of:

    from typing import Any, Callable, Tuple, Type, Union, cast
    

    we get:

    from typing import Any
    from typing import Callable
    from typing import Tuple
    from typing import Type
    from typing import Union
    from typing import cast
    

    Which doesn't look as nice, but means import changes shouldn't cause merge conflicts.

    opened by h4l 5
  • docopt-ng fails to parse usage string that worked with docopt

    docopt-ng fails to parse usage string that worked with docopt

    I've got an old CLI program which uses OG docopt. I'm giving it a bit of minor TLC to refresh the tooling, and I tried switching to docopt-ng, but -ng fails to parse my usage string for some reason:

    [email protected] /w/rnginline ((bef5200c…)) [127]> poetry run ipython
    Python 3.10.5 (main, Jun  6 2022, 12:05:50) [GCC 9.5.0]
    Type 'copyright', 'credits' or 'license' for more information
    IPython 8.4.0 -- An enhanced Interactive Python. Type '?' for help.
    
    In [1]: import docopt
    
    In [2]: docopt.__version__
    Out[2]: '0.8.1'
    
    In [3]: from rnginline import cmdline
    
    In [4]: docopt.docopt(cmdline.__doc__, argv=['rnginline', '--no-libxml2-compat', '/some/file'])
    An exception has occurred, use %tb to see the full traceback.
    
    DocoptExit: Warning: found unmatched (duplicate?) arguments [Option(None, '--no-libxml2-compat', 0, True)]
    usage: rnginline [options] <rng-src> [<rng-output>]
           rnginline [options] --stdin [<rng-output>]
    
    /home/vscode/.cache/pypoetry/virtualenvs/rnginline--qKLlanv-py3.10/lib/python3.10/site-packages/IPython/core/interactiveshell.py:3406: UserWarning: To exit: use 'exit', 'quit', or Ctrl-D.
      warn("To exit: use 'exit', 'quit', or Ctrl-D.", stacklevel=1)
    
    In [5]:                                                                                                                                                                                                            
    Do you really want to exit ([y]/n)? y
    [email protected] /w/rnginline ((bef5200c…))> poetry run pip uninstall docopt-ng
    Found existing installation: docopt-ng 0.8.1
    Uninstalling docopt-ng-0.8.1:
      Would remove:
        /home/vscode/.cache/pypoetry/virtualenvs/rnginline--qKLlanv-py3.10/lib/python3.10/site-packages/docopt/*
        /home/vscode/.cache/pypoetry/virtualenvs/rnginline--qKLlanv-py3.10/lib/python3.10/site-packages/docopt_ng-0.8.1.dist-info/*
    Proceed (Y/n)? y
      Successfully uninstalled docopt-ng-0.8.1
    [email protected] /w/rnginline ((bef5200c…))> poetry run pip install docopt
    Collecting docopt
      Using cached docopt-0.6.2-py2.py3-none-any.whl
    Installing collected packages: docopt
    Successfully installed docopt-0.6.2
    
    [email protected] /w/rnginline ((bef5200c…))> poetry run ipython
    Python 3.10.5 (main, Jun  6 2022, 12:05:50) [GCC 9.5.0]
    Type 'copyright', 'credits' or 'license' for more information
    IPython 8.4.0 -- An enhanced Interactive Python. Type '?' for help.
    
    In [1]: import docopt
    
    In [2]: docopt.__version__
    Out[2]: '0.6.2'
    
    In [3]: from rnginline import cmdline
    
    In [4]: docopt.docopt(cmdline.__doc__, argv=['rnginline', '--no-libxml2-compat', '/some/file'])
    Out[4]: 
    {'-': None,
     '--base-uri': None,
     '--default-base-uri': None,
     '--help': False,
     '--no-libxml2-compat': True,
     '--stdin': False,
     '--traceback': False,
     '--version': False,
     '<rng-output>': '/some/file',
     '<rng-src>': 'rnginline'}
    

    This is the usage string: https://github.com/h4l/rnginline/blob/b1d1c8cda2a17d46627309950f2442021749c07e/rnginline/cmdline.py#L14

    I really appreciate your efforts in keeping docopt going, It's a great library.

    opened by h4l 4
  • fork

    fork

    the idea of forking docopt because it's unmaintained it's cool but the idea of docopt is to be available in tons of languages, while docopt-ng only forked the python implementation. Do you plan to fork all others https://github.com/docopt?

    opened by noraj 4
  • Report exceptions that cause failures in testcases.docopt

    Report exceptions that cause failures in testcases.docopt

    Currently only DocoptTestException is reported, no info on the error is shown if any other error is raised during a testcases.docopt test. This change delegates to the default pytest.Item error reporting implementation for non-docopt errors.

    opened by h4l 3
  • Fix magic with arguments that have a dash

    Fix magic with arguments that have a dash

    I'd like to be able to support arguments that look like this:

    -a --argument-name This is the argument to test

    This PR enables dot access as before but converts the name to arguments.argument_name.

    opened by johnscillieri 3
  • Cleaning state pollution of global variable `arguments` by assigning with None

    Cleaning state pollution of global variable `arguments` by assigning with None

    This PR aims to improve test reliability of test test_docopt_ng_more_magic_global_arguments_and_dot_access by cleaning state pollution of global variable arguments by assigning with None.

    The test can fail in this way by running pip3 install pytest-repeat; python3 -m pytest --count=2 tests/test_docopt_ng.py::test_docopt_ng_more_magic_global_arguments_and_dot_access:

            global arguments
            docopt.docopt(doc, "-v file.py", more_magic=True)
    >       assert arguments == {"-v": True, "-q": False, "-r": False, "--help": False, "FILE": "file.py", "INPUT": None, "OUTPUT": None}
    E       AssertionError: assert {'--help': Fa...OUTPUT': None} == {'--help': Fa...v': True, ...}
    E         Omitting 6 identical items, use -vv to show
    E         Left contains 1 more item:
    E         {'<FILE>': None}
    E         Right contains 1 more item:
    E         {'FILE': 'file.py'}
    

    It may be better to clean state pollutions so that some other tests won't fail in the future due to the shared state pollution.

    opened by sturmianseq 2
  • Integrate docopt-dispatch in this project

    Integrate docopt-dispatch in this project

    I have started using docopt-dispatch and I find it very intriguing. It makes docopt CLI code super-concise and readable.

    Unfortunately, that package both has docopt as a hard dependency and is unmaintained for 7+ years.

    If we integrated the dispatching project in docopt-ng some CLI code could look like this, preserving the compatibility with the original docopt spec and staying aligned with the syntax of the original dispatch project:

    """Run something in development or production mode.
    
    Usage: run.py --development <host> <port>
           run.py --production <host> <port>
           run.py remote add <item>
           run.py remote delete <item>
    """
    from docopt import dispatch
    
    
    @dispatch.on('--development')
    def development(host, port, **kwargs):
        print('in *development* mode')
    
    
    @dispatch.on('--production')
    def development(host, port, **kwargs):
        print('in *production* mode')
    
    
    if __name__ == 'main':
        dispatch(__doc__)
    

    Would you accept a PR that adds the dispatching feature to docopt-ng?

    opened by bittner 0
  • Failing to put two spaces in description sometimes results in very obscure error.

    Failing to put two spaces in description sometimes results in very obscure error.

    I just began using docopt-ng. I was creating my interface from scratch (I currently use a functional but spaghetti-like script), and my docstring read something like:

    """Performous macOS Bundler
    
    Usage:
        macos_bundler.py
        macos_bundler.py [options]
        macos_bundler.py (-h | --help)
    
    Options:
    ...
    """
    

    But I kept getting the following error and couldn't figure out why.

        raise tokens.error("unmatched '%s'" % token)
    docopt.DocoptLanguageError: unmatched '('
    

    I double checked brackets and there were definitely no unmatched ones. I then double-checked the documentation to make sure I hadn't made a mistake with the syntax, and I couldn't find one.

    I had read sometimes docopt (I think the original one?) had issues with pipes, so even though that exact syntax appeared in the documentation, I tried to remove the macos_bundler.py (-h | --help) line and, the error went away; but I couldn't use either -h nor --help, because it kept telling me those optons needed an argument.

    Upon closer inspection, I noticed I had missed a space between -h --help and the option description.

    So, it seems missing writing something such as

    """Command
    Usage:
        cli_tool.py (-s | --long)
    
    Options:
        -s --long Some description for this option.
    """
    

    Will produce such an error.

    Of course, there is an error there, and one the documentation specifically warns against. However, in this particular scenario, the error message was very obscure.

    opened by Lord-Kamina 0
  • When docopt and docopt-ng are in the same venv, docopt takes precidence

    When docopt and docopt-ng are in the same venv, docopt takes precidence

    If you install pipenv install pipreqs pip-upgrader docopt-ng Which sometimes happens, you can't put everything into system or pipx.

    Then apps use the wrong docopt.

    $ python
    >>> import docopt
    >>> docopt.__file__
    'C:\\Users\\matth\\.virtualenvs\\demo_doc-j-5bRj6B\\lib\\site-packages\\docopt.py'
    >>> exit()
    
    $ pip install docopt-ng
    Requirement already satisfied: docopt-ng in c:\users\matth\.virtualenvs\demo_doc-j-5brj6b\lib\site-packages (0.7.2)
    

    In C# there was a way to handle this and ensure that two similarly named dlls weren't confused with each other, I don't know what the python way is to handle this scenario.

    opened by matthewdeanmartin 5
  • Performance penalty: combinatorial explosion in `transform`

    Performance penalty: combinatorial explosion in `transform`

    Description

    Using docopt for building utilities with relatively wide range of options is pretty limited because of a huge performance penalty. Namely, a combinatorial explosion may happen in the transform function: the pattern expansion (like ((-a | -b) (-c | -d)) => (-a -c | -a -d | -b -c | -b -d)) has unacceptable computational complexity.

    A good example would be the GNU ls utility. See the sample below.

    To Reproduce

    The script below takes almost 3 seconds to run which is terribly slow for just to parse CLI arguments.

    """
    ls with a subset of GNU options (that's not even all of them!)
    
    Usage:
        ls [-a|-A] [--hide=PATTERN] [-I=PATTERN] [-dLR]
           [--color] [-h|--si] [--indicator-style=WORD|-p|-F|--file-type]
           [--format=WORD|-x|-m|-x|-l|-1|-C|-g|-n|-o] [-Giks]
           [--sort=WORD|-f|-U|-S|-t|-v|-X] [--group-directories-first] [-r]
           [--time=WORD|-u|-c] [--time-style=TIME_STYLE]
           [FILES ...]
        ls --help
        ls --version
    
    Arguments:
        FILES
            list of files
    """
    from docopt import docopt
    
    args = docopt()
    
    opened by DNikolaevAtRocket 1
  • Written a docopt grammar, interested ?

    Written a docopt grammar, interested ?

    Not seeing any references to an actual docopt formal grammar yet, I am writing a PEG grammar for use in Python with Tatsu (https://tatsu.readthedocs.io). I am hopeful that it will be usable with other PEG parser generators but am not well enough versed in the area to know by how much they differ in syntax.

    I would like to work with others interested in developing a formal grammar for docopt. I'm not fixed on Tatsu or even PEG though I suspect PEG grammars will provide more accurate results for the corner cases.

    I appended a sketch of the steps I believe necessary to develop the grammar. I've written a grammar for the usage examples section. Now I need to take a step back and write the frame work to snag each major section. Divide and conquer seemed like the best approach. In a day or so, I could post the grammar and test cases to github.

    So, any information in this area or would anyone like to collaborate ?

    Philip


    Unix Utility Usage Grammar

    Or, a formal grammar for the docopy language.

    First identify which elements must be parsed and which (if any) may be discarded (or perhaps remain free form text).

    Characterize the delineations of each section sufficiently to write regular expression matchers for their start and end, or span.

    Write a grammar to parse to just the sections out as blocks of free form text. This forms the framework within which the section parsers will operate.

    For each section independently write a grammar to parse the it.

    One by one, incorporate the section parsers into the framework.

    opened by philip-h-dye 5
Releases(0.8.1)
  • 0.8.1(May 31, 2022)

    What's Changed

    • Actually run release workflow on tag push by @NickCrews in https://github.com/jazzband/docopt-ng/pull/29

    Full Changelog: https://github.com/jazzband/docopt-ng/compare/0.8.0...0.8.1

    Source code(tar.gz)
    Source code(zip)
  • 0.8.0(May 31, 2022)

    What's Changed

    • Fix magic with arguments that have a dash by @johnscillieri in https://github.com/jazzband/docopt-ng/pull/6
    • Expose DocoptExit exception in the all by @nyurik in https://github.com/jazzband/docopt-ng/pull/8
    • Update setup.py by @NickCrews in https://github.com/jazzband/docopt-ng/pull/17
    • Jazzband: Synced file(s) with jazzband/.github by @jazzband-bot in https://github.com/jazzband/docopt-ng/pull/21
    • Migrate to GitHub Actions. by @jezdez in https://github.com/jazzband/docopt-ng/pull/23
    • Cleaning state pollution of global variable arguments by assigning with None by @sturmianseq in https://github.com/jazzband/docopt-ng/pull/20
    • Apply black by @NickCrews in https://github.com/jazzband/docopt-ng/pull/24
    • Update to newer type annotation syntax by @NickCrews in https://github.com/jazzband/docopt-ng/pull/25
    • Readme by @NickCrews in https://github.com/jazzband/docopt-ng/pull/26
    • Setup.cfg by @NickCrews in https://github.com/jazzband/docopt-ng/pull/28

    New Contributors

    • @johnscillieri made their first contribution in https://github.com/jazzband/docopt-ng/pull/6
    • @nyurik made their first contribution in https://github.com/jazzband/docopt-ng/pull/8
    • @NickCrews made their first contribution in https://github.com/jazzband/docopt-ng/pull/17
    • @jazzband-bot made their first contribution in https://github.com/jazzband/docopt-ng/pull/21
    • @jezdez made their first contribution in https://github.com/jazzband/docopt-ng/pull/23
    • @sturmianseq made their first contribution in https://github.com/jazzband/docopt-ng/pull/20

    Full Changelog: https://github.com/jazzband/docopt-ng/compare/0.7.2...0.8.0

    Source code(tar.gz)
    Source code(zip)
Owner
Jazzband
We are all part of this
Jazzband
A drop-in replacement for argparse that allows options to also be set via config files and/or environment variables.

ConfigArgParse Overview Applications with more than a handful of user-settable options are best configured through a combination of command line args,

634 Dec 22, 2022
sane is a command runner made simple.

sane is a command runner made simple.

Miguel M. 22 Jan 03, 2023
A thin, practical wrapper around terminal capabilities in Python

Blessings Coding with Blessings looks like this... from blessings import Terminal t = Terminal() print(t.bold('Hi there!')) print(t.bold_red_on_brig

Erik Rose 1.4k Jan 07, 2023
Python composable command line interface toolkit

$ click_ Click is a Python package for creating beautiful command line interfaces in a composable way with as little code as necessary. It's the "Comm

The Pallets Projects 13.3k Dec 31, 2022
A fast, stateless http slash commands framework for scale. Built by the Crunchy bot team.

Roid 🤖 A fast, stateless http slash commands framework for scale. Built by the Crunchy bot team. 🚀 Installation You can install roid in it's default

Harrison Burt 7 Aug 09, 2022
Terminalcmd - a Python library which can help you to make your own terminal program with high-intellegence instruments

Terminalcmd - a Python library which can help you to make your own terminal program with high-intellegence instruments, that will make your code clear and readable.

Dallas 0 Jun 19, 2022
prompt_toolkit is a library for building powerful interactive command line applications in Python.

Python Prompt Toolkit prompt_toolkit is a library for building powerful interactive command line applications in Python. Read the documentation on rea

prompt-toolkit 8.1k Jan 04, 2023
plotting in the terminal

bashplotlib plotting in the terminal what is it? bashplotlib is a python package and command line tool for making basic plots in the terminal. It's a

Greg Lamp 1.7k Jan 02, 2023
Textual is a TUI (Text User Interface) framework for Python using Rich as a renderer.

Textual is a TUI (Text User Interface) framework for Python using Rich as a renderer. The end goal is to be able to rapidly create rich termin

Will McGugan 17k Jan 02, 2023
A simple terminal Christmas tree made with Python

Python Christmas Tree A simple CLI Christmas tree made with Python Installation Just clone the repository and run $ python terminal_tree.py More opti

Francisco B. 64 Dec 27, 2022
Python Command-line Application Tools

Clint: Python Command-line Interface Tools Clint is a module filled with a set of awesome tools for developing commandline applications. C ommand L in

Kenneth Reitz Archive 82 Dec 28, 2022
Python library that measures the width of unicode strings rendered to a terminal

Introduction This library is mainly for CLI programs that carefully produce output for Terminals, or make pretend to be an emulator. Problem Statement

Jeff Quast 305 Dec 25, 2022
Cleo allows you to create beautiful and testable command-line interfaces.

Cleo Create beautiful and testable command-line interfaces. Cleo is mostly a higher level wrapper for CliKit, so a lot of the components and utilities

Sébastien Eustace 984 Jan 02, 2023
Pythonic command line arguments parser, that will make you smile

docopt creates beautiful command-line interfaces Video introduction to docopt: PyCon UK 2012: Create *beautiful* command-line interfaces with Python N

7.7k Dec 30, 2022
emoji terminal output for Python

Emoji Emoji for Python. This project was inspired by kyokomi. Example The entire set of Emoji codes as defined by the unicode consortium is supported

Taehoon Kim 1.6k Jan 02, 2023
A CLI tool to build beautiful command-line interfaces with type validation.

Piou A CLI tool to build beautiful command-line interfaces with type validation. It is as simple as from piou import Cli, Option cli = Cli(descriptio

Julien Brayere 310 Dec 07, 2022
A module for parsing and processing commands.

cmdtools A module for parsing and processing commands. Installation pip install --upgrade cmdtools-py install latest commit from GitHub pip install g

1 Aug 14, 2022
Python library to build pretty command line user prompts ✨Easy to use multi-select lists, confirmations, free text prompts ...

Questionary ✨ Questionary is a Python library for effortlessly building pretty command line interfaces ✨ Features Installation Usage Documentation Sup

Tom Bocklisch 990 Jan 01, 2023
Cement is an advanced Application Framework for Python, with a primary focus on CLI

Cement Framework Cement is an advanced Application Framework for Python, with a primary focus on Command Line Interfaces (CLI). Its goal is to introdu

Data Folk Labs, LLC 1.1k Dec 31, 2022
Command line animations based on the state of the system

shell-emotions Command line animations based on the state of the system for Linux or Windows 10 The ascii animations were created using a modified ver

Simon Malave 63 Nov 12, 2022