Hide read_to_array from xrspatial.geotiff public namespace (#1708)#1711
Merged
brendancol merged 2 commits intoMay 12, 2026
Merged
Conversation
Contributor
There was a problem hiding this comment.
Pull request overview
This PR tightens xrspatial.geotiff’s public namespace by preventing the internal helper read_to_array (defined in xrspatial.geotiff._reader) from being inadvertently re-exported via xrspatial.geotiff.__init__, while keeping all internal call paths working.
Changes:
- Rebinds
_reader.read_to_arrayas a private name (_read_to_array) insidexrspatial/geotiff/__init__.pyand updates internal call sites accordingly. - Updates
test_band_validation_1673.pyto importread_to_arrayfrom the canonical private module path (xrspatial.geotiff._reader). - Adds a regression test module to ensure
read_to_arraydoes not reappear in the top-levelxrspatial.geotiffnamespace.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
xrspatial/geotiff/__init__.py |
Stops leaking read_to_array into the public namespace while preserving internal usage via _read_to_array. |
xrspatial/geotiff/tests/test_band_validation_1673.py |
Switches tests to import read_to_array directly from the private _reader module. |
xrspatial/geotiff/tests/test_namespace_no_leak_1708.py |
Adds regression coverage that enforces the “no public read_to_array export” namespace contract. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
The api-consistency sweep on 2026-05-12 flagged an orphan-API leak:
xrspatial/geotiff/__init__.py imports ``read_to_array`` from ``._reader``
so the eager ``open_geotiff`` body can call it, but as a side-effect
that bound the name in the public ``xrspatial.geotiff`` namespace.
``__all__`` does not list it, the module-level "Public API" docstring
does not document it, and the Sphinx pages do not advertise it -- but
``from xrspatial.geotiff import read_to_array`` worked anyway.
The library's own ``test_band_validation_1673.py`` imported it that way
six times, proving the leak was being used as if it were public.
External users who pattern-matched against the test would also be
relying on a name the maintainer never committed to support. A future
cleanup that removed the top-level import would have broken them with
no deprecation path.
This change binds the helper under a leading-underscore name in
``__init__.py``:
from ._reader import UnsafeURLError
from ._reader import read_to_array as _read_to_array
and updates each internal call site (six call sites: ``open_geotiff``,
the dask delayed window reader, and four GPU-fallback paths in
``read_geotiff_gpu``). The single test file that imported the leaked
name is updated to import from ``xrspatial.geotiff._reader`` directly,
which is the canonical private path.
``test_namespace_no_leak_1708.py`` pins the namespace contract:
``read_to_array`` must not be an attribute of ``xrspatial.geotiff``,
``__all__`` must not list it, and the canonical
``xrspatial.geotiff._reader.read_to_array`` import must still work.
This guards against a future maintainer re-adding a bare
``from ._reader import read_to_array`` line without realising it would
re-leak the name.
No runtime behaviour change in the supported public API. The deprecated
``plot_geotiff`` continues to be exposed at the top level for backward
compatibility because it has a documented deprecation path; this commit
takes no position on ``plot_geotiff``.
Closes #1708.
143f9d4 to
9b9eb82
Compare
The #1708 cleanup hid ``read_to_array`` from ``xrspatial.geotiff`` and bound the internal alias as ``_read_to_array``. The existing #1624 trace test still set ``xrspatial.geotiff.read_to_array`` via monkeypatch, which now raises ``AttributeError`` at the setattr call. Patch the alias the dask worker actually reads instead.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
The api-consistency sweep on 2026-05-12 flagged an orphan-API leak.
xrspatial/geotiff/__init__.pyimportsread_to_arrayfrom._readerso the eageropen_geotiffbody can call it, but as a side-effect that bound the name in the publicxrspatial.geotiffnamespace.__all__does not list it, the module-level "Public API" docstring does not document it, and the Sphinx pages do not advertise it -- yetfrom xrspatial.geotiff import read_to_arrayworked anyway.The library's own
test_band_validation_1673.pyimported it that way six times, proving the leak was being used as if it were public. External users who pattern-matched against the test would also be relying on a name the maintainer never committed to support. A future cleanup that removed the top-level import would have broken them with no deprecation path.This PR:
__init__.py:from ._reader import read_to_array as _read_to_array.open_geotiff, one in the dask delayed window reader, four GPU-fallback paths inread_geotiff_gpu).test_band_validation_1673.pyto import fromxrspatial.geotiff._readerdirectly, which is the canonical private path.test_namespace_no_leak_1708.pypinning the namespace contract.No runtime behaviour change in the supported public API.
Closes #1708.
Test plan
pytest xrspatial/geotiff/tests/test_namespace_no_leak_1708.pycovers the no-leak contract (4 tests) and the canonical private import.pytest xrspatial/geotiff/tests/test_band_validation_1673.pystill passes (the updated imports).pytest xrspatial/geotiff/tests/test_signature_annotations_1654.py xrspatial/geotiff/tests/test_signature_parity_1631.py xrspatial/geotiff/tests/test_features.py -k "all or contract or signature"passes (__all__and namespace contracts intact).open_geotiff(eager + windowed) andread_geotiff_daskproduce the same shapes and data as before.