Skip to content

Commit a14d254

Browse files
Update cmethods.adjust's type annotations (#155)
1 parent 144cc19 commit a14d254

11 files changed

+59
-47
lines changed

.github/workflows/_codecov.yaml

+1-1
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ jobs:
4848
run: python -m pip install ".[dev,test]"
4949

5050
- name: Generate coverage report
51-
run: pytest --cov --cov-report=xml
51+
run: pytest --retries 1 --cov --cov-report=xml
5252

5353
- name: Upload coverage to Codecov
5454
uses: codecov/codecov-action@1e68e06f1dbfde0e4cefc87efeba9e4643565303 #v5.1.2

.github/workflows/_test.yaml

+2-3
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,10 @@ jobs:
3333
python-version: ${{ inputs.python-version }}
3434

3535
- name: Install dependencies
36-
run: |
37-
python -m pip install --user --upgrade pip
36+
run: python -m pip install --user --upgrade pip
3837

3938
- name: Install package
4039
run: python -m pip install --user ".[dev,test]"
4140

4241
- name: Run unit tests
43-
run: pytest -vv tests
42+
run: pytest -vv --retries 1 tests

.github/workflows/cicd.yaml

+2-2
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ jobs:
4141
fail-fast: false
4242
matrix:
4343
os: [ubuntu-latest, macos-latest, windows-latest]
44-
python-version: ["3.9", "3.10", "3.11", "3.12"]
44+
python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"]
4545
with:
4646
os: ${{ matrix.os }}
4747
python-version: ${{ matrix.python-version }}
@@ -65,7 +65,7 @@ jobs:
6565
fail-fast: false
6666
matrix:
6767
os: [ubuntu-latest, windows-latest]
68-
python-version: ["3.9", "3.10", "3.11", "3.12"]
68+
python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"]
6969
with:
7070
os: ${{ matrix.os }}
7171
python-version: ${{ matrix.python-version }}

.pre-commit-config.yaml

+4-4
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
repos:
77
- repo: https://github.com/astral-sh/ruff-pre-commit
8-
rev: v0.7.0
8+
rev: v0.9.3
99
hooks:
1010
- id: ruff
1111
args:
@@ -23,12 +23,12 @@ repos:
2323
# - --install-types
2424
# - --non-interactive
2525
- repo: https://github.com/codespell-project/codespell
26-
rev: v2.3.0
26+
rev: v2.4.0
2727
hooks:
2828
- id: codespell
2929
additional_dependencies: [tomli]
3030
- repo: https://github.com/pre-commit/pre-commit-hooks
31-
rev: v4.6.0
31+
rev: v5.0.0
3232
hooks:
3333
# all available hooks can be found here: https://github.com/pre-commit/pre-commit-hooks/blob/main/.pre-commit-hooks.yaml
3434
- id: check-yaml
@@ -72,7 +72,7 @@ repos:
7272
- id: isort
7373
args: [--profile=black]
7474
- repo: https://github.com/PyCQA/bandit
75-
rev: 1.7.10
75+
rev: 1.8.2
7676
hooks:
7777
- id: bandit
7878
exclude: "^tests/.*|examples/.*"

Makefile

+8-1
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,16 @@ install:
3939
test:
4040
$(PYTHON) -m pytest $(PYTEST_OPTS) $(TESTS)
4141

42-
.PHONY: tests
42+
.PHONY: test
4343
tests: test
4444

45+
## retest Rerun tests that failed before
46+
##
47+
.PHONY: retest
48+
retest:
49+
$(PYTHON) -m pytest $(PYTEST_OPTS) --lf $(TESTS)
50+
51+
4552
## wip Run tests marked as wip
4653
##
4754
.PHONY: wip

cmethods/__init__.py

+6-6
Original file line numberDiff line numberDiff line change
@@ -173,8 +173,8 @@ def cli(**kwargs) -> None:
173173
datefmt="%Y/%m/%d %H:%M:%S",
174174
level=logging.INFO,
175175
)
176-
177-
logging.info("Loading data sets ...")
176+
log = logging.getLogger(__name__)
177+
log.info("Loading data sets ...")
178178
try:
179179
for key, message in zip(
180180
("obs", "simh", "simp"),
@@ -194,15 +194,15 @@ def cli(**kwargs) -> None:
194194
)
195195
kwargs[key] = kwargs[key][kwargs["variable"]]
196196
except (TypeError, KeyError) as exc:
197-
logging.error(exc)
197+
log.error(exc)
198198
sys.exit(1)
199199

200-
logging.info("Data sets loaded ...")
200+
log.info("Data sets loaded ...")
201201
kwargs["n_quantiles"] = kwargs["quantiles"]
202202
del kwargs["quantiles"]
203203

204-
logging.info("Applying %s ..." % kwargs["method"])
204+
log.info("Applying %s ...", kwargs["method"])
205205
result = adjust(**kwargs)
206206

207-
logging.info("Saving result to %s ..." % kwargs["output"])
207+
log.info("Saving result to %s ...", kwargs["output"])
208208
result.to_netcdf(kwargs["output"])

cmethods/core.py

