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)]
|