Create self-cleaning ephemeral directories that vanish after a lifetime or on restart.
Project description
ephemdir
ephemdir (ephemeral directory) creates temporary directories that clean
themselves up — automatically removed once their lifetime expires or after the
machine restarts. Names are playful two-word slugs like brave-otter or
nimble-marmot instead of dull ones like tmp_data.
Works on Linux, macOS and Windows with a single small dependency
(coolname).
Installation
pip install ephemdir
Quick start
from ephemdir import tempdir
# Lives until the next system restart (the default).
work = tempdir()
print(work) # -> /current/dir/brave-otter
(work.path / "data.txt").write_text("hello")
# Also expires after a given lifetime.
cache = tempdir(lifetime="2h") # "30m", "1h30m", 3600, timedelta(hours=2) ...
# Survive restarts and rely only on the lifetime.
keep = tempdir(lifetime="7d", remove_on_restart=False)
# Do not delete while a process still has files open inside (Linux/macOS).
busy = tempdir(lifetime="1h", keep_while_in_use=True)
# Use as a context manager: removed automatically when the block exits.
with tempdir() as scratch:
(scratch / "tmp.bin").write_bytes(b"...")
tempdir() parameters
| Parameter | Default | Description |
|---|---|---|
lifetime |
None |
Time to live: seconds, timedelta, or "2h"/"1h30m". None = until restart. |
remove_on_restart |
True |
Remove the directory after the machine reboots. |
keep_while_in_use |
False |
Defer deletion while files are still open inside (Linux/macOS). |
parent |
current dir | Where to create the directory. |
prefix |
"" |
Prefix prepended to the generated name. |
words |
2 |
Number of words in the generated name. |
Any option left unset falls back to the user config file, then to the built-in default shown above.
Managing a directory
d = tempdir()
d.path # pathlib.Path to the directory
d.created_at # creation timestamp
d.expires_at # expiry timestamp or None
d.remove() # delete now and stop tracking
d.keep() # stop tracking but keep on disk (becomes permanent)
d.extend("2h") # fresh lifetime counted from now (None = no time limit)
You can also manage any tracked directory later — by full path, exact name or a unique prefix of the name:
from ephemdir import keep, extend, remove, resolve, prune
keep("brave-otter") # liked it? make it permanent
extend("brave-otter", "2h") # give it two more hours from now
remove("brave-otter") # delete it right away
resolve("bra") # -> Path to the matching tracked directory
prune() # forget entries whose dirs were deleted manually
How cleanup works
ephemdir records each directory in a small JSON registry in your per-user data directory. Cleanup happens in two ways:
- Lazily — every call to
tempdir()first sweeps anything already due. - On demand — run
ephemdir sweepfrom the command line.
To clean up reliably over time (and right after a reboot), install a scheduled sweep service for your platform — one command, no manual unit files:
ephemdir install-service --interval 600 # launchd / systemd / Task Scheduler
ephemdir uninstall-service
Prefer to wire it up yourself? The equivalents are:
- Linux (cron):
*/10 * * * * ephemdir sweep - macOS (launchd): a
LaunchAgentrunningephemdir sweep; template inpackaging/. - Windows (Task Scheduler): a task running
ephemdir sweepat logon and on a repeating interval.
You can also keep a foreground watcher running:
ephemdir watch --interval 600
Configuration
Set per-user defaults in a config.toml file in your config directory
(~/.config/ephemdir/ on Linux, ~/Library/Application Support/ephemdir/ on
macOS, %APPDATA%\ephemdir\ on Windows). Every key is optional:
lifetime = "6h"
remove_on_restart = true
keep_while_in_use = true
prefix = "scratch-"
words = 2
These apply to any option you do not pass explicitly to tempdir() or the
ephemdir new command. Reading the file uses the standard-library tomllib
(Python 3.11+) or tomli on older versions.
The environment variables EPHEMDIR_DATA_DIR (registry location) and
EPHEMDIR_CONFIG_DIR (config location) override the platform defaults —
handy for sandboxes, tests and dotfile-managed setups.
Command-line interface
ephemdir new # create a directory, print its path
ephemdir new --lifetime 2h # with a lifetime
ephemdir new --keep-on-restart # do not remove on restart
ephemdir list # tracked directories, status and time left
ephemdir path brave-otter # print a tracked directory's path
ephemdir keep brave-otter # liked it? stop tracking, keep forever
ephemdir extend brave-otter 2h # fresh lifetime from now (--forever: no limit)
ephemdir rm brave-otter # remove a tracked directory now
ephemdir sweep # remove everything due now
ephemdir sweep --force # remove every tracked directory
ephemdir prune # forget entries deleted outside ephemdir
ephemdir watch # sweep periodically in the foreground
ephemdir install-service # schedule sweeps via the OS scheduler
ephemdir uninstall-service # remove the scheduled service
Every command that takes a directory accepts a full path, the exact name or a
unique prefix (bra for brave-otter). Add -v for more output or -q to
stay quiet.
Listing with time left
ephemdir list shows each directory's status at a glance:
🟢 spotted-armadillo 1h 59m left ~/work/spotted-armadillo
🟡 vermilion-mackerel 4m 59s left ~/work/vermilion-mackerel
🔄 caped-dodo until restart ~/work/caped-dodo
🔴 furious-caiman expired 5m ago ~/work/furious-caiman
👻 lucky-yak gone (deleted manually) ~/work/lucky-yak
🟢 counting down · 🟡 less than 15 minutes left · 🔴 due on the next
sweep · 🔄 until restart · 📌 no auto-cleanup · 👻 deleted outside
ephemdir (the entry is dropped automatically). Terminals without emoji support
fall back to ASCII tags; --plain forces them, --json prints
machine-readable output for scripting.
Jumping into directories (ecd / enew)
A subprocess cannot change your shell's working directory, so ephemdir ships
shell functions instead (the same trick zoxide and nvm use). Add one line
to your shell rc file:
# ~/.bashrc or ~/.zshrc
eval "$(ephemdir shell-init)"
# ~/.config/fish/config.fish
ephemdir shell-init fish | source
# PowerShell $PROFILE
Invoke-Expression (& ephemdir shell-init powershell | Out-String)
Then:
enew -l 2h # create a directory and cd into it
ecd brave-otter # cd into a tracked directory by name or prefix
ecd # cd into the most recently created one
The new and path commands print the path to stdout and all diagnostics
to stderr, so they also compose cleanly by hand: cd "$(ephemdir new)".
Development
pip install -e ".[dev]"
pytest
License
MIT © vindfjur
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
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file ephemdir-0.3.0.tar.gz.
File metadata
- Download URL: ephemdir-0.3.0.tar.gz
- Upload date:
- Size: 33.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
bf15f469b7c904e2afc3ca5190c813e48a60840d2660721cf1dd8af2d408ee96
|
|
| MD5 |
f4ef282ca5ad97424c61c679452a761c
|
|
| BLAKE2b-256 |
f160f64ae2e3404113e61721894e6ea0eb4385d282287cf054e371853b6a2ec1
|
Provenance
The following attestation bundles were made for ephemdir-0.3.0.tar.gz:
Publisher:
publish.yml on vindfjur/ephemdir
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
ephemdir-0.3.0.tar.gz -
Subject digest:
bf15f469b7c904e2afc3ca5190c813e48a60840d2660721cf1dd8af2d408ee96 - Sigstore transparency entry: 1789741014
- Sigstore integration time:
-
Permalink:
vindfjur/ephemdir@c6a01ddab640040c99861504847cc077494265b6 -
Branch / Tag:
refs/tags/v0.3.0 - Owner: https://github.com/vindfjur
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@c6a01ddab640040c99861504847cc077494265b6 -
Trigger Event:
release
-
Statement type:
File details
Details for the file ephemdir-0.3.0-py3-none-any.whl.
File metadata
- Download URL: ephemdir-0.3.0-py3-none-any.whl
- Upload date:
- Size: 28.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
bc3baa29a91a5ceb5790d734a12564a9d2dc12f4a3017f2b2bcf54400b62fd33
|
|
| MD5 |
cd822a0a88c6a071c1a98f9edc64412a
|
|
| BLAKE2b-256 |
37df9bcfc86aaaa24771fa3b4d67d35103ff5fcd8a5e102d74009f325ae08fd4
|
Provenance
The following attestation bundles were made for ephemdir-0.3.0-py3-none-any.whl:
Publisher:
publish.yml on vindfjur/ephemdir
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
ephemdir-0.3.0-py3-none-any.whl -
Subject digest:
bc3baa29a91a5ceb5790d734a12564a9d2dc12f4a3017f2b2bcf54400b62fd33 - Sigstore transparency entry: 1789741081
- Sigstore integration time:
-
Permalink:
vindfjur/ephemdir@c6a01ddab640040c99861504847cc077494265b6 -
Branch / Tag:
refs/tags/v0.3.0 - Owner: https://github.com/vindfjur
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@c6a01ddab640040c99861504847cc077494265b6 -
Trigger Event:
release
-
Statement type: