Skip to content

Usage linting

Statically lint the usage grammar itself, before any argv is parsed. See the Usage linting guide.

check

check(
    doc: str, schema: type[Any] | None = None
) -> list[Diagnostic]

Statically lint the usage grammar itself, before any argv is parsed.

Returns a list of "warning"-level diagnostics for defects the usage message contains that docopt would otherwise accept silently: an option declared but never usable, a [default: ...] on an always-required element, an empty [options] shortcut.

The check is read-only and does not affect parsing or matching. A usage message that does not parse is reported as a single "error", the one docopt raises for it at every run, and nothing else in it is looked at.

With schema, a dataclass, a TypedDict or a Cli subclass, the list also holds an "error" for every way the schema disagrees with the usage: a field with no element, two elements for one field, an element that may be absent for a field that is not optional, a type that cannot hold what the element yields. Binding raises the last two only on the argv that reaches them. A pydantic model, and a schema whose usage message does not parse, get one "warning" that says they were not checked.

To judge a type the check calls the coercion that binding uses, so an Enum of the schema is called with the values tried, and whatever its _missing_ does is done. A counted flag typed with a closed set, Literal[0, 1, 2] on [-v]..., is judged by its shape alone: the set is the author's limit on the count.

Fields are held against elements, and no more than that: a default is not held against its own annotation, and the schema is not constructed, so what its own __init__ takes or refuses is not looked at. The schema is held against the whole usage. A handler of a Dispatch table binds its schema only on the lines it is run for: Dispatch.check holds each schema against those.

Source code in src/docopt2/_lint.py
def check(doc: str, schema: type[Any] | None = None) -> list[Diagnostic]:
    """Statically lint the usage grammar itself, before any argv is parsed.

    Returns a list of ``"warning"``-level diagnostics for defects the usage message contains that
    [`docopt`][docopt2.docopt] would otherwise accept silently: an option declared but never usable, a
    ``[default: ...]`` on an always-required element, an empty ``[options]`` shortcut.

    The check is read-only and does not affect parsing or matching. A usage message that does not parse is
    reported as a single ``"error"``, the one [`docopt`][docopt2.docopt] raises for it at every run, and
    nothing else in it is looked at.

    With ``schema``, a dataclass, a ``TypedDict`` or a ``Cli`` subclass, the list also holds an ``"error"`` for
    every way the schema disagrees with the usage: a field with no element, two elements for one field, an
    element that may be absent for a field that is not optional, a type that cannot hold what the element
    yields. Binding raises the last two only on the argv that reaches them. A pydantic model, and a schema
    whose usage message does not parse, get one ``"warning"`` that says they were not checked.

    To judge a type the check calls the coercion that binding uses, so an ``Enum`` of the schema is called with
    the values tried, and whatever its ``_missing_`` does is done. A counted flag typed with a closed set,
    ``Literal[0, 1, 2]`` on ``[-v]...``, is judged by its shape alone: the set is the author's limit on the count.

    Fields are held against elements, and no more than that: a default is not held against its own annotation,
    and the schema is not constructed, so what its own ``__init__`` takes or refuses is not looked at. The
    schema is held against the whole usage. A handler of a ``Dispatch`` table binds its schema only on the
    lines it is run for: [`Dispatch.check`][docopt2.Dispatch.check] holds each schema against those.
    """
    found = _usage_findings(doc)
    return found if schema is None else [*found, *_schema_findings(doc, schema)]