Skip to content

Commit ef3698c

Browse files
committed
Drop Python 3.8 and 3.9 support
Update code and type hints to use Python 3.10
1 parent bb07cde commit ef3698c

File tree

10 files changed

+37
-44
lines changed

10 files changed

+37
-44
lines changed

.github/workflows/python-package.yml

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ jobs:
2727
runs-on: ubuntu-latest
2828
strategy:
2929
matrix:
30-
python-version: ["3.9", "3.12"]
30+
python-version: ["3.10", "3.13"]
3131
steps:
3232
- uses: actions/checkout@v4
3333
- uses: actions/setup-python@v5
@@ -46,8 +46,7 @@ jobs:
4646
runs-on: ubuntu-latest
4747
strategy:
4848
matrix:
49-
python-version:
50-
["3.8", "3.9", "3.10", "3.11", "3.12", "3.13", "3.14-dev"]
49+
python-version: ["3.10", "3.11", "3.12", "3.13", "3.14-dev"]
5150
steps:
5251
- uses: actions/checkout@v4
5352
- uses: actions/setup-python@v5

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10+
### Removed
11+
12+
- Dropped support for Python 3.8 & 3.9.
13+
1014
## [5.4.1] - 2025-07-20
1115

1216
Maintenance release

pyproject.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ classifiers = [
1717
"Typing :: Typed",
1818
]
1919
dynamic = ["version", "description"]
20-
requires-python = ">=3.8"
20+
requires-python = ">=3.10"
2121
dependencies = [
2222
"attrs >=23.1.0",
2323
"cattrs >=23.1.2",
@@ -34,7 +34,7 @@ test = [
3434
"pytest >=7.2.0",
3535
"pytest-cov >=4.0.0",
3636
"pytest-benchmark >=4.0.0",
37-
"mypy >=1.1.1",
37+
"mypy >=1.17.0",
3838
]
3939

4040
[tool.flit.module]

tcod/ecs/_converter.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,13 @@
22

33
import functools
44
from collections import defaultdict
5-
from typing import Any, Callable, get_args, get_origin
5+
from typing import TYPE_CHECKING, Any, get_args, get_origin
66

77
import cattrs
88

9+
if TYPE_CHECKING:
10+
from collections.abc import Callable
11+
912

1013
def _is_defaultdict_type(type_hint: object) -> bool:
1114
"""Return True if `type_hint` is a defaultdict type-hint."""

tcod/ecs/callbacks.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,16 @@
22

33
from __future__ import annotations
44

5-
from typing import TYPE_CHECKING, Any, Callable, TypeVar, Union
6-
7-
from typing_extensions import TypeAlias
5+
from collections.abc import Callable
6+
from typing import TYPE_CHECKING, Any, TypeAlias, TypeVar
87

98
if TYPE_CHECKING:
109
from tcod.ecs.entity import Entity
1110
from tcod.ecs.typing import ComponentKey
1211

1312
_T = TypeVar("_T")
1413

15-
_OnComponentChangedFunc: TypeAlias = Callable[["Entity", Union[_T, None], Union[_T, None]], None]
14+
_OnComponentChangedFunc: TypeAlias = Callable[["Entity", _T | None, _T | None], None]
1615
_OnComponentChangedFuncT = TypeVar("_OnComponentChangedFuncT", bound=_OnComponentChangedFunc[Any])
1716

1817
_on_component_changed_callbacks: dict[ComponentKey[Any], list[_OnComponentChangedFunc[Any]]] = {}

tcod/ecs/entity.py

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

33
from __future__ import annotations
44

5+
from collections.abc import Iterable, Iterator, Mapping, MutableMapping, MutableSet
56
from typing import (
67
TYPE_CHECKING,
78
Any,
89
Final,
910
Generic,
10-
Iterable,
11-
Iterator,
12-
Mapping,
13-
MutableMapping,
14-
MutableSet,
15-
Tuple,
16-
Type,
1711
TypeVar,
18-
Union,
1912
overload,
2013
)
2114
from weakref import WeakKeyDictionary, WeakValueDictionary
@@ -389,7 +382,7 @@ def _traverse_entities(start: Entity, traverse_parents: tuple[object, ...]) -> I
389382

390383

391384
@attrs.define(eq=False, frozen=True, weakref_slot=False)
392-
class EntityComponents(MutableMapping[Union[Type[Any], Tuple[object, Type[Any]]], object]):
385+
class EntityComponents(MutableMapping[type[Any] | tuple[object, type[Any]], object]):
393386
"""A proxy attribute to access an entities components like a dictionary.
394387
395388
See :any:`Entity.components`.

tcod/ecs/query.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
import itertools
66
import warnings
77
from collections import defaultdict
8-
from typing import TYPE_CHECKING, Any, Iterable, Iterator, Protocol, TypeVar, overload
8+
from typing import TYPE_CHECKING, Any, Protocol, TypeVar, overload
99
from weakref import WeakKeyDictionary, WeakSet
1010

1111
import attrs
@@ -15,6 +15,7 @@
1515
from tcod.ecs.constants import IsA
1616

1717
if TYPE_CHECKING:
18+
from collections.abc import Iterable, Iterator
1819
from collections.abc import Set as AbstractSet
1920

2021
from tcod.ecs.entity import Entity
@@ -471,7 +472,7 @@ def __getitem__(self, key: tuple[ComponentKey[object], ...]) -> Iterable[tuple[A
471472
continue
472473
registry_components = self.registry._components_by_type[component_key]
473474
entity_components.append([registry_components[entity] for entity in entities])
474-
return zip(*entity_components)
475+
return zip(*entity_components, strict=True)
475476

476477

477478
WorldQuery = BoundQuery

tcod/ecs/registry.py

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

55
import warnings
66
from collections import defaultdict
7-
from typing import TYPE_CHECKING, Any, DefaultDict, Dict, Final, Iterable, Mapping, NoReturn, Set, TypeVar
7+
from collections.abc import Iterable, Mapping
8+
from typing import TYPE_CHECKING, Any, Final, NoReturn, TypeVar
89

910
import attrs
1011
from typing_extensions import deprecated
@@ -195,23 +196,23 @@ def __setstate__(self, state: dict[str, Any]) -> None:
195196
# Apply defaultdict types to unpickled dictionaries
196197
self._components_by_type = converter.structure(
197198
state.pop("_components_by_type"),
198-
DefaultDict[Any, Dict[Any, Any]],
199+
defaultdict[Any, dict[Any, Any]],
199200
)
200201
self._components_by_entity = _components_by_entity_from(self._components_by_type)
201202

202203
self._tags_by_entity = converter.structure(
203204
state.pop("_tags_by_entity"),
204-
DefaultDict[Any, Set[Any]],
205+
defaultdict[Any, set[Any]],
205206
)
206207
self._tags_by_key = _tags_by_key_from_tags_by_entity(self._tags_by_entity)
207208

208209
self._relation_tags_by_entity = converter.structure(
209210
state.pop("_relation_tags_by_entity"),
210-
DefaultDict[Any, DefaultDict[Any, Set[Any]]],
211+
defaultdict[Any, defaultdict[Any, set[Any]]],
211212
)
212213
self._relation_components_by_entity = converter.structure(
213214
state.pop("_relation_components_by_entity"),
214-
DefaultDict[Any, DefaultDict[Any, Dict[Any, Any]]],
215+
defaultdict[Any, defaultdict[Any, dict[Any, Any]]],
215216
)
216217
self._relations_lookup = _relations_lookup_from(
217218
self._relation_tags_by_entity, self._relation_components_by_entity
@@ -231,11 +232,11 @@ def __getstate__(self) -> dict[str, Any]:
231232
converter = tcod.ecs._converter._get_converter()
232233
# Replace defaultdict types with plain dict when saving
233234
return {
234-
"_components_by_type": converter.structure(self._components_by_type, Dict[Any, Dict[Any, Any]]),
235-
"_tags_by_entity": converter.structure(self._tags_by_entity, Dict[Any, Any]),
236-
"_relation_tags_by_entity": converter.structure(self._relation_tags_by_entity, Dict[Any, Dict[Any, Any]]),
235+
"_components_by_type": converter.structure(self._components_by_type, dict[Any, dict[Any, Any]]),
236+
"_tags_by_entity": converter.structure(self._tags_by_entity, dict[Any, Any]),
237+
"_relation_tags_by_entity": converter.structure(self._relation_tags_by_entity, dict[Any, dict[Any, Any]]),
237238
"_relation_components_by_entity": converter.structure(
238-
self._relation_components_by_entity, Dict[Any, Dict[Any, Any]]
239+
self._relation_components_by_entity, dict[Any, dict[Any, Any]]
239240
),
240241
"_names_by_name": self._names_by_name,
241242
}

tcod/ecs/typing.py

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

33
from __future__ import annotations
44

5-
import sys
6-
import types
7-
from typing import TYPE_CHECKING, Any, Tuple, Type, TypeVar, Union
8-
9-
from typing_extensions import TypeAlias
5+
from types import EllipsisType
6+
from typing import TYPE_CHECKING, Any, TypeAlias, TypeVar
107

118
if TYPE_CHECKING:
129
from tcod.ecs.entity import Entity
@@ -15,23 +12,19 @@
1512
Entity = Any
1613
BoundQuery = Any
1714

18-
if sys.version_info >= (3, 10): # pragma: no cover
19-
EllipsisType: TypeAlias = types.EllipsisType
20-
else: # pragma: no cover
21-
EllipsisType = Any
2215

2316
_T = TypeVar("_T")
2417

25-
ComponentKey: TypeAlias = Union[Type[_T], Tuple[object, Type[_T]]]
18+
ComponentKey: TypeAlias = type[_T] | tuple[object, type[_T]]
2619
"""ComponentKey is plain `type` or tuple `(tag, type)`."""
2720

28-
_RelationTargetLookup: TypeAlias = Union[Entity, EllipsisType]
21+
_RelationTargetLookup: TypeAlias = Entity | EllipsisType
2922
"""Possible target for stored relations."""
3023

31-
_RelationQueryTarget: TypeAlias = Union[_RelationTargetLookup, BoundQuery]
24+
_RelationQueryTarget: TypeAlias = _RelationTargetLookup | BoundQuery
3225
"""Possible target for relation queries."""
3326

34-
_RelationQuery: TypeAlias = Union[Tuple[object, _RelationQueryTarget], Tuple[_RelationQueryTarget, object, None]] # noqa: PYI047
27+
_RelationQuery: TypeAlias = tuple[object, _RelationQueryTarget] | tuple[_RelationQueryTarget, object, None] # noqa: PYI047
3528
"""Query format for relations.
3629
3730
One of 4 formats:

tests/test_ecs.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
import pickle
77
import pickletools
88
import sys
9-
from typing import Callable, Iterator
9+
from collections.abc import Callable, Iterator # noqa: TC003
1010

1111
import pytest
1212

0 commit comments

Comments
 (0)