Files
Anthias/pyproject.toml
Viktor Petersson e211ec848e feat(sentry): add Sentry error tracking to the Django services (#3007)
* feat(sentry): add Sentry error tracking to the Django services

Adds sentry-sdk to the server and viewer dependency groups (plus the
mypy group, since that CI job imports settings) and initialises it in
the shared Django settings module, so anthias-server, anthias-celery,
and the viewer all report crashes.

- The DSN can be overridden via the SENTRY_DSN env var (pointing at
  an operator's own Sentry project), or set to an empty string to
  disable crash reporting entirely.
- environment= mirrors the ENVIRONMENT env var (production default)
  so dev/CI events are filterable in Sentry.
- release= comes from pyproject.toml's [project].version via the
  existing get_anthias_release() helper.
- send_default_pii is gated on the existing analytics_opt_out knob in
  anthias.conf — opted-out devices still report crashes, but without
  request headers / IPs / user data.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix(sentry): don't send events from test runs by default

The unit suite is built to run with no external network dependencies
(conftest.py force-mocks Redis for the same reason), and exceptions
raised on purpose by failing tests must not land in the production
Sentry project. Default the DSN to empty under ENVIRONMENT=test or
pytest (reusing the existing argv detector, moved up from the
DATABASES section); an explicit SENTRY_DSN still wins so the
integration stack can opt in deliberately.

Addresses the Copilot review comment on the hardcoded default DSN.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* test(sentry): pin the no-events-under-pytest guarantee

Asserts the client has no DSN, builds no transport, and drops
capture calls when running under pytest, so a future settings.py
refactor can't silently re-enable sending from test runs.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-07 07:41:46 +02:00

254 lines
7.2 KiB
TOML

[build-system]
requires = ["setuptools>=68", "wheel"]
build-backend = "setuptools.build_meta"
[project]
name = "anthias"
version = "2026.06.1"
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.4.0",
"celery-types==0.26.0",
"django-stubs==6.0.5",
"djangorestframework-stubs==3.16.9",
"mypy==2.1.0",
"ruff==0.14.10",
"tenacity==9.1.4",
"types-gunicorn==26.0.0.20260518",
"types-netifaces==0.11.0.20260408",
"types-python-dateutil==2.9.0.20260518",
"types-pytz==2026.2.0.20260506",
"types-PyYAML==6.0.12.20260408",
"types-requests==2.33.0.20260518",
]
docker-image-builder = [
"click==8.1.7",
"jinja2==3.1.6",
"pygit2==1.19.2",
"requests==2.33.1",
"python-on-whales==0.81.0",
]
server = [
"cec==0.2.8",
"celery==5.6.3",
"certifi==2026.5.20",
"channels==4.3.2",
"channels-redis==4.3.0",
"Django==5.2.14",
"djangorestframework==3.17.1",
"django-dbbackup==5.3.0",
"django-stubs-ext==6.0.3",
"drf-spectacular==0.29.0",
"Jinja2==3.1.6",
"netifaces==0.11.0",
"packaging==26.2",
# 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.
"Pillow==12.2.0",
"pillow-heif==1.3.0",
"psutil==7.2.2",
"pydbus==0.6.0",
"python-dateutil==2.9.0.post0",
"pytz==2026.2",
"PyYAML==6.0.3",
"redis==7.4.0",
"requests==2.33.1",
"sentry-sdk==2.61.1",
"tenacity==9.1.4",
"sh==2.2.2",
"urllib3==2.7.0",
"uvicorn[standard]==0.49.0",
"whitenoise==6.12.0",
"yt-dlp>=2026.3.17",
]
viewer = [
"cec==0.2.8",
"certifi==2026.5.20",
"Django==5.2.14",
"Jinja2==3.1.6",
"netifaces==0.11.0",
"pydbus==0.6.0",
"python-dateutil==2.9.0.post0",
"pytz==2026.2",
"redis==7.4.0",
"requests==2.33.1",
"sentry-sdk==2.61.1",
"tenacity==9.1.4",
"sh==2.2.2",
"urllib3==2.7.0",
]
dev = [
"pytest==9.0.3",
"pytest-cov==6.0.0",
"pytest-django==4.12.0",
"pytest-mock==3.15.1",
"pytest-xdist==3.8.0",
"playwright==1.59.0",
"pytest-playwright==0.8.0",
"time-machine==3.2.0",
]
host = [
"ansible-core==2.20.5",
"netifaces2==0.0.22",
"redis==7.4.0",
"requests==2.33.1",
"tenacity==9.1.4",
]
local = [
"click==8.1.7",
"requests==2.33.1",
"tenacity==9.1.4",
]
website = [
"pytest==9.0.3",
"requests==2.33.1",
]
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 (cec, netifaces, 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.14",
"django-dbbackup==5.3.0",
"django-stubs-ext==6.0.3",
"djangorestframework==3.17.1",
"drf-spectacular==0.29.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 cec / pydbus / sh pattern.
"Pillow==12.2.0",
"pytz==2026.2",
"sentry-sdk==2.61.1",
"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/<id>/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$",
]
[[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` itself is covered by partial PEP 561 stubs in stubs/channels-stubs/;
# only the helpers we actually call are typed there.
module = [
"cec",
"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"