[build-system] requires = ["setuptools>=84.0.0", "wheel"] build-backend = "setuptools.build_meta" [project] name = "anthias" version = "2026.11.0" description = "The world's most popular open source digital signage project." readme = "README.md" requires-python = ">=3.13" dependencies = [] [project.scripts] anthias-manage = "anthias_server.manage:main" [tool.setuptools.packages.find] where = ["src"] include = ["anthias_*"] namespaces = false [dependency-groups] dev-host = [ "ansible-lint==26.10.1", "celery-types==0.26.0", "django-stubs==6.1.2", "djangorestframework-stubs==3.18.1", "mypy==2.4.0", "ruff==0.17.1", "tenacity==9.2.1", "types-gunicorn==26.2.0.20261008", # Direct dev dep: types-psutil used to arrive transitively via # djangorestframework-stubs, which dropped it in 3.17.1 — pin it # directly so the psutil import in the server keeps its stubs. "types-psutil==7.2.2.20260906", "types-python-dateutil==2.9.0.20260807", "types-pytz==2026.5.0.20261006", "types-PyYAML==6.0.12.20260518", ] docker-image-builder = [ "click==8.5.0", "jinja2==3.1.6", "pygit2==1.20.1", "requests==2.34.2", "python-on-whales==0.81.0", ] server = [ "celery==5.6.3", "certifi==2026.10.18", "channels==4.3.2", "channels-redis==4.3.0", "Django==5.2.17", "djangorestframework==3.18.3", "django-dbbackup==5.3.1", "django-stubs-ext==6.1.2", "drf-spectacular==0.30.0", "Jinja2==3.1.6", "packaging==26.3", # Pillow + pillow-heif power the upload-time image normalisation # pipeline (HEIC / HEIF / TIFF → lossless WebP). pillow-heif # registers a libheif-backed Pillow plugin at import time; the # libheif1 system package is supplied by the base image (see # docker/Dockerfile.server.j2). Pillow itself is otherwise unused # — adding it here instead of relying on a transitive import keeps # the dependency explicit. # # Pinned to 1.4.0: 1.5.0 requires libheif >= 1.23.1 to build from # source, but Debian trixie ships libheif 1.19.8. arm64/x86 install # a prebuilt wheel so they don't compile and were unaffected, but # armhf (pi2/pi3) has no wheel — uv builds from source and the # compile fails ("pillow_heif requires libheif >= 1.23.1"), breaking # the 32-bit board images and the whole master build matrix. Hold at # 1.4.0 until trixie carries libheif >= 1.23.1 (or a 1.5.x with armhf # wheels lands). Do not let dependabot bump this past 1.4.0. "Pillow==12.3.0", "pillow-heif==1.4.0", "psutil==7.2.2", "pydbus==0.6.0", "python-dateutil==2.9.0.post0", "pytz==2026.5", "PyYAML==6.0.3", "redis==8.1.0", "requests==2.34.2", "sentry-sdk==2.72.0", "tenacity==9.2.1", "sh==2.4.0", "urllib3==2.8.0", "uvicorn[standard]==0.54.0", "whitenoise==6.12.0", "yt-dlp>=2026.7.4", ] viewer = [ "certifi==2026.10.18", "Django==5.2.17", "Jinja2==3.1.6", "pydbus==0.6.0", "python-dateutil==2.9.0.post0", "pytz==2026.5", "redis==8.1.0", "requests==2.34.2", "sentry-sdk==2.72.0", "tenacity==9.2.1", "sh==2.4.0", "urllib3==2.8.0", ] dev = [ "pytest==9.1.1", "pytest-cov==7.1.0", "pytest-django==4.14.0", "pytest-mock==3.17.0", "pytest-xdist==3.8.0", "playwright==1.64.0", "pytest-playwright==0.10.0", "time-machine==3.5.1", ] host = [ "ansible-core==2.21.5", "redis==8.1.0", "requests==2.34.2", "tenacity==9.2.1", ] local = [ "click==8.5.0", "requests==2.34.2", "tenacity==9.2.1", ] website = [ "pytest==9.1.1", "requests==2.34.2", ] test = [ { include-group = "server" }, { include-group = "viewer" }, { include-group = "dev" }, ] # Used by the python-mypy CI job. The django-stubs plugin imports # anthias_server.django_project.settings to introspect the app registry, so we need the # runtime deps that settings touches — but not the heavy native-extension # deps from the server group (pydbus, psutil, etc.). We also include # docker-image-builder so its tools (pygit2, python_on_whales) resolve. mypy = [ { include-group = "dev-host" }, { include-group = "docker-image-builder" }, "channels==4.3.2", "channels-redis==4.3.0", "Django==5.2.17", "django-dbbackup==5.3.1", "django-stubs-ext==6.1.2", "djangorestframework==3.18.3", "drf-spectacular==0.30.0", # Pillow ships PEP 561 stubs (py.typed). The processing module # imports PIL at top level, so mypy needs the package resolvable # to type-check the upload-time normalisation pipeline. # pillow-heif is intentionally not pinned here — it's listed in # tool.mypy.overrides above so its missing-import error is # ignored, mirroring the pydbus / sh pattern. "Pillow==12.3.0", "pytz==2026.5", "sentry-sdk==2.72.0", "whitenoise==6.12.0", ] [tool.pytest.ini_options] DJANGO_SETTINGS_MODULE = "anthias_server.django_project.settings" testpaths = ["tests", "src/anthias_server/api/tests"] python_files = ["test_*.py"] markers = [ "integration: marks tests as integration (deselect with '-m \"not integration\"')", ] # pytest-playwright config: # --browser chromium - skip firefox/webkit (only chromium is # installed in docker/Dockerfile.test). # --tracing retain-on-failure # - per-test trace; dropped for green tests, # drained to test-artifacts//trace.zip # on failure. `playwright show-trace # trace.zip` replays. # --screenshot only-on-failure # - full-page PNG into the same per-test dir. # --output test-artifacts - directory the GH Actions upload-artifact # step picks up (.gitignored). addopts = "--strict-markers --browser chromium --tracing retain-on-failure --screenshot only-on-failure --output test-artifacts" [tool.coverage.run] branch = true source = [ "src/anthias_server", "src/anthias_common", "src/anthias_viewer", ] omit = [ "*/migrations/*", "*/__init__.py", "src/anthias_server/django_project/asgi.py", "src/anthias_server/django_project/routing.py", "src/anthias_server/django_project/urls.py", "src/anthias_server/django_project/wsgi.py", "src/anthias_server/app/management/*", "src/anthias_server/manage.py", "src/anthias_host_agent/*", "bin/*", "tools/raspberry_pi_imager/*", "tools/image_builder/*", "src/anthias_viewer/__main__.py", ] [tool.coverage.report] fail_under = 80 show_missing = true skip_covered = false exclude_lines = [ "pragma: no cover", "raise NotImplementedError", "if TYPE_CHECKING:", "if __name__ == .__main__.:", ] [tool.coverage.xml] output = "coverage.xml" [tool.mypy] python_version = "3.13" strict = true follow_imports = "normal" mypy_path = ["src", "stubs"] explicit_package_bases = true plugins = ["mypy_django_plugin.main", "mypy_drf_plugin.main"] exclude = [ "^\\.venv/", "^node_modules/", "/migrations/", "/static/", "^build/", "^dist/", # Vendored verbatim from a pinned Yocto/poky upstream commit; see # the file header. Adding type annotations would put the file # off-pin and silently break the provenance comment. "^src/anthias_webview/sysroot-relativelinks\\.py$", # Build-time-only stdlib shims (imp/pipes/cgi) for Chromium 87's # Python-2-era build tooling; not app code, emulate removed stdlib. "^src/anthias_webview/pyshim/", ] [[tool.mypy.overrides]] # Third-party libs without type stubs. Listed explicitly so a future stub # release is noticed (and the override removed) instead of silently ignored. # `channels` and asgiref's untyped `testing` module are covered by partial # PEP 561 stubs in stubs/channels-stubs/ and stubs/asgiref-stubs/; only the # helpers we actually call are typed there. (asgiref ships py.typed itself, # but not for asgiref.testing — the partial marker keeps the real stubs for # every other asgiref module.) module = [ # Dev-only: emails/render_logo.py, run through `uv run --no-project`. "cairosvg", "channels_redis.*", "gi", "gi.*", "pillow_heif", "pydbus", "sh", "yt_dlp", "yt_dlp.*", ] ignore_missing_imports = true [tool.django-stubs] django_settings_module = "anthias_server.django_project.settings"