1[project] 2name = "backend" 3dynamic = ["version"] 4description = "decentralized music streaming platform built on ATProto" 5authors = [{ name = "zzstoatzz", email = "thrast36@gmail.com" }] 6dependencies = [ 7 "fastapi>=0.115.0", 8 "uvicorn[standard]>=0.34.0", 9 "httpx>=0.28.0", 10 "pydantic>=2.11.0", 11 "pydantic-settings>=2.7.0", 12 "python-dotenv>=1.1.0", 13 "sqlalchemy>=2.0.36", 14 "alembic>=1.14.0", 15 "asyncpg>=0.30.0", 16 "atproto @ git+https://github.com/zzstoatzz/atproto@main", 17 "boto3>=1.37.0", 18 "python-multipart>=0.0.20", 19 "python-jose[cryptography]>=3.3.0", 20 "passlib[bcrypt]>=1.7.4", 21 "psycopg[binary]>=3.2.12", 22 "greenlet>=3.2.4", 23 "logfire[fastapi,sqlalchemy]>=4.14.2", 24 "cachetools>=6.2.1", 25 "pytest-asyncio>=0.25.3", 26 "aioboto3>=15.5.0", 27 "slowapi @ git+https://github.com/zzstoatzz/slowapi.git@fix-deprecation", 28 "orjson>=3.11.4", 29 "mutagen>=1.47.0", 30] 31 32requires-python = ">=3.11" 33readme = "README.md" 34license = "Apache-2.0" 35 36keywords = ["music", "streaming", "atproto", "bluesky", "decentralized"] 37 38[dependency-groups] 39dev = [ 40 "dirty-equals>=0.9.0", 41 "ipython>=8.12.3", 42 "pdbpp>=0.10.3", 43 "prek>=0.2.13", 44 "pytest>=8.3.3", 45 "pytest-asyncio>=1.0.0", 46 "pytest-cov>=6.1.1", 47 "pytest-env>=1.1.5", 48 "pytest-timeout>=2.4.0", 49 "pytest-xdist>=3.6.1", 50 "ruff>=0.12.0", 51 "httpx>=0.28.0", 52 "ty>=0.0.1a25", 53] 54 55[build-system] 56requires = ["hatchling", "uv-dynamic-versioning>=0.7.0"] 57build-backend = "hatchling.build" 58 59[tool.hatch.version] 60source = "uv-dynamic-versioning" 61 62[tool.hatch.metadata] 63allow-direct-references = true 64 65[tool.uv-dynamic-versioning] 66vcs = "git" 67style = "pep440" 68bump = true 69fallback-version = "0.0.0" 70 71[tool.pytest.ini_options] 72asyncio_mode = "auto" 73asyncio_default_fixture_loop_scope = "function" 74timeout = 10 75env = [ 76 "RELAY_TEST_MODE=1", 77 "OAUTH_ENCRYPTION_KEY=hnSkDmgbbuK0rt7Ab3eJHAktb18gmebsdwKdTmq9mes=", 78 "LOGFIRE_IGNORE_NO_CONFIG=1", 79] 80markers = [ 81 "integration: marks tests as integration tests (deselect with '-m \"not integration\"')", 82] 83pythonpath = ["."] 84testpaths = ["tests"] 85python_files = ["test_*.py", "*_test.py"] 86python_classes = ["Test*"] 87python_functions = ["test_*"] 88filterwarnings = [ 89 "ignore::pydantic.warnings.UnsupportedFieldAttributeWarning", 90] 91 92[tool.ruff.lint] 93fixable = ["ALL"] 94ignore = [ 95 "COM812", 96 "PLR0913", # Too many arguments 97 "SIM102", # Dont require combining if statements 98] 99extend-select = [ 100 "B", # flake8-bugbear 101 "C4", # flake8-comprehensions 102 "I", # isort 103 "PIE", # flake8-pie 104 "RUF", # Ruff-specific 105 "SIM", # flake8-simplify 106 "UP", # pyupgrade 107] 108 109[tool.ruff.lint.per-file-ignores] 110"__init__.py" = ["F401", "I001"] 111"tests/**/*.py" = ["S101"] # Allow assert in tests 112"src/backend/api/**/*.py" = [ 113 "B008", 114] # Allow Depends() and File() in FastAPI route defaults 115"src/backend/main.py" = ["E402"] # Need warnings filter before imports 116 117[tool.coverage.run] 118source = ["src"] 119omit = ["tests/*", "sandbox/*"] 120 121[tool.coverage.report] 122exclude_lines = [ 123 "pragma: no cover", 124 "def __repr__", 125 "raise AssertionError", 126 "raise NotImplementedError", 127 "if __name__ == .__main__.:", 128 "if TYPE_CHECKING:", 129] 130 131[tool.ty.src] 132include = ["src", "tests"] 133exclude = [ 134 "**/node_modules", 135 "**/__pycache__", 136 ".venv", 137 ".git", 138 "dist", 139 "frontend", 140] 141 142[tool.ty.environment] 143python-version = "3.11" 144 145[tool.ty.rules] 146# start with basic checks, can tighten later 147unknown-argument = "ignore" 148no-matching-overload = "ignore"