Environment lifecycle
Creating, refreshing, and replacing environments — and what protects you when two processes try to do it at once.
Create
$ tn-venv .venv
Creation refuses to overwrite an existing environment unless you say
otherwise: if DEST/pyvenv.cfg already exists and neither --clear nor
--upgrade was given, the command fails with exit code 1. A pre-existing
non-environment directory (no pyvenv.cfg) is reused in place, matching
the behaviour of python -m venv.
One hard rule: the destination path must not contain the platform’s PATH
separator (; on Windows, : on POSIX). Such a path would corrupt every
activation script, so creation is refused up front with exit code 1.
Upgrade in place
$ tn-venv .venv --upgrade
--upgrade rewrites the interpreter binaries, pyvenv.cfg, and the
activation scripts, and re-runs the seeder (ensurepip --upgrade), without
touching site-packages. Use it after the base interpreter was updated
(e.g. 3.12.4 → 3.12.8) to re-point the environment at the new binaries.
Running --upgrade against a destination that does not exist simply
creates it — the flag is idempotent.
Clear and recreate
$ tn-venv .venv --clear
--clear deletes the entire destination directory — including
site-packages and anything else you left in it — before creating the
fresh environment. On Windows, read-only files are made writable during
deletion, so checked-out or locked-against-deletion artifacts do not block
recreation.
When --clear and --upgrade are combined, --clear wins: the directory
is removed first and --upgrade becomes a no-op.
Concurrency and locking
Every creation runs under an inter-process file lock named
DEST.tn-venv.lock, created next to the destination with
O_CREAT | O_EXCL:
A second
tn-venvprocess targeting the same directory waits, polling every 50 ms, for up to 120 seconds.The lock file records the holder’s pid, host, and timestamp. If the holder’s pid is dead and the lock is older than 600 seconds, the lock is considered stale and is reclaimed automatically — a crashed process can never wedge a directory forever.
When the timeout expires, creation fails with a
LockError(exit code 1) that names the lock file.
The lock is released whether creation succeeds, fails, or is interrupted.
What lands on disk
The exact per-platform file layout is documented in
Environment layout; pyvenv.cfg keys are enumerated in
pyvenv.cfg reference.