Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

mypy compliance #1721

Merged
merged 51 commits into from
May 1, 2024
Merged
Show file tree
Hide file tree
Changes from 42 commits
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
5370ae8
first pass at mypy compliance
Zeitsperre Apr 18, 2024
1e17209
more mypy fixes
Zeitsperre Apr 18, 2024
314122d
Merge branch 'main' into mypy-pylint
Zeitsperre Apr 18, 2024
de3d11f
fix units typo
Zeitsperre Apr 19, 2024
41ddd8b
Merge branch 'main' into mypy-pylint
Zeitsperre Apr 19, 2024
3ae68da
fix binning error
Zeitsperre Apr 19, 2024
48bdd1d
mypy fixes
Zeitsperre Apr 19, 2024
15b41c4
mypy fixes
Zeitsperre Apr 19, 2024
2fb1f33
fix bins
Zeitsperre Apr 19, 2024
e077988
Merge branch 'main' into mypy-pylint
Zeitsperre Apr 19, 2024
db771ab
add pandas-stubs for typing inference, disable overrides for mypy-com…
Zeitsperre Apr 19, 2024
861d967
more mypy fixes
Zeitsperre Apr 19, 2024
e8d5593
find modifiable dim and return str
Zeitsperre Apr 19, 2024
288b7a8
use casting
Zeitsperre Apr 19, 2024
bfa5e2c
fix regression
Zeitsperre Apr 22, 2024
6d22124
mypy fixes
Zeitsperre Apr 22, 2024
0814182
mypy fixes
Zeitsperre Apr 22, 2024
b262e5a
mypy fixes
Zeitsperre Apr 22, 2024
1c86bfa
fix regressions
Zeitsperre Apr 22, 2024
ae57f32
mypy fixes
Zeitsperre Apr 22, 2024
689d3ae
mypy fixes
Zeitsperre Apr 22, 2024
5d0dac6
mypy fixes
Zeitsperre Apr 22, 2024
9c1a071
remove unneeded overrides
Zeitsperre Apr 22, 2024
11175ae
fix breakages
Zeitsperre Apr 24, 2024
3f462c9
breaking change: remove retro-compatibility of indicator __getitem__
Zeitsperre Apr 24, 2024
f3622cc
adapt test ensemble to new behaviour
Zeitsperre Apr 24, 2024
4b83974
enable testing for PEP8 rule N802
Zeitsperre Apr 24, 2024
408289f
update CHANGES.rst
Zeitsperre Apr 24, 2024
7d842d6
Merge branch 'main' into mypy-pylint
Zeitsperre Apr 24, 2024
fd024d7
Merge branch 'main' into mypy-pylint
Zeitsperre Apr 25, 2024
827f142
Rewrite importlib usage
aulemahal Apr 29, 2024
e4b9866
use recommended importlib pattern in utils too
aulemahal Apr 30, 2024
4cc6578
remove wrapped_partial wrapper, adjust tests, more consistent variabl…
Zeitsperre Apr 30, 2024
af98288
Merge branch 'main' into mypy-pylint
Zeitsperre Apr 30, 2024
292944b
merge upstream
aulemahal Apr 30, 2024
9f0f1da
fix naming errors
Zeitsperre Apr 30, 2024
683e83d
Merge remote-tracking branch 'origin/mypy-pylint' into mypy-pylint
Zeitsperre Apr 30, 2024
5856971
reintroduce Quantified in snowfall_frequency
aulemahal Apr 30, 2024
0793148
Merge branch 'mypy-pylint' of github.com:Ouranosinc/xclim into mypy-p…
aulemahal Apr 30, 2024
fda6516
docstring formatting, consistency
Zeitsperre Apr 30, 2024
494cf9f
remove variable shadowing
Zeitsperre Apr 30, 2024
9424a74
mypy consistency
Zeitsperre Apr 30, 2024
cf2b980
fix regressions
Zeitsperre Apr 30, 2024
dff2ead
make note about typing annotation of decorators, mypy fixes
Zeitsperre Apr 30, 2024
9e3d112
mark N802 violation as excluded for tests
Zeitsperre Apr 30, 2024
285e9ab
remove manual identification of variable types, use `out` less
Zeitsperre Apr 30, 2024
85c131a
update CHANGES.rst
Zeitsperre May 1, 2024
e0f54f2
Merge branch 'main' into mypy-pylint
Zeitsperre May 1, 2024
863bfcd
update CHANGES.rst
Zeitsperre May 1, 2024
1a64b25
fix doctest
Zeitsperre May 1, 2024
ce99186
remove wrapped_partial call
Zeitsperre May 1, 2024
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
4 changes: 3 additions & 1 deletion CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ Breaking changes
* The previously deprecated function ``xclim.ensembles.change_significance`` has been removed. (:pull:`1737`).
* Indicators ``snw_season_length`` and ``snd_season_length`` have been modified, see above.
* The `hargeaves85`/`hg85` method for the ``potential_evapotranspiration`` indicator and indice has been modified for precision and consistency with recent academic literature. (:issue:`1710`, :pull:`1723`).

