Skip to content

Commit

Permalink
Fix issue #418. Unpin pymbolic. Resolve pydantic deprecation warnings (
Browse files Browse the repository at this point in the history
…#420)

### What kind of change does this PR introduce?

* Unpin pymbolic
* Resolve issue with `pymbolic > 2022.2`
* Tweaks to silence pydantic DeprecationWarning

### Does this PR introduce a breaking change?

Python3.9 support has been dropped.
  • Loading branch information
Zeitsperre authored Dec 2, 2024
2 parents 57b7df4 + ede6f94 commit 1da26b4
Show file tree
Hide file tree
Showing 13 changed files with 33 additions and 35 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ jobs:
fail-fast: false
matrix:
os: [ 'ubuntu-latest' ] # 'macos-latest' disabled until a new build of raven-hydro is available
python-version: [ "3.9", "3.11", "3.12" ]
python-version: [ "3.11", "3.12" ]
tox-env: [ 'false' ]
# - "3.13" # not yet supported by dependencies
include:
Expand Down Expand Up @@ -135,7 +135,7 @@ jobs:
os: [ "ubuntu-latest" ]
# - macos-latest # disabled until a new build of raven-hydro is available
# - windows-latest # disabled until xesmf is available
python-version: [ "3.9", "3.10", "3.11", "3.12" ]
python-version: [ "3.10", "3.11", "3.12" ]
defaults:
run:
shell: bash -l {0}
Expand Down
6 changes: 3 additions & 3 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,9 @@ repos:
hooks:
- id: nbqa-pyupgrade
args: [ '--py39-plus' ]
additional_dependencies: [ 'pyupgrade==3.16.0' ]
additional_dependencies: [ 'pyupgrade==3.19.0' ]
- id: nbqa-black
additional_dependencies: [ 'black==24.8.0' ]
additional_dependencies: [ 'black==24.10.0' ]
- id: nbqa-isort
additional_dependencies: [ 'isort==5.13.2' ]
- repo: https://github.com/kynan/nbstripout
Expand All @@ -84,7 +84,7 @@ repos:
rev: v1.8.0
hooks:
- id: numpydoc-validation
exclude: ^docs/|^tests/
exclude: "^docs/|^tests/"
- repo: https://github.com/python-jsonschema/check-jsonschema
rev: 0.29.4
hooks:
Expand Down
6 changes: 6 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@
Changelog
=========

