[project]
name = "python-playlist-sync"
version = "0.1.0"
description = ".net filtr-api playlist sync port to python"
readme = "README.md"
requires-python = ">=3.14"
dependencies = [
    "aiomysql>=0.3.2",
    "aiosqlite>=0.22.1",
    "arq>=0.27.0",
    "celery>=5.0.5",
    "cryptography>=49.0.0",
    "flower>=2.0.0",
    "fastapi>=0.135.3",
    "google-api-python-client>=2.0.0",
    "google-auth>=2.0.0",
    "google-auth-httplib2>=0.2.0",
    "greenlet>=3.3.2",
    "httpx>=0.28.1",
    "pydantic>=2.12.5",
    "PyJWT>=2.10.0",
    "pymysql>=1.1.2",
    "python-dotenv>=1.2.2",
    "respx>=0.23.1",
    "spotipy>=2.25.1",
    "sqlalchemy>=2.0.49",
    "sentry-sdk[fastapi]>=2.0.0",
    "sqlmodel>=0.0.38",
    "uvicorn>=0.44.0",
]

[dependency-groups]
dev = [
    "pytest>=9.0.3",
    "pytest-asyncio>=1.3.0",
    "pytest-cov>=7.1.0",
    "ruff>=0.15.9",
    "mypy>=1.20.0",
    "types-requests>=2.32.0",
]

[tool.mypy]
python_version = "3.14"
warn_return_any = true
warn_unused_configs = true
disallow_untyped_defs = true
disallow_incomplete_defs = true

[[tool.mypy.overrides]]
module = [
    "spotipy",
    "spotipy.*",
    "googleapiclient.*",
    "google.auth.*",
    "google.oauth2.*",
    "celery",
    "celery.*",
    "sentry_sdk",
    "sentry_sdk.*",
    "jwt",
    "cryptography.*",
]
ignore_missing_imports = true

[[tool.mypy.overrides]]
module = ["worker.*"]
disallow_untyped_defs = false
disallow_incomplete_defs = false
warn_return_any = false
ignore_errors = true

[tool.ruff]
line-length = 88

[tool.ruff.lint]
select = [
    "E",    # pycodestyle errors
    "F",    # pyflakes
    "I",    # isort
    "Q",    # flake8-quotes
    "D",    # pydocstyle
    "B",    # flake8-bugbear
]
ignore = [
    "D100",  # Missing docstring in public module
    "D101",  # Missing docstring in public class
    "D102",  # Missing docstring in public method
    "D103",  # Missing docstring in public function
    "D104",  # Missing docstring in public package
    "D107",  # Missing docstring in __init__
    "B008",  # FastAPI Depends() in default args is intentional
    "E712",  # SQLAlchemy ORM requires == True for BIT(1) column comparisons
]

[tool.ruff.lint.per-file-ignores]
"tests/**" = ["E402", "F841", "E741", "D205"]

[tool.ruff.lint.flake8-quotes]
inline-quotes = "double"

[tool.ruff.lint.isort]
known-first-party = ["playlist_sync", "worker"]
known-third-party = [
    "boto3",
    "lambdacommon",
    "packaging",
    "sentry_sdk"
]

[tool.ruff.lint.pydocstyle]
convention = "google"

[tool.pytest.ini_options]
asyncio_mode = "auto"
pythonpath = ["."]
testpaths = ["tests"]
markers = [
    "parity: side-by-side parity tests against a live .NET deployment (requires DOTNET_API_URL)",
    "e2e: end-to-end tests against a running docker-compose stack (requires E2E_API_URL or E2E_USE_INPROCESS=1)",
]
