Skip to content

Commit 16b53ac

Browse files
keewisdcherianpre-commit-ci[bot]
authored
drop support for python=3.9 (#8937)
* bump python in the min versions environments * bump python in ci * package metadata * docs * typo (This paragraph says it should be revisited after the bump) * tell `ruff` the target version is 3.10 * apply `pre-commit` hooks * automatically fix `UP038` * remove obsolete version checks * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Ignore what's left of UP007 * Force numpy>=2 --------- Co-authored-by: Deepak Cherian <dcherian@users.noreply.github.com> Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Deepak Cherian <deepak@cherian.net>
1 parent 7cfad41 commit 16b53ac

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

78 files changed

+280
-314
lines changed

.github/workflows/ci-additional.yaml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -139,15 +139,15 @@ jobs:
139139
fail_ci_if_error: false
140140

141141
mypy39:
142-
name: Mypy 3.9
142+
name: Mypy 3.10
143143
runs-on: "ubuntu-latest"
144144
needs: detect-ci-trigger
145145
defaults:
146146
run:
147147
shell: bash -l {0}
148148
env:
149149
CONDA_ENV_FILE: ci/requirements/environment.yml
150-
PYTHON_VERSION: "3.9"
150+
PYTHON_VERSION: "3.10"
151151

152152
steps:
153153
- uses: actions/checkout@v4
@@ -254,7 +254,7 @@ jobs:
254254
fail_ci_if_error: false
255255

256256
pyright39:
257-
name: Pyright 3.9
257+
name: Pyright 3.10
258258
runs-on: "ubuntu-latest"
259259
needs: detect-ci-trigger
260260
if: |
@@ -267,7 +267,7 @@ jobs:
267267
shell: bash -l {0}
268268
env:
269269
CONDA_ENV_FILE: ci/requirements/environment.yml
270-
PYTHON_VERSION: "3.9"
270+
PYTHON_VERSION: "3.10"
271271

272272
steps:
273273
- uses: actions/checkout@v4

.github/workflows/ci.yaml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,15 +47,15 @@ jobs:
4747
matrix:
4848
os: ["ubuntu-latest", "macos-latest", "windows-latest"]
4949
# Bookend python versions
50-
python-version: ["3.9", "3.12"]
50+
python-version: ["3.10", "3.12"]
5151
env: [""]
5252
include:
5353
# Minimum python version:
5454
- env: "bare-minimum"
55-
python-version: "3.9"
55+
python-version: "3.10"
5656
os: ubuntu-latest
5757
- env: "min-all-deps"
58-
python-version: "3.9"
58+
python-version: "3.10"
5959
os: ubuntu-latest
6060
# Latest python version:
6161
- env: "all-but-dask"

ci/requirements/bare-minimum.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ channels:
33
- conda-forge
44
- nodefaults
55
dependencies:
6-
- python=3.9
6+
- python=3.10
77
- coveralls
88
- pip
99
- pytest

ci/requirements/min-all-deps.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ dependencies:
77
# Run ci/min_deps_check.py to verify that this file respects the policy.
88
# When upgrading python, numpy, or pandas, must also change
99
# doc/user-guide/installing.rst, doc/user-guide/plotting.rst and setup.py.
10-
- python=3.9
10+
- python=3.10
1111
- array-api-strict=1.0 # dependency for testing the array api compat
1212
- boto3=1.26
1313
- bottleneck=1.3

doc/getting-started-guide/installing.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ Installation
66
Required dependencies
77
---------------------
88

9-
- Python (3.9 or later)
9+
- Python (3.10 or later)
1010
- `numpy <https://www.numpy.org/>`__ (1.23 or later)
1111
- `packaging <https://packaging.pypa.io/en/latest/#>`__ (23.1 or later)
1212
- `pandas <https://pandas.pydata.org/>`__ (2.0 or later)

pyproject.toml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ classifiers = [
99
"Intended Audience :: Science/Research",
1010
"Programming Language :: Python",
1111
"Programming Language :: Python :: 3",
12-
"Programming Language :: Python :: 3.9",
1312
"Programming Language :: Python :: 3.10",
1413
"Programming Language :: Python :: 3.11",
1514
"Programming Language :: Python :: 3.12",
@@ -20,7 +19,7 @@ dynamic = ["version"]
2019
license = {text = "Apache-2.0"}
2120
name = "xarray"
2221
readme = "README.md"
23-
requires-python = ">=3.9"
22+
requires-python = ">=3.10"
2423

2524
dependencies = [
2625
"numpy>=1.23",
@@ -242,7 +241,7 @@ extend-exclude = [
242241
"doc",
243242
"_typed_ops.pyi",
244243
]
245-
target-version = "py39"
244+
target-version = "py310"
246245

247246
[tool.ruff.lint]
248247
# E402: module level import not at top of file
@@ -255,6 +254,7 @@ ignore = [
255254
"E402",
256255
"E501",
257256
"E731",
257+
"UP007"
258258
]
259259
select = [
260260
"F", # Pyflakes

xarray/backends/api.py

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,20 @@
11
from __future__ import annotations
22

33
import os
4-
from collections.abc import Hashable, Iterable, Mapping, MutableMapping, Sequence
4+
from collections.abc import (
5+
Callable,
6+
Hashable,
7+
Iterable,
8+
Mapping,
9+
MutableMapping,
10+
Sequence,
11+
)
512
from functools import partial
613
from io import BytesIO
714
from numbers import Number
815
from typing import (
916
TYPE_CHECKING,
1017
Any,
11-
Callable,
1218
Final,
1319
Literal,
1420
Union,
@@ -358,7 +364,7 @@ def _dataset_from_backend_dataset(
358364
from_array_kwargs,
359365
**extra_tokens,
360366
):
361-
if not isinstance(chunks, (int, dict)) and chunks not in {None, "auto"}:
367+
if not isinstance(chunks, int | dict) and chunks not in {None, "auto"}:
362368
raise ValueError(
363369
f"chunks must be an int, dict, 'auto', or None. Instead found {chunks}."
364370
)
@@ -385,7 +391,7 @@ def _dataset_from_backend_dataset(
385391
if "source" not in ds.encoding:
386392
path = getattr(filename_or_obj, "path", filename_or_obj)
387393

388-
if isinstance(path, (str, os.PathLike)):
394+
if isinstance(path, str | os.PathLike):
389395
ds.encoding["source"] = _normalize_path(path)
390396

391397
return ds
@@ -1042,7 +1048,7 @@ def open_mfdataset(
10421048
raise OSError("no files to open")
10431049

10441050
if combine == "nested":
1045-
if isinstance(concat_dim, (str, DataArray)) or concat_dim is None:
1051+
if isinstance(concat_dim, str | DataArray) or concat_dim is None:
10461052
concat_dim = [concat_dim] # type: ignore[assignment]
10471053

10481054
# This creates a flat list which is easier to iterate over, whilst

xarray/backends/h5netcdf_.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ class H5NetCDFStore(WritableCFDataStore):
109109
def __init__(self, manager, group=None, mode=None, lock=HDF5_LOCK, autoclose=False):
110110
import h5netcdf
111111

112-
if isinstance(manager, (h5netcdf.File, h5netcdf.Group)):
112+
if isinstance(manager, h5netcdf.File | h5netcdf.Group):
113113
if group is None:
114114
root, group = find_root_and_group(manager)
115115
else:
@@ -374,7 +374,7 @@ def guess_can_open(
374374
if magic_number is not None:
375375
return magic_number.startswith(b"\211HDF\r\n\032\n")
376376

377-
if isinstance(filename_or_obj, (str, os.PathLike)):
377+
if isinstance(filename_or_obj, str | os.PathLike):
378378
_, ext = os.path.splitext(filename_or_obj)
379379
return ext in {".nc", ".nc4", ".cdf"}
380380

xarray/backends/lru_cache.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22

33
import threading
44
from collections import OrderedDict
5-
from collections.abc import Iterator, MutableMapping
6-
from typing import Any, Callable, TypeVar
5+
from collections.abc import Callable, Iterator, MutableMapping
6+
from typing import Any, TypeVar
77

88
K = TypeVar("K")
99
V = TypeVar("V")

xarray/backends/netCDF4_.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -615,7 +615,7 @@ def guess_can_open(
615615
# netcdf 3 or HDF5
616616
return magic_number.startswith((b"CDF", b"\211HDF\r\n\032\n"))
617617

618-
if isinstance(filename_or_obj, (str, os.PathLike)):
618+
if isinstance(filename_or_obj, str | os.PathLike):
619619
_, ext = os.path.splitext(filename_or_obj)
620620
return ext in {".nc", ".nc4", ".cdf"}
621621

xarray/backends/plugins.py

Lines changed: 4 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,22 +3,17 @@
33
import functools
44
import inspect
55
import itertools
6-
import sys
76
import warnings
7+
from collections.abc import Callable
88
from importlib.metadata import entry_points
9-
from typing import TYPE_CHECKING, Any, Callable
9+
from typing import TYPE_CHECKING, Any
1010

1111
from xarray.backends.common import BACKEND_ENTRYPOINTS, BackendEntrypoint
1212
from xarray.core.utils import module_available
1313

1414
if TYPE_CHECKING:
1515
import os
16-
from importlib.metadata import EntryPoint
17-
18-
if sys.version_info >= (3, 10):
19-
from importlib.metadata import EntryPoints
20-
else:
21-
EntryPoints = list[EntryPoint]
16+
from importlib.metadata import EntryPoint, EntryPoints
2217
from io import BufferedIOBase
2318

2419
from xarray.backends.common import AbstractDataStore
@@ -129,13 +124,8 @@ def list_engines() -> dict[str, BackendEntrypoint]:
129124
-----
130125
This function lives in the backends namespace (``engs=xr.backends.list_engines()``).
131126
If available, more information is available about each backend via ``engs["eng_name"]``.
132-
133-
# New selection mechanism introduced with Python 3.10. See GH6514.
134127
"""
135-
if sys.version_info >= (3, 10):
136-
entrypoints = entry_points(group="xarray.backends")
137-
else:
138-
entrypoints = entry_points().get("xarray.backends", [])
128+
entrypoints = entry_points(group="xarray.backends")
139129
return build_engines(entrypoints)
140130

141131

xarray/backends/scipy_.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -299,7 +299,7 @@ def guess_can_open(
299299
if magic_number is not None:
300300
return magic_number.startswith(b"CDF")
301301

302-
if isinstance(filename_or_obj, (str, os.PathLike)):
302+
if isinstance(filename_or_obj, str | os.PathLike):
303303
_, ext = os.path.splitext(filename_or_obj)
304304
return ext in {".nc", ".nc4", ".cdf", ".gz"}
305305

xarray/backends/zarr.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1140,7 +1140,7 @@ def guess_can_open(
11401140
self,
11411141
filename_or_obj: str | os.PathLike[Any] | BufferedIOBase | AbstractDataStore,
11421142
) -> bool:
1143-
if isinstance(filename_or_obj, (str, os.PathLike)):
1143+
if isinstance(filename_or_obj, str | os.PathLike):
11441144
_, ext = os.path.splitext(filename_or_obj)
11451145
return ext in {".zarr"}
11461146

xarray/coding/calendar_ops.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -362,7 +362,7 @@ def interp_calendar(source, target, dim="time"):
362362
"""
363363
from xarray.core.dataarray import DataArray
364364

365-
if isinstance(target, (pd.DatetimeIndex, CFTimeIndex)):
365+
if isinstance(target, pd.DatetimeIndex | CFTimeIndex):
366366
target = DataArray(target, dims=(dim,), name=dim)
367367

368368
if not _contains_datetime_like_objects(

xarray/coding/cftime_offsets.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -220,7 +220,7 @@ def _next_higher_resolution(self) -> Tick:
220220
raise ValueError("Could not convert to integer offset at any resolution")
221221

222222
def __mul__(self, other: int | float) -> Tick:
223-
if not isinstance(other, (int, float)):
223+
if not isinstance(other, int | float):
224224
return NotImplemented
225225
if isinstance(other, float):
226226
n = other * self.n
@@ -805,7 +805,7 @@ def to_cftime_datetime(date_str_or_date, calendar=None):
805805
return date
806806
elif isinstance(date_str_or_date, cftime.datetime):
807807
return date_str_or_date
808-
elif isinstance(date_str_or_date, (datetime, pd.Timestamp)):
808+
elif isinstance(date_str_or_date, datetime | pd.Timestamp):
809809
return cftime.DatetimeProlepticGregorian(*date_str_or_date.timetuple())
810810
else:
811811
raise TypeError(
@@ -1409,7 +1409,7 @@ def date_range_like(source, calendar, use_cftime=None):
14091409
from xarray.coding.frequencies import infer_freq
14101410
from xarray.core.dataarray import DataArray
14111411

1412-
if not isinstance(source, (pd.DatetimeIndex, CFTimeIndex)) and (
1412+
if not isinstance(source, pd.DatetimeIndex | CFTimeIndex) and (
14131413
isinstance(source, DataArray)
14141414
and (source.ndim != 1)
14151415
or not _contains_datetime_like_objects(source.variable)
@@ -1458,7 +1458,7 @@ def date_range_like(source, calendar, use_cftime=None):
14581458

14591459
# For the cases where the source ends on the end of the month, we expect the same in the new calendar.
14601460
if source_end.day == source_end.daysinmonth and isinstance(
1461-
freq_as_offset, (YearEnd, QuarterEnd, MonthEnd, Day)
1461+
freq_as_offset, YearEnd | QuarterEnd | MonthEnd | Day
14621462
):
14631463
end = end.replace(day=end.daysinmonth)
14641464

xarray/coding/cftimeindex.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -566,7 +566,7 @@ def shift( # type: ignore[override] # freq is typed Any, we are more precise
566566
if isinstance(freq, timedelta):
567567
return self + periods * freq
568568

569-
if isinstance(freq, (str, BaseCFTimeOffset)):
569+
if isinstance(freq, str | BaseCFTimeOffset):
570570
from xarray.coding.cftime_offsets import to_offset
571571

572572
return self + periods * to_offset(freq)

xarray/coding/frequencies.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ def infer_freq(index):
8282
from xarray.core.dataarray import DataArray
8383
from xarray.core.variable import Variable
8484

85-
if isinstance(index, (DataArray, pd.Series)):
85+
if isinstance(index, DataArray | pd.Series):
8686
if index.ndim != 1:
8787
raise ValueError("'index' must be 1D")
8888
elif not _contains_datetime_like_objects(Variable("dim", index)):

xarray/coding/times.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@
22

33
import re
44
import warnings
5-
from collections.abc import Hashable
5+
from collections.abc import Callable, Hashable
66
from datetime import datetime, timedelta
77
from functools import partial
8-
from typing import Callable, Literal, Union, cast
8+
from typing import Literal, Union, cast
99

1010
import numpy as np
1111
import pandas as pd

xarray/coding/variables.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@
33
from __future__ import annotations
44

55
import warnings
6-
from collections.abc import Hashable, MutableMapping
6+
from collections.abc import Callable, Hashable, MutableMapping
77
from functools import partial
8-
from typing import TYPE_CHECKING, Any, Callable, Union
8+
from typing import TYPE_CHECKING, Any, Union
99

1010
import numpy as np
1111
import pandas as pd

xarray/core/_aggregations.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44

55
from __future__ import annotations
66

7-
from collections.abc import Sequence
8-
from typing import TYPE_CHECKING, Any, Callable
7+
from collections.abc import Callable, Sequence
8+
from typing import TYPE_CHECKING, Any
99

1010
from xarray.core import duck_array_ops
1111
from xarray.core.options import OPTIONS

xarray/core/_typed_ops.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@
55
from __future__ import annotations
66

77
import operator
8-
from typing import TYPE_CHECKING, Any, Callable, overload
8+
from collections.abc import Callable
9+
from typing import TYPE_CHECKING, Any, overload
910

1011
from xarray.core import nputils, ops
1112
from xarray.core.types import (

xarray/core/accessor_str.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,11 +42,11 @@
4242
import codecs
4343
import re
4444
import textwrap
45-
from collections.abc import Hashable, Mapping
45+
from collections.abc import Callable, Hashable, Mapping
4646
from functools import reduce
4747
from operator import or_ as set_union
4848
from re import Pattern
49-
from typing import TYPE_CHECKING, Any, Callable, Generic
49+
from typing import TYPE_CHECKING, Any, Generic
5050
from unicodedata import normalize
5151

5252
import numpy as np
@@ -90,7 +90,7 @@ def _contains_obj_type(*, pat: Any, checker: Any) -> bool:
9090

9191
def _contains_str_like(pat: Any) -> bool:
9292
"""Determine if the object is a str-like or array of str-like."""
93-
if isinstance(pat, (str, bytes)):
93+
if isinstance(pat, str | bytes):
9494
return True
9595

9696
if not hasattr(pat, "dtype"):

0 commit comments

Comments
 (0)