CLI¶
nab exposes four subcommands: lock, download, config, and
cache. The first two read project shape from [tool.nab] in the
project’s pyproject.toml or a project-directory nab.toml; the CLI
carries runtime knobs and can override a project key for one run with a
--project-<key> flag. config inspects the layered configuration, and
cache inspects and clears the on-disk cache.
Synopsis¶
nab [--version | -V]
nab [OUTPUT FLAGS] lock [PATH] [RUNTIME OPTIONS] [--output PATH] [--format pylock|requirements|requirements-without-hashes]
nab [OUTPUT FLAGS] download [PATH] [RUNTIME OPTIONS] [--output DIR] [--max-concurrency N]
nab [OUTPUT FLAGS] config {list | get <key> | explain <key>} [--path PATH]
nab [OUTPUT FLAGS] cache {dir | verify | clear} [--cache-dir PATH]
OUTPUT FLAGS are the global verbosity, colour, and progress knobs listed
under Output control below. They are read before the subcommand, so they may
appear anywhere on the line.
PATH is positional and defaults to pyproject.toml in the
current directory. Run nab lock --help (or -h) for the full
per-command flag list. Boolean flags render as a --flag /
--no-flag pair (for example --cache / --no-cache). --offline
is layered, so an explicit --offline True / --offline False
overrides the config layers; bare --offline / --no-offline are
shorthands for those two values.
nab lock¶
Resolve and emit a lockfile or pin list. Three formats:
--format pylock(default) writes a PEP 751pylock.toml.--format requirementswrites a pip-compatiblerequirements.txtwith one--hash=<algo>:<digest>line per recorded digest.--format requirements-without-hasheswrites a sortedname==versionlist with no hashes.
Dependency-group selection (PEP 735):
--groups foo barfolds the named groups from the project’s[dependency-groups]table into the resolve. The selected group names land in the lockfile’s top-leveldependency-groupsarray. The separatedefault-groupsarray records the[tool.nab].default-groupsproject setting, not this run’s selection.--all-groupsselects every group defined in the project.
Extras selection:
--extras foo barfolds entries from the project’s own[project.optional-dependencies]table into the resolve. The selected extra names land in the lockfile’s top-levelextrasarray.--all-extrasselects every declared extra.
Both --groups and --extras produce a single union resolve. A
package that only a selected extra or group reaches is emitted with
a 'X' in extras or 'X' in dependency_groups marker, so an
installer given neither leaves it out; see
Lockfiles.
Workspace flags (see Lock a workspace):
--workspace-discovery(default) walks upward from the locked project for a[tool.nab.workspace]root and prefers its in-tree members over PyPI.--no-workspace-discoveryskips that search, so the run resolves the named project alone.--no-emit-workspacedrops the workspace members’ own[[packages]]entries from the emitted lockfile, along with the dependency edges and membership gates that reference them; the resolver still uses the members during the resolve. Default off (--no-no-emit-workspace). Use it when the lockfile is consumed by pip’s PEP 751 install or--require-hashes, which reject the directory entry a member pin emits because it cannot be hashed; pair it withpip install --no-deps -e <member>.
--output defaults to pylock.toml for pylock and
requirements.txt for the two requirements formats. Pass
--output - to write to stdout instead. A matrix has no default
requirements file: no one file can carry every tuple’s pins (see
below), so the requirements formats print to stdout unless --output
names a template.
A requirements --output template writes one file per tuple. The
variables are {python_version}, {platform_id}, and {selection},
which names the conflict fork a tuple belongs to (extra-cpu,
group-black22.group-isort5, empty when the resolve did not fork):
$ nab lock --format requirements-without-hashes --extras cpu gpu \
--output 'req-{python_version}-{selection}.txt'
Wrote req-3.12-extra-cpu.txt (12 packages, tuple py312-linux_x86_64-extra-cpu)
Wrote req-3.12-extra-gpu.txt (14 packages, tuple py312-linux_x86_64-extra-gpu)
A template that maps two tuples onto one path is rejected, naming the variables that would give every tuple its own file. When the tuples split on an axis no variable names, such as the libc or the implementation, no template separates them and the message points at pylock output instead.
Exits non-zero on resolution failure; the message starts with
error: resolution failed: followed by a derivation tree, and any
captured diagnostics are appended under a Diagnostics: section.
Universal mode ([tool.nab].mode = "universal") is supported for
all three formats:
pylockproduces one PEP 751 file with per-tuplePackageentries gated by markers (python_version,sys_platform,platform_machine, plusimplementation_namewhen the matrix declares a non-CPython implementation or more than one). Versions agreed across every tuple appear once without a marker; divergent versions appear once per(version, source)group with the matching tuples disjoined.requirementsandrequirements-without-hashesemit a sequence of# labelcomment blocks, one per(python, platform, implementation)tuple, followed by that tuple’s pins. Pip’s hash-checking mode cannot install a single requirements.txt across multiple tuples, so the per-tuple block format is for inspection or for tools that consume one block at a time.
Failed tuples render as # {label}: FAILED followed by the
indented error and exit 1.
--python X.Y resolves for that Python on this machine instead of the
running interpreter, like pip’s --python-version; it moves only the
python axis, so a declared [tool.nab.environment].platform stays. It is
rejected in universal mode, where the matrix declares the Python axis.
A project option can be overridden for one run with a --project-<key>
flag: --project-resolution, --project-mode, --project-requires-python,
--project-uploaded-prior-to, --project-dist-policy,
--project-build-policy, --project-build-requires-depth, and the
repeatable --project-constraint and --project-default-group. Every one
of them replaces the file value outright; repeating --project-constraint
builds up that run’s whole constraint list rather than adding to the
declared one. Each changes the resolved set, so passing one prints a
reproducibility notice on stderr and records the override in the
lockfile’s [tool.nab] block, since the lock no longer derives from the
committed files alone.
--locked re-resolves and checks that the committed pylock.toml is
already up to date, writing nothing. It exits non-zero if the lock would
change or is missing, so CI can assert the lock is current. It covers
pylock output to a file in single-environment mode.
When a mismatch is provable from the inputs alone, a changed direct
dependency, a narrowed requires-python, a changed extra or group, or a
tightened constraint, --locked fails fast with that reason before
resolving. Otherwise it runs the full re-resolve, and only that comparison
reports the lock up to date: nab is non-sticky, so a lock can satisfy every
input yet be stale once a newer admissible version exists.
--upgrade re-anchors the P<n>D resolve window to the current time
instead of reusing the timestamp recorded in an existing lockfile, and
prints a notice naming the cutoff it dropped.
nab download¶
Resolve and download every wheel, sdist, and direct-URL archive into a local directory. The download is idempotent: files whose recorded sha256 matches a local file are left alone. Local and VCS pins are skipped.
Universal mode ([tool.nab].mode = "universal") re-resolves
across the matrix and downloads the union of every tuple’s
artefacts into the same directory, deduplicated by URL so a
wheel shared across tuples is fetched once.
--outputdefaults towheels/.--max-concurrencycontrols parallel HTTP fetches (default8, minimum1). Layered, so it can also be set in annab.tomlorNAB_MAX_CONCURRENCY.--groups foo bar/--all-groupsand--extras foo bar/--all-extrasfold dependency groups and extras into the resolve as they do onnab lock, so they decide which artefacts are downloaded.--python X.Yresolves for that Python on this machine instead of the running interpreter, as onnab lock. It is rejected in universal mode, where the matrix declares the Python axis.--workspace-discovery(default) mirrorsnab lock: it finds a[tool.nab.workspace]root and resolves against the in-tree members.--no-workspace-discoveryturns that off. See Lock a workspace.
--offline, --cache-dir, --http-backend, --max-concurrency and the
--project-* overrides flow through the same layered config sources nab lock uses, so a NAB_* variable or a system/user/project nab.toml is
read for nab download as for nab lock.
Offline covers the artefacts too: an artefact that is neither already in
the output directory with a matching digest nor readable from a local
file:// path fails the run instead of being fetched.
A summary of how many files were written and how many were already present is printed to stderr.
nab config¶
Inspect the effective layered configuration (read-only). Three actions:
nab config listprints every option with its value, scope, and the source it came from.nab config get <key>prints one effective value.nab config explain <key>prints the full source stack for one key. The winning row carries a>gutter and the statuswinner, and every source it beats isshadowed. A shadowed source contributes nothing to the value, whatever the key’s type.
--include-rejected is a flag on nab config itself, so every action
takes it. Without it, a config file that sets an unknown key or a key
its scope does not allow is a config error: the inspector writes the
message to stderr, prints no configuration, and exits 1. With the flag
the run succeeds, and each action shows the refused sources differently:
nab config list --include-rejectedprints the option table, then arejected:section with one line per refused source: a key set outside its scope, an unknown key, and aNAB_*variable that is unknown or names a project-scope option. Without the flag those variables are stderr warnings instead.nab config explain <key> --include-rejectedadds arejectedrow for every source that tried to set that key and was not allowed. A refusal that names no option (an unknown key, or an unrecognisedNAB_*variable) belongs under no key, so onlynab config listshows it: onexplainsuch a variable loses its stderr warning and gains no row.nab config get <key> --include-rejectedprints the value and nothing else.getrenders no refusal at all, so the flag only decides whether the command runs, and takes thoseNAB_*warnings off stderr without printing anything in their place.
The same per-option override flags the run commands accept (the
--project-* overrides and the user knobs --offline, --cache-dir,
--http-backend, --max-concurrency) layer a CLI value on top, so the
inspector reflects the same effective values a run would see.
See Configuration for the source ladder and the
NAB_* environment variables.
nab cache¶
Inspect and clear the on-disk cache. It takes one location selector,
--cache-dir PATH. Without it the root is the one a run in the same
directory uses: cache-dir is read off the config source ladder, so a
nab.toml or NAB_CACHE_DIR sets it too (see
Configuration). Three actions:
nab cache dirprints the resolved cache root to stdout, whether or not it exists yet.nab cache verifywalks the cached index records read-only and reports any corrupt entry by path and reason. Cloned repositories and extracted archives hold upstream files, so they are not parsed.nab cache clearremoves every bucket under the root, including the cloned repositories and extracted archives, returning the cache to cold.
Runtime flags¶
lock and download accept the same runtime knobs:
Flag |
Default |
Effect |
|---|---|---|
|
|
Override the on-disk cache root. |
|
off |
Disable cache for this run. A declared VCS or archive source is materialised into a temporary directory instead, so it is refetched every run. Combine with |
|
unset |
Use cache only, never hit the network. Layered: |
|
|
Pick the async transport for fetches. Layered, so it can also be set in an |
A name absent from the index is remembered for a short window, so a repeated lookup is answered from cache, offline included.
Offline refuses rather than fetches, so a PEP 517 build environment
that has anything to install cannot be created and the build fails.
At build-remote that rejects only the sdist version, and the
resolve tries the next candidate. A declared local, VCS, or archive
source, or a workspace member, is the only candidate for its name, so
the same refusal ends the run. See Build policy.
urllib3 is the only backend pulled in by the base install. The
others surface a helpful ImportError if selected without the
matching extra.
Global flags¶
Flag |
Effect |
|---|---|
|
Print |
|
Standard argparse-style help. Per-subcommand help works too: |
The verbosity, colour, and progress flags below are also global.
Output control¶
These flags set how much nab writes to stderr, whether it colours it,
and whether it animates a progress line. They are global: nab reads them
before the subcommand, so they work with lock, download, config, and
cache. stdout carries only the requested output (the lockfile, the
requirements list, the config dump), so it stays pipeable at every
verbosity.
Flag |
Effect |
|---|---|
|
Raise verbosity. |
|
Lower verbosity. |
|
When to colour stderr: |
|
Shorthand for |
|
Suppress the live progress line (also |
Verbosity is the count of -v minus the count of -q. The five levels,
quietest first, are silent (-qq), quiet (-q), normal (the default),
verbose (-v), and debug (-vv). Errors print at every level; warnings
print unless -qq; the run summary and notes print at normal and above.
While nab lock or nab download resolves, a live line repaints on
stderr, counting package listings fetched and packages pinned:
Resolving... 12 fetched, 5 pinned
It shows only at normal verbosity on an stderr terminal; --no-progress
(or NAB_NO_PROGRESS) turns it off, and it never writes to stdout.
Environment variables¶
Variable |
Effect |
|---|---|
|
If set, |
|
Default verbosity when no |
|
If set to a non-empty value, suppress the live progress line, like |
|
If set to a non-empty value, disable colour under |
|
If set to a non-empty value, force colour under |
|
|
Exit codes¶
Code |
Meaning |
|---|---|
|
Success. |
|
Resolution failed, lockfile cannot be written (missing hash), download failed, missing |
|
Interrupted with Ctrl-C. |