Skip to main content

Bounded structural queries for huge directory trees

Project description

gazetteer (gaz)

Bounded structural queries for huge directory trees.

find, du, and grep were not built for multi-terabyte datasets. On a tree with millions of files, they hang for minutes with no output, or they return and flood your terminal (and an LLM's context window) with hundreds of thousands of lines. Ctrl-C gives you nothing back either way.

gaz answers structural questions — extension breakdowns, size by directory, duplicates, stale files, empty directories — under explicit time, count, and output budgets, and always tells you clearly when it stopped early instead of silently giving you a partial answer disguised as a complete one.

Every operation is bounded, and every truncated result says so.

A partial answer delivered in 30 seconds is more useful than a complete answer that never arrives. That's the whole product.

Install

pip install gaz

(The PyPI distribution is named gaz, not gazetteer — PyPI's admin name policy blocks the latter as a generic word. The command, the import gazetteer package internals, and everything else are unaffected.)

Developing locally

uv pip install -e ".[dev]"

If that leaves gaz raising ModuleNotFoundError: No module named 'gazetteer', your environment is likely mangling .pth-based editable installs. Use the workaround script instead, which symlinks the package into site-packages directly:

./scripts/reinstall-dev.sh

Commands

Every command takes an optional PATH (defaults to .), the shared budget flags (--max-seconds, --max-entries, --max-rows, --max-depth), and most accept --ext, --pattern, and --size to scope what's counted.

gaz ext — file-extension breakdown

The highest-value command for understanding a CV dataset at a glance: count, total size, and median size per extension.

$ gaz ext /data/dataset
ext   count    total_size  median_size
----  -------  ----------  -----------
.jpg  482,123  118.4 GB    241.2 KB
.xml  482,123  3.1 GB      6.6 KB
.txt  12       4.0 KB      340 B

Scanned 1,204 dirs / 964,012 files in 8.2s. Complete.

gaz tree — per-directory file counts and sizes

Depth-limited structure with a running total, sorted by size.

$ gaz tree /data/dataset --max-depth 2
dir                     n_files  total_size
----------------------  -------  ----------
/data/dataset/train     820,451  98.1 GB
/data/dataset/val       102,340  14.2 GB
/data/dataset/test      60,221   6.1 GB

Total: 3 dirs, 983,012 files, 118.4 GB
Scanned 1,204 dirs / 964,012 files in 8.2s. Complete.

gaz find — bounded pattern search

Filters during the walk rather than after it, so a narrow search over a huge tree doesn't pay the cost of collecting everything first.

$ gaz find "*.xml" /data/dataset --size ">1M"
path                                type  size
----------------------------------  ----  -----
/data/dataset/train/ann/0042.xml    file  1.2 MB

Scanned 1,204 dirs / 964,012 files in 6.1s. Complete.

gaz dup — duplicate files by content hash

Groups candidates by size first (cheap), then hashes only same-size groups under a separate --max-hash-seconds budget, and reports reclaimable space.

$ gaz dup /data/dataset
path (first copy)                    copies  size_each  reclaimable
------------------------------------  ------  ---------  -----------
/data/dataset/train/images/0001.jpg  3       241.2 KB   482.4 KB

Total: 1 duplicate sets, 482.4 KB reclaimable
Hashed 6 candidate files. Complete.
Scanned 1,204 dirs / 964,012 files in 8.2s. Complete.

gaz stale — old files worth archiving or deleting

$ gaz stale /data/dataset --older-than 180d --size ">100M"
path                                age   size
----------------------------------  ----  ------
/data/dataset/exports/old_run.tar   210d  1.2 GB

Total: 1 files older than 180d, 1.2 GB
Scanned 1,204 dirs / 964,012 files in 8.2s. Complete.

gaz empty — dead directories

Finds directories with no files anywhere in their subtree — debris from partial deletions or failed extraction jobs.

$ gaz empty /data/dataset
dir
------------------------------------
/data/dataset/train/images/.tmp_abc

Total: 1 empty directories
Scanned 1,204 dirs / 964,012 files in 8.2s. Complete.

The output contract

Every command prints a table, then a one-line natural-language status. Complete:

Scanned 1,204 dirs / 412,003 files in 8.2s. Complete.

Truncated — never presented as if it were the full answer:

Stopped at the 30.0s limit after 1,204 dirs / 412,003 files. Numbers
below are a lower bound. Re-run with --max-seconds 300 for a fuller
picture.

Exit code is always 0 on a successful run, including truncated ones — partial is a normal outcome, not an error. The status line is what tells you, and any agent reading your output, how much to trust the numbers.

See DESIGN.md for the full design rationale, and AGENTS.md if you're an AI agent working in this repo.

Why "gazetteer"

A gazetteer is a geographic index — compiled once from survey work, then consulted instead of re-surveying. That's the plan here too: a future gaz scan walks a tree once and stores the result, so later commands answer from an index in milliseconds instead of re-walking terabytes. Installed as gaz on PyPI (gazetteer was blocked by PyPI's name policy), typed as gaz.

Status

v0: the bounded walker plus ext, tree, find, dup, stale, and empty. No caching yet — every command does a live bounded walk. See DESIGN.md's "Later phases" for what's planned (a SQLite-backed cache, a gaz scan manifest, CV-dataset-aware commands, an MCP server).

License

MIT — see LICENSE.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

gaz-0.1.0.tar.gz (24.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

gaz-0.1.0-py3-none-any.whl (13.2 kB view details)

Uploaded Python 3

File details

Details for the file gaz-0.1.0.tar.gz.

File metadata

  • Download URL: gaz-0.1.0.tar.gz
  • Upload date:
  • Size: 24.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.29 {"installer":{"name":"uv","version":"0.11.29","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for gaz-0.1.0.tar.gz
Algorithm Hash digest
SHA256 b44adb7be2413458f6f30225b240f896a3c524f1e7f15981a329345663650083
MD5 a373a0b98609b1fc6eefb45950810c37
BLAKE2b-256 7a5f986b19620751ab8242f24d32aec60dcd3485d378d2bc1a7417b131339196

See more details on using hashes here.

File details

Details for the file gaz-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: gaz-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 13.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.29 {"installer":{"name":"uv","version":"0.11.29","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for gaz-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 b6939c9bbbbad60943b5f95c51c3556100f67f3b1eb66487c2d1eedc6b013108
MD5 4b0a84d51b15c39375214c87366b9ada
BLAKE2b-256 c49aa1109d5dcb1bd65dbbe4f143073ff62b162b3af98cf540f2449772aeb751

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page