Skip to main content

fdu (Python)

Fastest native du replacement and detailed file analytics for Python and Rust

Python bindings for fdu, which reports, for every directory in a tree at once, its size, file count, recency, and file kinds, and on request its lines of code and prose volume. It walks a tree on several threads through each platform’s native directory interface, and on a million-file tree runs about 9× as fast as du on macOS and 2.6× as fast on Linux, ahead of pdu, diskus, and dust (speed).

Set Up with Any Coding Agent

Give the agent this instruction:

Run uvx --no-build fdu@latest --install-skill from the project root to install fdu’s self-contained skill for current and future agent sessions.

The skill needs no prior session context or installed command; fdu --skill prints it.

Install the Command Line

uvx --no-build fdu@latest .
uv tool install --no-build fdu

The first command runs fdu once; the second keeps it on PATH. uv tool upgrade --no-build fdu updates that install; uvx --no-build fdu@<version> --help runs one exact release. 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 may fall back to building the source distribution. --no-build makes uv fail instead of compiling when no compatible wheel exists. If uv selects a free-threaded interpreter, pass --python 3.14. An exclude-newer policy in uv can filter a newly published fdu release. Review and allow the first-party fdu package in that policy, or wait for its cool-off to expire.

Use as a Python Library

uv add fdu
pip install fdu

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.

Population, Code Overview, and Cache Destination

fdu.report() derives discovery and content analysis from Selection.ignored:

import fdu

report = fdu.report(
    ".",
    fdu.Query(selection=fdu.Selection(ignored=fdu.IgnoredEntries.EXCLUDE)),
    analysis=fdu.AnalysisOptions(analyze=fdu.Analysis.CODE),
    cache_dir="/path/to/cache",
)

include is the default. exclude prunes safely ignored subtrees; only discovers ignored matches through ordinary ancestors and analyzes only ignored bodies. For retained work, fdu.open(..., ignored=...) and fdu.scan(..., ignored=...) choose the initial population. A default read inherits it. An Include index can answer a narrower selection; an index that never retained a population cannot widen its answer.

Code analysis defaults to CodeSection, whose overview includes selected source lines, language shares, ignored/non-ignored contributions, and coverage. SortKey.CODE_LINES ranks files or directories when code analysis was requested. File rows carry nullable sort_value and classification evidence; unavailable counts remain distinct from zero.

cache_dir on open/report and cache lifecycle calls names the exact destination and wins over FDU_CACHE_DIR. Otherwise XDG_CACHE_HOME/fdu wins over the platform default: ~/.cache/fdu on macOS and Linux, %LOCALAPPDATA%/fdu on Windows. list_caches and clear_all_caches take a keyword cache directory, independently of a scan root. cache_directory(cache_dir=...) resolves that destination without a root. cache_path(root, cache_dir=...) identifies the root’s .metadata.bin file; a matching .analysis.bin stores derived metrics without source bodies.

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. Selection(depth=5, min_share="1%", breadth=Bound.ALL, limit=Bound.ALL) describes the ordinary tree defaults. Breadth bounds children per directory; limit bounds data rows per section. TreeSection.limits records the effective controls. Each TreeOmission.entries counts directly hidden children: an omitted directory is one entry, while its nullable files count covers regular files throughout that hidden subtree. The optional TreeSection.remainder combines hidden contents across one tree, with nullable files, bytes, and allocated totals and bound reasons in stable order. It is None when nothing is hidden. A displayed root-level directory represents all its descendants, including children hidden by display bounds. The remainder counts only usage outside those displayed root-level rows. Parent totals already include the remainder, so do not add it to them. The terminal gives that remainder one root-level line, such as … and 12,345 more files, with its combined size and root share in the usual columns. Use report.render(bar_size=20) for wider bars, or bar_size=0 (also negative values) to hide them; the default is 10. Machine formats are unchanged. Machine reports use fdu.report/10. 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.

Metadata

Release files for fdu 0.3.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for fdu 0.3.0
File Size Uploaded Provenance Actions
fdu-0.3.0.tar.gz 1.2 MB Without provenance Details for fdu-0.3.0.tar.gz

Built distributions (wheels)