+17-15
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
from cmethods.scaling import linear_scaling as __linear_scaling
2222
from cmethods.scaling import variance_scaling as __variance_scaling
2323
from cmethods.static import SCALING_METHODS
24-
from cmethods.utils import UnknownMethodError, check_xr_types
24+
from cmethods.utils import UnknownMethodError, ensure_xr_dataarray
2525

2626
if TYPE_CHECKING:
2727
from cmethods.types import XRData
@@ -37,16 +37,16 @@
3737

3838
def apply_ufunc(
3939
method: str,
40-
obs: XRData,
41-
simh: XRData,
42-
simp: XRData,
40+
obs: xr.xarray.core.dataarray.DataArray,
41+
simh: xr.xarray.core.dataarray.DataArray,
42+
simp: xr.xarray.core.dataarray.DataArray,
4343
**kwargs: dict,
44-
) -> XRData:
44+
) -> xr.xarray.core.dataarray.DataArray:
4545
"""
4646
Internal function used to apply the bias correction technique to the
4747
passed input data.
4848
"""
49-
check_xr_types(obs=obs, simh=simh, simp=simp)
49+
ensure_xr_dataarray(obs=obs, simh=simh, simp=simp)
5050
if method not in __METHODS_FUNC__:
5151
raise UnknownMethodError(method, __METHODS_FUNC__.keys())
5252

@@ -96,11 +96,11 @@ def apply_ufunc(
9696

9797
def adjust(
9898
method: str,
99-
obs: XRData,
100-
simh: XRData,
101-
simp: XRData,
99+
obs: xr.xarray.core.dataarray.DataArray,
100+
simh: xr.xarray.core.dataarray.DataArray,
101+
simp: xr.xarray.core.dataarray.DataArray,
102102
**kwargs,
103-
) -> XRData:
103+
) -> xr.xarray.core.dataarray.DataArray | xr.xarray.core.dataarray.Dataset:
104104
"""
105105
Function to apply a bias correction technique on single and multidimensional
106106
data sets. For more information please refer to the method specific
@@ -119,19 +119,19 @@ def adjust(
119119
:param method: Technique to apply
120120
:type method: str
121121
:param obs: The reference/observational data set
122-
:type obs: XRData
122+
:type obs: xr.xarray.core.dataarray.DataArray
123123
:param simh: The modeled data of the control period
124-
:type simh: XRData
124+
:type simh: xr.xarray.core.dataarray.DataArray
125125
:param simp: The modeled data of the period to adjust
126-
:type simp: XRData
126+
:type simp: xr.xarray.core.dataarray.DataArray
127127
:param kwargs: Any other method-specific parameter (like
128128
``n_quantiles`` and ``kind``)
129129
:type kwargs: dict
130130
:return: The bias corrected/adjusted data set
131-
:rtype: XRData
131+
:rtype: xr.xarray.core.dataarray.DataArray | xr.xarray.core.dataarray.Dataset
132132
"""
133133
kwargs["adjust_called"] = True
134-
check_xr_types(obs=obs, simh=simh, simp=simp)
134+
ensure_xr_dataarray(obs=obs, simh=simh, simp=simp)
135135

