Skip to content

Commit c863a39

Browse files
committed
Drop Python 3.9, test against Python 3.14, and bump ProxyStore min version
1 parent 710a7c3 commit c863a39

12 files changed

Lines changed: 53 additions & 80 deletions

File tree

.github/workflows/integration.yml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ jobs:
1414
strategy:
1515
matrix:
1616
include:
17-
- toxenv: py39-dim
1817
- toxenv: py310-dim
1918
- toxenv: py311-dim
2019
- toxenv: py312-dim

.github/workflows/tests.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,6 @@ jobs:
1414
strategy:
1515
matrix:
1616
include:
17-
- os: ubuntu-latest
18-
python: 3.9
19-
toxenv: py39
2017
- os: ubuntu-latest
2118
python: '3.10'
2219
toxenv: py310
@@ -29,6 +26,9 @@ jobs:
2926
- os: ubuntu-latest
3027
python: '3.13'
3128
toxenv: py313
29+
- os: ubuntu-latest
30+
python: '3.14'
31+
toxenv: py314
3232
runs-on: ${{ matrix.os }}
3333

3434
steps:

docs/contributing/index.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,16 @@ and ProxyStore installed in editable mode with the necessary extras options.
88
```bash
99
$ git clone https://github.com/proxystore/extensions
1010
$ cd extensions
11-
$ tox --devenv venv -e py311
11+
$ tox --devenv venv -e py314
1212
$ . venv/bin/activate
1313
```
1414

1515
!!! warning
1616

1717
Running Tox in a Conda environment is possible but it may conflict with
1818
Tox's ability to find the correct Python versions. E.g., if your
19-
Conda environment is Python 3.9, running `#!bash $ tox -e p38` may still use
20-
Python 3.9.
19+
Conda environment is Python 3.14, running `#!bash $ tox -e p313` may still use
20+
Python 3.14.
2121

2222
To install manually:
2323
```bash
@@ -61,9 +61,9 @@ Code that is useful for building tests but is not a test itself belongs in the
6161

6262
```bash
6363
# Run all tests in tests/
64-
$ tox -e py311
64+
$ tox -e py314
6565
# Run a specific test
66-
$ tox -e py311 -- tests/x/y_test.py::test_z
66+
$ tox -e py314 -- tests/x/y_test.py::test_z
6767
```
6868

6969
### Tests (docker)
@@ -81,7 +81,7 @@ $ docker pull ghcr.io/proxystore/proxystore-dim:nightly
8181
# Be sure to change the path to your proxystore repo directory
8282
$ docker run --rm -it --network host -v /path/to/proxystore:/proxystore ghcr.io/proxystore/proxystore-dim:nightly
8383
# Inside container
84-
$ tox -e py311-dim
84+
$ tox -e py314-dim
8585
```
8686

8787
## Docs

proxystore_ex/connectors/daos.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -230,7 +230,7 @@ def get_batch(self, keys: Sequence[DAOSKey]) -> list[BytesLike | None]:
230230
objs.append(self.get(key))
231231
return objs
232232

233-
def new_key(self, obj: bytes | None = None) -> DAOSKey:
233+
def new_key(self, obj: BytesLike | None = None) -> DAOSKey:
234234
"""Create a new key.
235235
236236
Args:
@@ -286,10 +286,12 @@ def put_batch(self, objs: Sequence[BytesLike]) -> list[DAOSKey]:
286286
)
287287
for _ in objs
288288
]
289-
self._dict.bput({key.dict_key: obj for key, obj in zip(keys, objs)})
289+
self._dict.bput(
290+
{key.dict_key: obj for key, obj in zip(keys, objs, strict=False)},
291+
)
290292
return keys
291293

292-
def set(self, key: DAOSKey, obj: bytes) -> None:
294+
def set(self, key: DAOSKey, obj: BytesLike) -> None:
293295
"""Set the object associated with a key.
294296
295297
Note:

proxystore_ex/connectors/dim/margo.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -381,7 +381,7 @@ def put_batch(self, objs: Sequence[BytesLike]) -> list[DIMKey]:
381381
]
382382
rpcs: list[RPC] = []
383383

384-
for key, obj in zip(keys, objs):
384+
for key, obj in zip(keys, objs, strict=False):
385385
blk = self.engine.create_bulk(obj, bulk.read_only)
386386
rpcs.append(RPC(operation='put', key=key, data=blk))
387387

