Architecture¶
This page describes how the engine, the Python extension and ras-commander divide the work, how a read passes between them, and the rules that keep native results identical to h5py. Together, the engine and the extension are ras-commander's default HDF engine; h5py is the reference implementation and the fallback.
Three layers¶
ras-commander (Python, separate repository)
Hdf* classes ── public API, unchanged
ras_commander/fast_hdf.py ── routing: auto | h5py | native, sessions, fallback
│
▼
ras_commander_fast_hdf (python/, PyO3 extension)
converts engine results to NumPy arrays, dicts and Python exceptions;
native kernels: mesh polygons, fluvial/pluvial, PMTiles and vector exports, RAS text
│
▼
ras-commander-rust (crates/ras-commander-rust, pure Rust library)
HEC-RAS knowledge: project/plan catalog, HDF layouts, identities, units, time, CRS evidence
│
▼
hdf5-reader / hdf5-core (vendor/, pure Rust HDF5 decoding)
- The engine (
crates/ras-commander-rust) knows how HEC-RAS stores things: which datasets and tables exist in each HEC-RAS version, how mesh topology is laid out, how cross-section identities, time stamps and units are recorded. It has no Python in it, so other Rust programs can use it directly. - The extension (
python/) is the only place Python appears. It turns engine results into NumPy arrays and plain Python objects, maps engine errors to Python exceptions, contains panics, and adds kernels that only ras-commander needs. - ras-commander decides, for each read, whether to use the extension, and builds the same pandas, xarray and GeoPandas results from either source.
Packaging¶
ras-commander 0.107.1 and later declare ras-commander-fast-hdf>=0.1,<0.2 as
a core dependency with an environment marker that limits it to CPython on
Windows x64, Linux x64 and macOS arm64, the platforms with published wheels.
pip install ras-commander therefore installs the engine there and never
tries to build the Rust source distribution elsewhere. Where the extension is
not installed, ras-commander reads every dataset with h5py. Setting
RAS_COMMANDER_FAST_HDF=h5py turns the native engine off where it is
installed.
How a read flows¶
- A public ras-commander method (for example
HdfResultsMesh.get_mesh_timeseries) asksfast_hdffor a dataset instead of opening it with h5py. fast_hdfchecks the mode (RAS_COMMANDER_FAST_HDFor the method'sengine=argument) and whether this method is qualified for native reads.- In
autoornativemode it calls the extension, inside a session that lives for the duration of the public call. - The extension calls the engine, which validates the layout, budgets the read, decodes it and returns typed values or a typed error.
- On success, ras-commander builds its result exactly as it would from h5py.
On a refusal,
autorepeats the read with h5py;nativeraisesFastHdfError.
Exact or refuse¶
The engine's central rule: return exactly what h5py would return, or refuse
with a typed reason. It never guesses an encoding, a CRS, a unit or a layout,
and never repairs data. Because auto falls back to h5py on every refusal, a
refusal costs only speed, while a wrong value would be a silent error in an
engineering result. When in doubt, the engine refuses.
Refusals are reported with one status vocabulary (see Rust engine):
unavailable (canonically absent), unsupported (present but not proven, with
a code such as encoding or resource_limit), corrupt (damaged or
contradictory) and delegated (checked by another reader).
Qualification¶
A native read path is used by default only after it has been proven identical
to h5py on real files. ras-commander's equivalence suites run every public
method on a corpus of HEC-RAS 5.x–7.x files in all three modes and compare
values, dtypes, columns, index, attributes, CRS and exceptions. Methods the
corpus has not exercised natively are marked in ras-commander and stay on h5py
in auto mode. See Testing and qualification.
Safety¶
- The engine is
#![forbid(unsafe_code)]. The vendored HDF5 reader usesunsafeonly for read-only memory mapping and a few decoding paths. - Every count, offset and size read from a file is checked before use, and release builds keep integer-overflow checks on.
- Every read is budgeted before allocation (2 GiB of decoded values per call by default). Larger reads are refused; ras-commander then reads them in chunks.
- A panic that escapes despite this becomes an ordinary Python exception
(
python/src/panic_guard.rs), soautofalls back instead of the process crashing. - Files are opened read-only. Sessions are closed when the public ras-commander call returns, so no file stays locked on Windows.
Compatibility handshake¶
The extension exports API_VERSION. ras-commander uses the extension only
when that number equals the one it was built against; otherwise it logs one
warning and uses h5py for everything (or raises in native mode). This lets
the two packages be upgraded independently, within the version range
ras-commander declares, without ever mixing incompatible contracts. See Releasing.