Skip to content

v1 API on real Ray Serve (v0.6.0) (#46) #104

v1 API on real Ray Serve (v0.6.0) (#46)

v1 API on real Ray Serve (v0.6.0) (#46) #104

Workflow file for this run

# =================================
# Copyright: CEA-LIST/DIASI/SIALV
# Author : pixano@cea.fr
# License: CECILL-C
# =================================
name: Test Backend
on:
push:
paths:
- "src/**"
- "packages/**"
- "tests/**"
- ".github/workflows/test_back.yml"
- "pyproject.toml"
- ".pre-commit-config.yaml"
branches:
- "main"
pull_request:
paths:
- "src/**"
- "packages/**"
- "tests/**"
- ".github/workflows/test_back.yml"
- "pyproject.toml"
- ".pre-commit-config.yaml"
branches:
- "main"
permissions:
contents: read
jobs:
python_test:
name: Backend
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
python-version: ["3.10", "3.11", "3.12", "3.13"]
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
cache: "pip"
# Install the CPU torch build so the model code paths (sam2/transformers) are
# actually exercised instead of silently skipped via importorskip.
- name: Install dependencies
run: |
python -m pip install --upgrade pip
# Install torch AND torchvision from the same CPU index so their compiled ops stay
# ABI-coherent (open_clip / transformers pull torchvision; a PyPI torchvision against
# a CPU-index torch breaks with "operator torchvision::nms does not exist").
python -m pip install torch torchvision --index-url https://download.pytorch.org/whl/cpu
# The client is a hard core dep not yet on PyPI, so install it editable BEFORE `pip install .`.
python -m pip install -e packages/pixano-inference-client
python -m pip install .[test,transformers]
python -m pip install -e examples/numpy_detector # example entry-point plugin
python -m pip install -e packages/pixano-inference-sam # SAM2 plugin (fake predictor in tests; sam-2 lib not needed)
python -m pip install -e packages/pixano-inference-clip # CLIP embedding plugin (open_clip only needed for the integration test)
# Fast unit tests (the Ray Serve integration suite runs in its own job below).
- name: Test with pytest
run: |
pytest --cov=pixano_inference --cov-report=xml -m "not integration" tests/
- name: Upload coverage reports to Codecov with GitHub Action
uses: codecov/codecov-action@v4.2.0
env:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
integration:
name: Ray Serve integration (CPU)
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.12"
cache: "pip"
# Integration tests boot a real local Ray + Serve runtime with a numpy-only stub
# model (no torch, no GPU) and exercise deploy -> RUNNING -> predict -> undeploy.
- name: Install dependencies
run: |
python -m pip install --upgrade pip
# torch + torchvision from the same index (open_clip needs matching torchvision ops).
python -m pip install torch torchvision --index-url https://download.pytorch.org/whl/cpu
python -m pip install -e packages/pixano-inference-client # hard core dep, not yet on PyPI
python -m pip install .[test]
python -m pip install -e examples/numpy_detector # example entry-point plugin
python -m pip install -e packages/pixano-inference-clip # CLIP plugin: real MobileCLIP2 deploy+embed test
- name: Run integration tests
run: |
pytest -m integration tests/integration/
docker_smoke:
name: Docker build & smoke (CPU, framework-free)
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
# Build a minimal, framework-free image (no torch, no SAM) with the numpy example
# plugin, so the Dockerfile mechanics + entrypoint + healthcheck + Serve deploy path
# are validated fast, without pulling multi-GB torch/sam-2.
- name: Build minimal image
run: |
docker build \
--build-arg TORCH_INDEX_URL= \
--build-arg PIXANO_EXTRAS= \
--build-arg INSTALL_SAM=false \
--build-arg INSTALL_EXAMPLE=true \
-t pixano-inference:smoke .
- name: Run container and smoke-test /v1/ready
run: |
docker run -d --name pi -p 7463:7463 --shm-size=2g \
-v "$PWD/docker/models.numpy.py:/config/models.py:ro" \
pixano-inference:smoke --host 0.0.0.0 --port 7463 --config /config/models.py
for i in $(seq 1 40); do
if curl -fsS http://localhost:7463/health >/dev/null 2>&1; then echo "healthy"; break; fi
sleep 3
done
curl -fsS http://localhost:7463/v1/ready \
| python3 -c "import sys, json; d = json.load(sys.stdin); print(d); sys.exit(0 if d['ready'] else 1)" \
|| (docker logs pi; exit 1)
docker rm -f pi
framework_free_core:
name: Framework-free core
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
python-version: ["3.10", "3.13"]
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
cache: "pip"
# Deliberately install NO ML framework (no torch/jax/tensorflow/mlx). The core
# must import and the guardrail tests must pass with numpy only.
- name: Install core only
run: |
python -m pip install --upgrade pip
python -m pip install -e packages/pixano-inference-client # hard core dep, not yet on PyPI
python -m pip install .[test]
- name: Assert core imports pull no ML framework
run: |
pytest tests/test_core_framework_free.py -v
# A framework-free custom model, installed as a plugin package and discovered via its
# entry point — the recommended extension path, exercised here with no ML framework.
- name: Install and discover the example plugin (no ML framework)
run: |
python -m pip install -e examples/numpy_detector
pytest tests/test_plugins.py -v
openapi:
name: OpenAPI schema in sync
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
# Generate the schema in the LOCKED environment (uv.lock) so the check is deterministic:
# a fresh `pip install` resolves newer FastAPI/pydantic that emit a subtly different schema
# than the committed docs/openapi.json (which is generated against the lockfile).
- name: Install uv
uses: astral-sh/setup-uv@v5
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.12"
- name: Check the committed OpenAPI schema is in sync
run: |
uv sync --no-default-groups
uv run python scripts/gen_openapi.py --check
client_standalone:
name: Standalone client (no server deps)
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
python-version: ["3.10", "3.13"]
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
cache: "pip"
# Install ONLY the standalone client (no core, no ray/fastapi/torch). Its tests assert the
# import pulls in no heavy modules — the acceptance proof that third-party callers get a
# small install. Also confirm the whole server stack is genuinely absent.
- name: Install the client only
run: |
python -m pip install --upgrade pip
python -m pip install -e "packages/pixano-inference-client[masks]"
python -m pip install pytest
- name: Assert the server stack is not installed
run: |
python - <<'PY'
import importlib.util
for mod in ["ray", "fastapi", "uvicorn", "torch", "pixano_inference"]:
assert importlib.util.find_spec(mod) is None, f"{mod} should not be installed"
import pixano_inference_client
print("standalone client OK:", pixano_inference_client.PixanoInferenceClient)
PY
- name: Run the client package tests
run: |
pytest packages/pixano-inference-client/tests -v