Skip to content

Commit bc4f265

Browse files
authored
Drop support for Python 3.9 (#238)
2 parents 2046976 + 896e203 commit bc4f265

File tree

18 files changed

+80
-87
lines changed

18 files changed

+80
-87
lines changed

.github/workflows/ci.yml

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,6 @@ jobs:
1919
fail-fast: false
2020
matrix:
2121
include:
22-
- name: "pytest (3.9)"
23-
python: "3.9"
24-
tox: "3.9"
2522
- name: "pytest (3.10)"
2623
python: "3.10"
2724
tox: "3.10"

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ see the [documentation](https://pykka.readthedocs.io/).
2020

2121
## Installation
2222

23-
Pykka requires Python 3.9 or newer.
23+
Pykka requires Python 3.10 or newer.
2424

2525
Pykka is available from [PyPI](https://pypi.org/project/pykka/):
2626

docs/index.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ Pykka is available from PyPI. To install it, run::
1414

1515
pip install pykka
1616

17-
Pykka works with Python 3.9 or newer.
17+
Pykka works with Python 3.10 or newer.
1818

1919

2020
Inspiration

examples/resolver.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ def run(pool_size, *ips):
4141
hosts.append(resolvers[i % len(resolvers)].resolve(ip))
4242

4343
# Gather results (blocking)
44-
ip_to_host = zip(ips, pykka.get_all(hosts))
44+
ip_to_host = zip(ips, pykka.get_all(hosts), strict=True)
4545
pprint.pprint(list(ip_to_host))
4646

4747
# Clean up

pyproject.toml

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ name = "pykka"
33
version = "4.2.0"
44
description = "Pykka is a Python implementation of the actor model"
55
authors = [{ name = "Stein Magnus Jodal", email = "stein.magnus@jodal.no" }]
6-
requires-python = ">=3.9"
6+
requires-python = ">=3.10"
77
readme = "README.md"
88
license = "Apache-2.0"
99
keywords = ["actor", "concurrency", "threading"]
@@ -12,7 +12,6 @@ classifiers = [
1212
"Intended Audience :: Developers",
1313
"Topic :: Software Development :: Libraries",
1414
]
15-
dependencies = ["typing-extensions>=4.0.0 ; python_version < '3.10'"]
1615

1716
[project.urls]
1817
"Source code" = "https://github.com/jodal/pykka"
@@ -34,7 +33,11 @@ dev = [
3433
{ include-group = "ruff" },
3534
{ include-group = "tests" },
3635
]
37-
docs = ["sphinx>=6.2.1", "sphinx_rtd_theme>=1.3.0", "tomli>=2.0.1 ; python_version < '3.11'"]
36+
docs = [
37+
"sphinx>=6.2.1",
38+
"sphinx_rtd_theme>=1.3.0",
39+
"tomli>=2.0.1 ; python_version < '3.11'",
40+
]
3841
mypy = ["mypy>=1.17.1"]
3942
pyright = ["pyright>=1.1.403"]
4043
ruff = ["ruff>=0.12.8"]
@@ -63,7 +66,7 @@ warn_unused_configs = true
6366

6467

6568
[tool.pyright]
66-
pythonVersion = "3.9"
69+
pythonVersion = "3.10"
6770
typeCheckingMode = "strict"
6871
# Already coverd by tests and careful import ordering:
6972
reportImportCycles = false
@@ -72,7 +75,7 @@ reportPrivateUsage = false
7275

7376

7477
[tool.ruff]
75-
target-version = "py39"
78+
target-version = "py310"
7679

7780
[tool.ruff.lint]
7881
select = ["ALL"]
@@ -120,7 +123,6 @@ keep-runtime-typing = true
120123

121124
[tool.tox]
122125
env_list = [
123-
"3.9",
124126
"3.10",
125127
"3.11",
126128
"3.12",

src/pykka/_actor.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
import sys
66
import threading
77
import uuid
8-
from typing import TYPE_CHECKING, Any, Optional, Protocol, TypeVar
8+
from typing import TYPE_CHECKING, Any, Protocol, TypeVar
99

1010
from pykka import ActorDeadError, ActorRef, ActorRegistry, messages
1111
from pykka._introspection import get_attr_directly
@@ -310,9 +310,9 @@ def on_stop(self) -> None: # noqa: B027
310310

311311
def _handle_failure(
312312
self,
313-
exception_type: Optional[type[BaseException]],
314-
exception_value: Optional[BaseException],
315-
traceback: Optional[TracebackType],
313+
exception_type: type[BaseException] | None,
314+
exception_value: BaseException | None,
315+
traceback: TracebackType | None,
316316
) -> None:
317317
"""Log unexpected failures, unregisters and stops the actor."""
318318
logger.error(
@@ -324,9 +324,9 @@ def _handle_failure(
324324

325325
def on_failure( # noqa: B027
326326
self,
327-
exception_type: Optional[type[BaseException]],
328-
exception_value: Optional[BaseException],
329-
traceback: Optional[TracebackType],
327+
exception_type: type[BaseException] | None,
328+
exception_value: BaseException | None,
329+
traceback: TracebackType | None,
330330
) -> None:
331331
"""Run code when an unhandled exception is raised.
332332

src/pykka/_envelope.py

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

3-
from typing import TYPE_CHECKING, Any, Generic, Optional, TypeVar
3+
from typing import TYPE_CHECKING, Any, Generic, TypeVar
44

55
if TYPE_CHECKING:
66
from pykka import Future
@@ -24,9 +24,9 @@ class Envelope(Generic[T]):
2424
__slots__ = ["message", "reply_to"]
2525

2626
message: T
27-
reply_to: Optional[Future[Any]]
27+
reply_to: Future[Any] | None
2828

29-
def __init__(self, message: T, reply_to: Optional[Future[Any]] = None) -> None:
29+
def __init__(self, message: T, reply_to: Future[Any] | None = None) -> None:
3030
self.message = message
3131
self.reply_to = reply_to
3232

src/pykka/_future.py

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,17 @@
11
from __future__ import annotations
22

33
import functools
4+
from collections.abc import Callable, Generator, Iterable
45
from typing import (
56
TYPE_CHECKING,
67
Any,
7-
Callable,
88
Generic,
9-
Optional,
9+
TypeAlias,
1010
TypeVar,
1111
cast,
1212
)
1313

1414
if TYPE_CHECKING:
15-
from collections.abc import Generator, Iterable
16-
17-
from typing_extensions import TypeAlias
18-
1915
from pykka._types import OptExcInfo
2016

2117
__all__ = ["Future", "get_all"]
@@ -26,7 +22,7 @@
2622
M = TypeVar("M") # Result of Future.map()
2723
R = TypeVar("R") # Result of Future.reduce()
2824

29-
GetHookFunc: TypeAlias = Callable[[Optional[float]], T]
25+
GetHookFunc: TypeAlias = Callable[[float | None], T]
3026

3127

3228
class Future(Generic[T]):
@@ -38,8 +34,8 @@ class Future(Generic[T]):
3834
``await`` the future.
3935
"""
4036

41-
_get_hook: Optional[GetHookFunc[T]]
42-
_get_hook_result: Optional[T]
37+
_get_hook: GetHookFunc[T] | None
38+
_get_hook_result: T | None
4339

4440
def __init__(self) -> None:
4541
super().__init__()
@@ -52,7 +48,7 @@ def __repr__(self) -> str:
5248
def get(
5349
self,
5450
*,
55-
timeout: Optional[float] = None,
51+
timeout: float | None = None,
5652
) -> T:
5753
"""Get the value encapsulated by the future.
5854
@@ -82,7 +78,7 @@ def get(
8278

8379
def set(
8480
self,
85-
value: Optional[T] = None,
81+
value: T | None = None,
8682
) -> None:
8783
"""Set the encapsulated value.
8884
@@ -94,7 +90,7 @@ def set(
9490

9591
def set_exception(
9692
self,
97-
exc_info: Optional[OptExcInfo] = None,
93+
exc_info: OptExcInfo | None = None,
9894
) -> None:
9995
"""Set an exception as the encapsulated value.
10096
@@ -293,7 +289,7 @@ def __await__(self) -> Generator[None, None, T]:
293289
def get_all(
294290
futures: Iterable[Future[T]],
295291
*,
296-
timeout: Optional[float] = None,
292+
timeout: float | None = None,
297293
) -> Iterable[T]:
298294
"""Collect all values encapsulated in the list of futures.
299295

src/pykka/_proxy.py

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

33
import logging
4-
from typing import TYPE_CHECKING, Any, Generic, Optional, TypeVar
4+
from typing import TYPE_CHECKING, Any, Generic, TypeVar
55

66
from pykka import ActorDeadError, messages
77
from pykka._introspection import AttrInfo, introspect_attrs
@@ -131,7 +131,7 @@ def __init__(
131131
self,
132132
*,
133133
actor_ref: ActorRef[A],
134-
attr_path: Optional[AttrPath] = None,
134+
attr_path: AttrPath | None = None,
135135
) -> None:
136136
if not actor_ref.is_alive():
137137
msg = f"{actor_ref} not found"

src/pykka/_ref.py

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
Any,
66
Generic,
77
Literal,
8-
Optional,
98
TypeVar,
109
Union,
1110
overload,
@@ -104,7 +103,7 @@ def ask(
104103
message: Any,
105104
*,
106105
block: Literal[False],
107-
timeout: Optional[float] = None,
106+
timeout: float | None = None,
108107
) -> Future[Any]: ...
109108

110109
@overload
@@ -113,7 +112,7 @@ def ask(
113112
message: Any,
114113
*,
115114
block: Literal[True],
116-
timeout: Optional[float] = None,
115+
timeout: float | None = None,
117116
) -> Any: ...
118117

119118
@overload
@@ -122,15 +121,15 @@ def ask(
122121
message: Any,
123122
*,
124123
block: bool = True,
125-
timeout: Optional[float] = None,
124+
timeout: float | None = None,
126125
) -> Union[Any, Future[Any]]: ...
127126

128127
def ask(
129128
self,
130129
message: Any,
131130
*,
132131
block: bool = True,
133-
timeout: Optional[float] = None,
132+
timeout: float | None = None,
134133
) -> Union[Any, Future[Any]]:
135134
"""Send message to actor and wait for the reply.
136135
@@ -178,30 +177,30 @@ def stop(
178177
self,
179178
*,
180179
block: Literal[True],
181-
timeout: Optional[float] = None,
180+
timeout: float | None = None,
182181
) -> bool: ...
183182

184183
@overload
185184
def stop(
186185
self,
187186
*,
188187
block: Literal[False],
189-
timeout: Optional[float] = None,
188+
timeout: float | None = None,
190189
) -> Future[bool]: ...
191190

192191
@overload
193192
def stop(
194193
self,
195194
*,
196195
block: bool = True,
197-
timeout: Optional[float] = None,
196+
timeout: float | None = None,
198197
) -> Union[Any, Future[Any]]: ...
199198

200199
def stop(
201200
self,
202201
*,
203202
block: bool = True,
204-
timeout: Optional[float] = None,
203+
timeout: float | None = None,
205204
) -> Union[Any, Future[Any]]:
206205
"""Send a message to the actor, asking it to stop.
207206
@@ -223,7 +222,7 @@ def stop(
223222
"""
224223
ask_future = self.ask(_ActorStop(), block=False)
225224

226-
def _stop_result_converter(timeout: Optional[float]) -> bool:
225+
def _stop_result_converter(timeout: float | None) -> bool:
227226
try:
228227
ask_future.get(timeout=timeout)
229228
except ActorDeadError:

0 commit comments

Comments
 (0)