Skip to main content

PyStou

Welcome to PyStou – your ultimate toolkit for keeping your filesystem tidy and organized! Whether you're a developer drowning in duplicate folders or someone who loves archiving files but hates the clutter, PyStou is here to rescue you from chaos with style and efficiency.

PyStou is proudly developed by the International Consortium of Investigative Journalists (ICIJ), aiming to empower users with tools to manage and maintain large amounts of files.

Install

pipx install pystou      # isolated environment, recommended
uv tool install pystou   # https://docs.astral.sh/uv/
pip install pystou

Requires Python 3.9+. typer and rich are installed automatically.

Some archive formats need an external tool. Run pystou doctor to check which are present:

Tool Needed for
p7zip-full split ZIP archives (.z01, .z02, ...)
pst-utils Outlook .pst and .ost (readpst)
zstd .zst archives

From source:

git clone https://github.com/ICIJ/pystou.git
cd pystou
make install

Quick start

pystou stats  ~/Downloads -r            # what is in here?
pystou dedup  ~/Downloads -r            # prompt per duplicate group
pystou extract ~/Downloads -r --action extract
pystou cleanup ~/Downloads -r           # drop .DS_Store, Thumbs.db, ...
pystou restore ~/Downloads --all        # undo the above

Commands

Command Purpose
dedup Find duplicate directories and delete or merge them
extract Extract archives, optionally nested and in parallel
cleanup Remove OS junk files
identify Detect extension mismatches and encrypted archives
stats Report file counts, sizes, and types
empty Find and remove empty directories
restore Put quarantined items back
trash List or permanently purge quarantined items
doctor Check that external tools are installed

Every command takes an optional directory (default: current) and --help.

Reversible by default

cleanup, dedup, and extract never delete: they move items into a .pystou-trash/ directory next to the target. Use pystou restore to undo and pystou trash purge to reclaim the space. pystou trash purge is the only command that truly deletes data.

Pass --hard-delete to delete immediately instead.

Where PyStou writes

Logs and index databases follow the XDG Base Directory specification, so no command litters the directory you run it from:

What Location Override
JSON logs $XDG_STATE_HOME/pystou/logs (~/.local/state/pystou/logs) --log-dir
Index databases $XDG_CACHE_HOME/pystou/index (~/.cache/pystou/index) --db-dir

Each scanned tree gets its own index file, named after the target and a hash of its absolute path, so a run on /data is never offered the index built for /photos. Indexes are a cache: deleting them only costs a rescan.

Quarantined files are the exception and stay in .pystou-trash/ next to the target, because quarantining has to be a same-filesystem move to be atomic. Use --trash-dir to place it elsewhere on that filesystem.

Global options

These go before the subcommand name.

Flag Description
--no-color Disable colored output (piping, CI).
-q, --quiet Suppress progress bars and status messages; errors only.
--version Print the installed version and exit.
--install-completion Install shell completion (bash, zsh, fish).
--show-completion Print the completion script.
pystou --no-color dedup /data -r
pystou --quiet extract /data -r --action extract

Shared options

Flag Description Available on
-r, --recursive Recurse into subdirectories. dedup extract cleanup identify stats empty
-n, --dry-run Do not make any changes. dedup extract cleanup empty
--hard-delete Permanently delete instead of quarantining. dedup extract cleanup
--trash-dir PATH Override the trash location (must be the same filesystem). dedup extract cleanup restore trash
--log-dir PATH Directory for JSON log files (default: XDG state dir). all but doctor
--db-dir PATH Directory for index databases (default: XDG cache dir). dedup extract restore

Command reference

dedup

Identify duplicate directories and delete or merge them.

pystou dedup [directory] [options]
Option Description
-l, --level N Maximum recursion depth.
--action delete|merge|skip Apply to every duplicate group; omit to prompt per group.
pystou dedup /data -r                    # prompt per group
pystou dedup /data -r --action delete    # keep one copy of each
pystou dedup /data -r --action merge     # merge contents, then quarantine

extract

Extract archives and optionally clean up the sources.

pystou extract [directory] [options]

Each archive is extracted into its own directory beside it, named after the archive (photos.zip -> photos/). If that name is taken, a numbered one is used (photos (1)/), so extracting never overwrites existing files.

Supported formats: .zip, .tar, .tar.gz, .tgz, .tar.bz2, .tbz, .gz, .bz2, .zst, .tar.zst, .tzst, .pst, .ost, and split ZIP (.z01, .z02, ... detected from the main .zip).

Option Description
--action extract|skip Apply to every archive; omit to prompt per archive.
--remove-archives / --keep-archives Quarantine source archives after success, or keep them (default: keep).
-p, --parallel N Parallel extraction workers (default: 1).
--nested Recursively extract archives found in extracted content.
--max-depth N Maximum nesting depth for --nested (default: 10).
--type T Only process this archive type (repeatable).
--tolerant Keep partial .pst/.ost output when readpst fails (see below).
pystou extract /data -r --action extract --remove-archives
pystou extract /data -r --action extract -p 4 --nested
pystou extract /data -r --action extract --type zip --type pst

Outlook PST/OST: readpst sometimes exits with an error, most often on a modern Office 365 .ost cache, after already extracting most of the mail. By default PyStou treats that as a failure: the partial output is discarded and the archive is left in place. --tolerant keeps whatever messages were written and reports a warning. The recovered mail may be incomplete, which is why it is opt-in.

cleanup

