Files
F-r-ldraledigplannerare/new-features/fix-deprecations-backend-plan.md
T
2026-09-20 11:37:11 +02:00

70 lines
4.0 KiB
Markdown

# Fix backend deprecation warnings
## Context
`uv run pytest` on `backend/` emits 26 `DeprecationWarning`s. They are noise in CI output and two of the four sources are real forward-compat debt in our own code — the Starlette 422 constant is already renamed upstream, and Alembic's `version_path_separator` is superseded. Goal: our code emits zero deprecation warnings.
Confirmed inventory (Python 3.14.0, fastapi 0.136.3, starlette 1.2.1, alembic 1.18.4, slowapi 0.1.9):
| Source | Count | Ours? |
|---|---|---|
| `HTTP_422_UNPROCESSABLE_ENTITY` → use `HTTP_422_UNPROCESSABLE_CONTENT` | 8 | yes — 20 call sites |
| `alembic/config.py:612` — `No path_separator found in configuration` | 12 | yes — `backend/alembic.ini` |
| `slowapi/extension.py:717` — `asyncio.iscoroutinefunction` | 6 | no — upstream, out of scope |
Decision made: fix our code only. No `filterwarnings` config is added; the slowapi warning stays visible as an upstream reminder.
**Baseline:** 4 tests already fail on `main` (`test_migration_004_backfill.py::test_flexible_yearly_wish_keeps_the_same_bounding_range_every_year`, `test_leave_wish_repository.py::…test_flexible_series_keeps_one_bounding_range_per_year_unshifted`, two in `test_allocation_service.py`). These come from the uncommitted in-flight work in `app/entities/leave_wish.py` / `app/services/allocation_service.py` and are **unrelated** to this change. Expected result after the change: still exactly those 4, no more.
## Change 1 — rename the 422 constant (20 sites, 15 files)
Mechanical rename, same numeric value (422), so no wire-format or frontend impact:
```
status.HTTP_422_UNPROCESSABLE_ENTITY → status.HTTP_422_UNPROCESSABLE_CONTENT
```
All sites are in `backend/app/routers/`. Representative files: `workspace.py` (3 sites, lines 51/94/223 — inside conditional expressions, not plain raises), `settings.py` (3), `fetch_data.py` (2), `leave_wishes.py` (2), `plan.py` (2), `preschool_planning_days.py` (2), plus one each in `auth.py`, `calendar.py`, `day_overrides.py`, `planned_day_exclusions.py`, `planned_days.py`, `vacation_days.py`.
Notes:
- `status` is already imported from `fastapi` in every one of these files — no import changes.
- `status.HTTP_422_UNPROCESSABLE_CONTENT` is verified present in the installed starlette (evaluates to `422`).
- No test file references the constant by name (`git grep UNPROCESSABLE -- tests` is empty), so tests need no update.
- The warnings attributed to `fastapi/routing.py:328` are our handler frames raising through the dependency call — they disappear with this rename too.
## Change 2 — Alembic `path_separator`
`backend/alembic.ini` currently has:
```ini
prepend_sys_path = .
version_path_separator = os
```
Replace `version_path_separator = os` with `path_separator = os`. In Alembic ≥1.16 `path_separator` governs both `prepend_sys_path` and `version_locations`, and its absence is what triggers the legacy-splitting warning. Leave `prepend_sys_path = .` and the annotated `sqlalchemy.url` fallback untouched.
## Out of scope
- slowapi's `asyncio.iscoroutinefunction` warning — upstream, no released fix.
- `typing.Dict` in `app/utils/holidays.py` and `datetime.timezone.utc` in `app/services/auth_service.py` — older spellings, but not deprecated and not warning sources.
- The 4 pre-existing test failures.
## Verification
Delegate to a **Haiku** subagent (per the cost rule); require raw verbatim output, from `backend/`:
```bash
uv run ruff check .
uv run ruff format --check .
uv run pytest
uv run alembic upgrade head # exercises the alembic.ini change directly
```
Acceptance criteria:
1. The warnings summary contains **only** the 6 `slowapi/extension.py:717` lines — no `UNPROCESSABLE_ENTITY`, no `path_separator`, count down from 26 to 6.
2. Failure list is exactly the 4 baseline failures above; pass count unchanged at 860.
3. Coverage still ≥ the `--cov-fail-under=80` gate (no gate changes).
4. `alembic upgrade head` completes without the `path_separator` warning.
Then `graphify update .`.