Skip to content

Upgrade Python to 3.14 and all dependent libraries - #87

Open
jomey wants to merge 19 commits into
mainfrom
python_314
Open

jomey wants to merge 19 commits into
mainfrom
python_314

Conversation

@jomey

@jomey jomey commented Oct 22, 2026 •

Copy link
Copy Markdown
Member

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 twostream that now enforces to have the tau parameter always as an array. Before it also accepted a float, which made the code more complicated than needed.

jomey added 14 commits October 21, 2026 17:16
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.
@jomey
jomey requested review from a team and a lite review from Copilot October 22, 2026 14:08
@jomey jomey added the maintenance Technical updates to code base, dependent libraries, package install, or software architecture label Oct 22, 2026
These are now all listed as of 202610 with Python 3.14

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 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

Comment thread pyproject.toml Resolved
Comment thread smrf/envphys/solar/model.py Resolved
jomey added 4 commits October 22, 2026 09:36
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"

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addresses warning and enforces same behavior going forward.

Comment thread smrf/data/load_topo.py
x = ds.variables["x"][:]
y = ds.variables["y"][:]
x = ds.variables["x"][:].astype(np.float64)
y = ds.variables["y"][:].astype(np.float64)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Update to latest syntax

# 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))

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pandas now enforces casting on the user side

def twostream(
cos_z: float,
S0: float,
tau: npt.NDArray[np.float64],

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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(),

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Always return the same values independent if sun is down or up

Comment thread smrf/envphys/storms.py
new_storm[sta] = 0
new_storm["start"] = time
for station in row.index:
new_storm[station] = 0

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

New way to iterate over Pandas Series

Comment thread smrf/envphys/storms.py
# Accumulate precip for storm total
for sta, mass in row.iteritems():
new_storm[sta] += mass
for station, mass in row.items():

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alternative way to iterate as dictionary

" "]
r" .----------------. .----------------. .----------------. .----------------.",
r" | .--------------. || .--------------. || .--------------. || .--------------. |",
r" | | _______ | || | ____ ____ | || | _______ | || | _________ | |",

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

/ in strings need a raw string going forward to not indicate an escape character.

Comment thread smrf/spatial/grid.py
# 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))

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Scipy syntax update

@Hedrick-ARS Hedrick-ARS left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 Hedrick-ARS left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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?

@jomey

jomey commented Oct 22, 2026

Copy link
Copy Markdown
Member Author

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.

@jomey

jomey commented Oct 25, 2026

Copy link
Copy Markdown
Member Author

To get the tests passing we first must work on an updated conda environment.
This is started here:
iSnobal/model_setup#40

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

maintenance Technical updates to code base, dependent libraries, package install, or software architecture

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants