├── .github ├── CODE_OF_CONDUCT.md ├── FUNDING.yml ├── PULL_REQUEST_TEMPLATE.md ├── labels.toml └── workflows │ ├── ci.yml │ ├── codeql.yml │ ├── hacktoberfest.yml │ ├── issue-manager.yml │ ├── labels.yml │ └── upgrader.yml ├── .gitignore ├── .gitpod.yml ├── .pre-commit-config.yaml ├── CHANGELOG.md ├── README.md ├── commitlint.config.mjs ├── pyproject.toml ├── renovate.json ├── src └── flake8_django_migrations │ ├── __init__.py │ ├── checkers │ ├── __init__.py │ ├── base.py │ ├── issue.py │ └── remove_field.py │ └── plugin.py ├── templates ├── .changelog-old.md └── CHANGELOG.md.j2 ├── tests └── test_flake8_django_migrations.py └── uv.lock /.github/CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | We as members, contributors, and leaders pledge to make participation in our 6 | community a harassment-free experience for everyone, regardless of age, body 7 | size, visible or invisible disability, ethnicity, sex characteristics, gender 8 | identity and expression, level of experience, education, socioeconomic status, 9 | nationality, personal appearance, race, religion, or sexual identity 10 | and orientation. 11 | 12 | We pledge to act and interact in ways that contribute to an open, welcoming, 13 | diverse, inclusive, and healthy community. 14 | 15 | ## Our Standards 16 | 17 | Examples of behavior that contributes to a positive environment for our 18 | community include: 19 | 20 | - Demonstrating empathy and kindness toward other people 21 | - Being respectful of differing opinions, viewpoints, and experiences 22 | - Giving and gracefully accepting constructive feedback 23 | - Accepting responsibility and apologizing to those affected by our mistakes, 24 | and learning from the experience 25 | - Focusing on what is best not just for us as individuals, but for the 26 | overall community 27 | 28 | Examples of unacceptable behavior include: 29 | 30 | - The use of sexualized language or imagery, and sexual attention or 31 | advances of any kind 32 | - Trolling, insulting or derogatory comments, and personal or political attacks 33 | - Public or private harassment 34 | - Publishing others' private information, such as a physical or email 35 | address, without their explicit permission 36 | - Other conduct which could reasonably be considered inappropriate in a 37 | professional setting 38 | 39 | ## Enforcement Responsibilities 40 | 41 | Community leaders are responsible for clarifying and enforcing our standards of 42 | acceptable behavior and will take appropriate and fair corrective action in 43 | response to any behavior that they deem inappropriate, threatening, offensive, 44 | or harmful. 45 | 46 | Community leaders have the right and responsibility to remove, edit, or reject 47 | comments, commits, code, wiki edits, issues, and other contributions that are 48 | not aligned to this Code of Conduct, and will communicate reasons for moderation 49 | decisions when appropriate. 50 | 51 | ## Scope 52 | 53 | This Code of Conduct applies within all community spaces, and also applies when 54 | an individual is officially representing the community in public spaces. 55 | Examples of representing our community include using an official e-mail address, 56 | posting via an official social media account, or acting as an appointed 57 | representative at an online or offline event. 58 | 59 | ## Enforcement 60 | 61 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 62 | reported by contacting @browniebroke. All complaints will be reviewed and 63 | investigated promptly and fairly. 64 | 65 | All community leaders are obligated to respect the privacy and security of the 66 | reporter of any incident. 67 | 68 | ## Enforcement Guidelines 69 | 70 | Community leaders will follow these Community Impact Guidelines in determining 71 | the consequences for any action they deem in violation of this Code of Conduct: 72 | 73 | ### 1. Correction 74 | 75 | **Community Impact**: Use of inappropriate language or other behavior deemed 76 | unprofessional or unwelcome in the community. 77 | 78 | **Consequence**: A private, written warning from community leaders, providing 79 | clarity around the nature of the violation and an explanation of why the 80 | behavior was inappropriate. A public apology may be requested. 81 | 82 | ### 2. Warning 83 | 84 | **Community Impact**: A violation through a single incident or series 85 | of actions. 86 | 87 | **Consequence**: A warning with consequences for continued behavior. No 88 | interaction with the people involved, including unsolicited interaction with 89 | those enforcing the Code of Conduct, for a specified period of time. This 90 | includes avoiding interactions in community spaces as well as external channels 91 | like social media. Violating these terms may lead to a temporary or 92 | permanent ban. 93 | 94 | ### 3. Temporary Ban 95 | 96 | **Community Impact**: A serious violation of community standards, including 97 | sustained inappropriate behavior. 98 | 99 | **Consequence**: A temporary ban from any sort of interaction or public 100 | communication with the community for a specified period of time. No public or 101 | private interaction with the people involved, including unsolicited interaction 102 | with those enforcing the Code of Conduct, is allowed during this period. 103 | Violating these terms may lead to a permanent ban. 104 | 105 | ### 4. Permanent Ban 106 | 107 | **Community Impact**: Demonstrating a pattern of violation of community 108 | standards, including sustained inappropriate behavior, harassment of an 109 | individual, or aggression toward or disparagement of classes of individuals. 110 | 111 | **Consequence**: A permanent ban from any sort of public interaction within 112 | the community. 113 | 114 | ## Attribution 115 | 116 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], 117 | version 2.0, available at 118 | https://www.contributor-covenant.org/version/2/0/code_of_conduct.html. 119 | 120 | Community Impact Guidelines were inspired by [Mozilla's code of conduct 121 | enforcement ladder](https://github.com/mozilla/diversity). 122 | 123 | [homepage]: https://www.contributor-covenant.org 124 | 125 | For answers to common questions about this code of conduct, see the FAQ at 126 | https://www.contributor-covenant.org/faq. Translations are available at 127 | https://www.contributor-covenant.org/translations. 128 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: [browniebroke] 2 | patreon: browniebroke 3 | custom: ["https://paypal.me/browneibroke"] 4 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 9 | 10 | ### Description of change 11 | 12 | 25 | 26 | ### Pull-Request Checklist 27 | 28 | 35 | 36 | - [ ] Code is up-to-date with the `main` branch 37 | - [ ] This pull request follows the [contributing guidelines](https://github.com/browniebroke/django-admin-helpers/blob/main/CONTRIBUTING.md). 38 | - [ ] This pull request links relevant issues as `Fixes #0000` 39 | - [ ] There are new or updated unit tests validating the change 40 | - [ ] Documentation has been updated to reflect this change 41 | - [ ] The new commits follow conventions outlined in the [conventional commit spec](https://www.conventionalcommits.org/en/v1.0.0/), such as "fix(api): prevent racing of requests". 42 | 43 | > - If pre-commit.ci is failing, try `pre-commit run -a` for further information. 44 | > - If CI / test is failing, try `uv run pytest` for further information. 45 | 46 | 49 | -------------------------------------------------------------------------------- /.github/labels.toml: -------------------------------------------------------------------------------- 1 | [breaking] 2 | color = "ffcc00" 3 | name = "breaking" 4 | description = "Breaking change." 5 | 6 | [bug] 7 | color = "d73a4a" 8 | name = "bug" 9 | description = "Something isn't working" 10 | 11 | [dependencies] 12 | color = "0366d6" 13 | name = "dependencies" 14 | description = "Pull requests that update a dependency file" 15 | 16 | [github_actions] 17 | color = "000000" 18 | name = "github_actions" 19 | description = "Update of github actions" 20 | 21 | [documentation] 22 | color = "1bc4a5" 23 | name = "documentation" 24 | description = "Improvements or additions to documentation" 25 | 26 | [duplicate] 27 | color = "cfd3d7" 28 | name = "duplicate" 29 | description = "This issue or pull request already exists" 30 | 31 | [enhancement] 32 | color = "a2eeef" 33 | name = "enhancement" 34 | description = "New feature or request" 35 | 36 | ["good first issue"] 37 | color = "7057ff" 38 | name = "good first issue" 39 | description = "Good for newcomers" 40 | 41 | ["help wanted"] 42 | color = "008672" 43 | name = "help wanted" 44 | description = "Extra attention is needed" 45 | 46 | [invalid] 47 | color = "e4e669" 48 | name = "invalid" 49 | description = "This doesn't seem right" 50 | 51 | [nochangelog] 52 | color = "555555" 53 | name = "nochangelog" 54 | description = "Exclude pull requests from changelog" 55 | 56 | [question] 57 | color = "d876e3" 58 | name = "question" 59 | description = "Further information is requested" 60 | 61 | [removed] 62 | color = "e99695" 63 | name = "removed" 64 | description = "Removed piece of functionalities." 65 | 66 | [tests] 67 | color = "bfd4f2" 68 | name = "tests" 69 | description = "CI, CD and testing related changes" 70 | 71 | [wontfix] 72 | color = "ffffff" 73 | name = "wontfix" 74 | description = "This will not be worked on" 75 | 76 | [discussion] 77 | color = "c2e0c6" 78 | name = "discussion" 79 | description = "Some discussion around the project" 80 | 81 | [hacktoberfest] 82 | color = "ffa663" 83 | name = "hacktoberfest" 84 | description = "Good issues for Hacktoberfest" 85 | 86 | [answered] 87 | color = "0ee2b6" 88 | name = "answered" 89 | description = "Automatically closes as answered after a delay" 90 | 91 | [waiting] 92 | color = "5f7972" 93 | name = "waiting" 94 | description = "Automatically closes if no answer after a delay" 95 | 96 | [fund] 97 | color = "0E8A16" 98 | name = "fund" 99 | description = "Add a section linking to polar.sh for funding the issue." 100 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | pull_request: 8 | 9 | concurrency: 10 | group: ${{ github.head_ref || github.run_id }} 11 | cancel-in-progress: true 12 | 13 | jobs: 14 | test: 15 | runs-on: ${{ matrix.os }} 16 | strategy: 17 | fail-fast: false 18 | matrix: 19 | python-version: 20 | - "3.9" 21 | - "3.10" 22 | - "3.11" 23 | - "3.12" 24 | - "3.13" 25 | os: 26 | - ubuntu-latest 27 | - windows-latest 28 | - macOS-latest 29 | 30 | steps: 31 | - uses: actions/checkout@v4 32 | - uses: actions/setup-python@v5 33 | with: 34 | python-version: ${{ matrix.python-version }} 35 | - uses: astral-sh/setup-uv@v6 36 | - run: uv sync --no-python-downloads 37 | shell: bash 38 | - run: uv run pytest --cov-report=xml 39 | shell: bash 40 | - uses: codecov/codecov-action@v5 41 | with: 42 | token: ${{ secrets.CODECOV_TOKEN }} 43 | 44 | commitlint: 45 | runs-on: ubuntu-latest 46 | steps: 47 | - uses: actions/checkout@v4 48 | with: 49 | fetch-depth: 0 50 | - uses: wagoid/commitlint-github-action@v6.2.1 51 | 52 | release: 53 | needs: 54 | - test 55 | - commitlint 56 | 57 | runs-on: ubuntu-latest 58 | environment: release 59 | concurrency: release 60 | permissions: 61 | id-token: write 62 | attestations: write 63 | contents: write 64 | 65 | steps: 66 | - uses: actions/checkout@v4 67 | with: 68 | fetch-depth: 0 69 | ref: ${{ github.sha }} 70 | 71 | - name: Checkout commit for release 72 | run: | 73 | git checkout -B ${{ github.ref_name }} ${{ github.sha }} 74 | 75 | # Do a dry run of PSR 76 | - name: Test release 77 | uses: python-semantic-release/python-semantic-release@v10 78 | if: github.ref_name != 'main' 79 | with: 80 | no_operation_mode: true 81 | 82 | # On main branch: actual PSR + upload to PyPI & GitHub 83 | - name: Release 84 | uses: python-semantic-release/python-semantic-release@v10 85 | id: release 86 | if: github.ref_name == 'main' 87 | with: 88 | github_token: ${{ secrets.GITHUB_TOKEN }} 89 | 90 | - name: Attest build provenance 91 | uses: actions/attest-build-provenance@v2 92 | if: steps.release.outputs.released == 'true' 93 | with: 94 | subject-path: "dist/*" 95 | 96 | - name: Publish package distributions to PyPI 97 | uses: pypa/gh-action-pypi-publish@release/v1 98 | if: steps.release.outputs.released == 'true' 99 | 100 | - name: Publish package distributions to GitHub Releases 101 | uses: python-semantic-release/publish-action@v10 102 | if: steps.release.outputs.released == 'true' 103 | with: 104 | github_token: ${{ secrets.GITHUB_TOKEN }} 105 | tag: ${{ steps.release.outputs.tag }} 106 | -------------------------------------------------------------------------------- /.github/workflows/codeql.yml: -------------------------------------------------------------------------------- 1 | name: "CodeQL" 2 | 3 | on: 4 | push: 5 | branches: ["main"] 6 | pull_request: 7 | branches: ["main"] 8 | schedule: 9 | - cron: "34 23 * * 0" 10 | 11 | jobs: 12 | analyze: 13 | name: Analyze 14 | runs-on: ubuntu-latest 15 | permissions: 16 | actions: read 17 | contents: read 18 | security-events: write 19 | 20 | strategy: 21 | fail-fast: false 22 | matrix: 23 | language: [javascript, python] 24 | 25 | steps: 26 | - name: Checkout 27 | uses: actions/checkout@v4 28 | 29 | - name: Initialize CodeQL 30 | uses: github/codeql-action/init@v3 31 | with: 32 | languages: ${{ matrix.language }} 33 | queries: +security-and-quality 34 | 35 | - name: Autobuild 36 | uses: github/codeql-action/autobuild@v3 37 | if: ${{ matrix.language == 'javascript' || matrix.language == 'python' }} 38 | 39 | - name: Perform CodeQL Analysis 40 | uses: github/codeql-action/analyze@v3 41 | with: 42 | category: "/language:${{ matrix.language }}" 43 | -------------------------------------------------------------------------------- /.github/workflows/hacktoberfest.yml: -------------------------------------------------------------------------------- 1 | name: Hacktoberfest 2 | 3 | on: 4 | schedule: 5 | # Run every day in October 6 | - cron: "0 0 * 10 *" 7 | # Run on the 1st of November to revert 8 | - cron: "0 13 1 11 *" 9 | 10 | jobs: 11 | hacktoberfest: 12 | runs-on: ubuntu-latest 13 | 14 | steps: 15 | - uses: browniebroke/hacktoberfest-labeler-action@v2.3.0 16 | with: 17 | github_token: ${{ secrets.CPR_GITHUB_TOKEN }} 18 | -------------------------------------------------------------------------------- /.github/workflows/issue-manager.yml: -------------------------------------------------------------------------------- 1 | name: Issue Manager 2 | 3 | on: 4 | schedule: 5 | - cron: "0 0 * * *" 6 | issue_comment: 7 | types: 8 | - created 9 | issues: 10 | types: 11 | - labeled 12 | pull_request_target: 13 | types: 14 | - labeled 15 | workflow_dispatch: 16 | 17 | jobs: 18 | issue-manager: 19 | runs-on: ubuntu-latest 20 | steps: 21 | - uses: tiangolo/issue-manager@0.5.1 22 | with: 23 | token: ${{ secrets.GITHUB_TOKEN }} 24 | config: > 25 | { 26 | "answered": { 27 | "message": "Assuming the original issue was solved, it will be automatically closed now." 28 | }, 29 | "waiting": { 30 | "message": "Automatically closing. To re-open, please provide the additional information requested." 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /.github/workflows/labels.yml: -------------------------------------------------------------------------------- 1 | name: Sync Github labels 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | paths: 8 | - ".github/**" 9 | 10 | jobs: 11 | labels: 12 | runs-on: ubuntu-latest 13 | steps: 14 | - uses: actions/checkout@v4 15 | - name: Set up Python 16 | uses: actions/setup-python@v5 17 | with: 18 | python-version: 3.x 19 | - name: Install labels 20 | run: pip install labels 21 | - name: Sync config with Github 22 | run: labels -u ${{ github.repository_owner }} -t ${{ secrets.GITHUB_TOKEN }} sync -f .github/labels.toml 23 | -------------------------------------------------------------------------------- /.github/workflows/upgrader.yml: -------------------------------------------------------------------------------- 1 | name: Upgrader 2 | 3 | on: 4 | workflow_dispatch: 5 | schedule: 6 | - cron: "50 8 6 1-9,11-12 *" 7 | 8 | jobs: 9 | upgrade: 10 | uses: browniebroke/github-actions/.github/workflows/uv-upgrade.yml@v1 11 | secrets: 12 | gh_pat: ${{ secrets.GH_PERSONAL_ACCESS_TOKEN }} 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | env/ 12 | build/ 13 | develop-eggs/ 14 | dist/ 15 | downloads/ 16 | eggs/ 17 | .eggs/ 18 | lib/ 19 | lib64/ 20 | parts/ 21 | sdist/ 22 | var/ 23 | wheels/ 24 | *.egg-info/ 25 | .installed.cfg 26 | *.egg 27 | 28 | # PyInstaller 29 | # Usually these files are written by a python script from a template 30 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 31 | *.manifest 32 | *.spec 33 | 34 | # Installer logs 35 | pip-log.txt 36 | pip-delete-this-directory.txt 37 | 38 | # Unit test / coverage reports 39 | htmlcov/ 40 | .tox/ 41 | .coverage 42 | .coverage.* 43 | .cache 44 | nosetests.xml 45 | coverage.xml 46 | *.cover 47 | .hypothesis/ 48 | .pytest_cache/ 49 | 50 | # Translations 51 | *.mo 52 | *.pot 53 | 54 | # Django stuff: 55 | *.log 56 | local_settings.py 57 | 58 | # Flask stuff: 59 | instance/ 60 | .webassets-cache 61 | 62 | # Scrapy stuff: 63 | .scrapy 64 | 65 | # Sphinx documentation 66 | docs/_build/ 67 | 68 | # PyBuilder 69 | target/ 70 | 71 | # Jupyter Notebook 72 | .ipynb_checkpoints 73 | 74 | # pyenv 75 | .python-version 76 | 77 | # celery beat schedule file 78 | celerybeat-schedule 79 | 80 | # SageMath parsed files 81 | *.sage.py 82 | 83 | # dotenv 84 | .env 85 | 86 | # virtualenv 87 | .venv 88 | venv/ 89 | ENV/ 90 | 91 | # Spyder project settings 92 | .spyderproject 93 | .spyproject 94 | 95 | # Rope project settings 96 | .ropeproject 97 | 98 | # mkdocs documentation 99 | /site 100 | 101 | # mypy 102 | .mypy_cache/ 103 | 104 | # pytest 105 | .pytest_cache/ 106 | 107 | mypy-report/ 108 | tests/reports/ 109 | -------------------------------------------------------------------------------- /.gitpod.yml: -------------------------------------------------------------------------------- 1 | tasks: 2 | - command: | 3 | pip install uv 4 | PIP_USER=false uv sync 5 | - command: | 6 | pip install pre-commit 7 | pre-commit install 8 | PIP_USER=false pre-commit install-hooks 9 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | # See https://pre-commit.com for more information 2 | # See https://pre-commit.com/hooks.html for more hooks 3 | exclude: "CHANGELOG.md|.all-contributorsrc" 4 | default_stages: [pre-commit] 5 | 6 | ci: 7 | autofix_commit_msg: "chore(pre-commit.ci): auto fixes" 8 | autoupdate_commit_msg: "chore(pre-commit.ci): pre-commit autoupdate" 9 | 10 | repos: 11 | - repo: https://github.com/pre-commit/pre-commit-hooks 12 | rev: v5.0.0 13 | hooks: 14 | - id: debug-statements 15 | - id: check-builtin-literals 16 | - id: check-case-conflict 17 | - id: check-docstring-first 18 | - id: check-json 19 | - id: check-toml 20 | - id: check-xml 21 | - id: check-yaml 22 | - id: detect-private-key 23 | - id: end-of-file-fixer 24 | - id: trailing-whitespace 25 | - id: debug-statements 26 | - repo: https://github.com/tox-dev/pyproject-fmt 27 | rev: "v2.6.0" 28 | hooks: 29 | - id: pyproject-fmt 30 | - repo: https://github.com/astral-sh/uv-pre-commit 31 | rev: 0.7.10 32 | hooks: 33 | - id: uv-lock 34 | - repo: https://github.com/pre-commit/mirrors-prettier 35 | rev: v3.1.0 36 | hooks: 37 | - id: prettier 38 | args: ["--tab-width", "2"] 39 | - repo: https://github.com/astral-sh/ruff-pre-commit 40 | rev: v0.11.12 41 | hooks: 42 | - id: ruff 43 | args: [--fix, --exit-non-zero-on-fix] 44 | - id: ruff-format 45 | - repo: https://github.com/codespell-project/codespell 46 | rev: v2.4.1 47 | hooks: 48 | - id: codespell 49 | - repo: https://github.com/commitizen-tools/commitizen 50 | rev: v4.8.2 51 | hooks: 52 | - id: commitizen 53 | stages: [commit-msg] 54 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # CHANGELOG 2 | 3 | ## v1.1.0 (2024-10-31) 4 | 5 | ### Features 6 | 7 | - Drop support for python 3.8 (#650) ([`9c6e6d7`](https://github.com/browniebroke/flake8-django-migrations/commit/9c6e6d709593e35a28e1a25e06fa611cb3f8ae9c)) 8 | 9 | ## v1.0.0 (2023-06-27) 10 | 11 | ### Feature 12 | 13 | - Drop support for Python 3.7 ([`d41a017`](https://github.com/browniebroke/flake8-django-migrations/commit/d41a017ef1a830c59d9b287694eddc1aad65bd64)) 14 | 15 | ### Breaking 16 | 17 | - Drop support for Python 3.7 as it reached EOL on June 27, 2023. More infos: https://devguide.python.org/versions/ ([`d41a017`](https://github.com/browniebroke/flake8-django-migrations/commit/d41a017ef1a830c59d9b287694eddc1aad65bd64)) 18 | 19 | ### Documentation 20 | 21 | - Update badge for CI workflow ([#333](https://github.com/browniebroke/flake8-django-migrations/issues/333)) ([`9072f9c`](https://github.com/browniebroke/flake8-django-migrations/commit/9072f9c56a8293f0bc578c8af0bf73efc23fa1ac)) 22 | 23 | ## v0.3.0 (2022-11-20) 24 | 25 | ### Feature 26 | 27 | - Officially support Python 3.10 & 3.11 ([#301](https://github.com/browniebroke/flake8-django-migrations/issues/301)) ([`10a2572`](https://github.com/browniebroke/flake8-django-migrations/commit/10a25729ef8fb34f37b7b3490c858e076040d673)) 28 | 29 | ## v0.2.1 (2022-06-06) 30 | 31 | ### Fix 32 | 33 | - **deps:** Revert PSR upgrade ([`a7f4cf7`](https://github.com/browniebroke/flake8-django-migrations/commit/a7f4cf762a3c6ccb2283532f552520c9ae3c98ec)) 34 | 35 | ## v0.2.0 (2022-01-24) 36 | 37 | ### Feature 38 | 39 | - Drop support for Python 3.6 ([`cda2daa`](https://github.com/browniebroke/flake8-django-migrations/commit/cda2daa7a31d956a87f46862a83253f7535a5c36)) 40 | 41 | ## v0.1.1 (2021-04-06) 42 | 43 | ### Fix 44 | 45 | - Release in a separate environment ([`71550b8`](https://github.com/browniebroke/flake8-django-migrations/commit/71550b8d06f245d6d6046312ba77002185a8a990)) 46 | 47 | ## v0.1.0 (2020-11-10) 48 | 49 | ### Feature 50 | 51 | - DM001: `RemoveField` operation should be wrapped in `SeparateDatabaseAndState` ([`c571e0e`](https://github.com/browniebroke/flake8-django-migrations/commit/c571e0e026fbef9ba85782ff562cbdf9c6a763ed)) 52 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # flake8-django-migrations 2 | 3 |

