Skip to content

docopt2

Typed successor to docopt. The usage message is the parser spec.

from docopt2 import docopt

args = docopt("Usage: prog <host> <port>", "127.0.0.1 8080")
args
# {'<host>': '127.0.0.1', '<port>': '8080'}   -> an Arguments, a dict subclass

No builder, no decorators. You write the help text you would have written anyway, and that text parses the argv.

Pass a schema= and the same usage returns a typed object, each value coerced to its field type:

import dataclasses

from docopt2 import docopt


@dataclasses.dataclass
class Args:
    host: str
    port: int  # coerced from the parsed string


args = docopt("Usage: prog <host> <port>", "127.0.0.1 8080", schema=Args)
args
# Args(host='127.0.0.1', port=8080)   -> port is an int, not a str

Drop-in for docopt

docopt2 parses the same usage grammar and returns the same mapping, so switching over is a one-line import change.

It is a superset, not a bit-identical clone. It accepts some argvs the original rejects, and it fixes three of the original's parsing bugs. Every divergence is pinned by name.

Diagnostics come with it. Everything else is opt-in: typed results, linting, stubs, completion, dispatch.

Zero dependencies

The core runs on the standard library alone. Nothing to install, nothing to audit. pydantic and Hypothesis are optional extras (docopt2[pydantic], docopt2[hypothesis]), used only when you pass a pydantic model as a schema or reach for the Hypothesis strategy.

Why docopt2

  • Typed results


    Pass a dataclass, TypedDict, Cli subclass, or pydantic model as schema=. Values come back coerced to their field types, never a dict[str, Any].

    Typed results

  • Diagnostics that point at the problem


    A mismatch carets the offending token in your argv and cross-references the usage that rejected it. suggest=True adds a spell-checked "did you mean".

    Diagnostics

  • Subcommand dispatch


    Dispatch routes a matched command path to its handler, optionally typed per command. It is the dispatch layer docopt itself omits.

    Subcommand dispatch

  • Shell completion


    Context-aware completion scripts for bash, zsh, fish, PowerShell, and nushell. Tab offers only what is valid at the cursor.

    Shell completion

  • Schema codegen


    docopt2 stub (or generate_stub) writes the typed schema from your usage, in three styles, so you never hand-write it.

    Schema stubs

  • Layered value resolution


    Declare [env: VAR] and [config: key] in the usage. docopt2 resolves CLI over env over config over default, and args.source() reports which layer won.

    Layered fallback

  • Self-documenting --help


    help_style="rich" renders an aligned, colored help screen. It scopes to the subcommand the user typed and shows where each value resolves from.

    Rich help

  • Example generation


    docopt2 examples (or generate_examples) samples the argvs your usage accepts. Use it for drift detection, parser fuzzing, or a Hypothesis strategy.

    Example generation

  • Static usage linter


    docopt2 check (or check) lints the usage grammar itself: dead defaults, unusable options, ambiguous variadics. It catches them before they ship.

    Usage linting

  • Usage formatter


    docopt2 fmt (or format_usage) aligns the Options: block into one column. It is the formatter to check's linter, and it never changes what the usage parses to.

    Formatting usage

  • Round-trip codec


    format_argv is the inverse of docopt. It rebuilds a canonical argv from a parsed result and verifies it by re-parsing, so one usage spec drives both directions.

    Round-trip to argv

  • Compatibility checking


    check_compat (or docopt2 compat) reports the invocations an old usage accepts that a new one rejects. It surfaces only breaks it can prove, so it fits a release gate.

    Compatibility checking

Install

pip install docopt2  # just change the import

See Getting started to dive in, or browse the Guides and the API Reference for the full surface.