diff --git a/.copier-answers.resonant.yml b/.copier-answers.resonant.yml index e4bb3e43..408540a9 100644 --- a/.copier-answers.resonant.yml +++ b/.copier-answers.resonant.yml @@ -1,4 +1,4 @@ -_commit: v0.48.1 +_commit: v0.50.3 _src_path: https://github.com/kitware-resonant/cookiecutter-resonant core_app_name: core include_example_code: false diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 00000000..1a9382e2 --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,93 @@ +// For format details, see https://aka.ms/devcontainer.json. For config options, see the +// README at: https://github.com/devcontainers/templates/tree/main/src/docker-existing-docker-compose +{ + "name": "bats-ai", + "dockerComposeFile": [ + "../docker-compose.yml", + "../docker-compose.override.yml", + "./docker-compose.devcontainer.yml" + ], + "service": "django", + "overrideCommand": true, + // The "vscode" user and remoteUser are set by the base image label (devcontainers/base). + "workspaceFolder": "/home/vscode/bats-ai", + "features": { + "ghcr.io/devcontainers/features/git-lfs:1": {}, + "ghcr.io/devcontainers/features/node:1": {}, + "ghcr.io/rails/devcontainer/features/postgres-client:1": { + "version": 18 + }, + "ghcr.io/devcontainers/features/terraform:1": {}, + "ghcr.io/devcontainers/features/aws-cli:1": {}, + "ghcr.io/devcontainers/features/github-cli:1": {}, + "ghcr.io/devcontainers-extra/features/heroku-cli:1": {} + }, + "customizations": { + "vscode": { + "extensions": [ + // Python + "ms-python.python", + "ms-python.vscode-pylance", + "ms-python.debugpy", + "ms-python.mypy-type-checker", + "charliermarsh.ruff", + // Django + "batisteo.vscode-django", + "augustocdias.tasks-shell-input", + // Other file formats + "editorconfig.editorconfig", + "mikestead.dotenv", + "tamasfe.even-better-toml", + "timonwong.shellcheck", + // Infrastructure + "ms-azuretools.vscode-containers", + "hashicorp.terraform", + "github.vscode-github-actions", + // Remove AWS extension, as only the CLI is wanted; see: https://github.com/devcontainers/features/issues/1228 + "-AmazonWebServices.aws-toolkit-vscode" + ], + "settings": { + "containers.containerClient": "com.microsoft.visualstudio.containers.docker", + // Container-specific Python paths + "python.defaultInterpreterPath": "/home/vscode/venv/bin/python", + // Ensure that `envFile` from any user settings is ignored; Docker Compose provides it. + "python.envFile": "", + // Reduce file watcher overhead for generated/cache directories. + "files.watcherExclude": { + "**/__pycache__/**": true, + "**/.pytest_cache/**": true, + "**/node_modules/**": true + } + } + } + }, + // Prevent a prompt every time the debugger opens a port or Django auto-restarts. + "otherPortsAttributes": { + "onAutoForward": "silent" + }, + "portsAttributes": { + "8000": { + "label": "Django", + // Show a dialog if the port isn't free. + "requireLocalPort": true, + "onAutoForward": "silent" + }, + "8080": { + "label": "Vite", + "requireLocalPort": true, + "onAutoForward": "silent" + } + }, + // Install a global Python and create a venv before VSCode extensions start, + // to prevent prompts and ensure test discovery works on first load. + "onCreateCommand": { + "python": ["uv", "python", "install", "--default"], + "venv": ["uv", "sync", "--all-extras", "--all-groups"], + "npm": ["npm", "--prefix", "client", "install"] + }, + // Ensure it is re-synced on restarts. + "updateContentCommand": { + "venv": ["uv", "sync", "--all-extras", "--all-groups"], + "npm": ["npm", "--prefix", "client", "install"] + } +} diff --git a/.devcontainer/docker-compose.devcontainer.yml b/.devcontainer/docker-compose.devcontainer.yml new file mode 100644 index 00000000..3189ee29 --- /dev/null +++ b/.devcontainer/docker-compose.devcontainer.yml @@ -0,0 +1,14 @@ +services: + django: + # Don't expose ports, devcontainer forwarding is superior, since we can just bind to localhost. + ports: !reset [] + # Don't auto-run the default command, launch.json or the terminal will be used. + command: !reset [] + + celery: + # Celery will be started via launch.json or the terminal. + profiles: ["celery"] + + client: + # npm will be started via launch.json or the terminal. + profiles: ["client"] diff --git a/.editorconfig b/.editorconfig index 781569b5..e6c9576e 100644 --- a/.editorconfig +++ b/.editorconfig @@ -27,12 +27,11 @@ indent_size = 2 indent_size = 4 max_line_length = 100 -[*.toml] +[*.sh] indent_size = 2 -[*.{yml,yaml}] +[*.toml] indent_size = 2 -[*.{js,jsx,ts,tsx,vue}] +[*.{yml,yaml}] indent_size = 2 -max_line_length = 100 diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yml similarity index 89% rename from .github/workflows/ci.yaml rename to .github/workflows/ci.yml index f6978f74..3e4ddd99 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yml @@ -1,11 +1,9 @@ name: CI on: pull_request: - # types: [opened, synchronize] - # TODO: why is this here? push: branches: - - "main" + - main permissions: contents: read jobs: @@ -15,7 +13,7 @@ jobs: matrix: linter: [eslint, typescript] name: Lint [${{ matrix.linter }}] - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 steps: - name: Checkout repository uses: actions/checkout@v6 @@ -32,7 +30,7 @@ jobs: working-directory: client test-python: name: Test Python - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 services: postgres: image: postgis/postgis:latest @@ -55,7 +53,7 @@ jobs: - 5672:5672 minio: # This image does not require any command arguments (which GitHub Actions don't support) - image: bitnamilegacy/minio:2025.7.23 + image: bitnamilegacy/minio:latest env: MINIO_ROOT_USER: minioAccessKey MINIO_ROOT_PASSWORD: minioSecretKey @@ -66,16 +64,15 @@ jobs: --health-start-interval 2s ports: - 9000:9000 - steps: - name: Checkout repository uses: actions/checkout@v6 - name: Install uv uses: astral-sh/setup-uv@v7 - - name: Run tests - run: uv run tox + run: | + uv run tox env: DJANGO_DATABASE_URL: postgres://postgres:postgres@localhost:5432/django DJANGO_CELERY_BROKER_URL: amqp://localhost:5672/ - DJANGO_MINIO_STORAGE_URL: http://minioAccessKey:minioSecretKey@localhost:9000/django-storage-testing + DJANGO_MINIO_STORAGE_URL: http://minioAccessKey:minioSecretKey@localhost:9000/django-storage diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 00000000..c1357687 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,95 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "name": "Django: Server", + "type": "debugpy", + "request": "launch", + "program": "${workspaceFolder}/manage.py", + "args": ["runserver_plus", "--print-sql", "localhost:8000"], + "django": true, + "console": "integratedTerminal" + }, + { + "name": "Django: Server (eager Celery)", + "type": "debugpy", + "request": "launch", + "program": "${workspaceFolder}/manage.py", + "args": ["runserver_plus", "--print-sql", "localhost:8000"], + "env": { + "DJANGO_CELERY_TASK_ALWAYS_EAGER": "true" + }, + "django": true, + "console": "integratedTerminal" + }, + { + "name": "Django: Management Command", + "type": "debugpy", + "request": "launch", + "program": "${workspaceFolder}/manage.py", + "args": ["${input:managementCommand}"], + "django": true, + "console": "integratedTerminal" + }, + { + "name": "Celery: Worker", + "type": "debugpy", + "request": "launch", + "module": "celery", + "args": [ + "--app", + "bats_ai.celery", + "worker", + "--loglevel", + "INFO", + "--pool", + "solo", + "--without-heartbeat" + ], + "console": "integratedTerminal", + "justMyCode": false + }, + { + "name": "Pytest: Debug", + "type": "debugpy", + "request": "launch", + "purpose": ["debug-test"], + "console": "integratedTerminal", + "django": true, + "justMyCode": false + }, + { + "name": "Vite: Dev Server", + "type": "node", + "request": "launch", + "cwd": "${workspaceFolder}/client", + "runtimeExecutable": "npm", + "runtimeArgs": ["run", "dev"], + "console": "integratedTerminal" + } + ], + "compounds": [ + { + "name": "Django + Celery", + "configurations": ["Django: Server", "Celery: Worker"], + "stopAll": true + }, + { + "name": "Django + Celery + Vite", + "configurations": ["Django: Server", "Celery: Worker", "Vite: Dev Server"], + "stopAll": true + } + ], + "inputs": [ + { + "id": "managementCommand", + "type": "command", + "command": "shellCommand.execute", + "args": { + "command": "./manage.py help --commands", + "description": "Django management command", + "allowCustomValues": true + } + } + ] +} diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 00000000..90cc42f9 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,37 @@ +{ + // File cleanup + "files.trimTrailingWhitespace": true, + "files.insertFinalNewline": true, + "files.trimFinalNewlines": true, + + // Python + "python.analysis.autoFormatStrings": true, + "python.testing.pytestEnabled": true, + "python.analysis.autoImportCompletions": true, + "python.analysis.gotoDefinitionInStringLiteral": true, + // Allow auto-importing from deeper symbols inside of Django. + "python.analysis.packageIndexDepths": [ + { + "name": "django", + "depth": 6 + } + ], + "python.analysis.inlayHints.pytestParameters": true, + + // Django templates + "emmet.includeLanguages": { + "django-html": "html" + }, + + // Type checking: Use Mypy and disable Pylance. + "mypy-type-checker.importStrategy": "fromEnvironment", + // Mypy daemon seems better, but is buggy in practice. + "mypy-type-checker.preferDaemon": false, + "mypy-type-checker.reportingScope": "file", + "python.analysis.typeCheckingMode": "off", + + // Ruff + "[python]": { + "editor.defaultFormatter": "charliermarsh.ruff" + } +} diff --git a/README.md b/README.md index 9b9b1969..e8f5cc34 100644 --- a/README.md +++ b/README.md @@ -1,74 +1,51 @@ # bats-ai -## Develop with Docker (recommended quickstart) - -This is the simplest configuration for developers to start with. - -### Initial Setup - -1. Run `docker compose run --rm django ./manage.py migrate` -2. Run `docker compose run --rm django ./manage.py createsuperuser` - and follow the prompts to create your own user -3. Run `docker compose run --rm django ./manage.py loaddata species` to load species - data into the database - -### Run Vue Frontend - -1. Run `cd client/` -2. Run `npm install` -3. Run `npm run dev` - -### Run Application - -1. Run `docker compose up` -2. Access the site, starting at -3. When finished, use `Ctrl+C` - -### Maintenance - -To non-destructively update your development stack at any time: - -1. Run `docker compose down` -2. Run `docker compose pull` -3. Run `docker compose build --pull` -4. Run `docker compose run --rm django ./manage.py migrate` +## Setup +1. Install [VS Code with dev container support](https://code.visualstudio.com/docs/devcontainers/containers#_installation). +1. Open the project in VS Code, then run `Dev Containers: Reopen in Container` + from the Command Palette (`Ctrl+Shift+P`). +1. Once the container is ready, open a terminal and run: + ```sh + ./manage.py migrate + ./manage.py createsuperuser + ./manage.py loaddata species + ``` + +## Run +Open the **Run and Debug** panel (`Ctrl+Shift+D`) and select a launch configuration: + +* **Django: Server** — Starts the development server at +* **Django: Server (eager Celery)** — Same, but Celery tasks run synchronously + in the web process (useful for debugging task code without a worker) +* **Celery: Worker** — Starts only the Celery worker +* **Django + Celery** — Starts both the server and a Celery worker +* **Django: Management Command** — Pick and run any management command +* **Vite: Dev Server** - Starts the frontend development server at +* **Django + Celery + Vite** - Starts the server, a Celery worker, and the frontend. + +## Test +Run the full test suite from a terminal: `tox` + +Auto-format code: `tox -e format` + +Run and debug individual tests from the **Testing** panel (`Ctrl+Shift+;`). + +## Rebuild +After changes to the Dockerfile, Docker Compose files, or `devcontainer.json`, +run `Dev Containers: Rebuild Container` from the Command Palette (`Ctrl+Shift+P`). + +For dependency changes in `pyproject.toml`, just run `uv sync --all-extras --all-groups`. ## Dev Tool Endpoints -1. Main Site Interface [http://localhost:8080/](http://localhost:8080/) -2. Site Administration [http://localhost:8000/admin/](http://localhost:8000/admin/) -3. Swagger API (These are default swagger endpoints using Django-REST) [http://localhost:8000/api/docs/swagger/](http://localhost:8000/api/docs/swagger/) -4. Django Ninja API [http://localhost:8000/api/v1/docs#/](http://localhost:8000/api/v1/docs#/) -5. MinIO (S3 local management) [http://localhost:9001/browser](http://localhost:9001/browser) +1. Main Site Interface +2. Site Administration +3. Swagger API (These are default swagger endpoints using Django-REST) +4. Django Ninja API +5. MinIO (S3 local management) Username: 'minioAccessKey' Password: 'minioSecretKey' -## Develop Natively (advanced) - -This configuration still uses Docker to run attached services in the background, -but allows developers to run Python code on their native system. - -### Initial Setup for Native Development - -1. Run `docker compose -f ./docker-compose.yml up -d` -2. [Install `uv`](https://docs.astral.sh/uv/getting-started/installation/) -3. Run `export UV_ENV_FILE=./dev/.env.docker-compose-native` -4. Run `./manage.py migrate` -5. Run `./manage.py createsuperuser` and follow the prompts to create your own user - -### Run Native Application - -1. Ensure `docker compose -f ./docker-compose.yml up -d` is still active -2. Run `export UV_ENV_FILE=./dev/.env.docker-compose-native` -3. Run: `./manage.py runserver_plus` -4. Run in a separate terminal: `uv run celery --app bats_ai.celery worker --loglevel INFO --without-heartbeat` -5. Run in a separate terminal: - 1. `source ./dev/export-env.sh` - 2. `cd ./client` - 3. `npm install` - 4. `npm run dev` -6. When finished, run `docker compose stop` - ## Importing Recordings The `importRecordings` management command allows you to bulk import WAV files from a @@ -84,14 +61,14 @@ directory. It will: **Basic usage with Docker Compose (with bind mount):** -```bash -docker compose run --rm -v /path/to/wav/files:/data django ./manage.py importRecordings /data +```sh +./manage.py importRecordings /data ``` **With options:** ```bash -docker compose run --rm -v /path/to/wav/files:/data django ./manage.py importRecordings /data \ +./manage.py importRecordings /data \ --owner username \ --public \ --limit 10 @@ -104,47 +81,6 @@ docker compose run --rm -v /path/to/wav/files:/data django ./manage.py importRec - `--public`: Make imported recordings public - `--limit N`: Limit the number of WAV files to import (useful for testing) -**Example with bind mount:** - -```bash -docker compose run --rm \ - -v /media/bryon.lewis/Elements/BATSAI/training_files:/data \ - django ./manage.py importRecordings /data --limit 5 -``` - -This will: - -1. Mount your host directory `/media/bryon.lewis/Elements/BATSAI/training_files` to `/data` in the container -2. Import only the first 5 WAV files found -3. Use the first superuser as the owner -4. Create private recordings (unless `--public` is specified) - -## Testing - -### Initial Setup for Testing - -tox is used to manage the execution of all tests. -[Install `uv`](https://docs.astral.sh/uv/getting-started/installation/) and run tox with -`uv run tox ...`. - -When running the "Develop with Docker" configuration, all tox commands must be run as -`docker compose run --rm django uv run tox`; extra arguments may also be appended to this form. - -### Running Tests - -Run `uv run tox` to launch the full test suite. - -Individual test environments may be selectively run. -This also allows additional options to be be added. -Useful sub-commands include: - -- `uv run tox -e lint`: Run only the style checks -- `uv run tox -e type`: Run only the type checks -- `uv run tox -e test`: Run only the pytest-driven tests - -To automatically reformat all code to comply with -some (but not all) of the style checks, run `uv run tox -e format`. - ## Code Formatting It's recommended that you use `pre-commit` to provide additional @@ -186,7 +122,7 @@ is preferred because once the commit is created locally, you will need to rebase or otherwise rewrite the commit to make adjustments if done after the fact. Lastly, the GitLab CI/CD infrastructure runs the same `pre-commit` configuration -on all pipelines for new MRs. The automated checks in GitLab are optional, but +on all pipelines for new MRs. The automated checks in GitLab are optional, but it is highly recommended to perform these checks locally prior to pushing new commits. diff --git a/bats_ai/core/views/export_annotation.py b/bats_ai/core/views/export_annotation.py index dece2fbe..2ebd0487 100644 --- a/bats_ai/core/views/export_annotation.py +++ b/bats_ai/core/views/export_annotation.py @@ -1,7 +1,7 @@ from __future__ import annotations +from datetime import datetime import logging -from typing import TYPE_CHECKING from django.http import JsonResponse from django.shortcuts import get_object_or_404 @@ -10,9 +10,6 @@ from bats_ai.core.models import ExportedAnnotationFile -if TYPE_CHECKING: - from datetime import datetime - logger = logging.getLogger(__name__) router = Router() diff --git a/dev/django.Dockerfile b/dev/django.Dockerfile index d94c6b59..f62c265c 100644 --- a/dev/django.Dockerfile +++ b/dev/django.Dockerfile @@ -1,13 +1,33 @@ -FROM ghcr.io/astral-sh/uv:debian - -# Make Python more friendly to running in containers -ENV PYTHONDONTWRITEBYTECODE=1 \ - PYTHONUNBUFFERED=1 - -# Make uv install content in well-known locations -ENV UV_PROJECT_ENVIRONMENT=/var/lib/venv \ - UV_CACHE_DIR=/var/cache/uv/cache \ - UV_PYTHON_INSTALL_DIR=/var/cache/uv/bin \ - # The uv cache and environment are expected to be mounted on different volumes, - # so hardlinks won't work - UV_LINK_MODE=symlink +FROM mcr.microsoft.com/devcontainers/base:ubuntu-24.04 + +COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /usr/local/bin/ + +# Ensure Python output appears immediately in container logs. +ENV PYTHONUNBUFFERED=1 + +# Put the uv and npm caches in a separate location, +# where they can persist and be shared across containers. +# The uv cache and virtual environment are on different volumes, so hardlinks won't work. +ENV UV_CACHE_DIR=/home/vscode/pkg-cache/uv \ + UV_PYTHON_INSTALL_DIR=/home/vscode/pkg-cache/uv-python \ + UV_LINK_MODE=symlink \ + NPM_CONFIG_CACHE=/home/vscode/pkg-cache/npm + +# Put the virtual environment outside the project directory, +# to improve performance on macOS and prevent accidental usage from the host machine. +# Activate it, so `uv run` doesn't need to be prefixed. +ENV UV_PROJECT_ENVIRONMENT=/home/vscode/venv \ + PATH="/home/vscode/venv/bin:$PATH" + +# Put tool scratch files outside the project directory too. +ENV TOX_WORK_DIR=/home/vscode/tox \ + RUFF_CACHE_DIR=/home/vscode/.cache/ruff \ + MYPY_CACHE_DIR=/home/vscode/.cache/mypy + +RUN ["chsh", "-s", "/usr/bin/zsh", "vscode"] + +USER vscode + +# Pre-create named volume mount points, so the new volume inherits `vscode` user ownership: +# https://docs.docker.com/engine/storage/volumes/#populate-a-volume-using-a-container +RUN ["mkdir", "/home/vscode/pkg-cache"] diff --git a/dev/docker-development.md b/dev/docker-development.md new file mode 100644 index 00000000..a5faba3c --- /dev/null +++ b/dev/docker-development.md @@ -0,0 +1,23 @@ +# Docker Compose Development (without VS Code) + +An alternative to the recommended [dev container](../README.md) workflow. + +## Setup +1. `docker compose run --rm django ./manage.py migrate` +1. `docker compose run --rm django ./manage.py createsuperuser` + +## Run +1. `docker compose up` +1. Access http://localhost:8000/ +1. `Ctrl+C` to stop + +To include the Celery worker: `docker compose --profile celery up` + +## Update +1. `docker compose down` +1. `docker compose pull` +1. `docker compose build --pull` +1. `docker compose run --rm django ./manage.py migrate` + +## Reset +Remove all data and volumes: `docker compose down -v` diff --git a/dev/export-env.sh b/dev/export-env.sh index 6ffbebaf..4ea1678e 100644 --- a/dev/export-env.sh +++ b/dev/export-env.sh @@ -1,26 +1,28 @@ +# shellcheck shell=bash # Export environment variables from the .env file in the first argument. # If no argument is given, default to "dev/.env.docker-compose-native". # This file must be sourced, not run. if [ -n "$1" ]; then - # If an argument was provided, use it as the .env file - _dotenv_file="$1" + # If an argument was provided, use it as the .env file + _dotenv_file="$1" else - # Otherwise, use the default .env file - if [ -n "$ZSH_VERSION" ]; then - # ZSH has a different way to get the directory of the current script - _dotenv_dir="$0:A:h" - else - # Assume this is Bash - _dotenv_dir="$( dirname "${BASH_SOURCE[0]}" )" - fi - _dotenv_file="${_dotenv_dir}/.env.docker-compose-native" + # Otherwise, use the default .env file + if [ -n "$ZSH_VERSION" ]; then + # ZSH has a different way to get the directory of the current script + _dotenv_dir="$0:A:h" + else + # Assume this is Bash + _dotenv_dir="$( dirname "${BASH_SOURCE[0]}" )" + fi + _dotenv_file="${_dotenv_dir}/.env.docker-compose-native" fi # Export all assignments in the $_dotenv_file # Using "set -a" allows .env files with spaces or comments to work seamlessly # https://stackoverflow.com/a/45971167 set -a +# shellcheck source=.env.docker-compose-native . "$_dotenv_file" set +a diff --git a/dev/native-development.md b/dev/native-development.md new file mode 100644 index 00000000..4f122bb7 --- /dev/null +++ b/dev/native-development.md @@ -0,0 +1,19 @@ +# Native Development (advanced) + +Runs Python on the host while using Docker Compose for services. + +## Setup +1. [Install `uv`](https://docs.astral.sh/uv/getting-started/installation/) +1. Start services: `docker compose -f ./docker-compose.yml up -d` +1. Load environment: `source ./dev/export-env.sh` +1. `./manage.py migrate` +1. `./manage.py createsuperuser` + +## Run +1. Ensure services are running: `docker compose -f ./docker-compose.yml up -d` +1. `source ./dev/export-env.sh` +1. `./manage.py runserver_plus` +1. In a separate terminal: `celery --app bats_ai.celery worker --loglevel INFO --without-heartbeat` +1. Access http://localhost:8000/ + +Stop services when done: `docker compose stop` diff --git a/docker-compose.override.yml b/docker-compose.override.yml index 54d2721c..261610f7 100644 --- a/docker-compose.override.yml +++ b/docker-compose.override.yml @@ -9,12 +9,11 @@ services: ] # Log printing is enhanced by a TTY tty: true - environment: - UV_ENV_FILE: ./dev/.env.docker-compose - working_dir: /opt/django-project + working_dir: /home/vscode/bats-ai + env_file: ./dev/.env.docker-compose volumes: - - .:/opt/django-project - - uv_cache:/var/cache/uv + - .:/home/vscode/bats-ai + - pkg_cache:/home/vscode/pkg-cache ports: - 8000:8000 depends_on: @@ -38,14 +37,13 @@ services: "--loglevel", "INFO", "--without-heartbeat" ] - # Docker Compose does not set the TTY width, which causes Celery errors + # uv progress doesn't display properly with a Docker TTY tty: false - environment: - UV_ENV_FILE: ./dev/.env.docker-compose - working_dir: /opt/django-project + working_dir: /home/vscode/bats-ai + env_file: ./dev/.env.docker-compose volumes: - - .:/opt/django-project - - uv_cache:/var/cache/uv + - .:/home/vscode/bats-ai + - pkg_cache:/home/vscode/pkg-cache depends_on: postgres: condition: service_healthy @@ -71,4 +69,4 @@ services: - ./dev/.env.docker-compose volumes: - uv_cache: + pkg_cache: diff --git a/pyproject.toml b/pyproject.toml index 838d780c..b7e76c9b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -20,7 +20,7 @@ dependencies = [ "django-environ==0.13.0", "django-extensions==4.1", "django-oauth-toolkit==3.2.0", - "django-resonant-settings[allauth,celery]==0.48.1", + "django-resonant-settings[allauth,celery]==0.50.3", "django-resonant-utils[allauth,s3_storage]==0.19.0", "django-s3-file-field[s3]==1.1.0", "django-storages[s3]==1.14.6", @@ -207,6 +207,10 @@ extend-immutable-calls = ["ninja.Query"] [tool.ruff.lint.flake8-self] extend-ignore-names = ["_base_manager", "_default_manager", "_meta"] +[tool.ruff.lint.flake8-type-checking] +runtime-evaluated-base-classes = ["pydantic.BaseModel"] +runtime-evaluated-decorators = ["pydantic.validate_call"] + [tool.ruff.lint.isort] # Sort by name, don't cluster "from" vs "import" force-sort-within-sections = true diff --git a/tox.ini b/tox.ini index b1108c43..9fedc806 100644 --- a/tox.ini +++ b/tox.ini @@ -12,6 +12,8 @@ env_list = runner = uv-venv-lock-runner pass_env = DJANGO_* + RUFF_CACHE_DIR + MYPY_CACHE_DIR extras = development diff --git a/uv.lock b/uv.lock index bf6155c5..fe0cc974 100644 --- a/uv.lock +++ b/uv.lock @@ -305,7 +305,7 @@ requires-dist = [ { name = "django-minio-storage", marker = "extra == 'development'", specifier = "==0.5.9" }, { name = "django-ninja", specifier = "==1.6.2" }, { name = "django-oauth-toolkit", specifier = "==3.2.0" }, - { name = "django-resonant-settings", extras = ["allauth", "celery"], specifier = "==0.48.1" }, + { name = "django-resonant-settings", extras = ["allauth", "celery"], specifier = "==0.50.3" }, { name = "django-resonant-utils", extras = ["allauth", "s3-storage"], specifier = "==0.19.0" }, { name = "django-resonant-utils", extras = ["minio-storage"], marker = "extra == 'development'", specifier = "==0.19.0" }, { name = "django-s3-file-field", extras = ["minio"], marker = "extra == 'development'", specifier = "==1.1.0" }, @@ -949,15 +949,15 @@ wheels = [ [[package]] name = "django-resonant-settings" -version = "0.48.1" +version = "0.50.3" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "django" }, { name = "django-environ" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/93/36/70d9e2441a204e138c50c97b7791efa8e8bc15e17dfea2c2413733d2e576/django_resonant_settings-0.48.1.tar.gz", hash = "sha256:c101ccc60e6922e875140eeb3c2f089aac2bf0ebca63c512f826f91286d16983", size = 19231, upload-time = "2026-03-06T05:01:10.797Z" } +sdist = { url = "https://files.pythonhosted.org/packages/93/09/90d8a1bf0adc369da51f94ad001ff0ac0a66021ab1ea33b3732d80cb2e78/django_resonant_settings-0.50.3.tar.gz", hash = "sha256:a961cba3fe850845d636caccf3b927068cc25884a14f28d7e751bb16f0a8d9be", size = 19236, upload-time = "2026-04-10T14:04:25.793Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/5e/f2/15b8afe28ed7b76e8e7f7d6bac8b49cc977691142659d5468671c0889536/django_resonant_settings-0.48.1-py3-none-any.whl", hash = "sha256:01e494132d05828c4a79b54d1e5013052b4e40cc034e7dd52cf8b4c93a57e4e7", size = 26102, upload-time = "2026-03-06T05:01:09.754Z" }, + { url = "https://files.pythonhosted.org/packages/be/a5/b311d7038abf599098a6dcc7652fb26969cf744fef7eca28e82b8b94b5c0/django_resonant_settings-0.50.3-py3-none-any.whl", hash = "sha256:ada78d0cd0995596510eeb43e18fc278250f9d7962688b34515caceb39e72fb7", size = 26047, upload-time = "2026-04-10T14:04:26.541Z" }, ] [package.optional-dependencies]