You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Severity: release-blocking — pip install repo2rlenv is completely non-functional on Windows right now
Every repo2rlenv CLI invocation crashes on Windows before argument parsing even completes, including --version. This is not on a branch — it's in the current PyPI release (confirmed below), so anyone on Windows who installs the package today gets a tool that cannot run a single command.
Reproduction
# Fresh venv, real PyPI install — no git, no fork, no local state
uv venv && uv pip install repo2rlenv
repo2rlenv --version
ModuleNotFoundError: No module named 'fcntl'
Same result from a from-scratch git clone https://github.com/huggingface/Repo2RLEnv.git + uv sync --group dev + uv run repo2rlenv --version, and from the main branch tip directly (23616db) — so it isn't specific to the PyPI packaging step either.
Environment: Windows 11 Pro, Python 3.12.11.
Root cause
cli.py's dispatcher imports several new subsystems unconditionally, before routing to any subcommand — so this runs on every invocation, --version included:
Four files reachable from that chain do import fcntl at module level — fcntl is POSIX-only and does not exist in Windows' Python stdlib at all, so no amount of pip install-ing fixes it:
In each case it's used for the same thing — advisory, non-blocking file locking to stop two concurrent controllers/loops from running against the same output directory:
with (self.directory/".lock").open("a") aslock:
fcntl.flock(lock, fcntl.LOCK_EX|fcntl.LOCK_NB)
Trace confirming the exact import chain (_dispatch → quality.loop.cli → quality.loop.runner → import fcntl → ModuleNotFoundError) is in the repro above; happy to paste the full builtins.__import__ trace if useful.
All CI checks on that PR were green (Tests (py3.12/3.13/3.14), Lint, Build, etc.) — CI runs Ubuntu only, and fcntl exists on Linux, so nothing in the matrix could have caught this.
v0.9.0 was tagged and released to PyPI 2026-09-15T11:53:16Z, ~50 minutes later, from a commit that includes be393f9. Confirmed via git merge-base --is-ancestor be393f9 v0.9.0 and by installing repo2rlenv==0.9.0 from PyPI directly (repro above).
Proposed fix
Same shape at all four call sites — guard the import and the lock acquisition by platform, since fcntl.flock has no drop-in Windows equivalent in the stdlib (msvcrt.locking is the nearest analog but has a different API; the filelock package, already a common transitive dep in this kind of stack, is the more portable fix if a third dependency is acceptable):
importsysifsys.platform!="win32":
importfcntl
...
with (self.directory/".lock").open("a") aslock:
ifsys.platform!="win32":
fcntl.flock(lock, fcntl.LOCK_EX|fcntl.LOCK_NB)
# else: single-controller-per-directory isn't enforced on Windows yet
Separately, and lower-priority than the crash itself: _dispatch() eagerly importing every subsystem (campaigns, quality.loop, tasksmith, pipelines.recipes) just to register their argument parsers means a bug in any of them (not just this one) takes down the entire CLI, including --version and --help. Lazily importing each subparser's module only when that subcommand is actually invoked (argparse supports this via a thin wrapper, or add_parser(..., func=lambda args: _lazy_import_and_run(args))) would contain future failures to the subcommand that has them, rather than the whole binary.
Happy to send a PR for the four-file fcntl fix if useful — it's mechanical and doesn't touch the locking semantics on POSIX.
Severity: release-blocking —
pip install repo2rlenvis completely non-functional on Windows right nowEvery
repo2rlenvCLI invocation crashes on Windows before argument parsing even completes, including--version. This is not on a branch — it's in the current PyPI release (confirmed below), so anyone on Windows who installs the package today gets a tool that cannot run a single command.Reproduction
Same result from a from-scratch
git clone https://github.com/huggingface/Repo2RLEnv.git+uv sync --group dev+uv run repo2rlenv --version, and from themainbranch tip directly (23616db) — so it isn't specific to the PyPI packaging step either.Environment: Windows 11 Pro, Python 3.12.11.
Root cause
cli.py's dispatcher imports several new subsystems unconditionally, before routing to any subcommand — so this runs on every invocation,--versionincluded:Four files reachable from that chain do
import fcntlat module level —fcntlis POSIX-only and does not exist in Windows' Python stdlib at all, so no amount ofpip install-ing fixes it:src/repo2rlenv/quality/loop/runner.py:5src/repo2rlenv/tasksmith/runner.py:6src/repo2rlenv/tasksmith/batch.py:6src/repo2rlenv/pipelines/recipes/history/worker.py:6In each case it's used for the same thing — advisory, non-blocking file locking to stop two concurrent controllers/loops from running against the same output directory:
Trace confirming the exact import chain (
_dispatch→quality.loop.cli→quality.loop.runner→import fcntl→ModuleNotFoundError) is in the repro above; happy to paste the fullbuiltins.__import__trace if useful.Timeline
be393f9(feat: consolidate Tasksmith and owned Harbor generation recipes #109, "feat: consolidate Tasksmith and owned Harbor generation recipes") merged 2026-09-15T11:03:56Z — 468 files, +59,156/-187, 0 reviews, self-merged by its author.Tests (py3.12/3.13/3.14),Lint,Build, etc.) — CI runs Ubuntu only, andfcntlexists on Linux, so nothing in the matrix could have caught this.v0.9.0was tagged and released to PyPI 2026-09-15T11:53:16Z, ~50 minutes later, from a commit that includesbe393f9. Confirmed viagit merge-base --is-ancestor be393f9 v0.9.0and by installingrepo2rlenv==0.9.0from PyPI directly (repro above).Proposed fix
Same shape at all four call sites — guard the import and the lock acquisition by platform, since
fcntl.flockhas no drop-in Windows equivalent in the stdlib (msvcrt.lockingis the nearest analog but has a different API; thefilelockpackage, already a common transitive dep in this kind of stack, is the more portable fix if a third dependency is acceptable):Separately, and lower-priority than the crash itself:
_dispatch()eagerly importing every subsystem (campaigns,quality.loop,tasksmith,pipelines.recipes) just to register their argument parsers means a bug in any of them (not just this one) takes down the entire CLI, including--versionand--help. Lazily importing each subparser's module only when that subcommand is actually invoked (argparse supports this via a thin wrapper, oradd_parser(..., func=lambda args: _lazy_import_and_run(args))) would contain future failures to the subcommand that has them, rather than the whole binary.Happy to send a PR for the four-file
fcntlfix if useful — it's mechanical and doesn't touch the locking semantics on POSIX.