From 4180d3513ca65cb3e3b068f0520628d07867e272 Mon Sep 17 00:00:00 2001 From: malice Date: Fri, 22 May 2026 22:42:47 -0600 Subject: [PATCH] shared: promote dem.py to shared/ (prep for navi-offroute) (#9) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 Co-authored-by: Claude Opus 4.7 (1M context) --- backend/services/navi_geo/admin.py | 2 +- backend/services/navi_geo/geo_route.py | 2 +- backend/{services/navi_geo => shared}/dem.py | 12 +++++++++--- backend/shared/tests/test_dem.py | 18 ++++++++++++++++++ 4 files changed, 29 insertions(+), 5 deletions(-) rename backend/{services/navi_geo => shared}/dem.py (94%) create mode 100644 backend/shared/tests/test_dem.py diff --git a/backend/services/navi_geo/admin.py b/backend/services/navi_geo/admin.py index 83ccd27..153237b 100644 --- a/backend/services/navi_geo/admin.py +++ b/backend/services/navi_geo/admin.py @@ -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 diff --git a/backend/services/navi_geo/geo_route.py b/backend/services/navi_geo/geo_route.py index beb1387..316e82e 100644 --- a/backend/services/navi_geo/geo_route.py +++ b/backend/services/navi_geo/geo_route.py @@ -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') diff --git a/backend/services/navi_geo/dem.py b/backend/shared/dem.py similarity index 94% rename from backend/services/navi_geo/dem.py rename to backend/shared/dem.py index 2b9a8f1..03b29be 100755 --- a/backend/services/navi_geo/dem.py +++ b/backend/shared/dem.py @@ -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 diff --git a/backend/shared/tests/test_dem.py b/backend/shared/tests/test_dem.py new file mode 100644 index 0000000..e74d2ce --- /dev/null +++ b/backend/shared/tests/test_dem.py @@ -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)