Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: tox-dev/filelock
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 3.20.3
Choose a base ref
...
head repository: tox-dev/filelock
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 3.21.0
Choose a head ref
  • 10 commits
  • 23 files changed
  • 6 contributors

Commits on Jan 12, 2026

  1. [pre-commit.ci] pre-commit autoupdate (#466)

    Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
    Co-authored-by: Bernát Gábor <bgabor8@bloomberg.net>
    pre-commit-ci[bot] and gaborbernat authored Jan 12, 2026
    Configuration menu
    Copy the full SHA
    ce6c18a View commit details
    Browse the repository at this point in the history

Commits on Jan 20, 2026

  1. [pre-commit.ci] pre-commit autoupdate (#467)

    updates:
    - [github.com/astral-sh/ruff-pre-commit: v0.14.11 → v0.14.13](astral-sh/ruff-pre-commit@v0.14.11...v0.14.13)
    - [github.com/rbubley/mirrors-prettier: v3.7.4 → v3.8.0](rbubley/mirrors-prettier@v3.7.4...v3.8.0)
    
    Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
    pre-commit-ci[bot] authored Jan 20, 2026
    Configuration menu
    Copy the full SHA
    680b51c View commit details
    Browse the repository at this point in the history

Commits on Jan 26, 2026

  1. [pre-commit.ci] pre-commit autoupdate (#468)

    Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
    pre-commit-ci[bot] authored Jan 26, 2026
    Configuration menu
    Copy the full SHA
    c45841d View commit details
    Browse the repository at this point in the history

Commits on Feb 11, 2026

  1. 🔧 chore: modernize tooling and bump deps (#470)

    Replace mypy with ty for type checking as it provides faster feedback
    and simpler configuration. Adopt pytest 9's native TOML config format
    ([tool.pytest] with dotted keys). Drop the unused prettier xml plugin
    and configure print-width/prose-wrap to match project conventions.
    
    Remove the outdated black code style badge since the project uses ruff.
    Fix release.yml bot author exclusion patterns to use the [bot] suffix.
    Bump all dev dependencies to their latest releases.
    
    Signed-off-by: Bernát Gábor <bgabor8@bloomberg.net>
    gaborbernat authored Feb 11, 2026
    Configuration menu
    Copy the full SHA
    4ed0ca2 View commit details
    Browse the repository at this point in the history

Commits on Feb 12, 2026

  1. ✨ feat(lock): add SQLite-based ReadWriteLock (#399)

    The existing lock classes (`FileLock`, `SoftFileLock`) only support exclusive locking -- every caller blocks every other caller, even when most only need to read. This is fine for write-heavy workloads, but read-heavy ones pay an unnecessary serialization cost. 🔒
    
    This PR adds `ReadWriteLock`, a cross-process shared/exclusive lock backed by SQLite transactions. Multiple processes can hold a read lock simultaneously while write locks remain exclusive. The lock is reentrant within the same mode (nested reads or nested writes from the same thread), but upgrading from read to write or downgrading from write to read raises `RuntimeError` to prevent deadlocks. Write locks are pinned to the acquiring thread.
    
    The implementation uses SQLite's built-in `BEGIN TRANSACTION` (shared) and `BEGIN EXCLUSIVE TRANSACTION` (exclusive) with `journal_mode=MEMORY` rather than WAL, because WAL would allow readers to proceed during an exclusive write -- exactly the behavior we need to prevent. A double-check locking pattern serializes concurrent threads through a `threading.Lock` before touching SQLite, and `busy_timeout` is recomputed after each potentially-blocking pragma to keep timeout accounting accurate. Instances are singletons by default (keyed by resolved path via a `WeakValueDictionary`), matching the pattern established by `BaseFileLock`'s `is_singleton` parameter.
    
    📝 The docs (`docs/index.rst`) have been substantially reworked: a new section hierarchy (`Usage` / `Lock types`), platform resolution details for `FileLock`, a dedicated `ReadWriteLock` section with usage examples, limitations for every lock type, async variant mentions in "Choosing the right lock", and singleton lock documentation. The changelog has been backfilled from v3.12.1 through v3.20.3. Code examples now use `pathlib.Path` and descriptive variable names throughout. Existing docstrings in `_api.py`, `asyncio.py`, and `_soft.py` have been expanded with `:param:` / `:raises:` / `:return:` tags and `versionadded` directives.
    
    ♻️ The `_read_write.py` source extracts shared acquire logic into `_acquire()`, `_validate_reentrant()`, and `_configure_and_begin()` to eliminate ~50 lines of duplication between `acquire_read` and `acquire_write`. Internal attributes use underscore-prefixed names (`_con`, `_lock_level`, etc.) and imports are relative throughout.
    
    A PyPy-specific `test_virtualenv` skip was added due to a segfault in PyPy's `_sqlite3.Cursor.__del__._reset` during garbage collection -- no upstream issue was found for this bug.
    leventov authored Feb 12, 2026
    Configuration menu
    Copy the full SHA
    cfd4446 View commit details
    Browse the repository at this point in the history
  2. ✨ feat(unix): delete lock file on release (#408)

    Lock files are now cleaned up when released, preventing orphan .lock
    files from accumulating. The acquire/release cycle handles three
    race conditions:
    
    - Sticky-bit directories (#317): O_CREAT on a file owned by another
      user raises PermissionError, so we fall back to opening without
      O_CREAT when the file already exists.
    - Deleted-before-open: if the file vanishes between exists() and
      os.open(), the caller's retry loop recreates it.
    - Deleted-before-flock: if another process unlinks the file between
      our open() and flock(), st_nlink==0 detects the stale inode and
      the retry loop starts fresh.
    
    Fixes #31.
    
    Co-authored-by: Bernát Gábor <bgabor8@bloomberg.net>
    sbc100 and gaborbernat authored Feb 12, 2026
    Configuration menu
    Copy the full SHA
    03b0ab7 View commit details
    Browse the repository at this point in the history
  3. 👷 ci(release): consolidate to two jobs (#471)

    The bump and build jobs shared identical checkout and uv setup steps,
    and the all-pass gate job becomes unnecessary with a single build job
    that can serve as the branch protection check directly.
    
    Merging bump into build eliminates a runner spin-up and the duplicated
    checkout. The release job now references build outputs instead of bump.
    gaborbernat authored Feb 12, 2026
    Configuration menu
    Copy the full SHA
    be8fe1a View commit details
    Browse the repository at this point in the history
  4. 👷 ci(release): commit changelog and use release config (#472)

    The release workflow generated changelog text but never persisted it
    to docs/changelog.rst, so the repo changelog was always stale.
    
    The release job now updates the changelog file, commits as the
    actor who triggered the release, tags, and pushes before publishing.
    The changelog script reads excluded authors from .github/release.yml
    instead of hardcoding bot names.
    gaborbernat authored Feb 12, 2026
    Configuration menu
    Copy the full SHA
    0dc277c View commit details
    Browse the repository at this point in the history
  5. 🐛 fix(ci): make release workflow robust

    Job-level permissions override top-level, so the build job needed
    explicit contents:read for the PyGitHub API calls in changelog
    generation.
    
    Changelog text contains RST backticks that bash interprets as command
    substitution when interpolated via ${{ }}. Pass through env vars
    instead.
    
    Push the tag before the branch so if tag push fails, main stays clean.
    All three release steps (commit/tag, PyPI, GitHub release) are now
    idempotent for safe retries.
    gaborbernat committed Feb 12, 2026
    Configuration menu
    Copy the full SHA
    c2f5754 View commit details
    Browse the repository at this point in the history
  6. Release 3.21.0

    gaborbernat committed Feb 12, 2026
    Configuration menu
    Copy the full SHA
    053168f View commit details
    Browse the repository at this point in the history
Loading