[project]
name = "backend"
version = "0.1.0"
description = "Add your description here"
requires-python = ">=3.12"
dependencies = [
    "aiosmtplib>=5.1.2",
    "alembic>=1.18.5",
    "argon2-cffi>=25.1.0",
    "asyncpg>=0.31.0",
    "celery[redis]>=5.3.1",
    "email-validator>=2.3.0",
    "fastapi>=0.139.0",
    "faster-whisper>=1.2.1",
    "httpx>=0.28.1",
    "icalendar>=7.2.0",
    "livekit-api>=1.2.0",
    "prometheus-client>=0.25.0",
    "pydantic-settings>=2.14.2",
    "pyjwt>=2.13.0",
    "python-multipart>=0.0.32",
    "pyyaml>=6.0.3",
    "redis>=8.0.1",
    "sqlalchemy[asyncio]>=2.0.51",
    "tokenizers>=0.23.1",
    "uvicorn[standard]>=0.51.0",
]

# Уровни AI `medium`(опционально)/`max` (ADR-004, docs/architecture/adr/
# 004-ai-tier-matrix.md): cuBLAS/cuDNN 9 для faster-whisper на CUDA 12
# (`WhisperModel(..., device="cuda")`, `core/plugins/faster_whisper.py`,
# класс `FasterWhisperGPU`). Ставится только в GPU-образе воркера
# транскрибации (compose-сервис `worker-transcriber-gpu`,
# профиль `transcribe-gpu`) — не в базовом CPU-образе backend/worker.
[project.optional-dependencies]
gpu = [
    "nvidia-cublas-cu12",
    "nvidia-cudnn-cu12==9.*",
]

[dependency-groups]
dev = [
    "mypy>=2.3.0",
    "pytest>=9.1.1",
    "pytest-asyncio>=1.4.0",
    "ruff>=0.15.21",
    "types-pyyaml>=6.0.12.20260518",
]

[tool.ruff]
line-length = 100
target-version = "py312"
extend-exclude = ["alembic/versions"]

[tool.ruff.lint]
select = ["E", "F", "I", "UP", "B", "ASYNC"]
ignore = ["B008"]  # FastAPI's `Depends(...)` default-argument pattern is idiomatic

[tool.ruff.lint.per-file-ignores]
# Инлайн-стили HTML-письма (требование почтовых клиентов — внешний `<style>`
# большинство из них игнорирует) — длина строки не показатель качества здесь,
# оборачивать вёрстку ради line-length бессмысленно.
"services/email_templates.py" = ["E501"]

[tool.ruff.lint.isort]
# `workers/` — соседний пакет монорепо (см. `pythonpath` в
# [tool.pytest.ini_options]), а не сторонняя библиотека; без этого ruff
# постоянно перекладывает его импорт между группами first-party/third-party.
known-first-party = ["workers"]

[tool.mypy]
python_version = "3.12"
strict = true
plugins = ["pydantic.mypy"]
# `workers/` живёт вне backend/ (см. соответствующий комментарий у
# `pythonpath` в [tool.pytest.ini_options]) — добавляем корень репозитория
# в путь поиска модулей, чтобы mypy мог резолвить `import workers.*` в тестах.
mypy_path = ".."

[[tool.mypy.overrides]]
module = "livekit.*"
ignore_missing_imports = true

[[tool.mypy.overrides]]
# celery не поставляет тайп-стабы/py.typed; `@app.task` из-за этого
# нетипизирован — strict-режим backend/ на этот декоратор не распространяем.
module = "celery.*"
ignore_missing_imports = true

[[tool.mypy.overrides]]
# kombu (транспорт celery) тоже без тайп-стабов/py.typed — нужен для
# retry-обёртки postановки задач на `kombu.exceptions.OperationalError`/
# `ConnectionError` (workers/tasks/pipeline.py).
module = "kombu.*"
ignore_missing_imports = true

[[tool.mypy.overrides]]
module = "workers.tasks.*"
disallow_untyped_decorators = false

[[tool.mypy.overrides]]
# faster-whisper не поставляет тайп-стабы/py.typed.
module = "faster_whisper.*"
ignore_missing_imports = true

[tool.pytest.ini_options]
asyncio_mode = "auto"
asyncio_default_fixture_loop_scope = "session"
asyncio_default_test_loop_scope = "session"
testpaths = ["tests"]
# `workers/` живёт вне backend/ (репозиторий — монорепо), но
# в проде (deploy/docker-compose.yml) монтируется в тот же PYTHONPATH, что и
# backend-код. Добавляем корень репозитория в sys.path, чтобы тесты
# автоосвобождения комнат могли делать `import workers.*` так же, как в проде.
pythonpath = [".."]