4 | 5 | CI Status 6 | 7 | 8 | Test coverage percentage 9 | 10 |

11 |

12 | 13 | uv 14 | 15 | 16 | Ruff 17 | 18 | 19 | pre-commit 20 | 21 |

22 |

23 | 24 | PyPi Status 25 | 26 | pyversions 27 | license 28 |

29 | 30 | --- 31 | 32 | **Source Code**: https://github.com/browniebroke/flake8-django-migrations 33 | 34 | --- 35 | 36 | Flake8 plugin to lint for backwards incompatible database migrations. 37 | 38 | ## Installation 39 | 40 | Install using `pip` (or your favourite package manager): 41 | 42 | ```sh 43 | pip install flake8-django-migrations 44 | ``` 45 | 46 | ## Usage 47 | 48 | This plugin should be used automatically when running flake8: 49 | 50 | ```sh 51 | flake8 52 | ``` 53 | 54 | ## Checks 55 | 56 | This is the list of checks currently implemented by this plugin. 57 | 58 | ### DM001 59 | 60 | `RemoveField` operation should be wrapped in `SeparateDatabaseAndState`. 61 | 62 | Such an operation should be run in two separate steps, using `SeparateDatabaseAndState`, otherwise it is not backwards compatible. 63 | 64 | - Step 1: remove the field from the model and code. For foreign key fields, the foreign key constraint should also be dropped. 65 | - Step 2: remove the column from the database. 66 | 67 | #### Bad 68 | 69 | ```python 70 | class Migration(migrations.Migration): 71 | operations = [ 72 | migrations.RemoveField( 73 | model_name="order", 74 | name="total", 75 | ), 76 | ] 77 | ``` 78 | 79 | #### Good 80 | 81 | ```python 82 | class Migration(migrations.Migration): 83 | operations = [ 84 | migrations.SeparateDatabaseAndState( 85 | state_operations=[ 86 | migrations.RemoveField( 87 | model_name="order", 88 | name="total", 89 | ), 90 | ], 91 | ), 92 | ] 93 | ``` 94 | -------------------------------------------------------------------------------- /commitlint.config.mjs: -------------------------------------------------------------------------------- 1 | export default { 2 | extends: ["@commitlint/config-conventional"], 3 | rules: { 4 | "header-max-length": [0, "always", Infinity], 5 | "body-max-line-length": [0, "always", Infinity], 6 | "footer-max-line-length": [0, "always", Infinity], 7 | }, 8 | }; 9 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [build-system] 2 | build-backend = "setuptools.build_meta" 3 | requires = [ "setuptools" ] 4 | 5 | [project] 6 | name = "flake8-django-migrations" 7 | version = "1.1.0" 8 | description = "Flake8 plugin to lint for backwards incompatible database migrations" 9 | readme = "README.md" 10 | keywords = [ 11 | "django", 12 | "flake8", 13 | "lint", 14 | "migrations", 15 | ] 16 | license = { text = "MIT" } 17 | authors = [ 18 | { name = "Bruno Alla", email = "bruno.alla@festicket.com" }, 19 | ] 20 | requires-python = ">=3.9" 21 | classifiers = [ 22 | "Development Status :: 1 - Planning", 23 | "Environment :: Console", 24 | "Framework :: Flake8", 25 | "Intended Audience :: Developers", 26 | "Natural Language :: English", 27 | "Operating System :: OS Independent", 28 | "Programming Language :: Python :: 3 :: Only", 29 | "Programming Language :: Python :: 3.9", 30 | "Programming Language :: Python :: 3.10", 31 | "Programming Language :: Python :: 3.11", 32 | "Programming Language :: Python :: 3.12", 33 | "Programming Language :: Python :: 3.13", 34 | "Topic :: Software Development :: Quality Assurance", 35 | ] 36 | 37 | dependencies = [ 38 | "astor>=0.1", 39 | "flake8>=3.7", 40 | "importlib-metadata>=0.9; python_version<'3.8'", 41 | ] 42 | urls.repository = "https://github.com/browniebroke/flake8-django-migrations" 43 | entry-points."flake8.extension".DM = "flake8_django_migrations:Plugin" 44 | 45 | [dependency-groups] 46 | dev = [ 47 | "pytest>=8,<9", 48 | "pytest-cov>=6,<7", 49 | ] 50 | 51 | [tool.ruff] 52 | line-length = 88 53 | 54 | lint.select = [ 55 | "B", # flake8-bugbear 56 | "C4", # flake8-comprehensions 57 | "D", # flake8-docstrings 58 | "E", # pycodestyle 59 | "F", # pyflake 60 | "I", # isort 61 | "RUF", # ruff specific 62 | "S", # flake8-bandit 63 | "UP", # pyupgrade 64 | "W", # pycodestyle 65 | ] 66 | lint.ignore = [ 67 | "D100", # Missing docstring in public module 68 | "D104", # Missing docstring in public package 69 | "D107", # Missing docstring in `__init__` 70 | "D203", # 1 blank line required before class docstring 71 | "D212", # Multi-line docstring summary should start at the first line 72 | "D401", # First line of docstring should be in imperative mood 73 | ] 74 | lint.per-file-ignores."tests/**/*" = [ 75 | "D100", 76 | "D101", 77 | "D102", 78 | "D103", 79 | "D104", 80 | "S101", 81 | ] 82 | lint.isort.known-first-party = [ "flake8_django_migrations" ] 83 | 84 | [tool.pytest.ini_options] 85 | addopts = "-v -Wdefault --cov=flake8_django_migrations" 86 | pythonpath = [ "src" ] 87 | 88 | [tool.coverage.run] 89 | branch = true 90 | source = [ "flake8_django_migrations" ] 91 | 92 | [tool.coverage.report] 93 | ignore_errors = true 94 | 95 | [tool.semantic_release.branches.main] 96 | match = "main" 97 | 98 | [tool.semantic_release.branches.noop] 99 | match = "(?!main$)" 100 | prerelease = true 101 | 102 | [tool.semantic_release] 103 | version_toml = [ "pyproject.toml:project.version" ] 104 | version_variables = [ 105 | "src/flake8_django_migrations/__init__.py:__version__", 106 | ] 107 | build_command = """ 108 | pip install uv 109 | uv lock 110 | git add uv.lock 111 | uv build 112 | """ 113 | 114 | [tool.semantic_release.changelog] 115 | exclude_commit_patterns = [ 116 | "chore.*", 117 | "ci.*", 118 | "Merge pull request .*", 119 | ] 120 | 121 | [tool.semantic_release.changelog.environment] 122 | keep_trailing_newline = true 123 | -------------------------------------------------------------------------------- /renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["github>browniebroke/renovate-configs:python"] 3 | } 4 | -------------------------------------------------------------------------------- /src/flake8_django_migrations/__init__.py: -------------------------------------------------------------------------------- 1 | from .plugin import Plugin 2 | 3 | __version__ = "1.1.0" 4 | __all__ = ("Plugin",) 5 | -------------------------------------------------------------------------------- /src/flake8_django_migrations/checkers/__init__.py: -------------------------------------------------------------------------------- 1 | import logging 2 | 3 | logger = logging.getLogger(__name__) 4 | -------------------------------------------------------------------------------- /src/flake8_django_migrations/checkers/base.py: -------------------------------------------------------------------------------- 1 | import ast 2 | 3 | 4 | class Checker: 5 | """Base class for the plugin.""" 6 | 7 | @staticmethod 8 | def get_call_name(node: ast.Call): 9 | """Return call name for the given node.""" 10 | if isinstance(node.func, ast.Attribute): 11 | return node.func.attr 12 | elif isinstance(node.func, ast.Name): 13 | return node.func.id 14 | 15 | def run(self, node: ast.expr): 16 | """Entry point to be implemented in subclasses.""" 17 | raise NotImplementedError() 18 | -------------------------------------------------------------------------------- /src/flake8_django_migrations/checkers/issue.py: -------------------------------------------------------------------------------- 1 | class Issue: 2 | """Represent data points about a single issue.""" 3 | 4 | code: str 5 | message: str 6 | lineno: int 7 | col: int 8 | -------------------------------------------------------------------------------- /src/flake8_django_migrations/checkers/remove_field.py: -------------------------------------------------------------------------------- 1 | import ast 2 | from typing import Any 3 | 4 | from .base import Checker 5 | from .issue import Issue 6 | 7 | 8 | class DM001(Issue): 9 | """Dangerous RemoveField operation.""" 10 | 11 | code: str = "DM001" 12 | message: str = ( 13 | f"{code} RemoveField operation should be wrapped in SeparateDatabaseAndState" 14 | ) 15 | 16 | def __init__(self, lineno: int, col: int) -> None: 17 | self.lineno = lineno 18 | self.col = col 19 | 20 | 21 | class RemoveFieldChecker(Checker): 22 | """Checker that detects dangerous RemoveField operation.""" 23 | 24 | def run(self, node: ast.Call) -> Any: 25 | """Check whether the operation is safe.""" 26 | issues = [] 27 | call_name = self.get_call_name(node) 28 | if call_name == "SeparateDatabaseAndState": 29 | pass 30 | elif call_name == "RemoveField": 31 | issues.append(DM001(lineno=node.lineno, col=node.col_offset)) 32 | return issues 33 | -------------------------------------------------------------------------------- /src/flake8_django_migrations/plugin.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | import ast 4 | import importlib.metadata as importlib_metadata 5 | from collections.abc import Generator 6 | from typing import Any, ClassVar 7 | 8 | from .checkers.base import Checker 9 | from .checkers.issue import Issue 10 | from .checkers.remove_field import RemoveFieldChecker 11 | 12 | 13 | class Visitor(ast.NodeVisitor): 14 | """Custom AST visitor.""" 15 | 16 | checkers: ClassVar[list[Checker]] = [RemoveFieldChecker()] 17 | 18 | def __init__(self) -> None: 19 | self.issues: list[Issue] = [] 20 | 21 | def visit_Call(self, node: ast.Call) -> Any: 22 | """Called when visiting a function called.""" 23 | for checker in self.checkers: 24 | issues = checker.run(node) 25 | if issues: 26 | self.issues.extend(issues) 27 | 28 | 29 | class Plugin: 30 | """Declare the flake8 plugin.""" 31 | 32 | name = "flake8_django_migrations" 33 | version = importlib_metadata.version(name) 34 | 35 | def __init__(self, tree: ast.AST): 36 | self._tree = tree 37 | 38 | def run(self) -> Generator[tuple[int, int, str, type[Any]], None, None]: 39 | """Plugin entry point.""" 40 | visitor = Visitor() 41 | visitor.visit(self._tree) 42 | 43 | for issue in visitor.issues: 44 | yield issue.lineno, issue.col, issue.message, type(self) 45 | -------------------------------------------------------------------------------- /templates/.changelog-old.md: -------------------------------------------------------------------------------- 1 | ## v1.0.0 (2023-06-27) 2 | 3 | ### Feature 4 | 5 | - Drop support for Python 3.7 ([`d41a017`](https://github.com/browniebroke/flake8-django-migrations/commit/d41a017ef1a830c59d9b287694eddc1aad65bd64)) 6 | 7 | ### Breaking 8 | 9 | - Drop support for Python 3.7 as it reached EOL on June 27, 2023. More infos: https://devguide.python.org/versions/ ([`d41a017`](https://github.com/browniebroke/flake8-django-migrations/commit/d41a017ef1a830c59d9b287694eddc1aad65bd64)) 10 | 11 | ### Documentation 12 | 13 | - Update badge for CI workflow ([#333](https://github.com/browniebroke/flake8-django-migrations/issues/333)) ([`9072f9c`](https://github.com/browniebroke/flake8-django-migrations/commit/9072f9c56a8293f0bc578c8af0bf73efc23fa1ac)) 14 | 15 | ## v0.3.0 (2022-11-20) 16 | 17 | ### Feature 18 | 19 | - Officially support Python 3.10 & 3.11 ([#301](https://github.com/browniebroke/flake8-django-migrations/issues/301)) ([`10a2572`](https://github.com/browniebroke/flake8-django-migrations/commit/10a25729ef8fb34f37b7b3490c858e076040d673)) 20 | 21 | ## v0.2.1 (2022-06-06) 22 | 23 | ### Fix 24 | 25 | - **deps:** Revert PSR upgrade ([`a7f4cf7`](https://github.com/browniebroke/flake8-django-migrations/commit/a7f4cf762a3c6ccb2283532f552520c9ae3c98ec)) 26 | 27 | ## v0.2.0 (2022-01-24) 28 | 29 | ### Feature 30 | 31 | - Drop support for Python 3.6 ([`cda2daa`](https://github.com/browniebroke/flake8-django-migrations/commit/cda2daa7a31d956a87f46862a83253f7535a5c36)) 32 | 33 | ## v0.1.1 (2021-04-06) 34 | 35 | ### Fix 36 | 37 | - Release in a separate environment ([`71550b8`](https://github.com/browniebroke/flake8-django-migrations/commit/71550b8d06f245d6d6046312ba77002185a8a990)) 38 | 39 | ## v0.1.0 (2020-11-10) 40 | 41 | ### Feature 42 | 43 | - DM001: `RemoveField` operation should be wrapped in `SeparateDatabaseAndState` ([`c571e0e`](https://github.com/browniebroke/flake8-django-migrations/commit/c571e0e026fbef9ba85782ff562cbdf9c6a763ed)) 44 | -------------------------------------------------------------------------------- /templates/CHANGELOG.md.j2: -------------------------------------------------------------------------------- 1 | # CHANGELOG 2 | 3 | {%- for version, release in context.history.released.items() %} 4 | {%- if version.as_tag() > "v1.0.0" %} 5 | 6 | ## {{ version.as_tag() }} ({{ release.tagged_date.strftime("%Y-%m-%d") }}) 7 | 8 | {%- for category, commits in release["elements"].items() %}{% if category != "unknown" %} 9 | {# Category title: Breaking, Fix, Documentation #} 10 | ### {{ category | capitalize }} 11 | {# List actual changes in the category #} 12 | {%- for commit in commits %} 13 | - {{ commit.descriptions[0] | capitalize }} ([`{{ commit.short_hash }}`]({{ commit.hexsha | commit_hash_url }})) 14 | {%- endfor %}{# for commit #} 15 | 16 | {%- endif %}{% endfor %}{# for category, commits #} 17 | 18 | {%- endif %}{# if version.as_tag() #} 19 | 20 | {%- endfor %}{# for version, release #} 21 | 22 | {% include ".changelog-old.md" %}{# include old changelog at the end -#} 23 | -------------------------------------------------------------------------------- /tests/test_flake8_django_migrations.py: -------------------------------------------------------------------------------- 1 | """Tests for `flake8_django_migrations` package.""" 2 | 3 | import ast 4 | from textwrap import dedent 5 | 6 | from flake8_django_migrations import Plugin 7 | 8 | 9 | def _results(s: str) -> set[str]: 10 | tree = ast.parse(dedent(s)) 11 | plugin = Plugin(tree) 12 | return {f"{line}:{col} {msg}" for line, col, msg, _ in plugin.run()} 13 | 14 | 15 | def test_trivial_case(): 16 | assert _results("") == set() 17 | 18 | 19 | def test_plugin_version(): 20 | assert isinstance(Plugin.version, str) 21 | assert "." in Plugin.version 22 | 23 | 24 | def test_plugin_name(): 25 | assert isinstance(Plugin.name, str) 26 | 27 | 28 | def test_unsafe_drop_column(): 29 | input_code = """ 30 | class Migration(migrations.Migration): 31 | operations = [ 32 | migrations.RemoveField( 33 | model_name="order", 34 | name="total", 35 | ), 36 | ] 37 | """ 38 | assert _results(input_code) == { 39 | "4:8 DM001 RemoveField operation should be wrapped in SeparateDatabaseAndState", 40 | } 41 | 42 | 43 | def test_safe_remove_field(): 44 | input_code = """ 45 | class Migration(migrations.Migration): 46 | operations = [ 47 | migrations.SeparateDatabaseAndState( 48 | state_operations=[ 49 | migrations.RemoveField( 50 | model_name="order", 51 | name="total", 52 | ), 53 | ], 54 | ), 55 | ] 56 | """ 57 | 58 | assert _results(input_code) == set() 59 | -------------------------------------------------------------------------------- /uv.lock: -------------------------------------------------------------------------------- 1 | version = 1 2 | revision = 2 3 | requires-python = ">=3.9" 4 | 5 | [[package]] 6 | name = "astor" 7 | version = "0.8.1" 8 | source = { registry = "https://pypi.org/simple" } 9 | sdist = { url = "https://files.pythonhosted.org/packages/5a/21/75b771132fee241dfe601d39ade629548a9626d1d39f333fde31bc46febe/astor-0.8.1.tar.gz", hash = "sha256:6a6effda93f4e1ce9f618779b2dd1d9d84f1e32812c23a29b3fff6fd7f63fa5e", size = 35090, upload-time = "2019-12-10T01:50:35.51Z" } 10 | wheels = [ 11 | { url = "https://files.pythonhosted.org/packages/c3/88/97eef84f48fa04fbd6750e62dcceafba6c63c81b7ac1420856c8dcc0a3f9/astor-0.8.1-py2.py3-none-any.whl", hash = "sha256:070a54e890cefb5b3739d19f30f5a5ec840ffc9c50ffa7d23cc9fc1a38ebbfc5", size = 27488, upload-time = "2019-12-10T01:50:33.628Z" }, 12 | ] 13 | 14 | [[package]] 15 | name = "colorama" 16 | version = "0.4.6" 17 | source = { registry = "https://pypi.org/simple" } 18 | sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697, upload-time = "2022-10-25T02:36:22.414Z" } 19 | wheels = [ 20 | { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" }, 21 | ] 22 | 23 | [[package]] 24 | name = "coverage" 25 | version = "7.8.0" 26 | source = { registry = "https://pypi.org/simple" } 27 | sdist = { url = "https://files.pythonhosted.org/packages/19/4f/2251e65033ed2ce1e68f00f91a0294e0f80c80ae8c3ebbe2f12828c4cd53/coverage-7.8.0.tar.gz", hash = "sha256:7a3d62b3b03b4b6fd41a085f3574874cf946cb4604d2b4d3e8dca8cd570ca501", size = 811872, upload-time = "2025-03-30T20:36:45.376Z" } 28 | wheels = [ 29 | { url = "https://files.pythonhosted.org/packages/78/01/1c5e6ee4ebaaa5e079db933a9a45f61172048c7efa06648445821a201084/coverage-7.8.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2931f66991175369859b5fd58529cd4b73582461877ecfd859b6549869287ffe", size = 211379, upload-time = "2025-03-30T20:34:53.904Z" }, 30 | { url = "https://files.pythonhosted.org/packages/e9/16/a463389f5ff916963471f7c13585e5f38c6814607306b3cb4d6b4cf13384/coverage-7.8.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:52a523153c568d2c0ef8826f6cc23031dc86cffb8c6aeab92c4ff776e7951b28", size = 211814, upload-time = "2025-03-30T20:34:56.959Z" }, 31 | { url = "https://files.pythonhosted.org/packages/b8/b1/77062b0393f54d79064dfb72d2da402657d7c569cfbc724d56ac0f9c67ed/coverage-7.8.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5c8a5c139aae4c35cbd7cadca1df02ea8cf28a911534fc1b0456acb0b14234f3", size = 240937, upload-time = "2025-03-30T20:34:58.751Z" }, 32 | { url = "https://files.pythonhosted.org/packages/d7/54/c7b00a23150083c124e908c352db03bcd33375494a4beb0c6d79b35448b9/coverage-7.8.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5a26c0c795c3e0b63ec7da6efded5f0bc856d7c0b24b2ac84b4d1d7bc578d676", size = 238849, upload-time = "2025-03-30T20:35:00.521Z" }, 33 | { url = "https://files.pythonhosted.org/packages/f7/ec/a6b7cfebd34e7b49f844788fda94713035372b5200c23088e3bbafb30970/coverage-7.8.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:821f7bcbaa84318287115d54becb1915eece6918136c6f91045bb84e2f88739d", size = 239986, upload-time = "2025-03-30T20:35:02.307Z" }, 34 | { url = "https://files.pythonhosted.org/packages/21/8c/c965ecef8af54e6d9b11bfbba85d4f6a319399f5f724798498387f3209eb/coverage-7.8.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:a321c61477ff8ee705b8a5fed370b5710c56b3a52d17b983d9215861e37b642a", size = 239896, upload-time = "2025-03-30T20:35:04.141Z" }, 35 | { url = "https://files.pythonhosted.org/packages/40/83/070550273fb4c480efa8381735969cb403fa8fd1626d74865bfaf9e4d903/coverage-7.8.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:ed2144b8a78f9d94d9515963ed273d620e07846acd5d4b0a642d4849e8d91a0c", size = 238613, upload-time = "2025-03-30T20:35:05.889Z" }, 36 | { url = "https://files.pythonhosted.org/packages/07/76/fbb2540495b01d996d38e9f8897b861afed356be01160ab4e25471f4fed1/coverage-7.8.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:042e7841a26498fff7a37d6fda770d17519982f5b7d8bf5278d140b67b61095f", size = 238909, upload-time = "2025-03-30T20:35:07.76Z" }, 37 | { url = "https://files.pythonhosted.org/packages/a3/7e/76d604db640b7d4a86e5dd730b73e96e12a8185f22b5d0799025121f4dcb/coverage-7.8.0-cp310-cp310-win32.whl", hash = "sha256:f9983d01d7705b2d1f7a95e10bbe4091fabc03a46881a256c2787637b087003f", size = 213948, upload-time = "2025-03-30T20:35:09.144Z" }, 38 | { url = "https://files.pythonhosted.org/packages/5c/a7/f8ce4aafb4a12ab475b56c76a71a40f427740cf496c14e943ade72e25023/coverage-7.8.0-cp310-cp310-win_amd64.whl", hash = "sha256:5a570cd9bd20b85d1a0d7b009aaf6c110b52b5755c17be6962f8ccd65d1dbd23", size = 214844, upload-time = "2025-03-30T20:35:10.734Z" }, 39 | { url = "https://files.pythonhosted.org/packages/2b/77/074d201adb8383addae5784cb8e2dac60bb62bfdf28b2b10f3a3af2fda47/coverage-7.8.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:e7ac22a0bb2c7c49f441f7a6d46c9c80d96e56f5a8bc6972529ed43c8b694e27", size = 211493, upload-time = "2025-03-30T20:35:12.286Z" }, 40 | { url = "https://files.pythonhosted.org/packages/a9/89/7a8efe585750fe59b48d09f871f0e0c028a7b10722b2172dfe021fa2fdd4/coverage-7.8.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:bf13d564d310c156d1c8e53877baf2993fb3073b2fc9f69790ca6a732eb4bfea", size = 211921, upload-time = "2025-03-30T20:35:14.18Z" }, 41 | { url = "https://files.pythonhosted.org/packages/e9/ef/96a90c31d08a3f40c49dbe897df4f1fd51fb6583821a1a1c5ee30cc8f680/coverage-7.8.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a5761c70c017c1b0d21b0815a920ffb94a670c8d5d409d9b38857874c21f70d7", size = 244556, upload-time = "2025-03-30T20:35:15.616Z" }, 42 | { url = "https://files.pythonhosted.org/packages/89/97/dcd5c2ce72cee9d7b0ee8c89162c24972fb987a111b92d1a3d1d19100c61/coverage-7.8.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e5ff52d790c7e1628241ffbcaeb33e07d14b007b6eb00a19320c7b8a7024c040", size = 242245, upload-time = "2025-03-30T20:35:18.648Z" }, 43 | { url = "https://files.pythonhosted.org/packages/b2/7b/b63cbb44096141ed435843bbb251558c8e05cc835c8da31ca6ffb26d44c0/coverage-7.8.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d39fc4817fd67b3915256af5dda75fd4ee10621a3d484524487e33416c6f3543", size = 244032, upload-time = "2025-03-30T20:35:20.131Z" }, 44 | { url = "https://files.pythonhosted.org/packages/97/e3/7fa8c2c00a1ef530c2a42fa5df25a6971391f92739d83d67a4ee6dcf7a02/coverage-7.8.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:b44674870709017e4b4036e3d0d6c17f06a0e6d4436422e0ad29b882c40697d2", size = 243679, upload-time = "2025-03-30T20:35:21.636Z" }, 45 | { url = "https://files.pythonhosted.org/packages/4f/b3/e0a59d8df9150c8a0c0841d55d6568f0a9195692136c44f3d21f1842c8f6/coverage-7.8.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:8f99eb72bf27cbb167b636eb1726f590c00e1ad375002230607a844d9e9a2318", size = 241852, upload-time = "2025-03-30T20:35:23.525Z" }, 46 | { url = "https://files.pythonhosted.org/packages/9b/82/db347ccd57bcef150c173df2ade97976a8367a3be7160e303e43dd0c795f/coverage-7.8.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b571bf5341ba8c6bc02e0baeaf3b061ab993bf372d982ae509807e7f112554e9", size = 242389, upload-time = "2025-03-30T20:35:25.09Z" }, 47 | { url = "https://files.pythonhosted.org/packages/21/f6/3f7d7879ceb03923195d9ff294456241ed05815281f5254bc16ef71d6a20/coverage-7.8.0-cp311-cp311-win32.whl", hash = "sha256:e75a2ad7b647fd8046d58c3132d7eaf31b12d8a53c0e4b21fa9c4d23d6ee6d3c", size = 213997, upload-time = "2025-03-30T20:35:26.914Z" }, 48 | { url = "https://files.pythonhosted.org/packages/28/87/021189643e18ecf045dbe1e2071b2747901f229df302de01c998eeadf146/coverage-7.8.0-cp311-cp311-win_amd64.whl", hash = "sha256:3043ba1c88b2139126fc72cb48574b90e2e0546d4c78b5299317f61b7f718b78", size = 214911, upload-time = "2025-03-30T20:35:28.498Z" }, 49 | { url = "https://files.pythonhosted.org/packages/aa/12/4792669473297f7973518bec373a955e267deb4339286f882439b8535b39/coverage-7.8.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:bbb5cc845a0292e0c520656d19d7ce40e18d0e19b22cb3e0409135a575bf79fc", size = 211684, upload-time = "2025-03-30T20:35:29.959Z" }, 50 | { url = "https://files.pythonhosted.org/packages/be/e1/2a4ec273894000ebedd789e8f2fc3813fcaf486074f87fd1c5b2cb1c0a2b/coverage-7.8.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4dfd9a93db9e78666d178d4f08a5408aa3f2474ad4d0e0378ed5f2ef71640cb6", size = 211935, upload-time = "2025-03-30T20:35:31.912Z" }, 51 | { url = "https://files.pythonhosted.org/packages/f8/3a/7b14f6e4372786709a361729164125f6b7caf4024ce02e596c4a69bccb89/coverage-7.8.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f017a61399f13aa6d1039f75cd467be388d157cd81f1a119b9d9a68ba6f2830d", size = 245994, upload-time = "2025-03-30T20:35:33.455Z" }, 52 | { url = "https://files.pythonhosted.org/packages/54/80/039cc7f1f81dcbd01ea796d36d3797e60c106077e31fd1f526b85337d6a1/coverage-7.8.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0915742f4c82208ebf47a2b154a5334155ed9ef9fe6190674b8a46c2fb89cb05", size = 242885, upload-time = "2025-03-30T20:35:35.354Z" }, 53 | { url = "https://files.pythonhosted.org/packages/10/e0/dc8355f992b6cc2f9dcd5ef6242b62a3f73264893bc09fbb08bfcab18eb4/coverage-7.8.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8a40fcf208e021eb14b0fac6bdb045c0e0cab53105f93ba0d03fd934c956143a", size = 245142, upload-time = "2025-03-30T20:35:37.121Z" }, 54 | { url = "https://files.pythonhosted.org/packages/43/1b/33e313b22cf50f652becb94c6e7dae25d8f02e52e44db37a82de9ac357e8/coverage-7.8.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a1f406a8e0995d654b2ad87c62caf6befa767885301f3b8f6f73e6f3c31ec3a6", size = 244906, upload-time = "2025-03-30T20:35:39.07Z" }, 55 | { url = "https://files.pythonhosted.org/packages/05/08/c0a8048e942e7f918764ccc99503e2bccffba1c42568693ce6955860365e/coverage-7.8.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:77af0f6447a582fdc7de5e06fa3757a3ef87769fbb0fdbdeba78c23049140a47", size = 243124, upload-time = "2025-03-30T20:35:40.598Z" }, 56 | { url = "https://files.pythonhosted.org/packages/5b/62/ea625b30623083c2aad645c9a6288ad9fc83d570f9adb913a2abdba562dd/coverage-7.8.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:f2d32f95922927186c6dbc8bc60df0d186b6edb828d299ab10898ef3f40052fe", size = 244317, upload-time = "2025-03-30T20:35:42.204Z" }, 57 | { url = "https://files.pythonhosted.org/packages/62/cb/3871f13ee1130a6c8f020e2f71d9ed269e1e2124aa3374d2180ee451cee9/coverage-7.8.0-cp312-cp312-win32.whl", hash = "sha256:769773614e676f9d8e8a0980dd7740f09a6ea386d0f383db6821df07d0f08545", size = 214170, upload-time = "2025-03-30T20:35:44.216Z" }, 58 | { url = "https://files.pythonhosted.org/packages/88/26/69fe1193ab0bfa1eb7a7c0149a066123611baba029ebb448500abd8143f9/coverage-7.8.0-cp312-cp312-win_amd64.whl", hash = "sha256:e5d2b9be5b0693cf21eb4ce0ec8d211efb43966f6657807f6859aab3814f946b", size = 214969, upload-time = "2025-03-30T20:35:45.797Z" }, 59 | { url = "https://files.pythonhosted.org/packages/f3/21/87e9b97b568e223f3438d93072479c2f36cc9b3f6b9f7094b9d50232acc0/coverage-7.8.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:5ac46d0c2dd5820ce93943a501ac5f6548ea81594777ca585bf002aa8854cacd", size = 211708, upload-time = "2025-03-30T20:35:47.417Z" }, 60 | { url = "https://files.pythonhosted.org/packages/75/be/882d08b28a0d19c9c4c2e8a1c6ebe1f79c9c839eb46d4fca3bd3b34562b9/coverage-7.8.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:771eb7587a0563ca5bb6f622b9ed7f9d07bd08900f7589b4febff05f469bea00", size = 211981, upload-time = "2025-03-30T20:35:49.002Z" }, 61 | { url = "https://files.pythonhosted.org/packages/7a/1d/ce99612ebd58082fbe3f8c66f6d8d5694976c76a0d474503fa70633ec77f/coverage-7.8.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42421e04069fb2cbcbca5a696c4050b84a43b05392679d4068acbe65449b5c64", size = 245495, upload-time = "2025-03-30T20:35:51.073Z" }, 62 | { url = "https://files.pythonhosted.org/packages/dc/8d/6115abe97df98db6b2bd76aae395fcc941d039a7acd25f741312ced9a78f/coverage-7.8.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:554fec1199d93ab30adaa751db68acec2b41c5602ac944bb19187cb9a41a8067", size = 242538, upload-time = "2025-03-30T20:35:52.941Z" }, 63 | { url = "https://files.pythonhosted.org/packages/cb/74/2f8cc196643b15bc096d60e073691dadb3dca48418f08bc78dd6e899383e/coverage-7.8.0-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5aaeb00761f985007b38cf463b1d160a14a22c34eb3f6a39d9ad6fc27cb73008", size = 244561, upload-time = "2025-03-30T20:35:54.658Z" }, 64 | { url = "https://files.pythonhosted.org/packages/22/70/c10c77cd77970ac965734fe3419f2c98665f6e982744a9bfb0e749d298f4/coverage-7.8.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:581a40c7b94921fffd6457ffe532259813fc68eb2bdda60fa8cc343414ce3733", size = 244633, upload-time = "2025-03-30T20:35:56.221Z" }, 65 | { url = "https://files.pythonhosted.org/packages/38/5a/4f7569d946a07c952688debee18c2bb9ab24f88027e3d71fd25dbc2f9dca/coverage-7.8.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:f319bae0321bc838e205bf9e5bc28f0a3165f30c203b610f17ab5552cff90323", size = 242712, upload-time = "2025-03-30T20:35:57.801Z" }, 66 | { url = "https://files.pythonhosted.org/packages/bb/a1/03a43b33f50475a632a91ea8c127f7e35e53786dbe6781c25f19fd5a65f8/coverage-7.8.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:04bfec25a8ef1c5f41f5e7e5c842f6b615599ca8ba8391ec33a9290d9d2db3a3", size = 244000, upload-time = "2025-03-30T20:35:59.378Z" }, 67 | { url = "https://files.pythonhosted.org/packages/6a/89/ab6c43b1788a3128e4d1b7b54214548dcad75a621f9d277b14d16a80d8a1/coverage-7.8.0-cp313-cp313-win32.whl", hash = "sha256:dd19608788b50eed889e13a5d71d832edc34fc9dfce606f66e8f9f917eef910d", size = 214195, upload-time = "2025-03-30T20:36:01.005Z" }, 68 | { url = "https://files.pythonhosted.org/packages/12/12/6bf5f9a8b063d116bac536a7fb594fc35cb04981654cccb4bbfea5dcdfa0/coverage-7.8.0-cp313-cp313-win_amd64.whl", hash = "sha256:a9abbccd778d98e9c7e85038e35e91e67f5b520776781d9a1e2ee9d400869487", size = 214998, upload-time = "2025-03-30T20:36:03.006Z" }, 69 | { url = "https://files.pythonhosted.org/packages/2a/e6/1e9df74ef7a1c983a9c7443dac8aac37a46f1939ae3499424622e72a6f78/coverage-7.8.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:18c5ae6d061ad5b3e7eef4363fb27a0576012a7447af48be6c75b88494c6cf25", size = 212541, upload-time = "2025-03-30T20:36:04.638Z" }, 70 | { url = "https://files.pythonhosted.org/packages/04/51/c32174edb7ee49744e2e81c4b1414ac9df3dacfcb5b5f273b7f285ad43f6/coverage-7.8.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:95aa6ae391a22bbbce1b77ddac846c98c5473de0372ba5c463480043a07bff42", size = 212767, upload-time = "2025-03-30T20:36:06.503Z" }, 71 | { url = "https://files.pythonhosted.org/packages/e9/8f/f454cbdb5212f13f29d4a7983db69169f1937e869a5142bce983ded52162/coverage-7.8.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e013b07ba1c748dacc2a80e69a46286ff145935f260eb8c72df7185bf048f502", size = 256997, upload-time = "2025-03-30T20:36:08.137Z" }, 72 | { url = "https://files.pythonhosted.org/packages/e6/74/2bf9e78b321216d6ee90a81e5c22f912fc428442c830c4077b4a071db66f/coverage-7.8.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d766a4f0e5aa1ba056ec3496243150698dc0481902e2b8559314368717be82b1", size = 252708, upload-time = "2025-03-30T20:36:09.781Z" }, 73 | { url = "https://files.pythonhosted.org/packages/92/4d/50d7eb1e9a6062bee6e2f92e78b0998848a972e9afad349b6cdde6fa9e32/coverage-7.8.0-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ad80e6b4a0c3cb6f10f29ae4c60e991f424e6b14219d46f1e7d442b938ee68a4", size = 255046, upload-time = "2025-03-30T20:36:11.409Z" }, 74 | { url = "https://files.pythonhosted.org/packages/40/9e/71fb4e7402a07c4198ab44fc564d09d7d0ffca46a9fb7b0a7b929e7641bd/coverage-7.8.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:b87eb6fc9e1bb8f98892a2458781348fa37e6925f35bb6ceb9d4afd54ba36c73", size = 256139, upload-time = "2025-03-30T20:36:13.86Z" }, 75 | { url = "https://files.pythonhosted.org/packages/49/1a/78d37f7a42b5beff027e807c2843185961fdae7fe23aad5a4837c93f9d25/coverage-7.8.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:d1ba00ae33be84066cfbe7361d4e04dec78445b2b88bdb734d0d1cbab916025a", size = 254307, upload-time = "2025-03-30T20:36:16.074Z" }, 76 | { url = "https://files.pythonhosted.org/packages/58/e9/8fb8e0ff6bef5e170ee19d59ca694f9001b2ec085dc99b4f65c128bb3f9a/coverage-7.8.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:f3c38e4e5ccbdc9198aecc766cedbb134b2d89bf64533973678dfcf07effd883", size = 255116, upload-time = "2025-03-30T20:36:18.033Z" }, 77 | { url = "https://files.pythonhosted.org/packages/56/b0/d968ecdbe6fe0a863de7169bbe9e8a476868959f3af24981f6a10d2b6924/coverage-7.8.0-cp313-cp313t-win32.whl", hash = "sha256:379fe315e206b14e21db5240f89dc0774bdd3e25c3c58c2c733c99eca96f1ada", size = 214909, upload-time = "2025-03-30T20:36:19.644Z" }, 78 | { url = "https://files.pythonhosted.org/packages/87/e9/d6b7ef9fecf42dfb418d93544af47c940aa83056c49e6021a564aafbc91f/coverage-7.8.0-cp313-cp313t-win_amd64.whl", hash = "sha256:2e4b6b87bb0c846a9315e3ab4be2d52fac905100565f4b92f02c445c8799e257", size = 216068, upload-time = "2025-03-30T20:36:21.282Z" }, 79 | { url = "https://files.pythonhosted.org/packages/60/0c/5da94be095239814bf2730a28cffbc48d6df4304e044f80d39e1ae581997/coverage-7.8.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:fa260de59dfb143af06dcf30c2be0b200bed2a73737a8a59248fcb9fa601ef0f", size = 211377, upload-time = "2025-03-30T20:36:23.298Z" }, 80 | { url = "https://files.pythonhosted.org/packages/d5/cb/b9e93ebf193a0bb89dbcd4f73d7b0e6ecb7c1b6c016671950e25f041835e/coverage-7.8.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:96121edfa4c2dfdda409877ea8608dd01de816a4dc4a0523356067b305e4e17a", size = 211803, upload-time = "2025-03-30T20:36:25.74Z" }, 81 | { url = "https://files.pythonhosted.org/packages/78/1a/cdbfe9e1bb14d3afcaf6bb6e1b9ba76c72666e329cd06865bbd241efd652/coverage-7.8.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6b8af63b9afa1031c0ef05b217faa598f3069148eeee6bb24b79da9012423b82", size = 240561, upload-time = "2025-03-30T20:36:27.548Z" }, 82 | { url = "https://files.pythonhosted.org/packages/59/04/57f1223f26ac018d7ce791bfa65b0c29282de3e041c1cd3ed430cfeac5a5/coverage-7.8.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:89b1f4af0d4afe495cd4787a68e00f30f1d15939f550e869de90a86efa7e0814", size = 238488, upload-time = "2025-03-30T20:36:29.175Z" }, 83 | { url = "https://files.pythonhosted.org/packages/b7/b1/0f25516ae2a35e265868670384feebe64e7857d9cffeeb3887b0197e2ba2/coverage-7.8.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:94ec0be97723ae72d63d3aa41961a0b9a6f5a53ff599813c324548d18e3b9e8c", size = 239589, upload-time = "2025-03-30T20:36:30.876Z" }, 84 | { url = "https://files.pythonhosted.org/packages/e0/a4/99d88baac0d1d5a46ceef2dd687aac08fffa8795e4c3e71b6f6c78e14482/coverage-7.8.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:8a1d96e780bdb2d0cbb297325711701f7c0b6f89199a57f2049e90064c29f6bd", size = 239366, upload-time = "2025-03-30T20:36:32.563Z" }, 85 | { url = "https://files.pythonhosted.org/packages/ea/9e/1db89e135feb827a868ed15f8fc857160757f9cab140ffee21342c783ceb/coverage-7.8.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:f1d8a2a57b47142b10374902777e798784abf400a004b14f1b0b9eaf1e528ba4", size = 237591, upload-time = "2025-03-30T20:36:34.721Z" }, 86 | { url = "https://files.pythonhosted.org/packages/1b/6d/ac4d6fdfd0e201bc82d1b08adfacb1e34b40d21a22cdd62cfaf3c1828566/coverage-7.8.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:cf60dd2696b457b710dd40bf17ad269d5f5457b96442f7f85722bdb16fa6c899", size = 238572, upload-time = "2025-03-30T20:36:36.805Z" }, 87 | { url = "https://files.pythonhosted.org/packages/25/5e/917cbe617c230f7f1745b6a13e780a3a1cd1cf328dbcd0fd8d7ec52858cd/coverage-7.8.0-cp39-cp39-win32.whl", hash = "sha256:be945402e03de47ba1872cd5236395e0f4ad635526185a930735f66710e1bd3f", size = 213966, upload-time = "2025-03-30T20:36:38.551Z" }, 88 | { url = "https://files.pythonhosted.org/packages/bd/93/72b434fe550135869f9ea88dd36068af19afce666db576e059e75177e813/coverage-7.8.0-cp39-cp39-win_amd64.whl", hash = "sha256:90e7fbc6216ecaffa5a880cdc9c77b7418c1dcb166166b78dbc630d07f278cc3", size = 214852, upload-time = "2025-03-30T20:36:40.209Z" }, 89 | { url = "https://files.pythonhosted.org/packages/c4/f1/1da77bb4c920aa30e82fa9b6ea065da3467977c2e5e032e38e66f1c57ffd/coverage-7.8.0-pp39.pp310.pp311-none-any.whl", hash = "sha256:b8194fb8e50d556d5849753de991d390c5a1edeeba50f68e3a9253fbd8bf8ccd", size = 203443, upload-time = "2025-03-30T20:36:41.959Z" }, 90 | { url = "https://files.pythonhosted.org/packages/59/f1/4da7717f0063a222db253e7121bd6a56f6fb1ba439dcc36659088793347c/coverage-7.8.0-py3-none-any.whl", hash = "sha256:dbf364b4c5e7bae9250528167dfe40219b62e2d573c854d74be213e1e52069f7", size = 203435, upload-time = "2025-03-30T20:36:43.61Z" }, 91 | ] 92 | 93 | [package.optional-dependencies] 94 | toml = [ 95 | { name = "tomli", marker = "python_full_version <= '3.11'" }, 96 | ] 97 | 98 | [[package]] 99 | name = "exceptiongroup" 100 | version = "1.2.2" 101 | source = { registry = "https://pypi.org/simple" } 102 | sdist = { url = "https://files.pythonhosted.org/packages/09/35/2495c4ac46b980e4ca1f6ad6db102322ef3ad2410b79fdde159a4b0f3b92/exceptiongroup-1.2.2.tar.gz", hash = "sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc", size = 28883, upload-time = "2024-07-12T22:26:00.161Z" } 103 | wheels = [ 104 | { url = "https://files.pythonhosted.org/packages/02/cc/b7e31358aac6ed1ef2bb790a9746ac2c69bcb3c8588b41616914eb106eaf/exceptiongroup-1.2.2-py3-none-any.whl", hash = "sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b", size = 16453, upload-time = "2024-07-12T22:25:58.476Z" }, 105 | ] 106 | 107 | [[package]] 108 | name = "flake8" 109 | version = "7.2.0" 110 | source = { registry = "https://pypi.org/simple" } 111 | dependencies = [ 112 | { name = "mccabe" }, 113 | { name = "pycodestyle" }, 114 | { name = "pyflakes" }, 115 | ] 116 | sdist = { url = "https://files.pythonhosted.org/packages/e7/c4/5842fc9fc94584c455543540af62fd9900faade32511fab650e9891ec225/flake8-7.2.0.tar.gz", hash = "sha256:fa558ae3f6f7dbf2b4f22663e5343b6b6023620461f8d4ff2019ef4b5ee70426", size = 48177, upload-time = "2025-03-29T20:08:39.329Z" } 117 | wheels = [ 118 | { url = "https://files.pythonhosted.org/packages/83/5c/0627be4c9976d56b1217cb5187b7504e7fd7d3503f8bfd312a04077bd4f7/flake8-7.2.0-py2.py3-none-any.whl", hash = "sha256:93b92ba5bdb60754a6da14fa3b93a9361fd00a59632ada61fd7b130436c40343", size = 57786, upload-time = "2025-03-29T20:08:37.902Z" }, 119 | ] 120 | 121 | [[package]] 122 | name = "flake8-django-migrations" 123 | version = "1.1.0" 124 | source = { editable = "." } 125 | dependencies = [ 126 | { name = "astor" }, 127 | { name = "flake8" }, 128 | ] 129 | 130 | [package.dev-dependencies] 131 | dev = [ 132 | { name = "pytest" }, 133 | { name = "pytest-cov" }, 134 | ] 135 | 136 | [package.metadata] 137 | requires-dist = [ 138 | { name = "astor", specifier = ">=0.1" }, 139 | { name = "flake8", specifier = ">=3.7" }, 140 | { name = "importlib-metadata", marker = "python_full_version < '3.8'", specifier = ">=0.9" }, 141 | ] 142 | 143 | [package.metadata.requires-dev] 144 | dev = [ 145 | { name = "pytest", specifier = ">=8,<9" }, 146 | { name = "pytest-cov", specifier = ">=6,<7" }, 147 | ] 148 | 149 | [[package]] 150 | name = "iniconfig" 151 | version = "2.1.0" 152 | source = { registry = "https://pypi.org/simple" } 153 | sdist = { url = "https://files.pythonhosted.org/packages/f2/97/ebf4da567aa6827c909642694d71c9fcf53e5b504f2d96afea02718862f3/iniconfig-2.1.0.tar.gz", hash = "sha256:3abbd2e30b36733fee78f9c7f7308f2d0050e88f0087fd25c2645f63c773e1c7", size = 4793, upload-time = "2025-03-19T20:09:59.721Z" } 154 | wheels = [ 155 | { url = "https://files.pythonhosted.org/packages/2c/e1/e6716421ea10d38022b952c159d5161ca1193197fb744506875fbb87ea7b/iniconfig-2.1.0-py3-none-any.whl", hash = "sha256:9deba5723312380e77435581c6bf4935c94cbfab9b1ed33ef8d238ea168eb760", size = 6050, upload-time = "2025-03-19T20:10:01.071Z" }, 156 | ] 157 | 158 | [[package]] 159 | name = "mccabe" 160 | version = "0.7.0" 161 | source = { registry = "https://pypi.org/simple" } 162 | sdist = { url = "https://files.pythonhosted.org/packages/e7/ff/0ffefdcac38932a54d2b5eed4e0ba8a408f215002cd178ad1df0f2806ff8/mccabe-0.7.0.tar.gz", hash = "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325", size = 9658, upload-time = "2022-01-24T01:14:51.113Z" } 163 | wheels = [ 164 | { url = "https://files.pythonhosted.org/packages/27/1a/1f68f9ba0c207934b35b86a8ca3aad8395a3d6dd7921c0686e23853ff5a9/mccabe-0.7.0-py2.py3-none-any.whl", hash = "sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e", size = 7350, upload-time = "2022-01-24T01:14:49.62Z" }, 165 | ] 166 | 167 | [[package]] 168 | name = "packaging" 169 | version = "25.0" 170 | source = { registry = "https://pypi.org/simple" } 171 | sdist = { url = "https://files.pythonhosted.org/packages/a1/d4/1fc4078c65507b51b96ca8f8c3ba19e6a61c8253c72794544580a7b6c24d/packaging-25.0.tar.gz", hash = "sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f", size = 165727, upload-time = "2025-04-19T11:48:59.673Z" } 172 | wheels = [ 173 | { url = "https://files.pythonhosted.org/packages/20/12/38679034af332785aac8774540895e234f4d07f7545804097de4b666afd8/packaging-25.0-py3-none-any.whl", hash = "sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484", size = 66469, upload-time = "2025-04-19T11:48:57.875Z" }, 174 | ] 175 | 176 | [[package]] 177 | name = "pluggy" 178 | version = "1.5.0" 179 | source = { registry = "https://pypi.org/simple" } 180 | sdist = { url = "https://files.pythonhosted.org/packages/96/2d/02d4312c973c6050a18b314a5ad0b3210edb65a906f868e31c111dede4a6/pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1", size = 67955, upload-time = "2024-04-20T21:34:42.531Z" } 181 | wheels = [ 182 | { url = "https://files.pythonhosted.org/packages/88/5f/e351af9a41f866ac3f1fac4ca0613908d9a41741cfcf2228f4ad853b697d/pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669", size = 20556, upload-time = "2024-04-20T21:34:40.434Z" }, 183 | ] 184 | 185 | [[package]] 186 | name = "pycodestyle" 187 | version = "2.13.0" 188 | source = { registry = "https://pypi.org/simple" } 189 | sdist = { url = "https://files.pythonhosted.org/packages/04/6e/1f4a62078e4d95d82367f24e685aef3a672abfd27d1a868068fed4ed2254/pycodestyle-2.13.0.tar.gz", hash = "sha256:c8415bf09abe81d9c7f872502a6eee881fbe85d8763dd5b9924bb0a01d67efae", size = 39312, upload-time = "2025-03-29T17:33:30.669Z" } 190 | wheels = [ 191 | { url = "https://files.pythonhosted.org/packages/07/be/b00116df1bfb3e0bb5b45e29d604799f7b91dd861637e4d448b4e09e6a3e/pycodestyle-2.13.0-py2.py3-none-any.whl", hash = "sha256:35863c5974a271c7a726ed228a14a4f6daf49df369d8c50cd9a6f58a5e143ba9", size = 31424, upload-time = "2025-03-29T17:33:29.405Z" }, 192 | ] 193 | 194 | [[package]] 195 | name = "pyflakes" 196 | version = "3.3.2" 197 | source = { registry = "https://pypi.org/simple" } 198 | sdist = { url = "https://files.pythonhosted.org/packages/af/cc/1df338bd7ed1fa7c317081dcf29bf2f01266603b301e6858856d346a12b3/pyflakes-3.3.2.tar.gz", hash = "sha256:6dfd61d87b97fba5dcfaaf781171ac16be16453be6d816147989e7f6e6a9576b", size = 64175, upload-time = "2025-03-31T13:21:20.34Z" } 199 | wheels = [ 200 | { url = "https://files.pythonhosted.org/packages/15/40/b293a4fa769f3b02ab9e387c707c4cbdc34f073f945de0386107d4e669e6/pyflakes-3.3.2-py2.py3-none-any.whl", hash = "sha256:5039c8339cbb1944045f4ee5466908906180f13cc99cc9949348d10f82a5c32a", size = 63164, upload-time = "2025-03-31T13:21:18.503Z" }, 201 | ] 202 | 203 | [[package]] 204 | name = "pytest" 205 | version = "8.3.5" 206 | source = { registry = "https://pypi.org/simple" } 207 | dependencies = [ 208 | { name = "colorama", marker = "sys_platform == 'win32'" }, 209 | { name = "exceptiongroup", marker = "python_full_version < '3.11'" }, 210 | { name = "iniconfig" }, 211 | { name = "packaging" }, 212 | { name = "pluggy" }, 213 | { name = "tomli", marker = "python_full_version < '3.11'" }, 214 | ] 215 | sdist = { url = "https://files.pythonhosted.org/packages/ae/3c/c9d525a414d506893f0cd8a8d0de7706446213181570cdbd766691164e40/pytest-8.3.5.tar.gz", hash = "sha256:f4efe70cc14e511565ac476b57c279e12a855b11f48f212af1080ef2263d3845", size = 1450891, upload-time = "2025-03-02T12:54:54.503Z" } 216 | wheels = [ 217 | { url = "https://files.pythonhosted.org/packages/30/3d/64ad57c803f1fa1e963a7946b6e0fea4a70df53c1a7fed304586539c2bac/pytest-8.3.5-py3-none-any.whl", hash = "sha256:c69214aa47deac29fad6c2a4f590b9c4a9fdb16a403176fe154b79c0b4d4d820", size = 343634, upload-time = "2025-03-02T12:54:52.069Z" }, 218 | ] 219 | 220 | [[package]] 221 | name = "pytest-cov" 222 | version = "6.1.1" 223 | source = { registry = "https://pypi.org/simple" } 224 | dependencies = [ 225 | { name = "coverage", extra = ["toml"] }, 226 | { name = "pytest" }, 227 | ] 228 | sdist = { url = "https://files.pythonhosted.org/packages/25/69/5f1e57f6c5a39f81411b550027bf72842c4567ff5fd572bed1edc9e4b5d9/pytest_cov-6.1.1.tar.gz", hash = "sha256:46935f7aaefba760e716c2ebfbe1c216240b9592966e7da99ea8292d4d3e2a0a", size = 66857, upload-time = "2025-04-05T14:07:51.592Z" } 229 | wheels = [ 230 | { url = "https://files.pythonhosted.org/packages/28/d0/def53b4a790cfb21483016430ed828f64830dd981ebe1089971cd10cab25/pytest_cov-6.1.1-py3-none-any.whl", hash = "sha256:bddf29ed2d0ab6f4df17b4c55b0a657287db8684af9c42ea546b21b1041b3dde", size = 23841, upload-time = "2025-04-05T14:07:49.641Z" }, 231 | ] 232 | 233 | [[package]] 234 | name = "tomli" 235 | version = "2.2.1" 236 | source = { registry = "https://pypi.org/simple" } 237 | sdist = { url = "https://files.pythonhosted.org/packages/18/87/302344fed471e44a87289cf4967697d07e532f2421fdaf868a303cbae4ff/tomli-2.2.1.tar.gz", hash = "sha256:cd45e1dc79c835ce60f7404ec8119f2eb06d38b1deba146f07ced3bbc44505ff", size = 17175, upload-time = "2024-11-27T22:38:36.873Z" } 238 | wheels = [ 239 | { url = "https://files.pythonhosted.org/packages/43/ca/75707e6efa2b37c77dadb324ae7d9571cb424e61ea73fad7c56c2d14527f/tomli-2.2.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:678e4fa69e4575eb77d103de3df8a895e1591b48e740211bd1067378c69e8249", size = 131077, upload-time = "2024-11-27T22:37:54.956Z" }, 240 | { url = "https://files.pythonhosted.org/packages/c7/16/51ae563a8615d472fdbffc43a3f3d46588c264ac4f024f63f01283becfbb/tomli-2.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:023aa114dd824ade0100497eb2318602af309e5a55595f76b626d6d9f3b7b0a6", size = 123429, upload-time = "2024-11-27T22:37:56.698Z" }, 241 | { url = "https://files.pythonhosted.org/packages/f1/dd/4f6cd1e7b160041db83c694abc78e100473c15d54620083dbd5aae7b990e/tomli-2.2.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ece47d672db52ac607a3d9599a9d48dcb2f2f735c6c2d1f34130085bb12b112a", size = 226067, upload-time = "2024-11-27T22:37:57.63Z" }, 242 | { url = "https://files.pythonhosted.org/packages/a9/6b/c54ede5dc70d648cc6361eaf429304b02f2871a345bbdd51e993d6cdf550/tomli-2.2.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6972ca9c9cc9f0acaa56a8ca1ff51e7af152a9f87fb64623e31d5c83700080ee", size = 236030, upload-time = "2024-11-27T22:37:59.344Z" }, 243 | { url = "https://files.pythonhosted.org/packages/1f/47/999514fa49cfaf7a92c805a86c3c43f4215621855d151b61c602abb38091/tomli-2.2.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c954d2250168d28797dd4e3ac5cf812a406cd5a92674ee4c8f123c889786aa8e", size = 240898, upload-time = "2024-11-27T22:38:00.429Z" }, 244 | { url = "https://files.pythonhosted.org/packages/73/41/0a01279a7ae09ee1573b423318e7934674ce06eb33f50936655071d81a24/tomli-2.2.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8dd28b3e155b80f4d54beb40a441d366adcfe740969820caf156c019fb5c7ec4", size = 229894, upload-time = "2024-11-27T22:38:02.094Z" }, 245 | { url = "https://files.pythonhosted.org/packages/55/18/5d8bc5b0a0362311ce4d18830a5d28943667599a60d20118074ea1b01bb7/tomli-2.2.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:e59e304978767a54663af13c07b3d1af22ddee3bb2fb0618ca1593e4f593a106", size = 245319, upload-time = "2024-11-27T22:38:03.206Z" }, 246 | { url = "https://files.pythonhosted.org/packages/92/a3/7ade0576d17f3cdf5ff44d61390d4b3febb8a9fc2b480c75c47ea048c646/tomli-2.2.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:33580bccab0338d00994d7f16f4c4ec25b776af3ffaac1ed74e0b3fc95e885a8", size = 238273, upload-time = "2024-11-27T22:38:04.217Z" }, 247 | { url = "https://files.pythonhosted.org/packages/72/6f/fa64ef058ac1446a1e51110c375339b3ec6be245af9d14c87c4a6412dd32/tomli-2.2.1-cp311-cp311-win32.whl", hash = "sha256:465af0e0875402f1d226519c9904f37254b3045fc5084697cefb9bdde1ff99ff", size = 98310, upload-time = "2024-11-27T22:38:05.908Z" }, 248 | { url = "https://files.pythonhosted.org/packages/6a/1c/4a2dcde4a51b81be3530565e92eda625d94dafb46dbeb15069df4caffc34/tomli-2.2.1-cp311-cp311-win_amd64.whl", hash = "sha256:2d0f2fdd22b02c6d81637a3c95f8cd77f995846af7414c5c4b8d0545afa1bc4b", size = 108309, upload-time = "2024-11-27T22:38:06.812Z" }, 249 | { url = "https://files.pythonhosted.org/packages/52/e1/f8af4c2fcde17500422858155aeb0d7e93477a0d59a98e56cbfe75070fd0/tomli-2.2.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:4a8f6e44de52d5e6c657c9fe83b562f5f4256d8ebbfe4ff922c495620a7f6cea", size = 132762, upload-time = "2024-11-27T22:38:07.731Z" }, 250 | { url = "https://files.pythonhosted.org/packages/03/b8/152c68bb84fc00396b83e7bbddd5ec0bd3dd409db4195e2a9b3e398ad2e3/tomli-2.2.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8d57ca8095a641b8237d5b079147646153d22552f1c637fd3ba7f4b0b29167a8", size = 123453, upload-time = "2024-11-27T22:38:09.384Z" }, 251 | { url = "https://files.pythonhosted.org/packages/c8/d6/fc9267af9166f79ac528ff7e8c55c8181ded34eb4b0e93daa767b8841573/tomli-2.2.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e340144ad7ae1533cb897d406382b4b6fede8890a03738ff1683af800d54192", size = 233486, upload-time = "2024-11-27T22:38:10.329Z" }, 252 | { url = "https://files.pythonhosted.org/packages/5c/51/51c3f2884d7bab89af25f678447ea7d297b53b5a3b5730a7cb2ef6069f07/tomli-2.2.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:db2b95f9de79181805df90bedc5a5ab4c165e6ec3fe99f970d0e302f384ad222", size = 242349, upload-time = "2024-11-27T22:38:11.443Z" }, 253 | { url = "https://files.pythonhosted.org/packages/ab/df/bfa89627d13a5cc22402e441e8a931ef2108403db390ff3345c05253935e/tomli-2.2.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:40741994320b232529c802f8bc86da4e1aa9f413db394617b9a256ae0f9a7f77", size = 252159, upload-time = "2024-11-27T22:38:13.099Z" }, 254 | { url = "https://files.pythonhosted.org/packages/9e/6e/fa2b916dced65763a5168c6ccb91066f7639bdc88b48adda990db10c8c0b/tomli-2.2.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:400e720fe168c0f8521520190686ef8ef033fb19fc493da09779e592861b78c6", size = 237243, upload-time = "2024-11-27T22:38:14.766Z" }, 255 | { url = "https://files.pythonhosted.org/packages/b4/04/885d3b1f650e1153cbb93a6a9782c58a972b94ea4483ae4ac5cedd5e4a09/tomli-2.2.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:02abe224de6ae62c19f090f68da4e27b10af2b93213d36cf44e6e1c5abd19fdd", size = 259645, upload-time = "2024-11-27T22:38:15.843Z" }, 256 | { url = "https://files.pythonhosted.org/packages/9c/de/6b432d66e986e501586da298e28ebeefd3edc2c780f3ad73d22566034239/tomli-2.2.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b82ebccc8c8a36f2094e969560a1b836758481f3dc360ce9a3277c65f374285e", size = 244584, upload-time = "2024-11-27T22:38:17.645Z" }, 257 | { url = "https://files.pythonhosted.org/packages/1c/9a/47c0449b98e6e7d1be6cbac02f93dd79003234ddc4aaab6ba07a9a7482e2/tomli-2.2.1-cp312-cp312-win32.whl", hash = "sha256:889f80ef92701b9dbb224e49ec87c645ce5df3fa2cc548664eb8a25e03127a98", size = 98875, upload-time = "2024-11-27T22:38:19.159Z" }, 258 | { url = "https://files.pythonhosted.org/packages/ef/60/9b9638f081c6f1261e2688bd487625cd1e660d0a85bd469e91d8db969734/tomli-2.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:7fc04e92e1d624a4a63c76474610238576942d6b8950a2d7f908a340494e67e4", size = 109418, upload-time = "2024-11-27T22:38:20.064Z" }, 259 | { url = "https://files.pythonhosted.org/packages/04/90/2ee5f2e0362cb8a0b6499dc44f4d7d48f8fff06d28ba46e6f1eaa61a1388/tomli-2.2.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f4039b9cbc3048b2416cc57ab3bda989a6fcf9b36cf8937f01a6e731b64f80d7", size = 132708, upload-time = "2024-11-27T22:38:21.659Z" }, 260 | { url = "https://files.pythonhosted.org/packages/c0/ec/46b4108816de6b385141f082ba99e315501ccd0a2ea23db4a100dd3990ea/tomli-2.2.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:286f0ca2ffeeb5b9bd4fcc8d6c330534323ec51b2f52da063b11c502da16f30c", size = 123582, upload-time = "2024-11-27T22:38:22.693Z" }, 261 | { url = "https://files.pythonhosted.org/packages/a0/bd/b470466d0137b37b68d24556c38a0cc819e8febe392d5b199dcd7f578365/tomli-2.2.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a92ef1a44547e894e2a17d24e7557a5e85a9e1d0048b0b5e7541f76c5032cb13", size = 232543, upload-time = "2024-11-27T22:38:24.367Z" }, 262 | { url = "https://files.pythonhosted.org/packages/d9/e5/82e80ff3b751373f7cead2815bcbe2d51c895b3c990686741a8e56ec42ab/tomli-2.2.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9316dc65bed1684c9a98ee68759ceaed29d229e985297003e494aa825ebb0281", size = 241691, upload-time = "2024-11-27T22:38:26.081Z" }, 263 | { url = "https://files.pythonhosted.org/packages/05/7e/2a110bc2713557d6a1bfb06af23dd01e7dde52b6ee7dadc589868f9abfac/tomli-2.2.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e85e99945e688e32d5a35c1ff38ed0b3f41f43fad8df0bdf79f72b2ba7bc5272", size = 251170, upload-time = "2024-11-27T22:38:27.921Z" }, 264 | { url = "https://files.pythonhosted.org/packages/64/7b/22d713946efe00e0adbcdfd6d1aa119ae03fd0b60ebed51ebb3fa9f5a2e5/tomli-2.2.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ac065718db92ca818f8d6141b5f66369833d4a80a9d74435a268c52bdfa73140", size = 236530, upload-time = "2024-11-27T22:38:29.591Z" }, 265 | { url = "https://files.pythonhosted.org/packages/38/31/3a76f67da4b0cf37b742ca76beaf819dca0ebef26d78fc794a576e08accf/tomli-2.2.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:d920f33822747519673ee656a4b6ac33e382eca9d331c87770faa3eef562aeb2", size = 258666, upload-time = "2024-11-27T22:38:30.639Z" }, 266 | { url = "https://files.pythonhosted.org/packages/07/10/5af1293da642aded87e8a988753945d0cf7e00a9452d3911dd3bb354c9e2/tomli-2.2.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a198f10c4d1b1375d7687bc25294306e551bf1abfa4eace6650070a5c1ae2744", size = 243954, upload-time = "2024-11-27T22:38:31.702Z" }, 267 | { url = "https://files.pythonhosted.org/packages/5b/b9/1ed31d167be802da0fc95020d04cd27b7d7065cc6fbefdd2f9186f60d7bd/tomli-2.2.1-cp313-cp313-win32.whl", hash = "sha256:d3f5614314d758649ab2ab3a62d4f2004c825922f9e370b29416484086b264ec", size = 98724, upload-time = "2024-11-27T22:38:32.837Z" }, 268 | { url = "https://files.pythonhosted.org/packages/c7/32/b0963458706accd9afcfeb867c0f9175a741bf7b19cd424230714d722198/tomli-2.2.1-cp313-cp313-win_amd64.whl", hash = "sha256:a38aa0308e754b0e3c67e344754dff64999ff9b513e691d0e786265c93583c69", size = 109383, upload-time = "2024-11-27T22:38:34.455Z" }, 269 | { url = "https://files.pythonhosted.org/packages/6e/c2/61d3e0f47e2b74ef40a68b9e6ad5984f6241a942f7cd3bbfbdbd03861ea9/tomli-2.2.1-py3-none-any.whl", hash = "sha256:cb55c73c5f4408779d0cf3eef9f762b9c9f147a77de7b258bef0a5628adc85cc", size = 14257, upload-time = "2024-11-27T22:38:35.385Z" }, 270 | ] 271 | --------------------------------------------------------------------------------