Commit Graph

1 Commits

Author SHA1 Message Date
d3d89c890e feat: python tool/tagger.py sets up .venv too, not just tag.sh
The shell entry points got this in 99aa194; running the .py directly still
died with ModuleNotFoundError, which is the command the file's own docstring
had been telling people to use for months.

tool/venv_bootstrap.py creates .venv, installs the project and re-executes
the same command line through it. It is stdlib-only by necessity: it runs on
an interpreter where this package does not import yet, so it cannot route
through signal_bot.external, the one module allowed to start a process. That
is why it gets the second scoped per-file-ignore rather than the rule being
bent -- kuhy's call. test_external.py now asserts a closed list of two, so a
third file still fails the gate.

Two things that are less obvious than they look:

It runs on import rather than exposing a function to call. A call would have
to happen before the caller's own third-party imports, and code before
imports is E402 -- so a call-based design needs a lint suppression in every
file it protects. Importing the module is the whole interface.

And isort would sort "venv_bootstrap" after "fastapi", silently breaking the
ordering the module depends on. It gets its own isort section ahead of the
standard library, so the formatter enforces the order instead of undoing it.

Caught while verifying: ensure() used one check to decide both whether to
re-exec and whether to install. The interpreter you typed never grows a
fastapi, so every launch reinstalled the project first. Splitting them
(ready() probes the venv, missing() probes the caller) takes a warm run from
a full pip install to 0.47s. Pinned by a test.

Verified on a clone with no .venv: first run installs and prints one line,
second and third print nothing.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WBrE1b9HvFw3xvG9bJiDFt
2026-08-31 13:34:27 +02:00