Relax the `filelock<4` upper bound to allow filelock 4.x
envgap__pypa__virtualenv-3285
01 / FAILURE SIGNATURE
As reported upstream
No identifying execution failure has been captured.
Not a benchmark task.
- The project already builds and runs before the fix, so there is nothing to repair.
02 / ENVIRONMENT RECIPE
- Base commit
4f09d426aba3e07981d5003fe6daee77c1160ff8- Manifest
pyproject.toml- Reproduce
Awaiting issue-specific recipe- Run under trace
Awaiting a meaningful runtime command
03 / ORIGINAL ISSUE TEXT
pypa/virtualenv #3285 · read the original issue
**What's the problem this feature will solve?**
`virtualenv` caps `filelock` below 4:
```
filelock>=3.24.2,<4; python_version>='3.10'
```
`filelock` 4.0.0 was released on 2026-09-17 (4.0.1 on 2026-09-19), so this cap now blocks the whole downstream ecosystem from adopting it. Because `pre-commit` requires `virtualenv>=20.10.0`, effectively *any* project that uses `pre-commit` is transitively pinned to `filelock<4`, even if it never touches `virtualenv` directly.
A resolver failure for a project depending on both looks like this:
```
× No solution found when resolving dependencies:
╰─▶ Because virtualenv==21.2.1 depends on filelock>=3.24.2,<4 and your
project depends on filelock==4.0.1, we can conclude that your project
and virtualenv==21.2.1 are incompatible.
```
There is no escape by upgrading: I checked the PyPI metadata of every `virtualenv` release in the 21.x line (40 releases, 21.0 through the current 21.9.1) and all of them declare the same `filelock<4` bound. Dropping the direct pin doesn't help either — `uv` reports that every `virtualenv>=20.10.0` caps `filelock<4`, so `pre-commit` alone is enough to block it.
**Describe the solution you'd like**
Relax the upper bound to admit `filelock` 4.x, e.g.:
```
filelock>=3.24.2,<5; python_version>='3.10'
```
The cap looks precautionary rather than a response to an actual incompatibility:
- The only change in `filelock` 4.0.0 was [tox-dev/filelock#738](https://github.com/tox-dev/filelock/pull/738), *"replace the state mutex with a generation log"*, which is confined to the **soft** (`SoftFileLock`) read/write implementation.
- `virtualenv` never imports `SoftFileLock`. The single import site is `src/virtualenv/util/lock.py`:
```python
from filelock import FileLock, Timeout
```
Both of those are untouched by the 4.0.0 change.
**Verification I ran**
Against `virtualenv` 21.9.1 on CPython 3.13, swapping only the `filelock` version between `3.25.0` (the current upper-bound-satisfying release) and `4.0.1`:
| Check | filelock 3.25.0 | filelock 4.0.1 |
|---|---|---|
| `tests/unit` (excluding `test_sbom.py`, which fails collection on both, unrelated) | 452 passed, 84 skipped | **452 passed, 84 skipped** |
| `tests/unit/seed/embed/test_bootstrap_link_via_app_data.py` + `tests/unit/test_util.py` | 39 passed, 1 skipped | **39 passed, 1 skipped** |
| 6 concurrent `virtualenv` creations sharing one cold `--app-data` dir | 6/6 created, exit 0 | **6/6 created, exit 0** |
| `ReentrantFileLock.lock_for_key`, nested/reentrant | OK | **OK** |
Results are identical across the two, including the concurrency test that exercises `_CountedFileLock` and the `app_data` disk-folder locking.
**Alternative Solutions**
Downstream can force the issue with a resolver override (`[tool.uv] override-dependencies`), but that silently violates a declared constraint and isn't something I'd want to carry in a shared repo. Staying on `filelock` 3.x is the only other option, which is what we're doing for now.
**Additional context**
Hit while trying to update `filelock` in [scylladb/scylla-dtest](https://github.com/scylladb/scylla-dtest) — the lockfile refresh cannot resolve. Happy to open a PR relaxing the bound if you'd like.
04 / LABELS
Labels from the report text only; not yet run
No supported category has been assigned.
Label rules and the text that matched
[]