Skip to content

Commit

Permalink
feat: 移除 Python 3.8 支持 (#129)
Browse files Browse the repository at this point in the history
BREAKING CHANGE: 移除 Python 3.8 支持
  • Loading branch information
st1020 authored Jul 15, 2024
1 parent ca3db21 commit 1813a64
Show file tree
Hide file tree
Showing 48 changed files with 1,474 additions and 1,384 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ jobs:
cancel-in-progress: true
strategy:
matrix:
python-version: ['3.8', '3.9', '3.10', '3.11', '3.12']
python-version: ['3.9', '3.10', '3.11', '3.12']
os: [ubuntu-latest, windows-latest, macos-latest]
fail-fast: false
env:
Expand Down
7 changes: 3 additions & 4 deletions alicebot/adapter/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,13 @@

import os
from abc import ABC, abstractmethod
from collections.abc import Awaitable
from typing import (
TYPE_CHECKING,
Any,
Awaitable,
Callable,
Generic,
Optional,
Type,
TypeVar,
Union,
final,
Expand Down Expand Up @@ -50,7 +49,7 @@ class Adapter(Generic[EventT, ConfigT], ABC):

name: str
bot: "Bot"
Config: Type[ConfigT]
Config: type[ConfigT]

def __init__(self, bot: "Bot") -> None:
"""初始化。
Expand Down Expand Up @@ -120,7 +119,7 @@ async def get(
self,
func: Optional[Callable[[_EventT], Union[bool, Awaitable[bool]]]] = None,
*,
event_type: Type[_EventT],
event_type: type[_EventT],
max_try_times: Optional[int] = None,
timeout: Optional[Union[int, float]] = None,
) -> _EventT: ...
Expand Down
7 changes: 4 additions & 3 deletions alicebot/adapter/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,9 +72,10 @@ class WebSocketClientAdapter(Adapter[EventT, ConfigT], metaclass=ABCMeta):

async def run(self) -> None:
"""运行适配器。"""
async with aiohttp.ClientSession() as session, session.ws_connect(
self.url
) as ws:
async with (
aiohttp.ClientSession() as session,
session.ws_connect(self.url) as ws,
):
msg: aiohttp.WSMessage
async for msg in ws:
if self.bot.should_exit.is_set():
Expand Down
102 changes: 44 additions & 58 deletions alicebot/bot.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,28 +11,14 @@
import threading
import time
from collections import defaultdict
from collections.abc import Awaitable
from contextlib import AsyncExitStack
from itertools import chain
from pathlib import Path
from typing import (
Any,
Awaitable,
Callable,
Dict,
List,
Optional,
Set,
Tuple,
Type,
Union,
overload,
)
from typing import Any, Callable, Optional, Union, overload

import structlog
from pydantic import (
ValidationError,
create_model, # pyright: ignore[reportUnknownVariableType]
)
from pydantic import ValidationError, create_model

from alicebot.adapter import Adapter
from alicebot.config import AdapterConfig, ConfigModel, MainConfig, PluginConfig
Expand Down Expand Up @@ -86,51 +72,51 @@ class Bot:

config: MainConfig
should_exit: asyncio.Event # pyright: ignore[reportUninitializedInstanceVariable]
adapters: List[Adapter[Any, Any]]
plugins_priority_dict: Dict[int, List[Type[Plugin[Any, Any, Any]]]]
plugin_state: Dict[str, Any]
global_state: Dict[Any, Any]
adapters: list[Adapter[Any, Any]]
plugins_priority_dict: dict[int, list[type[Plugin[Any, Any, Any]]]]
plugin_state: dict[str, Any]
global_state: dict[Any, Any]

_condition: asyncio.Condition # 用于处理 get 的 Condition # pyright: ignore[reportUninitializedInstanceVariable]
_current_event: Optional[Event[Any]] # 当前待处理的 Event

_restart_flag: bool # 重新启动标志
_module_path_finder: ModulePathFinder # 用于查找 plugins 的模块元路径查找器
_raw_config_dict: Dict[str, Any] # 原始配置字典
_adapter_tasks: Set[
_raw_config_dict: dict[str, Any] # 原始配置字典
_adapter_tasks: set[
"asyncio.Task[None]"
] # 适配器任务集合,用于保持对适配器任务的引用
_handle_event_tasks: Set[
_handle_event_tasks: set[
"asyncio.Task[None]"
] # 事件处理任务,用于保持对适配器任务的引用

# 以下属性不会在重启时清除
_config_file: Optional[str] # 配置文件
_config_dict: Optional[Dict[str, Any]] # 配置字典
_config_dict: Optional[dict[str, Any]] # 配置字典
_hot_reload: bool # 热重载

_extend_plugins: List[
Union[Type[Plugin[Any, Any, Any]], str, Path]
_extend_plugins: list[
Union[type[Plugin[Any, Any, Any]], str, Path]
] # 使用 load_plugins() 方法程序化加载的插件列表
_extend_plugin_dirs: List[
_extend_plugin_dirs: list[
Path
] # 使用 load_plugins_from_dirs() 方法程序化加载的插件路径列表
_extend_adapters: List[
Union[Type[Adapter[Any, Any]], str]
_extend_adapters: list[
Union[type[Adapter[Any, Any]], str]
] # 使用 load_adapter() 方法程序化加载的适配器列表
_bot_run_hooks: List[BotHook]
_bot_exit_hooks: List[BotHook]
_adapter_startup_hooks: List[AdapterHook]
_adapter_run_hooks: List[AdapterHook]
_adapter_shutdown_hooks: List[AdapterHook]
_event_preprocessor_hooks: List[EventHook]
_event_postprocessor_hooks: List[EventHook]
_bot_run_hooks: list[BotHook]
_bot_exit_hooks: list[BotHook]
_adapter_startup_hooks: list[AdapterHook]
_adapter_run_hooks: list[AdapterHook]
_adapter_shutdown_hooks: list[AdapterHook]
_event_preprocessor_hooks: list[EventHook]
_event_postprocessor_hooks: list[EventHook]

def __init__(
self,
*,
config_file: Optional[str] = "config.toml",
config_dict: Optional[Dict[str, Any]] = None,
config_dict: Optional[dict[str, Any]] = None,
hot_reload: bool = False,
) -> None:
"""初始化 AliceBot,读取配置文件,创建配置,加载适配器和插件。
Expand Down Expand Up @@ -174,7 +160,7 @@ def __init__(
sys.meta_path.insert(0, self._module_path_finder)

@property
def plugins(self) -> List[Type[Plugin[Any, Any, Any]]]:
def plugins(self) -> list[type[Plugin[Any, Any, Any]]]:
"""当前已经加载的插件的列表。"""
return list(chain(*self.plugins_priority_dict.values()))

Expand Down Expand Up @@ -269,9 +255,9 @@ async def _run(self) -> None:

def _remove_plugin_by_path(
self, file: Path
) -> List[Type[Plugin[Any, Any, Any]]]: # pragma: no cover
) -> list[type[Plugin[Any, Any, Any]]]: # pragma: no cover
"""根据路径删除已加载的插件。"""
removed_plugins: List[Type[Plugin[Any, Any, Any]]] = []
removed_plugins: list[type[Plugin[Any, Any, Any]]] = []
for plugins in self.plugins_priority_dict.values():
_removed_plugins = list(
filter(
Expand Down Expand Up @@ -369,11 +355,11 @@ def _update_config(self) -> None:
"""更新 config,合并入来自 Plugin 和 Adapter 的 Config。"""

def update_config(
source: Union[List[Type[Plugin[Any, Any, Any]]], List[Adapter[Any, Any]]],
source: Union[list[type[Plugin[Any, Any, Any]]], list[Adapter[Any, Any]]],
name: str,
base: Type[ConfigModel],
) -> Tuple[Type[ConfigModel], ConfigModel]:
config_update_dict: Dict[str, Any] = {}
base: type[ConfigModel],
) -> tuple[type[ConfigModel], ConfigModel]:
config_update_dict: dict[str, Any] = {}
for i in source:
config_class = getattr(i, "Config", None)
if is_config_class(config_class):
Expand Down Expand Up @@ -576,7 +562,7 @@ async def get(
func: Optional[Callable[[EventT], Union[bool, Awaitable[bool]]]] = None,
*,
event_type: None = None,
adapter_type: Type[Adapter[EventT, Any]],
adapter_type: type[Adapter[EventT, Any]],
max_try_times: Optional[int] = None,
timeout: Optional[Union[int, float]] = None,
) -> EventT: ...
Expand All @@ -586,8 +572,8 @@ async def get(
self,
func: Optional[Callable[[EventT], Union[bool, Awaitable[bool]]]] = None,
*,
event_type: Type[EventT],
adapter_type: Optional[Type[AdapterT]] = None,
event_type: type[EventT],
adapter_type: Optional[type[AdapterT]] = None,
max_try_times: Optional[int] = None,
timeout: Optional[Union[int, float]] = None,
) -> EventT: ...
Expand All @@ -596,8 +582,8 @@ async def get(
self,
func: Optional[Callable[[Any], Union[bool, Awaitable[bool]]]] = None,
*,
event_type: Optional[Type[Event[Any]]] = None,
adapter_type: Optional[Type[Adapter[Any, Any]]] = None,
event_type: Optional[type[Event[Any]]] = None,
adapter_type: Optional[type[Adapter[Any, Any]]] = None,
max_try_times: Optional[int] = None,
timeout: Optional[Union[int, float]] = None,
) -> Event[Any]:
Expand Down Expand Up @@ -662,7 +648,7 @@ async def get(

def _load_plugin_class(
self,
plugin_class: Type[Plugin[Any, Any, Any]],
plugin_class: type[Plugin[Any, Any, Any]],
plugin_load_type: PluginLoadType,
plugin_file_path: Optional[str],
) -> None:
Expand Down Expand Up @@ -712,7 +698,7 @@ def _load_plugins_from_module_name(

def _load_plugins(
self,
*plugins: Union[Type[Plugin[Any, Any, Any]], str, Path],
*plugins: Union[type[Plugin[Any, Any, Any]], str, Path],
plugin_load_type: Optional[PluginLoadType] = None,
reload: bool = False,
) -> None:
Expand Down Expand Up @@ -787,7 +773,7 @@ def _load_plugins(
logger.exception("Load plugin failed:", plugin=plugin_)

def load_plugins(
self, *plugins: Union[Type[Plugin[Any, Any, Any]], str, Path]
self, *plugins: Union[type[Plugin[Any, Any, Any]], str, Path]
) -> None:
"""加载插件。
Expand Down Expand Up @@ -829,7 +815,7 @@ def load_plugins_from_dirs(self, *dirs: Path) -> None:
self._extend_plugin_dirs.extend(dirs)
self._load_plugins_from_dirs(*dirs)

def _load_adapters(self, *adapters: Union[Type[Adapter[Any, Any]], str]) -> None:
def _load_adapters(self, *adapters: Union[type[Adapter[Any, Any]], str]) -> None:
"""加载适配器。
Args:
Expand Down Expand Up @@ -873,7 +859,7 @@ def _load_adapters(self, *adapters: Union[Type[Adapter[Any, Any]], str]) -> None
else:
self.adapters.append(adapter_object)

def load_adapters(self, *adapters: Union[Type[Adapter[Any, Any]], str]) -> None:
def load_adapters(self, *adapters: Union[type[Adapter[Any, Any]], str]) -> None:
"""加载适配器。
Args:
Expand All @@ -889,10 +875,10 @@ def load_adapters(self, *adapters: Union[Type[Adapter[Any, Any]], str]) -> None:
def get_adapter(self, adapter: str) -> Adapter[Any, Any]: ...

@overload
def get_adapter(self, adapter: Type[AdapterT]) -> AdapterT: ...
def get_adapter(self, adapter: type[AdapterT]) -> AdapterT: ...

def get_adapter(
self, adapter: Union[str, Type[AdapterT]]
self, adapter: Union[str, type[AdapterT]]
) -> Union[Adapter[Any, Any], AdapterT]:
"""按照名称或适配器类获取已经加载的适配器。
Expand All @@ -913,7 +899,7 @@ def get_adapter(
return _adapter
raise LookupError(f'Can not find adapter named "{adapter}"')

def get_plugin(self, name: str) -> Type[Plugin[Any, Any, Any]]:
def get_plugin(self, name: str) -> type[Plugin[Any, Any, Any]]:
"""按照名称获取已经加载的插件类。
Args:
Expand Down
8 changes: 4 additions & 4 deletions alicebot/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
AliceBot 使用 [pydantic](https://pydantic-docs.helpmanual.io/) 来读取配置。
"""

from typing import Optional, Set, Union
from typing import Optional, Union

from pydantic import BaseModel, ConfigDict, DirectoryPath, Field

Expand Down Expand Up @@ -51,9 +51,9 @@ class BotConfig(ConfigModel):
log: AliceBot 日志相关设置。
"""

plugins: Set[str] = Field(default_factory=set)
plugin_dirs: Set[DirectoryPath] = Field(default_factory=set)
adapters: Set[str] = Field(default_factory=set)
plugins: set[str] = Field(default_factory=set)
plugin_dirs: set[DirectoryPath] = Field(default_factory=set)
adapters: set[str] = Field(default_factory=set)
log: Optional[LogConfig] = None


Expand Down
34 changes: 14 additions & 20 deletions alicebot/dependencies.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,28 +4,22 @@
"""

import inspect
from contextlib import AsyncExitStack, asynccontextmanager, contextmanager
from typing import (
Any,
AsyncContextManager,
AsyncGenerator,
Callable,
ContextManager,
Dict,
Generator,
Optional,
Type,
TypeVar,
Union,
cast,
from collections.abc import AsyncGenerator, Generator
from contextlib import (
AbstractAsyncContextManager,
AbstractContextManager,
AsyncExitStack,
asynccontextmanager,
contextmanager,
)
from typing import Any, Callable, Optional, TypeVar, Union, cast

from alicebot.utils import get_annotations, sync_ctx_manager_wrapper

_T = TypeVar("_T")
Dependency = Union[
# Class
Type[Union[_T, AsyncContextManager[_T], ContextManager[_T]]],
type[Union[_T, AbstractAsyncContextManager[_T], AbstractContextManager[_T]]],
# GeneratorContextManager
Callable[[], AsyncGenerator[_T, None]],
Callable[[], Generator[_T, None, None]],
Expand Down Expand Up @@ -80,7 +74,7 @@ async def solve_dependencies(
*,
use_cache: bool,
stack: AsyncExitStack,
dependency_cache: Dict[Dependency[Any], Any],
dependency_cache: dict[Dependency[Any], Any],
) -> _T:
"""解析子依赖。
Expand All @@ -101,7 +95,7 @@ async def solve_dependencies(

if isinstance(dependent, type):
# type of dependent is Type[T]
values: Dict[str, Any] = {}
values: dict[str, Any] = {}
ann = get_annotations(dependent)
for name, sub_dependent in inspect.getmembers(
dependent, lambda x: isinstance(x, InnerDepends)
Expand All @@ -119,16 +113,16 @@ async def solve_dependencies(
dependency_cache=dependency_cache,
)
depend_obj = cast(
Union[_T, AsyncContextManager[_T], ContextManager[_T]],
Union[_T, AbstractAsyncContextManager[_T], AbstractContextManager[_T]],
dependent.__new__(dependent), # pyright: ignore
)
for key, value in values.items():
setattr(depend_obj, key, value)
depend_obj.__init__() # type: ignore[misc] # pylint: disable=unnecessary-dunder-call

if isinstance(depend_obj, AsyncContextManager):
if isinstance(depend_obj, AbstractAsyncContextManager):
depend = await stack.enter_async_context(depend_obj)
elif isinstance(depend_obj, ContextManager):
elif isinstance(depend_obj, AbstractContextManager):
depend = await stack.enter_async_context(
sync_ctx_manager_wrapper(depend_obj)
)
Expand Down
Loading

0 comments on commit 1813a64

Please sign in to comment.