Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/dependabot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ updates:
npm:
patterns:
- "*"
- package-ecosystem: "pip"
- package-ecosystem: "uv"
directory: "/"
schedule:
interval: "daily"
Expand Down
11 changes: 11 additions & 0 deletions .github/workflows/generate-openapi-schema.yml
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,17 @@ jobs:
run: |
docker compose up -d

- name: Wait for server to be ready
run: |
for i in $(seq 1 30); do
if docker compose exec anthias-server python -c "import django" 2>/dev/null; then
echo "Server is ready"
break
fi
echo "Waiting for server... ($i/30)"
sleep 2
done

- name: Generate OpenAPI Schema
run: |
docker compose exec anthias-server \
Expand Down
21 changes: 21 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,27 @@ Inside Docker:
docker compose -f docker-compose.dev.yml exec anthias-server npm run dev
```

### Python Dependencies

All Python dependencies are managed via `pyproject.toml` dependency groups, with `uv.lock` for reproducible installs. Each Docker service has its own group:

- `server` — Django web app (anthias-server)
- `celery` — Celery worker (includes server group)
- `websocket` — WebSocket service
- `viewer` — Viewer service (standalone Dockerfile)
- `wifi-connect` — WiFi Connect service
- `dev` — Test utilities (mock, selenium, etc.)
- `test` — Combined group (includes server + dev + viewer)
- `host` — Host machine (Ansible, etc.)
- `local` — Local CLI tools
- `dev-host` — Ruff linter
- `docker-image-builder` — Docker image build tooling

```bash
uv lock # Regenerate lockfile after changing deps
uv sync --only-group <name> # Install a specific group
```

### Python Linting

```bash
Expand Down
4 changes: 2 additions & 2 deletions bin/install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -159,11 +159,11 @@ function install_packages() {
function install_ansible() {
display_section "Install Ansible"

REQUIREMENTS_URL="$GITHUB_RAW_URL/$BRANCH/requirements/requirements.host.txt"
PYPROJECT_URL="$GITHUB_RAW_URL/$BRANCH/pyproject.toml"
if [ "$DISTRO_VERSION" -le 11 ]; then
ANSIBLE_VERSION="ansible-core==2.15.9"
else
ANSIBLE_VERSION=$(curl -s $REQUIREMENTS_URL | grep ansible)
ANSIBLE_VERSION=$(curl -s "$PYPROJECT_URL" | grep ansible-core | sed 's/.*"\(ansible-core==[^"]*\)".*/\1/')
fi

SUDO_ARGS=()
Expand Down
11 changes: 3 additions & 8 deletions docker/Dockerfile.base.j2
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,8 @@ RUN --mount=type=cache,target=/var/cache/apt \
# https://github.com/balena-io-library/base-images/issues/562
RUN c_rehash

# We need this to ensure that the wheels can be built.
# Otherwise we get "invalid command 'bdist_wheel'"
{% if disable_cache_mounts %}
RUN \
{% if board in ['pi1', 'pi2'] %}
RUN pip3 install uv --break-system-packages
{% else %}
RUN --mount=type=cache,target=/root/.cache/pip \
COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /usr/local/bin/
{% endif %}
pip3 install --upgrade pip --break-system-packages && \
pip3 install wheel --break-system-packages

12 changes: 8 additions & 4 deletions docker/Dockerfile.celery.j2
Original file line number Diff line number Diff line change
@@ -1,16 +1,20 @@
{% include 'Dockerfile.base.j2' %}

COPY requirements/requirements.txt /tmp/requirements.txt
COPY pyproject.toml uv.lock /tmp/uv-deps/
{% if disable_cache_mounts %}
RUN \
{% else %}
RUN --mount=type=cache,target=/root/.cache/pip \
RUN --mount=type=cache,target=/root/.cache/uv \
{% endif %}
pip3 install -r /tmp/requirements.txt --break-system-packages
uv venv --system-site-packages /opt/venv && \
cd /tmp/uv-deps && \
VIRTUAL_ENV=/opt/venv uv sync --active --only-group celery --no-install-project --frozen

ENV PATH="/opt/venv/bin:$PATH"

RUN mkdir -p /usr/src/app
WORKDIR /usr/src/app
COPY . /usr/src/app/
WORKDIR /usr/src/app

ENV GIT_HASH={{ git_hash }}
ENV GIT_SHORT_HASH={{ git_short_hash }}
Expand Down
3 changes: 1 addition & 2 deletions docker/Dockerfile.dev
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
FROM python:3.11-bookworm

RUN apt-get update -y && \
pip install uv
COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /usr/local/bin/

WORKDIR /app

Expand Down
10 changes: 7 additions & 3 deletions docker/Dockerfile.server.j2
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,17 @@ RUN npm run build
{% endif %}
{% include 'Dockerfile.base.j2' %}

COPY requirements/requirements.txt /tmp/requirements.txt
COPY pyproject.toml uv.lock /tmp/uv-deps/
{% if disable_cache_mounts %}
RUN \
{% else %}
RUN --mount=type=cache,target=/root/.cache/pip \
RUN --mount=type=cache,target=/root/.cache/uv \
{% endif %}
pip3 install -r /tmp/requirements.txt --break-system-packages
uv venv --system-site-packages /opt/venv && \
cd /tmp/uv-deps && \
VIRTUAL_ENV=/opt/venv uv sync --active --only-group server --no-install-project --frozen

ENV PATH="/opt/venv/bin:$PATH"

RUN mkdir -p /usr/src/app
COPY . /usr/src/app/
Expand Down
23 changes: 13 additions & 10 deletions docker/Dockerfile.test.j2
Original file line number Diff line number Diff line change
Expand Up @@ -40,25 +40,24 @@ RUN --mount=type=cache,target=/var/cache/apt \
# WORKDIR /opt/ffmpeg
# COPY --from=builder /opt/ffmpeg/ffserver ./

ADD requirements/requirements.txt /tmp/requirements.txt
ADD requirements/requirements.dev.txt /tmp/requirements.dev.txt
ADD requirements/requirements.viewer.txt /tmp/requirements.viewer.txt

{% if not is_arm64 %}
RUN wget {{ chromedriver_dl_url }} -O /tmp/chromedriver.zip && \
unzip -o /tmp/chromedriver.zip -d /opt
RUN wget {{ chrome_dl_url }} -O /tmp/chrome.zip && \
unzip -o /tmp/chrome.zip -d /opt
{% endif %}

COPY pyproject.toml uv.lock /tmp/uv-deps/
{% if disable_cache_mounts %}
RUN \
{% else %}
RUN --mount=type=cache,target=/root/.cache/pip \
RUN --mount=type=cache,target=/root/.cache/uv \
{% endif %}
pip3 install \
-r /tmp/requirements.txt \
-r /tmp/requirements.dev.txt \
-r /tmp/requirements.viewer.txt \
--break-system-packages
uv venv --system-site-packages /opt/venv && \
cd /tmp/uv-deps && \
VIRTUAL_ENV=/opt/venv uv sync --active --only-group test --no-install-project --frozen

ENV PATH="/opt/venv/bin:$PATH"

RUN mkdir -p /usr/src/app
COPY . /usr/src/app
Expand All @@ -71,4 +70,8 @@ RUN cp ansible/roles/screenly/files/screenly.conf \
ENV GIT_HASH={{ git_hash }}
ENV GIT_SHORT_HASH={{ git_short_hash }}
ENV GIT_BRANCH={{ git_branch }}
{% if is_arm64 %}
ENV PATH="/usr/lib/chromium:/usr/lib/chromium-browser:$PATH"
{% else %}
ENV PATH="/opt/chrome-linux64:/opt/chromedriver-linux64:$PATH"
{% endif %}
28 changes: 13 additions & 15 deletions docker/Dockerfile.viewer.j2
Original file line number Diff line number Diff line change
Expand Up @@ -19,29 +19,28 @@ RUN --mount=type=cache,target=/var/cache/apt \
{% endif %}
{% endfor %}

# We need this to ensure that the wheels can be built.
# Otherwise we get "invalid command 'bdist_wheel'"
{% if disable_cache_mounts %}
RUN \
# Works around issue with `curl`
# https://github.com/balena-io-library/base-images/issues/562
RUN c_rehash

{% if board in ['pi1', 'pi2'] %}
RUN pip3 install uv --break-system-packages
{% else %}
RUN --mount=type=cache,target=/root/.cache/pip \
COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /usr/local/bin/
{% endif %}
pip3 install --upgrade pip --break-system-packages && \
pip3 install wheel --break-system-packages

# Install Python requirements
COPY requirements/requirements.viewer.txt /tmp/requirements.txt

COPY pyproject.toml uv.lock /tmp/uv-deps/
{% if disable_cache_mounts %}
RUN \
{% else %}
RUN --mount=type=cache,target=/root/.cache/pip \
RUN --mount=type=cache,target=/root/.cache/uv \
{% endif %}
pip3 install -r /tmp/requirements.txt --break-system-packages
uv venv --system-site-packages /opt/venv && \
cd /tmp/uv-deps && \
VIRTUAL_ENV=/opt/venv uv sync --active --only-group viewer --no-install-project --frozen

# Works around issue with `curl`
# https://github.com/balena-io-library/base-images/issues/562
RUN c_rehash
ENV PATH="/opt/venv/bin:$PATH"

# QT Base from packages does not support eglfs

Expand Down Expand Up @@ -83,7 +82,6 @@ RUN useradd -g video viewer

RUN rm -f /etc/localtime

WORKDIR /usr/src/app
RUN mkdir -p /usr/src/app
COPY . /usr/src/app/

Expand Down
12 changes: 8 additions & 4 deletions docker/Dockerfile.websocket.j2
Original file line number Diff line number Diff line change
@@ -1,16 +1,20 @@
{% include 'Dockerfile.base.j2' %}

COPY requirements/requirements-websocket.txt /tmp/requirements.txt
COPY pyproject.toml uv.lock /tmp/uv-deps/
{% if disable_cache_mounts %}
RUN \
{% else %}
RUN --mount=type=cache,target=/root/.cache/pip \
RUN --mount=type=cache,target=/root/.cache/uv \
{% endif %}
pip3 install -r /tmp/requirements.txt --break-system-packages
uv venv --system-site-packages /opt/venv && \
cd /tmp/uv-deps && \
VIRTUAL_ENV=/opt/venv uv sync --active --only-group websocket --no-install-project --frozen

ENV PATH="/opt/venv/bin:$PATH"

RUN mkdir -p /usr/src/app
WORKDIR /usr/src/app
COPY . /usr/src/app/
WORKDIR /usr/src/app

ENV GIT_HASH={{ git_hash }}
ENV GIT_SHORT_HASH={{ git_short_hash }}
Expand Down
10 changes: 7 additions & 3 deletions docker/Dockerfile.wifi-connect.j2
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,17 @@ RUN if [[ ! -z "{{ archive_url }}" ]]; then \
unzip -o /tmp/wifi_connect.zip -d /usr/src/app && \
rm /tmp/wifi_connect.zip; fi

COPY requirements/requirements.wifi-connect.txt /tmp/requirements.txt
COPY pyproject.toml uv.lock /tmp/uv-deps/
{% if disable_cache_mounts %}
RUN \
{% else %}
RUN --mount=type=cache,target=/root/.cache/pip \
RUN --mount=type=cache,target=/root/.cache/uv \
{% endif %}
pip3 install -r /tmp/requirements.txt --break-system-packages
uv venv --system-site-packages /opt/venv && \
cd /tmp/uv-deps && \
VIRTUAL_ENV=/opt/venv uv sync --active --only-group wifi-connect --no-install-project --frozen

ENV PATH="/opt/venv/bin:$PATH"

COPY send_zmq_message.py ./

Expand Down
Loading
Loading