Skip to content

Commit a0a70aa

Browse files
authored
geotiff: rename write_vrt's vrt_path kwarg to path (#1946) (#1962)
* geotiff: rename write_vrt's vrt_path kwarg to path (#1946) write_vrt's first positional kwarg was vrt_path while to_geotiff and write_geotiff_gpu use path, so callers passing write_vrt(path=...) hit TypeError on the only writer whose docstring advertises parity with the other two. Adds path as the canonical kwarg, keeps vrt_path as a deprecated alias (DeprecationWarning), and raises TypeError if both are supplied. Mirrors the existing crs / crs_wkt shim in the same writer (#1715). Tests pin positional and keyword forms, the deprecation warning on vrt_path, the both-supplied refusal, the cross-writer signature parity, and a round-trip equivalence between the two kwarg names. * geotiff: address PR #1962 review / CI fixes * geotiff: address PR #1962 review (sentinel for write_vrt path, docstring TypeError note) Switch write_vrt's path kwarg from a None default to a private _VRT_PATH_MISSING_SENTINEL so an explicit write_vrt(path=None, ...) or positional write_vrt(None, sources) is rejected with a clear TypeError naming the offending kwarg, instead of falling through to the "missing required argument" branch. Mirrors the existing _CRS_WKT_DEPRECATED_SENTINEL pattern in the same writer. Also mirror the crs_wkt entry's "passing both raises TypeError" wording in the write_vrt entry of the geotiff Public API docstring. Updates the test_write_vrt_path_annotated annotation assertion from 'str | None' to 'str' to match the new sentinel-typed default and adds two new regression tests pinning the keyword and positional explicit-None cases.
1 parent 94c62fb commit a0a70aa

5 files changed

Lines changed: 327 additions & 13 deletions

File tree

xrspatial/geotiff/__init__.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,10 @@
2626
write_geotiff_gpu(data, path, ...)
2727
GPU-only writer using nvCOMP. ``to_geotiff(..., gpu=True)`` calls this
2828
internally.
29-
write_vrt(vrt_path, source_files, ...)
30-
Generate a VRT mosaic XML from a list of GeoTIFF files.
29+
write_vrt(path, source_files, ...)
30+
Generate a VRT mosaic XML from a list of GeoTIFF files. ``vrt_path``
31+
is kept as a deprecated alias for ``path``; passing both ``path`` and
32+
``vrt_path`` raises ``TypeError`` (#1946).
3133
"""
3234
from __future__ import annotations
3335

xrspatial/geotiff/_runtime.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,21 @@
3939
# (forward verbatim to read_vrt). Mirrors the on_gpu_failure pattern. See
4040
# issue #1810.
4141
_MISSING_SOURCES_SENTINEL = object()
42+
# ``write_vrt`` historically named its first positional kwarg ``vrt_path``
43+
# while ``to_geotiff`` / ``write_geotiff_gpu`` use ``path``. The deprecation
44+
# shim adds ``path`` as the new name and accepts ``vrt_path`` with a
45+
# DeprecationWarning. The sentinel pattern distinguishes "user passed
46+
# vrt_path= explicitly" from "user passed nothing", which is the same
47+
# rationale ``_CRS_WKT_DEPRECATED_SENTINEL`` documents above. See
48+
# issue #1946.
49+
_VRT_PATH_DEPRECATED_SENTINEL = object()
50+
# ``write_vrt`` also needs to distinguish "user passed path= explicitly"
51+
# (including an explicit ``path=None``, which is an error) from "user
52+
# passed nothing" (fall through to the ``vrt_path`` shim). Without this
53+
# sentinel, ``write_vrt(None, sources)`` silently fell through to the
54+
# ``path is None`` branch and raised a "missing required argument"
55+
# TypeError for the wrong reason. See PR #1962 review.
56+
_VRT_PATH_MISSING_SENTINEL = object()
4257

4358

4459
# Spatial dim names recognised on 3D writer inputs. ``y``/``x`` are the

xrspatial/geotiff/_writers/vrt.py

Lines changed: 70 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,25 @@
11
"""VRT writer entry point.
22
33
Wraps ``_vrt.write_vrt`` with the public ``write_vrt`` surface:
4-
deprecation handling for ``crs_wkt`` (#1715), normalisation of the
5-
``crs`` kwarg to WKT via ``_resolve_crs_to_wkt``, and the parity
6-
docstring vs ``to_geotiff`` / ``write_geotiff_gpu``.
4+
deprecation handling for ``crs_wkt`` (#1715) and ``vrt_path`` (#1946),
5+
normalisation of the ``crs`` kwarg to WKT via ``_resolve_crs_to_wkt``,
6+
and the parity docstring vs ``to_geotiff`` / ``write_geotiff_gpu``.
77
"""
88
from __future__ import annotations
99

1010
import warnings
1111

1212
from .._crs import _resolve_crs_to_wkt
13-
from .._runtime import _CRS_WKT_DEPRECATED_SENTINEL
13+
from .._runtime import (
14+
_CRS_WKT_DEPRECATED_SENTINEL,
15+
_VRT_PATH_DEPRECATED_SENTINEL,
16+
_VRT_PATH_MISSING_SENTINEL,
17+
)
1418

1519

16-
def write_vrt(vrt_path: str, source_files: list[str], *,
20+
def write_vrt(path: str = _VRT_PATH_MISSING_SENTINEL,
21+
source_files: list[str] | None = None, *,
22+
vrt_path: str | None = _VRT_PATH_DEPRECATED_SENTINEL,
1723
relative: bool = True,
1824
crs: int | str | None = None,
1925
crs_wkt: str | None = _CRS_WKT_DEPRECATED_SENTINEL,
@@ -22,10 +28,19 @@ def write_vrt(vrt_path: str, source_files: list[str], *,
2228
2329
Parameters
2430
----------
25-
vrt_path : str
26-
Output .vrt file path.
31+
path : str
32+
Output .vrt file path. Mirrors the ``path`` kwarg on
33+
``to_geotiff`` and ``write_geotiff_gpu`` so the writer trio
34+
shares a single destination-arg name (issue #1946).
2735
source_files : list of str
2836
Paths to the source GeoTIFF files.
37+
vrt_path : str, optional
38+
Deprecated alias for ``path``. Emits ``DeprecationWarning`` when
39+
supplied; passing both ``path`` and ``vrt_path`` raises
40+
``TypeError``. Kept so existing callers (``write_vrt(vrt_path,
41+
sources)`` positional or ``write_vrt(vrt_path=...)`` keyword)
42+
keep working through the deprecation window. New code should
43+
use ``path``. See issue #1946.
2944
relative : bool, optional
3045
Store source paths relative to the VRT file (default True).
3146
crs : int, str, or None, optional
@@ -60,6 +75,53 @@ def write_vrt(vrt_path: str, source_files: list[str], *,
6075
# historic ``crs_wkt`` path; the new ``crs`` path normalises through
6176
# ``_resolve_crs_to_wkt`` before forwarding because the internal
6277
# writer still only speaks WKT.
78+
#
79+
# The ``path`` / ``vrt_path`` shim resolves the destination kwarg
80+
# before any other processing so the rest of the function works
81+
# uniformly against a single ``vrt_path`` local. ``path`` is the
82+
# new name (parity with to_geotiff / write_geotiff_gpu); ``vrt_path``
83+
# is kept as a deprecated alias to preserve back-compat for callers
84+
# using either positional ``write_vrt(vrt_path, sources)`` or
85+
# keyword ``write_vrt(vrt_path=...)``.
86+
path_passed = path is not _VRT_PATH_MISSING_SENTINEL
87+
vrt_path_passed = vrt_path is not _VRT_PATH_DEPRECATED_SENTINEL
88+
if path_passed and vrt_path_passed:
89+
# Both supplied is ambiguous regardless of whether the two values
90+
# happen to be the same string. Refuse rather than silently
91+
# picking one. Mirrors the same rule the ``crs`` / ``crs_wkt``
92+
# shim below applies.
93+
raise TypeError(
94+
"write_vrt: pass either 'path' or the deprecated 'vrt_path' "
95+
"alias, not both.")
96+
if vrt_path_passed:
97+
warnings.warn(
98+
"write_vrt(..., vrt_path=...) is deprecated; use path=... "
99+
"instead. The kwarg was renamed for parity with to_geotiff "
100+
"and write_geotiff_gpu, which already accept 'path' as the "
101+
"destination kwarg.",
102+
DeprecationWarning,
103+
stacklevel=2,
104+
)
105+
path = vrt_path
106+
elif not path_passed:
107+
# Neither name supplied. Match the previous ``TypeError: missing
108+
# required positional argument`` semantics by raising rather than
109+
# forwarding the sentinel into ``_write_vrt_internal``.
110+
raise TypeError(
111+
"write_vrt: missing required argument 'path'")
112+
if path is None:
113+
# Explicit ``path=None`` (including positional ``write_vrt(None,
114+
# sources)``) is rejected up front so the error message names the
115+
# offending kwarg instead of crashing deep in
116+
# ``os.path.dirname(os.path.abspath(None))``. The sentinel default
117+
# on ``path`` is what lets us distinguish this case from "caller
118+
# passed nothing" above.
119+
raise TypeError(
120+
"write_vrt: 'path' must be a str, got None")
121+
if source_files is None:
122+
raise TypeError(
123+
"write_vrt: missing required argument 'source_files'")
124+
63125
crs_wkt_passed = crs_wkt is not _CRS_WKT_DEPRECATED_SENTINEL
64126
if crs is not None and crs_wkt_passed:
65127
# Both supplied is ambiguous regardless of whether the WKT happens
@@ -83,7 +145,7 @@ def write_vrt(vrt_path: str, source_files: list[str], *,
83145

84146
from .._vrt import write_vrt as _write_vrt_internal
85147
return _write_vrt_internal(
86-
vrt_path, source_files,
148+
path, source_files,
87149
relative=relative,
88150
crs_wkt=resolved_wkt,
89151
nodata=nodata,

xrspatial/geotiff/tests/test_signature_annotations_1654.py

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -83,10 +83,24 @@ def test_write_geotiff_gpu_path_annotated():
8383
assert 'BinaryIO' in ann
8484

8585

86+
def test_write_vrt_path_annotated():
87+
"""``write_vrt(path, ...)`` is str-only (VRT writes are path-only by
88+
design; no file-like buffer support). After #1946 the canonical name
89+
is ``path`` (parity with ``to_geotiff`` / ``write_geotiff_gpu``).
90+
The annotation is plain ``str``: the default value is a private
91+
sentinel (not ``None``) so the deprecation shim can distinguish
92+
``write_vrt(path=None, ...)`` (rejected with TypeError) from a
93+
caller who omitted ``path`` entirely (routed through the ``vrt_path``
94+
alias). See PR #1962 review."""
95+
assert _annotation(write_vrt, 'path') == 'str'
96+
97+
8698
def test_write_vrt_vrt_path_annotated():
87-
"""``write_vrt(vrt_path, ...)`` stays str-only (VRT writes are
88-
path-only by design; no file-like buffer support)."""
89-
assert _annotation(write_vrt, 'vrt_path') == 'str'
99+
"""The deprecated ``vrt_path`` alias keeps the same ``str | None``
100+
annotation as ``path`` (str-only at the type level; ``None`` only
101+
appears because the sentinel default lets the shim detect omission).
102+
Pinned so a future re-rename does not silently widen the alias."""
103+
assert _annotation(write_vrt, 'vrt_path') == 'str | None'
90104

91105

92106
# --- source: str or BinaryIO (open_geotiff is the public dispatch) ---

0 commit comments

Comments
 (0)