Compare commits

..

No commits in common. "master" and "2024.10.11" have entirely different histories.

79 changed files with 750 additions and 1847 deletions

View File

@ -12,7 +12,7 @@ trim_trailing_whitespace = true
indent_style = space indent_style = space
indent_size = 4 indent_size = 4
[*.{html,css,scss,json,yml,xml,toml}] [*.{html,css,scss,json,yml,xml}]
indent_style = space indent_style = space
indent_size = 2 indent_size = 2

View File

@ -1653,65 +1653,5 @@
"name": "Francisco Navarro Morales ", "name": "Francisco Navarro Morales ",
"github_login": "spothound", "github_login": "spothound",
"twitter_username": "" "twitter_username": ""
},
{
"name": "Mariot Tsitoara",
"github_login": "mariot",
"twitter_username": ""
},
{
"name": "Christian Jensen",
"github_login": "jensenbox",
"twitter_username": "cjensen"
},
{
"name": "Denis Darii",
"github_login": "DNX",
"twitter_username": ""
},
{
"name": "qwerrrqw",
"github_login": "qwerrrqw",
"twitter_username": ""
},
{
"name": "Pulse-Mind",
"github_login": "pulse-mind",
"twitter_username": ""
},
{
"name": "Hana Belay",
"github_login": "earthcomfy",
"twitter_username": ""
},
{
"name": "Ed Morley",
"github_login": "edmorley",
"twitter_username": ""
},
{
"name": "Alan Cyment",
"github_login": "acyment",
"twitter_username": ""
},
{
"name": "Kawsar Alam Foysal",
"github_login": "iamfoysal",
"twitter_username": ""
},
{
"name": "Igor Jerosimić",
"github_login": "igor-wl",
"twitter_username": ""
},
{
"name": "Pepa",
"github_login": "07pepa",
"twitter_username": ""
},
{
"name": "Aidos Kanapyanov",
"github_login": "aidoskanapyanov",
"twitter_username": ""
} }
] ]

View File

@ -2,16 +2,23 @@
# https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file # https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file
version: 2 version: 2
enable-beta-ecosystems: true
updates: updates:
# Update Python deps for the template (not the generated project) # Update Python deps for the template (not the generated project)
- package-ecosystem: "uv" - package-ecosystem: "pip"
directory: "/" directory: "/"
schedule: schedule:
interval: "daily" interval: "daily"
labels: labels:
- "project infrastructure" - "project infrastructure"
# Update Python deps for the documentation
- package-ecosystem: "pip"
directory: "docs/"
schedule:
interval: "daily"
labels:
- "project infrastructure"
# Update GitHub actions in workflows # Update GitHub actions in workflows
- package-ecosystem: "github-actions" - package-ecosystem: "github-actions"
directory: "/" directory: "/"
@ -29,11 +36,11 @@ updates:
- "update" - "update"
# Enable version updates for Docker # Enable version updates for Docker
# We need to specify each Dockerfile in a separate entry because Dependabot doesn't
# support wildcards or recursively checking subdirectories. Check this issue for updates:
# https://github.com/dependabot/dependabot-core/issues/2178
- package-ecosystem: "docker" - package-ecosystem: "docker"
directories: directory: "{{cookiecutter.project_slug}}/compose/local/django/"
- "{{cookiecutter.project_slug}}/compose/local/django/"
- "{{cookiecutter.project_slug}}/compose/local/docs/"
- "{{cookiecutter.project_slug}}/compose/production/django/"
schedule: schedule:
interval: "daily" interval: "daily"
ignore: ignore:
@ -43,18 +50,62 @@ updates:
- "version-update:semver-minor" - "version-update:semver-minor"
labels: labels:
- "update" - "update"
groups:
docker-python:
patterns:
- "*"
- package-ecosystem: "docker" - package-ecosystem: "docker"
directories: directory: "{{cookiecutter.project_slug}}/compose/local/docs/"
- "{{cookiecutter.project_slug}}/compose/local/node/" schedule:
- "{{cookiecutter.project_slug}}/compose/production/aws/" interval: "daily"
- "{{cookiecutter.project_slug}}/compose/production/postgres/" ignore:
- "{{cookiecutter.project_slug}}/compose/production/nginx/" - dependency-name: "*"
- "{{cookiecutter.project_slug}}/compose/production/traefik/" update-types:
- "version-update:semver-major"
- "version-update:semver-minor"
labels:
- "update"
- package-ecosystem: "docker"
directory: "{{cookiecutter.project_slug}}/compose/local/node/"
schedule:
interval: "daily"
labels:
- "update"
- package-ecosystem: "docker"
directory: "{{cookiecutter.project_slug}}/compose/production/aws/"
schedule:
interval: "daily"
labels:
- "update"
- package-ecosystem: "docker"
directory: "{{cookiecutter.project_slug}}/compose/production/django/"
schedule:
interval: "daily"
ignore:
- dependency-name: "*"
update-types:
- "version-update:semver-major"
- "version-update:semver-minor"
labels:
- "update"
- package-ecosystem: "docker"
directory: "{{cookiecutter.project_slug}}/compose/production/postgres/"
schedule:
interval: "daily"
labels:
- "update"
- package-ecosystem: "docker"
directory: "{{cookiecutter.project_slug}}/compose/production/nginx/"
schedule:
interval: "daily"
versioning-strategy: increase
labels:
- "update"
- package-ecosystem: "docker"
directory: "{{cookiecutter.project_slug}}/compose/production/traefik/"
schedule: schedule:
interval: "daily" interval: "daily"
labels: labels:

View File

@ -1,52 +0,0 @@
name: align versions
on:
pull_request:
paths:
- "{{cookiecutter.project_slug}}/requirements/local.txt"
- "{{cookiecutter.project_slug}}/compose/local/node/Dockerfile"
# Manual trigger
workflow_dispatch:
permissions:
contents: write
pull-requests: write
jobs:
run:
if: ${{ github.actor == 'pyup-bot' }}
runs-on: ubuntu-latest
env:
GH_PAT: ${{ secrets.GH_PAT }}
strategy:
fail-fast: false
matrix:
job:
- script: scripts/ruff_version.py
name: Ruff
- script: scripts/node_version.py
name: Node
name: "${{ matrix.job.name }} versions"
steps:
- name: Checkout with token
uses: actions/checkout@v4
if: ${{ env.GH_PAT != '' }}
with:
token: ${{ env.GH_PAT }}
ref: ${{ github.head_ref }}
- name: Checkout without token
uses: actions/checkout@v4
if: ${{ env.GH_PAT == '' }}
with:
ref: ${{ github.head_ref }}
- uses: astral-sh/setup-uv@v5
- run: uv run ${{ matrix.job.script }}
- uses: stefanzweifel/git-auto-commit-action@v5
with:
commit_message: Align versions

View File

@ -24,7 +24,9 @@ jobs:
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- name: Install uv - name: Install uv
uses: astral-sh/setup-uv@v5 uses: astral-sh/setup-uv@v3
with:
enable-cache: "true"
- name: Install dependencies - name: Install dependencies
run: uv sync run: uv sync
- name: Run tests - name: Run tests
@ -53,7 +55,9 @@ jobs:
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- name: Install uv - name: Install uv
uses: astral-sh/setup-uv@v5 uses: astral-sh/setup-uv@v3
with:
enable-cache: "true"
- name: Install dependencies - name: Install dependencies
run: uv sync run: uv sync
- name: Docker ${{ matrix.script.name }} - name: Docker ${{ matrix.script.name }}
@ -81,28 +85,27 @@ jobs:
ports: ports:
- 6379:6379 - 6379:6379
postgres: postgres:
image: postgres:13 image: postgres:12
ports: ports:
- 5432:5432 - 5432:5432
env: env:
POSTGRES_PASSWORD: postgres POSTGRES_PASSWORD: postgres
env: env:
REDIS_URL: "redis://localhost:6379/0" CELERY_BROKER_URL: "redis://localhost:6379/0"
# postgres://user:password@host:port/database # postgres://user:password@host:port/database
DATABASE_URL: "postgres://postgres:postgres@localhost:5432/postgres" DATABASE_URL: "postgres://postgres:postgres@localhost:5432/postgres"
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.12"
- name: Install uv - name: Install uv
uses: astral-sh/setup-uv@v5 uses: astral-sh/setup-uv@v3
with:
enable-cache: "true"
- name: Install dependencies - name: Install dependencies
run: uv sync run: uv sync
- uses: actions/setup-node@v4 - uses: actions/setup-node@v4
with: with:
node-version: "22.14" node-version: "22"
- name: Bare Metal ${{ matrix.script.name }} - name: Bare Metal ${{ matrix.script.name }}
run: sh tests/test_bare.sh ${{ matrix.script.args }} run: sh tests/test_bare.sh ${{ matrix.script.args }}

View File

@ -11,7 +11,6 @@ permissions:
jobs: jobs:
lock: lock:
if: ${{ github.actor == 'dependabot[bot]' }}
runs-on: ubuntu-latest runs-on: ubuntu-latest
env: env:
GH_PAT: ${{ secrets.GH_PAT }} GH_PAT: ${{ secrets.GH_PAT }}
@ -26,7 +25,9 @@ jobs:
uses: actions/checkout@v4 uses: actions/checkout@v4
if: ${{ env.GH_PAT == '' }} if: ${{ env.GH_PAT == '' }}
- uses: astral-sh/setup-uv@v5 - uses: astral-sh/setup-uv@v3
with:
enable-cache: true
- run: uv lock - run: uv lock
- uses: stefanzweifel/git-auto-commit-action@v5 - uses: stefanzweifel/git-auto-commit-action@v5
with: with:

View File

@ -18,7 +18,9 @@ jobs:
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- name: Install uv - name: Install uv
uses: astral-sh/setup-uv@v5 uses: astral-sh/setup-uv@v3
with:
enable-cache: "true"
- name: Create Django Major Issue - name: Create Django Major Issue
run: uv run --frozen scripts/create_django_issue.py run: uv run --frozen scripts/create_django_issue.py
env: env:

View File

@ -16,12 +16,14 @@ jobs:
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- name: Install uv - name: Install uv
uses: astral-sh/setup-uv@v5 uses: astral-sh/setup-uv@v3
with:
enable-cache: "true"
- name: Set git details - name: Set git details
run: | run: |
git config --global user.name "github-actions" git config --global user.name "github-actions"
git config --global user.email "action@github.com" git config --global user.email "action@github.com"
- name: Update changelog - name: Update list
run: uv run --frozen scripts/update_changelog.py run: uv run --frozen scripts/update_changelog.py
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View File

@ -19,7 +19,9 @@ jobs:
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- name: Install uv - name: Install uv
uses: astral-sh/setup-uv@v5 uses: astral-sh/setup-uv@v3
with:
enable-cache: "true"
- name: Update list - name: Update list
run: uv run --frozen scripts/update_contributors.py run: uv run --frozen scripts/update_contributors.py
env: env:

View File

@ -1,6 +1,5 @@
exclude: "{{cookiecutter.project_slug}}|.github/contributors.json|CHANGELOG.md|CONTRIBUTORS.md" exclude: "{{cookiecutter.project_slug}}|.github/contributors.json|CHANGELOG.md|CONTRIBUTORS.md"
default_stages: [pre-commit] default_stages: [pre-commit]
minimum_pre_commit_version: "3.2.0"
default_language_version: default_language_version:
python: python3.12 python: python3.12
@ -27,29 +26,29 @@ repos:
args: ["--tab-width", "2"] args: ["--tab-width", "2"]
- repo: https://github.com/asottile/pyupgrade - repo: https://github.com/asottile/pyupgrade
rev: v3.19.1 rev: v3.17.0
hooks: hooks:
- id: pyupgrade - id: pyupgrade
args: [--py312-plus] args: [--py312-plus]
exclude: hooks/ exclude: hooks/
- repo: https://github.com/psf/black - repo: https://github.com/psf/black
rev: 25.1.0 rev: 24.10.0
hooks: hooks:
- id: black - id: black
- repo: https://github.com/PyCQA/isort - repo: https://github.com/PyCQA/isort
rev: 6.0.1 rev: 5.13.2
hooks: hooks:
- id: isort - id: isort
- repo: https://github.com/PyCQA/flake8 - repo: https://github.com/PyCQA/flake8
rev: 7.2.0 rev: 7.1.1
hooks: hooks:
- id: flake8 - id: flake8
- repo: https://github.com/tox-dev/pyproject-fmt - repo: https://github.com/tox-dev/pyproject-fmt
rev: "v2.5.1" rev: "2.3.0"
hooks: hooks:
- id: pyproject-fmt - id: pyproject-fmt

View File

@ -13,7 +13,7 @@ build:
- asdf plugin add uv - asdf plugin add uv
- asdf install uv latest - asdf install uv latest
- asdf global uv latest - asdf global uv latest
- uv sync --only-group docs --frozen - uv sync --extra docs --no-dev --frozen
- uv run -m sphinx -T -b html -d docs/_build/doctrees -D language=en docs $READTHEDOCS_OUTPUT/html - uv run -m sphinx -T -b html -d docs/_build/doctrees -D language=en docs $READTHEDOCS_OUTPUT/html
# Build documentation in the docs/ directory with Sphinx # Build documentation in the docs/ directory with Sphinx

View File

