fix(vision): dichiara le dipendenze del worker, pin numerico HTTP vs runner
Ruling R9: separa l'extra vision (runner: 4 pacchetti VisionSuite + numpy) da vision-worker (fastapi, uvicorn, pillow, python-multipart, sopra vision). Prima il worker risolveva solo perche' vs-pm2d le lista per conto suo; un domani lo stub di stazione dovra' incorporare il runner senza trascinarsi dietro un server web che non gli serve. Aggiorna Dockerfile.vision e README.md al nuovo extra; il test del worker ora pinna anche il valore numerico del diametro (non solo la chiave), agganciato alla stessa tolleranza del test in-process del runner. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014BBnuACZSCJqXrMYC3LUMU
This commit is contained in:
+1
-1
@@ -11,7 +11,7 @@ COPY --from=ghcr.io/astral-sh/uv:latest /uv /usr/local/bin/uv
|
||||
WORKDIR /app
|
||||
COPY pyproject.toml uv.lock ./
|
||||
COPY vendor/ ./vendor/
|
||||
RUN uv sync --extra vision --frozen --no-dev
|
||||
RUN uv sync --extra vision-worker --frozen --no-dev
|
||||
|
||||
COPY src/vision/ ./src/vision/
|
||||
COPY src/vision_worker/ ./src/vision_worker/
|
||||
|
||||
@@ -403,12 +403,24 @@ uv sync --extra vision --extra dev --python 3.13
|
||||
uv run --python 3.13 --extra vision --extra dev pytest src/vision/tests
|
||||
```
|
||||
|
||||
Lo stesso vale per `src/vision_worker/tests/`, il piccolo servizio FastAPI che
|
||||
espone il runner: dipende da `src.vision.runner` e quindi eredita lo stesso
|
||||
vincolo su Python 3.13.
|
||||
`src/vision_worker/tests/` eredita lo stesso vincolo su Python 3.13, perché
|
||||
il worker dipende da `src.vision.runner`, ma aggiunge dipendenze proprie -
|
||||
FastAPI, Uvicorn, Pillow, python-multipart - dichiarate in un extra
|
||||
separato, `vision-worker`, tenuto distinto da `vision` apposta: un
|
||||
consumatore che incorpora solo il runner (come un futuro agente di stazione,
|
||||
che non è un servizio web) non deve trascinarsi dietro un server che non gli
|
||||
serve. `vision-worker` include comunque `vision`, quindi un solo extra basta
|
||||
per avere un worker funzionante:
|
||||
|
||||
```bash
|
||||
uv run --python 3.13 --extra vision --extra dev pytest src/vision_worker/tests
|
||||
uv run --python 3.13 --extra vision-worker --extra dev pytest src/vision_worker/tests
|
||||
```
|
||||
|
||||
Per eseguire entrambe le suite insieme, nominando esplicitamente entrambi
|
||||
gli extra:
|
||||
|
||||
```bash
|
||||
uv run --python 3.13 --extra vision --extra vision-worker --extra dev pytest src/vision/tests src/vision_worker/tests
|
||||
```
|
||||
|
||||
### Il worker di visione (`Dockerfile.vision`)
|
||||
|
||||
+19
-2
@@ -53,13 +53,30 @@ dev = [
|
||||
"coverage>=7.0.0",
|
||||
]
|
||||
|
||||
# Vision runner (VisionSuite submodule). vs-task/vs-measure/vs-pm2d require
|
||||
# Python >=3.13 upstream; marker keeps the base 3.11 resolution untouched.
|
||||
# Vision runner (VisionSuite submodule): what src/vision/runner.py needs to
|
||||
# execute a graph. vs-task/vs-measure/vs-pm2d require Python >=3.13 upstream;
|
||||
# marker keeps the base 3.11 resolution untouched. numpy is declared
|
||||
# explicitly - runner.py imports it directly, and it must not depend on
|
||||
# being pulled in as a side effect of vs-pm2d's own dependencies.
|
||||
vision = [
|
||||
"visionsuite; python_version>='3.13'",
|
||||
"vs-task; python_version>='3.13'",
|
||||
"vs-measure; python_version>='3.13'",
|
||||
"vs-pm2d; python_version>='3.13'",
|
||||
"numpy; python_version>='3.13'",
|
||||
]
|
||||
|
||||
# Vision worker (src/vision_worker/): the FastAPI shell around the runner,
|
||||
# on top of `vision`. Kept separate on purpose (Ruling R9) - VisionSuite's
|
||||
# whole structure exists so a consumer installs only what it needs, and a
|
||||
# later station agent embeds the same runner without being a web service.
|
||||
# It must not drag fastapi/uvicorn onto shop-floor PCs.
|
||||
vision-worker = [
|
||||
"tiemeasureflow[vision]",
|
||||
"fastapi>=0.110.0; python_version>='3.13'",
|
||||
"uvicorn[standard]>=0.30.0; python_version>='3.13'",
|
||||
"pillow>=10.0.0; python_version>='3.13'",
|
||||
"python-multipart>=0.0.6; python_version>='3.13'",
|
||||
]
|
||||
|
||||
[project.scripts]
|
||||
|
||||
@@ -16,7 +16,7 @@ pytest.importorskip(
|
||||
reason=(
|
||||
"the vision tree requires Python >=3.13 (vs-task/vs-measure/vs-pm2d "
|
||||
"declare it upstream); run it with "
|
||||
"`uv run --python 3.13 --extra vision --extra dev pytest "
|
||||
"`uv run --python 3.13 --extra vision-worker --extra dev pytest "
|
||||
"src/vision_worker/tests`"
|
||||
),
|
||||
)
|
||||
@@ -75,6 +75,12 @@ async def test_run_returns_the_named_outputs():
|
||||
body = response.json()
|
||||
assert body["failures"] == []
|
||||
assert any(key.endswith(".diameter") for key in body["outputs"])
|
||||
# Pinned to src/vision/tests/test_runner.py's in-process expectation
|
||||
# (same graph, same image, same tolerance) - the whole point of a shared
|
||||
# engine_version is that the number does not depend on which path
|
||||
# computed it.
|
||||
diameter = next(v for k, v in body["outputs"].items() if k.endswith(".diameter"))
|
||||
assert diameter == pytest.approx(120.0, abs=4.0)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
|
||||
@@ -1975,6 +1975,18 @@ server = [
|
||||
{ name = "weasyprint" },
|
||||
]
|
||||
vision = [
|
||||
{ name = "numpy", marker = "python_full_version >= '3.13'" },
|
||||
{ name = "visionsuite", marker = "python_full_version >= '3.13'" },
|
||||
{ name = "vs-measure", marker = "python_full_version >= '3.13'" },
|
||||
{ name = "vs-pm2d", marker = "python_full_version >= '3.13'" },
|
||||
{ name = "vs-task", marker = "python_full_version >= '3.13'" },
|
||||
]
|
||||
vision-worker = [
|
||||
{ name = "fastapi", marker = "python_full_version >= '3.13'" },
|
||||
{ name = "numpy", marker = "python_full_version >= '3.13'" },
|
||||
{ name = "pillow", marker = "python_full_version >= '3.13'" },
|
||||
{ name = "python-multipart", marker = "python_full_version >= '3.13'" },
|
||||
{ name = "uvicorn", extra = ["standard"], marker = "python_full_version >= '3.13'" },
|
||||
{ name = "visionsuite", marker = "python_full_version >= '3.13'" },
|
||||
{ name = "vs-measure", marker = "python_full_version >= '3.13'" },
|
||||
{ name = "vs-pm2d", marker = "python_full_version >= '3.13'" },
|
||||
@@ -1988,6 +2000,7 @@ requires-dist = [
|
||||
{ name = "asyncmy", marker = "extra == 'server'", specifier = ">=0.2.0" },
|
||||
{ name = "bcrypt", marker = "extra == 'server'", specifier = ">=4.0.0" },
|
||||
{ name = "coverage", marker = "extra == 'dev'", specifier = ">=7.0.0" },
|
||||
{ name = "fastapi", marker = "python_full_version >= '3.13' and extra == 'vision-worker'", specifier = ">=0.110.0" },
|
||||
{ name = "fastapi", marker = "extra == 'server'", specifier = ">=0.110.0" },
|
||||
{ name = "flask", marker = "extra == 'client'", specifier = ">=3.0.0" },
|
||||
{ name = "flask-babel", marker = "extra == 'client'", specifier = ">=4.0.0" },
|
||||
@@ -1997,7 +2010,9 @@ requires-dist = [
|
||||
{ name = "httpx", marker = "extra == 'server'", specifier = ">=0.27.0" },
|
||||
{ name = "jinja2", marker = "extra == 'server'", specifier = ">=3.1.0" },
|
||||
{ name = "kaleido", marker = "extra == 'server'", specifier = ">=0.2.0" },
|
||||
{ name = "numpy", marker = "python_full_version >= '3.13' and extra == 'vision'" },
|
||||
{ name = "pdfplumber", marker = "extra == 'server'", specifier = ">=0.10.0" },
|
||||
{ name = "pillow", marker = "python_full_version >= '3.13' and extra == 'vision-worker'", specifier = ">=10.0.0" },
|
||||
{ name = "pillow", marker = "extra == 'server'", specifier = ">=10.0.0" },
|
||||
{ name = "plotly", marker = "extra == 'server'", specifier = ">=5.0.0" },
|
||||
{ name = "pydantic", specifier = ">=2.0.0" },
|
||||
@@ -2005,10 +2020,13 @@ requires-dist = [
|
||||
{ name = "pytest", marker = "extra == 'dev'", specifier = ">=8.0.0" },
|
||||
{ name = "pytest-asyncio", marker = "extra == 'dev'", specifier = ">=0.23.0" },
|
||||
{ name = "python-dotenv", specifier = ">=1.0.0" },
|
||||
{ name = "python-multipart", marker = "python_full_version >= '3.13' and extra == 'vision-worker'", specifier = ">=0.0.6" },
|
||||
{ name = "python-multipart", marker = "extra == 'server'", specifier = ">=0.0.6" },
|
||||
{ name = "requests", marker = "extra == 'client'", specifier = ">=2.31.0" },
|
||||
{ name = "sqlalchemy", extras = ["asyncio"], marker = "extra == 'server'", specifier = ">=2.0.0" },
|
||||
{ name = "tiemeasureflow", extras = ["vision"], marker = "extra == 'vision-worker'" },
|
||||
{ name = "urllib3", marker = "extra == 'client'", specifier = ">=2.0.0" },
|
||||
{ name = "uvicorn", extras = ["standard"], marker = "python_full_version >= '3.13' and extra == 'vision-worker'", specifier = ">=0.30.0" },
|
||||
{ name = "uvicorn", extras = ["standard"], marker = "extra == 'server'", specifier = ">=0.30.0" },
|
||||
{ name = "visionsuite", marker = "python_full_version >= '3.13' and extra == 'vision'", editable = "vendor/visionsuite/packages/vs-core" },
|
||||
{ name = "vs-measure", marker = "python_full_version >= '3.13' and extra == 'vision'", editable = "vendor/visionsuite/packages/vs-measure" },
|
||||
@@ -2016,7 +2034,7 @@ requires-dist = [
|
||||
{ name = "vs-task", marker = "python_full_version >= '3.13' and extra == 'vision'", editable = "vendor/visionsuite/packages/vs-task" },
|
||||
{ name = "weasyprint", marker = "extra == 'server'", specifier = ">=62.0" },
|
||||
]
|
||||
provides-extras = ["server", "client", "dev", "vision"]
|
||||
provides-extras = ["server", "client", "dev", "vision", "vision-worker"]
|
||||
|
||||
[[package]]
|
||||
name = "tinycss2"
|
||||
|
||||
Reference in New Issue
Block a user