From 9004768ff62074958964e7aa714ccff8be1a8b78 Mon Sep 17 00:00:00 2001 From: Stephen Brannen Date: Thu, 21 May 2026 16:06:45 -0500 Subject: [PATCH 1/4] chore: v0.3.3 code quality, CI improvements, and test coverage --- .../actions/setup-python-poetry/action.yml | 44 ++ .github/workflows/ci.yml | 72 +- README.md | 16 +- poetry.lock | 656 +++++++++++------- pyproject.toml | 13 +- squawk_alembic/__init__.py | 2 +- squawk_alembic/hook.py | 158 +++-- tests/conftest.py | 55 ++ tests/test_generate_sql.py | 164 +++++ tests/test_main.py | 238 +++++-- 10 files changed, 1032 insertions(+), 386 deletions(-) create mode 100644 .github/actions/setup-python-poetry/action.yml create mode 100644 tests/conftest.py create mode 100644 tests/test_generate_sql.py diff --git a/.github/actions/setup-python-poetry/action.yml b/.github/actions/setup-python-poetry/action.yml new file mode 100644 index 0000000..5465170 --- /dev/null +++ b/.github/actions/setup-python-poetry/action.yml @@ -0,0 +1,44 @@ +name: Setup Python Environment +description: Setup Python, Poetry, and cache dependencies + +inputs: + python-version: + description: Python version + required: false + default: '3.12' + install-dependencies: + description: Whether to install project dependencies + required: false + default: 'true' + +runs: + using: composite + steps: + - name: Set up Python + uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 + with: + python-version: ${{ inputs.python-version }} + + - name: Install Poetry + uses: snok/install-poetry@76e04a911780d5b312d89783f7b1cd627778900a # v1.4.1 + with: + version: "2.1.3" + virtualenvs-create: true + virtualenvs-in-project: true + installer-parallel: true + + - name: Cache virtualenv + if: inputs.install-dependencies == 'true' + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 + with: + path: .venv + key: ${{ runner.os }}-py${{ inputs.python-version }}-poetry-${{ hashFiles('**/poetry.lock') }} + restore-keys: | + ${{ runner.os }}-py${{ inputs.python-version }}-poetry- + + - name: Install dependencies + if: inputs.install-dependencies == 'true' + shell: bash + run: | + poetry sync -n + poetry env info -n diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 50d32f8..948927c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -6,40 +6,57 @@ on: pull_request: branches: [main] +concurrency: + group: ci-${{ github.head_ref || github.sha }} + cancel-in-progress: true + jobs: lint-and-test: runs-on: ubuntu-latest + timeout-minutes: 10 + outputs: + code_changed: ${{ steps.changes.outputs.code_changed }} steps: - name: Checkout code - uses: actions/checkout@v4 - - - name: Set up Python - uses: actions/setup-python@v5 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: - python-version: '3.12' + fetch-depth: 0 - - name: Install Poetry - uses: snok/install-poetry@76e04a911780d5b312d89783f7b1cd627778900a # v1.4.1 - with: - version: "2.1.3" - virtualenvs-create: true - virtualenvs-in-project: true + - name: Detect code changes + id: changes + run: | + if [ "${{ github.event_name }}" = "pull_request" ]; then + BASE="${{ github.event.pull_request.base.sha }}" + else + BASE="${{ github.event.before }}" + fi + # Only track files that affect the distributed package. + # Test, CI, and doc changes do not require a version bump or release. + CHANGED=$(git diff --name-only "$BASE" HEAD -- \ + 'squawk_alembic/' \ + 'pyproject.toml' \ + '.pre-commit-hooks.yaml') + if [ -n "$CHANGED" ]; then + echo "code_changed=true" >> "$GITHUB_OUTPUT" + echo "Code files changed:" + echo "$CHANGED" + else + echo "code_changed=false" >> "$GITHUB_OUTPUT" + echo "Only non-code files changed, skipping version check and release." + fi - - name: Install dependencies - run: poetry install --no-interaction + - name: Setup Python and Poetry + uses: ./.github/actions/setup-python-poetry - name: Run pre-commit hooks run: poetry run pre-commit run --all-files - name: Check version consistency + if: steps.changes.outputs.code_changed == 'true' run: | - PYPROJECT_VERSION=$(grep '^version = ' pyproject.toml | sed 's/version = "\(.*\)"/\1/' || true) - INIT_VERSION=$(grep '^__version__ = ' squawk_alembic/__init__.py | sed 's/__version__ = "\(.*\)"/\1/' || true) - if [ -z "$PYPROJECT_VERSION" ] || [ -z "$INIT_VERSION" ]; then - echo "::error::Could not parse version from pyproject.toml or __init__.py" - exit 1 - fi + PYPROJECT_VERSION=$(poetry version -s) + INIT_VERSION=$(python -c "import squawk_alembic; print(squawk_alembic.__version__)") if [ "$PYPROJECT_VERSION" != "$INIT_VERSION" ]; then echo "::error::Version mismatch: pyproject.toml ($PYPROJECT_VERSION) != __init__.py ($INIT_VERSION)" echo "Run 'make bump VERSION=x.y.z' to update both files." @@ -49,7 +66,7 @@ jobs: if [ "${{ github.event_name }}" = "pull_request" ]; then git fetch origin main --depth=1 - MAIN_VERSION=$(git show origin/main:pyproject.toml | grep '^version = ' | sed 's/version = "\(.*\)"/\1/' || true) + MAIN_VERSION=$(git show origin/main:pyproject.toml | python -c "import sys, tomllib; print(tomllib.loads(sys.stdin.read())['tool']['poetry']['version'])" || true) if [ -z "$MAIN_VERSION" ]; then echo "::warning::Could not determine version on main, skipping version bump check" elif [ "$PYPROJECT_VERSION" = "$MAIN_VERSION" ]; then @@ -64,8 +81,9 @@ jobs: auto-tag: needs: lint-and-test - if: github.event_name == 'push' + if: github.event_name == 'push' && needs.lint-and-test.outputs.code_changed == 'true' runs-on: ubuntu-latest + timeout-minutes: 5 permissions: contents: write outputs: @@ -74,14 +92,19 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@v4 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: fetch-depth: 0 + - name: Setup Python and Poetry + uses: ./.github/actions/setup-python-poetry + with: + install-dependencies: 'false' + - name: Create tag if needed id: tag run: | - VERSION=$(grep '^version = ' pyproject.toml | sed 's/version = "\(.*\)"/\1/') + VERSION=$(poetry version -s) TAG="v${VERSION}" echo "Detected version: $VERSION" @@ -103,12 +126,13 @@ jobs: needs: auto-tag if: needs.auto-tag.outputs.created == 'true' runs-on: ubuntu-latest + timeout-minutes: 5 permissions: contents: write steps: - name: Checkout code - uses: actions/checkout@v4 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Create GitHub Release env: diff --git a/README.md b/README.md index c3b0ef0..87ed127 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ Add the following to your `.pre-commit-config.yaml`: ```yaml repos: - repo: https://github.com/kintsugi-tax/squawk-pre-commit - rev: v0.3.0 + rev: v0.3.3 hooks: - id: squawk-alembic ``` @@ -25,7 +25,7 @@ The hook depends on `squawk-cli >= 2.0`. To pin a specific squawk version (match ```yaml repos: - repo: https://github.com/kintsugi-tax/squawk-pre-commit - rev: v0.3.0 + rev: v0.3.3 hooks: - id: squawk-alembic additional_dependencies: ["squawk-cli==2.41.0"] @@ -40,7 +40,7 @@ To skip migrations that already exist on a branch (useful for repos with existin ```yaml repos: - repo: https://github.com/kintsugi-tax/squawk-pre-commit - rev: v0.3.0 + rev: v0.3.3 hooks: - id: squawk-alembic args: [--diff-branch, main] @@ -92,6 +92,16 @@ Squawk reads its configuration from `.squawk.toml` in the consumer repo root. Se Some integration tests in `tests/test_squawk_config.py` require `squawk` on PATH and are automatically skipped if it is not installed. +**Versioning:** + +PRs that change package files (`squawk_alembic/`, `pyproject.toml`, `.pre-commit-hooks.yaml`) must include a version bump. CI enforces this. To bump: + +```bash +make bump VERSION=0.3.3 +``` + +This updates both `pyproject.toml` and `squawk_alembic/__init__.py`. On merge to main, CI automatically creates a git tag and GitHub release from the new version. Changes to tests, docs, or CI config do not require a version bump. + To test the hook against a consumer repo locally: ```bash diff --git a/poetry.lock b/poetry.lock index dc10bd1..963c1d4 100644 --- a/poetry.lock +++ b/poetry.lock @@ -46,6 +46,128 @@ files = [ {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, ] +[[package]] +name = "coverage" +version = "7.14.0" +description = "Code coverage measurement for Python" +optional = false +python-versions = ">=3.10" +groups = ["dev"] +files = [ + {file = "coverage-7.14.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:84c32d90bf4537f0e7b4dec9aaa9a938fb8205136b9d2ecf4d7629d5262dc075"}, + {file = "coverage-7.14.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:7c843572c605ab51cfdb5c6b5f2586e2a8467c0d28eca4bdef4ec70c5fecbd82"}, + {file = "coverage-7.14.0-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:0c451757d3fa2603354fdc789b5e58a0e327a117c370a40e3476ba4eabab228c"}, + {file = "coverage-7.14.0-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:3fd43f0616e765ab78d069cf8358def7363957a45cee446d65c502dcfeea7893"}, + {file = "coverage-7.14.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:731e535b1498b27d13594a0527a79b0510867b0ad891532be41cb883f2128e20"}, + {file = "coverage-7.14.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c7492f2d493b976941c7ca050f273cbda2f43c381124f7586a3e3c16d1804fec"}, + {file = "coverage-7.14.0-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:dc38367eaa2abb1b766ac333142bce7655335a73537f5c8b75aaa89c2b987757"}, + {file = "coverage-7.14.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:0a951308cde22cf77f953955a754d04dccb57fe3bb8e345d685778ed9fc1632a"}, + {file = "coverage-7.14.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:fab3877e4ebb06bd9d4d4d00ee53309ee5478e66873c66a382272e3ee33eb7ea"}, + {file = "coverage-7.14.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:b812eb847b19876ebf33fb6c4f11819af05ab6050b0bfa1bc53412ae81779adb"}, + {file = "coverage-7.14.0-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:d9c8ef6ed820c433de075657d72dda1f89a2984955e58b8a75feb3f184250218"}, + {file = "coverage-7.14.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:d128b1bba9361fbaaf6a19e179e6cfd6a9103ce0c0555876f72780acc93efd85"}, + {file = "coverage-7.14.0-cp310-cp310-win32.whl", hash = "sha256:65f267ca1370726ec2c1aa38bbe4df9a71a740f22878d2d4bf59d71a4cd8d323"}, + {file = "coverage-7.14.0-cp310-cp310-win_amd64.whl", hash = "sha256:b34ece8065914f938ed7f2c5872bb865336977a52919149846eac3744327267a"}, + {file = "coverage-7.14.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6a78e2a9d9c5e3b8d4ab9b9d28c985ea66fced0a7d7c2aec1f216e03a2011480"}, + {file = "coverage-7.14.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a1816c505187592dcd1c5a5f226601a549f70365fbd00930ac88b0c225b76bb4"}, + {file = "coverage-7.14.0-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:d8e1762f0e9cbc26ec315471e7b47855218e833cd5a032d706fbf43845d878c7"}, + {file = "coverage-7.14.0-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:9336e23e8bb3a3925398261385e2a1533957d3e760e91070dcb0e98bfa514eed"}, + {file = "coverage-7.14.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9cd1169b2230f9cbe9c638ba38022ed7a2b1e641cc07f7cea0365e4be2a74980"}, + {file = "coverage-7.14.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:d1bb3543b58fea74d2cd1abc4054cc927e4724687cb4560cd2ed88d2c7d820c0"}, + {file = "coverage-7.14.0-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:a93bac2cb577ef60074999ed56d8a1535894398e2ed920d4185c3ec0c8864742"}, + {file = "coverage-7.14.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:5904abf7e18cddc463219b17552229650c6b79e061d31a1059283051169cf7d5"}, + {file = "coverage-7.14.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:741f57cddc9004a8c81b084660215f33a6b597dbe62c31386b983ee26310e327"}, + {file = "coverage-7.14.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:664123feb0929d7affc135717dbd70d61d98688a08ab1e5ba464739620c6252d"}, + {file = "coverage-7.14.0-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:c83d2399a51bbec8429266905d33616f04bc5726b1138c35844d5fcd896b2e20"}, + {file = "coverage-7.14.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:bcb2e855b87321259a037429288ae85216d191c74de3e79bf57cd2bc0761992c"}, + {file = "coverage-7.14.0-cp311-cp311-win32.whl", hash = "sha256:731dc15b385ac52289743d476245b61e1a2927e803bef655b52bc3b2a75a21f3"}, + {file = "coverage-7.14.0-cp311-cp311-win_amd64.whl", hash = "sha256:bfb0ed8ec5d25e93face268115d7964db9df8b9aae8edcde9ec6b16c726a7cc1"}, + {file = "coverage-7.14.0-cp311-cp311-win_arm64.whl", hash = "sha256:7ebb1c6df9f78046a1b1e0a89674cd4bf73b7c648914eebcf976a57fd99a5627"}, + {file = "coverage-7.14.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7ffd19fc8aed057fd686a17a4935eef5f9859d69208f96310e893e64b9b6ccf5"}, + {file = "coverage-7.14.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:829994cfe1aeb773ca27bf246d4badc1e764893e3bfb98fff820fcecd1ca4662"}, + {file = "coverage-7.14.0-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:b4f07cf7edcb7ec39431a5074d7ea83b29a9f71fcfc494f0f40af4e65180420f"}, + {file = "coverage-7.14.0-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:ca3d9cf2c32b521bd9518385608787fa86f38daf993695307531822c3430ed67"}, + {file = "coverage-7.14.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:92af52828e7f29d827346b0294e5a0853fa206db77db0395b282918d41e28db9"}, + {file = "coverage-7.14.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:7b2bb6c9d7e769360d0f20a0f219603fd64f0c8f97de17ab25853261602be0fb"}, + {file = "coverage-7.14.0-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:1c9ed6ef99f88fb8c14aa8e2bf8eb0fe55fa2edfea68f8675d78741df1a5ac0e"}, + {file = "coverage-7.14.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8231ade007f37959fbf58acc677f26b922c02eda6f0428ea307da0fd39681bf3"}, + {file = "coverage-7.14.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:d8b013632cc1ce1d09dbe4f32667b4d320ec2f54fc326ebeffcd0b0bcc2bb6c4"}, + {file = "coverage-7.14.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:1733198802d71ec4c524f322e2867ee05c62e9e75df86bdca545407a221827d1"}, + {file = "coverage-7.14.0-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:72a305291fa8ee01332f1aaf38b348ca34097f6aa0b0ef627eef2837e57bbba5"}, + {file = "coverage-7.14.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:fcaba850dd317c65423a9d63d88f9573c53b00354d6dd95724576cc98a131595"}, + {file = "coverage-7.14.0-cp312-cp312-win32.whl", hash = "sha256:5ac83957a80d0701310e96d8bec68cdcf4f90a7674b7d13f15a344315b41ab27"}, + {file = "coverage-7.14.0-cp312-cp312-win_amd64.whl", hash = "sha256:70390b0da32cb90b501953716302906e8bcce087cb283e70d8c97729f22e92b2"}, + {file = "coverage-7.14.0-cp312-cp312-win_arm64.whl", hash = "sha256:91b993743d959b8be85b4abf9d5478216a69329c321efe5be0433c1a841d691d"}, + {file = "coverage-7.14.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f2bbb8254370eb4c628ff3d6fa8a7f74ddc40565394d4f7ab791d1fe568e37ef"}, + {file = "coverage-7.14.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:23b81107f46d3f21d0cbce30664fcec0f5d9f585638a67081750f99738f6bf66"}, + {file = "coverage-7.14.0-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:22a7e06a5f11a757cdfe79018e9095f9f69ae283c5cd8123774c788deec8717b"}, + {file = "coverage-7.14.0-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:9d1aa57a1dc8e05bdc42e81c5d671d849577aeedf279f4c449d6d286f9ed88ca"}, + {file = "coverage-7.14.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:90c1a51bcfddf645b3bb7ec333d9e94393a8e94f55642380fa8a9a5a9e636cb7"}, + {file = "coverage-7.14.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a841fae2fadcae4f438d43b6ccc4aac2ad609f47cdb6cfdce60cbb3fe5ca7bc2"}, + {file = "coverage-7.14.0-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:c79d2319cabef1fe8e86df73371126931550804738f78ad7d31e3aad85a67367"}, + {file = "coverage-7.14.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:1b23b0c6f0b1db6ad769b7050c8b641c0bf215ded26c1816955b17b7f26edfa9"}, + {file = "coverage-7.14.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:55d3089079ce181a4566b1065ab28d2575eb76d8ac8f81f4fcda2bf037fee087"}, + {file = "coverage-7.14.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:49c005cba1e2f9677fb2845dcdf9a2e72a52a17d63e8231aaaae35d9f50215ef"}, + {file = "coverage-7.14.0-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:9117377b823daa28aa8635fbb08cda1cd6be3d7143257345459559aeef852d52"}, + {file = "coverage-7.14.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:7b79d646cf46d5cf9a9f40281d4441df5849e445726e369006d2b117710b33fe"}, + {file = "coverage-7.14.0-cp313-cp313-win32.whl", hash = "sha256:fb609b3658479e33f9516d46f1a89dbb9b6c261366e3a11844a96ec487533dae"}, + {file = "coverage-7.14.0-cp313-cp313-win_amd64.whl", hash = "sha256:0773d8329cf32b6fd222e4b52622c61fe8d503eb966cfc8d3c3c10c96266d50e"}, + {file = "coverage-7.14.0-cp313-cp313-win_arm64.whl", hash = "sha256:b4e26a0f1b696faf283bffe5b8569e44e336c582439df5d53281ab89ee0cba96"}, + {file = "coverage-7.14.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:953f521ca9445300397e65fda3dca58b2dbd68fee983777420b57ac3c77e9f90"}, + {file = "coverage-7.14.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:98af83fd65ae24b1fdd03aaead967a9f523bcd2f1aab2d4f3ffda65bb568a6f1"}, + {file = "coverage-7.14.0-cp313-cp313t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:668b92e6958c4db7cf92e81caac328dfbbdbb215db2850ad28f0cbe1eea0bfbd"}, + {file = "coverage-7.14.0-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:9fbd898551762dea00d3fef2b1c4f99afd2c6a3ff952ea07d60a9bd5ed4f34bc"}, + {file = "coverage-7.14.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:68af363c07ecd8d4b7d4043d85cb376d7d227eceb54e5323ee45da73dbd3e426"}, + {file = "coverage-7.14.0-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:6e57054a583da8ac55edf24117ea4c9133032cfc4cf72aa2d48c1e5d4b52f899"}, + {file = "coverage-7.14.0-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:cc3499459bbcdd51a65b64c35ab7ed2764eaf3cba826e0df3f1d7fe2e102b70b"}, + {file = "coverage-7.14.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:45899ec2138a4346ed34d601dedf5076fb74edf2d1dd9dc76a78e82397edee90"}, + {file = "coverage-7.14.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:8767486808c436f05b23ab98eb963fb29185e32a9357a166971685cb3459900f"}, + {file = "coverage-7.14.0-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:a3b5ddfd6aa7ddad53ee3edb231e88a2151507a43229b7d71b953916deca127d"}, + {file = "coverage-7.14.0-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:63df0fe568e698e1045792399f8ab6da3a6c2dce3182813fb92afa2641087b47"}, + {file = "coverage-7.14.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:827d6397dbd95144939b18f89edf31f63e1f99633e8d5f32f22ba8bdda567477"}, + {file = "coverage-7.14.0-cp313-cp313t-win32.whl", hash = "sha256:7bf43e000d24012599b879791cff41589af90674722421ef11b11a5431920bab"}, + {file = "coverage-7.14.0-cp313-cp313t-win_amd64.whl", hash = "sha256:3f5549365af25d770e06b1f8f5682d9a5637d06eb494db91c6fa75d3950cc917"}, + {file = "coverage-7.14.0-cp313-cp313t-win_arm64.whl", hash = "sha256:6d160217ec6fe890f16ad3a9531761589443749e448f91986c972714fad361c8"}, + {file = "coverage-7.14.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:9aed9fa983514ca032790f3fe0d1c0e42ca7e16b42432af1706b50a9a46bef5d"}, + {file = "coverage-7.14.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:ba3b8390db29296dbbf49e91b6fe08f990743a90c8f447ba4c2ffc29670dfa63"}, + {file = "coverage-7.14.0-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:3a5d8e876dfa2f102e970b183863d6dedd023d3c0eeca1fe7a9787bc5f28b212"}, + {file = "coverage-7.14.0-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:5ebb8f4614a3787d567e610bbfdf96a4798dd69a1afb1bd8ad228d4111fe6ff3"}, + {file = "coverage-7.14.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6b9bf47223dd8db3d4c4b2e443b02bace480d428f0822c3f991600448a176c97"}, + {file = "coverage-7.14.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:3485a836550b303d006d57cc06e3d5afaabc642c77050b7c985a97b13e3776b8"}, + {file = "coverage-7.14.0-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:3e7e88110bae996d199d1693ca8ec3fd52441d426401ae963437598667b4c5eb"}, + {file = "coverage-7.14.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:15228a6800ce7bdf1b74800595e56db7138cecb338fdbf044806e10dcf182dfe"}, + {file = "coverage-7.14.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:9d26ac7f5398bafc5b57421ad994e8a4749e8a7a0e62d05ec7d53014d5963bfa"}, + {file = "coverage-7.14.0-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:2fb73254ff43c911c967a899e1359bc5049b4b115d6e8fbdde4937d0a2246cd5"}, + {file = "coverage-7.14.0-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:454a380af72c6adada298ed270d38c7a391288198dbfb8467f786f588751a90c"}, + {file = "coverage-7.14.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:65c86fb646d2bd2972e96bd1a8b45817ed907cee68655d6295fe7ec031d04cca"}, + {file = "coverage-7.14.0-cp314-cp314-win32.whl", hash = "sha256:6a6516b02a6101398e19a3f44820f69bab2590697f7def4331f668b14adaf828"}, + {file = "coverage-7.14.0-cp314-cp314-win_amd64.whl", hash = "sha256:45e0f79d8351fa76e256716df91eab12890d32678b9590df7ae1042e4bd4cf5d"}, + {file = "coverage-7.14.0-cp314-cp314-win_arm64.whl", hash = "sha256:4b899594a8b2d81e5cc064a0d7f9cac2081fed91049456cae7676787e41549c9"}, + {file = "coverage-7.14.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:f580f8c80acd94ac72e863efe2cab791d8c38d153e0b463b92dfa000d5c84cd1"}, + {file = "coverage-7.14.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:a2bd259c442cd43c49b30fbafc51776eb19ea396faf159d26a83e6a0a5f13b0c"}, + {file = "coverage-7.14.0-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:a706b908dfa85538863504c624b237a3cc34232bf403c057414ebfdb3b4d9f84"}, + {file = "coverage-7.14.0-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:7333cd944ee4393b9b3d3c1b598c936d4fc8d70573a4c7dacfec5590dd50e436"}, + {file = "coverage-7.14.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0f162bc9a15b82d947b02651b0c7e1609d6f7a8735ca330cfadec8481dd97d5a"}, + {file = "coverage-7.14.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:362cb78e01a5dc82009d88004cf60f2e6b6d6fcbfdec05b05af73b0abf40118f"}, + {file = "coverage-7.14.0-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:acebd068fca5512c3a6fde9c045f901613478781a73f0e82b307b214daef23fb"}, + {file = "coverage-7.14.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:29fe3da551dface75deb2ccbf87b6b66e2e7ef38f6d89050b428be94afff3490"}, + {file = "coverage-7.14.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:b4cc4fce8672fffcb09b0eafc167b396b3ba53c4a7230f54b7aaffbf6c835fa9"}, + {file = "coverage-7.14.0-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:5d4a51aad8ba8bdcd2b8bd8f03d4aca19693fa2327a3470e4718a25b03481020"}, + {file = "coverage-7.14.0-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:9f323af3e1e4f68b60b7b247e37b8515563a61375518fa59de1af48ba28a3db6"}, + {file = "coverage-7.14.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:1a0abc7342ea9711c469dd8b821c6c311e6bc6aac1442e5fbd6b27fae0a8f3db"}, + {file = "coverage-7.14.0-cp314-cp314t-win32.whl", hash = "sha256:a9f864ef57b7172e2db87a096642dd51e179e085ab6b2c371c29e885f65c8fb2"}, + {file = "coverage-7.14.0-cp314-cp314t-win_amd64.whl", hash = "sha256:29943e552fdc08e082eb51400fb2f58e118a83b5542bd06531214e084399b644"}, + {file = "coverage-7.14.0-cp314-cp314t-win_arm64.whl", hash = "sha256:742a73ea621953b012f2c4c2219b512180dd84489acf5b1596b0aafc55b9100b"}, + {file = "coverage-7.14.0-py3-none-any.whl", hash = "sha256:8de5b61163aee3d05c8a2beab6f47913df7981dad1baf82c414d99158c286ab1"}, + {file = "coverage-7.14.0.tar.gz", hash = "sha256:057a6af2f160a85384cde4ab36f0d2777bae1057bae255f95413cdd382aa5c74"}, +] + +[package.dependencies] +tomli = {version = "*", optional = true, markers = "python_full_version <= \"3.11.0a6\" and extra == \"toml\""} + +[package.extras] +toml = ["tomli ; python_full_version <= \"3.11.0a6\""] + [[package]] name = "distlib" version = "0.4.0" @@ -79,78 +201,104 @@ test = ["pytest (>=6)"] [[package]] name = "filelock" -version = "3.24.3" +version = "3.29.0" description = "A platform independent file lock." optional = false python-versions = ">=3.10" groups = ["dev"] files = [ - {file = "filelock-3.24.3-py3-none-any.whl", hash = "sha256:426e9a4660391f7f8a810d71b0555bce9008b0a1cc342ab1f6947d37639e002d"}, - {file = "filelock-3.24.3.tar.gz", hash = "sha256:011a5644dc937c22699943ebbfc46e969cdde3e171470a6e40b9533e5a72affa"}, + {file = "filelock-3.29.0-py3-none-any.whl", hash = "sha256:96f5f6344709aa1572bbf631c640e4ebeeb519e08da902c39a001882f30ac258"}, + {file = "filelock-3.29.0.tar.gz", hash = "sha256:69974355e960702e789734cb4871f884ea6fe50bd8404051a3530bc07809cf90"}, ] [[package]] name = "greenlet" -version = "3.3.2" +version = "3.5.1" description = "Lightweight in-process concurrent programming" optional = false python-versions = ">=3.10" groups = ["dev"] markers = "platform_machine == \"aarch64\" or platform_machine == \"ppc64le\" or platform_machine == \"x86_64\" or platform_machine == \"amd64\" or platform_machine == \"AMD64\" or platform_machine == \"win32\" or platform_machine == \"WIN32\"" files = [ - {file = "greenlet-3.3.2-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:9bc885b89709d901859cf95179ec9f6bb67a3d2bb1f0e88456461bd4b7f8fd0d"}, - {file = "greenlet-3.3.2-cp310-cp310-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b568183cf65b94919be4438dc28416b234b678c608cafac8874dfeeb2a9bbe13"}, - {file = "greenlet-3.3.2-cp310-cp310-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:527fec58dc9f90efd594b9b700662ed3fb2493c2122067ac9c740d98080a620e"}, - {file = "greenlet-3.3.2-cp310-cp310-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:508c7f01f1791fbc8e011bd508f6794cb95397fdb198a46cb6635eb5b78d85a7"}, - {file = "greenlet-3.3.2-cp310-cp310-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ad0c8917dd42a819fe77e6bdfcb84e3379c0de956469301d9fd36427a1ca501f"}, - {file = "greenlet-3.3.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:97245cc10e5515dbc8c3104b2928f7f02b6813002770cfaffaf9a6e0fc2b94ef"}, - {file = "greenlet-3.3.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:8c1fdd7d1b309ff0da81d60a9688a8bd044ac4e18b250320a96fc68d31c209ca"}, - {file = "greenlet-3.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:5d0e35379f93a6d0222de929a25ab47b5eb35b5ef4721c2b9cbcc4036129ff1f"}, - {file = "greenlet-3.3.2-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:c56692189a7d1c7606cb794be0a8381470d95c57ce5be03fb3d0ef57c7853b86"}, - {file = "greenlet-3.3.2-cp311-cp311-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1ebd458fa8285960f382841da585e02201b53a5ec2bac6b156fc623b5ce4499f"}, - {file = "greenlet-3.3.2-cp311-cp311-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a443358b33c4ec7b05b79a7c8b466f5d275025e750298be7340f8fc63dff2a55"}, - {file = "greenlet-3.3.2-cp311-cp311-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:4375a58e49522698d3e70cc0b801c19433021b5c37686f7ce9c65b0d5c8677d2"}, - {file = "greenlet-3.3.2-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8e2cd90d413acbf5e77ae41e5d3c9b3ac1d011a756d7284d7f3f2b806bbd6358"}, - {file = "greenlet-3.3.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:442b6057453c8cb29b4fb36a2ac689382fc71112273726e2423f7f17dc73bf99"}, - {file = "greenlet-3.3.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:45abe8eb6339518180d5a7fa47fa01945414d7cca5ecb745346fc6a87d2750be"}, - {file = "greenlet-3.3.2-cp311-cp311-win_amd64.whl", hash = "sha256:1e692b2dae4cc7077cbb11b47d258533b48c8fde69a33d0d8a82e2fe8d8531d5"}, - {file = "greenlet-3.3.2-cp311-cp311-win_arm64.whl", hash = "sha256:02b0a8682aecd4d3c6c18edf52bc8e51eacdd75c8eac52a790a210b06aa295fd"}, - {file = "greenlet-3.3.2-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:ac8d61d4343b799d1e526db579833d72f23759c71e07181c2d2944e429eb09cd"}, - {file = "greenlet-3.3.2-cp312-cp312-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3ceec72030dae6ac0c8ed7591b96b70410a8be370b6a477b1dbc072856ad02bd"}, - {file = "greenlet-3.3.2-cp312-cp312-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a2a5be83a45ce6188c045bcc44b0ee037d6a518978de9a5d97438548b953a1ac"}, - {file = "greenlet-3.3.2-cp312-cp312-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:ae9e21c84035c490506c17002f5c8ab25f980205c3e61ddb3a2a2a2e6c411fcb"}, - {file = "greenlet-3.3.2-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:43e99d1749147ac21dde49b99c9abffcbc1e2d55c67501465ef0930d6e78e070"}, - {file = "greenlet-3.3.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:4c956a19350e2c37f2c48b336a3afb4bff120b36076d9d7fb68cb44e05d95b79"}, - {file = "greenlet-3.3.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:6c6f8ba97d17a1e7d664151284cb3315fc5f8353e75221ed4324f84eb162b395"}, - {file = "greenlet-3.3.2-cp312-cp312-win_amd64.whl", hash = "sha256:34308836d8370bddadb41f5a7ce96879b72e2fdfb4e87729330c6ab52376409f"}, - {file = "greenlet-3.3.2-cp312-cp312-win_arm64.whl", hash = "sha256:d3a62fa76a32b462a97198e4c9e99afb9ab375115e74e9a83ce180e7a496f643"}, - {file = "greenlet-3.3.2-cp313-cp313-macosx_11_0_universal2.whl", hash = "sha256:aa6ac98bdfd716a749b84d4034486863fd81c3abde9aa3cf8eff9127981a4ae4"}, - {file = "greenlet-3.3.2-cp313-cp313-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ab0c7e7901a00bc0a7284907273dc165b32e0d109a6713babd04471327ff7986"}, - {file = "greenlet-3.3.2-cp313-cp313-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:d248d8c23c67d2291ffd47af766e2a3aa9fa1c6703155c099feb11f526c63a92"}, - {file = "greenlet-3.3.2-cp313-cp313-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:ccd21bb86944ca9be6d967cf7691e658e43417782bce90b5d2faeda0ff78a7dd"}, - {file = "greenlet-3.3.2-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b6997d360a4e6a4e936c0f9625b1c20416b8a0ea18a8e19cabbefc712e7397ab"}, - {file = "greenlet-3.3.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:64970c33a50551c7c50491671265d8954046cb6e8e2999aacdd60e439b70418a"}, - {file = "greenlet-3.3.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:1a9172f5bf6bd88e6ba5a84e0a68afeac9dc7b6b412b245dd64f52d83c81e55b"}, - {file = "greenlet-3.3.2-cp313-cp313-win_amd64.whl", hash = "sha256:a7945dd0eab63ded0a48e4dcade82939783c172290a7903ebde9e184333ca124"}, - {file = "greenlet-3.3.2-cp313-cp313-win_arm64.whl", hash = "sha256:394ead29063ee3515b4e775216cb756b2e3b4a7e55ae8fd884f17fa579e6b327"}, - {file = "greenlet-3.3.2-cp314-cp314-macosx_11_0_universal2.whl", hash = "sha256:8d1658d7291f9859beed69a776c10822a0a799bc4bfe1bd4272bb60e62507dab"}, - {file = "greenlet-3.3.2-cp314-cp314-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:18cb1b7337bca281915b3c5d5ae19f4e76d35e1df80f4ad3c1a7be91fadf1082"}, - {file = "greenlet-3.3.2-cp314-cp314-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c2e47408e8ce1c6f1ceea0dffcdf6ebb85cc09e55c7af407c99f1112016e45e9"}, - {file = "greenlet-3.3.2-cp314-cp314-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:e3cb43ce200f59483eb82949bf1835a99cf43d7571e900d7c8d5c62cdf25d2f9"}, - {file = "greenlet-3.3.2-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:63d10328839d1973e5ba35e98cccbca71b232b14051fd957b6f8b6e8e80d0506"}, - {file = "greenlet-3.3.2-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:8e4ab3cfb02993c8cc248ea73d7dae6cec0253e9afa311c9b37e603ca9fad2ce"}, - {file = "greenlet-3.3.2-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:94ad81f0fd3c0c0681a018a976e5c2bd2ca2d9d94895f23e7bb1af4e8af4e2d5"}, - {file = "greenlet-3.3.2-cp314-cp314-win_amd64.whl", hash = "sha256:8c4dd0f3997cf2512f7601563cc90dfb8957c0cff1e3a1b23991d4ea1776c492"}, - {file = "greenlet-3.3.2-cp314-cp314-win_arm64.whl", hash = "sha256:cd6f9e2bbd46321ba3bbb4c8a15794d32960e3b0ae2cc4d49a1a53d314805d71"}, - {file = "greenlet-3.3.2-cp314-cp314t-macosx_11_0_universal2.whl", hash = "sha256:e26e72bec7ab387ac80caa7496e0f908ff954f31065b0ffc1f8ecb1338b11b54"}, - {file = "greenlet-3.3.2-cp314-cp314t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8b466dff7a4ffda6ca975979bab80bdadde979e29fc947ac3be4451428d8b0e4"}, - {file = "greenlet-3.3.2-cp314-cp314t-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:b8bddc5b73c9720bea487b3bffdb1840fe4e3656fba3bd40aa1489e9f37877ff"}, - {file = "greenlet-3.3.2-cp314-cp314t-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:59b3e2c40f6706b05a9cd299c836c6aa2378cabe25d021acd80f13abf81181cf"}, - {file = "greenlet-3.3.2-cp314-cp314t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b26b0f4428b871a751968285a1ac9648944cea09807177ac639b030bddebcea4"}, - {file = "greenlet-3.3.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:1fb39a11ee2e4d94be9a76671482be9398560955c9e568550de0224e41104727"}, - {file = "greenlet-3.3.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:20154044d9085151bc309e7689d6f7ba10027f8f5a8c0676ad398b951913d89e"}, - {file = "greenlet-3.3.2-cp314-cp314t-win_amd64.whl", hash = "sha256:c04c5e06ec3e022cbfe2cd4a846e1d4e50087444f875ff6d2c2ad8445495cf1a"}, - {file = "greenlet-3.3.2.tar.gz", hash = "sha256:2eaf067fc6d886931c7962e8c6bede15d2f01965560f3359b27c80bde2d151f2"}, + {file = "greenlet-3.5.1-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:7eacb17a9d41538a2bc4912eba5ef13823c83cb69e4d141d0813debe7163187f"}, + {file = "greenlet-3.5.1-cp310-cp310-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e5cc9606aa5f4e0bde0d3bd502b44f743864c3ffa5cfa1011b1e30f5aa02366f"}, + {file = "greenlet-3.5.1-cp310-cp310-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c3d35f87c7253b715d13d679e0783d845910144f282cb939fe1ba4ac8616269c"}, + {file = "greenlet-3.5.1-cp310-cp310-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:00929c98ec525fd9bf075875d8c5f6a983a90906cdf78a66e6de2d8e466c2a19"}, + {file = "greenlet-3.5.1-cp310-cp310-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:540dae7b956209af4d70a3be35927b4055f617763771e5e84a5255bea934d2f5"}, + {file = "greenlet-3.5.1-cp310-cp310-manylinux_2_39_riscv64.whl", hash = "sha256:001775efe7b8e758861294c7a27c28af87f3f3f1c20468a2bc618c45b346c061"}, + {file = "greenlet-3.5.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:ed8cdb691169715a9a492844a83246f090182247d1a5031dc78a403f68ba1e97"}, + {file = "greenlet-3.5.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:9d59e840387076a51016777a9328b3f2c427c6f9208a6e958bad251be50a648d"}, + {file = "greenlet-3.5.1-cp310-cp310-win_amd64.whl", hash = "sha256:b9152fca4a6466e114aaec745ae61cba739903a109754a9d4e1262f01e9259b1"}, + {file = "greenlet-3.5.1-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:73f78f9b9f0a5c06e5c946ba1e8e36f5114923b6be109ee618c54f079c3ea14f"}, + {file = "greenlet-3.5.1-cp311-cp311-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a0cbed8bb44e23c5b199f888f4e4ce096b45ad9f25ff74a7ad0213875e936bb2"}, + {file = "greenlet-3.5.1-cp311-cp311-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a203a8bd0acb0701653d3bbb26e404854a68674139ed5cbb778830f42b09bb33"}, + {file = "greenlet-3.5.1-cp311-cp311-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:6ebeb75c81211f5c702576cf81f315e77e23cfdb2c7c6fcb9dd143e6de35c360"}, + {file = "greenlet-3.5.1-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8a271fcd66c74615cda6a964fda3f304267a12e50a084472218a39bb0376f563"}, + {file = "greenlet-3.5.1-cp311-cp311-manylinux_2_39_riscv64.whl", hash = "sha256:017a544f0385d441e88714160d089d6900ef46c9eff9d99b6715a5ef2d127747"}, + {file = "greenlet-3.5.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:ded7b068c7c31c1a8657d4fd42d886b3e051ae29f88b80c5ff9d502257b0f071"}, + {file = "greenlet-3.5.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:d0932b81d72f552ded9d810d00021b64d89f2195a91ce115b893f943b7a4ab3c"}, + {file = "greenlet-3.5.1-cp311-cp311-win_amd64.whl", hash = "sha256:88e300d136eac057b2397aa1cfd7328b4c87c7eb66a09c7bc6a1292234db474e"}, + {file = "greenlet-3.5.1-cp311-cp311-win_arm64.whl", hash = "sha256:cc6ab7e555c8a112ad3a76e368e86e12a2754bcae1652a5602e133ec7b635523"}, + {file = "greenlet-3.5.1-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:fa4f98af3a528f0c3fd592a26df7f376f93329c8f4d987f6bb979057af8bf5e2"}, + {file = "greenlet-3.5.1-cp312-cp312-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ffea73584b216150eab159b6d12348fb253e68757974de1e2c40d8a318ac89ed"}, + {file = "greenlet-3.5.1-cp312-cp312-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:1072b4f9edcc1e192d9283a66a3e68d6b84c561de33a83d7858beb9ba1effe10"}, + {file = "greenlet-3.5.1-cp312-cp312-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:89101bfd5011e069be974903cb3a4e4523845e4ece2d62dcd8d358933c0ef249"}, + {file = "greenlet-3.5.1-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:add5217d68b31130f0beca584d7fef4878327d2e31642b66618a14eef312b63b"}, + {file = "greenlet-3.5.1-cp312-cp312-manylinux_2_39_riscv64.whl", hash = "sha256:e6cd99ea59dd5d89f0c956606571d79bfe6f68c9eb7f4a4083a41a7f1587edee"}, + {file = "greenlet-3.5.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a5ea42a752d47a145eae922b605cd1634665ac3d5ec1e72402d5048e8d60d207"}, + {file = "greenlet-3.5.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:c5551170cf4f5ff5623e9af81323751979fee2c731e2287b61f73cd27257b823"}, + {file = "greenlet-3.5.1-cp312-cp312-win_amd64.whl", hash = "sha256:3c8bb982ad117d29478ef8f5533e97df21f1e2befd17a299257b0c96d1371c0b"}, + {file = "greenlet-3.5.1-cp312-cp312-win_arm64.whl", hash = "sha256:80eb4b04dadc4e67df3fae179a32c4706a3f495bc7f22fc8a81115d5f5512188"}, + {file = "greenlet-3.5.1-cp313-cp313-macosx_11_0_universal2.whl", hash = "sha256:51518ff74664078fc51bffcc6fc529b0df5ae58da192691cee765d45ce944a2b"}, + {file = "greenlet-3.5.1-cp313-cp313-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1ffdb3c0bb002c99cd8f298957e046c3dbf6006b5b7cdf11a4e19194624a0a0a"}, + {file = "greenlet-3.5.1-cp313-cp313-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:7715a5a2c3378ba602c3a440558261e13a820bb53a82693aacd7b7f6d964e283"}, + {file = "greenlet-3.5.1-cp313-cp313-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d40a890035c0058cadbdc4af7569800fd28a0e527a0fdbb7b5f9418f176846ce"}, + {file = "greenlet-3.5.1-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:dc71ff466927a201b08305acac451ebe1aedfcea002f62f1f2f2ac2ac1e6a135"}, + {file = "greenlet-3.5.1-cp313-cp313-manylinux_2_39_riscv64.whl", hash = "sha256:67821bb03e4e98664490edb787ff6af501194c29bbee0f5c1dfdcf1dc3d9d436"}, + {file = "greenlet-3.5.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:cd443683db272ebaaca03af98c0b063ab30db70ea8a31a1559f35e3f7b744ccd"}, + {file = "greenlet-3.5.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:089fff7a6ce8d9316d1f65ebc00273a56be258c1725b32b94de90a3a979557e1"}, + {file = "greenlet-3.5.1-cp313-cp313-win_amd64.whl", hash = "sha256:110a1ca7b49b014b097f6078272c3f4ed31af45b254de5228b79adba879f6af9"}, + {file = "greenlet-3.5.1-cp313-cp313-win_arm64.whl", hash = "sha256:f16ba1efc0715b680a18b8123d90dad887c6112ae3555b4b5c32c149540c6b4e"}, + {file = "greenlet-3.5.1-cp314-cp314-macosx_11_0_universal2.whl", hash = "sha256:d8ab31c9de8651a2facdd5c5bb0011f2380dd1a7af78ce2adf4b56095294fc07"}, + {file = "greenlet-3.5.1-cp314-cp314-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5e300185139abc337ade480c327183adf42a875ac7181bfe66d7d4efea31fbea"}, + {file = "greenlet-3.5.1-cp314-cp314-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:7ffdb990dcaa0234cf9845aead5df2e3c3a8b6507d409274dd87e0d5ab05ffc2"}, + {file = "greenlet-3.5.1-cp314-cp314-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:6c09df69dc1712d131332054a858a3e5cca400967fa3a672e2324fbb0971448c"}, + {file = "greenlet-3.5.1-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2f82b3597e9d83b63408affed0b48fd0f54935edac4302237b9a837be0dae33c"}, + {file = "greenlet-3.5.1-cp314-cp314-manylinux_2_39_riscv64.whl", hash = "sha256:a4764e0bfc6a4d114c865b32520805c16a990ef5f286a514413b05d5ecd6a23d"}, + {file = "greenlet-3.5.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:c0141e37414c10164e702b8fb1473304221ad98f71600850c6ef7ff4880feba0"}, + {file = "greenlet-3.5.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:50ae25a67bea74ea41fb14b960bc532df73eb713417b2d61892dced82fe8d3bc"}, + {file = "greenlet-3.5.1-cp314-cp314-win_amd64.whl", hash = "sha256:8a17c42330e261299766b75ac1ea32caa437a9453c8f65d16a13140db378ecd3"}, + {file = "greenlet-3.5.1-cp314-cp314-win_arm64.whl", hash = "sha256:7b5f5fae05b8ac6d176a61b60c394a8cbdc2b5b91b81793066e68745cf165e54"}, + {file = "greenlet-3.5.1-cp314-cp314t-macosx_11_0_universal2.whl", hash = "sha256:ea8da1e900d758d078810d4255d8c6aa572181896a31ec79d779eb79c3adc9ad"}, + {file = "greenlet-3.5.1-cp314-cp314t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a19570c52a21420dcbc94e661994bc325c0b5b11304540fed514586da5dc8f2e"}, + {file = "greenlet-3.5.1-cp314-cp314t-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:3d955c89b75eeca4723d7cc14135f393cd47c32e2a6cb4a8e4c6e760a26b0986"}, + {file = "greenlet-3.5.1-cp314-cp314t-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:ea37d5a157eb9493820d3792ac4ece28619a394391d2b9f2f78057d396ff0f0f"}, + {file = "greenlet-3.5.1-cp314-cp314t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:de2daaaebd1a5aa88c49045b6baf9310b3263796bd88db713edf37cf53e7bb4e"}, + {file = "greenlet-3.5.1-cp314-cp314t-manylinux_2_39_riscv64.whl", hash = "sha256:8d8a23250ea3ec7b36de8fa4b541e9e2db3ee82915cc060ab0631609ad8b28de"}, + {file = "greenlet-3.5.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:3bfbd69cc349e43bf3a8ae1c85548ff0718efc887615c2db16c3833d7b0b072d"}, + {file = "greenlet-3.5.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:4378720dd888136c27215a0214d32a4d37c3852765d45bc37aad0623423cfd78"}, + {file = "greenlet-3.5.1-cp314-cp314t-win_amd64.whl", hash = "sha256:45718441607f9325d948db98cbc691276059316d0358c188c246da4e1d4d23d2"}, + {file = "greenlet-3.5.1-cp315-cp315-macosx_11_0_universal2.whl", hash = "sha256:2baee5ca02031757ffe8cc3d69f0cc0aec7065ce362622da74f32d3bcab1c541"}, + {file = "greenlet-3.5.1-cp315-cp315-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9b1ec3274918a81d3ea778b9e75b56b72b33f300edb6cf7f3a7fe1dae56683de"}, + {file = "greenlet-3.5.1-cp315-cp315-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:111e2390ffffc47d5840b01711dd7fac07d4c09283d0283e7f3264b14e284c64"}, + {file = "greenlet-3.5.1-cp315-cp315-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:10a9a1c0bfbc93d41156ffcb90c75fbc05544054faf15dcc1fdf9765f8b607f0"}, + {file = "greenlet-3.5.1-cp315-cp315-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e630136e905fe5ff43e86945ae41220b6d1470956a39220e708110ac48d01ea5"}, + {file = "greenlet-3.5.1-cp315-cp315-manylinux_2_39_riscv64.whl", hash = "sha256:ef08c1567c78074b22d1a200183d52d04a14df447bf70bcbb6a3507a48e776fc"}, + {file = "greenlet-3.5.1-cp315-cp315-musllinux_1_2_aarch64.whl", hash = "sha256:975eac34b44a7077ca4d421348455b94f0f518246a7f14bc6d2fdcfe5b584368"}, + {file = "greenlet-3.5.1-cp315-cp315-musllinux_1_2_x86_64.whl", hash = "sha256:9ab3c3a0b2ae6198e67c898dad5215a49f9ae0d0081b3c3ec59f333e39eeca26"}, + {file = "greenlet-3.5.1-cp315-cp315-win_amd64.whl", hash = "sha256:cbfc69be86e10dcfef5b1e6269d1d6926552aa89ee39e1de3353360c1b6989ab"}, + {file = "greenlet-3.5.1-cp315-cp315-win_arm64.whl", hash = "sha256:92fd6d44ac5e5a887c8a5dc4a8ba0ba908527c31c12f78c6bc7dcfe8aab279f6"}, + {file = "greenlet-3.5.1-cp315-cp315t-macosx_11_0_universal2.whl", hash = "sha256:a6fdf2433a5441ef9a95464f7c3e674775da1c8c1177fff311cee1acad4626ed"}, + {file = "greenlet-3.5.1-cp315-cp315t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7546556f0d649f99f6a361098a55f761181bb2ea12ff150bb16d26092ad88244"}, + {file = "greenlet-3.5.1-cp315-cp315t-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:d5ee3ea898009fa898f85f9982255d35278c477bebe185beca249cab42d4526c"}, + {file = "greenlet-3.5.1-cp315-cp315t-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a57b0d05a0448eed231d59c0ceb287dde984551e54cbc51ac2d4865712838e9c"}, + {file = "greenlet-3.5.1-cp315-cp315t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a5c81f74d204d3edd136ebfd50dce53acbb776995d721a0fe801626cfc93b8cd"}, + {file = "greenlet-3.5.1-cp315-cp315t-manylinux_2_39_riscv64.whl", hash = "sha256:b0703c2cef53e01baec47f7a3868009913ad71ec678bbecb42a6f40895e4ce62"}, + {file = "greenlet-3.5.1-cp315-cp315t-musllinux_1_2_aarch64.whl", hash = "sha256:2c18ef16bf6d4dd410e4dd52996888ea1497be26892fe5bbc73580aba4287b8e"}, + {file = "greenlet-3.5.1-cp315-cp315t-musllinux_1_2_x86_64.whl", hash = "sha256:17d86354f0ae6b61bf9be5148d0dd34e06c3cb7c602c671f79f29ac3b150e659"}, + {file = "greenlet-3.5.1-cp315-cp315t-win_amd64.whl", hash = "sha256:e7516cf6ae6b8a582c2770a0caed47b8a48373ed732c33d69a72913ae6ac923e"}, + {file = "greenlet-3.5.1-cp315-cp315t-win_arm64.whl", hash = "sha256:5028648bf2253ec4745add746129d3904121fa7fe871a76bed23c5720573ce0a"}, + {file = "greenlet-3.5.1.tar.gz", hash = "sha256:5a56aeb7d5d9cc4b3a735efb5095bd4b4f6f0e4f93e5ca876d0e2315137b7829"}, ] [package.extras] @@ -159,14 +307,14 @@ test = ["objgraph", "psutil", "setuptools"] [[package]] name = "identify" -version = "2.6.16" +version = "2.6.19" description = "File identification library for Python" optional = false python-versions = ">=3.10" groups = ["dev"] files = [ - {file = "identify-2.6.16-py2.py3-none-any.whl", hash = "sha256:391ee4d77741d994189522896270b787aed8670389bfd60f326d677d64a6dfb0"}, - {file = "identify-2.6.16.tar.gz", hash = "sha256:846857203b5511bbe94d5a352a48ef2359532bc8f6727b5544077a0dcfb24980"}, + {file = "identify-2.6.19-py2.py3-none-any.whl", hash = "sha256:20e6a87f786f768c092a721ad107fc9df0eb89347be9396cadf3f4abbd1fb78a"}, + {file = "identify-2.6.19.tar.gz", hash = "sha256:6be5020c38fcb07da56c53733538a3081ea5aa70d36a156f83044bfbf9173842"}, ] [package.extras] @@ -186,14 +334,14 @@ files = [ [[package]] name = "mako" -version = "1.3.10" +version = "1.3.12" description = "A super-fast templating language that borrows the best ideas from the existing templating languages." optional = false python-versions = ">=3.8" groups = ["dev"] files = [ - {file = "mako-1.3.10-py3-none-any.whl", hash = "sha256:baef24a52fc4fc514a0887ac600f9f1cff3d82c61d4d700a1fa84d597b88db59"}, - {file = "mako-1.3.10.tar.gz", hash = "sha256:99579a6f39583fa7e5630a28c3c1f440e4e97a414b80372649c0ce338da2ea28"}, + {file = "mako-1.3.12-py3-none-any.whl", hash = "sha256:8f61569480282dbf557145ce441e4ba888be453c30989f879f0d652e39f53ea9"}, + {file = "mako-1.3.12.tar.gz", hash = "sha256:9f778e93289bd410bb35daadeb4fc66d95a746f0b75777b942088b7fd7af550a"}, ] [package.dependencies] @@ -317,26 +465,26 @@ files = [ [[package]] name = "packaging" -version = "26.0" +version = "26.2" description = "Core utilities for Python packages" optional = false python-versions = ">=3.8" groups = ["dev"] files = [ - {file = "packaging-26.0-py3-none-any.whl", hash = "sha256:b36f1fef9334a5588b4166f8bcd26a14e521f2b55e6b9de3aaa80d3ff7a37529"}, - {file = "packaging-26.0.tar.gz", hash = "sha256:00243ae351a257117b6a241061796684b084ed1c516a08c48a3f7e147a9d80b4"}, + {file = "packaging-26.2-py3-none-any.whl", hash = "sha256:5fc45236b9446107ff2415ce77c807cee2862cb6fac22b8a73826d0693b0980e"}, + {file = "packaging-26.2.tar.gz", hash = "sha256:ff452ff5a3e828ce110190feff1178bb1f2ea2281fa2075aadb987c2fb221661"}, ] [[package]] name = "platformdirs" -version = "4.9.2" +version = "4.9.6" description = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`." optional = false python-versions = ">=3.10" groups = ["dev"] files = [ - {file = "platformdirs-4.9.2-py3-none-any.whl", hash = "sha256:9170634f126f8efdae22fb58ae8a0eaa86f38365bc57897a6c4f781d1f5875bd"}, - {file = "platformdirs-4.9.2.tar.gz", hash = "sha256:9a33809944b9db043ad67ca0db94b14bf452cc6aeaac46a88ea55b26e2e9d291"}, + {file = "platformdirs-4.9.6-py3-none-any.whl", hash = "sha256:e61adb1d5e5cb3441b4b7710bea7e4c12250ca49439228cc1021c00dcfac0917"}, + {file = "platformdirs-4.9.6.tar.gz", hash = "sha256:3bfa75b0ad0db84096ae777218481852c0ebc6c727b3168c1b9e0118e458cf0a"}, ] [[package]] @@ -357,14 +505,14 @@ testing = ["coverage", "pytest", "pytest-benchmark"] [[package]] name = "pre-commit" -version = "4.5.1" +version = "4.6.0" description = "A framework for managing and maintaining multi-language pre-commit hooks." optional = false python-versions = ">=3.10" groups = ["dev"] files = [ - {file = "pre_commit-4.5.1-py2.py3-none-any.whl", hash = "sha256:3b3afd891e97337708c1674210f8eba659b52a38ea5f822ff142d10786221f77"}, - {file = "pre_commit-4.5.1.tar.gz", hash = "sha256:eb545fcff725875197837263e977ea257a402056661f09dae08e4b149b030a61"}, + {file = "pre_commit-4.6.0-py2.py3-none-any.whl", hash = "sha256:e2cf246f7299edcabcf15f9b0571fdce06058527f0a06535068a86d38089f29b"}, + {file = "pre_commit-4.6.0.tar.gz", hash = "sha256:718d2208cef53fdc38206e40524a6d4d9576d103eb16f0fec11c875e7716e9d9"}, ] [package.dependencies] @@ -376,14 +524,14 @@ virtualenv = ">=20.10.0" [[package]] name = "pygments" -version = "2.19.2" +version = "2.20.0" description = "Pygments is a syntax highlighting package written in Python." optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" groups = ["dev"] files = [ - {file = "pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b"}, - {file = "pygments-2.19.2.tar.gz", hash = "sha256:636cb2477cec7f8952536970bc533bc43743542f70392ae026374600add5b887"}, + {file = "pygments-2.20.0-py3-none-any.whl", hash = "sha256:81a9e26dd42fd28a23a2d169d86d7ac03b46e2f8b59ed4698fb4785f946d0176"}, + {file = "pygments-2.20.0.tar.gz", hash = "sha256:6757cd03768053ff99f3039c1a36d6c0aa0b263438fcab17520b30a303a82b5f"}, ] [package.extras] @@ -391,33 +539,34 @@ windows-terminal = ["colorama (>=0.4.6)"] [[package]] name = "pyrefly" -version = "0.54.0" +version = "1.0.0" description = "A fast type checker and language server for Python with powerful IDE features" optional = false python-versions = ">=3.8" groups = ["dev"] files = [ - {file = "pyrefly-0.54.0-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:58a3f092b6dc25ef79b2dc6c69a40f36784ca157c312bfc0baea463926a9db6d"}, - {file = "pyrefly-0.54.0-py3-none-macosx_11_0_arm64.whl", hash = "sha256:615081414106dd95873bc39c3a4bed68754c6cc24a8177ac51d22f88f88d3eb3"}, - {file = "pyrefly-0.54.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0cbcaf20f5fe585079079a95205c1f3cd4542d17228cdf1df560288880623b70"}, - {file = "pyrefly-0.54.0-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:66d5da116c0d34acfbd66663addd3ca8aa78a636f6692a66e078126d3620a883"}, - {file = "pyrefly-0.54.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6ef3ac27f1a4baaf67aead64287d3163350844794aca6315ad1a9650b16ec26a"}, - {file = "pyrefly-0.54.0-py3-none-win32.whl", hash = "sha256:7d607d72200a8afbd2db10bfefb40160a7a5d709d207161c21649cedd5cfc09a"}, - {file = "pyrefly-0.54.0-py3-none-win_amd64.whl", hash = "sha256:fd416f04f89309385696f685bd5c9141011f18c8072f84d31ca20c748546e791"}, - {file = "pyrefly-0.54.0-py3-none-win_arm64.whl", hash = "sha256:f06ab371356c7b1925e0bffe193b738797e71e5dbbff7fb5a13f90ee7521211d"}, - {file = "pyrefly-0.54.0.tar.gz", hash = "sha256:c6663be64d492f0d2f2a411ada9f28a6792163d34133639378b7f3dd9a8dca94"}, + {file = "pyrefly-1.0.0-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:e355a0908555348ed4b9585ef25c76ff566673e345c866c325f1633f44d890b6"}, + {file = "pyrefly-1.0.0-py3-none-macosx_11_0_arm64.whl", hash = "sha256:a7038efc3a40f8294edee339895633cf22db268c0d434cdbcbefc34f78a9ecc3"}, + {file = "pyrefly-1.0.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da331ca515ed1c08791da2b5f664cf9c1294c48fd802133262e7d5d51e0f4416"}, + {file = "pyrefly-1.0.0-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c74219d8f3e63cdaa5501a0b21d1c9d37011820f9606728d0ed06f09ae86a878"}, + {file = "pyrefly-1.0.0-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c0d05543b1bb6ee6d64149eb5d6b2fb15aa72d3962d6a97abca0afaca8b0c131"}, + {file = "pyrefly-1.0.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1382d5b1fcdb49a4de9f34d112d2bddf290a78ff93ee8149492ad5f1077ddffc"}, + {file = "pyrefly-1.0.0-py3-none-win32.whl", hash = "sha256:aa8b5d0e47080e3202a2547b39f7a5a61d2c781c712b3b67884f745ca2c759d2"}, + {file = "pyrefly-1.0.0-py3-none-win_amd64.whl", hash = "sha256:c8abcb0f2082e83c890375128f9cff4aa4d3f210b85eea7b3046c1ae764e77f5"}, + {file = "pyrefly-1.0.0-py3-none-win_arm64.whl", hash = "sha256:d150fa9e40e8392832be81c3bcfc0497c146674ce4d0f8e04e1ec29e775ffb8c"}, + {file = "pyrefly-1.0.0.tar.gz", hash = "sha256:5c2b810ffcebd84be71de5df1223651edee951653a66935c6f091e957c452455"}, ] [[package]] name = "pytest" -version = "9.0.2" +version = "9.0.3" description = "pytest: simple powerful testing with Python" optional = false python-versions = ">=3.10" groups = ["dev"] files = [ - {file = "pytest-9.0.2-py3-none-any.whl", hash = "sha256:711ffd45bf766d5264d487b917733b453d917afd2b0ad65223959f59089f875b"}, - {file = "pytest-9.0.2.tar.gz", hash = "sha256:75186651a92bd89611d1d9fc20f0b4345fd827c41ccd5c299a868a05d70edf11"}, + {file = "pytest-9.0.3-py3-none-any.whl", hash = "sha256:2c5efc453d45394fdd706ade797c0a81091eccd1d6e4bccfcd476e2b8e0ab5d9"}, + {file = "pytest-9.0.3.tar.gz", hash = "sha256:b86ada508af81d19edeb213c681b1d48246c1a91d304c6c81a427674c17eb91c"}, ] [package.dependencies] @@ -432,6 +581,46 @@ tomli = {version = ">=1", markers = "python_version < \"3.11\""} [package.extras] dev = ["argcomplete", "attrs (>=19.2)", "hypothesis (>=3.56)", "mock", "requests", "setuptools", "xmlschema"] +[[package]] +name = "pytest-cov" +version = "7.1.0" +description = "Pytest plugin for measuring coverage." +optional = false +python-versions = ">=3.9" +groups = ["dev"] +files = [ + {file = "pytest_cov-7.1.0-py3-none-any.whl", hash = "sha256:a0461110b7865f9a271aa1b51e516c9a95de9d696734a2f71e3e78f46e1d4678"}, + {file = "pytest_cov-7.1.0.tar.gz", hash = "sha256:30674f2b5f6351aa09702a9c8c364f6a01c27aae0c1366ae8016160d1efc56b2"}, +] + +[package.dependencies] +coverage = {version = ">=7.10.6", extras = ["toml"]} +pluggy = ">=1.2" +pytest = ">=7" + +[package.extras] +testing = ["process-tests", "pytest-xdist", "virtualenv"] + +[[package]] +name = "python-discovery" +version = "1.3.1" +description = "Python interpreter discovery" +optional = false +python-versions = ">=3.8" +groups = ["dev"] +files = [ + {file = "python_discovery-1.3.1-py3-none-any.whl", hash = "sha256:ed188687ebb3b82c01a17cd5ac62fc94d9f6487a7f1a0f9dfe89753fec91039c"}, + {file = "python_discovery-1.3.1.tar.gz", hash = "sha256:62f6db28064c9613e7ca76cb3f00c38c839a07c31c00dfe7ed0986493d2150a6"}, +] + +[package.dependencies] +filelock = ">=3.15.4" +platformdirs = ">=4.3.6,<5" + +[package.extras] +docs = ["furo (>=2025.12.19)", "sphinx (>=9.1)", "sphinx-autodoc-typehints (>=3.6.3)", "sphinxcontrib-mermaid (>=2)", "sphinxcontrib-towncrier (>=0.4)", "towncrier (>=25.8)"] +testing = ["covdefaults (>=2.3)", "coverage (>=7.5.4)", "pytest (>=8.3.5)", "pytest-mock (>=3.14)", "setuptools (>=75.1)"] + [[package]] name = "pyyaml" version = "6.0.3" @@ -517,99 +706,103 @@ files = [ [[package]] name = "ruff" -version = "0.15.2" +version = "0.15.14" description = "An extremely fast Python linter and code formatter, written in Rust." optional = false python-versions = ">=3.7" groups = ["dev"] files = [ - {file = "ruff-0.15.2-py3-none-linux_armv6l.whl", hash = "sha256:120691a6fdae2f16d65435648160f5b81a9625288f75544dc40637436b5d3c0d"}, - {file = "ruff-0.15.2-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:a89056d831256099658b6bba4037ac6dd06f49d194199215befe2bb10457ea5e"}, - {file = "ruff-0.15.2-py3-none-macosx_11_0_arm64.whl", hash = "sha256:e36dee3a64be0ebd23c86ffa3aa3fd3ac9a712ff295e192243f814a830b6bd87"}, - {file = "ruff-0.15.2-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a9fb47b6d9764677f8c0a193c0943ce9a05d6763523f132325af8a858eadc2b9"}, - {file = "ruff-0.15.2-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f376990f9d0d6442ea9014b19621d8f2aaf2b8e39fdbfc79220b7f0c596c9b80"}, - {file = "ruff-0.15.2-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2dcc987551952d73cbf5c88d9fdee815618d497e4df86cd4c4824cc59d5dd75f"}, - {file = "ruff-0.15.2-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:42a47fd785cbe8c01b9ff45031af875d101b040ad8f4de7bbb716487c74c9a77"}, - {file = "ruff-0.15.2-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cbe9f49354866e575b4c6943856989f966421870e85cd2ac94dccb0a9dcb2fea"}, - {file = "ruff-0.15.2-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b7a672c82b5f9887576087d97be5ce439f04bbaf548ee987b92d3a7dede41d3a"}, - {file = "ruff-0.15.2-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:72ecc64f46f7019e2bcc3cdc05d4a7da958b629a5ab7033195e11a438403d956"}, - {file = "ruff-0.15.2-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:8dcf243b15b561c655c1ef2f2b0050e5d50db37fe90115507f6ff37d865dc8b4"}, - {file = "ruff-0.15.2-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:dab6941c862c05739774677c6273166d2510d254dac0695c0e3f5efa1b5585de"}, - {file = "ruff-0.15.2-py3-none-musllinux_1_2_i686.whl", hash = "sha256:1b9164f57fc36058e9a6806eb92af185b0697c9fe4c7c52caa431c6554521e5c"}, - {file = "ruff-0.15.2-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:80d24fcae24d42659db7e335b9e1531697a7102c19185b8dc4a028b952865fd8"}, - {file = "ruff-0.15.2-py3-none-win32.whl", hash = "sha256:fd5ff9e5f519a7e1bd99cbe8daa324010a74f5e2ebc97c6242c08f26f3714f6f"}, - {file = "ruff-0.15.2-py3-none-win_amd64.whl", hash = "sha256:d20014e3dfa400f3ff84830dfb5755ece2de45ab62ecea4af6b7262d0fb4f7c5"}, - {file = "ruff-0.15.2-py3-none-win_arm64.whl", hash = "sha256:cabddc5822acdc8f7b5527b36ceac55cc51eec7b1946e60181de8fe83ca8876e"}, - {file = "ruff-0.15.2.tar.gz", hash = "sha256:14b965afee0969e68bb871eba625343b8673375f457af4abe98553e8bbb98342"}, + {file = "ruff-0.15.14-py3-none-linux_armv6l.whl", hash = "sha256:8dd2db9416e487c8d4b01fa7056bb02c4d05969d4f8d17a08c229c2f4ff3c108"}, + {file = "ruff-0.15.14-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:be4ff55af755bd71a00ab3dc6bd7ffc467bd76e0df6881e286c2e3d23e8fb43b"}, + {file = "ruff-0.15.14-py3-none-macosx_11_0_arm64.whl", hash = "sha256:48d5909d7d06276ce7dde6d32bfa4b0d4cb2651145cd8ee4b440722cbc77832f"}, + {file = "ruff-0.15.14-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ca8cbfa94c4f90984a67561978602746d4cd27103568f745fa90eee3f0d4107d"}, + {file = "ruff-0.15.14-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9a6bbc0333f1ab053423bcbf6226477d266ca7cec7738c4c8e3f55647803f3c4"}, + {file = "ruff-0.15.14-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8a24a4f7605d7003a6674d4387651effd939dead3fddd0f36561eb77a9a2e542"}, + {file = "ruff-0.15.14-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:049b5326e53ed80978f2fc041a280603f69dd6b0c95464342a2bb4572d9d9e2f"}, + {file = "ruff-0.15.14-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d4ed42e6696c8dfa5f06728e6441993901f548eb92d73bc472cb5a38d1395fbf"}, + {file = "ruff-0.15.14-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:715c543cf450c4888251f91c52f1942a800541d9bddd7ac060aa4e6b77ae7cba"}, + {file = "ruff-0.15.14-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:72ebab6013ec887d439d8b7593737a0a4ffb06d45d209d4e4bf2e92813082d3f"}, + {file = "ruff-0.15.14-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:49072d36abdbe97a8dd7f480afe9c675699c0c495d4c84076e2c1203c4550581"}, + {file = "ruff-0.15.14-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:958522aee105068640c2c2ceae08f413ae44d922f52a1374ac13d6a96032fc93"}, + {file = "ruff-0.15.14-py3-none-musllinux_1_2_i686.whl", hash = "sha256:f3707da619a143a2e8830e2abab8224478d69ace2d28cb6c20543ae97c36bf61"}, + {file = "ruff-0.15.14-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:bb01d645694e3ec0102105d07ef2d53703970407d59c04e59d3ba0b7a1d53553"}, + {file = "ruff-0.15.14-py3-none-win32.whl", hash = "sha256:6d0c1ad2a0ab718d39b6d8fd2217981ce4d625cd96a720095f798fb47d8b13e6"}, + {file = "ruff-0.15.14-py3-none-win_amd64.whl", hash = "sha256:802342981e056db3851a7836e5b070f8f15f67d4a685ae2a6160939d364b2902"}, + {file = "ruff-0.15.14-py3-none-win_arm64.whl", hash = "sha256:ff47b90a9ef6a40c9e2f3b479c1fb78531adf055b94c1eba0a7ba04b31951826"}, + {file = "ruff-0.15.14.tar.gz", hash = "sha256:48e866b165be4a9bdbf310f7d3c9a07edef2fe8cd63ffeb4e00bb590506ebf9f"}, ] [[package]] name = "sqlalchemy" -version = "2.0.46" +version = "2.0.49" description = "Database Abstraction Library" optional = false python-versions = ">=3.7" groups = ["dev"] files = [ - {file = "sqlalchemy-2.0.46-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:895296687ad06dc9b11a024cf68e8d9d3943aa0b4964278d2553b86f1b267735"}, - {file = "sqlalchemy-2.0.46-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ab65cb2885a9f80f979b85aa4e9c9165a31381ca322cbde7c638fe6eefd1ec39"}, - {file = "sqlalchemy-2.0.46-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:52fe29b3817bd191cc20bad564237c808967972c97fa683c04b28ec8979ae36f"}, - {file = "sqlalchemy-2.0.46-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:09168817d6c19954d3b7655da6ba87fcb3a62bb575fb396a81a8b6a9fadfe8b5"}, - {file = "sqlalchemy-2.0.46-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:be6c0466b4c25b44c5d82b0426b5501de3c424d7a3220e86cd32f319ba56798e"}, - {file = "sqlalchemy-2.0.46-cp310-cp310-win32.whl", hash = "sha256:1bc3f601f0a818d27bfe139f6766487d9c88502062a2cd3a7ee6c342e81d5047"}, - {file = "sqlalchemy-2.0.46-cp310-cp310-win_amd64.whl", hash = "sha256:e0c05aff5c6b1bb5fb46a87e0f9d2f733f83ef6cbbbcd5c642b6c01678268061"}, - {file = "sqlalchemy-2.0.46-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:261c4b1f101b4a411154f1da2b76497d73abbfc42740029205d4d01fa1052684"}, - {file = "sqlalchemy-2.0.46-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:181903fe8c1b9082995325f1b2e84ac078b1189e2819380c2303a5f90e114a62"}, - {file = "sqlalchemy-2.0.46-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:590be24e20e2424a4c3c1b0835e9405fa3d0af5823a1a9fc02e5dff56471515f"}, - {file = "sqlalchemy-2.0.46-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:7568fe771f974abadce52669ef3a03150ff03186d8eb82613bc8adc435a03f01"}, - {file = "sqlalchemy-2.0.46-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ebf7e1e78af38047e08836d33502c7a278915698b7c2145d045f780201679999"}, - {file = "sqlalchemy-2.0.46-cp311-cp311-win32.whl", hash = "sha256:9d80ea2ac519c364a7286e8d765d6cd08648f5b21ca855a8017d9871f075542d"}, - {file = "sqlalchemy-2.0.46-cp311-cp311-win_amd64.whl", hash = "sha256:585af6afe518732d9ccd3aea33af2edaae4a7aa881af5d8f6f4fe3a368699597"}, - {file = "sqlalchemy-2.0.46-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:3a9a72b0da8387f15d5810f1facca8f879de9b85af8c645138cba61ea147968c"}, - {file = "sqlalchemy-2.0.46-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2347c3f0efc4de367ba00218e0ae5c4ba2306e47216ef80d6e31761ac97cb0b9"}, - {file = "sqlalchemy-2.0.46-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9094c8b3197db12aa6f05c51c05daaad0a92b8c9af5388569847b03b1007fb1b"}, - {file = "sqlalchemy-2.0.46-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:37fee2164cf21417478b6a906adc1a91d69ae9aba8f9533e67ce882f4bb1de53"}, - {file = "sqlalchemy-2.0.46-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b1e14b2f6965a685c7128bd315e27387205429c2e339eeec55cb75ca4ab0ea2e"}, - {file = "sqlalchemy-2.0.46-cp312-cp312-win32.whl", hash = "sha256:412f26bb4ba942d52016edc8d12fb15d91d3cd46b0047ba46e424213ad407bcb"}, - {file = "sqlalchemy-2.0.46-cp312-cp312-win_amd64.whl", hash = "sha256:ea3cd46b6713a10216323cda3333514944e510aa691c945334713fca6b5279ff"}, - {file = "sqlalchemy-2.0.46-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:93a12da97cca70cea10d4b4fc602589c4511f96c1f8f6c11817620c021d21d00"}, - {file = "sqlalchemy-2.0.46-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:af865c18752d416798dae13f83f38927c52f085c52e2f32b8ab0fef46fdd02c2"}, - {file = "sqlalchemy-2.0.46-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8d679b5f318423eacb61f933a9a0f75535bfca7056daeadbf6bd5bcee6183aee"}, - {file = "sqlalchemy-2.0.46-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:64901e08c33462acc9ec3bad27fc7a5c2b6491665f2aa57564e57a4f5d7c52ad"}, - {file = "sqlalchemy-2.0.46-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e8ac45e8f4eaac0f9f8043ea0e224158855c6a4329fd4ee37c45c61e3beb518e"}, - {file = "sqlalchemy-2.0.46-cp313-cp313-win32.whl", hash = "sha256:8d3b44b3d0ab2f1319d71d9863d76eeb46766f8cf9e921ac293511804d39813f"}, - {file = "sqlalchemy-2.0.46-cp313-cp313-win_amd64.whl", hash = "sha256:77f8071d8fbcbb2dd11b7fd40dedd04e8ebe2eb80497916efedba844298065ef"}, - {file = "sqlalchemy-2.0.46-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a1e8cc6cc01da346dc92d9509a63033b9b1bda4fed7a7a7807ed385c7dccdc10"}, - {file = "sqlalchemy-2.0.46-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:96c7cca1a4babaaf3bfff3e4e606e38578856917e52f0384635a95b226c87764"}, - {file = "sqlalchemy-2.0.46-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:b2a9f9aee38039cf4755891a1e50e1effcc42ea6ba053743f452c372c3152b1b"}, - {file = "sqlalchemy-2.0.46-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:db23b1bf8cfe1f7fda19018e7207b20cdb5168f83c437ff7e95d19e39289c447"}, - {file = "sqlalchemy-2.0.46-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:56bdd261bfd0895452006d5316cbf35739c53b9bb71a170a331fa0ea560b2ada"}, - {file = "sqlalchemy-2.0.46-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:33e462154edb9493f6c3ad2125931e273bbd0be8ae53f3ecd1c161ea9a1dd366"}, - {file = "sqlalchemy-2.0.46-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9bcdce05f056622a632f1d44bb47dbdb677f58cad393612280406ce37530eb6d"}, - {file = "sqlalchemy-2.0.46-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:8e84b09a9b0f19accedcbeff5c2caf36e0dd537341a33aad8d680336152dc34e"}, - {file = "sqlalchemy-2.0.46-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:4f52f7291a92381e9b4de9050b0a65ce5d6a763333406861e33906b8aa4906bf"}, - {file = "sqlalchemy-2.0.46-cp314-cp314-win32.whl", hash = "sha256:70ed2830b169a9960193f4d4322d22be5c0925357d82cbf485b3369893350908"}, - {file = "sqlalchemy-2.0.46-cp314-cp314-win_amd64.whl", hash = "sha256:3c32e993bc57be6d177f7d5d31edb93f30726d798ad86ff9066d75d9bf2e0b6b"}, - {file = "sqlalchemy-2.0.46-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4dafb537740eef640c4d6a7c254611dca2df87eaf6d14d6a5fca9d1f4c3fc0fa"}, - {file = "sqlalchemy-2.0.46-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:42a1643dc5427b69aca967dae540a90b0fbf57eaf248f13a90ea5930e0966863"}, - {file = "sqlalchemy-2.0.46-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:ff33c6e6ad006bbc0f34f5faf941cfc62c45841c64c0a058ac38c799f15b5ede"}, - {file = "sqlalchemy-2.0.46-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:82ec52100ec1e6ec671563bbd02d7c7c8d0b9e71a0723c72f22ecf52d1755330"}, - {file = "sqlalchemy-2.0.46-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:6ac245604295b521de49b465bab845e3afe6916bcb2147e5929c8041b4ec0545"}, - {file = "sqlalchemy-2.0.46-cp38-cp38-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1e6199143d51e3e1168bedd98cc698397404a8f7508831b81b6a29b18b051069"}, - {file = "sqlalchemy-2.0.46-cp38-cp38-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:716be5bcabf327b6d5d265dbdc6213a01199be587224eb991ad0d37e83d728fd"}, - {file = "sqlalchemy-2.0.46-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:6f827fd687fa1ba7f51699e1132129eac8db8003695513fcf13fc587e1bd47a5"}, - {file = "sqlalchemy-2.0.46-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:c805fa6e5d461329fa02f53f88c914d189ea771b6821083937e79550bf31fc19"}, - {file = "sqlalchemy-2.0.46-cp38-cp38-win32.whl", hash = "sha256:3aac08f7546179889c62b53b18ebf1148b10244b3405569c93984b0388d016a7"}, - {file = "sqlalchemy-2.0.46-cp38-cp38-win_amd64.whl", hash = "sha256:0cc3117db526cad3e61074100bd2867b533e2c7dc1569e95c14089735d6fb4fe"}, - {file = "sqlalchemy-2.0.46-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:90bde6c6b1827565a95fde597da001212ab436f1b2e0c2dcc7246e14db26e2a3"}, - {file = "sqlalchemy-2.0.46-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:94b1e5f3a5f1ff4f42d5daab047428cd45a3380e51e191360a35cef71c9a7a2a"}, - {file = "sqlalchemy-2.0.46-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:93bb0aae40b52c57fd74ef9c6933c08c040ba98daf23ad33c3f9893494b8d3ce"}, - {file = "sqlalchemy-2.0.46-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:c4e2cc868b7b5208aec6c960950b7bb821f82c2fe66446c92ee0a571765e91a5"}, - {file = "sqlalchemy-2.0.46-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:965c62be8256d10c11f8907e7a8d3e18127a4c527a5919d85fa87fd9ecc2cfdc"}, - {file = "sqlalchemy-2.0.46-cp39-cp39-win32.whl", hash = "sha256:9397b381dcee8a2d6b99447ae85ea2530dcac82ca494d1db877087a13e38926d"}, - {file = "sqlalchemy-2.0.46-cp39-cp39-win_amd64.whl", hash = "sha256:4396c948d8217e83e2c202fbdcc0389cf8c93d2c1c5e60fa5c5a955eae0e64be"}, - {file = "sqlalchemy-2.0.46-py3-none-any.whl", hash = "sha256:f9c11766e7e7c0a2767dda5acb006a118640c9fc0a4104214b96269bfb78399e"}, - {file = "sqlalchemy-2.0.46.tar.gz", hash = "sha256:cf36851ee7219c170bb0793dbc3da3e80c582e04a5437bc601bfe8c85c9216d7"}, + {file = "sqlalchemy-2.0.49-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:42e8804962f9e6f4be2cbaedc0c3718f08f60a16910fa3d86da5a1e3b1bfe60f"}, + {file = "sqlalchemy-2.0.49-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:cc992c6ed024c8c3c592c5fc9846a03dd68a425674900c70122c77ea16c5fb0b"}, + {file = "sqlalchemy-2.0.49-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6eb188b84269f357669b62cb576b5b918de10fb7c728a005fa0ebb0b758adce1"}, + {file = "sqlalchemy-2.0.49-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:62557958002b69699bdb7f5137c6714ca1133f045f97b3903964f47db97ea339"}, + {file = "sqlalchemy-2.0.49-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:da9b91bca419dc9b9267ffadde24eae9b1a6bffcd09d0a207e5e3af99a03ce0d"}, + {file = "sqlalchemy-2.0.49-cp310-cp310-win32.whl", hash = "sha256:5e61abbec255be7b122aa461021daa7c3f310f3e743411a67079f9b3cc91ece3"}, + {file = "sqlalchemy-2.0.49-cp310-cp310-win_amd64.whl", hash = "sha256:0c98c59075b890df8abfcc6ad632879540f5791c68baebacb4f833713b510e75"}, + {file = "sqlalchemy-2.0.49-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c5070135e1b7409c4161133aa525419b0062088ed77c92b1da95366ec5cbebbe"}, + {file = "sqlalchemy-2.0.49-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9ac7a3e245fd0310fd31495eb61af772e637bdf7d88ee81e7f10a3f271bff014"}, + {file = "sqlalchemy-2.0.49-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4d4e5a0ceba319942fa6b585cf82539288a61e314ef006c1209f734551ab9536"}, + {file = "sqlalchemy-2.0.49-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:3ddcb27fb39171de36e207600116ac9dfd4ae46f86c82a9bf3934043e80ebb88"}, + {file = "sqlalchemy-2.0.49-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:32fe6a41ad97302db2931f05bb91abbcc65b5ce4c675cd44b972428dd2947700"}, + {file = "sqlalchemy-2.0.49-cp311-cp311-win32.whl", hash = "sha256:46d51518d53edfbe0563662c96954dc8fcace9832332b914375f45a99b77cc9a"}, + {file = "sqlalchemy-2.0.49-cp311-cp311-win_amd64.whl", hash = "sha256:951d4a210744813be63019f3df343bf233b7432aadf0db54c75802247330d3af"}, + {file = "sqlalchemy-2.0.49-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4bbccb45260e4ff1b7db0be80a9025bb1e6698bdb808b83fff0000f7a90b2c0b"}, + {file = "sqlalchemy-2.0.49-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:fb37f15714ec2652d574f021d479e78cd4eb9d04396dca36568fdfffb3487982"}, + {file = "sqlalchemy-2.0.49-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3bb9ec6436a820a4c006aad1ac351f12de2f2dbdaad171692ee457a02429b672"}, + {file = "sqlalchemy-2.0.49-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8d6efc136f44a7e8bc8088507eaabbb8c2b55b3dbb63fe102c690da0ddebe55e"}, + {file = "sqlalchemy-2.0.49-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e06e617e3d4fd9e51d385dfe45b077a41e9d1b033a7702551e3278ac597dc750"}, + {file = "sqlalchemy-2.0.49-cp312-cp312-win32.whl", hash = "sha256:83101a6930332b87653886c01d1ee7e294b1fe46a07dd9a2d2b4f91bcc88eec0"}, + {file = "sqlalchemy-2.0.49-cp312-cp312-win_amd64.whl", hash = "sha256:618a308215b6cececb6240b9abde545e3acdabac7ae3e1d4e666896bf5ba44b4"}, + {file = "sqlalchemy-2.0.49-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:df2d441bacf97022e81ad047e1597552eb3f83ca8a8f1a1fdd43cd7fe3898120"}, + {file = "sqlalchemy-2.0.49-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8e20e511dc15265fb433571391ba313e10dd8ea7e509d51686a51313b4ac01a2"}, + {file = "sqlalchemy-2.0.49-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:47604cb2159f8bbd5a1ab48a714557156320f20871ee64d550d8bf2683d980d3"}, + {file = "sqlalchemy-2.0.49-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:22d8798819f86720bc646ab015baff5ea4c971d68121cb36e2ebc2ee43ead2b7"}, + {file = "sqlalchemy-2.0.49-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9b1c058c171b739e7c330760044803099c7fff11511e3ab3573e5327116a9c33"}, + {file = "sqlalchemy-2.0.49-cp313-cp313-win32.whl", hash = "sha256:a143af2ea6672f2af3f44ed8f9cd020e9cc34c56f0e8db12019d5d9ecf41cb3b"}, + {file = "sqlalchemy-2.0.49-cp313-cp313-win_amd64.whl", hash = "sha256:12b04d1db2663b421fe072d638a138460a51d5a862403295671c4f3987fb9148"}, + {file = "sqlalchemy-2.0.49-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:24bd94bb301ec672d8f0623eba9226cc90d775d25a0c92b5f8e4965d7f3a1518"}, + {file = "sqlalchemy-2.0.49-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a51d3db74ba489266ef55c7a4534eb0b8db9a326553df481c11e5d7660c8364d"}, + {file = "sqlalchemy-2.0.49-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:55250fe61d6ebfd6934a272ee16ef1244e0f16b7af6cd18ab5b1fc9f08631db0"}, + {file = "sqlalchemy-2.0.49-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:46796877b47034b559a593d7e4b549aba151dae73f9e78212a3478161c12ab08"}, + {file = "sqlalchemy-2.0.49-cp313-cp313t-win32.whl", hash = "sha256:9c4969a86e41454f2858256c39bdfb966a20961e9b58bf8749b65abf447e9a8d"}, + {file = "sqlalchemy-2.0.49-cp313-cp313t-win_amd64.whl", hash = "sha256:b9870d15ef00e4d0559ae10ee5bc71b654d1f20076dbe8bc7ed19b4c0625ceba"}, + {file = "sqlalchemy-2.0.49-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:233088b4b99ebcbc5258c755a097aa52fbf90727a03a5a80781c4b9c54347a2e"}, + {file = "sqlalchemy-2.0.49-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:57ca426a48eb2c682dae8204cd89ea8ab7031e2675120a47924fabc7caacbc2a"}, + {file = "sqlalchemy-2.0.49-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:685e93e9c8f399b0c96a624799820176312f5ceef958c0f88215af4013d29066"}, + {file = "sqlalchemy-2.0.49-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:9e0400fa22f79acc334d9a6b185dc00a44a8e6578aa7e12d0ddcd8434152b187"}, + {file = "sqlalchemy-2.0.49-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:a05977bffe9bffd2229f477fa75eabe3192b1b05f408961d1bebff8d1cd4d401"}, + {file = "sqlalchemy-2.0.49-cp314-cp314-win32.whl", hash = "sha256:0f2fa354ba106eafff2c14b0cc51f22801d1e8b2e4149342023bd6f0955de5f5"}, + {file = "sqlalchemy-2.0.49-cp314-cp314-win_amd64.whl", hash = "sha256:77641d299179c37b89cf2343ca9972c88bb6eef0d5fc504a2f86afd15cd5adf5"}, + {file = "sqlalchemy-2.0.49-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c1dc3368794d522f43914e03312202523cc89692f5389c32bea0233924f8d977"}, + {file = "sqlalchemy-2.0.49-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7c821c47ecfe05cc32140dcf8dc6fd5d21971c86dbd56eabfe5ba07a64910c01"}, + {file = "sqlalchemy-2.0.49-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:9c04bff9a5335eb95c6ecf1c117576a0aa560def274876fd156cfe5510fccc61"}, + {file = "sqlalchemy-2.0.49-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:7f605a456948c35260e7b2a39f8952a26f077fd25653c37740ed186b90aaa68a"}, + {file = "sqlalchemy-2.0.49-cp314-cp314t-win32.whl", hash = "sha256:6270d717b11c5476b0cbb21eedc8d4dbb7d1a956fd6c15a23e96f197a6193158"}, + {file = "sqlalchemy-2.0.49-cp314-cp314t-win_amd64.whl", hash = "sha256:275424295f4256fd301744b8f335cff367825d270f155d522b30c7bf49903ee7"}, + {file = "sqlalchemy-2.0.49-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:8a97ac839c2c6672c4865e48f3cbad7152cee85f4233fb4ca6291d775b9b954a"}, + {file = "sqlalchemy-2.0.49-cp38-cp38-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c338ec6ec01c0bc8e735c58b9f5d51e75bacb6ff23296658826d7cfdfdb8678a"}, + {file = "sqlalchemy-2.0.49-cp38-cp38-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:566df36fd0e901625523a5a1835032f1ebdd7f7886c54584143fa6c668b4df3b"}, + {file = "sqlalchemy-2.0.49-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:d99945830a6f3e9638d89a28ed130b1eb24c91255e4f24366fbe699b983f29e4"}, + {file = "sqlalchemy-2.0.49-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:01146546d84185f12721a1d2ce0c6673451a7894d1460b592d378ca4871a0c72"}, + {file = "sqlalchemy-2.0.49-cp38-cp38-win32.whl", hash = "sha256:69469ce8ce7a8df4d37620e3163b71238719e1e2e5048d114a1b6ce0fbf8c662"}, + {file = "sqlalchemy-2.0.49-cp38-cp38-win_amd64.whl", hash = "sha256:b95b2f470c1b2683febd2e7eab1d3f0e078c91dbdd0b00e9c645d07a413bb99f"}, + {file = "sqlalchemy-2.0.49-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:43d044780732d9e0381ac8d5316f95d7f02ef04d6e4ef6dc82379f09795d993f"}, + {file = "sqlalchemy-2.0.49-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7d6be30b2a75362325176c036d7fb8d19e8846c77e87683ffaa8177b35135613"}, + {file = "sqlalchemy-2.0.49-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d898cc2c76c135ef65517f4ddd7a3512fb41f23087b0650efb3418b8389a3cd1"}, + {file = "sqlalchemy-2.0.49-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:059d7151fff513c53a4638da8778be7fce81a0c4854c7348ebd0c4078ddf28fe"}, + {file = "sqlalchemy-2.0.49-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:334edbcff10514ad1d66e3a70b339c0a29886394892490119dbb669627b17717"}, + {file = "sqlalchemy-2.0.49-cp39-cp39-win32.whl", hash = "sha256:74ab4ee7794d7ed1b0c37e7333640e0f0a626fc7b398c07a7aef52f484fddde3"}, + {file = "sqlalchemy-2.0.49-cp39-cp39-win_amd64.whl", hash = "sha256:88690f4e1f0fbf5339bedbb127e240fec1fd3070e9934c0b7bef83432f779d2f"}, + {file = "sqlalchemy-2.0.49-py3-none-any.whl", hash = "sha256:ec44cfa7ef1a728e88ad41674de50f6db8cfdb3e2af84af86e0041aaf02d43d0"}, + {file = "sqlalchemy-2.0.49.tar.gz", hash = "sha256:d15950a57a210e36dd4cec1aac22787e2a4d57ba9318233e2ef8b2daf9ff2d5f"}, ] [package.dependencies] @@ -643,77 +836,77 @@ sqlcipher = ["sqlcipher3_binary"] [[package]] name = "squawk-cli" -version = "2.41.0" +version = "2.53.0" description = "Linter for PostgreSQL migrations" optional = false python-versions = ">=3.8" groups = ["main"] files = [ - {file = "squawk_cli-2.41.0-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:1a1a3a0e2dfb1ab7b4a5b9cbd971f43d3e0e65c88b265d41ba35e3e1a2301da6"}, - {file = "squawk_cli-2.41.0-py3-none-macosx_11_0_arm64.whl", hash = "sha256:81e495db7e173fdfca6cdf512076cdf17e2fe0b5bd9ba98f8e24e6e82ee3620b"}, - {file = "squawk_cli-2.41.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:01997576efccf5a8f4497c6690113f3b80a4a25819e685b951a669010513bfab"}, - {file = "squawk_cli-2.41.0-py3-none-manylinux_2_28_x86_64.whl", hash = "sha256:ebf2eca5ebdabd5e8fa04b8f3576cc3ff34dce697414f8697b01b4979c356096"}, - {file = "squawk_cli-2.41.0-py3-none-win32.whl", hash = "sha256:20adeac4d5292bf51c4e2f5c4f06b22bb3ed3ef6cdd607914f20a577fc400b15"}, - {file = "squawk_cli-2.41.0-py3-none-win_amd64.whl", hash = "sha256:48dfc951f94faa24b73bbd0e4f67c45163ce0aa0b338fc44c7d1979833c640f5"}, - {file = "squawk_cli-2.41.0.tar.gz", hash = "sha256:7cac7cb7179967fe45757b67e5be055dba7f83b3ab9bd462e59b2ed237d182d3"}, + {file = "squawk_cli-2.53.0-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:e924e0583823789f45a24079e528bb8a64df74d36f9e9153a859ac8e0bcbe4b5"}, + {file = "squawk_cli-2.53.0-py3-none-macosx_11_0_arm64.whl", hash = "sha256:436160189472d84cfe1e1259064fc9d97172443c2e247ec9717570d501b03e09"}, + {file = "squawk_cli-2.53.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9edb4cb00198a0693603fe9fb179ec3dd074c75f0985ffbfdac8e2c0ef45e016"}, + {file = "squawk_cli-2.53.0-py3-none-manylinux_2_28_x86_64.whl", hash = "sha256:99b0868de362b7ae4847726dc391754c834a96dbd0954e284994d8ed979d1dc6"}, + {file = "squawk_cli-2.53.0-py3-none-win32.whl", hash = "sha256:0bbd82801491ea011d133446e7384fcc38ced241fcfa7536d6665187224d57bc"}, + {file = "squawk_cli-2.53.0-py3-none-win_amd64.whl", hash = "sha256:45f34827ab044884afa50ed394a74565eb267a86b40edfe7290720e33def9f32"}, + {file = "squawk_cli-2.53.0.tar.gz", hash = "sha256:3c5e66cfbbe8194e9f10a0d6ac8f7da9b3af87236c6f1372fc52524c6591b1df"}, ] [[package]] name = "tomli" -version = "2.4.0" +version = "2.4.1" description = "A lil' TOML parser" optional = false python-versions = ">=3.8" groups = ["dev"] -markers = "python_version == \"3.10\"" +markers = "python_full_version <= \"3.11.0a6\"" files = [ - {file = "tomli-2.4.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b5ef256a3fd497d4973c11bf142e9ed78b150d36f5773f1ca6088c230ffc5867"}, - {file = "tomli-2.4.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5572e41282d5268eb09a697c89a7bee84fae66511f87533a6f88bd2f7b652da9"}, - {file = "tomli-2.4.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:551e321c6ba03b55676970b47cb1b73f14a0a4dce6a3e1a9458fd6d921d72e95"}, - {file = "tomli-2.4.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5e3f639a7a8f10069d0e15408c0b96a2a828cfdec6fca05296ebcdcc28ca7c76"}, - {file = "tomli-2.4.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1b168f2731796b045128c45982d3a4874057626da0e2ef1fdd722848b741361d"}, - {file = "tomli-2.4.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:133e93646ec4300d651839d382d63edff11d8978be23da4cc106f5a18b7d0576"}, - {file = "tomli-2.4.0-cp311-cp311-win32.whl", hash = "sha256:b6c78bdf37764092d369722d9946cb65b8767bfa4110f902a1b2542d8d173c8a"}, - {file = "tomli-2.4.0-cp311-cp311-win_amd64.whl", hash = "sha256:d3d1654e11d724760cdb37a3d7691f0be9db5fbdaef59c9f532aabf87006dbaa"}, - {file = "tomli-2.4.0-cp311-cp311-win_arm64.whl", hash = "sha256:cae9c19ed12d4e8f3ebf46d1a75090e4c0dc16271c5bce1c833ac168f08fb614"}, - {file = "tomli-2.4.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:920b1de295e72887bafa3ad9f7a792f811847d57ea6b1215154030cf131f16b1"}, - {file = "tomli-2.4.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7d6d9a4aee98fac3eab4952ad1d73aee87359452d1c086b5ceb43ed02ddb16b8"}, - {file = "tomli-2.4.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:36b9d05b51e65b254ea6c2585b59d2c4cb91c8a3d91d0ed0f17591a29aaea54a"}, - {file = "tomli-2.4.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1c8a885b370751837c029ef9bc014f27d80840e48bac415f3412e6593bbc18c1"}, - {file = "tomli-2.4.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8768715ffc41f0008abe25d808c20c3d990f42b6e2e58305d5da280ae7d1fa3b"}, - {file = "tomli-2.4.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:7b438885858efd5be02a9a133caf5812b8776ee0c969fea02c45e8e3f296ba51"}, - {file = "tomli-2.4.0-cp312-cp312-win32.whl", hash = "sha256:0408e3de5ec77cc7f81960c362543cbbd91ef883e3138e81b729fc3eea5b9729"}, - {file = "tomli-2.4.0-cp312-cp312-win_amd64.whl", hash = "sha256:685306e2cc7da35be4ee914fd34ab801a6acacb061b6a7abca922aaf9ad368da"}, - {file = "tomli-2.4.0-cp312-cp312-win_arm64.whl", hash = "sha256:5aa48d7c2356055feef06a43611fc401a07337d5b006be13a30f6c58f869e3c3"}, - {file = "tomli-2.4.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:84d081fbc252d1b6a982e1870660e7330fb8f90f676f6e78b052ad4e64714bf0"}, - {file = "tomli-2.4.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:9a08144fa4cba33db5255f9b74f0b89888622109bd2776148f2597447f92a94e"}, - {file = "tomli-2.4.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c73add4bb52a206fd0c0723432db123c0c75c280cbd67174dd9d2db228ebb1b4"}, - {file = "tomli-2.4.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1fb2945cbe303b1419e2706e711b7113da57b7db31ee378d08712d678a34e51e"}, - {file = "tomli-2.4.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:bbb1b10aa643d973366dc2cb1ad94f99c1726a02343d43cbc011edbfac579e7c"}, - {file = "tomli-2.4.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4cbcb367d44a1f0c2be408758b43e1ffb5308abe0ea222897d6bfc8e8281ef2f"}, - {file = "tomli-2.4.0-cp313-cp313-win32.whl", hash = "sha256:7d49c66a7d5e56ac959cb6fc583aff0651094ec071ba9ad43df785abc2320d86"}, - {file = "tomli-2.4.0-cp313-cp313-win_amd64.whl", hash = "sha256:3cf226acb51d8f1c394c1b310e0e0e61fecdd7adcb78d01e294ac297dd2e7f87"}, - {file = "tomli-2.4.0-cp313-cp313-win_arm64.whl", hash = "sha256:d20b797a5c1ad80c516e41bc1fb0443ddb5006e9aaa7bda2d71978346aeb9132"}, - {file = "tomli-2.4.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:26ab906a1eb794cd4e103691daa23d95c6919cc2fa9160000ac02370cc9dd3f6"}, - {file = "tomli-2.4.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:20cedb4ee43278bc4f2fee6cb50daec836959aadaf948db5172e776dd3d993fc"}, - {file = "tomli-2.4.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:39b0b5d1b6dd03684b3fb276407ebed7090bbec989fa55838c98560c01113b66"}, - {file = "tomli-2.4.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a26d7ff68dfdb9f87a016ecfd1e1c2bacbe3108f4e0f8bcd2228ef9a766c787d"}, - {file = "tomli-2.4.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:20ffd184fb1df76a66e34bd1b36b4a4641bd2b82954befa32fe8163e79f1a702"}, - {file = "tomli-2.4.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:75c2f8bbddf170e8effc98f5e9084a8751f8174ea6ccf4fca5398436e0320bc8"}, - {file = "tomli-2.4.0-cp314-cp314-win32.whl", hash = "sha256:31d556d079d72db7c584c0627ff3a24c5d3fb4f730221d3444f3efb1b2514776"}, - {file = "tomli-2.4.0-cp314-cp314-win_amd64.whl", hash = "sha256:43e685b9b2341681907759cf3a04e14d7104b3580f808cfde1dfdb60ada85475"}, - {file = "tomli-2.4.0-cp314-cp314-win_arm64.whl", hash = "sha256:3d895d56bd3f82ddd6faaff993c275efc2ff38e52322ea264122d72729dca2b2"}, - {file = "tomli-2.4.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:5b5807f3999fb66776dbce568cc9a828544244a8eb84b84b9bafc080c99597b9"}, - {file = "tomli-2.4.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:c084ad935abe686bd9c898e62a02a19abfc9760b5a79bc29644463eaf2840cb0"}, - {file = "tomli-2.4.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0f2e3955efea4d1cfbcb87bc321e00dc08d2bcb737fd1d5e398af111d86db5df"}, - {file = "tomli-2.4.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0e0fe8a0b8312acf3a88077a0802565cb09ee34107813bba1c7cd591fa6cfc8d"}, - {file = "tomli-2.4.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:413540dce94673591859c4c6f794dfeaa845e98bf35d72ed59636f869ef9f86f"}, - {file = "tomli-2.4.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:0dc56fef0e2c1c470aeac5b6ca8cc7b640bb93e92d9803ddaf9ea03e198f5b0b"}, - {file = "tomli-2.4.0-cp314-cp314t-win32.whl", hash = "sha256:d878f2a6707cc9d53a1be1414bbb419e629c3d6e67f69230217bb663e76b5087"}, - {file = "tomli-2.4.0-cp314-cp314t-win_amd64.whl", hash = "sha256:2add28aacc7425117ff6364fe9e06a183bb0251b03f986df0e78e974047571fd"}, - {file = "tomli-2.4.0-cp314-cp314t-win_arm64.whl", hash = "sha256:2b1e3b80e1d5e52e40e9b924ec43d81570f0e7d09d11081b797bc4692765a3d4"}, - {file = "tomli-2.4.0-py3-none-any.whl", hash = "sha256:1f776e7d669ebceb01dee46484485f43a4048746235e683bcdffacdf1fb4785a"}, - {file = "tomli-2.4.0.tar.gz", hash = "sha256:aa89c3f6c277dd275d8e243ad24f3b5e701491a860d5121f2cdd399fbb31fc9c"}, + {file = "tomli-2.4.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f8f0fc26ec2cc2b965b7a3b87cd19c5c6b8c5e5f436b984e85f486d652285c30"}, + {file = "tomli-2.4.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4ab97e64ccda8756376892c53a72bd1f964e519c77236368527f758fbc36a53a"}, + {file = "tomli-2.4.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:96481a5786729fd470164b47cdb3e0e58062a496f455ee41b4403be77cb5a076"}, + {file = "tomli-2.4.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5a881ab208c0baf688221f8cecc5401bd291d67e38a1ac884d6736cbcd8247e9"}, + {file = "tomli-2.4.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:47149d5bd38761ac8be13a84864bf0b7b70bc051806bc3669ab1cbc56216b23c"}, + {file = "tomli-2.4.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ec9bfaf3ad2df51ace80688143a6a4ebc09a248f6ff781a9945e51937008fcbc"}, + {file = "tomli-2.4.1-cp311-cp311-win32.whl", hash = "sha256:ff2983983d34813c1aeb0fa89091e76c3a22889ee83ab27c5eeb45100560c049"}, + {file = "tomli-2.4.1-cp311-cp311-win_amd64.whl", hash = "sha256:5ee18d9ebdb417e384b58fe414e8d6af9f4e7a0ae761519fb50f721de398dd4e"}, + {file = "tomli-2.4.1-cp311-cp311-win_arm64.whl", hash = "sha256:c2541745709bad0264b7d4705ad453b76ccd191e64aa6f0fc66b69a293a45ece"}, + {file = "tomli-2.4.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:c742f741d58a28940ce01d58f0ab2ea3ced8b12402f162f4d534dfe18ba1cd6a"}, + {file = "tomli-2.4.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7f86fd587c4ed9dd76f318225e7d9b29cfc5a9d43de44e5754db8d1128487085"}, + {file = "tomli-2.4.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ff18e6a727ee0ab0388507b89d1bc6a22b138d1e2fa56d1ad494586d61d2eae9"}, + {file = "tomli-2.4.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:136443dbd7e1dee43c68ac2694fde36b2849865fa258d39bf822c10e8068eac5"}, + {file = "tomli-2.4.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:5e262d41726bc187e69af7825504c933b6794dc3fbd5945e41a79bb14c31f585"}, + {file = "tomli-2.4.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:5cb41aa38891e073ee49d55fbc7839cfdb2bc0e600add13874d048c94aadddd1"}, + {file = "tomli-2.4.1-cp312-cp312-win32.whl", hash = "sha256:da25dc3563bff5965356133435b757a795a17b17d01dbc0f42fb32447ddfd917"}, + {file = "tomli-2.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:52c8ef851d9a240f11a88c003eacb03c31fc1c9c4ec64a99a0f922b93874fda9"}, + {file = "tomli-2.4.1-cp312-cp312-win_arm64.whl", hash = "sha256:f758f1b9299d059cc3f6546ae2af89670cb1c4d48ea29c3cacc4fe7de3058257"}, + {file = "tomli-2.4.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:36d2bd2ad5fb9eaddba5226aa02c8ec3fa4f192631e347b3ed28186d43be6b54"}, + {file = "tomli-2.4.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:eb0dc4e38e6a1fd579e5d50369aa2e10acfc9cace504579b2faabb478e76941a"}, + {file = "tomli-2.4.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c7f2c7f2b9ca6bdeef8f0fa897f8e05085923eb091721675170254cbc5b02897"}, + {file = "tomli-2.4.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f3c6818a1a86dd6dca7ddcaaf76947d5ba31aecc28cb1b67009a5877c9a64f3f"}, + {file = "tomli-2.4.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:d312ef37c91508b0ab2cee7da26ec0b3ed2f03ce12bd87a588d771ae15dcf82d"}, + {file = "tomli-2.4.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:51529d40e3ca50046d7606fa99ce3956a617f9b36380da3b7f0dd3dd28e68cb5"}, + {file = "tomli-2.4.1-cp313-cp313-win32.whl", hash = "sha256:2190f2e9dd7508d2a90ded5ed369255980a1bcdd58e52f7fe24b8162bf9fedbd"}, + {file = "tomli-2.4.1-cp313-cp313-win_amd64.whl", hash = "sha256:8d65a2fbf9d2f8352685bc1364177ee3923d6baf5e7f43ea4959d7d8bc326a36"}, + {file = "tomli-2.4.1-cp313-cp313-win_arm64.whl", hash = "sha256:4b605484e43cdc43f0954ddae319fb75f04cc10dd80d830540060ee7cd0243cd"}, + {file = "tomli-2.4.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:fd0409a3653af6c147209d267a0e4243f0ae46b011aa978b1080359fddc9b6cf"}, + {file = "tomli-2.4.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:a120733b01c45e9a0c34aeef92bf0cf1d56cfe81ed9d47d562f9ed591a9828ac"}, + {file = "tomli-2.4.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:559db847dc486944896521f68d8190be1c9e719fced785720d2216fe7022b662"}, + {file = "tomli-2.4.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:01f520d4f53ef97964a240a035ec2a869fe1a37dde002b57ebc4417a27ccd853"}, + {file = "tomli-2.4.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7f94b27a62cfad8496c8d2513e1a222dd446f095fca8987fceef261225538a15"}, + {file = "tomli-2.4.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:ede3e6487c5ef5d28634ba3f31f989030ad6af71edfb0055cbbd14189ff240ba"}, + {file = "tomli-2.4.1-cp314-cp314-win32.whl", hash = "sha256:3d48a93ee1c9b79c04bb38772ee1b64dcf18ff43085896ea460ca8dec96f35f6"}, + {file = "tomli-2.4.1-cp314-cp314-win_amd64.whl", hash = "sha256:88dceee75c2c63af144e456745e10101eb67361050196b0b6af5d717254dddf7"}, + {file = "tomli-2.4.1-cp314-cp314-win_arm64.whl", hash = "sha256:b8c198f8c1805dc42708689ed6864951fd2494f924149d3e4bce7710f8eb5232"}, + {file = "tomli-2.4.1-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:d4d8fe59808a54658fcc0160ecfb1b30f9089906c50b23bcb4c69eddc19ec2b4"}, + {file = "tomli-2.4.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:7008df2e7655c495dd12d2a4ad038ff878d4ca4b81fccaf82b714e07eae4402c"}, + {file = "tomli-2.4.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1d8591993e228b0c930c4bb0db464bdad97b3289fb981255d6c9a41aedc84b2d"}, + {file = "tomli-2.4.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:734e20b57ba95624ecf1841e72b53f6e186355e216e5412de414e3c51e5e3c41"}, + {file = "tomli-2.4.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:8a650c2dbafa08d42e51ba0b62740dae4ecb9338eefa093aa5c78ceb546fcd5c"}, + {file = "tomli-2.4.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:504aa796fe0569bb43171066009ead363de03675276d2d121ac1a4572397870f"}, + {file = "tomli-2.4.1-cp314-cp314t-win32.whl", hash = "sha256:b1d22e6e9387bf4739fbe23bfa80e93f6b0373a7f1b96c6227c32bef95a4d7a8"}, + {file = "tomli-2.4.1-cp314-cp314t-win_amd64.whl", hash = "sha256:2c1c351919aca02858f740c6d33adea0c5deea37f9ecca1cc1ef9e884a619d26"}, + {file = "tomli-2.4.1-cp314-cp314t-win_arm64.whl", hash = "sha256:eab21f45c7f66c13f2a9e0e1535309cee140182a9cdae1e041d02e47291e8396"}, + {file = "tomli-2.4.1-py3-none-any.whl", hash = "sha256:0d85819802132122da43cb86656f8d1f8c6587d54ae7dcaf30e90533028b49fe"}, + {file = "tomli-2.4.1.tar.gz", hash = "sha256:7c7e1a961a0b2f2472c1ac5b69affa0ae1132c39adcb67aba98568702b9cc23f"}, ] [[package]] @@ -730,27 +923,24 @@ files = [ [[package]] name = "virtualenv" -version = "20.38.0" +version = "21.3.3" description = "Virtual Python Environment builder" optional = false python-versions = ">=3.8" groups = ["dev"] files = [ - {file = "virtualenv-20.38.0-py3-none-any.whl", hash = "sha256:d6e78e5889de3a4742df2d3d44e779366325a90cf356f15621fddace82431794"}, - {file = "virtualenv-20.38.0.tar.gz", hash = "sha256:94f39b1abaea5185bf7ea5a46702b56f1d0c9aa2f41a6c2b8b0af4ddc74c10a7"}, + {file = "virtualenv-21.3.3-py3-none-any.whl", hash = "sha256:7d5987d8369e098e41406efb780a3d4ca79280097293899e351a6407ee153ab3"}, + {file = "virtualenv-21.3.3.tar.gz", hash = "sha256:f5bda277e553b1c2b3c1a8debfc30496e1288cc93ce6b7b71b3280047e317328"}, ] [package.dependencies] distlib = ">=0.3.7,<1" filelock = {version = ">=3.24.2,<4", markers = "python_version >= \"3.10\""} platformdirs = ">=3.9.1,<5" +python-discovery = ">=1.3.1" typing-extensions = {version = ">=4.13.2", markers = "python_version < \"3.11\""} -[package.extras] -docs = ["furo (>=2023.7.26)", "pre-commit-uv (>=4.1.4)", "proselint (>=0.13)", "sphinx (>=7.1.2,!=7.3)", "sphinx-argparse (>=0.4)", "sphinx-autodoc-typehints (>=3.6.2)", "sphinx-copybutton (>=0.5.2)", "sphinx-inline-tabs (>=2025.12.21.14)", "sphinxcontrib-mermaid (>=2)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=23.6)"] -test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7)", "packaging (>=23.1)", "pytest (>=7.4)", "pytest-env (>=0.8.2)", "pytest-freezer (>=0.4.8) ; platform_python_implementation == \"PyPy\" or platform_python_implementation == \"GraalVM\" or platform_python_implementation == \"CPython\" and sys_platform == \"win32\" and python_version >= \"3.13\"", "pytest-mock (>=3.11.1)", "pytest-randomly (>=3.12)", "pytest-timeout (>=2.1)", "pytest-xdist (>=3.5)", "setuptools (>=68)", "time-machine (>=2.10) ; platform_python_implementation == \"CPython\""] - [metadata] lock-version = "2.1" python-versions = ">=3.10" -content-hash = "571a388b10319527ae4d2cf3e415e7adb49268c9cb92e103ed02b7903613ca9a" +content-hash = "3079fac4bd274881c5f8e8ab05b57bbaa6ef98b812fa04139473c792bccc0f28" diff --git a/pyproject.toml b/pyproject.toml index cf5806f..fb96a3d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "poetry.core.masonry.api" [tool.poetry] name = "squawk-alembic" -version = "0.3.2" +version = "0.3.3" description = "Pre-commit hook to lint Alembic migration SQL with squawk" packages = [{include = "squawk_alembic"}] readme = "README.md" @@ -29,11 +29,12 @@ python = ">=3.10" squawk-cli = ">=2.0" [tool.poetry.group.dev.dependencies] -alembic = "*" -pre-commit = "*" -pytest = "*" -ruff = "*" -pyrefly = "*" +alembic = "~=1.18.4" +pre-commit = "~=4.6.0" +pytest = "~=9.0.3" +ruff = "~=0.15.14" +pyrefly = "~=1.0.0" +pytest-cov = "~=7.1.0" [tool.poetry.scripts] squawk-alembic = "squawk_alembic.hook:main" diff --git a/squawk_alembic/__init__.py b/squawk_alembic/__init__.py index f9aa3e1..e19434e 100644 --- a/squawk_alembic/__init__.py +++ b/squawk_alembic/__init__.py @@ -1 +1 @@ -__version__ = "0.3.2" +__version__ = "0.3.3" diff --git a/squawk_alembic/hook.py b/squawk_alembic/hook.py index b6508cd..707821a 100644 --- a/squawk_alembic/hook.py +++ b/squawk_alembic/hook.py @@ -1,19 +1,20 @@ """Pre-commit hook that generates DDL via alembic upgrade --sql and lints with squawk.""" import argparse +import ast import os import re import subprocess import sys import tempfile -from ast import AnnAssign, Assign, Constant, Name, Tuple, iter_child_nodes, parse from configparser import ConfigParser, NoOptionError, NoSectionError +from dataclasses import dataclass from pathlib import Path _BRANCH_RE = re.compile(r"^[a-zA-Z0-9][a-zA-Z0-9._/\-]*$") -def find_migrations_path(): +def find_migrations_path() -> Path | None: """Auto-detect the alembic migrations versions directory from alembic.ini.""" config_path = Path("alembic.ini") if not config_path.exists(): @@ -36,50 +37,50 @@ def find_migrations_path(): return None +@dataclass(frozen=True, slots=True) class RevisionInfo: - __slots__ = ("revision", "down_revision", "is_merge") + revision: str + down_revision: str | tuple[str, ...] | None + is_merge: bool - def __init__(self, revision, down_revision, is_merge): - self.revision = revision - self.down_revision = down_revision - self.is_merge = is_merge - -def extract_revision_info(filepath): +def extract_revision_info(filepath: str | Path) -> RevisionInfo | None: """Parse a migration file to extract revision and down_revision from module-level assignments.""" with open(filepath) as f: try: - tree = parse(f.read()) + tree = ast.parse(f.read()) except SyntaxError: return None - revision = None - down_revision = None + revision: str | None = None + down_revision: str | tuple[str, ...] | None = None - for node in iter_child_nodes(tree): - if isinstance(node, AnnAssign): - if not isinstance(node.target, Name) or node.value is None: + for node in ast.iter_child_nodes(tree): + if isinstance(node, ast.AnnAssign): + if not isinstance(node.target, ast.Name) or node.value is None: continue name = node.target.id - elif isinstance(node, Assign): - if len(node.targets) != 1 or not isinstance(node.targets[0], Name): + elif isinstance(node, ast.Assign): + if len(node.targets) != 1 or not isinstance(node.targets[0], ast.Name): continue name = node.targets[0].id else: continue if name == "revision": - if isinstance(node.value, Constant) and isinstance(node.value.value, str): + if isinstance(node.value, ast.Constant) and isinstance( + node.value.value, str + ): revision = node.value.value elif name == "down_revision": - if isinstance(node.value, Constant): + if isinstance(node.value, ast.Constant): if isinstance(node.value.value, str): down_revision = node.value.value elif node.value.value is None: down_revision = None - elif isinstance(node.value, Tuple): - values = [] + elif isinstance(node.value, ast.Tuple): + values: list[str] = [] for elt in node.value.elts: - if isinstance(elt, Constant) and isinstance(elt.value, str): + if isinstance(elt, ast.Constant) and isinstance(elt.value, str): values.append(elt.value) down_revision = tuple(values) @@ -96,7 +97,7 @@ class GenerateSqlError(Exception): """Raised when alembic upgrade --sql fails.""" -def generate_sql(filepath): +def generate_sql(filepath: str | Path) -> str | None: """Run alembic upgrade --sql to generate the complete DDL for a migration. Returns the SQL string, or None if the file should be skipped (merge migration, @@ -109,7 +110,7 @@ def generate_sql(filepath): if info.is_merge: return None - base = info.down_revision if info.down_revision else "base" + base = info.down_revision if isinstance(info.down_revision, str) else "base" target = f"{base}:{info.revision}" env = os.environ.copy() @@ -136,11 +137,11 @@ def generate_sql(filepath): return result.stdout -def validate_branch(branch): +def validate_branch(branch: str) -> bool: """Validate that a branch name is safe and exists in git. For remote refs (origin/...), attempts a shallow fetch when the ref is - missing locally — common in CI shallow clones. + missing locally, common in CI shallow clones. """ if not _BRANCH_RE.match(branch) or ".." in branch: print( @@ -175,7 +176,7 @@ def validate_branch(branch): return False -def file_exists_on_branch(filepath, branch): +def file_exists_on_branch(filepath: str, branch: str) -> bool: """Check if a file exists on the given git branch.""" try: result = subprocess.run( @@ -187,7 +188,66 @@ def file_exists_on_branch(filepath, branch): return result.returncode == 0 -def main(): +class _SquawkNotFound(Exception): + pass + + +def _lint_file(filepath: str, migrations_path: Path, diff_branch: str | None) -> int: + """Lint a single migration file. Returns 0 on success/skip, 1 on failure. + + Raises _SquawkNotFound if the squawk binary is missing. + """ + try: + Path(filepath).relative_to(migrations_path) + except ValueError: + return 0 + + if diff_branch and file_exists_on_branch(filepath, diff_branch): + return 0 + + try: + sql = generate_sql(filepath) + except GenerateSqlError as exc: + print(str(exc), file=sys.stderr) + return 1 + except OSError as exc: + print( + f"squawk-alembic: cannot read migration file: {exc}", + file=sys.stderr, + ) + return 1 + + if not sql: + return 0 + + with tempfile.NamedTemporaryFile(mode="w", suffix=".sql", delete=False) as tmp: + tmp.write(sql) + tmp_path = tmp.name + + try: + result = subprocess.run( + ["squawk", tmp_path], + capture_output=True, + text=True, + ) + if result.returncode != 0: + output = result.stdout.replace(tmp_path, filepath) + error = result.stderr.replace(tmp_path, filepath) + if output: + print(output) + if error: + print(error, file=sys.stderr) + return 1 + except FileNotFoundError: + raise _SquawkNotFound + finally: + Path(tmp_path).unlink(missing_ok=True) + + return 0 + + +def main() -> int: + """CLI entrypoint. Returns 0 on success, 1 on any failure.""" parser = argparse.ArgumentParser() parser.add_argument( "--diff-branch", @@ -215,49 +275,15 @@ def main(): for filepath in args.files: try: - Path(filepath).relative_to(migrations_path) - except ValueError: - continue - - if args.diff_branch and file_exists_on_branch(filepath, args.diff_branch): - continue - - try: - sql = generate_sql(filepath) - except GenerateSqlError as exc: - print(str(exc), file=sys.stderr) - exit_code = 1 - continue - - if not sql: - continue - - with tempfile.NamedTemporaryFile(mode="w", suffix=".sql", delete=False) as tmp: - tmp.write(sql) - tmp_path = tmp.name - - try: - result = subprocess.run( - ["squawk", tmp_path], - capture_output=True, - text=True, - ) - if result.returncode != 0: - output = result.stdout.replace(tmp_path, filepath) - error = result.stderr.replace(tmp_path, filepath) - if output: - print(output) - if error: - print(error, file=sys.stderr) - exit_code = 1 - except FileNotFoundError: + result = _lint_file(filepath, migrations_path, args.diff_branch) + except _SquawkNotFound: print( "squawk-alembic: squawk not found. Install with: pip install squawk-cli", file=sys.stderr, ) return 1 - finally: - Path(tmp_path).unlink(missing_ok=True) + if result != 0: + exit_code = 1 return exit_code diff --git a/tests/conftest.py b/tests/conftest.py new file mode 100644 index 0000000..66cca91 --- /dev/null +++ b/tests/conftest.py @@ -0,0 +1,55 @@ +"""Shared test fixtures.""" + +import textwrap +from types import SimpleNamespace + +from pytest import fixture + + +@fixture() +def repo(tmp_path, monkeypatch): + """Set up a fake repo with alembic config and a versions directory.""" + monkeypatch.chdir(tmp_path) + versions = tmp_path / "migrations" / "versions" + versions.mkdir(parents=True) + (tmp_path / "alembic.ini").write_text("[alembic]\nscript_location = ./migrations\n") + return tmp_path + + +def make_result(returncode=0, stdout="", stderr=""): + return SimpleNamespace(returncode=returncode, stdout=stdout, stderr=stderr) + + +def write_migration(repo, filename, source): + path = repo / "migrations" / "versions" / filename + path.write_text(textwrap.dedent(source)) + return f"migrations/versions/{filename}" + + +def fake_subprocess( + alembic_result=None, + squawk_result=None, + git_exists_on_branch=False, + git_branch_valid=True, + git_fetch_succeeds=False, +): + """Return a side_effect function that dispatches based on the command.""" + alembic_res = alembic_result or make_result(stdout="CREATE TABLE foo (id int);\n") + squawk_res = squawk_result or make_result() + + def side_effect(cmd, **kwargs): + if cmd[0] == "git": + if "rev-parse" in cmd: + return make_result(returncode=0 if git_branch_valid else 1) + if "fetch" in cmd: + return make_result(returncode=0 if git_fetch_succeeds else 1) + if "cat-file" in cmd: + return make_result(returncode=0 if git_exists_on_branch else 1) + return make_result(returncode=1) + if cmd[0] == "alembic": + return alembic_res + if cmd[0] == "squawk": + return squawk_res + raise ValueError(f"unexpected command: {cmd}") + + return side_effect diff --git a/tests/test_generate_sql.py b/tests/test_generate_sql.py new file mode 100644 index 0000000..44f7ff7 --- /dev/null +++ b/tests/test_generate_sql.py @@ -0,0 +1,164 @@ +"""Tests for generate_sql, exercising it directly rather than through main().""" + +import textwrap +from unittest.mock import patch + +import pytest + +from squawk_alembic.hook import GenerateSqlError, generate_sql + +from .conftest import make_result + + +def write_file(tmp_path, source): + path = tmp_path / "migration.py" + path.write_text(textwrap.dedent(source)) + return str(path) + + +def test_returns_sql_for_valid_migration(tmp_path): + path = write_file( + tmp_path, + """ + revision = 'abc123' + down_revision = 'def456' + + def upgrade(): + pass + """, + ) + expected_sql = "CREATE TABLE foo (id int);\n" + with patch( + "subprocess.run", + return_value=make_result(stdout=expected_sql), + ): + assert generate_sql(path) == expected_sql + + +def test_returns_none_for_unparseable_file(tmp_path): + path = write_file(tmp_path, "this is not valid python {{{") + assert generate_sql(path) is None + + +def test_returns_none_for_merge_migration(tmp_path): + path = write_file( + tmp_path, + """ + revision = 'merge001' + down_revision = ('abc123', 'def456') + + def upgrade(): + pass + """, + ) + assert generate_sql(path) is None + + +def test_returns_none_for_missing_revision(tmp_path): + path = write_file( + tmp_path, + """ + down_revision = 'def456' + + def upgrade(): + pass + """, + ) + assert generate_sql(path) is None + + +def test_uses_base_when_down_revision_is_none(tmp_path): + path = write_file( + tmp_path, + """ + revision = 'first001' + down_revision = None + + def upgrade(): + pass + """, + ) + with patch( + "subprocess.run", + return_value=make_result(stdout="CREATE TABLE foo (id int);\n"), + ) as mock_run: + generate_sql(path) + cmd = mock_run.call_args[0][0] + assert "base:first001" in cmd + + +def test_raises_on_alembic_failure(tmp_path): + path = write_file( + tmp_path, + """ + revision = 'abc123' + down_revision = 'def456' + + def upgrade(): + pass + """, + ) + with patch( + "subprocess.run", + return_value=make_result(returncode=1, stderr="some error"), + ): + with pytest.raises(GenerateSqlError, match="alembic upgrade --sql failed"): + generate_sql(path) + + +def test_raises_when_alembic_not_found(tmp_path): + path = write_file( + tmp_path, + """ + revision = 'abc123' + down_revision = 'def456' + + def upgrade(): + pass + """, + ) + with patch("subprocess.run", side_effect=FileNotFoundError): + with pytest.raises(GenerateSqlError, match="alembic not found"): + generate_sql(path) + + +def test_provides_dummy_database_url_when_unset(tmp_path, monkeypatch): + monkeypatch.delenv("DATABASE_URL", raising=False) + path = write_file( + tmp_path, + """ + revision = 'abc123' + down_revision = 'def456' + + def upgrade(): + pass + """, + ) + with patch( + "subprocess.run", + return_value=make_result(stdout="SQL;\n"), + ) as mock_run: + generate_sql(path) + env = mock_run.call_args[1]["env"] + assert env["DATABASE_URL"] == "postgresql://localhost/lint" + + +def test_preserves_existing_database_url(tmp_path, monkeypatch): + monkeypatch.setenv("DATABASE_URL", "postgresql://real-host/real-db") + path = write_file( + tmp_path, + """ + revision = 'abc123' + down_revision = 'def456' + + def upgrade(): + pass + """, + ) + with patch( + "subprocess.run", + return_value=make_result(stdout="SQL;\n"), + ) as mock_run: + generate_sql(path) + env = mock_run.call_args[1]["env"] + assert env["DATABASE_URL"] == "postgresql://real-host/real-db" diff --git a/tests/test_main.py b/tests/test_main.py index a06cdee..d939cee 100644 --- a/tests/test_main.py +++ b/tests/test_main.py @@ -1,62 +1,10 @@ """Tests for the main hook entrypoint.""" -import textwrap from unittest.mock import patch -from pytest import fixture - from squawk_alembic.hook import main - -@fixture() -def repo(tmp_path, monkeypatch): - """Set up a fake repo with alembic config and a versions directory.""" - monkeypatch.chdir(tmp_path) - versions = tmp_path / "migrations" / "versions" - versions.mkdir(parents=True) - (tmp_path / "alembic.ini").write_text("[alembic]\nscript_location = ./migrations\n") - return tmp_path - - -def write_migration(repo, filename, source): - path = repo / "migrations" / "versions" / filename - path.write_text(textwrap.dedent(source)) - return f"migrations/versions/{filename}" - - -def make_result(returncode=0, stdout="", stderr=""): - return type( - "Result", (), {"returncode": returncode, "stdout": stdout, "stderr": stderr} - )() - - -def fake_subprocess( - alembic_result=None, - squawk_result=None, - git_exists_on_branch=False, - git_branch_valid=True, - git_fetch_succeeds=False, -): - """Return a side_effect function that dispatches based on the command.""" - alembic_res = alembic_result or make_result(stdout="CREATE TABLE foo (id int);\n") - squawk_res = squawk_result or make_result() - - def side_effect(cmd, **kwargs): - if cmd[0] == "git": - if "rev-parse" in cmd: - return make_result(returncode=0 if git_branch_valid else 1) - if "fetch" in cmd: - return make_result(returncode=0 if git_fetch_succeeds else 1) - if "cat-file" in cmd: - return make_result(returncode=0 if git_exists_on_branch else 1) - return make_result(returncode=1) - if cmd[0] == "alembic": - return alembic_res - if cmd[0] == "squawk": - return squawk_res - raise ValueError(f"unexpected command: {cmd}") - - return side_effect +from .conftest import fake_subprocess, make_result, write_migration def test_no_files(repo): @@ -134,6 +82,46 @@ def upgrade(): assert "some squawk warning" in captured.out +def test_squawk_failure_replaces_tmp_path_in_output(repo, capsys): + """Squawk output should show the original migration path, not the temp file path.""" + path = write_migration( + repo, + "020_path_rewrite.py", + """ + revision = 'rw001' + down_revision = 'prev001' + + from alembic import op + + def upgrade(): + op.execute("ALTER TABLE foo ADD COLUMN bar int") + """, + ) + + def side_effect(cmd, **kwargs): + if cmd[0] == "alembic": + return make_result(stdout="ALTER TABLE foo ADD COLUMN bar int;\n") + if cmd[0] == "squawk": + tmp = cmd[1] + return make_result( + returncode=1, + stdout=f"{tmp}:1: warning: prefer-robust-stmts\n", + stderr=f"error in {tmp}\n", + ) + raise ValueError(f"unexpected command: {cmd}") + + with ( + patch("sys.argv", ["squawk-alembic", path]), + patch("subprocess.run", side_effect=side_effect), + ): + assert main() == 1 + captured = capsys.readouterr() + assert path in captured.out + assert path in captured.err + assert "/tmp/" not in captured.out + assert "/tmp/" not in captured.err + + def test_alembic_failure_fails_run(repo, capsys): path = write_migration( repo, @@ -162,6 +150,29 @@ def upgrade(): assert "alembic upgrade --sql failed" in captured.err +def test_unreadable_migration_file(repo, capsys): + """A migration file that can't be opened should produce a clear error, not a traceback.""" + path = write_migration( + repo, + "026_unreadable.py", + """ + revision = 'ur001' + down_revision = 'prev001' + + def upgrade(): + pass + """, + ) + import os + + os.chmod(repo / "migrations" / "versions" / "026_unreadable.py", 0o000) + with patch("sys.argv", ["squawk-alembic", path]): + assert main() == 1 + os.chmod(repo / "migrations" / "versions" / "026_unreadable.py", 0o644) + captured = capsys.readouterr() + assert "cannot read migration file" in captured.err + + def test_missing_alembic_binary(repo, capsys): path = write_migration( repo, @@ -191,6 +202,38 @@ def alembic_not_found(cmd, **kwargs): assert "alembic not found" in captured.err +def test_missing_squawk_binary(repo, capsys): + """When squawk is not installed, the hook should fail with a helpful message.""" + path = write_migration( + repo, + "021_no_squawk.py", + """ + revision = 'ns001' + down_revision = 'prev001' + + from alembic import op + + def upgrade(): + op.execute("CREATE TABLE foo (id int)") + """, + ) + + def squawk_not_found(cmd, **kwargs): + if cmd[0] == "alembic": + return make_result(stdout="CREATE TABLE foo (id int);\n") + if cmd[0] == "squawk": + raise FileNotFoundError + raise ValueError(f"unexpected command: {cmd}") + + with ( + patch("sys.argv", ["squawk-alembic", path]), + patch("subprocess.run", side_effect=squawk_not_found), + ): + assert main() == 1 + captured = capsys.readouterr() + assert "squawk not found" in captured.err + + def test_merge_migration_skipped(repo): path = write_migration( repo, @@ -236,6 +279,95 @@ def upgrade(): assert "base:first001" in alembic_call +def test_multiple_files_all_pass(repo): + """All files should be processed when multiple are passed.""" + path1 = write_migration( + repo, + "022_multi_a.py", + """ + revision = 'ma001' + down_revision = 'prev001' + + from alembic import op + + def upgrade(): + op.execute("CREATE TABLE a (id int)") + """, + ) + path2 = write_migration( + repo, + "023_multi_b.py", + """ + revision = 'mb001' + down_revision = 'ma001' + + from alembic import op + + def upgrade(): + op.execute("CREATE TABLE b (id int)") + """, + ) + with ( + patch("sys.argv", ["squawk-alembic", path1, path2]), + patch("subprocess.run", side_effect=fake_subprocess()) as mock_run, + ): + assert main() == 0 + # alembic + squawk for each file = 4 calls + assert mock_run.call_count == 4 + + +def test_multiple_files_first_fails_second_still_runs(repo, capsys): + """A failure in one file should not prevent linting of subsequent files.""" + path1 = write_migration( + repo, + "024_fail.py", + """ + revision = 'f001' + down_revision = 'prev001' + + from alembic import op + + def upgrade(): + op.execute("ALTER TABLE foo ADD COLUMN bar int") + """, + ) + path2 = write_migration( + repo, + "025_pass.py", + """ + revision = 'p001' + down_revision = 'f001' + + from alembic import op + + def upgrade(): + op.execute("CREATE TABLE bar (id int)") + """, + ) + + call_count = {"alembic": 0} + + def side_effect(cmd, **kwargs): + if cmd[0] == "alembic": + call_count["alembic"] += 1 + if call_count["alembic"] == 1: + return make_result(returncode=1, stderr="alembic error on first\n") + return make_result(stdout="CREATE TABLE bar (id int);\n") + if cmd[0] == "squawk": + return make_result() + raise ValueError(f"unexpected command: {cmd}") + + with ( + patch("sys.argv", ["squawk-alembic", path1, path2]), + patch("subprocess.run", side_effect=side_effect) as mock_run, + ): + assert main() == 1 + # alembic (fail) + alembic (pass) + squawk (pass) = 3 + assert mock_run.call_count == 3 + captured = capsys.readouterr() + assert "alembic upgrade --sql failed" in captured.err + + def test_diff_branch_skips_existing_file(repo): path = write_migration( repo, From 9dc608fad16fb4f578b4b40d0ddc096e31a5e756 Mon Sep 17 00:00:00 2001 From: Stephen Brannen Date: Thu, 21 May 2026 16:15:54 -0500 Subject: [PATCH 2/4] fix: restore file permissions in finally block for unreadable-file test --- tests/test_main.py | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/tests/test_main.py b/tests/test_main.py index d939cee..cf66c27 100644 --- a/tests/test_main.py +++ b/tests/test_main.py @@ -165,12 +165,15 @@ def upgrade(): ) import os - os.chmod(repo / "migrations" / "versions" / "026_unreadable.py", 0o000) - with patch("sys.argv", ["squawk-alembic", path]): - assert main() == 1 - os.chmod(repo / "migrations" / "versions" / "026_unreadable.py", 0o644) - captured = capsys.readouterr() - assert "cannot read migration file" in captured.err + unreadable = repo / "migrations" / "versions" / "026_unreadable.py" + os.chmod(unreadable, 0o000) + try: + with patch("sys.argv", ["squawk-alembic", path]): + assert main() == 1 + captured = capsys.readouterr() + assert "cannot read migration file" in captured.err + finally: + os.chmod(unreadable, 0o644) def test_missing_alembic_binary(repo, capsys): From 9c7507bbdcb06aec40cf04741385e1356775c9db Mon Sep 17 00:00:00 2001 From: Stephen Brannen Date: Thu, 21 May 2026 16:25:15 -0500 Subject: [PATCH 3/4] refactor: replace with-patch context managers with @patch decorators in tests --- tests/test_generate_sql.py | 73 ++++---- tests/test_main.py | 361 ++++++++++++++++--------------------- 2 files changed, 190 insertions(+), 244 deletions(-) diff --git a/tests/test_generate_sql.py b/tests/test_generate_sql.py index 44f7ff7..71b203b 100644 --- a/tests/test_generate_sql.py +++ b/tests/test_generate_sql.py @@ -16,7 +16,8 @@ def write_file(tmp_path, source): return str(path) -def test_returns_sql_for_valid_migration(tmp_path): +@patch("subprocess.run") +def test_returns_sql_for_valid_migration(mock_run, tmp_path): path = write_file( tmp_path, """ @@ -28,11 +29,8 @@ def upgrade(): """, ) expected_sql = "CREATE TABLE foo (id int);\n" - with patch( - "subprocess.run", - return_value=make_result(stdout=expected_sql), - ): - assert generate_sql(path) == expected_sql + mock_run.return_value = make_result(stdout=expected_sql) + assert generate_sql(path) == expected_sql def test_returns_none_for_unparseable_file(tmp_path): @@ -67,7 +65,8 @@ def upgrade(): assert generate_sql(path) is None -def test_uses_base_when_down_revision_is_none(tmp_path): +@patch("subprocess.run") +def test_uses_base_when_down_revision_is_none(mock_run, tmp_path): path = write_file( tmp_path, """ @@ -78,16 +77,14 @@ def upgrade(): pass """, ) - with patch( - "subprocess.run", - return_value=make_result(stdout="CREATE TABLE foo (id int);\n"), - ) as mock_run: - generate_sql(path) - cmd = mock_run.call_args[0][0] - assert "base:first001" in cmd + mock_run.return_value = make_result(stdout="CREATE TABLE foo (id int);\n") + generate_sql(path) + cmd = mock_run.call_args[0][0] + assert "base:first001" in cmd -def test_raises_on_alembic_failure(tmp_path): +@patch("subprocess.run") +def test_raises_on_alembic_failure(mock_run, tmp_path): path = write_file( tmp_path, """ @@ -98,15 +95,13 @@ def upgrade(): pass """, ) - with patch( - "subprocess.run", - return_value=make_result(returncode=1, stderr="some error"), - ): - with pytest.raises(GenerateSqlError, match="alembic upgrade --sql failed"): - generate_sql(path) + mock_run.return_value = make_result(returncode=1, stderr="some error") + with pytest.raises(GenerateSqlError, match="alembic upgrade --sql failed"): + generate_sql(path) -def test_raises_when_alembic_not_found(tmp_path): +@patch("subprocess.run") +def test_raises_when_alembic_not_found(mock_run, tmp_path): path = write_file( tmp_path, """ @@ -117,12 +112,13 @@ def upgrade(): pass """, ) - with patch("subprocess.run", side_effect=FileNotFoundError): - with pytest.raises(GenerateSqlError, match="alembic not found"): - generate_sql(path) + mock_run.side_effect = FileNotFoundError + with pytest.raises(GenerateSqlError, match="alembic not found"): + generate_sql(path) -def test_provides_dummy_database_url_when_unset(tmp_path, monkeypatch): +@patch("subprocess.run") +def test_provides_dummy_database_url_when_unset(mock_run, tmp_path, monkeypatch): monkeypatch.delenv("DATABASE_URL", raising=False) path = write_file( tmp_path, @@ -134,16 +130,14 @@ def upgrade(): pass """, ) - with patch( - "subprocess.run", - return_value=make_result(stdout="SQL;\n"), - ) as mock_run: - generate_sql(path) - env = mock_run.call_args[1]["env"] - assert env["DATABASE_URL"] == "postgresql://localhost/lint" + mock_run.return_value = make_result(stdout="SQL;\n") + generate_sql(path) + env = mock_run.call_args[1]["env"] + assert env["DATABASE_URL"] == "postgresql://localhost/lint" -def test_preserves_existing_database_url(tmp_path, monkeypatch): +@patch("subprocess.run") +def test_preserves_existing_database_url(mock_run, tmp_path, monkeypatch): monkeypatch.setenv("DATABASE_URL", "postgresql://real-host/real-db") path = write_file( tmp_path, @@ -155,10 +149,7 @@ def upgrade(): pass """, ) - with patch( - "subprocess.run", - return_value=make_result(stdout="SQL;\n"), - ) as mock_run: - generate_sql(path) - env = mock_run.call_args[1]["env"] - assert env["DATABASE_URL"] == "postgresql://real-host/real-db" + mock_run.return_value = make_result(stdout="SQL;\n") + generate_sql(path) + env = mock_run.call_args[1]["env"] + assert env["DATABASE_URL"] == "postgresql://real-host/real-db" diff --git a/tests/test_main.py b/tests/test_main.py index cf66c27..6087d3a 100644 --- a/tests/test_main.py +++ b/tests/test_main.py @@ -1,5 +1,7 @@ """Tests for the main hook entrypoint.""" +import os +import sys from unittest.mock import patch from squawk_alembic.hook import main @@ -7,27 +9,28 @@ from .conftest import fake_subprocess, make_result, write_migration -def test_no_files(repo): - with patch("sys.argv", ["squawk-alembic"]): - assert main() == 0 +def test_no_files(repo, monkeypatch): + monkeypatch.setattr(sys, "argv", ["squawk-alembic"]) + assert main() == 0 def test_no_alembic_ini(tmp_path, monkeypatch, capsys): monkeypatch.chdir(tmp_path) - with patch("sys.argv", ["squawk-alembic", "some_file.py"]): - assert main() == 1 + monkeypatch.setattr(sys, "argv", ["squawk-alembic", "some_file.py"]) + assert main() == 1 captured = capsys.readouterr() assert "could not find alembic.ini" in captured.err -def test_file_outside_migrations_skipped(repo): +def test_file_outside_migrations_skipped(repo, monkeypatch): other = repo / "other.py" other.write_text("op.execute('DROP TABLE foo')") - with patch("sys.argv", ["squawk-alembic", "other.py"]): - assert main() == 0 + monkeypatch.setattr(sys, "argv", ["squawk-alembic", "other.py"]) + assert main() == 0 -def test_squawk_success(repo): +@patch("subprocess.run") +def test_squawk_success(mock_run, repo, monkeypatch): path = write_migration( repo, "002_raw_sql.py", @@ -41,20 +44,19 @@ def upgrade(): op.execute("CREATE TABLE foo (id int)") """, ) - with ( - patch("sys.argv", ["squawk-alembic", path]), - patch("subprocess.run", side_effect=fake_subprocess()) as mock_run, - ): - assert main() == 0 - assert mock_run.call_count == 2 - alembic_call = mock_run.call_args_list[0][0][0] - assert alembic_call[0] == "alembic" - assert "def456:abc123" in alembic_call - squawk_call = mock_run.call_args_list[1][0][0] - assert squawk_call[0] == "squawk" - - -def test_squawk_failure(repo, capsys): + mock_run.side_effect = fake_subprocess() + monkeypatch.setattr(sys, "argv", ["squawk-alembic", path]) + assert main() == 0 + assert mock_run.call_count == 2 + alembic_call = mock_run.call_args_list[0][0][0] + assert alembic_call[0] == "alembic" + assert "def456:abc123" in alembic_call + squawk_call = mock_run.call_args_list[1][0][0] + assert squawk_call[0] == "squawk" + + +@patch("subprocess.run") +def test_squawk_failure(mock_run, repo, capsys, monkeypatch): path = write_migration( repo, "003_bad_sql.py", @@ -68,21 +70,17 @@ def upgrade(): op.execute("ALTER TABLE foo ADD COLUMN bar int") """, ) - with ( - patch("sys.argv", ["squawk-alembic", path]), - patch( - "subprocess.run", - side_effect=fake_subprocess( - squawk_result=make_result(returncode=1, stdout="some squawk warning\n"), - ), - ), - ): - assert main() == 1 + mock_run.side_effect = fake_subprocess( + squawk_result=make_result(returncode=1, stdout="some squawk warning\n"), + ) + monkeypatch.setattr(sys, "argv", ["squawk-alembic", path]) + assert main() == 1 captured = capsys.readouterr() assert "some squawk warning" in captured.out -def test_squawk_failure_replaces_tmp_path_in_output(repo, capsys): +@patch("subprocess.run") +def test_squawk_failure_replaces_tmp_path_in_output(mock_run, repo, capsys, monkeypatch): """Squawk output should show the original migration path, not the temp file path.""" path = write_migration( repo, @@ -110,11 +108,9 @@ def side_effect(cmd, **kwargs): ) raise ValueError(f"unexpected command: {cmd}") - with ( - patch("sys.argv", ["squawk-alembic", path]), - patch("subprocess.run", side_effect=side_effect), - ): - assert main() == 1 + mock_run.side_effect = side_effect + monkeypatch.setattr(sys, "argv", ["squawk-alembic", path]) + assert main() == 1 captured = capsys.readouterr() assert path in captured.out assert path in captured.err @@ -122,7 +118,8 @@ def side_effect(cmd, **kwargs): assert "/tmp/" not in captured.err -def test_alembic_failure_fails_run(repo, capsys): +@patch("subprocess.run") +def test_alembic_failure_fails_run(mock_run, repo, capsys, monkeypatch): path = write_migration( repo, "004_alembic_fail.py", @@ -136,21 +133,16 @@ def upgrade(): op.execute("CREATE TABLE foo (id int)") """, ) - with ( - patch("sys.argv", ["squawk-alembic", path]), - patch( - "subprocess.run", - side_effect=fake_subprocess( - alembic_result=make_result(returncode=1, stderr="alembic error\n"), - ), - ), - ): - assert main() == 1 + mock_run.side_effect = fake_subprocess( + alembic_result=make_result(returncode=1, stderr="alembic error\n"), + ) + monkeypatch.setattr(sys, "argv", ["squawk-alembic", path]) + assert main() == 1 captured = capsys.readouterr() assert "alembic upgrade --sql failed" in captured.err -def test_unreadable_migration_file(repo, capsys): +def test_unreadable_migration_file(repo, capsys, monkeypatch): """A migration file that can't be opened should produce a clear error, not a traceback.""" path = write_migration( repo, @@ -163,20 +155,19 @@ def upgrade(): pass """, ) - import os - unreadable = repo / "migrations" / "versions" / "026_unreadable.py" os.chmod(unreadable, 0o000) try: - with patch("sys.argv", ["squawk-alembic", path]): - assert main() == 1 + monkeypatch.setattr(sys, "argv", ["squawk-alembic", path]) + assert main() == 1 captured = capsys.readouterr() assert "cannot read migration file" in captured.err finally: os.chmod(unreadable, 0o644) -def test_missing_alembic_binary(repo, capsys): +@patch("subprocess.run") +def test_missing_alembic_binary(mock_run, repo, capsys, monkeypatch): path = write_migration( repo, "005_no_alembic.py", @@ -196,16 +187,15 @@ def alembic_not_found(cmd, **kwargs): raise FileNotFoundError raise ValueError(f"unexpected command: {cmd}") - with ( - patch("sys.argv", ["squawk-alembic", path]), - patch("subprocess.run", side_effect=alembic_not_found), - ): - assert main() == 1 + mock_run.side_effect = alembic_not_found + monkeypatch.setattr(sys, "argv", ["squawk-alembic", path]) + assert main() == 1 captured = capsys.readouterr() assert "alembic not found" in captured.err -def test_missing_squawk_binary(repo, capsys): +@patch("subprocess.run") +def test_missing_squawk_binary(mock_run, repo, capsys, monkeypatch): """When squawk is not installed, the hook should fail with a helpful message.""" path = write_migration( repo, @@ -228,16 +218,15 @@ def squawk_not_found(cmd, **kwargs): raise FileNotFoundError raise ValueError(f"unexpected command: {cmd}") - with ( - patch("sys.argv", ["squawk-alembic", path]), - patch("subprocess.run", side_effect=squawk_not_found), - ): - assert main() == 1 + mock_run.side_effect = squawk_not_found + monkeypatch.setattr(sys, "argv", ["squawk-alembic", path]) + assert main() == 1 captured = capsys.readouterr() assert "squawk not found" in captured.err -def test_merge_migration_skipped(repo): +@patch("subprocess.run") +def test_merge_migration_skipped(mock_run, repo, monkeypatch): path = write_migration( repo, "006_merge.py", @@ -251,15 +240,13 @@ def upgrade(): pass """, ) - with ( - patch("sys.argv", ["squawk-alembic", path]), - patch("subprocess.run") as mock_run, - ): - assert main() == 0 - mock_run.assert_not_called() + monkeypatch.setattr(sys, "argv", ["squawk-alembic", path]) + assert main() == 0 + mock_run.assert_not_called() -def test_first_migration_uses_base(repo): +@patch("subprocess.run") +def test_first_migration_uses_base(mock_run, repo, monkeypatch): path = write_migration( repo, "007_first.py", @@ -273,16 +260,15 @@ def upgrade(): op.execute("CREATE TABLE foo (id int)") """, ) - with ( - patch("sys.argv", ["squawk-alembic", path]), - patch("subprocess.run", side_effect=fake_subprocess()) as mock_run, - ): - assert main() == 0 - alembic_call = mock_run.call_args_list[0][0][0] - assert "base:first001" in alembic_call + mock_run.side_effect = fake_subprocess() + monkeypatch.setattr(sys, "argv", ["squawk-alembic", path]) + assert main() == 0 + alembic_call = mock_run.call_args_list[0][0][0] + assert "base:first001" in alembic_call -def test_multiple_files_all_pass(repo): +@patch("subprocess.run") +def test_multiple_files_all_pass(mock_run, repo, monkeypatch): """All files should be processed when multiple are passed.""" path1 = write_migration( repo, @@ -310,16 +296,15 @@ def upgrade(): op.execute("CREATE TABLE b (id int)") """, ) - with ( - patch("sys.argv", ["squawk-alembic", path1, path2]), - patch("subprocess.run", side_effect=fake_subprocess()) as mock_run, - ): - assert main() == 0 - # alembic + squawk for each file = 4 calls - assert mock_run.call_count == 4 + mock_run.side_effect = fake_subprocess() + monkeypatch.setattr(sys, "argv", ["squawk-alembic", path1, path2]) + assert main() == 0 + # alembic + squawk for each file = 4 calls + assert mock_run.call_count == 4 -def test_multiple_files_first_fails_second_still_runs(repo, capsys): +@patch("subprocess.run") +def test_multiple_files_first_fails_second_still_runs(mock_run, repo, capsys, monkeypatch): """A failure in one file should not prevent linting of subsequent files.""" path1 = write_migration( repo, @@ -360,18 +345,17 @@ def side_effect(cmd, **kwargs): return make_result() raise ValueError(f"unexpected command: {cmd}") - with ( - patch("sys.argv", ["squawk-alembic", path1, path2]), - patch("subprocess.run", side_effect=side_effect) as mock_run, - ): - assert main() == 1 - # alembic (fail) + alembic (pass) + squawk (pass) = 3 - assert mock_run.call_count == 3 + mock_run.side_effect = side_effect + monkeypatch.setattr(sys, "argv", ["squawk-alembic", path1, path2]) + assert main() == 1 + # alembic (fail) + alembic (pass) + squawk (pass) = 3 + assert mock_run.call_count == 3 captured = capsys.readouterr() assert "alembic upgrade --sql failed" in captured.err -def test_diff_branch_skips_existing_file(repo): +@patch("subprocess.run") +def test_diff_branch_skips_existing_file(mock_run, repo, monkeypatch): path = write_migration( repo, "008_existing.py", @@ -385,21 +369,17 @@ def upgrade(): op.execute("CREATE TABLE foo (id int)") """, ) - with ( - patch("sys.argv", ["squawk-alembic", "--diff-branch", "main", path]), - patch( - "subprocess.run", - side_effect=fake_subprocess(git_exists_on_branch=True), - ) as mock_run, - ): - assert main() == 0 - # git rev-parse (validation) + git cat-file (exists check), no alembic or squawk - assert mock_run.call_count == 2 - assert mock_run.call_args_list[0][0][0][0] == "git" - assert mock_run.call_args_list[1][0][0][0] == "git" - - -def test_diff_branch_lints_new_file(repo): + mock_run.side_effect = fake_subprocess(git_exists_on_branch=True) + monkeypatch.setattr(sys, "argv", ["squawk-alembic", "--diff-branch", "main", path]) + assert main() == 0 + # git rev-parse (validation) + git cat-file (exists check), no alembic or squawk + assert mock_run.call_count == 2 + assert mock_run.call_args_list[0][0][0][0] == "git" + assert mock_run.call_args_list[1][0][0][0] == "git" + + +@patch("subprocess.run") +def test_diff_branch_lints_new_file(mock_run, repo, monkeypatch): path = write_migration( repo, "009_new.py", @@ -413,19 +393,15 @@ def upgrade(): op.execute("CREATE TABLE foo (id int)") """, ) - with ( - patch("sys.argv", ["squawk-alembic", "--diff-branch", "main", path]), - patch( - "subprocess.run", - side_effect=fake_subprocess(git_exists_on_branch=False), - ) as mock_run, - ): - assert main() == 0 - # git rev-parse + git cat-file + alembic + squawk = 4 calls - assert mock_run.call_count == 4 - - -def test_diff_branch_nonexistent_branch_errors(repo, capsys): + mock_run.side_effect = fake_subprocess(git_exists_on_branch=False) + monkeypatch.setattr(sys, "argv", ["squawk-alembic", "--diff-branch", "main", path]) + assert main() == 0 + # git rev-parse + git cat-file + alembic + squawk = 4 calls + assert mock_run.call_count == 4 + + +@patch("subprocess.run") +def test_diff_branch_nonexistent_branch_errors(mock_run, repo, capsys, monkeypatch): path = write_migration( repo, "011_nonexistent.py", @@ -439,21 +415,17 @@ def upgrade(): op.execute("CREATE TABLE foo (id int)") """, ) - with ( - patch("sys.argv", ["squawk-alembic", "--diff-branch", "nonexistent", path]), - patch( - "subprocess.run", - side_effect=fake_subprocess(git_branch_valid=False), - ) as mock_run, - ): - assert main() == 1 - # Only the git rev-parse validation call, then early exit - assert mock_run.call_count == 1 + mock_run.side_effect = fake_subprocess(git_branch_valid=False) + monkeypatch.setattr(sys, "argv", ["squawk-alembic", "--diff-branch", "nonexistent", path]) + assert main() == 1 + # Only the git rev-parse validation call, then early exit + assert mock_run.call_count == 1 captured = capsys.readouterr() assert "not found in git" in captured.err -def test_diff_branch_traversal_rejected(repo, capsys): +@patch("subprocess.run") +def test_diff_branch_traversal_rejected(mock_run, repo, capsys, monkeypatch): path = write_migration( repo, "013_traversal.py", @@ -467,17 +439,15 @@ def upgrade(): op.execute("CREATE TABLE foo (id int)") """, ) - with ( - patch("sys.argv", ["squawk-alembic", "--diff-branch", "refs/../main", path]), - patch("subprocess.run") as mock_run, - ): - assert main() == 1 - mock_run.assert_not_called() + monkeypatch.setattr(sys, "argv", ["squawk-alembic", "--diff-branch", "refs/../main", path]) + assert main() == 1 + mock_run.assert_not_called() captured = capsys.readouterr() assert "invalid branch name" in captured.err -def test_diff_branch_missing_git_binary(repo, capsys): +@patch("subprocess.run") +def test_diff_branch_missing_git_binary(mock_run, repo, capsys, monkeypatch): path = write_migration( repo, "014_no_git.py", @@ -491,16 +461,15 @@ def upgrade(): op.execute("CREATE TABLE foo (id int)") """, ) - with ( - patch("sys.argv", ["squawk-alembic", "--diff-branch", "main", path]), - patch("subprocess.run", side_effect=FileNotFoundError), - ): - assert main() == 1 + mock_run.side_effect = FileNotFoundError + monkeypatch.setattr(sys, "argv", ["squawk-alembic", "--diff-branch", "main", path]) + assert main() == 1 captured = capsys.readouterr() assert "git not found" in captured.err -def test_without_diff_branch_lints_all(repo): +@patch("subprocess.run") +def test_without_diff_branch_lints_all(mock_run, repo, monkeypatch): path = write_migration( repo, "010_all.py", @@ -514,16 +483,15 @@ def upgrade(): op.execute("CREATE TABLE foo (id int)") """, ) - with ( - patch("sys.argv", ["squawk-alembic", path]), - patch("subprocess.run", side_effect=fake_subprocess()) as mock_run, - ): - assert main() == 0 - # No git call, just alembic + squawk = 2 calls - assert mock_run.call_count == 2 + mock_run.side_effect = fake_subprocess() + monkeypatch.setattr(sys, "argv", ["squawk-alembic", path]) + assert main() == 0 + # No git call, just alembic + squawk = 2 calls + assert mock_run.call_count == 2 -def test_origin_branch_shallow_fetch_succeeds(repo): +@patch("subprocess.run") +def test_origin_branch_shallow_fetch_succeeds(mock_run, repo, monkeypatch): """In CI shallow clones, origin/main may not exist locally; the hook should fetch it.""" path = write_migration( repo, @@ -538,26 +506,22 @@ def upgrade(): op.execute("CREATE TABLE foo (id int)") """, ) - with ( - patch("sys.argv", ["squawk-alembic", "--diff-branch", "origin/main", path]), - patch( - "subprocess.run", - side_effect=fake_subprocess( - git_branch_valid=False, - git_fetch_succeeds=True, - git_exists_on_branch=False, - ), - ) as mock_run, - ): - assert main() == 0 - # git rev-parse (fail) + git fetch + git cat-file + alembic + squawk = 5 calls - assert mock_run.call_count == 5 - assert mock_run.call_args_list[0][0][0][0] == "git" - assert "fetch" in mock_run.call_args_list[1][0][0] - assert "cat-file" in mock_run.call_args_list[2][0][0] - - -def test_origin_branch_shallow_fetch_fails(repo, capsys): + mock_run.side_effect = fake_subprocess( + git_branch_valid=False, + git_fetch_succeeds=True, + git_exists_on_branch=False, + ) + monkeypatch.setattr(sys, "argv", ["squawk-alembic", "--diff-branch", "origin/main", path]) + assert main() == 0 + # git rev-parse (fail) + git fetch + git cat-file + alembic + squawk = 5 calls + assert mock_run.call_count == 5 + assert mock_run.call_args_list[0][0][0][0] == "git" + assert "fetch" in mock_run.call_args_list[1][0][0] + assert "cat-file" in mock_run.call_args_list[2][0][0] + + +@patch("subprocess.run") +def test_origin_branch_shallow_fetch_fails(mock_run, repo, capsys, monkeypatch): """When both rev-parse and fetch fail, the hook should error.""" path = write_migration( repo, @@ -572,24 +536,20 @@ def upgrade(): op.execute("CREATE TABLE foo (id int)") """, ) - with ( - patch("sys.argv", ["squawk-alembic", "--diff-branch", "origin/main", path]), - patch( - "subprocess.run", - side_effect=fake_subprocess( - git_branch_valid=False, - git_fetch_succeeds=False, - ), - ) as mock_run, - ): - assert main() == 1 - # git rev-parse (fail) + git fetch (fail) = 2 calls - assert mock_run.call_count == 2 + mock_run.side_effect = fake_subprocess( + git_branch_valid=False, + git_fetch_succeeds=False, + ) + monkeypatch.setattr(sys, "argv", ["squawk-alembic", "--diff-branch", "origin/main", path]) + assert main() == 1 + # git rev-parse (fail) + git fetch (fail) = 2 calls + assert mock_run.call_count == 2 captured = capsys.readouterr() assert "not found in git" in captured.err -def test_non_origin_branch_no_fetch_attempted(repo, capsys): +@patch("subprocess.run") +def test_non_origin_branch_no_fetch_attempted(mock_run, repo, capsys, monkeypatch): """Non-origin branches should not trigger a fetch attempt.""" path = write_migration( repo, @@ -604,15 +564,10 @@ def upgrade(): op.execute("CREATE TABLE foo (id int)") """, ) - with ( - patch("sys.argv", ["squawk-alembic", "--diff-branch", "main", path]), - patch( - "subprocess.run", - side_effect=fake_subprocess(git_branch_valid=False), - ) as mock_run, - ): - assert main() == 1 - # Only git rev-parse (fail), no fetch attempted - assert mock_run.call_count == 1 + mock_run.side_effect = fake_subprocess(git_branch_valid=False) + monkeypatch.setattr(sys, "argv", ["squawk-alembic", "--diff-branch", "main", path]) + assert main() == 1 + # Only git rev-parse (fail), no fetch attempted + assert mock_run.call_count == 1 captured = capsys.readouterr() assert "not found in git" in captured.err From a65eaa070f6cf76e069e12d391b5d5b9af29d06f Mon Sep 17 00:00:00 2001 From: Stephen Brannen Date: Thu, 21 May 2026 16:31:43 -0500 Subject: [PATCH 4/4] style: apply ruff formatting to test_main.py --- tests/test_main.py | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/tests/test_main.py b/tests/test_main.py index 6087d3a..0b8bda0 100644 --- a/tests/test_main.py +++ b/tests/test_main.py @@ -80,7 +80,9 @@ def upgrade(): @patch("subprocess.run") -def test_squawk_failure_replaces_tmp_path_in_output(mock_run, repo, capsys, monkeypatch): +def test_squawk_failure_replaces_tmp_path_in_output( + mock_run, repo, capsys, monkeypatch +): """Squawk output should show the original migration path, not the temp file path.""" path = write_migration( repo, @@ -304,7 +306,9 @@ def upgrade(): @patch("subprocess.run") -def test_multiple_files_first_fails_second_still_runs(mock_run, repo, capsys, monkeypatch): +def test_multiple_files_first_fails_second_still_runs( + mock_run, repo, capsys, monkeypatch +): """A failure in one file should not prevent linting of subsequent files.""" path1 = write_migration( repo, @@ -416,7 +420,9 @@ def upgrade(): """, ) mock_run.side_effect = fake_subprocess(git_branch_valid=False) - monkeypatch.setattr(sys, "argv", ["squawk-alembic", "--diff-branch", "nonexistent", path]) + monkeypatch.setattr( + sys, "argv", ["squawk-alembic", "--diff-branch", "nonexistent", path] + ) assert main() == 1 # Only the git rev-parse validation call, then early exit assert mock_run.call_count == 1 @@ -439,7 +445,9 @@ def upgrade(): op.execute("CREATE TABLE foo (id int)") """, ) - monkeypatch.setattr(sys, "argv", ["squawk-alembic", "--diff-branch", "refs/../main", path]) + monkeypatch.setattr( + sys, "argv", ["squawk-alembic", "--diff-branch", "refs/../main", path] + ) assert main() == 1 mock_run.assert_not_called() captured = capsys.readouterr() @@ -511,7 +519,9 @@ def upgrade(): git_fetch_succeeds=True, git_exists_on_branch=False, ) - monkeypatch.setattr(sys, "argv", ["squawk-alembic", "--diff-branch", "origin/main", path]) + monkeypatch.setattr( + sys, "argv", ["squawk-alembic", "--diff-branch", "origin/main", path] + ) assert main() == 0 # git rev-parse (fail) + git fetch + git cat-file + alembic + squawk = 5 calls assert mock_run.call_count == 5 @@ -540,7 +550,9 @@ def upgrade(): git_branch_valid=False, git_fetch_succeeds=False, ) - monkeypatch.setattr(sys, "argv", ["squawk-alembic", "--diff-branch", "origin/main", path]) + monkeypatch.setattr( + sys, "argv", ["squawk-alembic", "--diff-branch", "origin/main", path] + ) assert main() == 1 # git rev-parse (fail) + git fetch (fail) = 2 calls assert mock_run.call_count == 2