Skip to content

Accept upper-case base32 in the pure-Python decoder - #51

Open
gaoflow wants to merge 1 commit into
hkwi:masterfrom
gaoflow:pure-python-uppercase-base32
Open

Accept upper-case base32 in the pure-Python decoder#51
gaoflow wants to merge 1 commit into
hkwi:masterfrom
gaoflow:pure-python-uppercase-base32

Conversation

@gaoflow

@gaoflow gaoflow commented Jul 29, 2026

Copy link
Copy Markdown

The library ships the same public API twice: the _geohash Rust/PyO3 extension and the pure-Python geohash.py fallback used when the extension is not importable. The extension's build_base32_decode_map (src/geohash_core.rs) deliberately accepts upper-case base32 letters, but the fallback's _base32_map is lower-case only, so the decode path behaves differently depending on whether the compiled extension is present:

>>> import geohash                      # extension not built
>>> geohash.decode('EZS42')
Traceback (most recent call last):
  ...
KeyError: 'E'
>>> geohash.decode('ezs42')
(42.60498046875, -5.60302734375)

Every entry point that decodes a code -- decode, decode_exactly, bbox, neighbors, expand -- goes through _decode_c2i, so all five raise a bare KeyError on an upper-case geohash in the fallback while the extension returns a result. This is a widely hit path: PyPI ships a single x86_64 Linux wheel plus the sdist, and the README documents copying geohash.py standalone, so macOS / Windows / aarch64 / musllinux installs and the standalone-copy use all run the fallback.

This populates _base32_map with the upper-case keys as well, mirroring the extension's map exactly -- only the base32 letters get an upper-case form, so a i l o and A I L O stay invalid and mixed case works per character. It also replaces the bare KeyError for an out-of-alphabet character with the same ValueError("geohash code is [0123456789bcdefghjkmnpqrstuvwxyz]+") the extension raises through map_error (src/lib.rs).

Tests add upper-case, mixed-case and invalid-character cases across all five decode entry points. I also cross-checked the fallback against the built extension over 12k lower/upper/mixed geohashes and 3k invalid inputs; value and error type now match on every case, and the existing tests still pass.

The _geohash extension's build_base32_decode_map accepts upper-case
base32 letters, but the pure-Python fallback's _base32_map is
lower-case only, so decode/decode_exactly/bbox/neighbors/expand raise a
bare KeyError on an upper-case geohash whenever the extension is not
built. Populate _base32_map with the upper-case keys as well, and raise
ValueError with the same message the extension reports for a character
outside the alphabet instead of leaking KeyError.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant