Skip to content

Commit d25e7e7

Browse files
authored
Follow SPEC 0 and drop support for Python 3.9 and 3.10 (#477)
1 parent 5167fe0 commit d25e7e7

22 files changed

+81
-154
lines changed

.github/workflows/nox.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ jobs:
1212
fail-fast: false
1313
matrix:
1414
platform: [ubuntu-latest, macos-latest, windows-latest]
15-
python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"]
15+
python-version: ["3.11", "3.12", "3.13"]
1616

1717
steps:
1818
- uses: actions/checkout@v4

adaptive/learner/average_learner.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
from __future__ import annotations
22

3+
from collections.abc import Callable
34
from math import sqrt
4-
from typing import Callable
55

66
import cloudpickle
77
import numpy as np

adaptive/learner/average_learner1D.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,9 @@
33
import math
44
import sys
55
from collections import defaultdict
6-
from collections.abc import Iterable, Sequence
6+
from collections.abc import Callable, Iterable, Sequence
77
from copy import deepcopy
88
from math import hypot
9-
from typing import Callable
109

1110
import numpy as np
1211
import scipy.stats

adaptive/learner/balancing_learner.py

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

33
import itertools
4-
import sys
54
from collections import defaultdict
6-
from collections.abc import Iterable, Sequence
5+
from collections.abc import Callable, Iterable, Sequence
76
from contextlib import suppress
87
from functools import partial
98
from operator import itemgetter
10-
from typing import Any, Callable, Union, cast
9+
from typing import Any, Literal, TypeAlias, cast
1110

1211
import numpy as np
1312

@@ -16,13 +15,6 @@
1615
from adaptive.types import Int, Real
1716
from adaptive.utils import cache_latest, named_product, restore
1817

19-
if sys.version_info >= (3, 10):
20-
from typing import TypeAlias
21-
else:
22-
from typing_extensions import TypeAlias
23-
24-
from typing import Literal
25-
2618
try:
2719
import pandas
2820

@@ -38,11 +30,9 @@ def dispatch(child_functions: list[Callable], arg: Any) -> Any:
3830

3931
STRATEGY_TYPE: TypeAlias = Literal["loss_improvements", "loss", "npoints", "cycle"]
4032

41-
CDIMS_TYPE: TypeAlias = Union[
42-
Sequence[dict[str, Any]],
43-
tuple[Sequence[str], Sequence[tuple[Any, ...]]],
44-
None,
45-
]
33+
CDIMS_TYPE: TypeAlias = (
34+
Sequence[dict[str, Any]] | tuple[Sequence[str], Sequence[tuple[Any, ...]]] | None
35+
)
4636

4737

4838
class BalancingLearner(BaseLearner):

adaptive/learner/base_learner.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
from __future__ import annotations
22

33
import abc
4+
from collections.abc import Callable
45
from contextlib import suppress
5-
from typing import TYPE_CHECKING, Any, Callable, TypeVar
6+
from typing import TYPE_CHECKING, Any, TypeVar
67

78
import cloudpickle
89

adaptive/learner/data_saver.py

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

33
import functools
44
from collections import OrderedDict
5-
from typing import Any, Callable
5+
from collections.abc import Callable
6+
from typing import Any
67

78
from adaptive.learner.base_learner import BaseLearner, LearnerType
89
from adaptive.utils import copy_docstring_from

adaptive/learner/integrator_learner.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,10 @@
33

44
import sys
55
from collections import defaultdict
6+
from collections.abc import Callable
67
from math import sqrt
78
from operator import attrgetter
8-
from typing import TYPE_CHECKING, Callable
9+
from typing import TYPE_CHECKING
910

1011
import cloudpickle
1112
import numpy as np

adaptive/learner/learner1D.py

Lines changed: 15 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,9 @@
33
import collections.abc
44
import itertools
55
import math
6-
import sys
7-
from collections.abc import Sequence
6+
from collections.abc import Callable, Sequence
87
from copy import copy, deepcopy
9-
from typing import TYPE_CHECKING, Any, Callable, Optional, Union
8+
from typing import TYPE_CHECKING, Any, TypeAlias
109

1110
import cloudpickle
1211
import numpy as np
@@ -24,12 +23,6 @@
2423
partial_function_from_dataframe,
2524
)
2625

27-
if sys.version_info >= (3, 10):
28-
from typing import TypeAlias
29-
else:
30-
from typing_extensions import TypeAlias
31-
32-
3326
try:
3427
import pandas
3528

@@ -42,28 +35,21 @@
4235
# -- types --
4336

4437
# Commonly used types
45-
Interval: TypeAlias = Union[tuple[float, float], tuple[float, float, int]]
46-
NeighborsType: TypeAlias = SortedDict[float, list[Optional[float]]]
38+
Interval: TypeAlias = tuple[float, float] | tuple[float, float, int]
39+
NeighborsType: TypeAlias = SortedDict[float, list[float | None]]
4740

4841
# Types for loss_per_interval functions
4942
XsType0: TypeAlias = tuple[float, float]
50-
YsType0: TypeAlias = Union[tuple[float, float], tuple[np.ndarray, np.ndarray]]
51-
XsType1: TypeAlias = tuple[
52-
Optional[float], Optional[float], Optional[float], Optional[float]
53-
]
54-
YsType1: TypeAlias = Union[
55-
tuple[Optional[float], Optional[float], Optional[float], Optional[float]],
56-
tuple[
57-
Optional[np.ndarray],
58-
Optional[np.ndarray],
59-
Optional[np.ndarray],
60-
Optional[np.ndarray],
61-
],
62-
]
63-
XsTypeN: TypeAlias = tuple[Optional[float], ...]
64-
YsTypeN: TypeAlias = Union[
65-
tuple[Optional[float], ...], tuple[Optional[np.ndarray], ...]
66-
]
43+
YsType0: TypeAlias = tuple[float, float] | tuple[np.ndarray, np.ndarray]
44+
XsType1: TypeAlias = tuple[float | None, float | None, float | None, float | None]
45+
YsType1: TypeAlias = (
46+
tuple[float | None, float | None, float | None, float | None]
47+
| tuple[
48+
np.ndarray | None, np.ndarray | None, np.ndarray | None, np.ndarray | None
49+
]
50+
)
51+
XsTypeN: TypeAlias = tuple[float | None, ...]
52+
YsTypeN: TypeAlias = tuple[float | None, ...] | tuple[np.ndarray | None, ...]
6753

6854

6955
__all__ = [
@@ -598,7 +584,7 @@ def tell(self, x: float, y: Float | Sequence[Float] | np.ndarray) -> None:
598584
)
599585

600586
# either it is a float/int, if not, try casting to a np.array
601-
if not isinstance(y, (float, int)):
587+
if not isinstance(y, float | int):
602588
y = np.asarray(y, dtype=float)
603589

604590
# Add point to the real data dict

adaptive/learner/learner2D.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,9 @@
33
import itertools
44
import warnings
55
from collections import OrderedDict
6-
from collections.abc import Iterable
6+
from collections.abc import Callable, Iterable
77
from copy import copy
88
from math import sqrt
9-
from typing import Callable
109

1110
import cloudpickle
1211
import numpy as np

adaptive/learner/sequence_learner.py

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
from __future__ import annotations
22

3-
import sys
43
from copy import copy
5-
from typing import TYPE_CHECKING, Any
4+
from typing import TYPE_CHECKING, Any, TypeAlias
65

76
import cloudpickle
87
from sortedcontainers import SortedDict, SortedSet
@@ -16,8 +15,7 @@
1615
)
1716

1817
if TYPE_CHECKING:
19-
from collections.abc import Sequence
20-
from typing import Callable
18+
from collections.abc import Callable, Sequence
2119

2220
try:
2321
import pandas
@@ -27,10 +25,6 @@
2725
except ModuleNotFoundError:
2826
with_pandas = False
2927

30-
if sys.version_info >= (3, 10):
31-
from typing import TypeAlias
32-
else:
33-
from typing_extensions import TypeAlias
3428

3529
PointType: TypeAlias = tuple[Int, Any]
3630

adaptive/runner.py

Lines changed: 29 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -8,77 +8,48 @@
88
import itertools
99
import pickle
1010
import platform
11-
import sys
1211
import time
1312
import traceback
1413
import warnings
14+
from collections.abc import Callable
1515
from contextlib import suppress
1616
from datetime import datetime, timedelta
1717
from importlib.util import find_spec
18-
from typing import TYPE_CHECKING, Any, Callable, Literal, Optional, Union
18+
from typing import TYPE_CHECKING, Any, Literal, TypeAlias
1919

2020
import loky
2121

22-
from adaptive import (
23-
BalancingLearner,
24-
DataSaver,
25-
IntegratorLearner,
26-
SequenceLearner,
27-
)
22+
from adaptive import BalancingLearner, DataSaver, IntegratorLearner, SequenceLearner
2823
from adaptive.learner.base_learner import LearnerType
2924
from adaptive.notebook_integration import in_ipynb, live_info, live_plot
3025
from adaptive.utils import SequentialExecutor
3126

32-
ExecutorTypes: TypeAlias = Union[
33-
concurrent.ProcessPoolExecutor,
34-
concurrent.ThreadPoolExecutor,
35-
SequentialExecutor,
36-
loky.reusable_executor._ReusablePoolExecutor,
37-
]
38-
FutureTypes: TypeAlias = Union[concurrent.Future, asyncio.Future, asyncio.Task]
39-
4027
if TYPE_CHECKING:
4128
import holoviews
4229

4330

44-
if sys.version_info >= (3, 10):
45-
from typing import TypeAlias
46-
else:
47-
from typing_extensions import TypeAlias
48-
49-
5031
with_ipyparallel = find_spec("ipyparallel") is not None
5132
with_distributed = find_spec("distributed") is not None
5233
with_mpi4py = find_spec("mpi4py") is not None
5334

5435
if TYPE_CHECKING:
55-
ExecutorTypes = Optional[()]
56-
FutureTypes = Optional[()]
57-
58-
if with_distributed:
59-
import distributed
60-
61-
ExecutorTypes = Optional[
62-
Union[
63-
ExecutorTypes, distributed.Client, distributed.cfexecutor.ClientExecutor
64-
]
65-
]
66-
67-
if with_mpi4py:
68-
import mpi4py.futures
69-
70-
ExecutorTypes = Optional[Union[ExecutorTypes, mpi4py.futures.MPIPoolExecutor]]
71-
72-
if with_ipyparallel:
73-
import ipyparallel
74-
from ipyparallel.client.asyncresult import AsyncResult
36+
import distributed
37+
import ipyparallel
38+
import mpi4py.futures
39+
40+
ExecutorTypes: TypeAlias = (
41+
concurrent.ProcessPoolExecutor
42+
| concurrent.ThreadPoolExecutor
43+
| SequentialExecutor
44+
| loky.reusable_executor._ReusablePoolExecutor
45+
| distributed.Client
46+
| distributed.cfexecutor.ClientExecutor
47+
| mpi4py.futures.MPIPoolExecutor
48+
| ipyparallel.Client
49+
| ipyparallel.client.view.ViewExecutor
50+
)
51+
FutureTypes: TypeAlias = concurrent.Future | asyncio.Future
7552

76-
ExecutorTypes = Optional[
77-
Union[
78-
ExecutorTypes, ipyparallel.Client, ipyparallel.client.view.ViewExecutor
79-
]
80-
]
81-
FutureTypes = Optional[Union[FutureTypes, AsyncResult]]
8253

8354
with suppress(ModuleNotFoundError):
8455
import uvloop
@@ -203,7 +174,7 @@ def __init__(
203174

204175
self._max_tasks = ntasks
205176

206-
self._pending_tasks: dict[concurrent.Future, int] = {}
177+
self._pending_tasks: dict[FutureTypes, int] = {}
207178

208179
# if we instantiate our own executor, then we are also responsible
209180
# for calling 'shutdown'
@@ -292,7 +263,8 @@ def _process_futures(
292263
pid = self._pending_tasks.pop(fut)
293264
try:
294265
y = fut.result()
295-
t = time.time() - fut.start_time # total execution time
266+
# total execution time
267+
t = time.time() - fut.start_time # type: ignore[union-attr]
296268
except Exception as e:
297269
self._tracebacks[pid] = traceback.format_exc()
298270
self._to_retry[pid] = self._to_retry.get(pid, 0) + 1
@@ -508,12 +480,12 @@ def _run(self) -> None:
508480
try:
509481
while not self.goal(self.learner):
510482
futures = self._get_futures()
511-
done, _ = concurrent.wait(futures, return_when=first_completed)
512-
self._process_futures(done)
483+
done, _ = concurrent.wait(futures, return_when=first_completed) # type: ignore[arg-type]
484+
self._process_futures(done) # type: ignore[arg-type]
513485
finally:
514486
remaining = self._remove_unfinished()
515487
if remaining:
516-
concurrent.wait(remaining)
488+
concurrent.wait(remaining) # type: ignore[arg-type]
517489
# Some futures get their result set, despite being cancelled.
518490
# see https://github.com/python-adaptive/adaptive/issues/319
519491
with_result = {f for f in remaining if not f.cancelled() and f.done()}
@@ -835,13 +807,12 @@ async def _run(self) -> None:
835807
try:
836808
while not self.goal(self.learner):
837809
futures = self._get_futures()
838-
kw = {"loop": self.ioloop} if sys.version_info[:2] < (3, 10) else {}
839-
done, _ = await asyncio.wait(futures, return_when=first_completed, **kw) # type: ignore[arg-type]
810+
done, _ = await asyncio.wait(futures, return_when=first_completed) # type: ignore[arg-type,type-var]
840811
self._process_futures(done)
841812
finally:
842813
remaining = self._remove_unfinished()
843814
if remaining:
844-
await asyncio.wait(remaining)
815+
await asyncio.wait(remaining) # type: ignore[type-var]
845816
self._cleanup()
846817

847818
def elapsed_time(self) -> float:
@@ -1062,9 +1033,7 @@ def _get_ncores(
10621033
import mpi4py.futures
10631034
if with_ipyparallel and isinstance(ex, ipyparallel.client.view.ViewExecutor):
10641035
return len(ex.view)
1065-
elif isinstance(
1066-
ex, (concurrent.ProcessPoolExecutor, concurrent.ThreadPoolExecutor)
1067-
):
1036+
elif isinstance(ex, concurrent.ProcessPoolExecutor | concurrent.ThreadPoolExecutor):
10681037
return ex._max_workers # type: ignore[union-attr]
10691038
elif isinstance(ex, loky.reusable_executor._ReusablePoolExecutor):
10701039
return ex._max_workers # type: ignore[union-attr]
@@ -1119,7 +1088,7 @@ def stop_after(*, seconds=0, minutes=0, hours=0) -> Callable[[LearnerType], bool
11191088

11201089
class _TimeGoal:
11211090
def __init__(self, dt: timedelta | datetime | int | float):
1122-
self.dt = dt if isinstance(dt, (timedelta, datetime)) else timedelta(seconds=dt)
1091+
self.dt = dt if isinstance(dt, timedelta | datetime) else timedelta(seconds=dt)
11231092
self.start_time = None
11241093

11251094
def __call__(self, _):

0 commit comments

Comments
 (0)