Summary
Part of epic #2211. Phase 2 deliverable: one shared transform/georef resolver that every backend (read and write) calls, with parity tests across the supported cases. Replaces hand-copied coord-to-transform and georef classification logic that currently lives in multiple modules.
Scope
Refactor + parity tests. No public API change.
Files
- Modify:
xrspatial/geotiff/_coords.py — promote/centralize coords_to_transform, add resolve_georef() that returns a typed result.
- Modify:
xrspatial/geotiff/_attrs.py — georef_status derivation routes through resolve_georef().
- Modify:
xrspatial/geotiff/_writers/eager.py, _writers/gpu.py, _writers/vrt.py — call the resolver instead of inline logic.
- Modify:
xrspatial/geotiff/_backends/vrt.py — call the resolver.
- Create:
xrspatial/geotiff/tests/test_georef_resolver_parity_2211.py.
Resolver contract
- Input: a DataArray, or coord arrays + crs hint + transform hint.
- Output: a
GeorefResolution dataclass:
transform: GeoTransform | None
georef_status: Literal["none","coords","transform-only","crs-only","rotated-dropped","full"]
dropped_reason: str | None
applied_no_georef_marker: bool
- Owns: coord-to-transform inference, no-georef marker behavior, degenerate axis policy, rotated-affine read-only/drop policy.
Parity tests
Cover at minimum:
y/x dim names
lat/lon dim names
row/col dim names (no georef)
- transform-only (no CRS)
- CRS-only (no transform)
- rotated-affine dropped on read
For each case, assert identical GeorefResolution produced from every supported call site.
Acceptance
- All 6 fixture cases produce identical
GeorefResolution across eager/Dask/VRT call sites.
xrspatial/geotiff/tests/test_georef_status_2136.py and the test_allow_rotated_* suites still pass.
- No call site outside
_coords.py / _attrs.py builds a GeoTransform by hand on the read or write paths covered.
- No public API change.
Closes part of #2211.
Summary
Part of epic #2211. Phase 2 deliverable: one shared transform/georef resolver that every backend (read and write) calls, with parity tests across the supported cases. Replaces hand-copied coord-to-transform and georef classification logic that currently lives in multiple modules.
Scope
Refactor + parity tests. No public API change.
Files
xrspatial/geotiff/_coords.py— promote/centralizecoords_to_transform, addresolve_georef()that returns a typed result.xrspatial/geotiff/_attrs.py—georef_statusderivation routes throughresolve_georef().xrspatial/geotiff/_writers/eager.py,_writers/gpu.py,_writers/vrt.py— call the resolver instead of inline logic.xrspatial/geotiff/_backends/vrt.py— call the resolver.xrspatial/geotiff/tests/test_georef_resolver_parity_2211.py.Resolver contract
GeorefResolutiondataclass:transform: GeoTransform | Nonegeoref_status: Literal["none","coords","transform-only","crs-only","rotated-dropped","full"]dropped_reason: str | Noneapplied_no_georef_marker: boolParity tests
Cover at minimum:
y/xdim nameslat/londim namesrow/coldim names (no georef)For each case, assert identical
GeorefResolutionproduced from every supported call site.Acceptance
GeorefResolutionacross eager/Dask/VRT call sites.xrspatial/geotiff/tests/test_georef_status_2136.pyand thetest_allow_rotated_*suites still pass._coords.py/_attrs.pybuilds aGeoTransformby hand on the read or write paths covered.Closes part of #2211.