136136
if method == "detrended_quantile_mapping": # noqa: PLR2004
137137
raise ValueError(
@@ -169,6 +169,8 @@ def adjust(
169169
obs_group = group["obs"]
170170
simh_group = group["simh"]
171171
simp_group = group["simp"]
172+
else:
173+
raise ValueError("'group' must be a string or a dict!")
172174

173175
del kwargs["group"]
174176

cmethods/utils.py

+4-4
Original file line numberDiff line numberDiff line change
@@ -51,11 +51,11 @@ def check_adjust_called(
5151
)
5252

5353

54-
def check_xr_types(obs: XRData, simh: XRData, simp: XRData) -> None:
54+
def ensure_xr_dataarray(obs: XRData, simh: XRData, simp: XRData) -> None:
5555
"""
5656
Checks if the parameters are in the correct type. **only used internally**
5757
"""
58-
phrase: str = "must be type xarray.core.dataarray.Dataset or xarray.core.dataarray.DataArray"
58+
phrase: str = "must be type 'xarray.core.dataarray.DataArray'."
5959

6060
if not isinstance(obs, XRData_t):
6161
raise TypeError(f"'obs' {phrase}")
@@ -73,7 +73,7 @@ def check_np_types(
7373
"""
7474
Checks if the parameters are in the correct type. **only used internally**
7575
"""
76-
phrase: str = "must be type list, np.ndarray or np.generic"
76+
phrase: str = "must be type list, np.ndarray, or np.generic"
7777

7878
if not isinstance(obs, NPData_t):
7979
raise TypeError(f"'obs' {phrase}")
@@ -246,8 +246,8 @@ def get_adjusted_scaling_factor(
246246
"UnknownMethodError",
247247
"check_adjust_called",
248248
"check_np_types",
249-
"check_xr_types",
250249
"ensure_dividable",
250+
"ensure_xr_dataarray",
251251
"get_adjusted_scaling_factor",
252252
"get_cdf",
253253
"get_inverse_of_cdf",

pyproject.toml

+6-2
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,11 @@ keywords = [
3939
classifiers = [
4040
"License :: OSI Approved :: GNU General Public License v3 (GPLv3)",
4141
"Programming Language :: Python",
42+
"Programming Language :: Python :: 3.9",
43+
"Programming Language :: Python :: 3.10",
4244
"Programming Language :: Python :: 3.11",
4345
"Programming Language :: Python :: 3.12",
46+
"Programming Language :: Python :: 3.13",
4447
"Topic :: Software Development :: Libraries :: Python Modules",
4548
"Topic :: Utilities",
4649
"Topic :: Scientific/Engineering",
@@ -99,20 +102,21 @@ dev = [
99102
# linting
100103
"pylint",
101104
"flake8",
102-
"ruff==0.3.5",
105+
"ruff",
103106
# typing
104107
"mypy",
105108
]
106109
test = [
107110
# testing
108111
"pytest",
109112
"pytest-cov",
113+
"pytest-retry",
110114
"zarr",
111115
"dask[distributed]",
112116
"scikit-learn",
113117
"scipy",
114118
]
115-
examples = ["click", "matplotlib"]
119+
examples = ["matplotlib"]
116120

117121
[tool.codespell]
118122
check-filenames = true

tests/test_misc.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ def test_not_implemented_errors(
102102
def test_adjust_failing_dqm(datasets: dict) -> None:
103103
with pytest.raises(
104104
ValueError,
105-
match="This function is not available for detrended quantile mapping. "
105+
match=r"This function is not available for detrended quantile mapping. "
106106
"Please use cmethods.CMethods.detrended_quantile_mapping",
107107
):
108108
adjust(
@@ -118,7 +118,7 @@ def test_adjust_failing_dqm(datasets: dict) -> None:
118118
def test_adjust_failing_no_group_for_distribution(datasets: dict) -> None:
119119
with pytest.raises(
120120
ValueError,
121-
match="Can't use group for distribution based methods.",
121+
match=r"Can't use group for distribution based methods.",
122122
):
123123
adjust(
124124
method="quantile_mapping",

tests/test_utils.py

+7-7
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,8 @@
2525
from cmethods.static import MAX_SCALING_FACTOR
2626
from cmethods.utils import (
2727
check_np_types,
28-
check_xr_types,
2928
ensure_dividable,
29+
ensure_xr_dataarray,
3030
get_adjusted_scaling_factor,
3131
get_pdf,
3232
nan_or_equal,
@@ -133,7 +133,7 @@ def test_xr_type_check() -> None:
133133
correct. No error should occur.
134134
"""
135135
ds: xr.core.dataarray.Dataset = xr.core.dataarray.Dataset()
136-
check_xr_types(obs=ds, simh=ds, simp=ds)
136+
ensure_xr_dataarray(obs=ds, simh=ds, simp=ds)
137137

138138

139139
def test_type_check_failing() -> None:
@@ -142,7 +142,7 @@ def test_type_check_failing() -> None:
142142
have the correct type.
143143
"""
144144

145-
phrase: str = "must be type list, np.ndarray or np.generic"
145+
phrase: str = "must be type list, np.ndarray, or np.generic"
146146
with pytest.raises(TypeError, match=f"'obs' {phrase}"):
147147
check_np_types(obs=1, simh=[], simp=[])
148148

@@ -177,7 +177,7 @@ def test_detrended_quantile_mapping_type_check_simp_failing(datasets: dict) -> N
177177
"""n_quantiles must by type int"""
178178
with pytest.raises(
179179
TypeError,
180-
match="'simp' must be type xarray.core.dataarray.DataArray",
180+
match=r"'simp' must be type xarray.core.dataarray.DataArray",
181181
):
182182
detrended_quantile_mapping( # type: ignore[attr-defined]
183183
obs=datasets["+"]["obsh"][:, 0, 0],
@@ -222,7 +222,7 @@ def test_adjust_type_checking_failing() -> None:
222222
)
223223
with pytest.raises(
224224
TypeError,
225-
match="'obs' must be type xarray.core.dataarray.Dataset or xarray.core.dataarray.DataArray",
225+
match=r"'obs' must be type 'xarray.core.dataarray.DataArray'.",
226226
):
227227
adjust(
228228
method="linear_scaling",
@@ -233,7 +233,7 @@ def test_adjust_type_checking_failing() -> None:
233233
)
234234
with pytest.raises(
235235
TypeError,
236-
match="'simh' must be type xarray.core.dataarray.Dataset or xarray.core.dataarray.DataArray",
236+
match=r"'simh' must be type 'xarray.core.dataarray.DataArray'.",
237237
):
238238
adjust(
239239
method="linear_scaling",
@@ -245,7 +245,7 @@ def test_adjust_type_checking_failing() -> None:
245245

246246
with pytest.raises(
247247
TypeError,
248-
match="'simp' must be type xarray.core.dataarray.Dataset or xarray.core.dataarray.DataArray",
248+
match=r"'simp' must be type 'xarray.core.dataarray.DataArray'.",
249249
):
250250
adjust(
251251
method="linear_scaling",

0 commit comments

Comments
 (0)