proxystore_ex/connectors/dim/ucx.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -304,7 +304,7 @@ def put_batch(self, objs: Sequence[BytesLike]) -> list[DIMKey]:
304304
]
305305
rpcs = [
306306
RPC(operation='put', key=key, data=obj)
307-
for key, obj in zip(keys, objs)
307+
for key, obj in zip(keys, objs, strict=False)
308308
]
309309
self._send_rpcs(rpcs)
310310
return keys

proxystore_ex/connectors/dim/zmq.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -317,7 +317,7 @@ def put_batch(self, objs: Sequence[BytesLike]) -> list[DIMKey]:
317317
]
318318
rpcs = [
319319
RPC(operation='put', key=key, data=obj)
320-
for key, obj in zip(keys, objs)
320+
for key, obj in zip(keys, objs, strict=False)
321321
]
322322
self._send_rpcs(rpcs)
323323
return keys

proxystore_ex/plugins/distributed.py

Lines changed: 22 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -4,22 +4,18 @@
44

55
import functools
66
import logging
7-
import sys
87
import warnings
8+
from collections.abc import Callable
99
from collections.abc import Iterable
1010
from collections.abc import Mapping
1111
from functools import partial
1212
from typing import Any
13-
from typing import Callable
1413
from typing import cast
14+
from typing import ParamSpec
1515
from typing import TypeVar
1616

17-
if sys.version_info >= (3, 10): # pragma: >3.10 cover
18-
from typing import ParamSpec
19-
else: # pragma: <3.10 cover
20-
from typing_extensions import ParamSpec
21-
2217
try:
18+
from dask._task_spec import DataNode
2319
from dask.base import tokenize
2420
from dask.utils import funcname
2521
from distributed import Client as DaskDistributedClient
@@ -40,17 +36,6 @@
4036
from proxystore.store.utils import get_key
4137
from proxystore.warnings import ExperimentalWarning
4238