v0.17.0 (unreleased)
--------------------
* Add support for `pymbolic` > 2022.2 (PR #420)
* Convert `SymConfig` to a dict to silence pydantic deprecation warnings (PR #420)
* Drop support for Python 3.9 (PR #420)

v0.16.0 (2024-10-18)
--------------------

Expand Down
2 changes: 1 addition & 1 deletion CONTRIBUTING.rst
Original file line number Diff line number Diff line change
Expand Up @@ -239,5 +239,5 @@ This will create or update the French translation files in the `docs/locales/fr/
Code of Conduct
---------------

Please note that this project is released with a `Contributor Code of Conduct <https://github.com/CSHS-CWRA/RavenPy/blob/main/CODE_OF_CONDUCT.md>`_.
Please note that this project is released with a `Contributor Code of Conduct <https://github.com/CSHS-CWRA/RavenPy/blob/master/CODE_OF_CONDUCT.md>`_.
By participating in this project you agree to abide by its terms.
3 changes: 2 additions & 1 deletion docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -162,11 +162,12 @@ For example:

```{code-cell} ipython3
from typing import Union
from pydantic import ConfigDict
from pydantic.dataclasses import dataclass
from pymbolic.primitives import Variable
from ravenpy.config import Sym
@dataclass(config=dict(arbitrary_types_allowed=True))
@dataclass(config=ConfigDict(arbitrary_types_allowed=True))
class P:
X01: Union[Variable, float] = Variable("X01")
Expand Down
2 changes: 1 addition & 1 deletion environment-dev.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ dependencies:
- pydantic >=2.0
- pydap >=3.4.0
- pymetalink >=6.5.2
- pymbolic <=2022.2 # 2024.1.0 is not supported
- pymbolic >=2024.2
- pyproj >=3.3.0
- rasterio
- rioxarray
Expand Down
8 changes: 3 additions & 5 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ maintainers = [
{name = "Trevor James Smith", email = "[email protected]"}
]
readme = {file = "README.rst", content-type = "text/x-rst"}
requires-python = ">=3.9.0"
requires-python = ">=3.10.0"
keywords = ["raven", "raven-hydro", "hydrology", "gis", "analysis", "modelling"]
license = {file = "LICENSE"}
classifiers = [
Expand All @@ -24,7 +24,6 @@ classifiers = [
"Natural Language :: English",
"Operating System :: OS Independent",
"Programming Language :: Python :: 3 :: Only",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
Expand Down Expand Up @@ -53,7 +52,7 @@ dependencies = [
"platformdirs",
"pydantic >=2.0",
"pydap >=3.4.0",
"pymbolic <=2022.2", # 2024.1.0 is not supported
"pymbolic >=2024.2",
"raven-hydro >=0.3.1,<1.0",
"scipy >=1.9.0",
"spotpy >=1.6.1",
Expand Down Expand Up @@ -160,7 +159,6 @@ ravenpy = "ravenpy.cli:main"

[tool.black]
target-version = [
"py39",
"py310",
"py311",
"py312",
Expand Down Expand Up @@ -254,7 +252,7 @@ exclude = [

[tool.isort]
profile = "black"
py_version = 39
py_version = "310"

[tool.mypy]
plugins = [
Expand Down
12 changes: 5 additions & 7 deletions src/ravenpy/config/base.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import typing
from collections.abc import Sequence
from enum import Enum
from textwrap import dedent, indent
from typing import Any, Optional, Union

from pydantic import BaseModel, ConfigDict, Field, RootModel, model_validator
from pymbolic.primitives import Expression, Variable
from pymbolic.primitives import ExpressionNode, Variable

"""
Notes
Expand All @@ -27,11 +26,10 @@
"""


class SymConfig:
arbitrary_types_allowed = True
SymConfig = ConfigDict(arbitrary_types_allowed=True)


Sym = Union[Variable, Expression, float, None]
Sym = Union[Variable, ExpressionNode, float, None]


def optfield(**kwds):
Expand Down Expand Up @@ -323,7 +321,7 @@ def parse_symbolic(value, **kwds):
dictionary to recreate the correct model.
"""
from pymbolic.mapper.evaluator import EvaluationMapper as EM # noqa: N817
from pymbolic.primitives import Expression, Variable
from pymbolic.primitives import ExpressionNode, Variable

if isinstance(value, dict):
return {k: parse_symbolic(v, **kwds) for k, v in value.items()}
Expand All @@ -337,7 +335,7 @@ def parse_symbolic(value, **kwds):
attrs = attrs["root"]
return value.model_validate(parse_symbolic(attrs, **kwds))

elif isinstance(value, (Variable, Expression)):
elif isinstance(value, (Variable, ExpressionNode)):
# Inject numerical values numerical value
return EM(context=kwds)(value)

Expand Down
1 change: 0 additions & 1 deletion src/ravenpy/config/emulators/hbvec.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
from collections.abc import Sequence
from typing import Literal, Union
from warnings import warn

from pydantic import Field, field_validator
from pydantic.dataclasses import dataclass
Expand Down
11 changes: 6 additions & 5 deletions src/ravenpy/config/rvs.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import datetime as dt
from collections.abc import Sequence
from dataclasses import asdict, is_dataclass
from dataclasses import asdict, fields, is_dataclass
from pathlib import Path
from typing import Any, Optional, Union

Expand Down Expand Up @@ -390,7 +390,10 @@ def _rv(self, rv: str):
def is_symbolic(self):
"""Return True if configuration contains symbolic expressions."""
if self.params is not None:
p = asdict(self.params)
p = {
field.name: getattr(self.params, field.name)
for field in fields(self.params)
}
return is_symbolic(p)

return False
Expand Down Expand Up @@ -511,11 +514,9 @@ def zip(

def is_symbolic(params: dict) -> bool:
"""Return True if parameters include a symbolic variable."""
from dataclasses import is_dataclass

from pymbolic.primitives import Variable

if is_dataclass(params):
params = asdict(params)
params = {field.name: getattr(params, field.name) for field in fields(params)}

return any([isinstance(v, Variable) for v in params.values()])
6 changes: 1 addition & 5 deletions src/ravenpy/config/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,11 +54,7 @@ def nc_specs(
if isinstance(fn, str) and str(fn)[:4] == "http":
pass
elif Path(fn).exists():
# `strict` kwarg is not available in Python 3.9
try:
fn = os.path.realpath(fn, strict=True)
except TypeError:
fn = os.path.realpath(fn)
fn = os.path.realpath(fn, strict=True)
else:
raise ValueError("NetCDF file not found.")

Expand Down
4 changes: 2 additions & 2 deletions tests/test_rvs.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

import cftime
import pytest
from pydantic import Field, ValidationError
from pydantic import ConfigDict, Field, ValidationError
from pydantic.dataclasses import dataclass
from pymbolic.primitives import Variable

Expand Down Expand Up @@ -62,7 +62,7 @@ def test_duplicate_emulator(gr4jcn_config):


def test_set_params():
@dataclass(config=dict(arbitrary_types_allowed=True))
@dataclass(config=ConfigDict(arbitrary_types_allowed=True))
class P:
X01: Union[Variable, float] = Variable("X01")

Expand Down
3 changes: 1 addition & 2 deletions tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
min_version = 4.18.0
envlist =
lint
py{3.9,3.10,3.11,3.12,3.13}
py{3.10,3.11,3.12,3.13}
docs
requires =
flit >= 3.9.0,<4.0
Expand All @@ -13,7 +13,6 @@ opts =

[gh]
python =
3.9 = py3.9-coveralls
3.10 = py3.10-coveralls-upstream
3.11 = py3.11-coveralls
3.12 = py3.12-coveralls
Expand Down

0 comments on commit 1da26b4

Please sign in to comment.