Skip to content

Commit 577a24d

Browse files
committed
feat: 更新支持的最低 Python 版本为 3.11
1 parent d2cc397 commit 577a24d

File tree

58 files changed

+2214
-2665
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

58 files changed

+2214
-2665
lines changed

.github/workflows/test.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ jobs:
1919
cancel-in-progress: true
2020
strategy:
2121
matrix:
22-
python-version: ['3.9', '3.10', '3.11', '3.12', '3.13']
22+
python-version: ['3.11', '3.12', '3.13']
2323
os: [ubuntu-latest, windows-latest, macos-latest]
2424
fail-fast: false
2525
env:

README.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,14 @@ AliceBot 是一个简单的 Python 异步多后端机器人框架,支持多种
128128

129129
更多信息请参阅 AliceBot [文档](https://docs.alicebot.dev/)
130130

131+
# 支持的 Python 版本
132+
133+
AliceBot 的最新版本仅支持最近的三个 Python 主要版本。
134+
135+
当前支持的最低 Python 版本为:
136+
137+
<img src="https://img.shields.io/python/required-version-toml?tomlFilePath=https%3A%2F%2Fgithub.com%2FAliceBotProject%2Falicebot%2Fraw%2Fmain%2Fpyproject.toml" alt="pypi">
138+
131139
## 对比
132140

133141
本项目受到了 [NoneBot](https://github.com/nonebot/nonebot2) 项目的启发,以下简单介绍两者的异同。

alicebot/adapter/__init__.py

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,11 @@
55

66
import os
77
from abc import ABC, abstractmethod
8-
from collections.abc import Awaitable
8+
from collections.abc import Awaitable, Callable
99
from typing import (
1010
TYPE_CHECKING,
1111
Any,
12-
Callable,
1312
Generic,
14-
Optional,
15-
Union,
1613
final,
1714
overload,
1815
)
@@ -108,33 +105,33 @@ async def shutdown(self) -> None:
108105
@overload
109106
async def get(
110107
self,
111-
func: Optional[Callable[[EventT], Union[bool, Awaitable[bool]]]] = None,
108+
func: Callable[[EventT], bool | Awaitable[bool]] | None = None,
112109
*,
113110
event_type: None = None,
114-
max_try_times: Optional[int] = None,
115-
timeout: Optional[Union[int, float]] = None,
111+
max_try_times: int | None = None,
112+
timeout: float | None = None,
116113
to_thread: bool = False,
117114
) -> EventT: ...
118115

119116
@overload
120117
async def get(
121118
self,
122-
func: Optional[Callable[[_EventT], Union[bool, Awaitable[bool]]]] = None,
119+
func: Callable[[_EventT], bool | Awaitable[bool]] | None = None,
123120
*,
124121
event_type: type[_EventT],
125-
max_try_times: Optional[int] = None,
126-
timeout: Optional[Union[int, float]] = None,
122+
max_try_times: int | None = None,
123+
timeout: float | None = None,
127124
to_thread: bool = False,
128125
) -> _EventT: ...
129126

130127
@final
131128
async def get(
132129
self,
133-
func: Optional[Callable[[Any], Union[bool, Awaitable[bool]]]] = None,
130+
func: Callable[[Any], bool | Awaitable[bool]] | None = None,
134131
*,
135132
event_type: Any = None,
136-
max_try_times: Optional[int] = None,
137-
timeout: Optional[Union[int, float]] = None,
133+
max_try_times: int | None = None,
134+
timeout: float | None = None,
138135
to_thread: bool = False,
139136
) -> Event[Any]:
140137
"""获取满足指定条件的的事件,协程会等待直到适配器接收到满足条件的事件、超过最大事件数或超时。

alicebot/adapter/utils.py

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
"""
55

66
from abc import ABCMeta, abstractmethod
7-
from typing import Literal, Optional, Union
7+
from typing import Literal
88
from typing_extensions import override
99

1010
import aiohttp
@@ -171,17 +171,15 @@ class WebSocketAdapter(Adapter[EventT, ConfigT], metaclass=ABCMeta):
171171
同时支持 WebSocket 客户端和服务端。
172172
"""
173173

174-
websocket: Union[web.WebSocketResponse, aiohttp.ClientWebSocketResponse, None] = (
175-
None
176-
)
174+
websocket: web.WebSocketResponse | aiohttp.ClientWebSocketResponse | None = None
177175

178176
# ws
179-
session: Optional[aiohttp.ClientSession]
177+
session: aiohttp.ClientSession | None
180178

181179
# reverse-ws
182-
app: Optional[web.Application]
183-
runner: Optional[web.AppRunner]
184-
site: Optional[web.TCPSite]
180+
app: web.Application | None
181+
runner: web.AppRunner | None
182+
site: web.TCPSite | None
185183

186184
# config
187185
adapter_type: Literal["ws", "reverse-ws"]

alicebot/bot.py

Lines changed: 35 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,13 @@
88
import signal
99
import sys
1010
import threading
11+
import tomllib
1112
from collections import defaultdict
12-
from collections.abc import Awaitable
13+
from collections.abc import Awaitable, Callable
1314
from contextlib import AsyncExitStack
1415
from itertools import chain
1516
from pathlib import Path
16-
from typing import Any, Callable, Optional, Union, cast, overload
17+
from typing import Any, cast, overload
1718

1819
import anyio
1920
import structlog
@@ -36,12 +37,6 @@
3637
samefile,
3738
)
3839

39-
if sys.version_info >= (3, 11): # pragma: no cover
40-
import tomllib
41-
else: # pragma: no cover
42-
import tomli as tomllib
43-
44-
4540
__all__ = ["Bot"]
4641

4742
HANDLED_SIGNALS = (
@@ -81,19 +76,19 @@ class Bot:
8176
_raw_config_dict: dict[str, Any] # 原始配置字典
8277

8378
# 以下属性不会在重启时清除
84-
_config_file: Optional[str] # 配置文件
85-
_config_dict: Optional[dict[str, Any]] # 配置字典
79+
_config_file: str | None # 配置文件
80+
_config_dict: dict[str, Any] | None # 配置字典
8681
_hot_reload: bool # 热重载
8782
_handle_signals: bool # 处理信号
8883

8984
_extend_plugins: list[
90-
Union[type[Plugin[Any, Any, Any]], str, Path]
85+
type[Plugin[Any, Any, Any]] | str | Path
9186
] # 使用 load_plugins() 方法程序化加载的插件列表
9287
_extend_plugin_dirs: list[
9388
Path
9489
] # 使用 load_plugins_from_dirs() 方法程序化加载的插件路径列表
9590
_extend_adapters: list[
96-
Union[type[Adapter[Any, Any]], str]
91+
type[Adapter[Any, Any]] | str
9792
] # 使用 load_adapter() 方法程序化加载的适配器列表
9893
_bot_run_hooks: list[BotHook]
9994
_bot_exit_hooks: list[BotHook]
@@ -106,8 +101,8 @@ class Bot:
106101
def __init__(
107102
self,
108103
*,
109-
config_file: Optional[str] = "config.toml",
110-
config_dict: Optional[dict[str, Any]] = None,
104+
config_file: str | None = "config.toml",
105+
config_dict: dict[str, Any] | None = None,
111106
hot_reload: bool = False,
112107
handle_signals: bool = True,
113108
) -> None:
@@ -269,7 +264,7 @@ def _remove_plugin_by_path(
269264
async def _run_hot_reload(self) -> None: # pragma: no cover
270265
"""热重载。"""
271266
try:
272-
from watchfiles import Change, awatch
267+
from watchfiles import Change, awatch # noqa: PLC0415
273268
except ImportError:
274269
logger.warning(
275270
'Hot reload needs to install "watchfiles", try "pip install watchfiles"'
@@ -346,7 +341,7 @@ def _update_config(self) -> None:
346341
"""更新 config,合并入来自 Plugin 和 Adapter 的 Config。"""
347342

348343
def update_config(
349-
source: Union[list[type[Plugin[Any, Any, Any]]], list[Adapter[Any, Any]]],
344+
source: list[type[Plugin[Any, Any, Any]]] | list[Adapter[Any, Any]],
350345
name: str,
351346
base: type[ConfigModel],
352347
) -> tuple[type[ConfigModel], ConfigModel]:
@@ -578,47 +573,47 @@ async def _run_plugin(
578573
@overload
579574
async def get(
580575
self,
581-
func: Optional[Callable[[Event[Any]], Union[bool, Awaitable[bool]]]] = None,
576+
func: Callable[[Event[Any]], bool | Awaitable[bool]] | None = None,
582577
*,
583578
event_type: None = None,
584579
adapter_type: None = None,
585-
max_try_times: Optional[int] = None,
586-
timeout: Optional[Union[int, float]] = None,
580+
max_try_times: int | None = None,
581+
timeout: float | None = None,
587582
to_thread: bool = False,
588583
) -> Event[Any]: ...
589584

590585
@overload
591586
async def get(
592587
self,
593-
func: Optional[Callable[[EventT], Union[bool, Awaitable[bool]]]] = None,
588+
func: Callable[[EventT], bool | Awaitable[bool]] | None = None,
594589
*,
595590
event_type: None = None,
596591
adapter_type: type[Adapter[EventT, Any]],
597-
max_try_times: Optional[int] = None,
598-
timeout: Optional[Union[int, float]] = None,
592+
max_try_times: int | None = None,
593+
timeout: float | None = None,
599594
to_thread: bool = False,
600595
) -> EventT: ...
601596

602597
@overload
603598
async def get(
604599
self,
605-
func: Optional[Callable[[EventT], Union[bool, Awaitable[bool]]]] = None,
600+
func: Callable[[EventT], bool | Awaitable[bool]] | None = None,
606601
*,
607602
event_type: type[EventT],
608-
adapter_type: Optional[type[Adapter[Any, Any]]] = None,
609-
max_try_times: Optional[int] = None,
610-
timeout: Optional[Union[int, float]] = None,
603+
adapter_type: type[Adapter[Any, Any]] | None = None,
604+
max_try_times: int | None = None,
605+
timeout: float | None = None,
611606
to_thread: bool = False,
612607
) -> EventT: ...
613608

614609
async def get(
615610
self,
616-
func: Optional[Callable[[Any], Union[bool, Awaitable[bool]]]] = None,
611+
func: Callable[[Any], bool | Awaitable[bool]] | None = None,
617612
*,
618-
event_type: Optional[type[Event[Any]]] = None,
619-
adapter_type: Optional[type[Adapter[Any, Any]]] = None,
620-
max_try_times: Optional[int] = None,
621-
timeout: Optional[Union[int, float]] = None,
613+
event_type: type[Event[Any]] | None = None,
614+
adapter_type: type[Adapter[Any, Any]] | None = None,
615+
max_try_times: int | None = None,
616+
timeout: float | None = None,
622617
to_thread: bool = False,
623618
) -> Event[Any]:
624619
"""获取满足指定条件的的事件,协程会等待直到适配器接收到满足条件的事件、超过最大事件数或超时。
@@ -655,7 +650,7 @@ def _load_plugin_class(
655650
self,
656651
plugin_class: type[Plugin[Any, Any, Any]],
657652
plugin_load_type: PluginLoadType,
658-
plugin_file_path: Optional[str],
653+
plugin_file_path: str | None,
659654
) -> None:
660655
"""加载插件类。"""
661656
priority = getattr(plugin_class, "priority", None)
@@ -703,8 +698,8 @@ def _load_plugins_from_module_name(
703698

704699
def _load_plugins(
705700
self,
706-
*plugins: Union[type[Plugin[Any, Any, Any]], str, Path],
707-
plugin_load_type: Optional[PluginLoadType] = None,
701+
*plugins: type[Plugin[Any, Any, Any]] | str | Path,
702+
plugin_load_type: PluginLoadType | None = None,
708703
reload: bool = False,
709704
) -> None:
710705
"""加载插件。
@@ -762,7 +757,7 @@ def _load_plugins(
762757
plugin_module_name = ".".join(rel_path.parts[:-1])
763758
else:
764759
plugin_module_name = ".".join(
765-
rel_path.parts[:-1] + (rel_path.stem,)
760+
(*rel_path.parts[:-1], rel_path.stem)
766761
)
767762

768763
self._load_plugins_from_module_name(
@@ -777,9 +772,7 @@ def _load_plugins(
777772
except Exception:
778773
logger.exception("Load plugin failed:", plugin=plugin_)
779774

780-
def load_plugins(
781-
self, *plugins: Union[type[Plugin[Any, Any, Any]], str, Path]
782-
) -> None:
775+
def load_plugins(self, *plugins: type[Plugin[Any, Any, Any]] | str | Path) -> None:
783776
"""加载插件。
784777
785778
Args:
@@ -820,7 +813,7 @@ def load_plugins_from_dirs(self, *dirs: Path) -> None:
820813
self._extend_plugin_dirs.extend(dirs)
821814
self._load_plugins_from_dirs(*dirs)
822815

823-
def _load_adapters(self, *adapters: Union[type[Adapter[Any, Any]], str]) -> None:
816+
def _load_adapters(self, *adapters: type[Adapter[Any, Any]] | str) -> None:
824817
"""加载适配器。
825818
826819
Args:
@@ -864,7 +857,7 @@ def _load_adapters(self, *adapters: Union[type[Adapter[Any, Any]], str]) -> None
864857
else:
865858
self.adapters.append(adapter_object)
866859

867-
def load_adapters(self, *adapters: Union[type[Adapter[Any, Any]], str]) -> None:
860+
def load_adapters(self, *adapters: type[Adapter[Any, Any]] | str) -> None:
868861
"""加载适配器。
869862
870863
Args:
@@ -883,8 +876,8 @@ def get_adapter(self, adapter: str) -> Adapter[Any, Any]: ...
883876
def get_adapter(self, adapter: type[AdapterT]) -> AdapterT: ...
884877

885878
def get_adapter(
886-
self, adapter: Union[str, type[AdapterT]]
887-
) -> Union[Adapter[Any, Any], AdapterT]:
879+
self, adapter: str | type[AdapterT]
880+
) -> Adapter[Any, Any] | AdapterT:
888881
"""按照名称或适配器类获取已经加载的适配器。
889882
890883
Args:

alicebot/config.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,6 @@
33
AliceBot 使用 [pydantic](https://pydantic-docs.helpmanual.io/) 来读取配置。
44
"""
55

6-
from typing import Optional, Union
7-
86
from pydantic import BaseModel, ConfigDict, DirectoryPath, Field
97

108
__all__ = [
@@ -37,7 +35,7 @@ class LogConfig(ConfigModel):
3735
verbose_exception: 详细的异常记录,设置为 `True` 时会在日志中添加异常的 Traceback。
3836
"""
3937

40-
level: Union[str, int] = "DEBUG"
38+
level: str | int = "DEBUG"
4139
verbose_exception: bool = False
4240

4341

@@ -56,7 +54,7 @@ class BotConfig(ConfigModel):
5654
plugins: set[str] = Field(default_factory=set[str])
5755
plugin_dirs: set[DirectoryPath] = Field(default_factory=set[DirectoryPath])
5856
adapters: set[str] = Field(default_factory=set[str])
59-
log: Optional[LogConfig] = None
57+
log: LogConfig | None = None
6058

6159

6260
class PluginConfig(ConfigModel):

0 commit comments

Comments
 (0)