43-
try: # pragma: >3.9 cover
44-
from dask._task_spec import DataNode
45-
46-
class _ProxyNode(DataNode):
47-
key: ConnectorKeyT
48-
value: Proxy[Any]
49-
50-
USE_TASK_SPEC = True
51-
except ImportError: # pragma: <=3.9 cover
52-
USE_TASK_SPEC = False
53-
5439
warnings.warn(
5540
'Dask plugins are an experimental feature and may exhibit unexpected '
5641
'behaviour or change in the future.',
@@ -65,6 +50,11 @@ class _ProxyNode(DataNode):
6550
logger = logging.getLogger(__name__)
6651

6752

53+
class _ProxyNode(DataNode):
54+
key: ConnectorKeyT
55+
value: Proxy[Any]
56+
57+
6858
class Client(DaskDistributedClient):
6959
"""Dask Distributed Client with ProxyStore support.
7060
@@ -211,11 +201,11 @@ def map( # type: ignore[no-untyped-def]
211201
# and instead want to wait to proxy until the later calls to map()
212202
# on each batch.
213203
key = key or funcname(func)
214-
iterables = list(zip(*zip(*iterables))) # type: ignore[assignment]
204+
iterables = list(zip(*zip(*iterables, strict=False), strict=False)) # type: ignore[assignment]
215205
if not isinstance(key, list) and pure: # pragma: no branch
216206
key = [
217207
f'{key}-{tokenize(func, kwargs, *args)}-proxy'
218-
for args in zip(*iterables)
208+
for args in zip(*iterables, strict=False)
219209
]
220210

221211
iterables = tuple(
@@ -265,7 +255,7 @@ def map( # type: ignore[no-untyped-def]
265255
not (batch_size and batch_size > 1 and total_length > batch_size)
266256
and self._ps_store is not None
267257
):
268-
for future, *args in zip(futures, *iterables):
258+
for future, *args in zip(futures, *iterables, strict=False):
269259
# TODO: how to delete kwargs?
270260
callback = partial(
271261
_evict_proxies_callback,
@@ -385,7 +375,7 @@ def submit( # type: ignore[no-untyped-def]
385375

386376

387377
def _evict_proxies_callback(
388-
_future: DaskDistributedFuture,
378+
_future: DaskDistributedFuture[Any],
389379
keys: Iterable[ConnectorKeyT],
390380
store: Store[Any],
391381
) -> None:
@@ -394,17 +384,11 @@ def _evict_proxies_callback(
394384

395385

396386
def _get_keys(iterable: Iterable[Any]) -> tuple[ConnectorKeyT, ...]:
397-
if USE_TASK_SPEC: # pragma: >3.9 cover
398-
return tuple(x.key for x in iterable if isinstance(x, _ProxyNode))
399-
else: # pragma: <=3.9 cover
400-
return tuple(x for x in iterable if isinstance(x, Proxy))
387+
return tuple(x.key for x in iterable if isinstance(x, _ProxyNode))
401388

402389

403390
def _is_proxy(obj: Any) -> bool:
404-
if USE_TASK_SPEC: # pragma: >3.9 cover
405-
return isinstance(obj, (_ProxyNode, Proxy))
406-
else: # pragma: <=3.9 cover
407-
return isinstance(obj, Proxy)
391+
return isinstance(obj, _ProxyNode | Proxy)
408392

409393

410394
def _proxy_by_size(
@@ -495,13 +479,10 @@ def _proxy_iterable(
495479
for value in iterable
496480
)
497481

498-
if USE_TASK_SPEC: # pragma: >3.9 cover
499-
return tuple(
500-
_ProxyNode(get_key(obj), obj) if isinstance(obj, Proxy) else obj
501-
for obj in objects
502-
)
503-
else: # pragma: <=3.9 cover
504-
return objects
482+
return tuple(
483+
_ProxyNode(get_key(obj), obj) if isinstance(obj, Proxy) else obj
484+
for obj in objects
485+
)
505486

506487

507488
def _proxy_mapping(
@@ -533,15 +514,10 @@ def _proxy_mapping(
533514
for key in mapping
534515
}
535516

536-
if USE_TASK_SPEC: # pragma: >3.9 cover
537-
return {
538-
key: _ProxyNode(get_key(obj), obj)
539-
if isinstance(obj, Proxy)
540-
else obj
541-
for key, obj in objects.items()
542-
}
543-
else: # pragma: <=3.9 cover
544-
return objects
517+
return {
518+
key: _ProxyNode(get_key(obj), obj) if isinstance(obj, Proxy) else obj
519+
for key, obj in objects.items()
520+
}
545521

546522

547523
def _proxy_task_wrapper(

pyproject.toml

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -15,20 +15,16 @@ maintainers = [
1515
]
1616
description = "ProxyStore extensions."
1717
readme = "README.md"
18-
requires-python = ">=3.9"
18+
requires-python = ">=3.10"
1919
license = {text = "MIT"}
2020
classifiers = [
2121
"License :: OSI Approved :: MIT License",
22-
"Programming Language :: Python :: 3.9",
23-
"Programming Language :: Python :: 3.10",
24-
"Programming Language :: Python :: 3.11",
25-
"Programming Language :: Python :: 3.12",
26-
"Programming Language :: Python :: 3.13",
22+
"Programming Language :: Python :: 3",
2723
"Programming Language :: Python :: 3 :: Only",
2824
"Programming Language :: Python :: Implementation :: CPython",
2925
]
3026
dependencies = [
31-
"proxystore>=0.6.5",
27+
"proxystore>=0.8.3",
3228
"pyzmq",
3329
]
3430

@@ -86,7 +82,7 @@ omit = [
8682
parallel = true
8783

8884
[tool.mypy]
89-
python_version = "3.12"
85+
python_version = "3.14"
9086
plugins = [ "proxystore.mypy_plugin" ]
9187
check_untyped_defs = true
9288
disallow_any_generics = true
@@ -112,7 +108,7 @@ timeout = 30
112108

113109
[tool.ruff]
114110
line-length = 79
115-
target-version = "py39"
111+
target-version = "py310"
116112

117113
[tool.ruff.format]
118114
indent-style = "space"

testing/connectors.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@
33
import contextlib
44
import importlib.util
55
import platform
6+
from collections.abc import Callable
67
from collections.abc import Generator
78
from contextlib import AbstractContextManager
89
from typing import Any
9-
from typing import Callable
1010
from unittest import mock
1111

1212
import pytest

0 commit comments

Comments
 (0)