fdu (Python)
Python bindings for fdu, a fast, incremental file roll-up engine.
Install
uvx fdu@latest . # run the latest release once, without installing it
uv tool install fdu # put the fdu command on your PATH; uv tool upgrade fdu updates it
uv add fdu # use the library in a uv project
pip install fdu # or install the library with pip
uvx fdu@<version> --help runs one exact release.
For coding agents, fdu --install-skill writes the agent skill under the project root
and fdu --skill prints it; the
repository README has the details.
Prebuilt abi3 wheels cover GIL-enabled CPython 3.12 and newer on Linux glibc (x86-64
and arm64), macOS (x86-64 and arm64), and Windows x86-64, so installing needs no Rust
toolchain. Free-threaded CPython, such as 3.14t, cannot install them and is not
supported; an installer there falls back to building the source distribution.
If uv selects a free-threaded interpreter, pass --python 3.14 (or --python 3.12), as
in uv tool install --python 3.14 fdu.
Use
The public package is fdu; fdu._native is private build machinery.
The supported API includes typed query and scan options, immutable report sections,
roll-ups, per-path provenance, cache management, refresh results, and change feeds.
.gitignore is read by default: tree, summary, extension, and file rows carry their
ignored share, Selection(ignored=...) selects one side, and Status.ignore_rules
names any file the limits refused.
ScanOptions carries the switch (read_controls) and both limits (control_budget,
control_line_limit). Cache status is typed as CacheState, with StaleReason and
LeftoverKind, and clear_all_caches returns a ClearSummary. Filesystem failures
that prevent an operation from starting remain exceptions.
Errors that make a scan partial remain structured data on Status, so callers can use
the covered result without losing the reason it is incomplete.
The
roll-up adapter example
shows one scan serving several application-owned summaries without parsing terminal
output or adopting fdu’s machine schema as the application’s internal model.
from pathlib import Path
import fdu
index = fdu.open(
Path("/path/to/tree"),
cache=fdu.CachePolicy.AUTO,
scan=fdu.ScanOptions(one_filesystem=True),
analysis=fdu.AnalysisOptions(analyze=fdu.Analysis.ALL),
)
print(index.status.complete)
print(index.total().by_extension)
report = index.report(
fdu.Query(
views=(fdu.View.TYPES, fdu.View.FAMILIES, fdu.View.DOCUMENTS),
selection=fdu.Selection(limit=20, size=fdu.SizeMetric.APPARENT),
)
)
print(report.provenance.freshness)
print(report.sections)
print(report.as_dict())
mark = index.clock
result = index.refresh()
print(result.status, index.since(mark).changes)
Every method is bulk: it returns a whole structured result in one call rather than a
cursor Python iterates.
Open, scan, and the native reconciliation phase of refresh run with the GIL released, so
unrelated Python threads and independent indexes can progress.
Content analysis streams every eligible file through EOF. Binary data, invalid UTF-8,
and unsupported SLOC languages remain visible as coverage without making the operation
partial; I/O failures and files changed during a read remain operational errors.
One Index object still has PyO3 runtime borrow exclusion: an overlapping call on
that same object is rejected rather than becoming an unsynchronized shared-index access.
The wheel enables the optional watch dependency and exposes Index.watch() as a
closable, event-driven change feed.
Content analysis itself remains one-shot: refresh reanalyzes after metadata
reconciliation, while a watch feed reports metadata changes.
Analysis names the same analyzers as the command line’s --analyze: lines, code,
and words, with none and all as totals.
AnalysisOptions takes one of them or a comma-separated set such as "code,words",
plus a worker count.
Typed report sections expose stable type/family groups, exact share fractions, line and
word slots, page denominators, coverage outcomes, analyzer provenance, detection source
and confidence, and generated/vendor/documentation flags.
The original extension grouping remains available as the extensions view.
The package supports Python 3.12 and newer and builds one abi3-py312 extension rather
than separate native payloads for every Python minor release.
Directory Inventories and Formats
A default Query() keeps the existing directory tree.
Select a flat presentation when requesting a report, so an ordinary tree need not
materialize a complete inventory:
from pathlib import Path
import fdu
index = fdu.open(Path("/path/to/tree"))
for name in (".venv", "venv", "node_modules", "target"):
report = index.report(
fdu.Query(
format=fdu.Format.LONG,
selection=fdu.Selection(
kinds=(fdu.EntryKind.DIR,),
include=(name,),
modified_before="30d",
sort=fdu.SortKey.MTIME,
reverse=True,
),
)
)
print(report.render())
print(report.render(fdu.Format.JSON))
All four reads use one retained index without rescanning.
View.LIST is the metadata default.
Format.TREE explicitly requests the current tree; PATHS lists matching paths, LONG
adds size and signed modification age, and JSON/JSONL/YAML carry exact metrics.
TEXT selects automatic human presentation.
Legacy View.FILES keeps flat name ordering, and View.TREE preserves structured
directory output. Largest/recent remain regular-file presets, with optional Paths/Long
output.
Directory FileRow values carry subtree bytes, allocated, files, dirs,
complete, mtime_ns, and age_ns; non-directory counts are None. A directory whose
subtree was not listed in full has complete=False, lower-bound sizes, and
age_ns=None. The fixed Report.age_reference_ns explains age, including negative
future ages and pre-epoch mtime.
An unrepresentable reference yields None age.
Exclusions win throughout the subtree; nested roots may overlap, while grouped totals
count their union once.
Age describes modification, not access or last use.
Native entry/lookup projections retain inode attributes; these report rows deliberately
carry subtree metrics instead.
A Report owns its requested projection.
Re-render it to another serialization or between Paths and Long without querying again;
request another report to change between a bounded tree and complete flat inventory.
An incompatible conversion raises InvalidArgumentError rather than silently listing
only visible tree rows.
Tree limits remain per-directory, flat limits apply to the whole list, and machine List
output is complete unless explicitly limited.
Details and exact fields are in the
usage guide and
machine-output reference.
Long-lived roots
fdu.opened is the direct typed interface to the long-lived engine.
It starts progressive discovery, returns several projections from one coherent version,
exposes exact resumable changes, verifies explicit path sets, accepts discovery
priorities, and joins all native work on close:
from pathlib import Path
from fdu import opened
with opened.OpenedIndex.open(Path("."), opened.OpenedOptions(observe=True)) as index:
answer = index.read(
opened.Tree(page=opened.Page(limit=200, max_work=100_000)),
opened.Diagnostics(),
)
cursor = answer.change_cursor
changed = index.changes(cursor, timeout=1.0)
The methods are synchronous and release the GIL during native work. An async application adapts them with its own executor policy, keeping task and shutdown ownership visible. The package does not run a private event loop or shell out to the command line.
The wheel also exposes the native Rust CLI as the fdu console script.
Argument parsing, help, streams, color, errors, broken-pipe handling, and exit status
all use the same Rust process boundary as the Cargo-installed binary; there is no Python
CLI reimplementation.
Status: 0.x. A new minor release may change the Python API; the release process states the compatibility rules. Building and testing the package from a checkout is covered in the repository README.
License: MIT.
Release files for fdu 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| fdu-0.1.0.tar.gz | 990.2 kB | Details |
Built distributions (wheels)
| File | Reset | |||
|---|---|---|---|---|
| fdu-0.1.0-cp312-abi3-win_amd64.whl | CPython 3.12 | abi3 | Windows x86-64 | Details |
| fdu-0.1.0-cp312-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl | CPython 3.12 | abi3 | Linux glibc 2.17+ x86-64 | Details |
| fdu-0.1.0-cp312-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl | CPython 3.12 | abi3 | Linux glibc 2.17+ ARM64 | Details |
| fdu-0.1.0-cp312-abi3-macosx_11_0_x86_64.whl | CPython 3.12 | abi3 | macOS 11.0+ x86-64 | Details |
| fdu-0.1.0-cp312-abi3-macosx_11_0_arm64.whl | CPython 3.12 | abi3 | macOS 11.0+ ARM64 | Details |
Total release size: 10.6 MB
Release files / fdu-0.1.0.tar.gz
| Download URL | fdu-0.1.0.tar.gz |
|---|---|
| Size | 990.2 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
b31c14b34776adc266de8797d97c1f9c358b22190029e4d618f041c68979453e
|
|
BLAKE2b-256 checksum How to use checksums |
df49ebc1fd0fbc4163e1d12d7756135e9c49badacb4de72cfe326b2c4f24751e
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.12.1 {"installer":{"name":"uv","version":"0.12.1","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / fdu-0.1.0-cp312-abi3-win_amd64.whl
| Download URL | fdu-0.1.0-cp312-abi3-win_amd64.whl |
|---|---|
| Size | 2.1 MB |
| Tags | CPython 3.12 Windows x86-64 abi3 |
|
SHA-256 checksum How to use checksums |
43311ffcafcd52680b2ce4b946fe728e1d4976f035ddfb37ab122c59a8ff4b9c
|
|
BLAKE2b-256 checksum How to use checksums |
7684065e5482810c97339f9c59e74ac9f0cd2e789dc0fc80b9e3944b18b65f33
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.12.1 {"installer":{"name":"uv","version":"0.12.1","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / fdu-0.1.0-cp312-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
| Download URL | fdu-0.1.0-cp312-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl |
|---|---|
| Size | 2.0 MB |
| Tags | CPython 3.12 Linux glibc 2.17+ x86-64 abi3 |
|
SHA-256 checksum How to use checksums |
6dd83f9868d6e1cc877205a2b7abf5bebd874c3f776388693d839de002f0d5b4
|
|
BLAKE2b-256 checksum How to use checksums |
1e18e0eab9775383d4713721862373fd9043c291e2bd0e007464ceba91e289a5
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.12.1 {"installer":{"name":"uv","version":"0.12.1","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / fdu-0.1.0-cp312-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
| Download URL | fdu-0.1.0-cp312-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl |
|---|---|
| Size | 1.9 MB |
| Tags | CPython 3.12 Linux glibc 2.17+ ARM64 abi3 |
|
SHA-256 checksum How to use checksums |
b5e56f40682be6c9642057423cd55e7265d701dbd161354079319f4478300f4b
|
|
BLAKE2b-256 checksum How to use checksums |
d37ed3226f5e5173ab5d9c204218d7d26774b3e3431fedb4bd64eaaac4e9d6dd
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.12.1 {"installer":{"name":"uv","version":"0.12.1","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / fdu-0.1.0-cp312-abi3-macosx_11_0_x86_64.whl
| Download URL | fdu-0.1.0-cp312-abi3-macosx_11_0_x86_64.whl |
|---|---|
| Size | 1.9 MB |
| Tags | CPython 3.12 abi3 macOS 11.0+ x86-64 |
|
SHA-256 checksum How to use checksums |
6b3021e8270310d533a9fd790c15aafc9327e5405ad4d448188527f9b16a9fdd
|
|
BLAKE2b-256 checksum How to use checksums |
728a9e98ebcd47a1c0a8785fc29b7e6eee1890589249270fdf4eb9840c7f40d1
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.12.1 {"installer":{"name":"uv","version":"0.12.1","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / fdu-0.1.0-cp312-abi3-macosx_11_0_arm64.whl
| Download URL | fdu-0.1.0-cp312-abi3-macosx_11_0_arm64.whl |
|---|---|
| Size | 1.8 MB |
| Tags | CPython 3.12 abi3 macOS 11.0+ ARM64 |
|
SHA-256 checksum How to use checksums |
2f3052e7f29908dda1268e42e1127983b80d40346b325b13b371b0390629af78
|
|
BLAKE2b-256 checksum How to use checksums |
3e6181856f41d6bda347c7a89f7925e60e42136dc8361eb1a49d5023ad43ea16
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.12.1 {"installer":{"name":"uv","version":"0.12.1","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|