Repository navigation
Conversation
Reduce the external package dependecies and copy the few methods over. The ARS package is no longer maintained and it is one less library that was only tested with old Python versions. Closes #12
Explictly set method argument values when combining datasets to the current defaults so there are no changes with future library upgrades.
np.Inf was changed to np.inf
Instead of returning an array with one element, directly grab the first index element.
Pandas no longer silently casts these values and raises an error. This ensures current behavior going forward.
`iteritems` was deprecated and is now either `items` or just the index.
Averaging float32 coordinates loses precision and varies with numpy version. Cast to float64 in get_center and update the expected test values (center x, basin longitude) to the exact results. Analyzed with the help of Copilot.
Backslashes cause conflicts.
These are now all listed as of 202610 with Python 3.14
There was a problem hiding this comment.
🟡 Changes recommended
Critical compatibility issues remain in the documentation environment and nighttime solar handling.
2 open issues
What changed in this PR
This pull request upgrades SMRF for Python 3.14 and newer NumPy, Pandas, SciPy, and Xarray releases while modernizing compatibility-related code.
Changes:
- Updates Python and dependency requirements in
pyproject.toml. - Replaces deprecated or private scientific-Python APIs.
- Adds local NetCDF projection utilities.
- Updates solar, topology, data-loading, output, and formatting code.
| File | Description | Review notes |
|---|---|---|
smrf/utils/utils.py |
Uses public SciPy interpolation imports. | — |
smrf/utils/spatialnc.py |
Adds local NetCDF projection utilities. | — |
smrf/tests/data/test_topo.py |
Updates topology expectations and formatting. | — |
smrf/spatial/grid.py |
Replaces a private SciPy coordinate helper. | — |
smrf/output/output_netcdf.py |
Uses local projection utilities and modernized syntax. | — |
smrf/framework/ascii_art.py |
Cleans up ASCII-art string literals. | — |
smrf/envphys/storms.py |
Updates Pandas iteration and syntax. | — |
smrf/envphys/solar/model.py |
Adjusts solar model result handling. | Critical (4 votes): nighttime scalar-zero results can cause indexing errors. |
smrf/envphys/solar/cloud.py |
Adapts cloud calculations to solar output changes. | — |
smrf/distribute/wind/winstral.py |
Modernizes NumPy, Pandas, and exception usage. | — |
smrf/distribute/variable_base.py |
Replaces deprecated NumPy aliases and updates assignments. | — |
smrf/data/load_topo.py |
Updates coordinate precision and exception handling. | — |
smrf/data/hrrr/grib_file_xarray.py |
Updates Xarray combination arguments. | — |
pyproject.toml |
Raises the minimum Python version and updates dependencies. | Critical (1 vote): the Read the Docs Python environment remains incompatible with the new package requirement. |
Review effort: Lite
The twostream method now consistently returns arrays so the change to model.py can index the return results no matter if the sun is up or down.
Reduce the complexity of the method signature and always expect an array. The only place where this was called as a float was in the model.py This also consolidates the tests written for twostream.
| try: | ||
| variable_data = xr.combine_by_coords( | ||
| variable_data, combine_attrs='drop' | ||
| variable_data, combine_attrs="drop", compat="no_conflicts", join="outer" |
There was a problem hiding this comment.
Addresses warning and enforces same behavior going forward.
| x = ds.variables["x"][:] | ||
| y = ds.variables["y"][:] | ||
| x = ds.variables["x"][:].astype(np.float64) | ||
| y = ds.variables["y"][:].astype(np.float64) |
There was a problem hiding this comment.
Increase to float64 so the mean calculation is more precise. Made the tests fail.
| flatwind.loc[m] = data_speed[m] / expVal | ||
| else: | ||
| flatwind.loc[m] = np.NaN | ||
| flatwind.loc[m] = np.nan |
There was a problem hiding this comment.
Main change with outdated syntax.
| self.min = self.config.get("min", -np.Inf) | ||
| self.max = self.config.get("max", np.Inf) | ||
| self.min = self.config.get("min", -np.inf) | ||
| self.max = self.config.get("max", np.inf) |
| # get solar using twostream | ||
| dtt = pd.to_datetime(dt) | ||
| basin_sol.iloc[idt, :] = model_solar(dtt, lat, lon) | ||
| basin_sol.iloc[idt, :] = np.float32(model_solar(dtt, lat, lon)) |
There was a problem hiding this comment.
Pandas now enforces casting on the user side
| def twostream( | ||
| cos_z: float, | ||
| S0: float, | ||
| tau: npt.NDArray[np.float64], |
There was a problem hiding this comment.
Enforce tau as arrays going forward to simplify method signature
| "direct_transmittance": zeros.copy(), | ||
| "upwelling_irradiance": zeros.copy(), | ||
| "irradiance_at_bottom": zeros.copy(), | ||
| "irradiance_normal_to_beam": zeros.copy(), |
There was a problem hiding this comment.
Always return the same values independent if sun is down or up
| new_storm[sta] = 0 | ||
| new_storm["start"] = time | ||
| for station in row.index: | ||
| new_storm[station] = 0 |
There was a problem hiding this comment.
New way to iterate over Pandas Series
| # Accumulate precip for storm total | ||
| for sta, mass in row.iteritems(): | ||
| new_storm[sta] += mass | ||
| for station, mass in row.items(): |
There was a problem hiding this comment.
Alternative way to iterate as dictionary
| " "] | ||
| r" .----------------. .----------------. .----------------. .----------------.", | ||
| r" | .--------------. || .--------------. || .--------------. || .--------------. |", | ||
| r" | | _______ | || | ____ ____ | || | _______ | || | _________ | |", |
There was a problem hiding this comment.
/ in strings need a raw string going forward to not indicate an escape character.
| # get triangulation | ||
| if self.tri is None: | ||
| xy = _ndim_coords_from_arrays((self.metadata.utm_x, self.metadata.utm_y)) | ||
| xy = np.column_stack((self.metadata.utm_x, self.metadata.utm_y)) |
Hedrick-ARS
left a comment
There was a problem hiding this comment.
Well, looks like @jomey was busy here. Thanks for making this push to update all the new syntax for 3.14.
Does this entirely remove the need for the spatialnc package?
Hedrick-ARS
left a comment
There was a problem hiding this comment.
Well it looks like @jomey was busy. Thank you for updating all the syntax here for 3.14.
Does this remove the final dependency on spatialnc package?
I build this PR based on the PR #86. That's why you see the changes to spatialnc again. Once we merge this first PR, then this will be gone from here. |
|
To get the tests passing we first must work on an updated conda environment. |

This upgrades SMRF to run with Pyton 3.14, Numpy 2.5, and Pandas 3. The changes are small and all tests pass without updating gold files. All files that were touched also got a little syntax polish with the Ruff linter.
This should be merged after we cut a last release with the current Python 3.9 version. Then give this a good spin and see what broke that tests did not show.
Code behavior changes
The only logic that was changed was to
twostreamthat now enforces to have thetauparameter always as an array. Before it also accepted a float, which made the code more complicated than needed.