@ -3,877 +3,6 @@ All enhancements and patches to Cookiecutter Django will be documented in this f
<!-- GENERATOR_PLACEHOLDER --> <!-- GENERATOR_PLACEHOLDER -->
## 2025.04.08
### Updated
- Update django-extensions to 4.0 ([#5770](https://github.com/cookiecutter/cookiecutter-django/pull/5770))
## 2025.04.05
### Changed
- Add Docker build caching on GitHub Actions ([#5700](https://github.com/cookiecutter/cookiecutter-django/pull/5700))
- Pin Pillow and Sphinx to non yanked release ([#5765](https://github.com/cookiecutter/cookiecutter-django/pull/5765))
### Updated
- Update ruff to 0.11.4 ([#5767](https://github.com/cookiecutter/cookiecutter-django/pull/5767))
## 2025.04.03
### Updated
- Update django-anymail to 13.0 ([#5763](https://github.com/cookiecutter/cookiecutter-django/pull/5763))
- Update pytest-django to 4.11.1 ([#5762](https://github.com/cookiecutter/cookiecutter-django/pull/5762))
- Update ruff to 0.11.3 ([#5761](https://github.com/cookiecutter/cookiecutter-django/pull/5761))
- Update django-allauth to 65.7.0 ([#5760](https://github.com/cookiecutter/cookiecutter-django/pull/5760))
## 2025.04.02
### Fixed
- Fix line endings for dotenv merge script on Windows ([#5754](https://github.com/cookiecutter/cookiecutter-django/pull/5754))
### Updated
- Update crispy-bootstrap5 to 2025.4 ([#5756](https://github.com/cookiecutter/cookiecutter-django/pull/5756))
- Update Django from 5.0 to 5.1 ([#5740](https://github.com/cookiecutter/cookiecutter-django/pull/5740))
- Update sentry-sdk to 2.25.1 ([#5757](https://github.com/cookiecutter/cookiecutter-django/pull/5757))
- Update django-storages to 1.14.6 ([#5753](https://github.com/cookiecutter/cookiecutter-django/pull/5753))
- Update pytest-django to 4.11.0 ([#5752](https://github.com/cookiecutter/cookiecutter-django/pull/5752))
## 2025.04.01
### Updated
- Update pillow to 11.2.0 ([#5751](https://github.com/cookiecutter/cookiecutter-django/pull/5751))
- Bump traefik from 3.3.4 to 3.3.5 ([#5750](https://github.com/cookiecutter/cookiecutter-django/pull/5750))
- Update celery to 5.5.0 ([#5748](https://github.com/cookiecutter/cookiecutter-django/pull/5748))
## 2025.03.31
### Updated
- Update django-allauth to 65.6.0 ([#5741](https://github.com/cookiecutter/cookiecutter-django/pull/5741))
- Update sentry-sdk to 2.25.0 ([#5747](https://github.com/cookiecutter/cookiecutter-django/pull/5747))
- Update coverage to 7.8.0 ([#5745](https://github.com/cookiecutter/cookiecutter-django/pull/5745))
## 2025.03.28
### Updated
- Update djangorestframework to 3.16.0 ([#5743](https://github.com/cookiecutter/cookiecutter-django/pull/5743))
- Update django-upgrade pre-commit hook to v1.24.0 ([#5742](https://github.com/cookiecutter/cookiecutter-django/pull/5742))
## 2025.03.24
### Updated
- Update django-allauth to 65.5.0 ([#5723](https://github.com/cookiecutter/cookiecutter-django/pull/5723))
- Update sentry-sdk to 2.24.1 ([#5739](https://github.com/cookiecutter/cookiecutter-django/pull/5739))
## 2025.03.22
### Updated
- Update coverage to 7.7.1 ([#5736](https://github.com/cookiecutter/cookiecutter-django/pull/5736))
## 2025.03.21
### Updated
- Update sentry-sdk to 2.24.0 ([#5734](https://github.com/cookiecutter/cookiecutter-django/pull/5734))
- Update django-debug-toolbar to 5.1.0 ([#5732](https://github.com/cookiecutter/cookiecutter-django/pull/5732))
- Update ruff to 0.11.2 ([#5735](https://github.com/cookiecutter/cookiecutter-django/pull/5735))
- Bump amazon/aws-cli from 2.24.0 to 2.25.0 ([#5733](https://github.com/cookiecutter/cookiecutter-django/pull/5733))
- Auto-update pre-commit hooks ([#5657](https://github.com/cookiecutter/cookiecutter-django/pull/5657))
## 2025.03.19
### Updated
- Update pre-commit to 4.2.0 ([#5730](https://github.com/cookiecutter/cookiecutter-django/pull/5730))
## 2025.03.17
### Updated
- Update sentry-sdk to 2.23.1 ([#5727](https://github.com/cookiecutter/cookiecutter-django/pull/5727))
- Update coverage to 7.7.0 ([#5725](https://github.com/cookiecutter/cookiecutter-django/pull/5725))
## 2025.03.15
### Updated
- Update psycopg to 3.2.6 ([#5721](https://github.com/cookiecutter/cookiecutter-django/pull/5721))
- Update ruff to 0.11.0 ([#5724](https://github.com/cookiecutter/cookiecutter-django/pull/5724))
## 2025.03.08
### Updated
- Update ruff to 0.9.10 ([#5720](https://github.com/cookiecutter/cookiecutter-django/pull/5720))
## 2025.03.06
### Updated
- Update django to 5.0.13 ([#5719](https://github.com/cookiecutter/cookiecutter-django/pull/5719))
## 2025.03.04
### Changed
- Add groups for dependabot updates ([#5709](https://github.com/cookiecutter/cookiecutter-django/pull/5709))
### Updated
- Update sphinx to 8.3.0 ([#5714](https://github.com/cookiecutter/cookiecutter-django/pull/5714))
- Update pytest to 8.3.5 ([#5713](https://github.com/cookiecutter/cookiecutter-django/pull/5713))
## 2025.03.01
### Updated
- Update ruff to 0.9.9 ([#5711](https://github.com/cookiecutter/cookiecutter-django/pull/5711))
## 2025.02.28
### Updated
- Update ruff to 0.9.8 ([#5708](https://github.com/cookiecutter/cookiecutter-django/pull/5708))
- Bump babel-loader from 9.2.1 to 10.0.0 ([#5710](https://github.com/cookiecutter/cookiecutter-django/pull/5710))
## 2025.02.26
### Updated
- Bump traefik from 3.3.3 to 3.3.4 ([#5705](https://github.com/cookiecutter/cookiecutter-django/pull/5705))
## 2025.02.25
### Documentation
- Fix links to FAQ about `contrib.sites` directory ([#5704](https://github.com/cookiecutter/cookiecutter-django/pull/5704))
## 2025.02.23
### Changed
- Group dependabot docker directories ([#5698](https://github.com/cookiecutter/cookiecutter-django/pull/5698))
### Updated
- Update sphinx to 8.2.1 ([#5696](https://github.com/cookiecutter/cookiecutter-django/pull/5696))
- Update psycopg to 3.2.5 ([#5697](https://github.com/cookiecutter/cookiecutter-django/pull/5697))
## 2025.02.21
### Updated
- Update djangorestframework-stubs to 3.15.3 ([#5695](https://github.com/cookiecutter/cookiecutter-django/pull/5695))
- Update sphinx to 8.2.0 ([#5693](https://github.com/cookiecutter/cookiecutter-django/pull/5693))
- Update ruff to 0.9.7 ([#5694](https://github.com/cookiecutter/cookiecutter-django/pull/5694))
## 2025.02.17
### Updated
- Update sentry-sdk to 2.22.0 ([#5692](https://github.com/cookiecutter/cookiecutter-django/pull/5692))
- Update django-storages to 1.14.5 ([#5690](https://github.com/cookiecutter/cookiecutter-django/pull/5690))
## 2025.02.14
### Updated
- Bump node from 22.13 to 22.14 ([#5688](https://github.com/cookiecutter/cookiecutter-django/pull/5688))
## 2025.02.13
### Updated
- Update sentry-sdk to 2.21.0 ([#5687](https://github.com/cookiecutter/cookiecutter-django/pull/5687))
## 2025.02.11
### Updated
- Update coverage to 7.6.12 ([#5686](https://github.com/cookiecutter/cookiecutter-django/pull/5686))
## 2025.02.10
### Updated
- Update pytest-django to 4.10.0 ([#5684](https://github.com/cookiecutter/cookiecutter-django/pull/5684))
- Update ruff to 0.9.6 ([#5683](https://github.com/cookiecutter/cookiecutter-django/pull/5683))
- Bump amazon/aws-cli from 2.23.0 to 2.24.0 ([#5682](https://github.com/cookiecutter/cookiecutter-django/pull/5682))
## 2025.02.08
### Updated
- Update coverage to 7.6.11 ([#5681](https://github.com/cookiecutter/cookiecutter-django/pull/5681))
## 2025.02.07
### Updated
- Update mypy to 1.15.0 ([#5664](https://github.com/cookiecutter/cookiecutter-django/pull/5664))
- Update django-stubs to 5.1.3 ([#5680](https://github.com/cookiecutter/cookiecutter-django/pull/5680))
- Bump python from 3.12.8 to 3.12.9 in local Docker image ([#5678](https://github.com/cookiecutter/cookiecutter-django/pull/5678))
- Bump python from 3.12.8 to 3.12.9 in production Docker image ([#5677](https://github.com/cookiecutter/cookiecutter-django/pull/5677))
- Bump python from 3.12.8 to 3.12.9 in docs Docker image ([#5676](https://github.com/cookiecutter/cookiecutter-django/pull/5676))
- Update django-allauth to 65.4.1 ([#5679](https://github.com/cookiecutter/cookiecutter-django/pull/5679))
- Update django-cors-headers to 4.7.0 ([#5675](https://github.com/cookiecutter/cookiecutter-django/pull/5675))
- Update whitenoise to 6.9.0 ([#5674](https://github.com/cookiecutter/cookiecutter-django/pull/5674))
## 2025.02.06
### Fixed
- Bump node version in production Dockerfile from 20 to 22.13 ([#5672](https://github.com/cookiecutter/cookiecutter-django/pull/5672))
### Updated
- Update ruff to 0.9.5 ([#5673](https://github.com/cookiecutter/cookiecutter-django/pull/5673))
## 2025.02.05
### Changed
- Add missing trailing slash in test `MEDIA_URL` ([#5666](https://github.com/cookiecutter/cookiecutter-django/pull/5666))
### Updated
- Update django to 5.0.12 ([#5667](https://github.com/cookiecutter/cookiecutter-django/pull/5667))
## 2025.02.03
### Updated
- Bump traefik from 3.3.2 to 3.3.3 ([#5660](https://github.com/cookiecutter/cookiecutter-django/pull/5660))
- Update factory-boy to 3.3.2 ([#5661](https://github.com/cookiecutter/cookiecutter-django/pull/5661))
## 2025.01.30
### Updated
- Update ruff to 0.9.4 ([#5659](https://github.com/cookiecutter/cookiecutter-django/pull/5659))
## 2025.01.26
### Changed
- Migrate generated project from `runtime.txt` to `.python-version` ([#5652](https://github.com/cookiecutter/cookiecutter-django/pull/5652))
### Documentation
- Update Heroku deployment guide ([#5656](https://github.com/cookiecutter/cookiecutter-django/pull/5656))
## 2025.01.24
### Updated
- Update ruff to 0.9.3 ([#5654](https://github.com/cookiecutter/cookiecutter-django/pull/5654))
## 2025.01.21
### Changed
- Update linter error code from TCH to TC ([#5651](https://github.com/cookiecutter/cookiecutter-django/pull/5651))
### Updated
- Update pre-commit to 4.1.0 ([#5650](https://github.com/cookiecutter/cookiecutter-django/pull/5650))
## 2025.01.20
### Changed
- Group all API tests under a `tests.api` namespace ([#5615](https://github.com/cookiecutter/cookiecutter-django/pull/5615))
- Migrate post-generation hook to pathlib ([#5648](https://github.com/cookiecutter/cookiecutter-django/pull/5648))
## 2025.01.16
### Updated
- Update ruff to 0.9.2 ([#5646](https://github.com/cookiecutter/cookiecutter-django/pull/5646))
- Bump amazon/aws-cli from 2.22.1 to 2.23.0 ([#5645](https://github.com/cookiecutter/cookiecutter-django/pull/5645))
## 2025.01.15
### Fixed
- Fix setting for to `CELERY_WORKER_HIJACK_ROOT_LOGGER` ([#5643](https://github.com/cookiecutter/cookiecutter-django/pull/5643))
### Updated
- Update psycopg to 3.2.4 ([#5644](https://github.com/cookiecutter/cookiecutter-django/pull/5644))
- Update django-stubs to 5.1.2 ([#5639](https://github.com/cookiecutter/cookiecutter-django/pull/5639))
- Bump traefik from 3.3.1 to 3.3.2 ([#5642](https://github.com/cookiecutter/cookiecutter-django/pull/5642))
## 2025.01.14
### Updated
- Update django to 5.0.11 ([#5640](https://github.com/cookiecutter/cookiecutter-django/pull/5640))
- Update sentry-sdk to 2.20.0 ([#5638](https://github.com/cookiecutter/cookiecutter-django/pull/5638))
- Update django-debug-toolbar to 5.0.1 ([#5636](https://github.com/cookiecutter/cookiecutter-django/pull/5636))
## 2025.01.13
### Updated
- Update django-environ to 0.12.0 ([#5635](https://github.com/cookiecutter/cookiecutter-django/pull/5635))
- Bump traefik from 3.3.0 to 3.3.1 ([#5634](https://github.com/cookiecutter/cookiecutter-django/pull/5634))
## 2025.01.11
### Updated
- Update ruff to 0.9.1 ([#5633](https://github.com/cookiecutter/cookiecutter-django/pull/5633))
## 2025.01.10
### Updated
- Update watchfiles to 1.0.4 ([#5631](https://github.com/cookiecutter/cookiecutter-django/pull/5631))
## 2025.01.09
### Changed
- Drop support for Python 2 in template generation hooks ([#5614](https://github.com/cookiecutter/cookiecutter-django/pull/5614))
### Updated
- Bump node from 22.12 to 22.13 ([#5627](https://github.com/cookiecutter/cookiecutter-django/pull/5627))
## 2025.01.07
### Fixed
- Set `minimum_pre_commit_version` in pre-commit config ([#5626](https://github.com/cookiecutter/cookiecutter-django/pull/5626))
### Updated
- Bump traefik from 3.2.3 to 3.3.0 ([#5625](https://github.com/cookiecutter/cookiecutter-django/pull/5625))
## 2025.01.06
### Changed
- Add justfile for use with docker ([#5621](https://github.com/cookiecutter/cookiecutter-django/pull/5621))
## 2025.01.04
### Updated
- Update ruff to 0.8.6 ([#5622](https://github.com/cookiecutter/cookiecutter-django/pull/5622))
## 2025.01.02
### Fixed
- Fix logging configuration for Celery tasks ([#5563](https://github.com/cookiecutter/cookiecutter-django/pull/5563))
### Updated
- Update ruff to 0.8.5 ([#5619](https://github.com/cookiecutter/cookiecutter-django/pull/5619))
- Update pillow to 11.1.0 ([#5617](https://github.com/cookiecutter/cookiecutter-django/pull/5617))
## 2024.12.27
### Updated
- Update coverage to 7.6.10 ([#5608](https://github.com/cookiecutter/cookiecutter-django/pull/5608))
- Update uvicorn-worker to 0.3.0 ([#5607](https://github.com/cookiecutter/cookiecutter-django/pull/5607))
## 2024.12.26
### Updated
- Update collectfasta to 3.2.1 ([#5606](https://github.com/cookiecutter/cookiecutter-django/pull/5606))
- Update django-allauth to 65.3.1 ([#5605](https://github.com/cookiecutter/cookiecutter-django/pull/5605))
## 2024.12.24
### Updated
- Update djlint to 1.36.4 ([#5603](https://github.com/cookiecutter/cookiecutter-django/pull/5603))
- Update uvicorn to 0.34.0 ([#5592](https://github.com/cookiecutter/cookiecutter-django/pull/5592))
## 2024.12.23
### Updated
- Bump webpack-cli from 5.1.4 to 6.0.1 ([#5601](https://github.com/cookiecutter/cookiecutter-django/pull/5601))
## 2024.12.20
### Updated
- Update ruff to 0.8.4 ([#5595](https://github.com/cookiecutter/cookiecutter-django/pull/5595))
## 2024.12.17
### Updated
- Update djangorestframework-stubs to 3.15.2 ([#5591](https://github.com/cookiecutter/cookiecutter-django/pull/5591))
- Bump traefik from 3.2.2 to 3.2.3 ([#5594](https://github.com/cookiecutter/cookiecutter-django/pull/5594))
## 2024.12.12
### Updated
- Update ruff to 0.8.3 ([#5587](https://github.com/cookiecutter/cookiecutter-django/pull/5587))
## 2024.12.11
### Updated
- Bump traefik from 3.2.1 to 3.2.2 ([#5586](https://github.com/cookiecutter/cookiecutter-django/pull/5586))
## 2024.12.10
### Updated
- Update watchfiles to 1.0.3 ([#5585](https://github.com/cookiecutter/cookiecutter-django/pull/5585))
- Bump node from 22.11 to 22.12 ([#5583](https://github.com/cookiecutter/cookiecutter-django/pull/5583))
## 2024.12.08
### Fixed
- Pin node to version 22.11 ([#5582](https://github.com/cookiecutter/cookiecutter-django/pull/5582))
### Updated
- Update ruff to 0.8.2 ([#5576](https://github.com/cookiecutter/cookiecutter-django/pull/5576))
- Update coverage to 7.6.9 ([#5581](https://github.com/cookiecutter/cookiecutter-django/pull/5581))
- Update sentry-sdk to 2.19.2 ([#5579](https://github.com/cookiecutter/cookiecutter-django/pull/5579))
- Bump python from 3.12.7 to 3.12.8 in production Docker image ([#5575](https://github.com/cookiecutter/cookiecutter-django/pull/5575))
- Bump python from 3.12.7 to 3.12.8 in local Docker image ([#5574](https://github.com/cookiecutter/cookiecutter-django/pull/5574))
- Bump python from 3.12.7 to 3.12.8 in docs Docker image ([#5573](https://github.com/cookiecutter/cookiecutter-django/pull/5573))
- Update hiredis to 3.1.0 ([#5571](https://github.com/cookiecutter/cookiecutter-django/pull/5571))
- Update redis to 5.2.1 ([#5580](https://github.com/cookiecutter/cookiecutter-django/pull/5580))
- Update django to 5.0.10 ([#5572](https://github.com/cookiecutter/cookiecutter-django/pull/5572))
- Update drf-spectacular to 0.28.0 ([#5564](https://github.com/cookiecutter/cookiecutter-django/pull/5564))
## 2024.12.03
### Updated
- Update django-upgrade to 1.22.2 ([#5567](https://github.com/cookiecutter/cookiecutter-django/pull/5567))
## 2024.12.02
### Updated
- Update pytest to 8.3.4 ([#5566](https://github.com/cookiecutter/cookiecutter-django/pull/5566))
## 2024.12.01
### Updated
- Update django-allauth to 65.3.0 ([#5565](https://github.com/cookiecutter/cookiecutter-django/pull/5565))
## 2024.11.29
### Updated
- Update ruff to 0.8.1 ([#5557](https://github.com/cookiecutter/cookiecutter-django/pull/5557))
- Update djlint to 1.36.3 ([#5558](https://github.com/cookiecutter/cookiecutter-django/pull/5558))
## 2024.11.28
### Updated
- Update djlint to 1.36.2 ([#5555](https://github.com/cookiecutter/cookiecutter-django/pull/5555))
## 2024.11.27
### Fixed
- Pin dart-sass to 1.77.6 to avoid deprecation warnings ([#5552](https://github.com/cookiecutter/cookiecutter-django/pull/5552))
### Updated
- Bump gulp-imagemin from 7.1.0 to 9.1.0 ([#5052](https://github.com/cookiecutter/cookiecutter-django/pull/5052))
- Bump gulp from 4.0.2 to 5.0.0 ([#4949](https://github.com/cookiecutter/cookiecutter-django/pull/4949))
## 2024.11.26
### Updated
- Update coverage to 7.6.8 ([#5547](https://github.com/cookiecutter/cookiecutter-django/pull/5547))
- Update watchfiles to 1.0.0 ([#5548](https://github.com/cookiecutter/cookiecutter-django/pull/5548))
## 2024.11.22
### Updated
- Update ruff to 0.8.0 ([#5545](https://github.com/cookiecutter/cookiecutter-django/pull/5545))
## 2024.11.21
### Changed
- Add support for secure Redis (TLS support) ([#5526](https://github.com/cookiecutter/cookiecutter-django/pull/5526))
### Updated
- Update sentry-sdk to 2.19.0 ([#5543](https://github.com/cookiecutter/cookiecutter-django/pull/5543))
- Update uvicorn to 0.32.1 ([#5539](https://github.com/cookiecutter/cookiecutter-django/pull/5539))
- Bump traefik from 3.2.0 to 3.2.1 ([#5541](https://github.com/cookiecutter/cookiecutter-django/pull/5541))
## 2024.11.20
### Fixed
- Fix typos in translation instructions in README ([#5538](https://github.com/cookiecutter/cookiecutter-django/pull/5538))
### Updated
- Bump amazon/aws-cli from 2.21.0 to 2.22.1 ([#5537](https://github.com/cookiecutter/cookiecutter-django/pull/5537))
## 2024.11.16
### Updated
- Update ruff to 0.7.4 ([#5531](https://github.com/cookiecutter/cookiecutter-django/pull/5531))
## 2024.11.15
### Updated
- Update coverage to 7.6.5 ([#5529](https://github.com/cookiecutter/cookiecutter-django/pull/5529))
## 2024.11.14
### Updated
- Bump amazon/aws-cli from 2.20.0 to 2.21.0 ([#5528](https://github.com/cookiecutter/cookiecutter-django/pull/5528))
## 2024.11.13
### Updated
- Update werkzeug to 3.1.3 ([#5524](https://github.com/cookiecutter/cookiecutter-django/pull/5524))
- Update ruff to 0.7.3 ([#5521](https://github.com/cookiecutter/cookiecutter-django/pull/5521))
- Bump amazon/aws-cli from 2.19.0 to 2.20.0 ([#5527](https://github.com/cookiecutter/cookiecutter-django/pull/5527))
- Update django-allauth to 65.2.0 ([#5523](https://github.com/cookiecutter/cookiecutter-django/pull/5523))
## 2024.11.08
### Updated
- Update ruff pre-commit hook to 0.7.3 ([#5522](https://github.com/cookiecutter/cookiecutter-django/pull/5522))
## 2024.11.07
### Updated
- Update djlint to 1.36.1 ([#5519](https://github.com/cookiecutter/cookiecutter-django/pull/5519))
## 2024.11.05
### Updated
- Update djlint to 1.36.0 ([#5517](https://github.com/cookiecutter/cookiecutter-django/pull/5517))
## 2024.11.04
### Updated
- Update sentry-sdk to 2.18.0 ([#5515](https://github.com/cookiecutter/cookiecutter-django/pull/5515))
## 2024.11.02
### Updated
- Update ruff to 0.7.2 ([#5510](https://github.com/cookiecutter/cookiecutter-django/pull/5510))
## 2024.11.01
### Updated
- Update djlint to 1.35.4 ([#5508](https://github.com/cookiecutter/cookiecutter-django/pull/5508))
- Bump amazon/aws-cli from 2.18.1 to 2.19.0 ([#5507](https://github.com/cookiecutter/cookiecutter-django/pull/5507))
## 2024.10.30
### Documentation
- Small spelling correction in comment ([#5502](https://github.com/cookiecutter/cookiecutter-django/pull/5502))
### Updated
- Update djlint to 1.35.3 ([#5503](https://github.com/cookiecutter/cookiecutter-django/pull/5503))
- Update whitenoise to 6.8.2 ([#5501](https://github.com/cookiecutter/cookiecutter-django/pull/5501))
## 2024.10.29
### Updated
- Update django-cors-headers to 4.6.0 ([#5499](https://github.com/cookiecutter/cookiecutter-django/pull/5499))
- Update whitenoise to 6.8.1 ([#5497](https://github.com/cookiecutter/cookiecutter-django/pull/5497))
- Bump traefik from 3.1.6 to 3.2.0 ([#5498](https://github.com/cookiecutter/cookiecutter-django/pull/5498))
## 2024.10.26
### Updated
- Update django-stubs to 5.1.1 ([#5495](https://github.com/cookiecutter/cookiecutter-django/pull/5495))
- Update mypy to 1.13.0 ([#5484](https://github.com/cookiecutter/cookiecutter-django/pull/5484))
- Update werkzeug to 3.0.6 ([#5492](https://github.com/cookiecutter/cookiecutter-django/pull/5492))
## 2024.10.25
### Updated
- Update werkzeug to 3.0.5 and unpin watchdog&lt;5 ([#5489](https://github.com/cookiecutter/cookiecutter-django/pull/5489))
## 2024.10.24
### Updated
- Update ruff to 0.7.1 ([#5487](https://github.com/cookiecutter/cookiecutter-django/pull/5487))
- Update redis to 5.2.0 ([#5486](https://github.com/cookiecutter/cookiecutter-django/pull/5486))
- Update django-allauth to 65.1.0 ([#5485](https://github.com/cookiecutter/cookiecutter-django/pull/5485))
## 2024.10.22
### Changed
- Fix broken links in generated README ([#5482](https://github.com/cookiecutter/cookiecutter-django/pull/5482))
### Updated
- Auto-update pre-commit hooks ([#5483](https://github.com/cookiecutter/cookiecutter-django/pull/5483))
## 2024.10.21
### Changed
- Remove CELERY_BROKER_URL in favor of REDIS_URL ([#4861](https://github.com/cookiecutter/cookiecutter-django/pull/4861))
### Fixed
- Fix a number of issues with Azure storage ([#5476](https://github.com/cookiecutter/cookiecutter-django/pull/5476))
### Updated
- Update coverage to 7.6.4 ([#5480](https://github.com/cookiecutter/cookiecutter-django/pull/5480))
## 2024.10.17
### Updated
- Update ruff to 0.7.0 ([#5474](https://github.com/cookiecutter/cookiecutter-django/pull/5474))
- Update uvicorn to 0.32.0 ([#5471](https://github.com/cookiecutter/cookiecutter-django/pull/5471))
- Update pillow to 11.0.0 ([#5470](https://github.com/cookiecutter/cookiecutter-django/pull/5470))
- Update sentry-sdk to 2.17.0 ([#5473](https://github.com/cookiecutter/cookiecutter-django/pull/5473))
## 2024.10.15
### Changed
- [pre-commit.ci] pre-commit autoupdate ([#5468](https://github.com/cookiecutter/cookiecutter-django/pull/5468))
## 2024.10.14
### Changed
- Add requirements for ubuntu 24.04 ([#5467](https://github.com/cookiecutter/cookiecutter-django/pull/5467))
### Updated
- Update sphinx to 8.1.3 ([#5463](https://github.com/cookiecutter/cookiecutter-django/pull/5463))
- Update coverage to 7.6.3 ([#5464](https://github.com/cookiecutter/cookiecutter-django/pull/5464))
## 2024.10.12
### Changed
- Pin Python version to 3.12 ([#5456](https://github.com/cookiecutter/cookiecutter-django/pull/5456))
### Updated
- Update sphinx to 8.1.1 ([#5457](https://github.com/cookiecutter/cookiecutter-django/pull/5457))
- Auto-update pre-commit hooks ([#5458](https://github.com/cookiecutter/cookiecutter-django/pull/5458))
- Update django-cors-headers to 4.5.0 ([#5459](https://github.com/cookiecutter/cookiecutter-django/pull/5459))
## 2024.10.11 ## 2024.10.11

View File

@ -201,20 +201,6 @@ Listed in alphabetical order.
</td> </td>
<td></td> <td></td>
</tr> </tr>
<tr>
<td>Aidos Kanapyanov</td>
<td>
<a href="https://github.com/aidoskanapyanov">aidoskanapyanov</a>
</td>
<td></td>
</tr>
<tr>
<td>Alan Cyment</td>
<td>
<a href="https://github.com/acyment">acyment</a>
</td>
<td></td>
</tr>
<tr> <tr>
<td>Alberto Sanchez</td> <td>Alberto Sanchez</td>
<td> <td>
@ -558,13 +544,6 @@ Listed in alphabetical order.
</td> </td>
<td></td> <td></td>
</tr> </tr>
<tr>
<td>Christian Jensen</td>
<td>
<a href="https://github.com/jensenbox">jensenbox</a>
</td>
<td>cjensen</td>
</tr>
<tr> <tr>
<td>Christopher Clarke</td> <td>Christopher Clarke</td>
<td> <td>
@ -747,13 +726,6 @@ Listed in alphabetical order.
</td> </td>
<td></td> <td></td>
</tr> </tr>
<tr>
<td>Denis Darii</td>
<td>
<a href="https://github.com/DNX">DNX</a>
</td>
<td></td>
</tr>
<tr> <tr>
<td>Denis Orehovsky</td> <td>Denis Orehovsky</td>
<td> <td>
@ -817,13 +789,6 @@ Listed in alphabetical order.
</td> </td>
<td></td> <td></td>
</tr> </tr>
<tr>
<td>Ed Morley</td>
<td>
<a href="https://github.com/edmorley">edmorley</a>
</td>
<td></td>
</tr>
<tr> <tr>
<td>Emanuel Calso</td> <td>Emanuel Calso</td>
<td> <td>
@ -1020,13 +985,6 @@ Listed in alphabetical order.
</td> </td>
<td></td> <td></td>
</tr> </tr>
<tr>
<td>Hana Belay</td>
<td>
<a href="https://github.com/earthcomfy">earthcomfy</a>
</td>
<td></td>
</tr>
<tr> <tr>
<td>Hana Quadara</td> <td>Hana Quadara</td>
<td> <td>
@ -1111,13 +1069,6 @@ Listed in alphabetical order.
</td> </td>
<td></td> <td></td>
</tr> </tr>
<tr>
<td>Igor Jerosimić</td>
<td>
<a href="https://github.com/igor-wl">igor-wl</a>
</td>
<td></td>
</tr>
<tr> <tr>
<td>Imran Rahman</td> <td>Imran Rahman</td>
<td> <td>
@ -1335,13 +1286,6 @@ Listed in alphabetical order.
</td> </td>
<td></td> <td></td>
</tr> </tr>
<tr>
<td>Kawsar Alam Foysal</td>
<td>
<a href="https://github.com/iamfoysal">iamfoysal</a>
</td>
<td></td>
</tr>
<tr> <tr>
<td>Keith Bailey</td> <td>Keith Bailey</td>
<td> <td>
@ -1545,13 +1489,6 @@ Listed in alphabetical order.
</td> </td>
<td></td> <td></td>
</tr> </tr>
<tr>
<td>Mariot Tsitoara</td>
<td>
<a href="https://github.com/mariot">mariot</a>
</td>
<td></td>
</tr>
<tr> <tr>
<td>Marlon Castillo</td> <td>Marlon Castillo</td>
<td> <td>
@ -1888,13 +1825,6 @@ Listed in alphabetical order.
</td> </td>
<td></td> <td></td>
</tr> </tr>
<tr>
<td>Pepa</td>
<td>
<a href="https://github.com/07pepa">07pepa</a>
</td>
<td></td>
</tr>
<tr> <tr>
<td>Peter Bittner</td> <td>Peter Bittner</td>
<td> <td>
@ -1937,13 +1867,6 @@ Listed in alphabetical order.
</td> </td>
<td></td> <td></td>
</tr> </tr>
<tr>
<td>Pulse-Mind</td>
<td>
<a href="https://github.com/pulse-mind">pulse-mind</a>
</td>
<td></td>
</tr>
<tr> <tr>
<td>quroom</td> <td>quroom</td>
<td> <td>
@ -1951,13 +1874,6 @@ Listed in alphabetical order.
</td> </td>
<td></td> <td></td>
</tr> </tr>
<tr>
<td>qwerrrqw</td>
<td>
<a href="https://github.com/qwerrrqw">qwerrrqw</a>
</td>
<td></td>
</tr>
<tr> <tr>
<td>Raony Guimarães Corrêa</td> <td>Raony Guimarães Corrêa</td>
<td> <td>

View File

@ -13,13 +13,13 @@ Powered by [Cookiecutter](https://github.com/cookiecutter/cookiecutter), Cookiec
production-ready Django projects quickly. production-ready Django projects quickly.
- Documentation: <https://cookiecutter-django.readthedocs.io/en/latest/> - Documentation: <https://cookiecutter-django.readthedocs.io/en/latest/>
- See [Troubleshooting](https://cookiecutter-django.readthedocs.io/en/latest/5-help/troubleshooting.html) for common errors and obstacles - See [Troubleshooting](https://cookiecutter-django.readthedocs.io/en/latest/troubleshooting.html) for common errors and obstacles
- If you have problems with Cookiecutter Django, please open [issues](https://github.com/cookiecutter/cookiecutter-django/issues/new) don't send - If you have problems with Cookiecutter Django, please open [issues](https://github.com/cookiecutter/cookiecutter-django/issues/new) don't send
emails to the maintainers. emails to the maintainers.
## Features ## Features
- For Django 5.1 - For Django 5.0
- Works with Python 3.12 - Works with Python 3.12
- Renders Django projects with 100% starting test coverage - Renders Django projects with 100% starting test coverage
- Twitter [Bootstrap](https://github.com/twbs/bootstrap) v5 - Twitter [Bootstrap](https://github.com/twbs/bootstrap) v5
@ -51,7 +51,7 @@ _These features can be enabled during initial project setup._
## Constraints ## Constraints
- Only maintained 3rd party libraries are used. - Only maintained 3rd party libraries are used.
- Uses PostgreSQL everywhere: 13 - 16 ([MySQL fork](https://github.com/mabdullahadeel/cookiecutter-django-mysql) also available). - Uses PostgreSQL everywhere: 12 - 16 ([MySQL fork](https://github.com/mabdullahadeel/cookiecutter-django-mysql) also available).
- Environment variables for configuration (This won't work with Apache/mod_wsgi). - Environment variables for configuration (This won't work with Apache/mod_wsgi).
## Support this Project! ## Support this Project!
@ -94,7 +94,7 @@ You'll be prompted for some values. Provide them, then a Django project will be
**Warning**: After this point, change 'Daniel Greenfeld', 'pydanny', etc to your own information. **Warning**: After this point, change 'Daniel Greenfeld', 'pydanny', etc to your own information.
Answer the prompts with your own desired [options](http://cookiecutter-django.readthedocs.io/en/latest/1-getting-started/project-generation-options.html). For example: Answer the prompts with your own desired [options](http://cookiecutter-django.readthedocs.io/en/latest/project-generation-options.html). For example:
Cloning into 'cookiecutter-django'... Cloning into 'cookiecutter-django'...
remote: Counting objects: 550, done. remote: Counting objects: 550, done.
@ -133,7 +133,8 @@ Answer the prompts with your own desired [options](http://cookiecutter-django.re
2 - 15 2 - 15
3 - 14 3 - 14
4 - 13 4 - 13
Choose from 1, 2, 3, 4 [1]: 1 5 - 12
Choose from 1, 2, 3, 4, 5 [1]: 1
Select cloud_provider: Select cloud_provider:
1 - AWS 1 - AWS
2 - GCP 2 - GCP

View File

@ -18,7 +18,7 @@
"windows": "n", "windows": "n",
"editor": ["None", "PyCharm", "VS Code"], "editor": ["None", "PyCharm", "VS Code"],
"use_docker": "n", "use_docker": "n",
"postgresql_version": ["16", "15", "14", "13"], "postgresql_version": ["16", "15", "14", "13", "12"],
"cloud_provider": ["AWS", "GCP", "Azure", "None"], "cloud_provider": ["AWS", "GCP", "Azure", "None"],
"mail_service": [ "mail_service": [
"Mailgun", "Mailgun",

View File

@ -70,6 +70,7 @@ postgresql_version:
2. 15 2. 15
3. 14 3. 14
4. 13 4. 13
5. 12
cloud_provider: cloud_provider:
Select a cloud provider for static & media files. The choices are: Select a cloud provider for static & media files. The choices are:

View File

@ -39,6 +39,7 @@ The following table lists settings and their defaults for third-party applicatio
======================================= =========================== ============================================== ====================================================================== ======================================= =========================== ============================================== ======================================================================
Environment Variable Django Setting Development Default Production Default Environment Variable Django Setting Development Default Production Default
======================================= =========================== ============================================== ====================================================================== ======================================= =========================== ============================================== ======================================================================
CELERY_BROKER_URL CELERY_BROKER_URL auto w/ Docker; raises error w/o raises error
DJANGO_AWS_ACCESS_KEY_ID AWS_ACCESS_KEY_ID n/a raises error DJANGO_AWS_ACCESS_KEY_ID AWS_ACCESS_KEY_ID n/a raises error
DJANGO_AWS_SECRET_ACCESS_KEY AWS_SECRET_ACCESS_KEY n/a raises error DJANGO_AWS_SECRET_ACCESS_KEY AWS_SECRET_ACCESS_KEY n/a raises error
DJANGO_AWS_STORAGE_BUCKET_NAME AWS_STORAGE_BUCKET_NAME n/a raises error DJANGO_AWS_STORAGE_BUCKET_NAME AWS_STORAGE_BUCKET_NAME n/a raises error

View File

@ -242,41 +242,6 @@ The stack comes with a dedicated node service to build the static assets, watch
.. _Sass: https://sass-lang.com/ .. _Sass: https://sass-lang.com/
.. _live reloading: https://browsersync.io .. _live reloading: https://browsersync.io
Using Just for Docker Commands
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
We have included a ``justfile`` to simplify the use of frequent Docker commands for local development.
.. warning::
Currently, "Just" does not reliably handle signals or forward them to its subprocesses. As a result,
pressing CTRL+C (or sending other signals like SIGTERM, SIGINT, or SIGHUP) may only interrupt
"Just" itself rather than its subprocesses.
For more information, see `this GitHub issue <https://github.com/casey/just/issues/2473>`_.
First, install Just using one of the methods described in the `official documentation <https://just.systems/man/en/packages.html>`_.
Here are the available commands:
- ``just build``
Builds the Python image using the local Docker Compose file.
- ``just up``
Starts the containers in detached mode and removes orphaned containers.
- ``just down``
Stops the running containers.
- ``just prune``
Stops and removes containers along with their volumes. You can optionally pass an argument with the service name to prune a single container.
- ``just logs``
Shows container logs. You can optionally pass an argument with the service name to view logs for a specific service.
- ``just manage <command>``
Runs Django management commands within the container. Replace ``<command>`` with any valid Django management command, such as ``migrate``, ``createsuperuser``, or ``shell``.
(Optionally) Developing locally with HTTPS (Optionally) Developing locally with HTTPS
------------------------------------------ ------------------------------------------

View File

@ -55,6 +55,8 @@ First things first.
#. Set the environment variables for your database(s): :: #. Set the environment variables for your database(s): ::
$ export DATABASE_URL=postgres://postgres:<password>@127.0.0.1:5432/<DB name given to createdb> $ export DATABASE_URL=postgres://postgres:<password>@127.0.0.1:5432/<DB name given to createdb>
# Optional: set broker URL if using Celery
$ export CELERY_BROKER_URL=redis://localhost:6379/0
.. note:: .. note::

View File

@ -14,7 +14,6 @@ Run these commands to deploy the project to Heroku:
# Note: this is not a free plan # Note: this is not a free plan
heroku addons:create heroku-postgresql:essential-0 heroku addons:create heroku-postgresql:essential-0
# On Windows use double quotes for the time zone, e.g. # On Windows use double quotes for the time zone, e.g.
# heroku pg:backups schedule --at "02:00 America/Los_Angeles" DATABASE_URL # heroku pg:backups schedule --at "02:00 America/Los_Angeles" DATABASE_URL
heroku pg:backups schedule --at '02:00 America/Los_Angeles' DATABASE_URL heroku pg:backups schedule --at '02:00 America/Los_Angeles' DATABASE_URL
@ -25,6 +24,10 @@ Run these commands to deploy the project to Heroku:
# Assuming you chose Mailgun as mail service (see below for others) # Assuming you chose Mailgun as mail service (see below for others)
heroku addons:create mailgun:starter heroku addons:create mailgun:starter
heroku config:set PYTHONHASHSEED=random
heroku config:set WEB_CONCURRENCY=4
heroku config:set DJANGO_DEBUG=False heroku config:set DJANGO_DEBUG=False
heroku config:set DJANGO_SETTINGS_MODULE=config.settings.production heroku config:set DJANGO_SETTINGS_MODULE=config.settings.production
heroku config:set DJANGO_SECRET_KEY="$(openssl rand -base64 64)" heroku config:set DJANGO_SECRET_KEY="$(openssl rand -base64 64)"
@ -83,6 +86,8 @@ it's in the ``Procfile``, but is turned off by default:
.. code-block:: bash .. code-block:: bash
# Set the broker URL to Redis
heroku config:set CELERY_BROKER_URL=`heroku config:get REDIS_URL`
# Scale dyno to 1 instance # Scale dyno to 1 instance
heroku ps:scale worker=1 heroku ps:scale worker=1

View File

@ -188,7 +188,7 @@ latex_documents = [
"cookiecutter-django Documentation", "cookiecutter-django Documentation",
"cookiecutter-django", "cookiecutter-django",
"manual", "manual",
), )
] ]
# The name of an image file (relative to this directory) to place at the top of # The name of an image file (relative to this directory) to place at the top of
@ -223,7 +223,7 @@ man_pages = [
"Cookiecutter Django documentation", "Cookiecutter Django documentation",
["Daniel Roy Greenfeld"], ["Daniel Roy Greenfeld"],
1, 1,
), )
] ]
# If true, show URL addresses after external links. # If true, show URL addresses after external links.
@ -242,7 +242,7 @@ texinfo_documents = [
"Cookiecutter Django documentation", "Cookiecutter Django documentation",
"Daniel Roy Greenfeld", "Daniel Roy Greenfeld",
"Cookiecutter Django", "Cookiecutter Django",
"A Cookiecutter template for creating production-ready Django projects quickly.", "A Cookiecutter template for creating production-ready " "Django projects quickly.",
"Miscellaneous", "Miscellaneous",
) )
] ]

View File

@ -1,8 +1,21 @@
"""
NOTE:
the below code is to be maintained Python 2.x-compatible
as the whole Cookiecutter Django project initialization
can potentially be run in Python 2.x environment
(at least so we presume in `pre_gen_project.py`).
TODO: restrict Cookiecutter Django project initialization to
Python 3.x environments only
"""
from __future__ import print_function
import json import json
import os
import random import random
import shutil import shutil
import string import string
from pathlib import Path
try: try:
# Inspired by # Inspired by
@ -24,28 +37,40 @@ DEBUG_VALUE = "debug"
def remove_open_source_files(): def remove_open_source_files():
file_names = ["CONTRIBUTORS.txt", "LICENSE"] file_names = ["CONTRIBUTORS.txt", "LICENSE"]
for file_name in file_names: for file_name in file_names:
Path(file_name).unlink() os.remove(file_name)
def remove_gplv3_files(): def remove_gplv3_files():
file_names = ["COPYING"] file_names = ["COPYING"]
for file_name in file_names: for file_name in file_names:
Path(file_name).unlink() os.remove(file_name)
def remove_custom_user_manager_files(): def remove_custom_user_manager_files():
users_path = Path("{{cookiecutter.project_slug}}", "users") os.remove(
(users_path / "managers.py").unlink() os.path.join(
(users_path / "tests" / "test_managers.py").unlink() "{{cookiecutter.project_slug}}",
"users",
"managers.py",
)
)
os.remove(
os.path.join(
"{{cookiecutter.project_slug}}",
"users",
"tests",
"test_managers.py",
)
)
def remove_pycharm_files(): def remove_pycharm_files():
idea_dir_path = Path(".idea") idea_dir_path = ".idea"
if idea_dir_path.exists(): if os.path.exists(idea_dir_path):
shutil.rmtree(idea_dir_path) shutil.rmtree(idea_dir_path)
docs_dir_path = Path("docs", "pycharm") docs_dir_path = os.path.join("docs", "pycharm")
if docs_dir_path.exists(): if os.path.exists(docs_dir_path):
shutil.rmtree(docs_dir_path) shutil.rmtree(docs_dir_path)
@ -57,18 +82,13 @@ def remove_docker_files():
"docker-compose.local.yml", "docker-compose.local.yml",
"docker-compose.production.yml", "docker-compose.production.yml",
".dockerignore", ".dockerignore",
"justfile",
] ]
for file_name in file_names: for file_name in file_names:
Path(file_name).unlink() os.remove(file_name)
if "{{ cookiecutter.editor }}" == "PyCharm": if "{{ cookiecutter.editor }}" == "PyCharm":
file_names = ["docker_compose_up_django.xml", "docker_compose_up_docs.xml"] file_names = ["docker_compose_up_django.xml", "docker_compose_up_docs.xml"]
for file_name in file_names: for file_name in file_names:
Path(".idea", "runConfigurations", file_name).unlink() os.remove(os.path.join(".idea", "runConfigurations", file_name))
def remove_nginx_docker_files():
shutil.rmtree(Path("compose", "production", "nginx"))
def remove_utility_files(): def remove_utility_files():
@ -76,23 +96,23 @@ def remove_utility_files():
def remove_heroku_files(): def remove_heroku_files():
file_names = ["Procfile", "requirements.txt"] file_names = ["Procfile", "runtime.txt", "requirements.txt"]
for file_name in file_names: for file_name in file_names:
if file_name == "requirements.txt" and "{{ cookiecutter.ci_tool }}".lower() == "travis": if file_name == "requirements.txt" and "{{ cookiecutter.ci_tool }}".lower() == "travis":
# don't remove the file if we are using travisci but not using heroku # don't remove the file if we are using travisci but not using heroku
continue continue
Path(file_name).unlink() os.remove(file_name)
shutil.rmtree("bin") shutil.rmtree("bin")
def remove_sass_files(): def remove_sass_files():
shutil.rmtree(Path("{{cookiecutter.project_slug}}", "static", "sass")) shutil.rmtree(os.path.join("{{cookiecutter.project_slug}}", "static", "sass"))
def remove_gulp_files(): def remove_gulp_files():
file_names = ["gulpfile.mjs"] file_names = ["gulpfile.js"]
for file_name in file_names: for file_name in file_names:
Path(file_name).unlink() os.remove(file_name)
def remove_webpack_files(): def remove_webpack_files():
@ -101,30 +121,36 @@ def remove_webpack_files():
def remove_vendors_js(): def remove_vendors_js():
vendors_js_path = Path("{{ cookiecutter.project_slug }}", "static", "js", "vendors.js") vendors_js_path = os.path.join(
if vendors_js_path.exists(): "{{ cookiecutter.project_slug }}",
vendors_js_path.unlink() "static",
"js",
"vendors.js",
)
if os.path.exists(vendors_js_path):
os.remove(vendors_js_path)
def remove_packagejson_file(): def remove_packagejson_file():
file_names = ["package.json"] file_names = ["package.json"]
for file_name in file_names: for file_name in file_names:
Path(file_name).unlink() os.remove(file_name)
def update_package_json(remove_dev_deps=None, remove_keys=None, scripts=None): def update_package_json(remove_dev_deps=None, remove_keys=None, scripts=None):
remove_dev_deps = remove_dev_deps or [] remove_dev_deps = remove_dev_deps or []
remove_keys = remove_keys or [] remove_keys = remove_keys or []
scripts = scripts or {} scripts = scripts or {}
package_json = Path("package.json") with open("package.json", mode="r") as fd:
content = json.loads(package_json.read_text()) content = json.load(fd)
for package_name in remove_dev_deps: for package_name in remove_dev_deps:
content["devDependencies"].pop(package_name) content["devDependencies"].pop(package_name)
for key in remove_keys: for key in remove_keys:
content.pop(key) content.pop(key)
content["scripts"].update(scripts) content["scripts"].update(scripts)
updated_content = json.dumps(content, ensure_ascii=False, indent=2) + "\n" with open("package.json", mode="w") as fd:
package_json.write_text(updated_content) json.dump(content, fd, ensure_ascii=False, indent=2)
fd.write("\n")
def handle_js_runner(choice, use_docker, use_async): def handle_js_runner(choice, use_docker, use_async):
@ -149,7 +175,7 @@ def handle_js_runner(choice, use_docker, use_async):
remove_keys=["babel"], remove_keys=["babel"],
scripts={ scripts={
"dev": "gulp", "dev": "gulp",
"build": "gulp build", "build": "gulp generate-assets",
}, },
) )
remove_webpack_files() remove_webpack_files()
@ -188,8 +214,8 @@ def handle_js_runner(choice, use_docker, use_async):
def remove_prettier_pre_commit(): def remove_prettier_pre_commit():
pre_commit_yaml = Path(".pre-commit-config.yaml") with open(".pre-commit-config.yaml", "r") as fd:
content = pre_commit_yaml.read_text().splitlines() content = fd.readlines()
removing = False removing = False
new_lines = [] new_lines = []
@ -201,34 +227,35 @@ def remove_prettier_pre_commit():
if not removing: if not removing:
new_lines.append(line) new_lines.append(line)
pre_commit_yaml.write_text("\n".join(new_lines)) with open(".pre-commit-config.yaml", "w") as fd:
fd.writelines(new_lines)
def remove_celery_files(): def remove_celery_files():
file_paths = [ file_names = [
Path("config", "celery_app.py"), os.path.join("config", "celery_app.py"),
Path("{{ cookiecutter.project_slug }}", "users", "tasks.py"), os.path.join("{{ cookiecutter.project_slug }}", "users", "tasks.py"),
Path("{{ cookiecutter.project_slug }}", "users", "tests", "test_tasks.py"), os.path.join("{{ cookiecutter.project_slug }}", "users", "tests", "test_tasks.py"),
] ]
for file_path in file_paths: for file_name in file_names:
file_path.unlink() os.remove(file_name)
def remove_async_files(): def remove_async_files():
file_paths = [ file_names = [
Path("config", "asgi.py"), os.path.join("config", "asgi.py"),
Path("config", "websocket.py"), os.path.join("config", "websocket.py"),
] ]
for file_path in file_paths: for file_name in file_names:
file_path.unlink() os.remove(file_name)
def remove_dottravisyml_file(): def remove_dottravisyml_file():
Path(".travis.yml").unlink() os.remove(".travis.yml")
def remove_dotgitlabciyml_file(): def remove_dotgitlabciyml_file():
Path(".gitlab-ci.yml").unlink() os.remove(".gitlab-ci.yml")
def remove_dotgithub_folder(): def remove_dotgithub_folder():
@ -236,7 +263,7 @@ def remove_dotgithub_folder():
def remove_dotdrone_file(): def remove_dotdrone_file():
Path(".drone.yml").unlink() os.remove(".drone.yml")
def generate_random_string(length, using_digits=False, using_ascii_letters=False, using_punctuation=False): def generate_random_string(length, using_digits=False, using_ascii_letters=False, using_punctuation=False):
@ -262,7 +289,7 @@ def generate_random_string(length, using_digits=False, using_ascii_letters=False
return "".join([random.choice(symbols) for _ in range(length)]) return "".join([random.choice(symbols) for _ in range(length)])
def set_flag(file_path: Path, flag, value=None, formatted=None, *args, **kwargs): def set_flag(file_path, flag, value=None, formatted=None, *args, **kwargs):
if value is None: if value is None:
random_string = generate_random_string(*args, **kwargs) random_string = generate_random_string(*args, **kwargs)
if random_string is None: if random_string is None:
@ -275,7 +302,7 @@ def set_flag(file_path: Path, flag, value=None, formatted=None, *args, **kwargs)
random_string = formatted.format(random_string) random_string = formatted.format(random_string)
value = random_string value = random_string
with file_path.open("r+") as f: with open(file_path, "r+") as f:
file_contents = f.read().replace(flag, value) file_contents = f.read().replace(flag, value)
f.seek(0) f.seek(0)
f.write(file_contents) f.write(file_contents)
@ -284,7 +311,7 @@ def set_flag(file_path: Path, flag, value=None, formatted=None, *args, **kwargs)
return value return value
def set_django_secret_key(file_path: Path): def set_django_secret_key(file_path):
django_secret_key = set_flag( django_secret_key = set_flag(
file_path, file_path,
"!!!SET DJANGO_SECRET_KEY!!!", "!!!SET DJANGO_SECRET_KEY!!!",
@ -295,7 +322,7 @@ def set_django_secret_key(file_path: Path):
return django_secret_key return django_secret_key
def set_django_admin_url(file_path: Path): def set_django_admin_url(file_path):
django_admin_url = set_flag( django_admin_url = set_flag(
file_path, file_path,
"!!!SET DJANGO_ADMIN_URL!!!", "!!!SET DJANGO_ADMIN_URL!!!",
@ -350,16 +377,16 @@ def set_celery_flower_password(file_path, value=None):
def append_to_gitignore_file(ignored_line): def append_to_gitignore_file(ignored_line):
with Path(".gitignore").open("a") as gitignore_file: with open(".gitignore", "a") as gitignore_file:
gitignore_file.write(ignored_line) gitignore_file.write(ignored_line)
gitignore_file.write("\n") gitignore_file.write("\n")
def set_flags_in_envs(postgres_user, celery_flower_user, debug=False): def set_flags_in_envs(postgres_user, celery_flower_user, debug=False):
local_django_envs_path = Path(".envs", ".local", ".django") local_django_envs_path = os.path.join(".envs", ".local", ".django")
production_django_envs_path = Path(".envs", ".production", ".django") production_django_envs_path = os.path.join(".envs", ".production", ".django")
local_postgres_envs_path = Path(".envs", ".local", ".postgres") local_postgres_envs_path = os.path.join(".envs", ".local", ".postgres")
production_postgres_envs_path = Path(".envs", ".production", ".postgres") production_postgres_envs_path = os.path.join(".envs", ".production", ".postgres")
set_django_secret_key(production_django_envs_path) set_django_secret_key(production_django_envs_path)
set_django_admin_url(production_django_envs_path) set_django_admin_url(production_django_envs_path)
@ -376,33 +403,35 @@ def set_flags_in_envs(postgres_user, celery_flower_user, debug=False):
def set_flags_in_settings_files(): def set_flags_in_settings_files():
set_django_secret_key(Path("config", "settings", "local.py")) set_django_secret_key(os.path.join("config", "settings", "local.py"))
set_django_secret_key(Path("config", "settings", "test.py")) set_django_secret_key(os.path.join("config", "settings", "test.py"))
def remove_envs_and_associated_files(): def remove_envs_and_associated_files():
shutil.rmtree(".envs") shutil.rmtree(".envs")
Path("merge_production_dotenvs_in_dotenv.py").unlink() os.remove("merge_production_dotenvs_in_dotenv.py")
shutil.rmtree("tests") shutil.rmtree("tests")
def remove_celery_compose_dirs(): def remove_celery_compose_dirs():
shutil.rmtree(Path("compose", "local", "django", "celery")) shutil.rmtree(os.path.join("compose", "local", "django", "celery"))
shutil.rmtree(Path("compose", "production", "django", "celery")) shutil.rmtree(os.path.join("compose", "production", "django", "celery"))
def remove_node_dockerfile(): def remove_node_dockerfile():
shutil.rmtree(Path("compose", "local", "node")) shutil.rmtree(os.path.join("compose", "local", "node"))
def remove_aws_dockerfile(): def remove_aws_dockerfile():
shutil.rmtree(Path("compose", "production", "aws")) shutil.rmtree(os.path.join("compose", "production", "aws"))
def remove_drf_starter_files(): def remove_drf_starter_files():
Path("config", "api_router.py").unlink() os.remove(os.path.join("config", "api_router.py"))
shutil.rmtree(Path("{{cookiecutter.project_slug}}", "users", "api")) shutil.rmtree(os.path.join("{{cookiecutter.project_slug}}", "users", "api"))
shutil.rmtree(Path("{{cookiecutter.project_slug}}", "users", "tests", "api")) os.remove(os.path.join("{{cookiecutter.project_slug}}", "users", "tests", "test_drf_urls.py"))
os.remove(os.path.join("{{cookiecutter.project_slug}}", "users", "tests", "test_drf_views.py"))
os.remove(os.path.join("{{cookiecutter.project_slug}}", "users", "tests", "test_swagger.py"))
def main(): def main():
@ -428,8 +457,6 @@ def main():
if "{{ cookiecutter.use_docker }}".lower() == "y": if "{{ cookiecutter.use_docker }}".lower() == "y":
remove_utility_files() remove_utility_files()
if "{{ cookiecutter.cloud_provider }}".lower() != "none":
remove_nginx_docker_files()
else: else:
remove_docker_files() remove_docker_files()

View File

@ -1,3 +1,15 @@
"""
NOTE:
the below code is to be maintained Python 2.x-compatible
as the whole Cookiecutter Django project initialization
can potentially be run in Python 2.x environment.
TODO: restrict Cookiecutter Django project initialization
to Python 3.x environments only
"""
from __future__ import print_function
import sys import sys
TERMINATOR = "\x1b[0m" TERMINATOR = "\x1b[0m"
@ -22,10 +34,36 @@ assert project_slug == project_slug.lower(), "'{}' project slug should be all lo
assert "\\" not in "{{ cookiecutter.author_name }}", "Don't include backslashes in author name." assert "\\" not in "{{ cookiecutter.author_name }}", "Don't include backslashes in author name."
if "{{ cookiecutter.use_docker }}".lower() == "n":
python_major_version = sys.version_info[0]
if python_major_version == 2:
print(
WARNING + "You're running cookiecutter under Python 2, but the generated "
"project requires Python 3.12+. Do you want to proceed (y/n)? " + TERMINATOR
)
yes_options, no_options = frozenset(["y"]), frozenset(["n"])
while True:
choice = raw_input().lower() # noqa: F821
if choice in yes_options:
break
elif choice in no_options:
print(INFO + "Generation process stopped as requested." + TERMINATOR)
sys.exit(1)
else:
print(
HINT
+ "Please respond with {} or {}: ".format(
", ".join(["'{}'".format(o) for o in yes_options if not o == ""]),
", ".join(["'{}'".format(o) for o in no_options if not o == ""]),
)
+ TERMINATOR
)
if "{{ cookiecutter.use_whitenoise }}".lower() == "n" and "{{ cookiecutter.cloud_provider }}" == "None": if "{{ cookiecutter.use_whitenoise }}".lower() == "n" and "{{ cookiecutter.cloud_provider }}" == "None":
print("You should either use Whitenoise or select a Cloud Provider to serve static files") print("You should either use Whitenoise or select a " "Cloud Provider to serve static files")
sys.exit(1) sys.exit(1)
if "{{ cookiecutter.mail_service }}" == "Amazon SES" and "{{ cookiecutter.cloud_provider }}" != "AWS": if "{{ cookiecutter.mail_service }}" == "Amazon SES" and "{{ cookiecutter.cloud_provider }}" != "AWS":
print("You should either use AWS or select a different Mail Service for sending emails.") print("You should either use AWS or select a different " "Mail Service for sending emails.")
sys.exit(1) sys.exit(1)

View File

@ -1,6 +1,6 @@
[project] [project]
name = "cookiecutter-django" name = "cookiecutter-django"
version = "2025.04.08" version = "2024.10.11"
description = "A Cookiecutter template for creating production-ready Django projects quickly." description = "A Cookiecutter template for creating production-ready Django projects quickly."
readme = "README.md" readme = "README.md"
keywords = [ keywords = [
@ -14,7 +14,7 @@ license = { text = "BSD" }
authors = [ authors = [
{ name = "Daniel Roy Greenfeld", email = "pydanny@gmail.com" }, { name = "Daniel Roy Greenfeld", email = "pydanny@gmail.com" },
] ]
requires-python = ">=3.12,<3.13" requires-python = ">=3.12"
classifiers = [ classifiers = [
"Development Status :: 4 - Beta", "Development Status :: 4 - Beta",
"Environment :: Console", "Environment :: Console",
@ -25,38 +25,37 @@ classifiers = [
"Programming Language :: Python", "Programming Language :: Python",
"Programming Language :: Python :: 3 :: Only", "Programming Language :: Python :: 3 :: Only",
"Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Programming Language :: Python :: Implementation :: CPython", "Programming Language :: Python :: Implementation :: CPython",
"Topic :: Software Development", "Topic :: Software Development",
] ]
dependencies = [ dependencies = [
"binaryornot==0.4.4", "binaryornot==0.4.4",
"cookiecutter==2.6", "cookiecutter==2.6",
"django-upgrade==1.22.2", "django-upgrade==1.21",
"djlint==1.36.4", "djlint==1.35.2",
"gitpython==3.1.43", "gitpython==3.1.43",
"jinja2==3.1.5", "jinja2==3.1.4",
"pre-commit==4.1.0", "pre-commit==3.8",
"pygithub==2.5", "pygithub==2.4",
"pytest==8.3.4", "pytest==8.3.3",
"pytest-cookies==0.7", "pytest-cookies==0.7",
"pytest-instafail==0.5", "pytest-instafail==0.5",
"pytest-xdist==3.6.1", "pytest-xdist==3.6.1",
"pyyaml==6.0.2", "pyyaml==6.0.2",
"requests==2.32.3", "requests==2.32.3",
"ruff==0.11.4", "ruff==0.6.9",
"sh==2.1; sys_platform!='win23'", "sh==2.0.7; sys_platform!='win23'",
"tox==4.23.2", "tox==4.21.2",
"tox-uv>=1.17", "tox-uv>=1.11.2",
] ]
urls = { Repository = "https://github.com/cookiecutter/cookiecutter-django" } optional-dependencies.docs = [
[dependency-groups]
docs = [
"myst-parser>=4", "myst-parser>=4",
"sphinx>=8.0.2", "sphinx>=8.0.2",
"sphinx-autobuild>=2024.10.3", "sphinx-autobuild>=2024.10.3",
"sphinx-rtd-theme>=3", "sphinx-rtd-theme>=3",
] ]
urls = { Repository = "https://github.com/cookiecutter/cookiecutter-django" }
[tool.black] [tool.black]
line-length = 119 line-length = 119
@ -75,9 +74,6 @@ known_first_party = [
"hooks", "hooks",
] ]
[tool.pyproject-fmt]
keep_full_version = true
# ==== pytest ==== # ==== pytest ====
[tool.pytest.ini_options] [tool.pytest.ini_options]

View File

@ -12,6 +12,7 @@ from __future__ import annotations
import os import os
import re import re
import sys import sys
from collections.abc import Iterable
from pathlib import Path from pathlib import Path
from typing import TYPE_CHECKING, Any, NamedTuple from typing import TYPE_CHECKING, Any, NamedTuple
@ -19,8 +20,6 @@ import requests
from github import Github from github import Github
if TYPE_CHECKING: if TYPE_CHECKING:
from collections.abc import Iterable
from github.Issue import Issue from github.Issue import Issue
CURRENT_FILE = Path(__file__) CURRENT_FILE = Path(__file__)
@ -84,7 +83,7 @@ def get_name_and_version(requirements_line: str) -> tuple[str, ...]:
def get_all_latest_django_versions( def get_all_latest_django_versions(
django_max_version: tuple[DjVersion] | None = None, django_max_version: tuple[DjVersion] = None,
) -> tuple[DjVersion, list[DjVersion]]: ) -> tuple[DjVersion, list[DjVersion]]:
""" """
Grabs all Django versions that are worthy of a GitHub issue. Grabs all Django versions that are worthy of a GitHub issue.
@ -222,7 +221,8 @@ class GitHubManager:
if supported_dj_versions: if supported_dj_versions:
if any(v >= needed_dj_version for v in supported_dj_versions): if any(v >= needed_dj_version for v in supported_dj_versions):
return package_info["info"]["version"], "" return package_info["info"]["version"], ""
return "", "" else:
return "", ""
# Django classifier DNE; assume it isn't a Django lib # Django classifier DNE; assume it isn't a Django lib
# Great exceptions include pylint-django, where we need to do this manually... # Great exceptions include pylint-django, where we need to do this manually...

View File

@ -1,69 +0,0 @@
from __future__ import annotations
import json
from pathlib import Path
ROOT = Path(__file__).parent.parent
TEMPLATED_ROOT = ROOT / "{{cookiecutter.project_slug}}"
DOCKERFILE = TEMPLATED_ROOT / "compose" / "local" / "node" / "Dockerfile"
PROD_DOCKERFILE = TEMPLATED_ROOT / "compose" / "production" / "django" / "Dockerfile"
PACKAGE_JSON = TEMPLATED_ROOT / "package.json"
CI_YML = ROOT / ".github" / "workflows" / "ci.yml"
def main() -> None:
new_version = get_version_from_dockerfile()
old_version = get_version_from_package_json()
if old_version != new_version:
update_package_json_version(old_version, new_version)
update_ci_node_version(old_version, new_version)
update_production_node_version(old_version, new_version)
def get_version_from_dockerfile() -> str:
# Extract version out of base image name:
# FROM docker.io/node:22.13-bookworm-slim
# -> 22.13
with DOCKERFILE.open("r") as f:
for line in f:
if "FROM docker.io/node:" in line:
_, _, docker_tag = line.partition(":")
version_str, _, _ = docker_tag.partition("-")
return version_str
raise RuntimeError("Could not find version in Dockerfile")
def get_version_from_package_json() -> str:
package_json = json.loads(PACKAGE_JSON.read_text())
return package_json["engines"]["node"]
def update_package_json_version(old_version: str, new_version: str) -> None:
package_json_text = PACKAGE_JSON.read_text()
package_json_text = package_json_text.replace(
f'"node": "{old_version}"',
f'"node": "{new_version}"',
)
PACKAGE_JSON.write_text(package_json_text)
def update_ci_node_version(old_version: str, new_version: str) -> None:
yml_content = CI_YML.read_text()
yml_content = yml_content.replace(
f'node-version: "{old_version}"',
f'node-version: "{new_version}"',
)
CI_YML.write_text(yml_content)
def update_production_node_version(old_version: str, new_version: str) -> None:
dockerfile_content = PROD_DOCKERFILE.read_text()
dockerfile_content = dockerfile_content.replace(
f"FROM docker.io/node:{old_version}",
f"FROM docker.io/node:{new_version}",
)
PROD_DOCKERFILE.write_text(dockerfile_content)
if __name__ == "__main__":
main()

View File

@ -1,56 +0,0 @@
from __future__ import annotations
import subprocess
import tomllib
from pathlib import Path
ROOT = Path(__file__).parent.parent
TEMPLATED_ROOT = ROOT / "{{cookiecutter.project_slug}}"
REQUIREMENTS_LOCAL_TXT = TEMPLATED_ROOT / "requirements" / "local.txt"
PRE_COMMIT_CONFIG = TEMPLATED_ROOT / ".pre-commit-config.yaml"
PYPROJECT_TOML = ROOT / "pyproject.toml"
def main() -> None:
new_version = get_requirements_txt_version()
old_version = get_pyproject_toml_version()
if old_version == new_version:
return
update_ruff_version(old_version, new_version)
subprocess.run(["uv", "lock", "--no-upgrade"], cwd=ROOT)
def get_requirements_txt_version() -> str:
content = REQUIREMENTS_LOCAL_TXT.read_text()
for line in content.split("\n"):
if line.startswith("ruff"):
return line.split(" ")[0].split("==")[1]
raise RuntimeError("Could not find ruff version in requirements/local.txt")
def get_pyproject_toml_version() -> str:
data = tomllib.loads(PYPROJECT_TOML.read_text())
for dependency in data["project"]["dependencies"]:
if dependency.startswith("ruff=="):
return dependency.split("==")[1]
raise RuntimeError("Could not find ruff version in pyproject.toml")
def update_ruff_version(old_version: str, new_version: str) -> None:
# Update pyproject.toml
new_content = PYPROJECT_TOML.read_text().replace(
f"ruff=={old_version}",
f"ruff=={new_version}",
)
PYPROJECT_TOML.write_text(new_content)
# Update pre-commit config
new_content = PRE_COMMIT_CONFIG.read_text().replace(
f"repo: https://github.com/astral-sh/ruff-pre-commit\n rev: v{old_version}",
f"repo: https://github.com/astral-sh/ruff-pre-commit\n rev: v{new_version}",
)
PRE_COMMIT_CONFIG.write_text(new_content)
if __name__ == "__main__":
main()

View File

@ -1,7 +1,6 @@
import datetime as dt import datetime as dt
import os import os
import re import re
import subprocess
from collections.abc import Iterable from collections.abc import Iterable
from pathlib import Path from pathlib import Path
@ -52,12 +51,8 @@ def main() -> None:
update_version(setup_py_path, release) update_version(setup_py_path, release)
print(f"Updated version in {setup_py_path}") print(f"Updated version in {setup_py_path}")
# Run uv lock
uv_lock_path = ROOT / "uv.lock"
subprocess.run(["uv", "lock", "--no-upgrade"], cwd=ROOT)
# Commit changes, create tag and push # Commit changes, create tag and push
update_git_repo([changelog_path, setup_py_path, uv_lock_path], release) update_git_repo([changelog_path, setup_py_path], release)
# Create GitHub release # Create GitHub release
github_release = repo.create_git_release( github_release = repo.create_git_release(

View File

@ -2,8 +2,6 @@ import glob
import os import os
import re import re
import sys import sys
from collections.abc import Iterable
from pathlib import Path
import pytest import pytest
@ -63,6 +61,7 @@ SUPPORTED_COMBINATIONS = [
{"postgresql_version": "15"}, {"postgresql_version": "15"},
{"postgresql_version": "14"}, {"postgresql_version": "14"},
{"postgresql_version": "13"}, {"postgresql_version": "13"},
{"postgresql_version": "12"},
{"cloud_provider": "AWS", "use_whitenoise": "y"}, {"cloud_provider": "AWS", "use_whitenoise": "y"},
{"cloud_provider": "AWS", "use_whitenoise": "n"}, {"cloud_provider": "AWS", "use_whitenoise": "n"},
{"cloud_provider": "GCP", "use_whitenoise": "y"}, {"cloud_provider": "GCP", "use_whitenoise": "y"},
@ -147,19 +146,19 @@ def _fixture_id(ctx):
return "-".join(f"{key}:{value}" for key, value in ctx.items()) return "-".join(f"{key}:{value}" for key, value in ctx.items())
def build_files_list(base_path: Path): def build_files_list(base_dir):
"""Build a list containing absolute paths to the generated files.""" """Build a list containing absolute paths to the generated files."""
return [dirpath / file_path for dirpath, subdirs, files in base_path.walk() for file_path in files] return [os.path.join(dirpath, file_path) for dirpath, subdirs, files in os.walk(base_dir) for file_path in files]
def check_paths(paths: Iterable[Path]): def check_paths(paths):
"""Method to check all paths have correct substitutions.""" """Method to check all paths have correct substitutions."""
# Assert that no match is found in any of the files # Assert that no match is found in any of the files
for path in paths: for path in paths:
if is_binary(str(path)): if is_binary(path):
continue continue
for line in path.open(): for line in open(path):
match = RE_OBJ.search(line) match = RE_OBJ.search(line)
assert match is None, f"cookiecutter variable not replaced in {path}" assert match is None, f"cookiecutter variable not replaced in {path}"
@ -174,7 +173,7 @@ def test_project_generation(cookies, context, context_override):
assert result.project_path.name == context["project_slug"] assert result.project_path.name == context["project_slug"]
assert result.project_path.is_dir() assert result.project_path.is_dir()
paths = build_files_list(result.project_path) paths = build_files_list(str(result.project_path))
assert paths assert paths
check_paths(paths) check_paths(paths)
@ -272,7 +271,7 @@ def test_djlint_check_passes(cookies, context_override):
@pytest.mark.parametrize( @pytest.mark.parametrize(
("use_docker", "expected_test_script"), ["use_docker", "expected_test_script"],
[ [
("n", "pytest"), ("n", "pytest"),
("y", "docker compose -f docker-compose.local.yml run django pytest"), ("y", "docker compose -f docker-compose.local.yml run django pytest"),
@ -287,7 +286,7 @@ def test_travis_invokes_pytest(cookies, context, use_docker, expected_test_scrip
assert result.project_path.name == context["project_slug"] assert result.project_path.name == context["project_slug"]
assert result.project_path.is_dir() assert result.project_path.is_dir()
with (result.project_path / ".travis.yml").open() as travis_yml: with open(f"{result.project_path}/.travis.yml") as travis_yml:
try: try:
yml = yaml.safe_load(travis_yml)["jobs"]["include"] yml = yaml.safe_load(travis_yml)["jobs"]["include"]
assert yml[0]["script"] == ["ruff check ."] assert yml[0]["script"] == ["ruff check ."]
@ -297,7 +296,7 @@ def test_travis_invokes_pytest(cookies, context, use_docker, expected_test_scrip
@pytest.mark.parametrize( @pytest.mark.parametrize(
("use_docker", "expected_test_script"), ["use_docker", "expected_test_script"],
[ [
("n", "pytest"), ("n", "pytest"),
("y", "docker compose -f docker-compose.local.yml run django pytest"), ("y", "docker compose -f docker-compose.local.yml run django pytest"),
@ -312,11 +311,11 @@ def test_gitlab_invokes_precommit_and_pytest(cookies, context, use_docker, expec
assert result.project_path.name == context["project_slug"] assert result.project_path.name == context["project_slug"]
assert result.project_path.is_dir() assert result.project_path.is_dir()
with (result.project_path / ".gitlab-ci.yml").open() as gitlab_yml: with open(f"{result.project_path}/.gitlab-ci.yml") as gitlab_yml:
try: try:
gitlab_config = yaml.safe_load(gitlab_yml) gitlab_config = yaml.safe_load(gitlab_yml)
assert gitlab_config["precommit"]["script"] == [ assert gitlab_config["precommit"]["script"] == [
"pre-commit run --show-diff-on-failure --color=always --all-files", "pre-commit run --show-diff-on-failure --color=always --all-files"
] ]
assert gitlab_config["pytest"]["script"] == [expected_test_script] assert gitlab_config["pytest"]["script"] == [expected_test_script]
except yaml.YAMLError as e: except yaml.YAMLError as e:
@ -324,7 +323,7 @@ def test_gitlab_invokes_precommit_and_pytest(cookies, context, use_docker, expec
@pytest.mark.parametrize( @pytest.mark.parametrize(
("use_docker", "expected_test_script"), ["use_docker", "expected_test_script"],
[ [
("n", "pytest"), ("n", "pytest"),
("y", "docker compose -f docker-compose.local.yml run django pytest"), ("y", "docker compose -f docker-compose.local.yml run django pytest"),
@ -339,7 +338,7 @@ def test_github_invokes_linter_and_pytest(cookies, context, use_docker, expected
assert result.project_path.name == context["project_slug"] assert result.project_path.name == context["project_slug"]
assert result.project_path.is_dir() assert result.project_path.is_dir()
with (result.project_path / ".github" / "workflows" / "ci.yml").open() as github_yml: with open(f"{result.project_path}/.github/workflows/ci.yml") as github_yml:
try: try:
github_config = yaml.safe_load(github_yml) github_config = yaml.safe_load(github_yml)
linter_present = False linter_present = False
@ -379,7 +378,7 @@ def test_error_if_incompatible(cookies, context, invalid_context):
@pytest.mark.parametrize( @pytest.mark.parametrize(
("editor", "pycharm_docs_exist"), ["editor", "pycharm_docs_exist"],
[ [
("None", False), ("None", False),
("PyCharm", True), ("PyCharm", True),
@ -390,9 +389,9 @@ def test_pycharm_docs_removed(cookies, context, editor, pycharm_docs_exist):
context.update({"editor": editor}) context.update({"editor": editor})
result = cookies.bake(extra_context=context) result = cookies.bake(extra_context=context)
index_rst = result.project_path / "docs" / "index.rst" with open(f"{result.project_path}/docs/index.rst") as f:
has_pycharm_docs = "pycharm/configuration" in index_rst.read_text() has_pycharm_docs = "pycharm/configuration" in f.read()
assert has_pycharm_docs is pycharm_docs_exist assert has_pycharm_docs is pycharm_docs_exist
def test_trim_domain_email(cookies, context): def test_trim_domain_email(cookies, context):
@ -402,7 +401,7 @@ def test_trim_domain_email(cookies, context):
"use_docker": "y", "use_docker": "y",
"domain_name": " example.com ", "domain_name": " example.com ",
"email": " me@example.com ", "email": " me@example.com ",
}, }
) )
result = cookies.bake(extra_context=context) result = cookies.bake(extra_context=context)

View File

@ -18,21 +18,22 @@ cd my_awesome_project
docker compose -f docker-compose.local.yml build docker compose -f docker-compose.local.yml build
# run the project's type checks # run the project's type checks
docker compose -f docker-compose.local.yml run --rm django mypy my_awesome_project docker compose -f docker-compose.local.yml run django mypy my_awesome_project
# run the project's tests # run the project's tests
docker compose -f docker-compose.local.yml run --rm django pytest docker compose -f docker-compose.local.yml run django pytest
# return non-zero status code if there are migrations that have not been created # return non-zero status code if there are migrations that have not been created
docker compose -f docker-compose.local.yml run --rm django python manage.py makemigrations --check || { echo "ERROR: there were changes in the models, but migration listed above have not been created and are not saved in version control"; exit 1; } docker compose -f docker-compose.local.yml run django python manage.py makemigrations --check || { echo "ERROR: there were changes in the models, but migration listed above have not been created and are not saved in version control"; exit 1; }
# Test support for translations # Test support for translations
docker compose -f docker-compose.local.yml run --rm django python manage.py makemessages --all docker compose -f docker-compose.local.yml run django python manage.py makemessages --all
# Make sure the check doesn't raise any warnings # Make sure the check doesn't raise any warnings
docker compose -f docker-compose.local.yml run --rm \ docker compose -f docker-compose.local.yml run \
-e DJANGO_SECRET_KEY="$(openssl rand -base64 64)" \ -e DJANGO_SECRET_KEY="$(openssl rand -base64 64)" \
-e REDIS_URL=redis://redis:6379/0 \ -e REDIS_URL=redis://redis:6379/0 \
-e CELERY_BROKER_URL=redis://redis:6379/0 \
-e DJANGO_AWS_ACCESS_KEY_ID=x \ -e DJANGO_AWS_ACCESS_KEY_ID=x \
-e DJANGO_AWS_SECRET_ACCESS_KEY=x \ -e DJANGO_AWS_SECRET_ACCESS_KEY=x \
-e DJANGO_AWS_STORAGE_BUCKET_NAME=x \ -e DJANGO_AWS_STORAGE_BUCKET_NAME=x \
@ -42,10 +43,10 @@ docker compose -f docker-compose.local.yml run --rm \
django python manage.py check --settings=config.settings.production --deploy --database default --fail-level WARNING django python manage.py check --settings=config.settings.production --deploy --database default --fail-level WARNING
# Generate the HTML for the documentation # Generate the HTML for the documentation
docker compose -f docker-compose.docs.yml run --rm docs make html docker compose -f docker-compose.docs.yml run docs make html
# Run npm build script if package.json is present # Run npm build script if package.json is present
if [ -f "package.json" ] if [ -f "package.json" ]
then then
docker compose -f docker-compose.local.yml run --rm node npm run build docker compose -f docker-compose.local.yml run node npm run build
fi fi

View File

@ -8,7 +8,7 @@ import pytest
from hooks.post_gen_project import append_to_gitignore_file from hooks.post_gen_project import append_to_gitignore_file
@pytest.fixture @pytest.fixture()
def working_directory(tmp_path): def working_directory(tmp_path):
prev_cwd = Path.cwd() prev_cwd = Path.cwd()
os.chdir(tmp_path) os.chdir(tmp_path)

327
uv.lock
View File

@ -1,5 +1,5 @@
version = 1 version = 1
requires-python = "==3.12.*" requires-python = ">=3.12"
[[package]] [[package]]
name = "alabaster" name = "alabaster"
@ -12,16 +12,15 @@ wheels = [
[[package]] [[package]]
name = "anyio" name = "anyio"
version = "4.7.0" version = "4.6.0"
source = { registry = "https://pypi.org/simple" } source = { registry = "https://pypi.org/simple" }
dependencies = [ dependencies = [
{ name = "idna" }, { name = "idna" },
{ name = "sniffio" }, { name = "sniffio" },
{ name = "typing-extensions" },
] ]
sdist = { url = "https://files.pythonhosted.org/packages/f6/40/318e58f669b1a9e00f5c4453910682e2d9dd594334539c7b7817dabb765f/anyio-4.7.0.tar.gz", hash = "sha256:2f834749c602966b7d456a7567cafcb309f96482b5081d14ac93ccd457f9dd48", size = 177076 } sdist = { url = "https://files.pythonhosted.org/packages/78/49/f3f17ec11c4a91fe79275c426658e509b07547f874b14c1a526d86a83fc8/anyio-4.6.0.tar.gz", hash = "sha256:137b4559cbb034c477165047febb6ff83f390fc3b20bf181c1fc0a728cb8beeb", size = 170983 }
wheels = [ wheels = [
{ url = "https://files.pythonhosted.org/packages/a0/7a/4daaf3b6c08ad7ceffea4634ec206faeff697526421c20f07628c7372156/anyio-4.7.0-py3-none-any.whl", hash = "sha256:ea60c3723ab42ba6fff7e8ccb0488c898ec538ff4df1f1d5e642c3601d07e352", size = 93052 }, { url = "https://files.pythonhosted.org/packages/9e/ef/7a4f225581a0d7886ea28359179cb861d7fbcdefad29663fc1167b86f69f/anyio-4.6.0-py3-none-any.whl", hash = "sha256:c7d2e9d63e31599eeb636c8c5c03a7e108d73b345f064f1c19fdc87b79036a9a", size = 89631 },
] ]
[[package]] [[package]]
@ -96,6 +95,17 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/fc/83/8353e5c9b01bb46332dac3dfb18e6c597a04ceb085c19c814c2f78a8c0d0/cffi-1.17.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:17c6d6d3260c7f2d94f657e6872591fe8733872a86ed1345bda872cfc8c74885", size = 488388 }, { url = "https://files.pythonhosted.org/packages/fc/83/8353e5c9b01bb46332dac3dfb18e6c597a04ceb085c19c814c2f78a8c0d0/cffi-1.17.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:17c6d6d3260c7f2d94f657e6872591fe8733872a86ed1345bda872cfc8c74885", size = 488388 },
{ url = "https://files.pythonhosted.org/packages/73/0c/f9d5ca9a095b1fc88ef77d1f8b85d11151c374144e4606da33874e17b65b/cffi-1.17.0-cp312-cp312-win32.whl", hash = "sha256:c3b8bd3133cd50f6b637bb4322822c94c5ce4bf0d724ed5ae70afce62187c492", size = 172096 }, { url = "https://files.pythonhosted.org/packages/73/0c/f9d5ca9a095b1fc88ef77d1f8b85d11151c374144e4606da33874e17b65b/cffi-1.17.0-cp312-cp312-win32.whl", hash = "sha256:c3b8bd3133cd50f6b637bb4322822c94c5ce4bf0d724ed5ae70afce62187c492", size = 172096 },
{ url = "https://files.pythonhosted.org/packages/72/21/8c5d285fe20a6e31d29325f1287bb0e55f7d93630a5a44cafdafb5922495/cffi-1.17.0-cp312-cp312-win_amd64.whl", hash = "sha256:dca802c8db0720ce1c49cce1149ff7b06e91ba15fa84b1d59144fef1a1bc7ac2", size = 181478 }, { url = "https://files.pythonhosted.org/packages/72/21/8c5d285fe20a6e31d29325f1287bb0e55f7d93630a5a44cafdafb5922495/cffi-1.17.0-cp312-cp312-win_amd64.whl", hash = "sha256:dca802c8db0720ce1c49cce1149ff7b06e91ba15fa84b1d59144fef1a1bc7ac2", size = 181478 },
{ url = "https://files.pythonhosted.org/packages/17/8f/581f2f3c3464d5f7cf87c2f7a5ba9acc6976253e02d73804240964243ec2/cffi-1.17.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:6ce01337d23884b21c03869d2f68c5523d43174d4fc405490eb0091057943118", size = 182638 },
{ url = "https://files.pythonhosted.org/packages/8d/1c/c9afa66684b7039f48018eb11b229b659dfb32b7a16b88251bac106dd1ff/cffi-1.17.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:cab2eba3830bf4f6d91e2d6718e0e1c14a2f5ad1af68a89d24ace0c6b17cced7", size = 178453 },
{ url = "https://files.pythonhosted.org/packages/cc/b6/1a134d479d3a5a1ff2fabbee551d1d3f1dd70f453e081b5f70d604aae4c0/cffi-1.17.0-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:14b9cbc8f7ac98a739558eb86fabc283d4d564dafed50216e7f7ee62d0d25377", size = 454441 },
{ url = "https://files.pythonhosted.org/packages/b1/b4/e1569475d63aad8042b0935dbf62ae2a54d1e9142424e2b0e924d2d4a529/cffi-1.17.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b00e7bcd71caa0282cbe3c90966f738e2db91e64092a877c3ff7f19a1628fdcb", size = 478543 },
{ url = "https://files.pythonhosted.org/packages/d2/40/a9ad03fbd64309dec5bb70bc803a9a6772602de0ee164d7b9a6ca5a89249/cffi-1.17.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:41f4915e09218744d8bae14759f983e466ab69b178de38066f7579892ff2a555", size = 485463 },
{ url = "https://files.pythonhosted.org/packages/a6/1a/f10be60e006dd9242a24bcc2b1cd55c34c578380100f742d8c610f7a5d26/cffi-1.17.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e4760a68cab57bfaa628938e9c2971137e05ce48e762a9cb53b76c9b569f1204", size = 470854 },
{ url = "https://files.pythonhosted.org/packages/cc/b3/c035ed21aa3d39432bd749fe331ee90e4bc83ea2dbed1f71c4bc26c41084/cffi-1.17.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:011aff3524d578a9412c8b3cfaa50f2c0bd78e03eb7af7aa5e0df59b158efb2f", size = 479096 },
{ url = "https://files.pythonhosted.org/packages/00/cb/6f7edde01131de9382c89430b8e253b8c8754d66b63a62059663ceafeab2/cffi-1.17.0-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:a003ac9edc22d99ae1286b0875c460351f4e101f8c9d9d2576e78d7e048f64e0", size = 484013 },
{ url = "https://files.pythonhosted.org/packages/b9/83/8e4e8c211ea940210d293e951bf06b1bfb90f2eeee590e9778e99b4a8676/cffi-1.17.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:ef9528915df81b8f4c7612b19b8628214c65c9b7f74db2e34a646a0a2a0da2d4", size = 488119 },
{ url = "https://files.pythonhosted.org/packages/5e/52/3f7cfbc4f444cb4f73ff17b28690d12436dde665f67d68f1e1687908ab6c/cffi-1.17.0-cp313-cp313-win32.whl", hash = "sha256:70d2aa9fb00cf52034feac4b913181a6e10356019b18ef89bc7c12a283bf5f5a", size = 172122 },
{ url = "https://files.pythonhosted.org/packages/94/19/cf5baa07ee0f0e55eab7382459fbddaba0fdb0ba45973dd92556ae0d02db/cffi-1.17.0-cp313-cp313-win_amd64.whl", hash = "sha256:b7b6ea9e36d32582cda3465f54c4b454f62f23cb083ebc7a94e2ca6ef011c3a7", size = 181504 },
] ]
[[package]] [[package]]
@ -145,7 +155,7 @@ name = "click"
version = "8.1.7" version = "8.1.7"
source = { registry = "https://pypi.org/simple" } source = { registry = "https://pypi.org/simple" }
dependencies = [ dependencies = [
{ name = "colorama", marker = "sys_platform == 'win32'" }, { name = "colorama", marker = "platform_system == 'Windows'" },
] ]
sdist = { url = "https://files.pythonhosted.org/packages/96/d3/f04c7bfcf5c1862a2a5b845c6b2b360488cf47af55dfa79c98f6a6bf98b5/click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de", size = 336121 } sdist = { url = "https://files.pythonhosted.org/packages/96/d3/f04c7bfcf5c1862a2a5b845c6b2b360488cf47af55dfa79c98f6a6bf98b5/click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de", size = 336121 }
wheels = [ wheels = [
@ -182,7 +192,7 @@ wheels = [
[[package]] [[package]]
name = "cookiecutter-django" name = "cookiecutter-django"
version = "2025.4.8" version = "2024.10.10"
source = { virtual = "." } source = { virtual = "." }
dependencies = [ dependencies = [
{ name = "binaryornot" }, { name = "binaryornot" },
@ -205,7 +215,7 @@ dependencies = [
{ name = "tox-uv" }, { name = "tox-uv" },
] ]
[package.dev-dependencies] [package.optional-dependencies]
docs = [ docs = [
{ name = "myst-parser" }, { name = "myst-parser" },
{ name = "sphinx" }, { name = "sphinx" },
@ -217,30 +227,26 @@ docs = [
requires-dist = [ requires-dist = [
{ name = "binaryornot", specifier = "==0.4.4" }, { name = "binaryornot", specifier = "==0.4.4" },
{ name = "cookiecutter", specifier = "==2.6" }, { name = "cookiecutter", specifier = "==2.6" },
{ name = "django-upgrade", specifier = "==1.22.2" }, { name = "django-upgrade", specifier = "==1.21" },
{ name = "djlint", specifier = "==1.36.4" }, { name = "djlint", specifier = "==1.35.2" },
{ name = "gitpython", specifier = "==3.1.43" }, { name = "gitpython", specifier = "==3.1.43" },
{ name = "jinja2", specifier = "==3.1.5" }, { name = "jinja2", specifier = "==3.1.4" },
{ name = "pre-commit", specifier = "==4.1.0" }, { name = "myst-parser", marker = "extra == 'docs'", specifier = ">=4" },
{ name = "pygithub", specifier = "==2.5" }, { name = "pre-commit", specifier = "==3.8" },
{ name = "pytest", specifier = "==8.3.4" }, { name = "pygithub", specifier = "==2.4" },
{ name = "pytest", specifier = "==8.3.3" },
{ name = "pytest-cookies", specifier = "==0.7" }, { name = "pytest-cookies", specifier = "==0.7" },
{ name = "pytest-instafail", specifier = "==0.5" }, { name = "pytest-instafail", specifier = "==0.5" },
{ name = "pytest-xdist", specifier = "==3.6.1" }, { name = "pytest-xdist", specifier = "==3.6.1" },
{ name = "pyyaml", specifier = "==6.0.2" }, { name = "pyyaml", specifier = "==6.0.2" },
{ name = "requests", specifier = "==2.32.3" }, { name = "requests", specifier = "==2.32.3" },
{ name = "ruff", specifier = "==0.11.4" }, { name = "ruff", specifier = "==0.6.9" },
{ name = "sh", marker = "sys_platform != 'win23'", specifier = "==2.1" }, { name = "sh", marker = "sys_platform != 'win23'", specifier = "==2.0.7" },
{ name = "tox", specifier = "==4.23.2" }, { name = "sphinx", marker = "extra == 'docs'", specifier = ">=8.0.2" },
{ name = "tox-uv", specifier = ">=1.17" }, { name = "sphinx-autobuild", marker = "extra == 'docs'", specifier = ">=2024.10.3" },
] { name = "sphinx-rtd-theme", marker = "extra == 'docs'", specifier = ">=3" },
{ name = "tox", specifier = "==4.21.2" },
[package.metadata.requires-dev] { name = "tox-uv", specifier = ">=1.11.2" },
docs = [
{ name = "myst-parser", specifier = ">=4" },
{ name = "sphinx", specifier = ">=8.0.2" },
{ name = "sphinx-autobuild", specifier = ">=2024.10.3" },
{ name = "sphinx-rtd-theme", specifier = ">=3" },
] ]
[[package]] [[package]]
@ -306,24 +312,26 @@ wheels = [
[[package]] [[package]]
name = "django-upgrade" name = "django-upgrade"
version = "1.22.2" version = "1.21.0"
source = { registry = "https://pypi.org/simple" } source = { registry = "https://pypi.org/simple" }
dependencies = [ dependencies = [
{ name = "tokenize-rt" }, { name = "tokenize-rt" },
] ]
sdist = { url = "https://files.pythonhosted.org/packages/f3/46/24e32ffdad682df8c273e2f434096246c89d265948a2fd214307f31eeeec/django_upgrade-1.22.2.tar.gz", hash = "sha256:8643abdde2961e3c60173ebee84f48371ffbec5181095a38cac080947af0d2ae", size = 67932 } sdist = { url = "https://files.pythonhosted.org/packages/2e/30/5215e526e054831cbbc454ce81fb5e825224019824a185e3c011cf199b90/django_upgrade-1.21.0.tar.gz", hash = "sha256:e65021029e7d18b407bd128a8ccb31e5e06685068b37b6b1eaf2f77aa3d3df98", size = 66708 }
wheels = [ wheels = [
{ url = "https://files.pythonhosted.org/packages/98/64/7b1432a7eca9e8e24b27ef89b9badca59add35a6dc785a63aa886b167c9d/django_upgrade-1.22.2-py3-none-any.whl", hash = "sha256:fb76b183b2e8186bb1157734083569a4b754dce2e812c2a723454bd248fb1373", size = 69114 }, { url = "https://files.pythonhosted.org/packages/56/76/7a7eeb88657abf8a0f97fbab4f6600be2ec89577e3695c395b47e6860ec5/django_upgrade-1.21.0-py3-none-any.whl", hash = "sha256:a0a7b11d5108fb2d3038cea2382c1332c9be4ff5059a38357fbd28116ebf3803", size = 67796 },
] ]
[[package]] [[package]]
name = "djlint" name = "djlint"
version = "1.36.4" version = "1.35.2"
source = { registry = "https://pypi.org/simple" } source = { registry = "https://pypi.org/simple" }
dependencies = [ dependencies = [
{ name = "click" }, { name = "click" },
{ name = "colorama" }, { name = "colorama" },
{ name = "cssbeautifier" }, { name = "cssbeautifier" },
{ name = "html-tag-names" },
{ name = "html-void-elements" },
{ name = "jsbeautifier" }, { name = "jsbeautifier" },
{ name = "json5" }, { name = "json5" },
{ name = "pathspec" }, { name = "pathspec" },
@ -331,13 +339,9 @@ dependencies = [
{ name = "regex" }, { name = "regex" },
{ name = "tqdm" }, { name = "tqdm" },
] ]
sdist = { url = "https://files.pythonhosted.org/packages/74/89/ecf5be9f5c59a0c53bcaa29671742c5e269cc7d0e2622e3f65f41df251bf/djlint-1.36.4.tar.gz", hash = "sha256:17254f218b46fe5a714b224c85074c099bcb74e3b2e1f15c2ddc2cf415a408a1", size = 47849 } sdist = { url = "https://files.pythonhosted.org/packages/a4/ee/ac8ee551ec04d5a214e62d008f40bf309574f103416482e03fb61fbad61c/djlint-1.35.2.tar.gz", hash = "sha256:318de9d4b9b0061a111f8f5164ecbacd8215f449dd4bd5a76d2a691c815ee103", size = 44684 }
wheels = [ wheels = [
{ url = "https://files.pythonhosted.org/packages/53/f5/9ae02b875604755d4d00cebf96b218b0faa3198edc630f56a139581aed87/djlint-1.36.4-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:ff9faffd7d43ac20467493fa71d5355b5b330a00ade1c4d1e859022f4195223b", size = 354886 }, { url = "https://files.pythonhosted.org/packages/e0/31/297cad1a493f2910d366418acd0f33da908dfb8b16b8d6c6bafddac4fa7d/djlint-1.35.2-py3-none-any.whl", hash = "sha256:4ba995bad378f2afa77c8ea56ba1c14429d9ff26a18e8ae23bc71eedb9152243", size = 50641 },
{ url = "https://files.pythonhosted.org/packages/97/51/284443ff2f2a278f61d4ae6ae55eaf820ad9f0fd386d781cdfe91f4de495/djlint-1.36.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:79489e262b5ac23a8dfb7ca37f1eea979674cfc2d2644f7061d95bea12c38f7e", size = 323237 },
{ url = "https://files.pythonhosted.org/packages/6d/5e/791f4c5571f3f168ad26fa3757af8f7a05c623fde1134a9c4de814ee33b7/djlint-1.36.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e58c5fa8c6477144a0be0a87273706a059e6dd0d6efae01146ae8c29cdfca675", size = 411719 },
{ url = "https://files.pythonhosted.org/packages/1f/11/894425add6f84deffcc6e373f2ce250f2f7b01aa58c7f230016ebe7a0085/djlint-1.36.4-cp312-cp312-win_amd64.whl", hash = "sha256:bb6903777bf3124f5efedcddf1f4716aef097a7ec4223fc0fa54b865829a6e08", size = 362076 },
{ url = "https://files.pythonhosted.org/packages/4b/67/f7aeea9be6fb3bd984487af8d0d80225a0b1e5f6f7126e3332d349fb13fe/djlint-1.36.4-py3-none-any.whl", hash = "sha256:e9699b8ac3057a6ed04fb90835b89bee954ed1959c01541ce4f8f729c938afdd", size = 52290 },
] ]
[[package]] [[package]]
@ -406,6 +410,24 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/95/04/ff642e65ad6b90db43e668d70ffb6736436c7ce41fcc549f4e9472234127/h11-0.14.0-py3-none-any.whl", hash = "sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761", size = 58259 }, { url = "https://files.pythonhosted.org/packages/95/04/ff642e65ad6b90db43e668d70ffb6736436c7ce41fcc549f4e9472234127/h11-0.14.0-py3-none-any.whl", hash = "sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761", size = 58259 },
] ]
[[package]]
name = "html-tag-names"
version = "0.1.2"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/41/7c/8c0dc3c5650036127fb4629d31cadf6cbdd57e21a77f9793fa8b2c8a3241/html-tag-names-0.1.2.tar.gz", hash = "sha256:04924aca48770f36b5a41c27e4d917062507be05118acb0ba869c97389084297", size = 15173 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/9a/e4/242318dcaa06d8525ff72332fc15cea2cffb84c06cfc73c7da6c6b45801a/html_tag_names-0.1.2-py3-none-any.whl", hash = "sha256:eeb69ef21078486b615241f0393a72b41352c5219ee648e7c61f5632d26f0420", size = 15218 },
]
[[package]]
name = "html-void-elements"
version = "0.1.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/80/5c/5f17d77256bf78ca98647517fadee50575e75d812daa01352c31d89d5bf2/html-void-elements-0.1.0.tar.gz", hash = "sha256:931b88f84cd606fee0b582c28fcd00e41d7149421fb673e1e1abd2f0c4f231f0", size = 14766 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/f5/0a/373f28a1cf37f8c9aa23c82cbcac7197ddea95c88b5a3eaa564cdb8de375/html_void_elements-0.1.0-py3-none-any.whl", hash = "sha256:784cf39db03cdeb017320d9301009f8f3480f9d7b254d0974272e80e0cb5e0d2", size = 14889 },
]
[[package]] [[package]]
name = "identify" name = "identify"
version = "2.6.0" version = "2.6.0"
@ -444,14 +466,14 @@ wheels = [
[[package]] [[package]]
name = "jinja2" name = "jinja2"
version = "3.1.5" version = "3.1.4"
source = { registry = "https://pypi.org/simple" } source = { registry = "https://pypi.org/simple" }
dependencies = [ dependencies = [
{ name = "markupsafe" }, { name = "markupsafe" },
] ]
sdist = { url = "https://files.pythonhosted.org/packages/af/92/b3130cbbf5591acf9ade8708c365f3238046ac7cb8ccba6e81abccb0ccff/jinja2-3.1.5.tar.gz", hash = "sha256:8fefff8dc3034e27bb80d67c671eb8a9bc424c0ef4c0826edbff304cceff43bb", size = 244674 } sdist = { url = "https://files.pythonhosted.org/packages/ed/55/39036716d19cab0747a5020fc7e907f362fbf48c984b14e62127f7e68e5d/jinja2-3.1.4.tar.gz", hash = "sha256:4a3aee7acbbe7303aede8e9648d13b8bf88a429282aa6122a993f0ac800cb369", size = 240245 }
wheels = [ wheels = [
{ url = "https://files.pythonhosted.org/packages/bd/0f/2ba5fbcd631e3e88689309dbe978c5769e883e4b84ebfe7da30b43275c5a/jinja2-3.1.5-py3-none-any.whl", hash = "sha256:aba0f4dc9ed8013c424088f68a5c226f7d6097ed89b246d7749c2ec4175c6adb", size = 134596 }, { url = "https://files.pythonhosted.org/packages/31/80/3a54838c3fb461f6fec263ebf3a3a41771bd05190238de3486aae8540c36/jinja2-3.1.4-py3-none-any.whl", hash = "sha256:bc5dd2abb727a5319567b7a813e6a2e7318c39f4f487cfe6c89c6f9c7d25197d", size = 133271 },
] ]
[[package]] [[package]]
@ -588,7 +610,7 @@ wheels = [
[[package]] [[package]]
name = "pre-commit" name = "pre-commit"
version = "4.1.0" version = "3.8.0"
source = { registry = "https://pypi.org/simple" } source = { registry = "https://pypi.org/simple" }
dependencies = [ dependencies = [
{ name = "cfgv" }, { name = "cfgv" },
@ -597,9 +619,9 @@ dependencies = [
{ name = "pyyaml" }, { name = "pyyaml" },
{ name = "virtualenv" }, { name = "virtualenv" },
] ]
sdist = { url = "https://files.pythonhosted.org/packages/2a/13/b62d075317d8686071eb843f0bb1f195eb332f48869d3c31a4c6f1e063ac/pre_commit-4.1.0.tar.gz", hash = "sha256:ae3f018575a588e30dfddfab9a05448bfbd6b73d78709617b5a2b853549716d4", size = 193330 } sdist = { url = "https://files.pythonhosted.org/packages/64/10/97ee2fa54dff1e9da9badbc5e35d0bbaef0776271ea5907eccf64140f72f/pre_commit-3.8.0.tar.gz", hash = "sha256:8bb6494d4a20423842e198980c9ecf9f96607a07ea29549e180eef9ae80fe7af", size = 177815 }
wheels = [ wheels = [
{ url = "https://files.pythonhosted.org/packages/43/b3/df14c580d82b9627d173ceea305ba898dca135feb360b6d84019d0803d3b/pre_commit-4.1.0-py2.py3-none-any.whl", hash = "sha256:d29e7cb346295bcc1cc75fc3e92e343495e3ea0196c9ec6ba53f49f10ab6ae7b", size = 220560 }, { url = "https://files.pythonhosted.org/packages/07/92/caae8c86e94681b42c246f0bca35c059a2f0529e5b92619f6aba4cf7e7b6/pre_commit-3.8.0-py2.py3-none-any.whl", hash = "sha256:9a90a53bf82fdd8778d58085faf8d83df56e40dfe18f45b19446e26bf1b3a63f", size = 204643 },
] ]
[[package]] [[package]]
@ -613,7 +635,7 @@ wheels = [
[[package]] [[package]]
name = "pygithub" name = "pygithub"
version = "2.5.0" version = "2.4.0"
source = { registry = "https://pypi.org/simple" } source = { registry = "https://pypi.org/simple" }
dependencies = [ dependencies = [
{ name = "deprecated" }, { name = "deprecated" },
@ -623,9 +645,9 @@ dependencies = [
{ name = "typing-extensions" }, { name = "typing-extensions" },
{ name = "urllib3" }, { name = "urllib3" },
] ]
sdist = { url = "https://files.pythonhosted.org/packages/16/ce/aa91d30040d9552c274e7ea8bd10a977600d508d579a4bb262b95eccf961/pygithub-2.5.0.tar.gz", hash = "sha256:e1613ac508a9be710920d26eb18b1905ebd9926aa49398e88151c1b526aad3cf", size = 3552804 } sdist = { url = "https://files.pythonhosted.org/packages/f1/a0/1e8b8ca88df9857836f5bf8e3ee15dfb810d19814ef700b12f99ce11f691/pygithub-2.4.0.tar.gz", hash = "sha256:6601e22627e87bac192f1e2e39c6e6f69a43152cfb8f307cee575879320b3051", size = 3476673 }
wheels = [ wheels = [
{ url = "https://files.pythonhosted.org/packages/37/05/bfbdbbc5d8aafd8dae9b3b6877edca561fccd8528ef5edc4e7b6d23721b5/PyGithub-2.5.0-py3-none-any.whl", hash = "sha256:b0b635999a658ab8e08720bdd3318893ff20e2275f6446fcf35bf3f44f2c0fd2", size = 375935 }, { url = "https://files.pythonhosted.org/packages/0a/f3/e185613c411757c0c18b904ea2db173f2872397eddf444a3fe8cdde47077/PyGithub-2.4.0-py3-none-any.whl", hash = "sha256:81935aa4bdc939fba98fee1cb47422c09157c56a27966476ff92775602b9ee24", size = 362599 },
] ]
[[package]] [[package]]
@ -685,7 +707,7 @@ wheels = [
[[package]] [[package]]
name = "pytest" name = "pytest"
version = "8.3.4" version = "8.3.3"
source = { registry = "https://pypi.org/simple" } source = { registry = "https://pypi.org/simple" }
dependencies = [ dependencies = [
{ name = "colorama", marker = "sys_platform == 'win32'" }, { name = "colorama", marker = "sys_platform == 'win32'" },
@ -693,9 +715,9 @@ dependencies = [
{ name = "packaging" }, { name = "packaging" },
{ name = "pluggy" }, { name = "pluggy" },
] ]
sdist = { url = "https://files.pythonhosted.org/packages/05/35/30e0d83068951d90a01852cb1cef56e5d8a09d20c7f511634cc2f7e0372a/pytest-8.3.4.tar.gz", hash = "sha256:965370d062bce11e73868e0335abac31b4d3de0e82f4007408d242b4f8610761", size = 1445919 } sdist = { url = "https://files.pythonhosted.org/packages/8b/6c/62bbd536103af674e227c41a8f3dcd022d591f6eed5facb5a0f31ee33bbc/pytest-8.3.3.tar.gz", hash = "sha256:70b98107bd648308a7952b06e6ca9a50bc660be218d53c257cc1fc94fda10181", size = 1442487 }
wheels = [ wheels = [
{ url = "https://files.pythonhosted.org/packages/11/92/76a1c94d3afee238333bc0a42b82935dd8f9cf8ce9e336ff87ee14d9e1cf/pytest-8.3.4-py3-none-any.whl", hash = "sha256:50e16d954148559c9a74109af1eaf0c945ba2d8f30f0a3d3335edde19788b6f6", size = 343083 }, { url = "https://files.pythonhosted.org/packages/6b/77/7440a06a8ead44c7757a64362dd22df5760f9b12dc5f11b6188cd2fc27a0/pytest-8.3.3-py3-none-any.whl", hash = "sha256:a6853c7375b2663155079443d2e45de913a911a11d669df02a50814944db57b2", size = 342341 },
] ]
[[package]] [[package]]
@ -775,6 +797,15 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/c9/1f/4f998c900485e5c0ef43838363ba4a9723ac0ad73a9dc42068b12aaba4e4/PyYAML-6.0.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8b9c7197f7cb2738065c481a0461e50ad02f18c78cd75775628afb4d7137fb3b", size = 756611 }, { url = "https://files.pythonhosted.org/packages/c9/1f/4f998c900485e5c0ef43838363ba4a9723ac0ad73a9dc42068b12aaba4e4/PyYAML-6.0.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8b9c7197f7cb2738065c481a0461e50ad02f18c78cd75775628afb4d7137fb3b", size = 756611 },
{ url = "https://files.pythonhosted.org/packages/df/d1/f5a275fdb252768b7a11ec63585bc38d0e87c9e05668a139fea92b80634c/PyYAML-6.0.2-cp312-cp312-win32.whl", hash = "sha256:ef6107725bd54b262d6dedcc2af448a266975032bc85ef0172c5f059da6325b4", size = 140591 }, { url = "https://files.pythonhosted.org/packages/df/d1/f5a275fdb252768b7a11ec63585bc38d0e87c9e05668a139fea92b80634c/PyYAML-6.0.2-cp312-cp312-win32.whl", hash = "sha256:ef6107725bd54b262d6dedcc2af448a266975032bc85ef0172c5f059da6325b4", size = 140591 },
{ url = "https://files.pythonhosted.org/packages/0c/e8/4f648c598b17c3d06e8753d7d13d57542b30d56e6c2dedf9c331ae56312e/PyYAML-6.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:7e7401d0de89a9a855c839bc697c079a4af81cf878373abd7dc625847d25cbd8", size = 156338 }, { url = "https://files.pythonhosted.org/packages/0c/e8/4f648c598b17c3d06e8753d7d13d57542b30d56e6c2dedf9c331ae56312e/PyYAML-6.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:7e7401d0de89a9a855c839bc697c079a4af81cf878373abd7dc625847d25cbd8", size = 156338 },
{ url = "https://files.pythonhosted.org/packages/ef/e3/3af305b830494fa85d95f6d95ef7fa73f2ee1cc8ef5b495c7c3269fb835f/PyYAML-6.0.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:efdca5630322a10774e8e98e1af481aad470dd62c3170801852d752aa7a783ba", size = 181309 },
{ url = "https://files.pythonhosted.org/packages/45/9f/3b1c20a0b7a3200524eb0076cc027a970d320bd3a6592873c85c92a08731/PyYAML-6.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:50187695423ffe49e2deacb8cd10510bc361faac997de9efef88badc3bb9e2d1", size = 171679 },
{ url = "https://files.pythonhosted.org/packages/7c/9a/337322f27005c33bcb656c655fa78325b730324c78620e8328ae28b64d0c/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ffe8360bab4910ef1b9e87fb812d8bc0a308b0d0eef8c8f44e0254ab3b07133", size = 733428 },
{ url = "https://files.pythonhosted.org/packages/a3/69/864fbe19e6c18ea3cc196cbe5d392175b4cf3d5d0ac1403ec3f2d237ebb5/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:17e311b6c678207928d649faa7cb0d7b4c26a0ba73d41e99c4fff6b6c3276484", size = 763361 },
{ url = "https://files.pythonhosted.org/packages/04/24/b7721e4845c2f162d26f50521b825fb061bc0a5afcf9a386840f23ea19fa/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70b189594dbe54f75ab3a1acec5f1e3faa7e8cf2f1e08d9b561cb41b845f69d5", size = 759523 },
{ url = "https://files.pythonhosted.org/packages/2b/b2/e3234f59ba06559c6ff63c4e10baea10e5e7df868092bf9ab40e5b9c56b6/PyYAML-6.0.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:41e4e3953a79407c794916fa277a82531dd93aad34e29c2a514c2c0c5fe971cc", size = 726660 },
{ url = "https://files.pythonhosted.org/packages/fe/0f/25911a9f080464c59fab9027482f822b86bf0608957a5fcc6eaac85aa515/PyYAML-6.0.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:68ccc6023a3400877818152ad9a1033e3db8625d899c72eacb5a668902e4d652", size = 751597 },
{ url = "https://files.pythonhosted.org/packages/14/0d/e2c3b43bbce3cf6bd97c840b46088a3031085179e596d4929729d8d68270/PyYAML-6.0.2-cp313-cp313-win32.whl", hash = "sha256:bc2fa7c6b47d6bc618dd7fb02ef6fdedb1090ec036abab80d4681424b84c1183", size = 140527 },
{ url = "https://files.pythonhosted.org/packages/fa/de/02b54f42487e3d3c6efb3f89428677074ca7bf43aae402517bc7cca949f3/PyYAML-6.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563", size = 156446 },
] ]
[[package]] [[package]]
@ -830,36 +861,36 @@ wheels = [
[[package]] [[package]]
name = "ruff" name = "ruff"
version = "0.11.4" version = "0.6.9"
source = { registry = "https://pypi.org/simple" } source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/e8/5b/3ae20f89777115944e89c2d8c2e795dcc5b9e04052f76d5347e35e0da66e/ruff-0.11.4.tar.gz", hash = "sha256:f45bd2fb1a56a5a85fae3b95add03fb185a0b30cf47f5edc92aa0355ca1d7407", size = 3933063 } sdist = { url = "https://files.pythonhosted.org/packages/26/0d/6148a48dab5662ca1d5a93b7c0d13c03abd3cc7e2f35db08410e47cef15d/ruff-0.6.9.tar.gz", hash = "sha256:b076ef717a8e5bc819514ee1d602bbdca5b4420ae13a9cf61a0c0a4f53a2baa2", size = 3095355 }
wheels = [ wheels = [
{ url = "https://files.pythonhosted.org/packages/9c/db/baee59ac88f57527fcbaad3a7b309994e42329c6bc4d4d2b681a3d7b5426/ruff-0.11.4-py3-none-linux_armv6l.whl", hash = "sha256:d9f4a761ecbde448a2d3e12fb398647c7f0bf526dbc354a643ec505965824ed2", size = 10106493 }, { url = "https://files.pythonhosted.org/packages/6e/8f/f7a0a0ef1818662efb32ed6df16078c95da7a0a3248d64c2410c1e27799f/ruff-0.6.9-py3-none-linux_armv6l.whl", hash = "sha256:064df58d84ccc0ac0fcd63bc3090b251d90e2a372558c0f057c3f75ed73e1ccd", size = 10440526 },
{ url = "https://files.pythonhosted.org/packages/c1/d6/9a0962cbb347f4ff98b33d699bf1193ff04ca93bed4b4222fd881b502154/ruff-0.11.4-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:8c1747d903447d45ca3d40c794d1a56458c51e5cc1bc77b7b64bd2cf0b1626cc", size = 10876382 }, { url = "https://files.pythonhosted.org/packages/8b/69/b179a5faf936a9e2ab45bb412a668e4661eded964ccfa19d533f29463ef6/ruff-0.6.9-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:140d4b5c9f5fc7a7b074908a78ab8d384dd7f6510402267bc76c37195c02a7ec", size = 10034612 },
{ url = "https://files.pythonhosted.org/packages/3a/8f/62bab0c7d7e1ae3707b69b157701b41c1ccab8f83e8501734d12ea8a839f/ruff-0.11.4-py3-none-macosx_11_0_arm64.whl", hash = "sha256:51a6494209cacca79e121e9b244dc30d3414dac8cc5afb93f852173a2ecfc906", size = 10237050 }, { url = "https://files.pythonhosted.org/packages/c7/ef/fd1b4be979c579d191eeac37b5cfc0ec906de72c8bcd8595e2c81bb700c1/ruff-0.6.9-py3-none-macosx_11_0_arm64.whl", hash = "sha256:53fd8ca5e82bdee8da7f506d7b03a261f24cd43d090ea9db9a1dc59d9313914c", size = 9706197 },
{ url = "https://files.pythonhosted.org/packages/09/96/e296965ae9705af19c265d4d441958ed65c0c58fc4ec340c27cc9d2a1f5b/ruff-0.11.4-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3f171605f65f4fc49c87f41b456e882cd0c89e4ac9d58e149a2b07930e1d466f", size = 10424984 }, { url = "https://files.pythonhosted.org/packages/29/61/b376d775deb5851cb48d893c568b511a6d3625ef2c129ad5698b64fb523c/ruff-0.6.9-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:645d7d8761f915e48a00d4ecc3686969761df69fb561dd914a773c1a8266e14e", size = 10751855 },
{ url = "https://files.pythonhosted.org/packages/e5/56/644595eb57d855afed6e54b852e2df8cd5ca94c78043b2f29bdfb29882d5/ruff-0.11.4-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ebf99ea9af918878e6ce42098981fc8c1db3850fef2f1ada69fb1dcdb0f8e79e", size = 9957438 }, { url = "https://files.pythonhosted.org/packages/13/d7/def9e5f446d75b9a9c19b24231a3a658c075d79163b08582e56fa5dcfa38/ruff-0.6.9-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:eae02b700763e3847595b9d2891488989cac00214da7f845f4bcf2989007d577", size = 10200889 },
{ url = "https://files.pythonhosted.org/packages/86/83/9d3f3bed0118aef3e871ded9e5687fb8c5776bde233427fd9ce0a45db2d4/ruff-0.11.4-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:edad2eac42279df12e176564a23fc6f4aaeeb09abba840627780b1bb11a9d223", size = 11547282 }, { url = "https://files.pythonhosted.org/packages/6c/d6/7f34160818bcb6e84ce293a5966cba368d9112ff0289b273fbb689046047/ruff-0.6.9-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7d5ccc9e58112441de8ad4b29dcb7a86dc25c5f770e3c06a9d57e0e5eba48829", size = 11038678 },
{ url = "https://files.pythonhosted.org/packages/40/e6/0c6e4f5ae72fac5ccb44d72c0111f294a5c2c8cc5024afcb38e6bda5f4b3/ruff-0.11.4-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:f103a848be9ff379fc19b5d656c1f911d0a0b4e3e0424f9532ececf319a4296e", size = 12182020 }, { url = "https://files.pythonhosted.org/packages/13/34/a40ff8ae62fb1b26fb8e6fa7e64bc0e0a834b47317880de22edd6bfb54fb/ruff-0.6.9-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:417b81aa1c9b60b2f8edc463c58363075412866ae4e2b9ab0f690dc1e87ac1b5", size = 11808682 },
{ url = "https://files.pythonhosted.org/packages/b5/92/4aed0e460aeb1df5ea0c2fbe8d04f9725cccdb25d8da09a0d3f5b8764bf8/ruff-0.11.4-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:193e6fac6eb60cc97b9f728e953c21cc38a20077ed64f912e9d62b97487f3f2d", size = 11679154 }, { url = "https://files.pythonhosted.org/packages/2e/6d/25a4386ae4009fc798bd10ba48c942d1b0b3e459b5403028f1214b6dd161/ruff-0.6.9-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3c866b631f5fbce896a74a6e4383407ba7507b815ccc52bcedabb6810fdb3ef7", size = 11330446 },
{ url = "https://files.pythonhosted.org/packages/1b/d3/7316aa2609f2c592038e2543483eafbc62a0e1a6a6965178e284808c095c/ruff-0.11.4-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7af4e5f69b7c138be8dcffa5b4a061bf6ba6a3301f632a6bce25d45daff9bc99", size = 13905985 }, { url = "https://files.pythonhosted.org/packages/f7/f6/bdf891a9200d692c94ebcd06ae5a2fa5894e522f2c66c2a12dd5d8cb2654/ruff-0.6.9-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7b118afbb3202f5911486ad52da86d1d52305b59e7ef2031cea3425142b97d6f", size = 12483048 },
{ url = "https://files.pythonhosted.org/packages/63/80/734d3d17546e47ff99871f44ea7540ad2bbd7a480ed197fe8a1c8a261075/ruff-0.11.4-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:126b1bf13154aa18ae2d6c3c5efe144ec14b97c60844cfa6eb960c2a05188222", size = 11348343 }, { url = "https://files.pythonhosted.org/packages/a7/86/96f4252f41840e325b3fa6c48297e661abb9f564bd7dcc0572398c8daa42/ruff-0.6.9-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a67267654edc23c97335586774790cde402fb6bbdb3c2314f1fc087dee320bfa", size = 10936855 },
{ url = "https://files.pythonhosted.org/packages/04/7b/70fc7f09a0161dce9613a4671d198f609e653d6f4ff9eee14d64c4c240fb/ruff-0.11.4-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:e8806daaf9dfa881a0ed603f8a0e364e4f11b6ed461b56cae2b1c0cab0645304", size = 10308487 }, { url = "https://files.pythonhosted.org/packages/45/87/801a52d26c8dbf73424238e9908b9ceac430d903c8ef35eab1b44fcfa2bd/ruff-0.6.9-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:3ef0cc774b00fec123f635ce5c547dac263f6ee9fb9cc83437c5904183b55ceb", size = 10713007 },
{ url = "https://files.pythonhosted.org/packages/1a/22/1cdd62dabd678d75842bf4944fd889cf794dc9e58c18cc547f9eb28f95ed/ruff-0.11.4-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:5d94bb1cc2fc94a769b0eb975344f1b1f3d294da1da9ddbb5a77665feb3a3019", size = 9929091 }, { url = "https://files.pythonhosted.org/packages/be/27/6f7161d90320a389695e32b6ebdbfbedde28ccbf52451e4b723d7ce744ad/ruff-0.6.9-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:12edd2af0c60fa61ff31cefb90aef4288ac4d372b4962c2864aeea3a1a2460c0", size = 10274594 },
{ url = "https://files.pythonhosted.org/packages/9f/20/40e0563506332313148e783bbc1e4276d657962cc370657b2fff20e6e058/ruff-0.11.4-py3-none-musllinux_1_2_i686.whl", hash = "sha256:995071203d0fe2183fc7a268766fd7603afb9996785f086b0d76edee8755c896", size = 10924659 }, { url = "https://files.pythonhosted.org/packages/00/52/dc311775e7b5f5b19831563cb1572ecce63e62681bccc609867711fae317/ruff-0.6.9-py3-none-musllinux_1_2_i686.whl", hash = "sha256:55bb01caeaf3a60b2b2bba07308a02fca6ab56233302406ed5245180a05c5625", size = 10608024 },
{ url = "https://files.pythonhosted.org/packages/b5/41/eef9b7aac8819d9e942f617f9db296f13d2c4576806d604aba8db5a753f1/ruff-0.11.4-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:7a37ca937e307ea18156e775a6ac6e02f34b99e8c23fe63c1996185a4efe0751", size = 11428160 }, { url = "https://files.pythonhosted.org/packages/98/b6/be0a1ddcbac65a30c985cf7224c4fce786ba2c51e7efeb5178fe410ed3cf/ruff-0.6.9-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:925d26471fa24b0ce5a6cdfab1bb526fb4159952385f386bdcc643813d472039", size = 10982085 },
{ url = "https://files.pythonhosted.org/packages/ff/61/c488943414fb2b8754c02f3879de003e26efdd20f38167ded3fb3fc1cda3/ruff-0.11.4-py3-none-win32.whl", hash = "sha256:0e9365a7dff9b93af933dab8aebce53b72d8f815e131796268709890b4a83270", size = 10311496 }, { url = "https://files.pythonhosted.org/packages/bb/a4/c84bc13d0b573cf7bb7d17b16d6d29f84267c92d79b2f478d4ce322e8e72/ruff-0.6.9-py3-none-win32.whl", hash = "sha256:eb61ec9bdb2506cffd492e05ac40e5bc6284873aceb605503d8494180d6fc84d", size = 8522088 },
{ url = "https://files.pythonhosted.org/packages/b6/2b/2a1c8deb5f5dfa3871eb7daa41492c4d2b2824a74d2b38e788617612a66d/ruff-0.11.4-py3-none-win_amd64.whl", hash = "sha256:5a9fa1c69c7815e39fcfb3646bbfd7f528fa8e2d4bebdcf4c2bd0fa037a255fb", size = 11399146 }, { url = "https://files.pythonhosted.org/packages/74/be/fc352bd8ca40daae8740b54c1c3e905a7efe470d420a268cd62150248c91/ruff-0.6.9-py3-none-win_amd64.whl", hash = "sha256:785d31851c1ae91f45b3d8fe23b8ae4b5170089021fbb42402d811135f0b7117", size = 9359275 },
{ url = "https://files.pythonhosted.org/packages/4f/03/3aec4846226d54a37822e4c7ea39489e4abd6f88388fba74e3d4abe77300/ruff-0.11.4-py3-none-win_arm64.whl", hash = "sha256:d435db6b9b93d02934cf61ef332e66af82da6d8c69aefdea5994c89997c7a0fc", size = 10450306 }, { url = "https://files.pythonhosted.org/packages/3e/14/fd026bc74ded05e2351681545a5f626e78ef831f8edce064d61acd2e6ec7/ruff-0.6.9-py3-none-win_arm64.whl", hash = "sha256:a9641e31476d601f83cd602608739a0840e348bda93fec9f1ee816f8b6798b93", size = 8679879 },
] ]
[[package]] [[package]]
name = "sh" name = "sh"
version = "2.1.0" version = "2.0.7"
source = { registry = "https://pypi.org/simple" } source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/52/12/b7965006c5adc57ba5459385358bd27c4983cd490884a75be86eb1d3efeb/sh-2.1.0.tar.gz", hash = "sha256:7e27301c574bec8ca5bf6f211851357526455ee97cd27a7c4c6cc5e2375399cb", size = 345525 } sdist = { url = "https://files.pythonhosted.org/packages/14/7a/5148402146d360a6d15922814a3b065b52be3a5fe878a8834d3ce4e7d33f/sh-2.0.7.tar.gz", hash = "sha256:029d45198902bfb967391eccfd13a88d92f7cebd200411e93f99ebacc6afbb35", size = 345477 }
wheels = [ wheels = [
{ url = "https://files.pythonhosted.org/packages/00/59/f6551f49c123751e921038c24215157bd50aef375ced16cac57229678c43/sh-2.1.0-py3-none-any.whl", hash = "sha256:bf5e44178dd96a542126c2774e9b7ab1d89bfe0e2ef84d92e6d0ed7358d63d01", size = 38080 }, { url = "https://files.pythonhosted.org/packages/15/c2/79f9dea6fc544c0eb79ed5018a38860c52d597c4be66c2cf2029bea5b3fd/sh-2.0.7-py3-none-any.whl", hash = "sha256:2f2f79a65abd00696cf2e9ad26508cf8abb6dba5745f40255f1c0ded2876926d", size = 38103 },
] ]
[[package]] [[package]]
@ -900,7 +931,7 @@ wheels = [
[[package]] [[package]]
name = "sphinx" name = "sphinx"
version = "8.1.3" version = "8.0.2"
source = { registry = "https://pypi.org/simple" } source = { registry = "https://pypi.org/simple" }
dependencies = [ dependencies = [
{ name = "alabaster" }, { name = "alabaster" },
@ -920,9 +951,9 @@ dependencies = [
{ name = "sphinxcontrib-qthelp" }, { name = "sphinxcontrib-qthelp" },
{ name = "sphinxcontrib-serializinghtml" }, { name = "sphinxcontrib-serializinghtml" },
] ]
sdist = { url = "https://files.pythonhosted.org/packages/6f/6d/be0b61178fe2cdcb67e2a92fc9ebb488e3c51c4f74a36a7824c0adf23425/sphinx-8.1.3.tar.gz", hash = "sha256:43c1911eecb0d3e161ad78611bc905d1ad0e523e4ddc202a58a821773dc4c927", size = 8184611 } sdist = { url = "https://files.pythonhosted.org/packages/25/a7/3cc3d6dcad70aba2e32a3ae8de5a90026a0a2fdaaa0756925e3a120249b6/sphinx-8.0.2.tar.gz", hash = "sha256:0cce1ddcc4fd3532cf1dd283bc7d886758362c5c1de6598696579ce96d8ffa5b", size = 8189041 }
wheels = [ wheels = [
{ url = "https://files.pythonhosted.org/packages/26/60/1ddff83a56d33aaf6f10ec8ce84b4c007d9368b21008876fceda7e7381ef/sphinx-8.1.3-py3-none-any.whl", hash = "sha256:09719015511837b76bf6e03e42eb7595ac8c2e41eeb9c29c5b755c6b677992a2", size = 3487125 }, { url = "https://files.pythonhosted.org/packages/4d/61/2ad169c6ff1226b46e50da0e44671592dbc6d840a52034a0193a99b28579/sphinx-8.0.2-py3-none-any.whl", hash = "sha256:56173572ae6c1b9a38911786e206a110c9749116745873feae4f9ce88e59391d", size = 3498950 },
] ]
[[package]] [[package]]
@ -944,16 +975,16 @@ wheels = [
[[package]] [[package]]
name = "sphinx-rtd-theme" name = "sphinx-rtd-theme"
version = "3.0.2" version = "3.0.0"
source = { registry = "https://pypi.org/simple" } source = { registry = "https://pypi.org/simple" }
dependencies = [ dependencies = [
{ name = "docutils" }, { name = "docutils" },
{ name = "sphinx" }, { name = "sphinx" },
{ name = "sphinxcontrib-jquery" }, { name = "sphinxcontrib-jquery" },
] ]
sdist = { url = "https://files.pythonhosted.org/packages/91/44/c97faec644d29a5ceddd3020ae2edffa69e7d00054a8c7a6021e82f20335/sphinx_rtd_theme-3.0.2.tar.gz", hash = "sha256:b7457bc25dda723b20b086a670b9953c859eab60a2a03ee8eb2bb23e176e5f85", size = 7620463 } sdist = { url = "https://files.pythonhosted.org/packages/21/f8/2667f9cab89827528596588dd9de6f937f52e5c6e87e6f28ecb866955551/sphinx_rtd_theme-3.0.0.tar.gz", hash = "sha256:905d67de03217fd3d76fbbdd992034ac8e77044ef8063a544dda1af74d409e08", size = 7620317 }
wheels = [ wheels = [
{ url = "https://files.pythonhosted.org/packages/85/77/46e3bac77b82b4df5bb5b61f2de98637724f246b4966cfc34bc5895d852a/sphinx_rtd_theme-3.0.2-py2.py3-none-any.whl", hash = "sha256:422ccc750c3a3a311de4ae327e82affdaf59eb695ba4936538552f3b00f4ee13", size = 7655561 }, { url = "https://files.pythonhosted.org/packages/21/11/81e5bfffdbd6dd3173d5ee29b4629a03ba80d38d4a250e7a8504af22d5c2/sphinx_rtd_theme-3.0.0-py2.py3-none-any.whl", hash = "sha256:1ffe1539957775bfa0a7331370de7dc145b6eac705de23365dc55c5d94bb08e7", size = 7655495 },
] ]
[[package]] [[package]]
@ -1024,14 +1055,14 @@ wheels = [
[[package]] [[package]]
name = "starlette" name = "starlette"
version = "0.45.1" version = "0.39.2"
source = { registry = "https://pypi.org/simple" } source = { registry = "https://pypi.org/simple" }
dependencies = [ dependencies = [
{ name = "anyio" }, { name = "anyio" },
] ]
sdist = { url = "https://files.pythonhosted.org/packages/c1/be/b398217eb35b356d2d9bb84ec67071ea2842e02950fcf38b33df9d5b24ba/starlette-0.45.1.tar.gz", hash = "sha256:a8ae1fa3b1ab7ca83a4abd77871921a13fb5aeaf4874436fb96c29dfcd4ecfa3", size = 2573953 } sdist = { url = "https://files.pythonhosted.org/packages/02/0a/62fbd5697f6174041f9b4e2e377b6f383f9189b77dbb7d73d24624caca1d/starlette-0.39.2.tar.gz", hash = "sha256:caaa3b87ef8518ef913dac4f073dea44e85f73343ad2bdc17941931835b2a26a", size = 2573080 }
wheels = [ wheels = [
{ url = "https://files.pythonhosted.org/packages/6b/2c/a50484b035ee0e13ebb7a42391e391befbfc1b6a9ad5503e83badd182ada/starlette-0.45.1-py3-none-any.whl", hash = "sha256:5656c0524f586e9148d9a3c1dd5257fb42a99892fb0dc6877dd76ef4d184aac3", size = 71488 }, { url = "https://files.pythonhosted.org/packages/60/f0/04547f776c8845be46df4bdd1f11159c088bd39e916f35d7da1b9f6eb3ef/starlette-0.39.2-py3-none-any.whl", hash = "sha256:134dd6deb655a9775991d352312d53f1879775e5cc8a481f966e83416a2c3f71", size = 73219 },
] ]
[[package]] [[package]]
@ -1054,7 +1085,7 @@ wheels = [
[[package]] [[package]]
name = "tox" name = "tox"
version = "4.23.2" version = "4.21.2"
source = { registry = "https://pypi.org/simple" } source = { registry = "https://pypi.org/simple" }
dependencies = [ dependencies = [
{ name = "cachetools" }, { name = "cachetools" },
@ -1067,23 +1098,23 @@ dependencies = [
{ name = "pyproject-api" }, { name = "pyproject-api" },
{ name = "virtualenv" }, { name = "virtualenv" },
] ]
sdist = { url = "https://files.pythonhosted.org/packages/1f/86/32b10f91b4b975a37ac402b0f9fa016775088e0565c93602ba0b3c729ce8/tox-4.23.2.tar.gz", hash = "sha256:86075e00e555df6e82e74cfc333917f91ecb47ffbc868dcafbd2672e332f4a2c", size = 189998 } sdist = { url = "https://files.pythonhosted.org/packages/2a/db/ba5b1a4cf664f221a33c3cbb1adf40ccccbbd13f5eec6d9d7291c7a39e44/tox-4.21.2.tar.gz", hash = "sha256:49381ff102296753e378fa5ff30e42a35e695f149b4dbf8a2c49d15fdb5797b2", size = 188539 }
wheels = [ wheels = [
{ url = "https://files.pythonhosted.org/packages/af/c0/124b73d01c120e917383bc6c53ebc34efdf7243faa9fca64d105c94cf2ab/tox-4.23.2-py3-none-any.whl", hash = "sha256:452bc32bb031f2282881a2118923176445bac783ab97c874b8770ab4c3b76c38", size = 166758 }, { url = "https://files.pythonhosted.org/packages/f8/20/168300f3f334e255b618322dce14b86a5c423aab05f28be14d1a2d6af14a/tox-4.21.2-py3-none-any.whl", hash = "sha256:13d996adcd792e7c82994b0e116d85efd84f0c6d185254d83d156f73f86b2038", size = 165698 },
] ]
[[package]] [[package]]
name = "tox-uv" name = "tox-uv"
version = "1.17.0" version = "1.11.2"
source = { registry = "https://pypi.org/simple" } source = { registry = "https://pypi.org/simple" }
dependencies = [ dependencies = [
{ name = "packaging" }, { name = "packaging" },
{ name = "tox" }, { name = "tox" },
{ name = "uv" }, { name = "uv" },
] ]
sdist = { url = "https://files.pythonhosted.org/packages/57/e3/04e7430a21290aaf91087123055249052f9bafaa48178f4ab58b8d73d839/tox_uv-1.17.0.tar.gz", hash = "sha256:07020acd90048b5c898b2c8f1e7c1c4cf944161745d7bfe5b9458ed67f4998b7", size = 17640 } sdist = { url = "https://files.pythonhosted.org/packages/fa/cf/7062095ae8c5e6a25d7153b9b1c4a16e52df61859160b3db66a60f055d1e/tox_uv-1.11.2.tar.gz", hash = "sha256:a7aded5c3fb69f055b523357988c1055bb573e91bfd7ecfb9b5233ebcab5d10b", size = 13628 }
wheels = [ wheels = [
{ url = "https://files.pythonhosted.org/packages/fa/be/fc8209e150fec799fd01fa027f372cdf87d6cf0eeb083e43ee48037199e5/tox_uv-1.17.0-py3-none-any.whl", hash = "sha256:cdc95eca6fd98a7716b9da7c9cf901d4836d6956089d6cb3417f00c8d98b513c", size = 14010 }, { url = "https://files.pythonhosted.org/packages/6a/50/5b9f2d9d10bfdfb1f748bbcdb6eae5a5da6d2a7adbef9a4df34aceac6eca/tox_uv-1.11.2-py3-none-any.whl", hash = "sha256:7f8f1737b3277e1cddcb5b89fcc5931d04923562c940ae60f29e140908566df2", size = 11265 },
] ]
[[package]] [[package]]
@ -1091,7 +1122,7 @@ name = "tqdm"
version = "4.66.5" version = "4.66.5"
source = { registry = "https://pypi.org/simple" } source = { registry = "https://pypi.org/simple" }
dependencies = [ dependencies = [
{ name = "colorama", marker = "sys_platform == 'win32'" }, { name = "colorama", marker = "platform_system == 'Windows'" },
] ]
sdist = { url = "https://files.pythonhosted.org/packages/58/83/6ba9844a41128c62e810fddddd72473201f3eacde02046066142a2d96cc5/tqdm-4.66.5.tar.gz", hash = "sha256:e1020aef2e5096702d8a025ac7d16b1577279c9d63f8375b63083e9a5f0fcbad", size = 169504 } sdist = { url = "https://files.pythonhosted.org/packages/58/83/6ba9844a41128c62e810fddddd72473201f3eacde02046066142a2d96cc5/tqdm-4.66.5.tar.gz", hash = "sha256:e1020aef2e5096702d8a025ac7d16b1577279c9d63f8375b63083e9a5f0fcbad", size = 169504 }
wheels = [ wheels = [
@ -1127,39 +1158,40 @@ wheels = [
[[package]] [[package]]
name = "uv" name = "uv"
version = "0.5.13" version = "0.4.6"
source = { registry = "https://pypi.org/simple" } source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/a4/09/dc3b7beb8abc663c962320eff9862e5c718383bd6e03e9490da5621f77c5/uv-0.5.13.tar.gz", hash = "sha256:58a66786f2e95c89539bafd819cf2959f56199457301eac8faa920c1872c4f36", size = 2555484 } sdist = { url = "https://files.pythonhosted.org/packages/02/5c/916bc1eacf2a5ca8cd33dc5d51cc9f64735ef6faccefd2f689d34b9eb23a/uv-0.4.6.tar.gz", hash = "sha256:5c142b0082844c9eca4a303e13cf1d286622f49af70e8f922b833cb3e667b2e3", size = 1859862 }
wheels = [ wheels = [
{ url = "https://files.pythonhosted.org/packages/52/bf/142c1aefdb0cdb1200d8fd2193073d3b4b28028a7cacbce3fcaafe5fd9bf/uv-0.5.13-py3-none-linux_armv6l.whl", hash = "sha256:45301cb355fc0525e692d220ea7cb196e8378a53162b27d6eea6e65c7635ed3d", size = 14408033 }, { url = "https://files.pythonhosted.org/packages/09/0b/eb3ca96aa881e5a88e704b5d7aec99610cc0d64702c984da24ae2a5682c2/uv-0.4.6-py3-none-linux_armv6l.whl", hash = "sha256:e0360bb3b094d106d1fa00b3a15c69ccd0d1593682c33affb1b94367a248a378", size = 11097185 },
{ url = "https://files.pythonhosted.org/packages/a0/3e/dc408e34fbb6e7bb5d1462dfeb765074c7951d400e31ba31c9b21ac46250/uv-0.5.13-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:ff96602b7d391f35dc25122c2661e680a9e94864e96801611ef05c853826c82c", size = 14406050 }, { url = "https://files.pythonhosted.org/packages/30/1c/3c27e0fe4ad1a5b9792a61e92283457beec7949863c1b3435ef79cfad179/uv-0.4.6-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:16ae9f0a9b3bb6db755d057c4ff55b0e82fbb09243a1dce02720268718c0a11c", size = 11558713 },
{ url = "https://files.pythonhosted.org/packages/04/da/2e8cd58fb76c213a03c2fb556ad0858a6e585cd6e4b5f0e531ac81f113a8/uv-0.5.13-py3-none-macosx_11_0_arm64.whl", hash = "sha256:941c13f15a8726a2f5ad3fffa0bbe98e221c98fbe73adbca62cf327bd3fb029c", size = 13370750 }, { url = "https://files.pythonhosted.org/packages/5a/f8/93e8574c91ef7884154af6f80d213ee11f7710201c2fe0d73a9f9556bd2d/uv-0.4.6-py3-none-macosx_11_0_arm64.whl", hash = "sha256:e6e925f661aeaf392cc102d3c2f6f05b6994519bd7a36578f836a4bbf42ee813", size = 10668873 },
{ url = "https://files.pythonhosted.org/packages/92/f1/4a0c9c1dbf6a237bd48fca67b9732e2d33e05536e2f54e8290c90e552ebc/uv-0.5.13-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.musllinux_1_1_aarch64.whl", hash = "sha256:642d7e62c376487a63a03fb830749fb24dd7653f715864df2fb8788f29dfb85e", size = 13646567 }, { url = "https://files.pythonhosted.org/packages/0f/f3/1b2625aa119ee66fc7a6c3c1026c66707a5f99a0c86e5d49fd237f45f0b5/uv-0.4.6-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.musllinux_1_1_aarch64.whl", hash = "sha256:86f78fb80989b524ce7da705fb5af613339a8eadbcf9e230bb16e8a7d383c2ce", size = 11006778 },
{ url = "https://files.pythonhosted.org/packages/83/41/c39977fdc5eb6c2060a7705963460a0214452ee8d3f79bb8b96b3bbdaca2/uv-0.5.13-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b5aab53db952f7f4505cfc2f62ecedb4a7977d746622f67cbadf052bef0d916e", size = 14172837 }, { url = "https://files.pythonhosted.org/packages/30/01/cbe8bc23dd1e32b77b652e31757fcdb636c194bd13acf32e2438a72daf5a/uv-0.4.6-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a66442018e09467222824b685b2d401053dfdbc3b5f6fb1f863ca2eb2560076a", size = 10896611 },
{ url = "https://files.pythonhosted.org/packages/d2/21/0823f2ac33febb103dfc51e0aa43c4540375b29689dfc846a897b1d704cb/uv-0.5.13-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f57250f46914affab4e4ca50822f1fbc7910df01818a22b7d91d4f5ccc5eb80c", size = 14907424 }, { url = "https://files.pythonhosted.org/packages/5f/11/46328fc827f4bf35b715a97f067a61563f5421e0e35ba6fd16b9de82771a/uv-0.4.6-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4db5c2b770bb0e95a4d32dc19943109310c86103fe8b8ecf0d18dfe1a4f2a212", size = 11563597 },
{ url = "https://files.pythonhosted.org/packages/82/51/04ed1d8e5cac1f3f26f20c9cb0202b1fad0bb3fb1c8c0ba320f82eb0b205/uv-0.5.13-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:6fb26d2b6d4b6467b98acc22b67bbdd16360a1b843842d7cd77ff4df70884567", size = 15497699 }, { url = "https://files.pythonhosted.org/packages/3e/b1/8774d2fab7cbec44e68aafa58745ce9ec2af26a17e1d6ad86284fcd79acf/uv-0.4.6-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:9bf486c6331197a301bff253945b233d852ed2fdc322e93c78d382092813161d", size = 12341920 },
{ url = "https://files.pythonhosted.org/packages/f7/b9/dd859a72bfde9c2daa7f64ebad699e4e75fda1e45dcf6ac8026f88296b55/uv-0.5.13-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:414dd7083bd7e06ab2db0ee6cfe81b0810c416e79ff1643701e15e2df5e1db2b", size = 15225898 }, { url = "https://files.pythonhosted.org/packages/81/cc/f53877269f75d4bba8e4bad131b6aa2d39d6545afff2c703be2c9608ad50/uv-0.4.6-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2bd9879eb8ee9de0fa532136ddfe76c1b425520fa6de52f5d023567e226a08b5", size = 12142981 },
{ url = "https://files.pythonhosted.org/packages/c0/bd/faed9861a27b9a24c0e93b5c18fbf0f4cc7a88e46bf15ad0fa03ffc7fb98/uv-0.5.13-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:01fc5e928efba822ff28007f827c3c274b644508253fe358ec79085bae1da0c9", size = 19963452 }, { url = "https://files.pythonhosted.org/packages/13/b8/373d86645849320eb61e213e657084f7cf6be2d6f2b13e413cb555876659/uv-0.4.6-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:831be24db75938ebb01f9e6b7bcf24683b9661f91aab4108636207ba9dc6a2b9", size = 15237758 },
{ url = "https://files.pythonhosted.org/packages/a7/64/00896d517e95621aa10e7a19dc6de636edab73f80b5e6ff4df73188731be/uv-0.5.13-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:82479440765e507af1f2732bd496ec6ed849488f5ce310b8556cfe8c12da1c5f", size = 14970047 }, { url = "https://files.pythonhosted.org/packages/29/bb/0accc6347df2f88efd092aa821eba46edebac726659a0160590989860b77/uv-0.4.6-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b8cdadb99b842494a0a39e0184cacfb4af722fdbea3d4cb5ee3b25ea0b824292", size = 11925644 },
{ url = "https://files.pythonhosted.org/packages/d0/8f/f62f7fe20b7ead1e2afbe050932e698eb5ce6c2649fe49c2d2f96dc5fcba/uv-0.5.13-py3-none-manylinux_2_28_aarch64.whl", hash = "sha256:18f2141e71f6cb4c0ab44f1a100838d336f14c1d7a1c62444c79c2c2554331be", size = 13854500 }, { url = "https://files.pythonhosted.org/packages/a6/3d/32dfd30e22dca7ea76a1298d42cdda3c3e80be6763d9d87a14a5b9bbb38b/uv-0.4.6-py3-none-manylinux_2_28_aarch64.whl", hash = "sha256:081793fc66286ad0f9b939b5ab3239d20d486eff7b8f7c574d3fdcd44536595e", size = 11116370 },
{ url = "https://files.pythonhosted.org/packages/52/2b/efef56357acb6a63aab425f03c8d819eef7cd261a34bf8b6f64bc86a82d2/uv-0.5.13-py3-none-musllinux_1_1_armv7l.whl", hash = "sha256:4c2e75845c9c5adae3e8274967f70023b740488d732f88100baeef70090b60a0", size = 14178985 }, { url = "https://files.pythonhosted.org/packages/72/8a/18731ce4fae35a205efabd5f5f1979821fcb66f4d6ad6818e79b0b0bce20/uv-0.4.6-py3-none-musllinux_1_1_armv7l.whl", hash = "sha256:346db85ce897c6c782af33504922a84c583180906244ea224a306e2393f396f4", size = 10901947 },
{ url = "https://files.pythonhosted.org/packages/e3/83/394d65c16d058eda1179c05418c68289f983aab2c278d06ea273e3e6299a/uv-0.5.13-py3-none-musllinux_1_1_i686.whl", hash = "sha256:6de38097d5efa86ae62a71ff268e16f7eab86f4afa63c32b546cb7f5a182874f", size = 14552142 }, { url = "https://files.pythonhosted.org/packages/a7/08/665613bc0cb41f85afc1059b6b25815d5904020822d3a958986aa2d2eee6/uv-0.4.6-py3-none-musllinux_1_1_i686.whl", hash = "sha256:5d507dee4767d054171dcdbc1ac1fa7d15a7579e20ff988162c749f09a95f943", size = 11389509 },
{ url = "https://files.pythonhosted.org/packages/4b/6e/712477a76954f64bb6f0391c9dd1081e41c97d1f653c92688b1618e7fcdc/uv-0.5.13-py3-none-musllinux_1_1_x86_64.whl", hash = "sha256:30440409a28f1d5d34af8839a48ba9c26da06fc295f363ba9b12689b796453d4", size = 15088698 }, { url = "https://files.pythonhosted.org/packages/23/47/5a30dd313ce2c33c3637ea17c65fcddbfbf005fc456c6025f18e99bf56e8/uv-0.4.6-py3-none-musllinux_1_1_ppc64le.whl", hash = "sha256:397e02640cbddc4230da8d614ef9a7138a024b9ce396f2a27013cd254e97480d", size = 13150151 },
{ url = "https://files.pythonhosted.org/packages/7d/b6/a06fa33db44426275ab0ba87dc4a4e770acfab0897ee212a6ff4d3423e1d/uv-0.5.13-py3-none-win32.whl", hash = "sha256:df2a751e8319e11ef2d8bec30d549ee13949027aaa936ab2a0ab126602f4232b", size = 14459272 }, { url = "https://files.pythonhosted.org/packages/44/0e/37f4040363d05a0cca7f35759d34bb2ca10e9d89a647b8c6c3888ed8b643/uv-0.4.6-py3-none-musllinux_1_1_x86_64.whl", hash = "sha256:93165aa25f5278a0844c91a367140e725d384633946705651ff8e70757c2e92f", size = 12048785 },
{ url = "https://files.pythonhosted.org/packages/a5/c8/b3bdc883e4ca0612ddd9f956d116308742f12d9140361dba6b2fcf66294d/uv-0.5.13-py3-none-win_amd64.whl", hash = "sha256:4219f1ed370bb2cec5f10dcc93fa9ecf5615fa67e0b71eef4817d571291f0bfc", size = 16315884 }, { url = "https://files.pythonhosted.org/packages/b4/1e/0b21ab16140d252d211411b4f61e2e448830f76b5cd5b88bb8dd827e5c7d/uv-0.4.6-py3-none-win32.whl", hash = "sha256:954f91be1b8e531e9fd3d6d549ec1638c20ce4e77dc6e272c5c5d21b8c952f11", size = 11320666 },
{ url = "https://files.pythonhosted.org/packages/d8/44/0231b506b5c2ea9da3242142fc7e53696060f548bb6f1cebca89268fa238/uv-0.4.6-py3-none-win_amd64.whl", hash = "sha256:86ecd19796363f0161600120d81ce7e3d17d54cce6d25017190daa608a8ab535", size = 12520653 },
] ]
[[package]] [[package]]
name = "uvicorn" name = "uvicorn"
version = "0.34.0" version = "0.31.0"
source = { registry = "https://pypi.org/simple" } source = { registry = "https://pypi.org/simple" }
dependencies = [ dependencies = [
{ name = "click" }, { name = "click" },
{ name = "h11" }, { name = "h11" },
] ]
sdist = { url = "https://files.pythonhosted.org/packages/4b/4d/938bd85e5bf2edeec766267a5015ad969730bb91e31b44021dfe8b22df6c/uvicorn-0.34.0.tar.gz", hash = "sha256:404051050cd7e905de2c9a7e61790943440b3416f49cb409f965d9dcd0fa73e9", size = 76568 } sdist = { url = "https://files.pythonhosted.org/packages/0a/96/ee52d900f8e41cc35eaebfda76f3619c2e45b741f3ee957d6fe32be1b2aa/uvicorn-0.31.0.tar.gz", hash = "sha256:13bc21373d103859f68fe739608e2eb054a816dea79189bc3ca08ea89a275906", size = 77140 }
wheels = [ wheels = [
{ url = "https://files.pythonhosted.org/packages/61/14/33a3a1352cfa71812a3a21e8c9bfb83f60b0011f5e36f2b1399d51928209/uvicorn-0.34.0-py3-none-any.whl", hash = "sha256:023dc038422502fa28a09c7a30bf2b6991512da7dcdb8fd35fe57cfc154126f4", size = 62315 }, { url = "https://files.pythonhosted.org/packages/05/12/206aca5442524d16be7702d08b453d7c274c86fd759266b1f709d4ef43ba/uvicorn-0.31.0-py3-none-any.whl", hash = "sha256:cac7be4dd4d891c363cd942160a7b02e69150dcbc7a36be04d5f4af4b17c8ced", size = 63656 },
] ]
[[package]] [[package]]
@ -1178,46 +1210,69 @@ wheels = [
[[package]] [[package]]
name = "watchfiles" name = "watchfiles"
version = "1.0.3" version = "0.24.0"
source = { registry = "https://pypi.org/simple" } source = { registry = "https://pypi.org/simple" }
dependencies = [ dependencies = [
{ name = "anyio" }, { name = "anyio" },
] ]
sdist = { url = "https://files.pythonhosted.org/packages/3c/7e/4569184ea04b501840771b8fcecee19b2233a8b72c196061263c0ef23c0b/watchfiles-1.0.3.tar.gz", hash = "sha256:f3ff7da165c99a5412fe5dd2304dd2dbaaaa5da718aad942dcb3a178eaa70c56", size = 38185 } sdist = { url = "https://files.pythonhosted.org/packages/c8/27/2ba23c8cc85796e2d41976439b08d52f691655fdb9401362099502d1f0cf/watchfiles-0.24.0.tar.gz", hash = "sha256:afb72325b74fa7a428c009c1b8be4b4d7c2afedafb2982827ef2156646df2fe1", size = 37870 }
wheels = [ wheels = [
{ url = "https://files.pythonhosted.org/packages/bf/a9/c8b5ab33444306e1a324cb2b51644f8458dd459e30c3841f925012893e6a/watchfiles-1.0.3-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:93436ed550e429da007fbafb723e0769f25bae178fbb287a94cb4ccdf42d3af3", size = 391395 }, { url = "https://files.pythonhosted.org/packages/35/82/92a7bb6dc82d183e304a5f84ae5437b59ee72d48cee805a9adda2488b237/watchfiles-0.24.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:7211b463695d1e995ca3feb38b69227e46dbd03947172585ecb0588f19b0d87a", size = 374137 },
{ url = "https://files.pythonhosted.org/packages/ad/d3/403af5f07359863c03951796ddab265ee8cce1a6147510203d0bf43950e7/watchfiles-1.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c18f3502ad0737813c7dad70e3e1cc966cc147fbaeef47a09463bbffe70b0a00", size = 381432 }, { url = "https://files.pythonhosted.org/packages/87/91/49e9a497ddaf4da5e3802d51ed67ff33024597c28f652b8ab1e7c0f5718b/watchfiles-0.24.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4b8693502d1967b00f2fb82fc1e744df128ba22f530e15b763c8d82baee15370", size = 367733 },
{ url = "https://files.pythonhosted.org/packages/f6/5f/921f2f2beabaf24b1ad81ac22bb69df8dd5771fdb68d6f34a5912a420941/watchfiles-1.0.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6a5bc3ca468bb58a2ef50441f953e1f77b9a61bd1b8c347c8223403dc9b4ac9a", size = 441448 }, { url = "https://files.pythonhosted.org/packages/0d/d8/90eb950ab4998effea2df4cf3a705dc594f6bc501c5a353073aa990be965/watchfiles-0.24.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cdab9555053399318b953a1fe1f586e945bc8d635ce9d05e617fd9fe3a4687d6", size = 437322 },
{ url = "https://files.pythonhosted.org/packages/63/d7/67d0d750b246f248ccdb400a85a253e93e419ea5b6cbe968fa48b97a5f30/watchfiles-1.0.3-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:0d1ec043f02ca04bf21b1b32cab155ce90c651aaf5540db8eb8ad7f7e645cba8", size = 446852 }, { url = "https://files.pythonhosted.org/packages/6c/a2/300b22e7bc2a222dd91fce121cefa7b49aa0d26a627b2777e7bdfcf1110b/watchfiles-0.24.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:34e19e56d68b0dad5cff62273107cf5d9fbaf9d75c46277aa5d803b3ef8a9e9b", size = 433409 },
{ url = "https://files.pythonhosted.org/packages/53/7c/d7cd94c7d0905f1e2f1c2232ea9bc39b1a48affd007e09c547ead96edb8f/watchfiles-1.0.3-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f58d3bfafecf3d81c15d99fc0ecf4319e80ac712c77cf0ce2661c8cf8bf84066", size = 471662 }, { url = "https://files.pythonhosted.org/packages/99/44/27d7708a43538ed6c26708bcccdde757da8b7efb93f4871d4cc39cffa1cc/watchfiles-0.24.0-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:41face41f036fee09eba33a5b53a73e9a43d5cb2c53dad8e61fa6c9f91b5a51e", size = 452142 },
{ url = "https://files.pythonhosted.org/packages/26/81/738f8e66f7525753996b8aa292f78dcec1ef77887d62e6cdfb04cc2f352f/watchfiles-1.0.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1df924ba82ae9e77340101c28d56cbaff2c991bd6fe8444a545d24075abb0a87", size = 493765 }, { url = "https://files.pythonhosted.org/packages/b0/ec/c4e04f755be003129a2c5f3520d2c47026f00da5ecb9ef1e4f9449637571/watchfiles-0.24.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5148c2f1ea043db13ce9b0c28456e18ecc8f14f41325aa624314095b6aa2e9ea", size = 469414 },
{ url = "https://files.pythonhosted.org/packages/d2/50/78e21f5da24ab39114e9b24f7b0945ea1c6fc7bc9ae86cd87f8eaeb47325/watchfiles-1.0.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:632a52dcaee44792d0965c17bdfe5dc0edad5b86d6a29e53d6ad4bf92dc0ff49", size = 490558 }, { url = "https://files.pythonhosted.org/packages/c5/4e/cdd7de3e7ac6432b0abf282ec4c1a1a2ec62dfe423cf269b86861667752d/watchfiles-0.24.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7e4bd963a935aaf40b625c2499f3f4f6bbd0c3776f6d3bc7c853d04824ff1c9f", size = 472962 },
{ url = "https://files.pythonhosted.org/packages/a8/93/1873fea6354b2858eae8970991d64e9a449d87726d596490d46bf00af8ed/watchfiles-1.0.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80bf4b459d94a0387617a1b499f314aa04d8a64b7a0747d15d425b8c8b151da0", size = 442808 }, { url = "https://files.pythonhosted.org/packages/27/69/e1da9d34da7fc59db358424f5d89a56aaafe09f6961b64e36457a80a7194/watchfiles-0.24.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c79d7719d027b7a42817c5d96461a99b6a49979c143839fc37aa5748c322f234", size = 425705 },
{ url = "https://files.pythonhosted.org/packages/4f/b4/2fc4c92fb28b029f66d04a4d430fe929284e9ff717b04bb7a3bb8a7a5605/watchfiles-1.0.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:ca94c85911601b097d53caeeec30201736ad69a93f30d15672b967558df02885", size = 615287 }, { url = "https://files.pythonhosted.org/packages/e8/c1/24d0f7357be89be4a43e0a656259676ea3d7a074901f47022f32e2957798/watchfiles-0.24.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:32aa53a9a63b7f01ed32e316e354e81e9da0e6267435c7243bf8ae0f10b428ef", size = 612851 },
{ url = "https://files.pythonhosted.org/packages/1e/d4/93da24db39257e440240d338b617c5153ad11d361c34108f5c0e1e0743eb/watchfiles-1.0.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:65ab1fb635476f6170b07e8e21db0424de94877e4b76b7feabfe11f9a5fc12b5", size = 612812 }, { url = "https://files.pythonhosted.org/packages/c7/af/175ba9b268dec56f821639c9893b506c69fd999fe6a2e2c51de420eb2f01/watchfiles-0.24.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:ce72dba6a20e39a0c628258b5c308779b8697f7676c254a845715e2a1039b968", size = 594868 },
{ url = "https://files.pythonhosted.org/packages/c6/67/9fd3661c2dc0309abd6021876653d91e8b64fb279529e2cadaa3520ef3e3/watchfiles-1.0.3-cp312-cp312-win32.whl", hash = "sha256:49bc1bc26abf4f32e132652f4b3bfeec77d8f8f62f57652703ef127e85a3e38d", size = 271642 }, { url = "https://files.pythonhosted.org/packages/44/81/1f701323a9f70805bc81c74c990137123344a80ea23ab9504a99492907f8/watchfiles-0.24.0-cp312-none-win32.whl", hash = "sha256:d9018153cf57fc302a2a34cb7564870b859ed9a732d16b41a9b5cb2ebed2d444", size = 264109 },
{ url = "https://files.pythonhosted.org/packages/ae/aa/8c887edb78cd67f5d4d6a35c3aeb46d748643ebf962163130fb1871e2ee0/watchfiles-1.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:48681c86f2cb08348631fed788a116c89c787fdf1e6381c5febafd782f6c3b44", size = 285505 }, { url = "https://files.pythonhosted.org/packages/b4/0b/32cde5bc2ebd9f351be326837c61bdeb05ad652b793f25c91cac0b48a60b/watchfiles-0.24.0-cp312-none-win_amd64.whl", hash = "sha256:551ec3ee2a3ac9cbcf48a4ec76e42c2ef938a7e905a35b42a1267fa4b1645896", size = 277055 },
{ url = "https://files.pythonhosted.org/packages/7b/31/d212fa6390f0e73a91913ada0b925b294a78d67794795371208baf73f0b5/watchfiles-1.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:9e080cf917b35b20c889225a13f290f2716748362f6071b859b60b8847a6aa43", size = 277263 }, { url = "https://files.pythonhosted.org/packages/4b/81/daade76ce33d21dbec7a15afd7479de8db786e5f7b7d249263b4ea174e08/watchfiles-0.24.0-cp312-none-win_arm64.whl", hash = "sha256:b52a65e4ea43c6d149c5f8ddb0bef8d4a1e779b77591a458a893eb416624a418", size = 266169 },
{ url = "https://files.pythonhosted.org/packages/30/dc/6e9f5447ae14f645532468a84323a942996d74d5e817837a5c8ce9d16c69/watchfiles-0.24.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:3d2e3ab79a1771c530233cadfd277fcc762656d50836c77abb2e5e72b88e3a48", size = 373764 },
{ url = "https://files.pythonhosted.org/packages/79/c0/c3a9929c372816c7fc87d8149bd722608ea58dc0986d3ef7564c79ad7112/watchfiles-0.24.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:327763da824817b38ad125dcd97595f942d720d32d879f6c4ddf843e3da3fe90", size = 367873 },
{ url = "https://files.pythonhosted.org/packages/2e/11/ff9a4445a7cfc1c98caf99042df38964af12eed47d496dd5d0d90417349f/watchfiles-0.24.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bd82010f8ab451dabe36054a1622870166a67cf3fce894f68895db6f74bbdc94", size = 438381 },
{ url = "https://files.pythonhosted.org/packages/48/a3/763ba18c98211d7bb6c0f417b2d7946d346cdc359d585cc28a17b48e964b/watchfiles-0.24.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d64ba08db72e5dfd5c33be1e1e687d5e4fcce09219e8aee893a4862034081d4e", size = 432809 },
{ url = "https://files.pythonhosted.org/packages/30/4c/616c111b9d40eea2547489abaf4ffc84511e86888a166d3a4522c2ba44b5/watchfiles-0.24.0-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1cf1f6dd7825053f3d98f6d33f6464ebdd9ee95acd74ba2c34e183086900a827", size = 451801 },
{ url = "https://files.pythonhosted.org/packages/b6/be/d7da83307863a422abbfeb12903a76e43200c90ebe5d6afd6a59d158edea/watchfiles-0.24.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:43e3e37c15a8b6fe00c1bce2473cfa8eb3484bbeecf3aefbf259227e487a03df", size = 468886 },
{ url = "https://files.pythonhosted.org/packages/1d/d3/3dfe131ee59d5e90b932cf56aba5c996309d94dafe3d02d204364c23461c/watchfiles-0.24.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:88bcd4d0fe1d8ff43675360a72def210ebad3f3f72cabfeac08d825d2639b4ab", size = 472973 },
{ url = "https://files.pythonhosted.org/packages/42/6c/279288cc5653a289290d183b60a6d80e05f439d5bfdfaf2d113738d0f932/watchfiles-0.24.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:999928c6434372fde16c8f27143d3e97201160b48a614071261701615a2a156f", size = 425282 },
{ url = "https://files.pythonhosted.org/packages/d6/d7/58afe5e85217e845edf26d8780c2d2d2ae77675eeb8d1b8b8121d799ce52/watchfiles-0.24.0-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:30bbd525c3262fd9f4b1865cb8d88e21161366561cd7c9e1194819e0a33ea86b", size = 612540 },
{ url = "https://files.pythonhosted.org/packages/6d/d5/b96eeb9fe3fda137200dd2f31553670cbc731b1e13164fd69b49870b76ec/watchfiles-0.24.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:edf71b01dec9f766fb285b73930f95f730bb0943500ba0566ae234b5c1618c18", size = 593625 },
{ url = "https://files.pythonhosted.org/packages/c1/e5/c326fe52ee0054107267608d8cea275e80be4455b6079491dfd9da29f46f/watchfiles-0.24.0-cp313-none-win32.whl", hash = "sha256:f4c96283fca3ee09fb044f02156d9570d156698bc3734252175a38f0e8975f07", size = 263899 },
{ url = "https://files.pythonhosted.org/packages/a6/8b/8a7755c5e7221bb35fe4af2dc44db9174f90ebf0344fd5e9b1e8b42d381e/watchfiles-0.24.0-cp313-none-win_amd64.whl", hash = "sha256:a974231b4fdd1bb7f62064a0565a6b107d27d21d9acb50c484d2cdba515b9366", size = 276622 },
] ]
[[package]] [[package]]
name = "websockets" name = "websockets"
version = "14.1" version = "13.1"
source = { registry = "https://pypi.org/simple" } source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/f4/1b/380b883ce05bb5f45a905b61790319a28958a9ab1e4b6b95ff5464b60ca1/websockets-14.1.tar.gz", hash = "sha256:398b10c77d471c0aab20a845e7a60076b6390bfdaac7a6d2edb0d2c59d75e8d8", size = 162840 } sdist = { url = "https://files.pythonhosted.org/packages/e2/73/9223dbc7be3dcaf2a7bbf756c351ec8da04b1fa573edaf545b95f6b0c7fd/websockets-13.1.tar.gz", hash = "sha256:a3b3366087c1bc0a2795111edcadddb8b3b59509d5db5d7ea3fdd69f954a8878", size = 158549 }
wheels = [ wheels = [
{ url = "https://files.pythonhosted.org/packages/55/64/55698544ce29e877c9188f1aee9093712411a8fc9732cca14985e49a8e9c/websockets-14.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:ed907449fe5e021933e46a3e65d651f641975a768d0649fee59f10c2985529ed", size = 161957 }, { url = "https://files.pythonhosted.org/packages/df/46/c426282f543b3c0296cf964aa5a7bb17e984f58dde23460c3d39b3148fcf/websockets-13.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:9d75baf00138f80b48f1eac72ad1535aac0b6461265a0bcad391fc5aba875cfc", size = 157821 },
{ url = "https://files.pythonhosted.org/packages/a2/b1/b088f67c2b365f2c86c7b48edb8848ac27e508caf910a9d9d831b2f343cb/websockets-14.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:87e31011b5c14a33b29f17eb48932e63e1dcd3fa31d72209848652310d3d1f0d", size = 159620 }, { url = "https://files.pythonhosted.org/packages/aa/85/22529867010baac258da7c45848f9415e6cf37fef00a43856627806ffd04/websockets-13.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:9b6f347deb3dcfbfde1c20baa21c2ac0751afaa73e64e5b693bb2b848efeaa49", size = 155480 },
{ url = "https://files.pythonhosted.org/packages/c1/89/2a09db1bbb40ba967a1b8225b07b7df89fea44f06de9365f17f684d0f7e6/websockets-14.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:bc6ccf7d54c02ae47a48ddf9414c54d48af9c01076a2e1023e3b486b6e72c707", size = 159852 }, { url = "https://files.pythonhosted.org/packages/29/2c/bdb339bfbde0119a6e84af43ebf6275278698a2241c2719afc0d8b0bdbf2/websockets-13.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:de58647e3f9c42f13f90ac7e5f58900c80a39019848c5547bc691693098ae1bd", size = 155715 },
{ url = "https://files.pythonhosted.org/packages/ca/c1/f983138cd56e7d3079f1966e81f77ce6643f230cd309f73aa156bb181749/websockets-14.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9777564c0a72a1d457f0848977a1cbe15cfa75fa2f67ce267441e465717dcf1a", size = 169675 }, { url = "https://files.pythonhosted.org/packages/9f/d0/8612029ea04c5c22bf7af2fd3d63876c4eaeef9b97e86c11972a43aa0e6c/websockets-13.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a1b54689e38d1279a51d11e3467dd2f3a50f5f2e879012ce8f2d6943f00e83f0", size = 165647 },
{ url = "https://files.pythonhosted.org/packages/c1/c8/84191455d8660e2a0bdb33878d4ee5dfa4a2cedbcdc88bbd097303b65bfa/websockets-14.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a655bde548ca98f55b43711b0ceefd2a88a71af6350b0c168aa77562104f3f45", size = 168619 }, { url = "https://files.pythonhosted.org/packages/56/04/1681ed516fa19ca9083f26d3f3a302257e0911ba75009533ed60fbb7b8d1/websockets-13.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cf1781ef73c073e6b0f90af841aaf98501f975d306bbf6221683dd594ccc52b6", size = 164592 },
{ url = "https://files.pythonhosted.org/packages/8d/a7/62e551fdcd7d44ea74a006dc193aba370505278ad76efd938664531ce9d6/websockets-14.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a3dfff83ca578cada2d19e665e9c8368e1598d4e787422a460ec70e531dbdd58", size = 169042 }, { url = "https://files.pythonhosted.org/packages/38/6f/a96417a49c0ed132bb6087e8e39a37db851c70974f5c724a4b2a70066996/websockets-13.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8d23b88b9388ed85c6faf0e74d8dec4f4d3baf3ecf20a65a47b836d56260d4b9", size = 165012 },
{ url = "https://files.pythonhosted.org/packages/ad/ed/1532786f55922c1e9c4d329608e36a15fdab186def3ca9eb10d7465bc1cc/websockets-14.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6a6c9bcf7cdc0fd41cc7b7944447982e8acfd9f0d560ea6d6845428ed0562058", size = 169345 }, { url = "https://files.pythonhosted.org/packages/40/8b/fccf294919a1b37d190e86042e1a907b8f66cff2b61e9befdbce03783e25/websockets-13.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3c78383585f47ccb0fcf186dcb8a43f5438bd7d8f47d69e0b56f71bf431a0a68", size = 165311 },
{ url = "https://files.pythonhosted.org/packages/ea/fb/160f66960d495df3de63d9bcff78e1b42545b2a123cc611950ffe6468016/websockets-14.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:4b6caec8576e760f2c7dd878ba817653144d5f369200b6ddf9771d64385b84d4", size = 168725 }, { url = "https://files.pythonhosted.org/packages/c1/61/f8615cf7ce5fe538476ab6b4defff52beb7262ff8a73d5ef386322d9761d/websockets-13.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:d6d300f8ec35c24025ceb9b9019ae9040c1ab2f01cddc2bcc0b518af31c75c14", size = 164692 },
{ url = "https://files.pythonhosted.org/packages/cf/53/1bf0c06618b5ac35f1d7906444b9958f8485682ab0ea40dee7b17a32da1e/websockets-14.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:eb6d38971c800ff02e4a6afd791bbe3b923a9a57ca9aeab7314c21c84bf9ff05", size = 168712 }, { url = "https://files.pythonhosted.org/packages/5c/f1/a29dd6046d3a722d26f182b783a7997d25298873a14028c4760347974ea3/websockets-13.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:a9dcaf8b0cc72a392760bb8755922c03e17a5a54e08cca58e8b74f6902b433cf", size = 164686 },
{ url = "https://files.pythonhosted.org/packages/e5/22/5ec2f39fff75f44aa626f86fa7f20594524a447d9c3be94d8482cd5572ef/websockets-14.1-cp312-cp312-win32.whl", hash = "sha256:1d045cbe1358d76b24d5e20e7b1878efe578d9897a25c24e6006eef788c0fdf0", size = 162838 }, { url = "https://files.pythonhosted.org/packages/0f/99/ab1cdb282f7e595391226f03f9b498f52109d25a2ba03832e21614967dfa/websockets-13.1-cp312-cp312-win32.whl", hash = "sha256:2f85cf4f2a1ba8f602298a853cec8526c2ca42a9a4b947ec236eaedb8f2dc80c", size = 158712 },
{ url = "https://files.pythonhosted.org/packages/74/27/28f07df09f2983178db7bf6c9cccc847205d2b92ced986cd79565d68af4f/websockets-14.1-cp312-cp312-win_amd64.whl", hash = "sha256:90f4c7a069c733d95c308380aae314f2cb45bd8a904fb03eb36d1a4983a4993f", size = 163277 }, { url = "https://files.pythonhosted.org/packages/46/93/e19160db48b5581feac8468330aa11b7292880a94a37d7030478596cc14e/websockets-13.1-cp312-cp312-win_amd64.whl", hash = "sha256:38377f8b0cdeee97c552d20cf1865695fcd56aba155ad1b4ca8779a5b6ef4ac3", size = 159145 },
{ url = "https://files.pythonhosted.org/packages/b0/0b/c7e5d11020242984d9d37990310520ed663b942333b83a033c2f20191113/websockets-14.1-py3-none-any.whl", hash = "sha256:4d4fc827a20abe6d544a119896f6b78ee13fe81cbfef416f3f2ddf09a03f0e2e", size = 156277 }, { url = "https://files.pythonhosted.org/packages/51/20/2b99ca918e1cbd33c53db2cace5f0c0cd8296fc77558e1908799c712e1cd/websockets-13.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:a9ab1e71d3d2e54a0aa646ab6d4eebfaa5f416fe78dfe4da2839525dc5d765c6", size = 157828 },
{ url = "https://files.pythonhosted.org/packages/b8/47/0932a71d3d9c0e9483174f60713c84cee58d62839a143f21a2bcdbd2d205/websockets-13.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:b9d7439d7fab4dce00570bb906875734df13d9faa4b48e261c440a5fec6d9708", size = 155487 },
{ url = "https://files.pythonhosted.org/packages/a9/60/f1711eb59ac7a6c5e98e5637fef5302f45b6f76a2c9d64fd83bbb341377a/websockets-13.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:327b74e915cf13c5931334c61e1a41040e365d380f812513a255aa804b183418", size = 155721 },
{ url = "https://files.pythonhosted.org/packages/6a/e6/ba9a8db7f9d9b0e5f829cf626ff32677f39824968317223605a6b419d445/websockets-13.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:325b1ccdbf5e5725fdcb1b0e9ad4d2545056479d0eee392c291c1bf76206435a", size = 165609 },
{ url = "https://files.pythonhosted.org/packages/c1/22/4ec80f1b9c27a0aebd84ccd857252eda8418ab9681eb571b37ca4c5e1305/websockets-13.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:346bee67a65f189e0e33f520f253d5147ab76ae42493804319b5716e46dddf0f", size = 164556 },
{ url = "https://files.pythonhosted.org/packages/27/ac/35f423cb6bb15600438db80755609d27eda36d4c0b3c9d745ea12766c45e/websockets-13.1-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:91a0fa841646320ec0d3accdff5b757b06e2e5c86ba32af2e0815c96c7a603c5", size = 164993 },
{ url = "https://files.pythonhosted.org/packages/31/4e/98db4fd267f8be9e52e86b6ee4e9aa7c42b83452ea0ea0672f176224b977/websockets-13.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:18503d2c5f3943e93819238bf20df71982d193f73dcecd26c94514f417f6b135", size = 165360 },
{ url = "https://files.pythonhosted.org/packages/3f/15/3f0de7cda70ffc94b7e7024544072bc5b26e2c1eb36545291abb755d8cdb/websockets-13.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:a9cd1af7e18e5221d2878378fbc287a14cd527fdd5939ed56a18df8a31136bb2", size = 164745 },
{ url = "https://files.pythonhosted.org/packages/a1/6e/66b6b756aebbd680b934c8bdbb6dcb9ce45aad72cde5f8a7208dbb00dd36/websockets-13.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:70c5be9f416aa72aab7a2a76c90ae0a4fe2755c1816c153c1a2bcc3333ce4ce6", size = 164732 },
{ url = "https://files.pythonhosted.org/packages/35/c6/12e3aab52c11aeb289e3dbbc05929e7a9d90d7a9173958477d3ef4f8ce2d/websockets-13.1-cp313-cp313-win32.whl", hash = "sha256:624459daabeb310d3815b276c1adef475b3e6804abaf2d9d2c061c319f7f187d", size = 158709 },
{ url = "https://files.pythonhosted.org/packages/41/d8/63d6194aae711d7263df4498200c690a9c39fb437ede10f3e157a6343e0d/websockets-13.1-cp313-cp313-win_amd64.whl", hash = "sha256:c518e84bb59c2baae725accd355c8dc517b4a3ed8db88b4bc93c78dae2974bf2", size = 159144 },
{ url = "https://files.pythonhosted.org/packages/56/27/96a5cd2626d11c8280656c6c71d8ab50fe006490ef9971ccd154e0c42cd2/websockets-13.1-py3-none-any.whl", hash = "sha256:a9a396a6ad26130cdae92ae10c36af09d9bfe6cafe69670fd3b6da9b07b4044f", size = 152134 },
] ]
[[package]] [[package]]

View File

@ -7,7 +7,7 @@ environment:
POSTGRES_DB: 'test_{{ cookiecutter.project_slug }}' POSTGRES_DB: 'test_{{ cookiecutter.project_slug }}'
POSTGRES_HOST_AUTH_METHOD: trust POSTGRES_HOST_AUTH_METHOD: trust
{%- if cookiecutter.use_celery == 'y' %} {%- if cookiecutter.use_celery == 'y' %}
REDIS_URL: 'redis://redis:6379/0' CELERY_BROKER_URL: 'redis://redis:6379/0'
{%- endif %} {%- endif %}
steps: steps:

View File

@ -12,7 +12,7 @@ trim_trailing_whitespace = true
indent_style = space indent_style = space
indent_size = 4 indent_size = 4
[*.{html,css,scss,json,yml,xml,toml}] [*.{html,css,scss,json,yml,xml}]
indent_style = space indent_style = space
indent_size = 2 indent_size = 2

View File

@ -9,20 +9,16 @@ updates:
# Every weekday # Every weekday
schedule: schedule:
interval: 'daily' interval: 'daily'
groups:
github-actions:
patterns:
- '*'
{%- if cookiecutter.use_docker == 'y' %} {%- if cookiecutter.use_docker == 'y' %}
# Enable version updates for Docker # Enable version updates for Docker
# We need to specify each Dockerfile in a separate entry because Dependabot doesn't
# support wildcards or recursively checking subdirectories. Check this issue for updates:
# https://github.com/dependabot/dependabot-core/issues/2178
- package-ecosystem: 'docker' - package-ecosystem: 'docker'
# Look for a `Dockerfile` in the `compose/local/django` directory # Look for a `Dockerfile` in the `compose/local/django` directory
directories: directory: 'compose/local/django/'
- 'compose/local/django/'
- 'compose/local/docs/'
- 'compose/production/django/'
# Every weekday # Every weekday
schedule: schedule:
interval: 'daily' interval: 'daily'
@ -32,41 +28,81 @@ updates:
update-types: update-types:
- 'version-update:semver-major' - 'version-update:semver-major'
- 'version-update:semver-minor' - 'version-update:semver-minor'
groups:
docker-python:
patterns:
- '*'
- package-ecosystem: 'docker' - package-ecosystem: 'docker'
# Look for a `Dockerfile` in the listed directories # Look for a `Dockerfile` in the `compose/local/docs` directory
directories: directory: 'compose/local/docs/'
- 'compose/local/node/'
- 'compose/production/aws/'
- 'compose/production/postgres/'
- 'compose/production/traefik/'
{%- if cookiecutter.cloud_provider == 'None' %}
- 'compose/production/nginx/'
{%- endif %}
# Every weekday # Every weekday
schedule: schedule:
interval: 'daily' interval: 'daily'
# Ignore minor version updates (3.10 -> 3.11) but update patch versions
ignore:
- dependency-name: '*'
update-types:
- 'version-update:semver-major'
- 'version-update:semver-minor'
- package-ecosystem: 'docker'
# Look for a `Dockerfile` in the `compose/local/node` directory
directory: 'compose/local/node/'
# Every weekday
schedule:
interval: 'daily'
- package-ecosystem: 'docker'
# Look for a `Dockerfile` in the `compose/production/aws` directory
directory: 'compose/production/aws/'
# Every weekday
schedule:
interval: 'daily'
- package-ecosystem: 'docker'
# Look for a `Dockerfile` in the `compose/production/django` directory
directory: 'compose/production/django/'
# Every weekday
schedule:
interval: 'daily'
# Ignore minor version updates (3.10 -> 3.11) but update patch versions
ignore:
- dependency-name: '*'
update-types:
- 'version-update:semver-major'
- 'version-update:semver-minor'
- package-ecosystem: 'docker'
# Look for a `Dockerfile` in the `compose/production/postgres` directory
directory: 'compose/production/postgres/'
# Every weekday
schedule:
interval: 'daily'
- package-ecosystem: 'docker'
# Look for a `Dockerfile` in the `compose/production/traefik` directory
directory: 'compose/production/traefik/'
# Every weekday
schedule:
interval: 'daily'
{%- if cookiecutter.cloud_provider == 'None' %}
- package-ecosystem: 'docker'
# Look for a `Dockerfile` in the `compose/production/nginx` directory
directory: 'compose/production/nginx/'
# Every weekday
schedule:
interval: 'daily'
{%- endif %}
{%- endif %} {%- endif %}
# Enable version updates for Python/Pip - Production # Enable version updates for Python/Pip - Production
- package-ecosystem: 'pip' - package-ecosystem: 'pip'
# Look for a `requirements.txt` in the `root` directory # Look for a `requirements.txt` in the `root` directory
# also 'setup.cfg', '.python-version' and 'requirements/*.txt' # also 'setup.cfg', 'runtime.txt' and 'requirements/*.txt'
directory: '/' directory: '/'
# Every weekday # Every weekday
schedule: schedule:
interval: 'daily' interval: 'daily'
groups:
python:
update-types:
- 'minor'
- 'patch'
{%- if cookiecutter.frontend_pipeline == 'Gulp' %} {%- if cookiecutter.frontend_pipeline == 'Gulp' %}
@ -77,10 +113,5 @@ updates:
# Every weekday # Every weekday
schedule: schedule:
interval: 'daily' interval: 'daily'
groups:
javascript:
update-types:
- 'minor'
- 'patch'
{%- endif %} {%- endif %}

View File

@ -28,7 +28,7 @@ jobs:
- name: Set up Python - name: Set up Python
uses: actions/setup-python@v5 uses: actions/setup-python@v5
with: with:
python-version-file: '.python-version' python-version: '3.12'
{%- if cookiecutter.open_source_license != 'Not open source' %} {%- if cookiecutter.open_source_license != 'Not open source' %}
# Consider using pre-commit.ci for open source project # Consider using pre-commit.ci for open source project
@ -57,7 +57,7 @@ jobs:
env: env:
{%- if cookiecutter.use_celery == 'y' %} {%- if cookiecutter.use_celery == 'y' %}
REDIS_URL: 'redis://localhost:6379/0' CELERY_BROKER_URL: 'redis://localhost:6379/0'
{%- endif %} {%- endif %}
# postgres://user:password@host:port/database # postgres://user:password@host:port/database
DATABASE_URL: 'postgres://postgres:postgres@localhost:5432/postgres' DATABASE_URL: 'postgres://postgres:postgres@localhost:5432/postgres'
@ -68,31 +68,11 @@ jobs:
uses: actions/checkout@v4 uses: actions/checkout@v4
{%- if cookiecutter.use_docker == 'y' %} {%- if cookiecutter.use_docker == 'y' %}
- name: Set up Docker Buildx - name: Build the Stack
uses: docker/setup-buildx-action@v3 run: docker compose -f docker-compose.local.yml build django
- name: Build and cache local backend - name: Build the docs
uses: docker/bake-action@v6 run: docker compose -f docker-compose.docs.yml build docs
with:
push: false
load: true
files: docker-compose.local.yml
targets: django
set: |
django.cache-from=type=gha,scope=django-cached-tests
django.cache-to=type=gha,scope=django-cached-tests,mode=max
postgres.cache-from=type=gha,scope=postgres-cached-tests
postgres.cache-to=type=gha,scope=postgres-cached-tests,mode=max
- name: Build and cache docs
uses: docker/bake-action@v6
with:
push: false
load: true
files: docker-compose.docs.yml
set: |
docs.cache-from=type=gha,scope=cached-docs
docs.cache-to=type=gha,scope=cached-docs,mode=max
- name: Check DB Migrations - name: Check DB Migrations
run: docker compose -f docker-compose.local.yml run --rm django python manage.py makemigrations --check run: docker compose -f docker-compose.local.yml run --rm django python manage.py makemigrations --check
@ -108,9 +88,9 @@ jobs:
{%- else %} {%- else %}
- name: Set up Python - name: Set up Python
uses: actions/setup-python@v5 uses: actions/setup-python@v4
with: with:
python-version-file: '.python-version' python-version: '3.12'
cache: pip cache: pip
cache-dependency-path: | cache-dependency-path: |
requirements/base.txt requirements/base.txt

View File

@ -59,6 +59,9 @@ docs/_build/
# PyBuilder # PyBuilder
target/ target/
# pyenv
.python-version
{% if cookiecutter.use_celery == 'y' -%} {% if cookiecutter.use_celery == 'y' -%}
# celery beat schedule file # celery beat schedule file
celerybeat-schedule celerybeat-schedule

View File

@ -8,7 +8,7 @@ variables:
POSTGRES_DB: 'test_{{ cookiecutter.project_slug }}' POSTGRES_DB: 'test_{{ cookiecutter.project_slug }}'
POSTGRES_HOST_AUTH_METHOD: trust POSTGRES_HOST_AUTH_METHOD: trust
{%- if cookiecutter.use_celery == 'y' %} {%- if cookiecutter.use_celery == 'y' %}
REDIS_URL: 'redis://redis:6379/0' CELERY_BROKER_URL: 'redis://redis:6379/0'
{%- endif %} {%- endif %}
precommit: precommit:

View File

@ -1,6 +1,5 @@
exclude: '^docs/|/migrations/|devcontainer.json' exclude: '^docs/|/migrations/|devcontainer.json'
default_stages: [pre-commit] default_stages: [pre-commit]
minimum_pre_commit_version: "3.2.0"
default_language_version: default_language_version:
python: python3.12 python: python3.12
@ -29,14 +28,14 @@ repos:
exclude: '{{cookiecutter.project_slug}}/templates/' exclude: '{{cookiecutter.project_slug}}/templates/'
- repo: https://github.com/adamchainz/django-upgrade - repo: https://github.com/adamchainz/django-upgrade
rev: '1.24.0' rev: '1.22.0'
hooks: hooks:
- id: django-upgrade - id: django-upgrade
args: ['--target-version', '5.0'] args: ['--target-version', '5.0']
# Run the Ruff linter. # Run the Ruff linter.
- repo: https://github.com/astral-sh/ruff-pre-commit - repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.11.4 rev: v0.6.9
hooks: hooks:
# Linter # Linter
- id: ruff - id: ruff
@ -45,7 +44,7 @@ repos:
- id: ruff-format - id: ruff-format
- repo: https://github.com/Riverside-Healthcare/djLint - repo: https://github.com/Riverside-Healthcare/djLint
rev: v1.36.4 rev: v1.35.2
hooks: hooks:
- id: djlint-reformat-django - id: djlint-reformat-django
- id: djlint-django - id: djlint-django

View File

@ -1 +0,0 @@
3.12

View File

@ -12,7 +12,7 @@ License: {{cookiecutter.open_source_license}}
## Settings ## Settings
Moved to [settings](https://cookiecutter-django.readthedocs.io/en/latest/1-getting-started/settings.html). Moved to [settings](http://cookiecutter-django.readthedocs.io/en/latest/settings.html).
## Basic Commands ## Basic Commands
@ -46,7 +46,7 @@ To run the tests, check your test coverage, and generate an HTML coverage report
### Live reloading and Sass CSS compilation ### Live reloading and Sass CSS compilation
Moved to [Live reloading and SASS compilation](https://cookiecutter-django.readthedocs.io/en/latest/2-local-development/developing-locally.html#using-webpack-or-gulp). Moved to [Live reloading and SASS compilation](https://cookiecutter-django.readthedocs.io/en/latest/developing-locally.html#sass-compilation-live-reloading).
{%- if cookiecutter.use_celery == "y" %} {%- if cookiecutter.use_celery == "y" %}
@ -87,7 +87,7 @@ celery -A config.celery_app worker -B -l info
In development, it is often nice to be able to see emails that are being sent from your application. For that reason local SMTP server [Mailpit](https://github.com/axllent/mailpit) with a web interface is available as docker container. In development, it is often nice to be able to see emails that are being sent from your application. For that reason local SMTP server [Mailpit](https://github.com/axllent/mailpit) with a web interface is available as docker container.
Container mailpit will start automatically when you will run all docker containers. Container mailpit will start automatically when you will run all docker containers.
Please check [cookiecutter-django Docker documentation](https://cookiecutter-django.readthedocs.io/en/latest/2-local-development/developing-locally-docker.html) for more details how to start all containers. Please check [cookiecutter-django Docker documentation](http://cookiecutter-django.readthedocs.io/en/latest/deployment-with-docker.html) for more details how to start all containers.
With Mailpit running, to view messages that are sent by your application, open your browser and go to `http://127.0.0.1:8025` With Mailpit running, to view messages that are sent by your application, open your browser and go to `http://127.0.0.1:8025`
{%- else %} {%- else %}
@ -130,14 +130,14 @@ The following details how to deploy this application.
### Heroku ### Heroku
See detailed [cookiecutter-django Heroku documentation](https://cookiecutter-django.readthedocs.io/en/latest/3-deployment/deployment-on-heroku.html). See detailed [cookiecutter-django Heroku documentation](http://cookiecutter-django.readthedocs.io/en/latest/deployment-on-heroku.html).
{%- endif %} {%- endif %}
{%- if cookiecutter.use_docker.lower() == "y" %} {%- if cookiecutter.use_docker.lower() == "y" %}
### Docker ### Docker
See detailed [cookiecutter-django Docker documentation](https://cookiecutter-django.readthedocs.io/en/latest/3-deployment/deployment-with-docker.html). See detailed [cookiecutter-django Docker documentation](http://cookiecutter-django.readthedocs.io/en/latest/deployment-with-docker.html).
{%- endif %} {%- endif %}
{%- if cookiecutter.frontend_pipeline in ['Gulp', 'Webpack'] %} {%- if cookiecutter.frontend_pipeline in ['Gulp', 'Webpack'] %}

View File

@ -1,5 +1,5 @@
# define an alias for the specific python version used in this file. # define an alias for the specific python version used in this file.
FROM docker.io/python:3.12.9-slim-bookworm AS python FROM docker.io/python:3.12.7-slim-bookworm AS python
# Python build stage # Python build stage
FROM python AS python-build-stage FROM python AS python-build-stage

View File

@ -13,4 +13,4 @@ echo 'Starting flower'
exec watchfiles --filter python celery.__main__.main \ exec watchfiles --filter python celery.__main__.main \
--args \ --args \
"-A config.celery_app -b \"${REDIS_URL}\" flower --basic_auth=\"${CELERY_FLOWER_USER}:${CELERY_FLOWER_PASSWORD}\"" "-A config.celery_app -b \"${CELERY_BROKER_URL}\" flower --basic_auth=\"${CELERY_FLOWER_USER}:${CELERY_FLOWER_PASSWORD}\""

View File

@ -1,5 +1,5 @@
# define an alias for the specific python version used in this file. # define an alias for the specific python version used in this file.
FROM docker.io/python:3.12.9-slim-bookworm AS python FROM docker.io/python:3.12.7-slim-bookworm AS python
# Python build stage # Python build stage

View File

@ -1,4 +1,4 @@
FROM docker.io/node:22.14-bookworm-slim FROM docker.io/node:22-bookworm-slim
WORKDIR /app WORKDIR /app

View File

@ -1,4 +1,4 @@
FROM docker.io/amazon/aws-cli:2.25.0 FROM docker.io/amazon/aws-cli:2.18.1
# Clear entrypoint from the base image, otherwise it's always calling the aws CLI # Clear entrypoint from the base image, otherwise it's always calling the aws CLI
ENTRYPOINT [] ENTRYPOINT []

View File

@ -1,5 +1,5 @@
{% if cookiecutter.frontend_pipeline in ['Gulp', 'Webpack'] -%} {% if cookiecutter.frontend_pipeline in ['Gulp', 'Webpack'] -%}
FROM docker.io/node:22.14-bookworm-slim AS client-builder FROM docker.io/node:20-bookworm-slim AS client-builder
ARG APP_HOME=/app ARG APP_HOME=/app
WORKDIR ${APP_HOME} WORKDIR ${APP_HOME}
@ -25,7 +25,7 @@ RUN npm run build
{%- endif %} {%- endif %}
# define an alias for the specific python version used in this file. # define an alias for the specific python version used in this file.
FROM docker.io/python:3.12.9-slim-bookworm AS python FROM docker.io/python:3.12.7-slim-bookworm AS python
# Python build stage # Python build stage
FROM python AS python-build-stage FROM python AS python-build-stage
@ -61,7 +61,7 @@ ENV BUILD_ENV=${BUILD_ENVIRONMENT}
WORKDIR ${APP_HOME} WORKDIR ${APP_HOME}
RUN addgroup --system django \ RUN addgroup --system django \
&& adduser --system --ingroup django django && adduser --system --ingroup django django
# Install required system dependencies # Install required system dependencies
@ -125,6 +125,9 @@ RUN chown -R django:django ${APP_HOME}
USER django USER django
RUN DATABASE_URL="" \ RUN DATABASE_URL="" \
{%- if cookiecutter.use_celery == "y" %}
CELERY_BROKER_URL="" \
{%- endif %}
DJANGO_SETTINGS_MODULE="config.settings.test" \ DJANGO_SETTINGS_MODULE="config.settings.test" \
python manage.py compilemessages python manage.py compilemessages

View File

@ -14,6 +14,6 @@ echo 'Starting flower'
exec celery \ exec celery \
-A config.celery_app \ -A config.celery_app \
-b "${REDIS_URL}" \ -b "${CELERY_BROKER_URL}" \
flower \ flower \
--basic_auth="${CELERY_FLOWER_USER}:${CELERY_FLOWER_PASSWORD}" --basic_auth="${CELERY_FLOWER_USER}:${CELERY_FLOWER_PASSWORD}"

View File

@ -4,6 +4,12 @@ set -o errexit
set -o pipefail set -o pipefail
set -o nounset set -o nounset
{% if cookiecutter.use_celery == 'y' %}
# N.B. If only .env files supported variable expansion...
export CELERY_BROKER_URL="${REDIS_URL}"
{% endif %}
if [ -z "${POSTGRES_USER}" ]; then if [ -z "${POSTGRES_USER}" ]; then
base_postgres_image_default_user='postgres' base_postgres_image_default_user='postgres'
export POSTGRES_USER="${base_postgres_image_default_user}" export POSTGRES_USER="${base_postgres_image_default_user}"

View File

@ -1,4 +1,4 @@
FROM docker.io/traefik:3.3.5 FROM docker.io/traefik:3.1.6
RUN mkdir -p /etc/traefik/acme \ RUN mkdir -p /etc/traefik/acme \
&& touch /etc/traefik/acme/acme.json \ && touch /etc/traefik/acme/acme.json \
&& chmod 600 /etc/traefik/acme/acme.json && chmod 600 /etc/traefik/acme/acme.json

View File

@ -1,3 +1,4 @@
# ruff: noqa
""" """
ASGI config for {{ cookiecutter.project_name }} project. ASGI config for {{ cookiecutter.project_name }} project.
@ -24,9 +25,12 @@ os.environ.setdefault("DJANGO_SETTINGS_MODULE", "config.settings.local")
# This application object is used by any ASGI server configured to use this file. # This application object is used by any ASGI server configured to use this file.
django_application = get_asgi_application() django_application = get_asgi_application()
# Apply ASGI middleware here.
# from helloworld.asgi import HelloWorldApplication
# application = HelloWorldApplication(application)
# Import websocket application here, so apps from django_application are loaded first # Import websocket application here, so apps from django_application are loaded first
from config.websocket import websocket_application # noqa: E402 from config.websocket import websocket_application
async def application(scope, receive, send): async def application(scope, receive, send):

View File

@ -1,7 +1,6 @@
import os import os
from celery import Celery from celery import Celery
from celery.signals import setup_logging
# set the default Django settings module for the 'celery' program. # set the default Django settings module for the 'celery' program.
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "config.settings.local") os.environ.setdefault("DJANGO_SETTINGS_MODULE", "config.settings.local")
@ -14,15 +13,5 @@ app = Celery("{{cookiecutter.project_slug}}")
# should have a `CELERY_` prefix. # should have a `CELERY_` prefix.
app.config_from_object("django.conf:settings", namespace="CELERY") app.config_from_object("django.conf:settings", namespace="CELERY")
@setup_logging.connect
def config_loggers(*args, **kwargs):
from logging.config import dictConfig
from django.conf import settings
dictConfig(settings.LOGGING)
# Load task modules from all registered Django app configs. # Load task modules from all registered Django app configs.
app.autodiscover_tasks() app.autodiscover_tasks()

View File

@ -1,9 +1,6 @@
# ruff: noqa: ERA001, E501 # ruff: noqa: ERA001, E501
"""Base settings to build other settings files upon.""" """Base settings to build other settings files upon."""
{% if cookiecutter.use_celery == 'y' -%}
import ssl
{%- endif %}
from pathlib import Path from pathlib import Path
import environ import environ
@ -285,9 +282,6 @@ LOGGING = {
"root": {"level": "INFO", "handlers": ["console"]}, "root": {"level": "INFO", "handlers": ["console"]},
} }
REDIS_URL = env("REDIS_URL", default="redis://{% if cookiecutter.use_docker == 'y' %}redis{%else%}localhost{% endif %}:6379/0")
REDIS_SSL = REDIS_URL.startswith("rediss://")
{% if cookiecutter.use_celery == 'y' -%} {% if cookiecutter.use_celery == 'y' -%}
# Celery # Celery
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
@ -295,13 +289,9 @@ if USE_TZ:
# https://docs.celeryq.dev/en/stable/userguide/configuration.html#std:setting-timezone # https://docs.celeryq.dev/en/stable/userguide/configuration.html#std:setting-timezone
CELERY_TIMEZONE = TIME_ZONE CELERY_TIMEZONE = TIME_ZONE
# https://docs.celeryq.dev/en/stable/userguide/configuration.html#std:setting-broker_url # https://docs.celeryq.dev/en/stable/userguide/configuration.html#std:setting-broker_url
CELERY_BROKER_URL = REDIS_URL CELERY_BROKER_URL = env("CELERY_BROKER_URL")
# https://docs.celeryq.dev/en/stable/userguide/configuration.html#redis-backend-use-ssl
CELERY_BROKER_USE_SSL = {"ssl_cert_reqs": ssl.CERT_NONE} if REDIS_SSL else None
# https://docs.celeryq.dev/en/stable/userguide/configuration.html#std:setting-result_backend # https://docs.celeryq.dev/en/stable/userguide/configuration.html#std:setting-result_backend
CELERY_RESULT_BACKEND = REDIS_URL CELERY_RESULT_BACKEND = CELERY_BROKER_URL
# https://docs.celeryq.dev/en/stable/userguide/configuration.html#redis-backend-use-ssl
CELERY_REDIS_BACKEND_USE_SSL = CELERY_BROKER_USE_SSL
# https://docs.celeryq.dev/en/stable/userguide/configuration.html#result-extended # https://docs.celeryq.dev/en/stable/userguide/configuration.html#result-extended
CELERY_RESULT_EXTENDED = True CELERY_RESULT_EXTENDED = True
# https://docs.celeryq.dev/en/stable/userguide/configuration.html#result-backend-always-retry # https://docs.celeryq.dev/en/stable/userguide/configuration.html#result-backend-always-retry
@ -327,20 +317,18 @@ CELERY_BEAT_SCHEDULER = "django_celery_beat.schedulers:DatabaseScheduler"
CELERY_WORKER_SEND_TASK_EVENTS = True CELERY_WORKER_SEND_TASK_EVENTS = True
# https://docs.celeryq.dev/en/stable/userguide/configuration.html#std-setting-task_send_sent_event # https://docs.celeryq.dev/en/stable/userguide/configuration.html#std-setting-task_send_sent_event
CELERY_TASK_SEND_SENT_EVENT = True CELERY_TASK_SEND_SENT_EVENT = True
# https://docs.celeryq.dev/en/stable/userguide/configuration.html#worker-hijack-root-logger
CELERY_WORKER_HIJACK_ROOT_LOGGER = False
{%- endif %} {%- endif %}
# django-allauth # django-allauth
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
ACCOUNT_ALLOW_REGISTRATION = env.bool("DJANGO_ACCOUNT_ALLOW_REGISTRATION", True) ACCOUNT_ALLOW_REGISTRATION = env.bool("DJANGO_ACCOUNT_ALLOW_REGISTRATION", True)
# https://docs.allauth.org/en/latest/account/configuration.html # https://docs.allauth.org/en/latest/account/configuration.html
ACCOUNT_LOGIN_METHODS = {"{{cookiecutter.username_type}}"} ACCOUNT_AUTHENTICATION_METHOD = "{{cookiecutter.username_type}}"
# https://docs.allauth.org/en/latest/account/configuration.html # https://docs.allauth.org/en/latest/account/configuration.html
{%- if cookiecutter.username_type == "username" %} ACCOUNT_EMAIL_REQUIRED = True
ACCOUNT_SIGNUP_FIELDS = ["email*", "username*", "password1*", "password2*"] {%- if cookiecutter.username_type == "email" %}
{%- else %} # https://docs.allauth.org/en/latest/account/configuration.html
ACCOUNT_SIGNUP_FIELDS = ["email*", "password1*", "password2*"] ACCOUNT_USERNAME_REQUIRED = False
# https://docs.allauth.org/en/latest/account/configuration.html # https://docs.allauth.org/en/latest/account/configuration.html
ACCOUNT_USER_MODEL_USERNAME_FIELD = None ACCOUNT_USER_MODEL_USERNAME_FIELD = None
{%- endif %} {%- endif %}

View File

@ -16,7 +16,6 @@ from sentry_sdk.integrations.redis import RedisIntegration
from .base import * # noqa: F403 from .base import * # noqa: F403
from .base import DATABASES from .base import DATABASES
from .base import INSTALLED_APPS from .base import INSTALLED_APPS
from .base import REDIS_URL
{%- if cookiecutter.use_drf == "y" %} {%- if cookiecutter.use_drf == "y" %}
from .base import SPECTACULAR_SETTINGS from .base import SPECTACULAR_SETTINGS
{%- endif %} {%- endif %}
@ -38,10 +37,10 @@ DATABASES["default"]["CONN_MAX_AGE"] = env.int("CONN_MAX_AGE", default=60)
CACHES = { CACHES = {
"default": { "default": {
"BACKEND": "django_redis.cache.RedisCache", "BACKEND": "django_redis.cache.RedisCache",
"LOCATION": REDIS_URL, "LOCATION": env("REDIS_URL"),
"OPTIONS": { "OPTIONS": {
"CLIENT_CLASS": "django_redis.client.DefaultClient", "CLIENT_CLASS": "django_redis.client.DefaultClient",
# Mimicking memcache behavior. # Mimicing memcache behavior.
# https://github.com/jazzband/django-redis#memcached-exceptions-behavior # https://github.com/jazzband/django-redis#memcached-exceptions-behavior
"IGNORE_EXCEPTIONS": True, "IGNORE_EXCEPTIONS": True,
}, },
@ -171,7 +170,7 @@ STORAGES = {
"BACKEND": "storages.backends.azure_storage.AzureStorage", "BACKEND": "storages.backends.azure_storage.AzureStorage",
"OPTIONS": { "OPTIONS": {
"location": "media", "location": "media",
"overwrite_files": False, "file_overwrite": False,
}, },
}, },
{%- if cookiecutter.use_whitenoise == 'y' %} {%- if cookiecutter.use_whitenoise == 'y' %}
@ -324,7 +323,7 @@ COMPRESS_FILTERS = {
"js": ["compressor.filters.jsmin.JSMinFilter"], "js": ["compressor.filters.jsmin.JSMinFilter"],
} }
{% endif %} {% endif %}
{%- if cookiecutter.use_whitenoise == 'n' and cookiecutter.cloud_provider in ('AWS', 'GCP') -%} {%- if cookiecutter.use_whitenoise == 'n' -%}
# Collectfasta # Collectfasta
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
# https://github.com/jasongi/collectfasta#installation # https://github.com/jasongi/collectfasta#installation

View File

@ -33,7 +33,7 @@ TEMPLATES[0]["OPTIONS"]["debug"] = True # type: ignore[index]
# MEDIA # MEDIA
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
# https://docs.djangoproject.com/en/dev/ref/settings/#media-url # https://docs.djangoproject.com/en/dev/ref/settings/#media-url
MEDIA_URL = "http://media.testserver/" MEDIA_URL = "http://media.testserver"
{%- if cookiecutter.frontend_pipeline == 'Webpack' %} {%- if cookiecutter.frontend_pipeline == 'Webpack' %}
# django-webpack-loader # django-webpack-loader

View File

@ -1,3 +1,4 @@
# ruff: noqa
from django.conf import settings from django.conf import settings
from django.conf.urls.static import static from django.conf.urls.static import static
from django.contrib import admin from django.contrib import admin
@ -42,7 +43,7 @@ urlpatterns += [
# API base url # API base url
path("api/", include("config.api_router")), path("api/", include("config.api_router")),
# DRF auth token # DRF auth token
path("api/auth-token/", obtain_auth_token, name="obtain_auth_token"), path("api/auth-token/", obtain_auth_token),
path("api/schema/", SpectacularAPIView.as_view(), name="api-schema"), path("api/schema/", SpectacularAPIView.as_view(), name="api-schema"),
path( path(
"api/docs/", "api/docs/",
@ -76,7 +77,4 @@ if settings.DEBUG:
if "debug_toolbar" in settings.INSTALLED_APPS: if "debug_toolbar" in settings.INSTALLED_APPS:
import debug_toolbar import debug_toolbar
urlpatterns = [ urlpatterns = [path("__debug__/", include(debug_toolbar.urls))] + urlpatterns
path("__debug__/", include(debug_toolbar.urls)),
*urlpatterns,
]

View File

@ -1,3 +1,4 @@
# ruff: noqa
""" """
WSGI config for {{ cookiecutter.project_name }} project. WSGI config for {{ cookiecutter.project_name }} project.
@ -24,9 +25,16 @@ from django.core.wsgi import get_wsgi_application
# {{ cookiecutter.project_slug }} directory. # {{ cookiecutter.project_slug }} directory.
BASE_DIR = Path(__file__).resolve(strict=True).parent.parent BASE_DIR = Path(__file__).resolve(strict=True).parent.parent
sys.path.append(str(BASE_DIR / "{{ cookiecutter.project_slug }}")) sys.path.append(str(BASE_DIR / "{{ cookiecutter.project_slug }}"))
# We defer to a DJANGO_SETTINGS_MODULE already in the environment. This breaks
# if running multiple sites in the same mod_wsgi process. To fix this, use
# mod_wsgi daemon mode with each site in its own daemon process, or use
# os.environ["DJANGO_SETTINGS_MODULE"] = "config.settings.production"
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "config.settings.production") os.environ.setdefault("DJANGO_SETTINGS_MODULE", "config.settings.production")
# This application object is used by any WSGI server configured to use this # This application object is used by any WSGI server configured to use this
# file. This includes Django's development server, if the WSGI_APPLICATION # file. This includes Django's development server, if the WSGI_APPLICATION
# setting points here. # setting points here.
application = get_wsgi_application() application = get_wsgi_application()
# Apply WSGI middleware here.
# from helloworld.wsgi import HelloWorldApplication
# application = HelloWorldApplication(application)

View File

@ -1,4 +1,4 @@
# ruff: noqa: ERA001, PTH100 # ruff: noqa
# Configuration file for the Sphinx documentation builder. # Configuration file for the Sphinx documentation builder.
# #
# This file only contains a selection of the most common options. For a full # This file only contains a selection of the most common options. For a full
@ -13,10 +13,9 @@
import os import os
import sys import sys
import django import django
if os.getenv("READTHEDOCS", default="False") == "True": if os.getenv("READTHEDOCS", default=False) == "True":
sys.path.insert(0, os.path.abspath("..")) sys.path.insert(0, os.path.abspath(".."))
os.environ["DJANGO_READ_DOT_ENV_FILE"] = "True" os.environ["DJANGO_READ_DOT_ENV_FILE"] = "True"
os.environ["USE_DOCKER"] = "no" os.environ["USE_DOCKER"] = "no"
@ -27,13 +26,16 @@ else:
sys.path.insert(0, os.path.abspath("..")) sys.path.insert(0, os.path.abspath(".."))
{%- endif %} {%- endif %}
os.environ["DATABASE_URL"] = "sqlite:///readthedocs.db" os.environ["DATABASE_URL"] = "sqlite:///readthedocs.db"
{%- if cookiecutter.use_celery == 'y' %}
os.environ["CELERY_BROKER_URL"] = os.getenv("REDIS_URL", "redis://redis:6379")
{%- endif %}
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "config.settings.local") os.environ.setdefault("DJANGO_SETTINGS_MODULE", "config.settings.local")
django.setup() django.setup()
# -- Project information ----------------------------------------------------- # -- Project information -----------------------------------------------------
project = "{{ cookiecutter.project_name }}" project = "{{ cookiecutter.project_name }}"
copyright = """{% now 'utc', '%Y' %}, {{ cookiecutter.author_name }}""" # noqa: A001 copyright = """{% now 'utc', '%Y' %}, {{ cookiecutter.author_name }}"""
author = "{{ cookiecutter.author_name }}" author = "{{ cookiecutter.author_name }}"

View File

@ -3,32 +3,28 @@
//////////////////////////////// ////////////////////////////////
// Gulp and package // Gulp and package
import { src, dest, parallel, series, task, watch } from 'gulp'; const { src, dest, parallel, series, watch } = require('gulp');
import pjson from './package.json' with {type: 'json'}; const pjson = require('./package.json');
// Plugins // Plugins
import autoprefixer from 'autoprefixer'; const autoprefixer = require('autoprefixer');
import browserSyncLib from 'browser-sync'; const browserSync = require('browser-sync').create();
import concat from 'gulp-concat'; const concat = require('gulp-concat');
import tildeImporter from 'node-sass-tilde-importer'; const tildeImporter = require('node-sass-tilde-importer');
import cssnano from 'cssnano'; const cssnano = require('cssnano');
import pixrem from 'pixrem'; const imagemin = require('gulp-imagemin');
import plumber from 'gulp-plumber'; const pixrem = require('pixrem');
import postcss from 'gulp-postcss'; const plumber = require('gulp-plumber');
import rename from 'gulp-rename'; const postcss = require('gulp-postcss');
import gulpSass from 'gulp-sass';
import * as dartSass from 'sass';
import gulUglifyES from 'gulp-uglify-es';
import { spawn } from 'node:child_process';
const browserSync = browserSyncLib.create();
const reload = browserSync.reload; const reload = browserSync.reload;
const sass = gulpSass(dartSass); const rename = require('gulp-rename');
const uglify = gulUglifyES.default; const sass = require('gulp-sass')(require('sass'));
const spawn = require('child_process').spawn;
const uglify = require('gulp-uglify-es').default;
// Relative paths function // Relative paths function
function pathsConfig() { function pathsConfig(appName) {
const appName = `./${pjson.name}`; this.app = `./${pjson.name}`;
const vendorsRoot = 'node_modules'; const vendorsRoot = 'node_modules';
return { return {
@ -36,13 +32,13 @@ function pathsConfig() {
`${vendorsRoot}/@popperjs/core/dist/umd/popper.js`, `${vendorsRoot}/@popperjs/core/dist/umd/popper.js`,
`${vendorsRoot}/bootstrap/dist/js/bootstrap.js`, `${vendorsRoot}/bootstrap/dist/js/bootstrap.js`,
], ],
app: appName, app: this.app,
templates: `${appName}/templates`, templates: `${this.app}/templates`,
css: `${appName}/static/css`, css: `${this.app}/static/css`,
sass: `${appName}/static/sass`, sass: `${this.app}/static/sass`,
fonts: `${appName}/static/fonts`, fonts: `${this.app}/static/fonts`,
images: `${appName}/static/images`, images: `${this.app}/static/images`,
js: `${appName}/static/js`, js: `${this.app}/static/js`,
}; };
} }
@ -99,8 +95,7 @@ function vendorScripts() {
} }
// Image compression // Image compression
async function imgCompression() { function imgCompression() {
const imagemin = (await import("gulp-imagemin")).default;
return src(`${paths.images}/*`) return src(`${paths.images}/*`)
.pipe(imagemin()) // Compresses PNG, JPEG, GIF and SVG images .pipe(imagemin()) // Compresses PNG, JPEG, GIF and SVG images
.pipe(dest(paths.images)); .pipe(dest(paths.images));
@ -168,7 +163,7 @@ function watchPaths() {
} }
// Generate all assets // Generate all assets
const build = parallel(styles, scripts, vendorScripts, imgCompression); const generateAssets = parallel(styles, scripts, vendorScripts, imgCompression);
// Set up dev environment // Set up dev environment
{%- if cookiecutter.use_docker == 'n' %} {%- if cookiecutter.use_docker == 'n' %}
@ -181,6 +176,6 @@ const dev = parallel(runServer, initBrowserSync, watchPaths);
const dev = parallel(initBrowserSync, watchPaths); const dev = parallel(initBrowserSync, watchPaths);
{%- endif %} {%- endif %}
task('default', series(build, dev)); exports.default = series(generateAssets, dev);
task('build', build); exports['generate-assets'] = generateAssets;
task('dev', dev); exports['dev'] = dev;

View File

@ -1,38 +0,0 @@
export COMPOSE_FILE := "docker-compose.local.yml"
## Just does not yet manage signals for subprocesses reliably, which can lead to unexpected behavior.
## Exercise caution before expanding its usage in production environments.
## For more information, see https://github.com/casey/just/issues/2473 .
# Default command to list all available commands.
default:
@just --list
# build: Build python image.
build:
@echo "Building python image..."
@docker compose build
# up: Start up containers.
up:
@echo "Starting up containers..."
@docker compose up -d --remove-orphans
# down: Stop containers.
down:
@echo "Stopping containers..."
@docker compose down
# prune: Remove containers and their volumes.
prune *args:
@echo "Killing containers and removing volumes..."
@docker compose down -v {{ "{{args}}" }}
# logs: View container logs
logs *args:
@docker compose logs -f {{ "{{args}}" }}
# manage: Executes `manage.py` command.
manage +args:
@docker compose run --rm django python ./manage.py {{ "{{args}}" }}

View File

@ -1,6 +1,6 @@
# Translations # Translations
Start by configuring the `LANGUAGES` settings in `base.py`, by uncommenting languages you are willing to support. Then, translation strings will be placed in this folder when running: Start by configuring the `LANGUAGES` settings in `base.py`, by uncommenting languages you are willing to support. Then, translations strings will be placed in this folder when running:
```bash ```bash
{% if cookiecutter.use_docker == 'y' %}docker compose -f docker-compose.local.yml run --rm django {% endif %}python manage.py makemessages --all --no-location {% if cookiecutter.use_docker == 'y' %}docker compose -f docker-compose.local.yml run --rm django {% endif %}python manage.py makemessages --all --no-location
@ -19,7 +19,7 @@ Once all translations are done, they need to be compiled into `.mo` files (stand
{% if cookiecutter.use_docker == 'y' %}docker compose -f docker-compose.local.yml run --rm django {% endif %}python manage.py compilemessages {% if cookiecutter.use_docker == 'y' %}docker compose -f docker-compose.local.yml run --rm django {% endif %}python manage.py compilemessages
``` ```
Note that the `.po` files are NOT used by the application directly, so if the `.mo` files are out of date, the content won't appear as translated even if the `.po` files are up-to-date. Note that the `.po` files are NOT used by the application directly, so if the `.mo` files are out of dates, the content won't appear as translated even if the `.po` files are up-to-date.
## Production ## Production

View File

@ -1,22 +1,28 @@
#!/usr/bin/env python #!/usr/bin/env python
"""Django's command-line utility for administrative tasks.""" # ruff: noqa
import os import os
import sys import sys
from pathlib import Path from pathlib import Path
if __name__ == "__main__":
def main():
"""Run administrative tasks."""
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "config.settings.local") os.environ.setdefault("DJANGO_SETTINGS_MODULE", "config.settings.local")
try: try:
from django.core.management import execute_from_command_line from django.core.management import execute_from_command_line
except ImportError as exc: except ImportError:
raise ImportError( # noqa: TRY003 # The above import may fail for some other reason. Ensure that the
"Couldn't import Django. Are you sure it's installed and " # noqa: EM101 # issue is really that Django is missing to avoid masking other
"available on your PYTHONPATH environment variable? Did you " # exceptions on Python 2.
"forget to activate a virtual environment?", try:
) from exc import django
except ImportError:
raise ImportError(
"Couldn't import Django. Are you sure it's installed and "
"available on your PYTHONPATH environment variable? Did you "
"forget to activate a virtual environment?"
)
raise
# This allows easy placement of apps within the interior # This allows easy placement of apps within the interior
# {{ cookiecutter.project_slug }} directory. # {{ cookiecutter.project_slug }} directory.
@ -24,7 +30,3 @@ def main():
sys.path.append(str(current_path / "{{ cookiecutter.project_slug }}")) sys.path.append(str(current_path / "{{ cookiecutter.project_slug }}"))
execute_from_command_line(sys.argv) execute_from_command_line(sys.argv)
if __name__ == "__main__":
main()

View File

@ -1,3 +1,5 @@
# ruff: noqa
import os
from collections.abc import Sequence from collections.abc import Sequence
from pathlib import Path from pathlib import Path
@ -17,7 +19,7 @@ def merge(
merged_content = "" merged_content = ""
for merge_file in files_to_merge: for merge_file in files_to_merge:
merged_content += merge_file.read_text() merged_content += merge_file.read_text()
merged_content += "\n" merged_content += os.linesep
output_file.write_text(merged_content) output_file.write_text(merged_content)

View File

@ -6,15 +6,15 @@
"@babel/preset-env": "^7.16.5", "@babel/preset-env": "^7.16.5",
"@popperjs/core": "^2.10.2", "@popperjs/core": "^2.10.2",
"autoprefixer": "^10.4.0", "autoprefixer": "^10.4.0",
"babel-loader": "^10.0.0", "babel-loader": "^9.1.2",
"bootstrap": "^5.2.3", "bootstrap": "^5.2.3",
"browser-sync": "^3.0.2", "browser-sync": "^3.0.2",
"css-loader": "^7.1.2", "css-loader": "^7.1.2",
"gulp-concat": "^2.6.1", "gulp-concat": "^2.6.1",
"concurrently": "^9.0.0", "concurrently": "^9.0.0",
"cssnano": "^7.0.0", "cssnano": "^7.0.0",
"gulp": "^5.0.0", "gulp": "^4.0.2",
"gulp-imagemin": "^9.1.0", "gulp-imagemin": "^7.1.0",
"gulp-plumber": "^1.2.1", "gulp-plumber": "^1.2.1",
"gulp-postcss": "^10.0.0", "gulp-postcss": "^10.0.0",
"gulp-rename": "^2.0.0", "gulp-rename": "^2.0.0",
@ -26,16 +26,16 @@
"postcss": "^8.3.11", "postcss": "^8.3.11",
"postcss-loader": "^8.0.0", "postcss-loader": "^8.0.0",
"postcss-preset-env": "^10.0.3", "postcss-preset-env": "^10.0.3",
"sass": "1.77.6", "sass": "^1.43.4",
"sass-loader": "^16.0.1", "sass-loader": "^16.0.1",
"webpack": "^5.82.0", "webpack": "^5.65.0",
"webpack-bundle-tracker": "^3.0.1", "webpack-bundle-tracker": "^3.0.1",
"webpack-cli": "^6.0.1", "webpack-cli": "^5.0.1",
"webpack-dev-server": "^5.0.2", "webpack-dev-server": "^5.0.2",
"webpack-merge": "^6.0.1" "webpack-merge": "^6.0.1"
}, },
"engines": { "engines": {
"node": "22.14" "node": "22"
}, },
"browserslist": [ "browserslist": [
"last 2 versions" "last 2 versions"

View File

@ -106,7 +106,7 @@ select = [
"SLOT", "SLOT",
"SIM", "SIM",
"TID", "TID",
"TC", "TCH",
"INT", "INT",
# "ARG", # Unused function argument # "ARG", # Unused function argument
"PTH", "PTH",
@ -135,7 +135,7 @@ ignore = [
# The fixes in extend-unsafe-fixes will require # The fixes in extend-unsafe-fixes will require
# provide the `--unsafe-fixes` flag when fixing. # provide the `--unsafe-fixes` flag when fixing.
extend-unsafe-fixes = [ extend-unsafe-fixes = [
"UP038", "UP038",
] ]
[tool.ruff.lint.isort] [tool.ruff.lint.isort]

View File

@ -1,5 +1,5 @@
python-slugify==8.0.4 # https://github.com/un33k/python-slugify python-slugify==8.0.4 # https://github.com/un33k/python-slugify
Pillow==11.1.0 # pyup: != 11.2.0 # https://github.com/python-pillow/Pillow Pillow==10.4.0 # https://github.com/python-pillow/Pillow
{%- if cookiecutter.frontend_pipeline == 'Django Compressor' %} {%- if cookiecutter.frontend_pipeline == 'Django Compressor' %}
{%- if cookiecutter.windows == 'y' and cookiecutter.use_docker == 'n' %} {%- if cookiecutter.windows == 'y' and cookiecutter.use_docker == 'n' %}
rcssmin==1.1.2 --install-option="--without-c-extensions" # https://github.com/ndparker/rcssmin rcssmin==1.1.2 --install-option="--without-c-extensions" # https://github.com/ndparker/rcssmin
@ -9,42 +9,42 @@ rcssmin==1.1.2 # https://github.com/ndparker/rcssmin
{%- endif %} {%- endif %}
argon2-cffi==23.1.0 # https://github.com/hynek/argon2_cffi argon2-cffi==23.1.0 # https://github.com/hynek/argon2_cffi
{%- if cookiecutter.use_whitenoise == 'y' %} {%- if cookiecutter.use_whitenoise == 'y' %}
whitenoise==6.9.0 # https://github.com/evansd/whitenoise whitenoise==6.7.0 # https://github.com/evansd/whitenoise
{%- endif %} {%- endif %}
redis==5.2.1 # https://github.com/redis/redis-py redis==5.1.1 # https://github.com/redis/redis-py
{%- if cookiecutter.use_docker == "y" or cookiecutter.windows == "n" %} {%- if cookiecutter.use_docker == "y" or cookiecutter.windows == "n" %}
hiredis==3.1.0 # https://github.com/redis/hiredis-py hiredis==3.0.0 # https://github.com/redis/hiredis-py
{%- endif %} {%- endif %}
{%- if cookiecutter.use_celery == "y" %} {%- if cookiecutter.use_celery == "y" %}
celery==5.5.0 # pyup: < 6.0 # https://github.com/celery/celery celery==5.4.0 # pyup: < 6.0 # https://github.com/celery/celery
django-celery-beat==2.7.0 # https://github.com/celery/django-celery-beat django-celery-beat==2.7.0 # https://github.com/celery/django-celery-beat
{%- if cookiecutter.use_docker == 'y' %} {%- if cookiecutter.use_docker == 'y' %}
flower==2.0.1 # https://github.com/mher/flower flower==2.0.1 # https://github.com/mher/flower
{%- endif %} {%- endif %}
{%- endif %} {%- endif %}
{%- if cookiecutter.use_async == 'y' %} {%- if cookiecutter.use_async == 'y' %}
uvicorn[standard]==0.34.0 # https://github.com/encode/uvicorn uvicorn[standard]==0.31.0 # https://github.com/encode/uvicorn
uvicorn-worker==0.3.0 # https://github.com/Kludex/uvicorn-worker uvicorn-worker==0.2.0 # https://github.com/Kludex/uvicorn-worker
{%- endif %} {%- endif %}
# Django # Django
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
django==5.1.8 # pyup: < 5.2 # https://www.djangoproject.com/ django==5.0.9 # pyup: < 5.1 # https://www.djangoproject.com/
django-environ==0.12.0 # https://github.com/joke2k/django-environ django-environ==0.11.2 # https://github.com/joke2k/django-environ
django-model-utils==5.0.0 # https://github.com/jazzband/django-model-utils django-model-utils==5.0.0 # https://github.com/jazzband/django-model-utils
django-allauth[mfa]==65.7.0 # https://github.com/pennersr/django-allauth django-allauth[mfa]==65.0.2 # https://github.com/pennersr/django-allauth
django-crispy-forms==2.3 # https://github.com/django-crispy-forms/django-crispy-forms django-crispy-forms==2.3 # https://github.com/django-crispy-forms/django-crispy-forms
crispy-bootstrap5==2025.4 # https://github.com/django-crispy-forms/crispy-bootstrap5 crispy-bootstrap5==2024.10 # https://github.com/django-crispy-forms/crispy-bootstrap5
{%- if cookiecutter.frontend_pipeline == 'Django Compressor' %} {%- if cookiecutter.frontend_pipeline == 'Django Compressor' %}
django-compressor==4.5.1 # https://github.com/django-compressor/django-compressor django-compressor==4.5.1 # https://github.com/django-compressor/django-compressor
{%- endif %} {%- endif %}
django-redis==5.4.0 # https://github.com/jazzband/django-redis django-redis==5.4.0 # https://github.com/jazzband/django-redis
{%- if cookiecutter.use_drf == 'y' %} {%- if cookiecutter.use_drf == 'y' %}
# Django REST Framework # Django REST Framework
djangorestframework==3.16.0 # https://github.com/encode/django-rest-framework djangorestframework==3.15.2 # https://github.com/encode/django-rest-framework
django-cors-headers==4.7.0 # https://github.com/adamchainz/django-cors-headers django-cors-headers==4.4.0 # https://github.com/adamchainz/django-cors-headers
# DRF-spectacular for api documentation # DRF-spectacular for api documentation
drf-spectacular==0.28.0 # https://github.com/tfranzel/drf-spectacular drf-spectacular==0.27.2 # https://github.com/tfranzel/drf-spectacular
{%- endif %} {%- endif %}
{%- if cookiecutter.frontend_pipeline == 'Webpack' %} {%- if cookiecutter.frontend_pipeline == 'Webpack' %}
django-webpack-loader==3.1.1 # https://github.com/django-webpack/django-webpack-loader django-webpack-loader==3.1.1 # https://github.com/django-webpack/django-webpack-loader

View File

@ -1,43 +1,44 @@
-r production.txt -r production.txt
Werkzeug[watchdog]==3.1.3 # https://github.com/pallets/werkzeug watchdog==4.0.2 # https://github.com/gorakhargosh/watchdog
Werkzeug[watchdog]==3.0.4 # https://github.com/pallets/werkzeug
ipdb==0.13.13 # https://github.com/gotcha/ipdb ipdb==0.13.13 # https://github.com/gotcha/ipdb
{%- if cookiecutter.use_docker == 'y' %} {%- if cookiecutter.use_docker == 'y' %}
psycopg[c]==3.2.6 # https://github.com/psycopg/psycopg psycopg[c]==3.2.3 # https://github.com/psycopg/psycopg
{%- else %} {%- else %}
psycopg[binary]==3.2.6 # https://github.com/psycopg/psycopg psycopg[binary]==3.2.3 # https://github.com/psycopg/psycopg
{%- endif %} {%- endif %}
{%- if cookiecutter.use_async == 'y' or cookiecutter.use_celery == 'y' %} {%- if cookiecutter.use_async == 'y' or cookiecutter.use_celery == 'y' %}
watchfiles==1.0.4 # https://github.com/samuelcolvin/watchfiles watchfiles==0.24.0 # https://github.com/samuelcolvin/watchfiles
{%- endif %} {%- endif %}
# Testing # Testing
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
mypy==1.15.0 # https://github.com/python/mypy mypy==1.11.2 # https://github.com/python/mypy
django-stubs[compatible-mypy]==5.1.3 # https://github.com/typeddjango/django-stubs django-stubs[compatible-mypy]==5.1.0 # https://github.com/typeddjango/django-stubs
pytest==8.3.5 # https://github.com/pytest-dev/pytest pytest==8.3.3 # https://github.com/pytest-dev/pytest
pytest-sugar==1.0.0 # https://github.com/Teemu/pytest-sugar pytest-sugar==1.0.0 # https://github.com/Frozenball/pytest-sugar
{%- if cookiecutter.use_drf == "y" %} {%- if cookiecutter.use_drf == "y" %}
djangorestframework-stubs==3.15.3 # https://github.com/typeddjango/djangorestframework-stubs djangorestframework-stubs==3.15.1 # https://github.com/typeddjango/djangorestframework-stubs
{%- endif %} {%- endif %}
# Documentation # Documentation
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
sphinx==8.2.3 # pyup: != 8.3.0 # https://github.com/sphinx-doc/sphinx sphinx==8.0.2 # https://github.com/sphinx-doc/sphinx
sphinx-autobuild==2024.10.3 # https://github.com/GaretJax/sphinx-autobuild sphinx-autobuild==2024.10.3 # https://github.com/GaretJax/sphinx-autobuild
# Code quality # Code quality
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
ruff==0.11.4 # https://github.com/astral-sh/ruff ruff==0.6.9 # https://github.com/astral-sh/ruff
coverage==7.8.0 # https://github.com/nedbat/coveragepy coverage==7.6.2 # https://github.com/nedbat/coveragepy
djlint==1.36.4 # https://github.com/Riverside-Healthcare/djLint djlint==1.35.2 # https://github.com/Riverside-Healthcare/djLint
pre-commit==4.2.0 # https://github.com/pre-commit/pre-commit pre-commit==4.0.1 # https://github.com/pre-commit/pre-commit
# Django # Django
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
factory-boy==3.3.2 # https://github.com/FactoryBoy/factory_boy factory-boy==3.3.1 # https://github.com/FactoryBoy/factory_boy
django-debug-toolbar==5.1.0 # https://github.com/jazzband/django-debug-toolbar django-debug-toolbar==4.4.6 # https://github.com/jazzband/django-debug-toolbar
django-extensions==4.0 # https://github.com/django-extensions/django-extensions django-extensions==3.2.3 # https://github.com/django-extensions/django-extensions
django-coverage-plugin==3.1.0 # https://github.com/nedbat/django_coverage_plugin django-coverage-plugin==3.1.0 # https://github.com/nedbat/django_coverage_plugin
pytest-django==4.11.1 # https://github.com/pytest-dev/pytest-django pytest-django==4.9.0 # https://github.com/pytest-dev/pytest-django

View File

@ -3,42 +3,42 @@
-r base.txt -r base.txt
gunicorn==23.0.0 # https://github.com/benoitc/gunicorn gunicorn==23.0.0 # https://github.com/benoitc/gunicorn
psycopg[c]==3.2.6 # https://github.com/psycopg/psycopg psycopg[c]==3.2.3 # https://github.com/psycopg/psycopg
{%- if cookiecutter.use_whitenoise == 'n'and cookiecutter.cloud_provider in ('AWS', 'GCP') %} {%- if cookiecutter.use_whitenoise == 'n' %}
Collectfasta==3.2.1 # https://github.com/jasongi/collectfasta Collectfasta==3.2.0 # https://github.com/jasongi/collectfasta
{%- endif %} {%- endif %}
{%- if cookiecutter.use_sentry == "y" %} {%- if cookiecutter.use_sentry == "y" %}
sentry-sdk==2.25.1 # https://github.com/getsentry/sentry-python sentry-sdk==2.16.0 # https://github.com/getsentry/sentry-python
{%- endif %} {%- endif %}
{%- if cookiecutter.use_docker == "n" and cookiecutter.windows == "y" %} {%- if cookiecutter.use_docker == "n" and cookiecutter.windows == "y" %}
hiredis==3.1.0 # https://github.com/redis/hiredis-py hiredis==3.0.0 # https://github.com/redis/hiredis-py
{%- endif %} {%- endif %}
# Django # Django
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
{%- if cookiecutter.cloud_provider == 'AWS' %} {%- if cookiecutter.cloud_provider == 'AWS' %}
django-storages[s3]==1.14.6 # https://github.com/jschneier/django-storages django-storages[s3]==1.14.4 # https://github.com/jschneier/django-storages
{%- elif cookiecutter.cloud_provider == 'GCP' %} {%- elif cookiecutter.cloud_provider == 'GCP' %}
django-storages[google]==1.14.6 # https://github.com/jschneier/django-storages django-storages[google]==1.14.4 # https://github.com/jschneier/django-storages
{%- elif cookiecutter.cloud_provider == 'Azure' %} {%- elif cookiecutter.cloud_provider == 'Azure' %}
django-storages[azure]==1.14.6 # https://github.com/jschneier/django-storages django-storages[azure]==1.14.4 # https://github.com/jschneier/django-storages
{%- endif %} {%- endif %}
{%- if cookiecutter.mail_service == 'Mailgun' %} {%- if cookiecutter.mail_service == 'Mailgun' %}
django-anymail[mailgun]==13.0 # https://github.com/anymail/django-anymail django-anymail[mailgun]==12.0 # https://github.com/anymail/django-anymail
{%- elif cookiecutter.mail_service == 'Amazon SES' %} {%- elif cookiecutter.mail_service == 'Amazon SES' %}
django-anymail[amazon-ses]==13.0 # https://github.com/anymail/django-anymail django-anymail[amazon-ses]==12.0 # https://github.com/anymail/django-anymail
{%- elif cookiecutter.mail_service == 'Mailjet' %} {%- elif cookiecutter.mail_service == 'Mailjet' %}
django-anymail[mailjet]==13.0 # https://github.com/anymail/django-anymail django-anymail[mailjet]==12.0 # https://github.com/anymail/django-anymail
{%- elif cookiecutter.mail_service == 'Mandrill' %} {%- elif cookiecutter.mail_service == 'Mandrill' %}
django-anymail[mandrill]==13.0 # https://github.com/anymail/django-anymail django-anymail[mandrill]==12.0 # https://github.com/anymail/django-anymail
{%- elif cookiecutter.mail_service == 'Postmark' %} {%- elif cookiecutter.mail_service == 'Postmark' %}
django-anymail[postmark]==13.0 # https://github.com/anymail/django-anymail django-anymail[postmark]==12.0 # https://github.com/anymail/django-anymail
{%- elif cookiecutter.mail_service == 'Sendgrid' %} {%- elif cookiecutter.mail_service == 'Sendgrid' %}
django-anymail[sendgrid]==13.0 # https://github.com/anymail/django-anymail django-anymail[sendgrid]==12.0 # https://github.com/anymail/django-anymail
{%- elif cookiecutter.mail_service == 'Brevo' %} {%- elif cookiecutter.mail_service == 'Brevo' %}
django-anymail[brevo]==13.0 # https://github.com/anymail/django-anymail django-anymail[brevo]==12.0 # https://github.com/anymail/django-anymail
{%- elif cookiecutter.mail_service == 'SparkPost' %} {%- elif cookiecutter.mail_service == 'SparkPost' %}
django-anymail[sparkpost]==13.0 # https://github.com/anymail/django-anymail django-anymail[sparkpost]==12.0 # https://github.com/anymail/django-anymail
{%- elif cookiecutter.mail_service == 'Other SMTP' %} {%- elif cookiecutter.mail_service == 'Other SMTP' %}
django-anymail==13.0 # https://github.com/anymail/django-anymail django-anymail==12.0 # https://github.com/anymail/django-anymail
{%- endif %} {%- endif %}

View File

@ -0,0 +1 @@
python-3.12.7

View File

@ -1,23 +0,0 @@
##basic build dependencies of various Django apps for Debian Bookworm 12.x
#build-essential metapackage install: make, gcc, g++,
build-essential
#required to translate
gettext
python3-dev
##shared dependencies of:
##Pillow, pylibmc
zlib1g-dev
##Postgresql and psycopg dependencies
libpq-dev
##Pillow dependencies
libtiff5-dev
libjpeg62-turbo-dev
libfreetype6-dev
liblcms2-dev
libwebp-dev
##django-extensions
libgraphviz-dev

View File

@ -1,5 +1,5 @@
""" """
To understand why this file is here, please read: To understand why this file is here, please read:
https://cookiecutter-django.readthedocs.io/en/latest/5-help/faq.html#why-is-there-a-django-contrib-sites-directory-in-cookiecutter-django http://cookiecutter-django.readthedocs.io/en/latest/faq.html#why-is-there-a-django-contrib-sites-directory-in-cookiecutter-django
""" """

View File

@ -1,5 +1,5 @@
""" """
To understand why this file is here, please read: To understand why this file is here, please read:
https://cookiecutter-django.readthedocs.io/en/latest/5-help/faq.html#why-is-there-a-django-contrib-sites-directory-in-cookiecutter-django http://cookiecutter-django.readthedocs.io/en/latest/faq.html#why-is-there-a-django-contrib-sites-directory-in-cookiecutter-django
""" """

View File

@ -1,7 +1,7 @@
""" """
To understand why this file is here, please read: To understand why this file is here, please read:
https://cookiecutter-django.readthedocs.io/en/latest/5-help/faq.html#why-is-there-a-django-contrib-sites-directory-in-cookiecutter-django http://cookiecutter-django.readthedocs.io/en/latest/faq.html#why-is-there-a-django-contrib-sites-directory-in-cookiecutter-django
""" """
from django.conf import settings from django.conf import settings
from django.db import migrations from django.db import migrations

View File

@ -1,5 +1,5 @@
""" """
To understand why this file is here, please read: To understand why this file is here, please read:
https://cookiecutter-django.readthedocs.io/en/latest/5-help/faq.html#why-is-there-a-django-contrib-sites-directory-in-cookiecutter-django http://cookiecutter-django.readthedocs.io/en/latest/faq.html#why-is-there-a-django-contrib-sites-directory-in-cookiecutter-django
""" """

View File

@ -17,7 +17,7 @@ class UserAdminChangeForm(admin_forms.UserChangeForm):
{%- endif %} {%- endif %}
class UserAdminCreationForm(admin_forms.AdminUserCreationForm): # type: ignore[name-defined] # django-stubs is missing the class, thats why the error is thrown: typeddjango/django-stubs#2555 class UserAdminCreationForm(admin_forms.UserCreationForm):
""" """
Form for User Creation in the Admin Area. Form for User Creation in the Admin Area.
To change user signup, see UserSignupForm and UserSocialSignupForm. To change user signup, see UserSignupForm and UserSocialSignupForm.

View File

@ -4,14 +4,14 @@ import pytest
from django.urls import reverse from django.urls import reverse
def test_api_docs_accessible_by_admin(admin_client): def test_swagger_accessible_by_admin(admin_client):
url = reverse("api-docs") url = reverse("api-docs")
response = admin_client.get(url) response = admin_client.get(url)
assert response.status_code == HTTPStatus.OK assert response.status_code == HTTPStatus.OK
@pytest.mark.django_db @pytest.mark.django_db
def test_api_docs_not_accessible_by_anonymous_users(client): def test_swagger_ui_not_accessible_by_normal_user(client):
url = reverse("api-docs") url = reverse("api-docs")
response = client.get(url) response = client.get(url)
assert response.status_code == HTTPStatus.FORBIDDEN assert response.status_code == HTTPStatus.FORBIDDEN