shared: promote dem.py to shared/ (prep for navi-offroute) (#9)

Pure refactor, no behavior change. Moves services/navi_geo/dem.py to
shared/dem.py (verbatim logic + env override; only docstring + location
changed) and re-points navi-geo's two imports (geo_route.py, admin.py) to
`from shared.dem import ...`.

Per extraction-8-phase-a.md §5/§13.1: navi-offroute (#18) needs the same
DEMReader, so a single source of truth in shared/ beats a third copy. Second
shared/ promotion after PR #7 round-2's shared/git_sha.py; navi-offroute will
`from shared.dem import DEMReader` directly.

Adds shared/tests/test_dem.py (dem_path default + NAVI_DEM_PMTILES override).
navi-geo behavior unchanged (test_reverse_bundle mocks geo_route._DEM, agnostic
to DEMReader's location). Full suite: 104 passed / 1 skipped (+2).

Co-authored-by: zvx-echo6 <mj@k7zvx.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
malice 2026-05-22 22:42:47 -06:00 committed by GitHub
commit 4180d3513c
4 changed files with 29 additions and 5 deletions

View file

@ -19,7 +19,7 @@ from shared.admin_info import build_info_response
from .geocode import photon_url
from .landclass_client import landclass_url
from .netsyms import db_path as netsyms_db_path
from .dem import dem_path
from shared.dem import dem_path
from .geo_route import tz_db_path
from .address_book import _config_path as address_book_path

View file

@ -23,7 +23,7 @@ from flask import Blueprint, request, jsonify
from . import geocode as geocode_mod
from . import landclass_client
from .geocode import photon_url, _parse_photon_features
from .dem import DEMReader, dem_path
from shared.dem import DEMReader, dem_path
logger = logging.getLogger('navi_geo.geo_route')

View file

@ -1,10 +1,16 @@
"""
DEM tile reader (port of recon's offroute/dem.py).
Shared DEM tile reader (port of recon's offroute/dem.py).
Reads elevation tiles from planet-dem.pmtiles (Terrarium-encoded WebP),
decodes them into numpy arrays, and provides a stitched elevation grid
for a given bounding box. navi-geo uses ``sample_point`` for the reverse
bundle's ``elevation_m``. Faithful port; only change is the env-override path.
for a given bounding box.
Lives in ``shared/`` because it's designed to be used by multiple navi-*
services that need elevation: navi-geo's reverse bundle uses ``sample_point``
for ``elevation_m``, and other elevation-consuming services import the same
``DEMReader`` rather than each carrying a copy. The DEM path is env-overridable
via ``NAVI_DEM_PMTILES`` (``dem_path()``). Faithful logic; only the location and
docstring changed in the promotion.
"""
import math
import os

View file

@ -0,0 +1,18 @@
"""Hermetic tests for shared.dem — no live PMTiles I/O (the real file is 657 GB).
Behavioural coverage of DEMReader.sample_point already lives in navi-geo's
test_reverse_bundle.py (via the geo_route._DEM mock); these only pin the shared
module's import + the env-override path contract.
"""
from shared.dem import DEMReader, dem_path, DEFAULT_DEM_PATH # noqa: F401 (import smoke)
def test_dem_path_default_when_unset(monkeypatch):
monkeypatch.delenv('NAVI_DEM_PMTILES', raising=False)
assert dem_path() == DEFAULT_DEM_PATH
def test_dem_path_env_override(monkeypatch, tmp_path):
custom = tmp_path / 'custom.pmtiles'
monkeypatch.setenv('NAVI_DEM_PMTILES', str(custom))
assert str(dem_path()) == str(custom)