Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,13 @@ v0.18.0 (unreleased)
* `ravenpy` now supports Python3.13. (PR #459)
* Updated `raven-hydro` to v0.4.0 (`RavenHydroFramework` v4.0.1). (PR #459)
* Updated `xclim` to v0.54.0, `pint` to v0.24.4, and `numpy` to v1.24.0 (no longer pinned below v2.0). (PR #459)
* `ravenpy` is now registered with the Open Source Security Foundation (OSSF) Best Practices initiative (`RavenPy OpenSSF-BP Status <https://www.bestpractices.dev/en/projects/10064>`_). (PR #464)

Bug fixes
^^^^^^^^^
* Fix bug in _MonthlyRecord class definition crashing the pydantic-autodoc serialization. (PR #458)
* Fixed a small API bug in the `Comparing_hindcasts_and_ESP_forecasts.ipynb` notebook. (PR #463)
* The `Raven` model previously always reported version "3.7", regardless of the installed `Raven` version. It now uses `raven-hydro`'s `__raven_version__` attribute. (PR #464)

Internal changes
^^^^^^^^^^^^^^^^
Expand All @@ -22,6 +24,7 @@ Internal changes
* Removed several `type: ignore` statements.
* Spelling errors in documentation have been addressed.
* GitHub Workflows now test `ravenpy` using macOS as well as Python3.13. (PR #459)
* Several small deprecation and usage warnings as well as a few variable typing issues have been addressed. (PR #464)

v0.17.0 (2025-01-27)
--------------------
Expand Down
9 changes: 4 additions & 5 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ RavenPy |logo|
+----------------------------+-----------------------------------------------------+
| Open Source | |license| |ossf-score| |
+----------------------------+-----------------------------------------------------+
| Coding Standards | |black| |isort| |ruff| |pre-commit| |
| Coding Standards | |black| |isort| |ruff| |ossf-bp| |pre-commit| |
+----------------------------+-----------------------------------------------------+
| Development Status | |status| |build| |coveralls| |
+----------------------------+-----------------------------------------------------+
Expand Down Expand Up @@ -87,10 +87,9 @@ This package was created with Cookiecutter_ and the `Ouranosinc/cookiecutter-pyp
:target: https://github.com/CSHS-CWRA/RavenPy
:alt: RavenPy Logo

..
.. |ossf-bp| image:: https://bestpractices.coreinfrastructure.org/projects/9945/badge
:target: https://bestpractices.coreinfrastructure.org/projects/9945
:alt: Open Source Security Foundation Best Practices
.. |ossf-bp| image:: https://bestpractices.coreinfrastructure.org/projects/10064/badge
:target: https://bestpractices.coreinfrastructure.org/projects/10064
:alt: Open Source Security Foundation Best Practices

.. |ossf-score| image:: https://api.securityscorecards.dev/projects/github.com/CSHS-CWRA/RavenPy/badge
:target: https://securityscorecards.dev/viewer/?uri=github.com/CSHS-CWRA/RavenPy
Expand Down
7 changes: 4 additions & 3 deletions src/ravenpy/config/defaults.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from raven_hydro import __raven_version__

units = {
"PRECIP": "mm/d",
"PRECIP_DAILY_AVE": "mm/d",
Expand Down Expand Up @@ -58,11 +60,10 @@ def default_nc_attrs():
import datetime as dt

now = dt.datetime.now().isoformat(timespec="seconds")
# TODO: get version from shared library
version = "3.7"
version = __raven_version__

return {
"history": f"Created on {now} by Raven {version}",
"references": "Craig, J.R., and the Raven Development Team, Raven user's and developer's manual "
f"(Version {version}), URL: http://raven.uwaterloo.ca/ (2023).",
f"(Version {version}), URL: https://raven.uwaterloo.ca/ (2025).",
}
20 changes: 11 additions & 9 deletions src/ravenpy/config/rvs.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
from typing import Any, Optional, Union

import cftime
from pydantic import ConfigDict, Field, ValidationInfo, field_validator, model_validator
from pydantic import ConfigDict, Field, ValidationInfo, field_validator
from raven_hydro import __raven_version__

from ..config import commands as rc
from ..config import options as o
Expand All @@ -29,9 +30,9 @@ class RVI(RV):

run_name: Optional[str] = optfield(alias="RunName")
calendar: Optional[o.Calendar] = optfield(alias="Calendar")
start_date: Optional[date] = optfield(alias="StartDate")
start_date: Optional[Union[str, date]] = optfield(alias="StartDate")
assimilation_start_time: Optional[date] = optfield(alias="AssimilationStartTime")
end_date: Optional[date] = optfield(alias="EndDate")
end_date: Optional[Union[str, date]] = optfield(alias="EndDate")
duration: Optional[float] = optfield(alias="Duration")
time_step: Optional[Union[float, str]] = optfield(alias="TimeStep")
interpolation: Optional[o.Interpolation] = optfield(alias="Interpolation")
Expand Down Expand Up @@ -138,6 +139,8 @@ def dates2cf(cls, v, info):
).value.lower()

obj = cftime._cftime.DATE_TYPES[calendar]
if isinstance(v, str):
v = dt.datetime.fromisoformat(v)

return obj(*v.timetuple()[:6])

Expand Down Expand Up @@ -258,15 +261,14 @@ class RVE(RV):
class Config(RVI, RVC, RVH, RVT, RVP, RVE):
__rv__ = None

def header(self, rv):
@staticmethod
def header(rv):
"""Return the header to print at the top of each RV file."""
import datetime as dt
from textwrap import dedent

import ravenpy

# TODO: Better mechanism to fetch version
version = "3.7"
version = __raven_version__

return dedent(
f"""
Expand Down Expand Up @@ -512,11 +514,11 @@ def zip(
return zip


def is_symbolic(params: dict) -> bool:
def is_symbolic(params: Union[dict, Any]) -> bool:
"""Return True if parameters include a symbolic variable."""
from pymbolic.primitives import Variable

if is_dataclass(params):
if is_dataclass(params) and not isinstance(params, type):
params = {field.name: getattr(params, field.name) for field in fields(params)}

return any([isinstance(v, Variable) for v in params.values()])
1 change: 1 addition & 0 deletions src/ravenpy/extractors/routing_product.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
from osgeo import ogr, osr
from shapely import wkt

osr.UseExceptions()
except (ImportError, ModuleNotFoundError) as e:
msg = gis_import_error_message.format(Path(__file__).stem)
raise ImportError(msg) from e
Expand Down
4 changes: 3 additions & 1 deletion src/ravenpy/utilities/analysis.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,10 @@

try:
import rasterio
from osgeo.gdal import Dataset, DEMProcessing
from osgeo.gdal import Dataset, DEMProcessing, UseExceptions
from shapely.geometry import GeometryCollection, MultiPolygon, Polygon, shape

UseExceptions()
except (ImportError, ModuleNotFoundError) as e:
msg = gis_import_error_message.format(Path(__file__).stem)
raise ImportError(msg) from e
Expand Down
4 changes: 3 additions & 1 deletion src/ravenpy/utilities/forecasting.py
Original file line number Diff line number Diff line change
Expand Up @@ -374,7 +374,9 @@ def ensemble_prediction(

# Run the model for each year
ensemble = []
forecast_ds = xr.open_dataset(forecast, use_cftime=True)

time_coder = xr.coders.CFDatetimeCoder(use_cftime=True)
forecast_ds = xr.open_dataset(forecast, decode_times=time_coder)

for member in range(0, len(forecast_ds[ens_dim])):
# Prepare model instance
Expand Down
2 changes: 1 addition & 1 deletion tests/test_geoserver.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ def test_hydrobasins_upstream_aggregate(self, tmp_path):
aggregated = self.geoserver.hydrobasins_aggregate(gdf_upstream)

assert len(aggregated) == 1
assert float(aggregated.SUB_AREA.values) == 4977.8
assert aggregated.SUB_AREA.values[0] == 4977.8
np.testing.assert_equal(
aggregated.geometry.bounds.values,
np.array([[-83.8167, 8.7625, -82.7125, 9.5875]]),
Expand Down
Loading