Table of built distributions (wheels) for fdu 0.3.0
File Actions
fdu-0.3.0-cp312-abi3-win_amd64.whl CPython 3.12 abi3 Windows x86-64 Details for fdu-0.3.0-cp312-abi3-win_amd64.whl
fdu-0.3.0-cp312-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl CPython 3.12 abi3 Linux glibc 2.17+ x86-64 Details for fdu-0.3.0-cp312-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
fdu-0.3.0-cp312-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl CPython 3.12 abi3 Linux glibc 2.17+ ARM64 Details for fdu-0.3.0-cp312-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
fdu-0.3.0-cp312-abi3-macosx_11_0_x86_64.whl CPython 3.12 abi3 macOS 11.0+ x86-64 Details for fdu-0.3.0-cp312-abi3-macosx_11_0_x86_64.whl
fdu-0.3.0-cp312-abi3-macosx_11_0_arm64.whl CPython 3.12 abi3 macOS 11.0+ ARM64 Details for fdu-0.3.0-cp312-abi3-macosx_11_0_arm64.whl

Total release size: 12.0 MB

Release files / fdu-0.3.0.tar.gz

Download URL fdu-0.3.0.tar.gz
Size 1.2 MB
Tags Source
SHA-256 checksum
How to use checksums
161c2f2a3e885d51154d80baa2cc9f4a6f85a1ec34cbe76e2c7c3572abeb45ef
BLAKE2b-256 checksum
How to use checksums
05679557954e7c4a79654ed15223b5562832d54ae778f72ceebbc965c084caee
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.3.0-cp312-abi3-win_amd64.whl

Download URL fdu-0.3.0-cp312-abi3-win_amd64.whl
Size 2.3 MB
Tags CPython 3.12 Windows x86-64 abi3
SHA-256 checksum
How to use checksums
5a26e94f726cabad765b827b4bb195827e7c29df831052b227e89c13729971a2
BLAKE2b-256 checksum
How to use checksums
de6b3fd114a20214507abc75ce28bc8f5fc2dfc3658e26444681dc9908a4fc3e
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.3.0-cp312-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl

Download URL fdu-0.3.0-cp312-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Size 2.3 MB
Tags CPython 3.12 Linux glibc 2.17+ x86-64 abi3
SHA-256 checksum
How to use checksums
bdb979aac8907b09e1a74729b7f6b9cb81d8cc7c93aa41418f4eec54b2c954d8
BLAKE2b-256 checksum
How to use checksums
f97775e1517116f5acd1fd85726dba7e627ce21a72aa00c52805bd567770c589
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.3.0-cp312-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl

Download URL fdu-0.3.0-cp312-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Size 2.1 MB
Tags CPython 3.12 Linux glibc 2.17+ ARM64 abi3
SHA-256 checksum
How to use checksums
52a23209e2ed04b49cc43b7089a510e6a8ad0071238e209f2b58afb32d4ce45f
BLAKE2b-256 checksum
How to use checksums
a3f091563b722d9edf2901a6736a71f9cfb12854ed6f31d1fe7d329e83febed2
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.3.0-cp312-abi3-macosx_11_0_x86_64.whl

Download URL fdu-0.3.0-cp312-abi3-macosx_11_0_x86_64.whl
Size 2.1 MB
Tags CPython 3.12 abi3 macOS 11.0+ x86-64
SHA-256 checksum
How to use checksums
a2668e21445391bbe60e6d4d5c2d521a9532312a8ce3e7e046ecc1560d843205
BLAKE2b-256 checksum
How to use checksums
e628ce73621d2adaec293573507134a52fa757f06d11c95ecc4d1603fe543639
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.3.0-cp312-abi3-macosx_11_0_arm64.whl

Download URL fdu-0.3.0-cp312-abi3-macosx_11_0_arm64.whl
Size 2.0 MB
Tags CPython 3.12 abi3 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
e069ff0af61bd7eb329bf6249ef42ecb9b900783e71d7be935eefc69a334ddd5
BLAKE2b-256 checksum
How to use checksums
cd2b1ad8db2d8b1057f66914f8f09afab74e0f062376256a094808c170e1c8bb
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}

Security for fdu 0.3.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page