Remove junk files created by operating systems and applications.

pystou cleanup [directory] [options]

Removed by default:

  • macOS: .DS_Store, ._.DS_Store, ._*, __MACOSX, .AppleDouble, .Spotlight-V100, .Trashes, .fseventsd, .TemporaryItems, .LSOverride
  • Windows: Thumbs.db, ehthumbs.db, ehthumbs_vista.db, desktop.ini
Option Description
--include NAME Additional exact file/directory name to remove (repeatable).
--list-only List junk files without removing them.
pystou cleanup /data -r --list-only
pystou cleanup /data -r --include ".gitkeep" --include ".keep"

identify

Detect file types and flag mismatched extensions or encrypted archives.

pystou identify [directory] [options]
Option Description
--check mismatch|encrypted|all Which check to run (repeatable). Omit to run all.
--extensions EXT Comma-separated extensions to filter on (e.g. .zip,.pdf).
pystou identify /data -r --check encrypted
pystou identify /data -r --check mismatch --extensions ".zip,.pdf,.docx"

stats

Report on files and directories.

pystou stats [directory] [options]
Option Description
--top N Number of top items to show (default: 10).
--by-extension Break down by file extension.
--by-size Show largest files.
--json Output as JSON.
pystou stats /data -r --by-size --top 20
pystou stats /data -r --json

empty

Find and remove empty directories.

pystou empty [directory] [options]
Option Description
--list-only List empty directories without removing them.
--include-hidden Include hidden directories (starting with .).
pystou empty /data -r --list-only
pystou empty /data -r --include-hidden

restore

Move quarantined items back to their original locations.

pystou restore [directory] [options]
Option Description
--run ID Restore one quarantine run (find IDs with pystou trash list).
--all Restore every item across all runs.
--path ORIGINAL Restore a single item by its original absolute path.
pystou restore /data --run 20260613T142501Z-9f3a
pystou restore /data --all
pystou restore /data --path /data/old-file.zip

Restore never overwrites an occupied path. If the original destination exists, the item stays in the trash and is reported as skipped.

trash

pystou trash list  [directory] [--json]
pystou trash purge [directory] [options]

list shows every quarantine run with its item count and reclaimable space. purge permanently deletes; there is no undo.

purge option Description
--run ID Purge one run.
--all Purge every run.
--older-than DAYS Purge runs at least DAYS old.
pystou trash list /data
pystou trash purge /data --older-than 30

doctor

Check that readpst, zstd, and 7z are installed and on your PATH.

pystou doctor [--json]

Migrating from 0.x

0.3.0 replaced the argparse CLI of 0.2.x with Typer.

Command Old flag (<=0.2.x) Now
dedup -c 1 / -c 2 / -c 3 --action delete / merge / skip
extract -c 1 / -c 2 --action extract / skip
extract -dc 1 / -dc 2 --remove-archives / --keep-archives
extract -N --nested
identify --check-mismatch / --check-encrypted / --check-all --check mismatch / encrypted / all

Behavior changes:

  • cleanup, dedup, and extract quarantine instead of deleting. --hard-delete restores the old behavior.
  • New commands: pystou restore, pystou trash list, pystou trash purge, pystou doctor.
  • pystou --install-completion enables shell tab-completion.

Development

make install    # sync the environment with dev extras
make test
make lint
make typecheck

Archive extraction tests need readpst, zstd, and 7z on your PATH.

License

MIT.

Download files

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

Source Distribution

pystou-0.5.0.tar.gz (145.5 kB view details)

Uploaded Source

Built Distribution

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

pystou-0.5.0-py3-none-any.whl (53.0 kB view details)

Uploaded Python 3

File details

Details for the file pystou-0.5.0.tar.gz.

File metadata

  • Download URL: pystou-0.5.0.tar.gz
  • Upload date:
  • Size: 145.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for pystou-0.5.0.tar.gz
Algorithm Hash digest
SHA256 00b3063e7d6bc186f127a4f2fe1e06c654984411ba0eb622cdc5d0fa7eff232b
MD5 546fa367e41d2d8811e5c58fc54acf4b
BLAKE2b-256 b4378c94a978d755e64cefdb1138694f995492bffe4964f2af3822b84c42e79c

See more details on using hashes here.

Provenance

The following attestation bundles were made for pystou-0.5.0.tar.gz:

Publisher: release.yml on ICIJ/pystou

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file pystou-0.5.0-py3-none-any.whl.

File metadata

  • Download URL: pystou-0.5.0-py3-none-any.whl
  • Upload date:
  • Size: 53.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for pystou-0.5.0-py3-none-any.whl
Algorithm Hash digest
SHA256 45bbe75f97f7fe02123faef38a616d371b9d191b7fb562f34c8ab284d5a53e07
MD5 97f8d62328469b5e2ac1ec95fba846e6
BLAKE2b-256 4dae760682b8a3e7d814074dd5b1e866ec09de44a6d8ab945ccf9a589b3e3a44

See more details on using hashes here.

Provenance

The following attestation bundles were made for pystou-0.5.0-py3-none-any.whl:

Publisher: release.yml on ICIJ/pystou

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

0.8.1

2 files

0.8.0

2 files

0.7.0

2 files

0.6.0

2 files

This release

0.5.0 This release

2 files

0.4.1

2 files

0.4.0

2 files

0.3.1

2 files

0.3.0

2 files

0.2.0

2 files

0.1.1

2 files

0.1.0

2 files

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