Skip to content

Commit 5d51927

Browse files
authored
chore(*): Remove Python 3.9 support and bump dev deps (#19)
1 parent 3ba470f commit 5d51927

21 files changed

Lines changed: 106 additions & 117 deletions

File tree

.editorconfig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,5 @@ insert_final_newline = true
99
max_line_length = 120
1010
trim_trailing_whitespace = true
1111

12-
[{*.py, run-script}]
12+
[{*.py,run-script}]
1313
indent_size = 4

.github/workflows/cd.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ jobs:
1818
- uses: actions/checkout@v4
1919
- uses: actions/setup-python@v5
2020
with:
21-
python-version: '3.13.0-rc.2'
21+
python-version: '3.13'
2222
- name: version
2323
run: sed -i "s/__version__ = '.*'/__version__ = '$VERSION'/g" aiodi/__init__.py
2424
- name: deps

.github/workflows/ci.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ jobs:
1414
strategy:
1515
matrix:
1616
os: [ ubuntu-latest ]
17-
python-version: [ '3.9', '3.10', '3.11', '3.12', '3.13.0-rc.2' ]
17+
python-version: [ '3.10', '3.11', '3.12', '3.13' ]
1818
steps:
1919
- uses: actions/checkout@v4
2020
- uses: actions/setup-python@v5

Containerfile

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,7 @@ WORKDIR /app
44

55
RUN conda install -y --download-only "python=3.12" && \
66
conda install -y --download-only "python=3.11" && \
7-
conda install -y --download-only "python=3.10" && \
8-
conda install -y --download-only "python=3.9"
7+
conda install -y --download-only "python=3.10"
98

109
COPY . ./
1110

@@ -26,8 +25,3 @@ FROM miniconda3 AS py310
2625

2726
RUN conda install -y "python=3.10"
2827
RUN --mount=type=cache,target=/root/.cache/pip python3 run-script dev-install
29-
30-
FROM miniconda3 AS py39
31-
32-
RUN conda install -y "python=3.9"
33-
RUN --mount=type=cache,target=/root/.cache/pip python3 run-script dev-install

LICENSE

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
MIT License
22

3-
Copyright (c) 2022 - 2024 aiopy
3+
Copyright (c) 2022 - 2025 aiopy
44

55
Permission is hereby granted, free of charge, to any person obtaining a copy
66
of this software and associated documentation files (the "Software"), to deal

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@ if __name__ == '__main__':
167167

168168
## Requirements
169169

170-
- Python >= 3.9
170+
- Python >= 3.10
171171

172172
## Contributing
173173

aiodi/builder.py

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
from pathlib import Path
22
from random import shuffle
3-
from typing import Any, Callable, Dict, List, MutableMapping, Optional, Tuple, Union
3+
from typing import Any, Callable, MutableMapping
44

55
from .container import Container
66
from .logger import logger
@@ -17,22 +17,22 @@
1717

1818

1919
class ContainerBuilder:
20-
_filenames: List[str]
21-
_cwd: Optional[str]
20+
_filenames: list[str]
21+
_cwd: str | None
2222
_debug: bool
23-
_resolvers: Dict[str, Resolver[Any, Any]]
24-
_decoders: Dict[str, Callable[[Union[str, Path]], Union[MutableMapping[str, Any], Dict[str, Any]]]]
25-
_map_items: Callable[[Dict[str, Dict[str, Any]]], List[Tuple[str, Any, Dict[str, Any]]]]
23+
_resolvers: dict[str, Resolver[Any, Any]]
24+
_decoders: dict[str, Callable[[str | Path], MutableMapping[str, Any] | dict[str, Any]]]
25+
_map_items: Callable[[dict[str, dict[str, Any]]], list[tuple[str, Any, dict[str, Any]]]]
2626

2727
def __init__(
2828
self,
29-
filenames: Optional[List[str]] = None,
30-
cwd: Optional[str] = None,
29+
filenames: list[str] | None = None,
30+
cwd: str | None = None,
3131
*,
3232
debug: bool = False,
3333
tool_key: str = 'aiodi',
3434
var_key: str = 'env', # Container retro-compatibility
35-
toml_decoder: Optional[TOMLDecoder] = None,
35+
toml_decoder: TOMLDecoder | None = None,
3636
) -> None:
3737
self._filenames = (
3838
[
@@ -58,7 +58,7 @@ def __init__(
5858
'toml': lambda path: (toml_decoder or lazy_toml_decoder())(path).get('tool', {}).get(tool_key, {}),
5959
}
6060

61-
def map_items(items: Dict[str, Dict[str, Any]]) -> List[Tuple[str, Any, Dict[str, Any]]]:
61+
def map_items(items: dict[str, dict[str, Any]]) -> list[tuple[str, Any, dict[str, Any]]]:
6262
return [
6363
(key, val, {})
6464
for key, val in {
@@ -70,7 +70,7 @@ def map_items(items: Dict[str, Dict[str, Any]]) -> List[Tuple[str, Any, Dict[str
7070
self._map_items = map_items
7171

7272
def load(self) -> Container:
73-
extra: Dict[str, Any] = {
73+
extra: dict[str, Any] = {
7474
'path_data': {},
7575
'data': {},
7676
'_service_defaults': ServiceDefaults(),
@@ -125,9 +125,9 @@ def load(self) -> Container:
125125
def _parse_values(
126126
self,
127127
resolver: Resolver[Any, Any],
128-
storage: Dict[str, Any],
129-
extra: Dict[str, Any],
130-
items: Dict[str, Any],
128+
storage: dict[str, Any],
129+
extra: dict[str, Any],
130+
items: dict[str, Any],
131131
) -> None:
132132
limit_retries = pow(len(items.keys()), 3)
133133
while len(items.keys()) > 0:

aiodi/container.py

Lines changed: 18 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,7 @@
44
Any,
55
Callable,
66
Dict,
7-
List,
87
Optional,
9-
Tuple,
108
Type,
119
TypeVar,
1210
Union,
@@ -18,18 +16,18 @@
1816

1917
_T = TypeVar('_T')
2018

21-
ContainerKey = Union[str, Type[Any], object]
19+
ContainerKey = str | Type[Any] | object
2220

2321

2422
class Container(Dict[Any, Any]):
2523
debug: bool = False
26-
_parameter_resolvers: List[Callable[['Container'], Any]] = []
24+
_parameter_resolvers: list[Callable[['Container'], Any]] = []
2725

2826
def __init__(
2927
self,
3028
items: Optional[
3129
Union[
32-
Dict[str, Any], List[Union[ContainerKey, Tuple[ContainerKey, _T, Dict[str, Any]]]] # hardcoded
30+
dict[str, Any], list[Union[ContainerKey, tuple[ContainerKey, _T, dict[str, Any]]]] # hardcoded
3331
] # magic
3432
] = None,
3533
debug: bool = False,
@@ -42,12 +40,12 @@ def __init__(
4240
super(Container, self).__init__({})
4341
self.resolve(items)
4442

45-
def resolve_parameter(self, fn: Callable[['Container'], Any]) -> Tuple[int, Callable[['Container'], Any]]:
43+
def resolve_parameter(self, fn: Callable[['Container'], Any]) -> tuple[int, Callable[['Container'], Any]]:
4644
self._parameter_resolvers.append(fn)
4745
return len(self._parameter_resolvers) - 1, fn
4846

49-
def resolve(self, items: List[Union[ContainerKey, Tuple[ContainerKey, _T, Dict[str, Any]]]]) -> None:
50-
items_: List[Any] = list(map(self._sanitize_item_before_resolve, items))
47+
def resolve(self, items: list[Union[ContainerKey, tuple[ContainerKey, _T, dict[str, Any]]]]) -> None:
48+
items_: list[Any] = list(map(self._sanitize_item_before_resolve, items))
5149
while items_:
5250
for index, item in enumerate(items_):
5351
# Check if already exist
@@ -96,7 +94,7 @@ def set(self, key: ContainerKey, val: _T = ...) -> None: # type: ignore
9694
here = here.setdefault(key, {})
9795
here[keys[-1]] = val
9896

99-
def get(self, key: ContainerKey, typ: Optional[Type[_T]] = None, instance_of: bool = False) -> _T: # type: ignore
97+
def get(self, key: ContainerKey, typ: Type[_T] | None = None, instance_of: bool = False) -> _T: # type: ignore
10098
"""
10199
e.g. 1
102100
container = Container({'config': {'version': '0.1.0'}, 'app.libs.MyClass': '...'})
@@ -152,8 +150,8 @@ def __contains__(self, *o) -> bool: # type: ignore
152150

153151
@staticmethod
154152
def _sanitize_item_before_resolve(
155-
item: Union[ContainerKey, Tuple[ContainerKey, _T, Dict[str, Any]]]
156-
) -> Tuple[ContainerKey, _T, Dict[str, Any]]:
153+
item: Union[ContainerKey, tuple[ContainerKey, _T, dict[str, Any]]]
154+
) -> tuple[ContainerKey, _T, dict[str, Any]]:
157155
if not isinstance(item, tuple):
158156
return item, item, {} # type: ignore
159157
length = len(item)
@@ -163,15 +161,15 @@ def _sanitize_item_before_resolve(
163161
return item[0], item[1], {}
164162
if length >= 3:
165163
return item[:3]
166-
raise ValueError('Tuple must be at least of one item')
164+
raise ValueError('tuple must be at least of one item')
167165

168166
def _resolve_or_postpone_item(
169167
self,
170-
item: Tuple[ContainerKey, _T, Dict[str, Any]],
171-
items: List[Tuple[ContainerKey, _T, Dict[str, Any]]],
172-
) -> Optional[Dict[str, Any]]:
168+
item: tuple[ContainerKey, _T, dict[str, Any]],
169+
items: list[tuple[ContainerKey, _T, dict[str, Any]]],
170+
) -> dict[str, Any] | None:
173171
parameters = signature(item[1]).parameters.items() # type: ignore
174-
kwargs: Dict[str, Any] = {}
172+
kwargs: dict[str, Any] = {}
175173
item[2].update(self._sanitize_item_parameters_before_resolve_or_postpone(parameters, item[2]))
176174
for parameter in parameters:
177175
name: str = parameter[0]
@@ -208,7 +206,7 @@ def _resolve_or_postpone_item(
208206
return None
209207

210208
@classmethod
211-
def _get_instance_of(cls, items: Dict[str, Any], typ: Type[Any]) -> List[Any]:
209+
def _get_instance_of(cls, items: dict[str, Any], typ: Type[Any]) -> list[Any]:
212210
instances = []
213211
for _, val in items.items():
214212
if isinstance(val, typ):
@@ -224,7 +222,7 @@ def _resolve_or_postpone_item_parameter(
224222
self,
225223
name: str,
226224
typ: Type[Any],
227-
item: Tuple[ContainerKey, _T, Dict[str, Any]],
225+
item: tuple[ContainerKey, _T, dict[str, Any]],
228226
) -> Any:
229227
if name not in item[2]:
230228
return None
@@ -245,8 +243,8 @@ def _resolve_or_postpone_item_parameter(
245243

246244
@staticmethod
247245
def _sanitize_item_parameters_before_resolve_or_postpone(
248-
meta_params: AbstractSet[Any], params: Dict[str, Any]
249-
) -> Dict[str, Any]:
246+
meta_params: AbstractSet[Any], params: dict[str, Any]
247+
) -> dict[str, Any]:
250248
for meta_param in meta_params:
251249
name: str = meta_param[0]
252250
typ: Type[Any] = meta_param[1].annotation

aiodi/resolver/__init__.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
from abc import ABC, abstractmethod
2-
from typing import Any, Dict, Generic, NamedTuple, TypeVar
2+
from typing import Any, Generic, NamedTuple, TypeVar
33

44
Metadata = TypeVar('Metadata', bound=NamedTuple)
55
Value = TypeVar('Value', bound=Any)
@@ -43,7 +43,7 @@ def times(self) -> int:
4343

4444
class Resolver(ABC, Generic[Metadata, Value]):
4545
@abstractmethod
46-
def extract_metadata(self, data: Dict[str, Any], extra: Dict[str, Any]) -> Metadata:
46+
def extract_metadata(self, data: dict[str, Any], extra: dict[str, Any]) -> Metadata:
4747
"""
4848
Extract metadata from data
4949
@@ -53,7 +53,7 @@ def extract_metadata(self, data: Dict[str, Any], extra: Dict[str, Any]) -> Metad
5353
"""
5454

5555
@abstractmethod
56-
def parse_value(self, metadata: Metadata, retries: int, extra: Dict[str, Any]) -> Value:
56+
def parse_value(self, metadata: Metadata, retries: int, extra: dict[str, Any]) -> Value:
5757
"""
5858
Parse value from metadata
5959

aiodi/resolver/loader.py

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
11
from pathlib import Path
2-
from typing import Any, Callable, Dict, MutableMapping, NamedTuple, Tuple, Union
2+
from typing import Any, Callable, MutableMapping, NamedTuple
33

44
from . import Resolver
55
from .path import PathData
66
from .service import ServiceDefaults
77

8-
InputData = Union[str, Path]
9-
OutputData = Union[MutableMapping[str, Any], Dict[str, Any]]
8+
InputData = str | Path
9+
OutputData = MutableMapping[str, Any] | dict[str, Any]
1010

1111

1212
class LoaderMetadata(NamedTuple):
1313
path_data: PathData
14-
decoders: Dict[str, Callable[[InputData], OutputData]]
14+
decoders: dict[str, Callable[[InputData], OutputData]]
1515

1616
def decode(self) -> OutputData:
1717
for filepath in self.path_data.filepaths:
@@ -29,8 +29,8 @@ def decode(self) -> OutputData:
2929

3030

3131
class LoadData(NamedTuple):
32-
variables: Dict[str, Any]
33-
services: Dict[str, Any]
32+
variables: dict[str, Any]
33+
services: dict[str, Any]
3434
service_defaults: ServiceDefaults
3535

3636
@classmethod
@@ -62,7 +62,7 @@ def from_metadata(cls, metadata: LoaderMetadata, data: OutputData) -> 'LoadData'
6262

6363

6464
class LoaderResolver(Resolver[LoaderMetadata, LoadData]):
65-
def extract_metadata(self, data: Dict[str, Any], extra: Dict[str, Any]) -> LoaderMetadata: # pylint: disable=W0613
65+
def extract_metadata(self, data: dict[str, Any], extra: dict[str, Any]) -> LoaderMetadata: # pylint: disable=W0613
6666
return LoaderMetadata(
6767
path_data=data['path_data'],
6868
decoders=data['decoders'],
@@ -72,14 +72,14 @@ def parse_value(
7272
self,
7373
metadata: LoaderMetadata,
7474
retries: int, # pylint: disable=W0613
75-
extra: Dict[str, Any], # pylint: disable=W0613
75+
extra: dict[str, Any], # pylint: disable=W0613
7676
) -> LoadData:
7777
return LoadData.from_metadata(metadata=metadata, data=metadata.decode())
7878

7979

8080
def prepare_loader_to_parse(
81-
resolver: Resolver[Any, Any], items: Dict[str, Any], extra: Dict[str, Any] # pylint: disable=W0613
82-
) -> Dict[str, Tuple[LoaderMetadata, int]]:
81+
resolver: Resolver[Any, Any], items: dict[str, Any], extra: dict[str, Any] # pylint: disable=W0613
82+
) -> dict[str, tuple[LoaderMetadata, int]]:
8383
return {
8484
'value': (resolver.extract_metadata(data=items, extra=extra), 0),
8585
}

0 commit comments

Comments
 (0)