* The `__getitem__` method of ``xclim.core.indicator.Parameter`` instances has been removed. Accessing members of ``Parameters`` now uniquely uses dot notation. (:pull:`1721`).

Bug fixes
^^^^^^^^^
Expand All @@ -36,6 +36,8 @@ Bug fixes
* Fixed "agreement fraction" in ``robustness_fractions`` to distinguish between negative change and no change. Added "negative" and "changed negative" fractions (:issue:`1690`, :pull:`1711`).
* ``make_criteria`` now skips columns with NaNs across all realizations. (:pull:`1713`).
* Fixed bug QuantileDeltaMapping adjustment not working for seasonal grouping (:issue:`1704`, :pull:`1716`).
* The codebase has been adjusted to address several (~300) `mypy`-related typing errors. (:issue:`1719`, :pull:`1721`).
* PEP8 rule `N802` is now enabled in the `ruff` formatter. (:pull:`1721`).

Internal changes
^^^^^^^^^^^^^^^^
Expand Down
1 change: 1 addition & 0 deletions environment.yml
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ dependencies:
- nc-time-axis
- netCDF4 >=1.4
- notebook
- pandas-stubs
- platformdirs
- pooch
- pre-commit
Expand Down
18 changes: 8 additions & 10 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ dev = [
"nbqa",
"nbval",
"netCDF4 >=1.4",
"pandas-stubs>=2.2",
"platformdirs >=3.2",
"pre-commit >=2.9",
"pybtex",
Expand Down Expand Up @@ -207,24 +208,20 @@ python_version = 3.9
show_error_codes = true
warn_return_any = true
warn_unused_configs = true
plugins = ["numpy.typing.mypy_plugin"]

[[tool.mypy.overrides]]
module = [
"boltons.*",
"bottleneck.*",
"cftime.*",
"clisops.core.subset.*",
"dask.*",
"lmoments3.*",
"matplotlib.*",
"jsonpickle.*",
"numba.*",
"numpy.*",
"pandas.*",
"pint.*",
"pytest_socket.*",
"SBCK.*",
"scipy.*",
"sklearn.cluster.*",
"xarray.*",
"sklearn.*",
"statsmodels.*",
"yamale.*",
"yaml.*"
]
ignore_missing_imports = true
Expand Down Expand Up @@ -273,6 +270,7 @@ select = [
"D",
"E",
"F",
"N802",
"W"
]

Expand Down
4 changes: 2 additions & 2 deletions tests/test_analog.py
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,7 @@ def test_compare_with_matlab(self):


class TestKS:
def test_1D_ks_2samp(self, random):
def test_1D_ks_2samp(self, random): # noqa: N802
# Compare with scipy.stats.ks_2samp
x = random.standard_normal(50) + 1
y = random.standard_normal(50)
Expand All @@ -210,7 +210,7 @@ def test_compare_with_matlab(self):
assert_almost_equal(dm, 0.96667, 4)


def analytical_KLDiv(p, q):
def analytical_KLDiv(p, q): # noqa: N802
"""Return the Kullback-Leibler divergence between two distributions.

Parameters
Expand Down
2 changes: 1 addition & 1 deletion tests/test_cffwis.py
Original file line number Diff line number Diff line change
Expand Up @@ -389,7 +389,7 @@ def test_fire_weather_ufunc_errors(
),
],
)
def test_fire_season_R(self, open_dataset, key, kwargs):
def test_fire_season_R(self, open_dataset, key, kwargs): # noqa: N802
expected = self._get_cffdrs_fire_season(key)
in_ds = open_dataset("FWI/cffdrs_test_wDC.nc")
nid = int(key[2])
Expand Down
40 changes: 21 additions & 19 deletions tests/test_indicators.py
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,7 @@ def test_opt_vars(tasmin_series, tasmax_series):
tx = tasmax_series(np.zeros(365))

multiOptVar(tasmin=tn, tasmax=tx)
assert multiOptVar.parameters["tasmin"]["kind"] == InputKind.OPTIONAL_VARIABLE
assert multiOptVar.parameters["tasmin"].kind == InputKind.OPTIONAL_VARIABLE


def test_registering():
Expand Down Expand Up @@ -265,8 +265,10 @@ def test_module():
"""Translations are keyed according to the module where the indicators are defined."""
assert atmos.tg_mean.__module__.split(".")[2] == "atmos"
# Virtual module also are stored under xclim.indicators
assert xclim.indicators.cf.fg.__module__ == "xclim.indicators.cf"
assert xclim.indicators.icclim.GD4.__module__ == "xclim.indicators.icclim"
assert xclim.indicators.cf.fg.__module__ == "xclim.indicators.cf" # noqa: F821
assert (
xclim.indicators.icclim.GD4.__module__ == "xclim.indicators.icclim"
) # noqa: F821


def test_temp_unit_conversion(tas_series):
Expand Down Expand Up @@ -377,7 +379,7 @@ def test_multiindicator(tas_series):
compute=uniindtemp_compute,
)
with pytest.raises(ValueError, match="Indicator minmaxtemp4 was wrongly defined"):
tmin, tmax = ind(tas, freq="YS")
_tmin, _tmax = ind(tas, freq="YS")


def test_missing(tas_series):
Expand Down Expand Up @@ -480,7 +482,7 @@ def test_all_parameters_understood(official_indicators):
for identifier, ind in official_indicators.items():
indinst = ind.get_instance()
for name, param in indinst.parameters.items():
if param["kind"] == InputKind.OTHER_PARAMETER:
if param.kind == InputKind.OTHER_PARAMETER:
problems.add((identifier, name))
# this one we are ok with.
if problems - {
Expand Down Expand Up @@ -587,15 +589,15 @@ def test_parsed_doc():
assert "tas" in xclim.atmos.liquid_precip_accumulation.parameters

params = xclim.atmos.drought_code.parameters
assert params["tas"]["description"] == "Noon temperature."
assert params["tas"]["units"] == "[temperature]"
assert params["tas"]["kind"] is InputKind.VARIABLE
assert params["tas"]["default"] == "tas"
assert params["snd"]["default"] is None
assert params["snd"]["kind"] is InputKind.OPTIONAL_VARIABLE
assert params["snd"]["units"] == "[length]"
assert params["season_method"]["kind"] is InputKind.STRING
assert params["season_method"]["choices"] == {"GFWED", None, "WF93", "LA08"}
assert params["tas"].description == "Noon temperature."
assert params["tas"].units == "[temperature]"
assert params["tas"].kind is InputKind.VARIABLE
assert params["tas"].default == "tas"
assert params["snd"].default is None
assert params["snd"].kind is InputKind.OPTIONAL_VARIABLE
assert params["snd"].units == "[length]"
assert params["season_method"].kind is InputKind.STRING
assert params["season_method"].choices == {"GFWED", None, "WF93", "LA08"}


def test_default_formatter():
Expand All @@ -604,7 +606,7 @@ def test_default_formatter():
assert default_formatter.format("{month}", month="m3") == "march"


def test_AttrFormatter():
def test_AttrFormatter(): # noqa: N802
fmt = AttrFormatter(
mapping={"evil": ["méchant", "méchante"], "nice": ["beau", "belle"]},
modifiers=["m", "f"],
Expand Down Expand Up @@ -655,14 +657,14 @@ def test_input_dataset(open_dataset):
ds = open_dataset("ERA5/daily_surface_cancities_1990-1993.nc")

# Use defaults
out = xclim.atmos.daily_temperature_range(freq="YS", ds=ds)
_ = xclim.atmos.daily_temperature_range(freq="YS", ds=ds)

# Use non-defaults (inverted on purpose)
with xclim.set_options(cf_compliance="log"):
out = xclim.atmos.daily_temperature_range("tasmax", "tasmin", freq="YS", ds=ds)
_ = xclim.atmos.daily_temperature_range("tasmax", "tasmin", freq="YS", ds=ds)

# Use a mix
out = xclim.atmos.daily_temperature_range(tasmax=ds.tasmax, freq="YS", ds=ds)
_ = xclim.atmos.daily_temperature_range(tasmax=ds.tasmax, freq="YS", ds=ds)

# Inexistent variable:
dsx = ds.drop_vars("tasmin")
Expand Down Expand Up @@ -817,7 +819,7 @@ def test_indicator_call_errors(tas_series):
uniIndTemp(tas, oups=3)


def test_resamplingIndicator_new_error():
def test_resamplingIndicator_new_error(): # noqa: N802
with pytest.raises(ValueError, match="ResamplingIndicator require a 'freq'"):
Daily(
realm="atmos",
Expand Down
12 changes: 6 additions & 6 deletions tests/test_indices.py
Original file line number Diff line number Diff line change
Expand Up @@ -3717,42 +3717,42 @@ def test_wet_spell_frequency_op(pr_series):


class TestSfcWindMax:
def test_sfcWind_max(self, sfcWind_series):
def test_sfcWind_max(self, sfcWind_series): # noqa: N802
sfcWind = sfcWind_series(np.array([14.11, 15.27, 10.70]))
out = xci.sfcWind_max(sfcWind)
np.testing.assert_allclose(out, [15.27])


class TestSfcWindMean:
def test_sfcWind_mean(self, sfcWind_series):
def test_sfcWind_mean(self, sfcWind_series): # noqa: N802
sfcWind = sfcWind_series(np.array([14.11, 15.27, 10.70]))
out = xci.sfcWind_mean(sfcWind)
np.testing.assert_allclose(out, [13.36])


class TestSfcWindMin:
def test_sfcWind_min(self, sfcWind_series):
def test_sfcWind_min(self, sfcWind_series): # noqa: N802
sfcWind = sfcWind_series(np.array([14.11, 15.27, 10.70]))
out = xci.sfcWind_min(sfcWind)
np.testing.assert_allclose(out, [10.70])


class TestSfcWindmaxMax:
def test_sfcWindmax_max(self, sfcWindmax_series):
def test_sfcWindmax_max(self, sfcWindmax_series): # noqa: N802
sfcWindmax = sfcWindmax_series(np.array([14.11, 15.27, 10.70]))
out = xci.sfcWindmax_max(sfcWindmax)
np.testing.assert_allclose(out, [15.27])


class TestSfcWindmaxMean:
def test_sfcWindmax_mean(self, sfcWindmax_series):
def test_sfcWindmax_mean(self, sfcWindmax_series): # noqa: N802
sfcWindmax = sfcWindmax_series(np.array([14.11, 15.27, 10.70]))
out = xci.sfcWindmax_mean(sfcWindmax)
np.testing.assert_allclose(out, [13.36])


class TestSfcWindmaxMin:
def test_sfcWindmax_min(self, sfcWindmax_series):
def test_sfcWindmax_min(self, sfcWindmax_series): # noqa: N802
sfcWindmax = sfcWindmax_series(np.array([14.11, 15.27, 10.70]))
out = xci.sfcWindmax_min(sfcWindmax)
np.testing.assert_allclose(out, [10.70])
Expand Down
14 changes: 10 additions & 4 deletions tests/test_sdba/test_adjustment.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,9 @@ def test_time(self, kind, name, series, random):
np.testing.assert_array_almost_equal(p, ref)

@pytest.mark.parametrize("kind,name", [(ADDITIVE, "tas"), (MULTIPLICATIVE, "pr")])
def test_mon_U(self, mon_series, series, mon_triangular, kind, name, random):
def test_mon_U( # noqa: N802
self, mon_series, series, mon_triangular, kind, name, random
):
n = 10000
u = random.random(n)

Expand Down Expand Up @@ -209,7 +211,9 @@ def test_quantiles(self, series, kind, name, random):

@pytest.mark.parametrize("kind,name", [(ADDITIVE, "tas"), (MULTIPLICATIVE, "pr")])
@pytest.mark.parametrize("add_dims", [True, False])
def test_mon_U(self, mon_series, series, kind, name, add_dims, random):
def test_mon_U( # noqa: N802
self, mon_series, series, kind, name, add_dims, random
):
"""
Train on
hist: U
Expand Down Expand Up @@ -324,7 +328,7 @@ def test_quantiles(self, series, kind, name, random):
@pytest.mark.parametrize("use_dask", [True, False])
@pytest.mark.parametrize("kind,name", [(ADDITIVE, "tas"), (MULTIPLICATIVE, "pr")])
@pytest.mark.parametrize("add_dims", [True, False])
def test_mon_U(
def test_mon_U( # noqa: N802
self, mon_series, series, mon_triangular, add_dims, kind, name, use_dask, random
):
"""
Expand Down Expand Up @@ -480,7 +484,9 @@ def test_quantiles(self, series, kind, name, random):
np.testing.assert_array_almost_equal(p[middle], ref[middle], 1)

@pytest.mark.parametrize("kind,name", [(ADDITIVE, "tas"), (MULTIPLICATIVE, "pr")])
def test_mon_U(self, mon_series, series, mon_triangular, kind, name, random):
def test_mon_U( # noqa: N802
self, mon_series, series, mon_triangular, kind, name, random
):
"""
Train on
hist: U
Expand Down
8 changes: 4 additions & 4 deletions tests/test_temperature.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ class TestDTR:
nc_tasmax = os.path.join("NRCANdaily", "nrcan_canada_daily_tasmax_1990.nc")
nc_tasmin = os.path.join("NRCANdaily", "nrcan_canada_daily_tasmin_1990.nc")

def test_DTR_3d_data_with_nans(self, open_dataset):
def test_DTR_3d_data_with_nans(self, open_dataset): # noqa: N802
tasmax = open_dataset(self.nc_tasmax).tasmax
tasmax_C = open_dataset(self.nc_tasmax).tasmax
tasmax_C -= K2C
Expand Down Expand Up @@ -176,7 +176,7 @@ class TestTmean:
os.path.join("NRCANdaily", "nrcan_canada_daily_tasmin_1990.nc"),
)

def test_Tmean_3d_data(self, open_dataset):
def test_Tmean_3d_data(self, open_dataset): # noqa: N802
ds_tmax = open_dataset(self.nc_files[0])
ds_tmin = open_dataset(self.nc_files[1])
tas = atmos.tg(ds_tmin.tasmin, ds_tmax.tasmax)
Expand Down Expand Up @@ -205,7 +205,7 @@ def test_Tmean_3d_data(self, open_dataset):
class TestTx:
nc_file = os.path.join("NRCANdaily", "nrcan_canada_daily_tasmax_1990.nc")

def test_TX_3d_data(self, open_dataset):
def test_TX_3d_data(self, open_dataset): # noqa: N802
tasmax = open_dataset(self.nc_file).tasmax
tasmax_C = open_dataset(self.nc_file).tasmax
tasmax_C.values -= K2C
Expand Down Expand Up @@ -255,7 +255,7 @@ def test_TX_3d_data(self, open_dataset):
class TestTn:
nc_file = os.path.join("NRCANdaily", "nrcan_canada_daily_tasmin_1990.nc")

def test_TN_3d_data(self, open_dataset):
def test_TN_3d_data(self, open_dataset): # noqa: N802
tasmin = open_dataset(self.nc_file).tasmin
tasmin_C = open_dataset(self.nc_file).tasmin
tasmin_C.values -= K2C
Expand Down
26 changes: 0 additions & 26 deletions tests/test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@
# Test for utils
from __future__ import annotations

from inspect import signature

import numpy as np
import xarray as xr

Expand All @@ -12,7 +10,6 @@
ensure_chunk_size,
nan_calc_percentiles,
walk_map,
wrapped_partial,
)
from xclim.testing.helpers import test_timeseries as _test_timeseries

Expand All @@ -24,29 +21,6 @@ def test_walk_map():
assert o["b"]["c"] == 0


def test_wrapped_partial():
def func(a, b=1, c=1):
"""Docstring"""
return (a, b, c)

newf = wrapped_partial(func, b=2)
assert list(signature(newf).parameters.keys()) == ["a", "c"]
assert newf(1) == (1, 2, 1)

newf = wrapped_partial(func, suggested=dict(c=2), b=2)
assert list(signature(newf).parameters.keys()) == ["a", "c"]
assert newf(1) == (1, 2, 2)
assert newf.__doc__ == func.__doc__

def func(a, b=1, c=1, **kws): # pylint: disable=function-redefined
"""Docstring"""
return a, b, c

newf = wrapped_partial(func, suggested=dict(c=2), a=2, b=2)
assert list(signature(newf).parameters.keys()) == ["c", "kws"]
assert newf() == (2, 2, 2)


def test_ensure_chunk_size():
da = xr.DataArray(np.zeros((20, 21, 20)), dims=("x", "y", "z"))

Expand Down
Loading
Loading