rivia.utils¶
Shared helpers: path handling, validation, logging.
Shared helpers (path handling, validation, logging).
- rivia.utils.assert_path_writable(path)[source]¶
Raise
PermissionErrorearly if path cannot be written.Tests the actual filesystem operations that a write requires:
If the file exists: attempts a rename to a temporary name and back. On Windows this requires
DELETEaccess on the source — the same permission GDAL needs to delete-and-rewrite the file. GIS applications (ArcGIS, QGIS, RASMapper) typically hold files open withoutFILE_SHARE_DELETE, so the rename fails if any of them have the file open, even on network/SMB shares whereCreateFileWchecks are unreliable.If the file does not exist: creates and immediately removes a zero-byte sentinel in the parent directory to verify write permission.
- Parameters:
- Raises:
PermissionError – If the path cannot be written, with a message identifying the file and suggesting the user close it in any open application.
- Return type:
- rivia.utils.check_sim_date(date)[source]¶
Raise
ValueErrorif date is not inDDMONYYYYformat.The month abbreviation is case-insensitive (e.g.
"01jan2020"is valid).
- rivia.utils.check_sim_time(time_str)[source]¶
Raise
ValueErrorif time_str is notHHMMorHHMMSSwith HH <= 24.
- rivia.utils.format_hec_datetime(d)[source]¶
Format a
datetime.datetimeas a HEC-RAS"DDMONYYYY HH:MM:SS"string.This is the canonical format used in HEC-RAS HDF5 attributes and runtime log timestamps (space separator, colon-separated 24-hour time, uppercase month abbreviation).
- Parameters:
- Returns:
e.g.
"01OCT2024 00:00:02"- Return type:
Examples
>>> import datetime as dt >>> format_hec_datetime(dt.datetime(2024, 10, 1, 0, 0, 2)) '01OCT2024 00:00:02'
- rivia.utils.log_call(level=20)[source]¶
Decorator that logs when a function is called.
- Parameters:
level (int) –
logginglevel constant (e.g.logging.INFO,logging.DEBUG). Defaults tologging.INFO.
Examples
>>> from rivia.utils import log_call >>> import logging >>> @log_call(logging.INFO) ... def my_func(): ...
- rivia.utils.normalize_sim_end_time(date, time)[source]¶
Normalize a HEC-RAS simulation end
(date, time)pair.HEC-RAS represents midnight as
"2400"on the ending day, but can also produce"0000"on the following day for the same instant. Restart filenames always use the"2400"form, so when time is"0000"this function rolls the date back by one day and substitutes"2400".- Parameters:
- Returns:
(date, time)— adjusted when time is"0000", unchanged otherwise.- Return type:
Examples
>>> normalize_sim_end_time("02JAN2026", "0000") ('01JAN2026', '2400') >>> normalize_sim_end_time("02JAN2026", "1200") ('02JAN2026', '1200') >>> normalize_sim_end_time("01JAN2026", "2400") ('01JAN2026', '2400')
- rivia.utils.normalize_sim_start_time(date, time)[source]¶
Normalize a HEC-RAS simulation start
(date, time)pair.HEC-RAS represents midnight as
"2400"on the ending day, but the same instant used as a start time should be expressed as"0000"on the following day. When time is"2400"this function advances the date by one day and substitutes"0000".- Parameters:
- Returns:
(date, time)— adjusted when time is"2400", unchanged otherwise.- Return type:
Examples
>>> normalize_sim_start_time("01JAN2026", "2400") ('02JAN2026', '0000') >>> normalize_sim_start_time("01JAN2026", "1200") ('01JAN2026', '1200') >>> normalize_sim_start_time("01JAN2026", "0000") ('01JAN2026', '0000')
- rivia.utils.parse_hec_datetime(text, fmt=None)[source]¶
Parse any HEC-RAS combined datetime string.
The date part is always
DDMONYYYY(9 characters), followed by a separator (space or comma), then a time part in one of the supported variants:HH:MM:SS— 24-hour with colons (HDF timestamps, runtime log lines)HH:MM:SS AM/PM— 12-hour with colons (Simulation started at:lines)HHMMSS— 6-digit, no colons (space or comma separator)HHMM— 4-digit, no colons (space or comma separator)
HH=24is handled in all variants: treated as00:XX:XXon the following day, matching HEC-RAS end-of-day midnight convention.- Parameters:
- Return type:
- Raises:
ValueError – If the string is too short, has an unsupported separator, or uses an unrecognised time variant (auto-detect path only).
Examples
>>> parse_hec_datetime("01OCT2024 00:00:02") datetime.datetime(2024, 10, 1, 0, 0, 2) >>> parse_hec_datetime("01JAN2026 24:00:00") datetime.datetime(2026, 1, 2, 0, 0) >>> parse_hec_datetime("01JAN2026,2400") datetime.datetime(2026, 1, 2, 0, 0) >>> parse_hec_datetime("01JAN2026 0002", fmt="%d%b%Y %H%M") datetime.datetime(2026, 1, 1, 0, 2)
- rivia.utils.parse_interval(text)[source]¶
Parse a HEC-RAS interval string and return a
datetime.timedelta.HEC-RAS writes interval strings as a number immediately followed by a unit abbreviation, with optional whitespace between them, e.g.
'20SEC','5MIN','1HR','1HOUR','1DAY','2WEEK'.Supported units (case-insensitive):
Unit
Timedelta
SEC
timedelta(seconds=n)MIN
timedelta(minutes=n)HR
timedelta(hours=n)HOUR
timedelta(hours=n)DAY
timedelta(days=n)WEEK
timedelta(weeks=n)MONTH
timedelta(days=n*30)(approximate)YEAR
timedelta(days=n*365)(approximate)- Parameters:
text (
str|bytes) – Raw interval string from a HEC-RAS HDF attribute or plan file. Bytes are decoded as UTF-8 before parsing.- Return type:
- Raises:
ValueError – If text does not match the expected
<number><unit>format or the unit is not recognised.
- rivia.utils.timed(level=35)[source]¶
Decorator that logs the elapsed wall-clock time of a function call.
- Parameters:
level (int) –
logginglevel constant (e.g.logging.INFO,logging.DEBUG). Defaults tologging.DEBUG.
Examples
>>> from rivia.utils import timed >>> import logging >>> @timed(logging.INFO) ... def my_func(): ...
Submodules