From 08ad5c288ccb9208d76cd9b18589bba57ecc2e7c Mon Sep 17 00:00:00 2001 From: Azide Date: Tue, 17 Dec 2024 10:52:21 +0800 Subject: [PATCH] =?UTF-8?q?:technologist:=20=E4=BD=BF=E7=94=A8=20Ruff=20?= =?UTF-8?q?=E5=8C=85=E5=8A=9E=E6=89=80=E6=9C=89=E6=A0=BC=E5=BC=8F=E5=8C=96?= =?UTF-8?q?=E5=92=8C=E6=A3=80=E6=9F=A5=20(#663)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/ruff.yml | 7 +- .pre-commit-config.yaml | 16 +- README.md | 3 - extra_plugins/auto_agree.py | 4 +- nonebot_bison/__init__.py | 8 +- nonebot_bison/admin_page/__init__.py | 11 +- nonebot_bison/admin_page/api.py | 39 ++--- nonebot_bison/admin_page/jwt.py | 2 +- nonebot_bison/admin_page/token_manager.py | 2 +- nonebot_bison/admin_page/types.py | 2 +- nonebot_bison/apis.py | 4 +- nonebot_bison/bootstrap.py | 6 +- nonebot_bison/compat.py | 4 +- nonebot_bison/config/__init__.py | 4 +- nonebot_bison/config/config_legacy.py | 17 ++- nonebot_bison/config/db_config.py | 22 +-- nonebot_bison/config/db_migration.py | 6 +- nonebot_bison/config/db_model.py | 12 +- .../config/migrations/0571870f5222_init_db.py | 2 +- .../migrations/4a46ba54a3f3_alter_type.py | 2 +- .../5f3370328e44_add_time_weight_table.py | 2 +- .../632b8086bc2b_add_user_target.py | 2 +- ...38b3f39c2_make_user_target_not_nullable.py | 2 +- .../8d3863e9d74b_remove_uid_and_type.py | 2 +- .../a333d6224193_add_last_scheduled_time.py | 2 +- .../migrations/a5466912fad0_map_user.py | 4 +- .../aceef470d69c_alter_fields_not_null.py | 2 +- .../bd92923c218f_alter_json_not_null.py | 4 +- .../migrations/f90b712557a9_add_cookie.py | 2 +- .../f9baef347cc8_remove_old_target.py | 4 +- .../config/subs_io/nbesf_model/__init__.py | 2 +- .../config/subs_io/nbesf_model/base.py | 4 +- .../config/subs_io/nbesf_model/v1.py | 23 +-- .../config/subs_io/nbesf_model/v2.py | 23 +-- .../config/subs_io/nbesf_model/v3.py | 31 ++-- nonebot_bison/config/subs_io/subs_io.py | 17 ++- nonebot_bison/platform/__init__.py | 7 +- nonebot_bison/platform/arknights.py | 31 ++-- nonebot_bison/platform/bilibili/__init__.py | 6 +- nonebot_bison/platform/bilibili/fsm.py | 18 +-- nonebot_bison/platform/bilibili/models.py | 6 +- nonebot_bison/platform/bilibili/platforms.py | 53 ++++--- nonebot_bison/platform/bilibili/retry.py | 19 ++- nonebot_bison/platform/bilibili/scheduler.py | 16 +- nonebot_bison/platform/ceobecanteen/cache.py | 14 +- nonebot_bison/platform/ceobecanteen/models.py | 2 +- .../platform/ceobecanteen/platform.py | 30 ++-- nonebot_bison/platform/ceobecanteen/utils.py | 2 +- nonebot_bison/platform/ff14.py | 11 +- nonebot_bison/platform/ncm.py | 15 +- nonebot_bison/platform/platform.py | 22 +-- nonebot_bison/platform/rss.py | 20 +-- nonebot_bison/platform/weibo.py | 29 ++-- nonebot_bison/plugin_config.py | 4 +- nonebot_bison/post/abstract_post.py | 8 +- nonebot_bison/post/post.py | 15 +- nonebot_bison/scheduler/__init__.py | 4 +- nonebot_bison/scheduler/manager.py | 15 +- nonebot_bison/scheduler/scheduler.py | 16 +- nonebot_bison/script/cli.py | 25 +-- nonebot_bison/send.py | 12 +- nonebot_bison/sub_manager/__init__.py | 41 ++--- nonebot_bison/sub_manager/add_cookie.py | 15 +- .../sub_manager/add_cookie_target.py | 18 +-- nonebot_bison/sub_manager/add_sub.py | 17 ++- nonebot_bison/sub_manager/del_cookie.py | 9 +- .../sub_manager/del_cookie_target.py | 9 +- nonebot_bison/sub_manager/del_sub.py | 11 +- nonebot_bison/sub_manager/query_sub.py | 11 +- nonebot_bison/sub_manager/utils.py | 20 +-- nonebot_bison/theme/__init__.py | 5 +- nonebot_bison/theme/registry.py | 7 +- nonebot_bison/theme/themes/arknights/build.py | 8 +- nonebot_bison/theme/themes/basic/build.py | 7 +- nonebot_bison/theme/themes/brief/build.py | 4 +- .../theme/themes/ceobe_canteen/build.py | 19 +-- nonebot_bison/theme/themes/ht2i/build.py | 14 +- nonebot_bison/theme/types.py | 8 +- nonebot_bison/theme/utils.py | 4 +- nonebot_bison/types.py | 6 +- nonebot_bison/utils/__init__.py | 28 ++-- nonebot_bison/utils/context.py | 2 +- nonebot_bison/utils/get_bot.py | 4 +- nonebot_bison/utils/http.py | 2 +- nonebot_bison/utils/image.py | 15 +- nonebot_bison/utils/site.py | 13 +- poetry.lock | 144 +++--------------- pyproject.toml | 58 ++++--- tests/config/test_config_legacy.py | 2 +- tests/config/test_config_operation.py | 18 +-- tests/config/test_cookie.py | 6 +- tests/config/test_data_migration.py | 8 +- tests/config/test_scheduler_conf.py | 12 +- tests/conftest.py | 20 +-- tests/platforms/test_arknights.py | 34 ++--- tests/platforms/test_bilibili.py | 36 ++--- tests/platforms/test_bilibili_bangumi.py | 8 +- tests/platforms/test_bilibili_live.py | 20 +-- tests/platforms/test_ceobecanteen.py | 18 +-- tests/platforms/test_ff14.py | 8 +- tests/platforms/test_ncm_artist.py | 8 +- tests/platforms/test_ncm_radio.py | 8 +- tests/platforms/test_platform.py | 84 +++++----- tests/platforms/test_platform_tag_filter.py | 6 +- tests/platforms/test_rss.py | 18 +-- tests/platforms/test_weibo.py | 16 +- tests/post/test_generate.py | 27 ++-- tests/scheduler/test_site.py | 36 ++--- tests/sub_manager/test_abort.py | 18 +-- tests/sub_manager/test_add.py | 37 ++--- tests/sub_manager/test_add_cookie.py | 10 +- tests/sub_manager/test_admin.py | 4 +- tests/sub_manager/test_delete_cookie.py | 16 +- tests/sub_manager/test_no_permission.py | 4 +- tests/sub_manager/test_query_del.py | 20 +-- tests/subs_io/test_cli.py | 8 +- tests/subs_io/test_subs_io.py | 10 +- tests/test_admin_page.py | 8 +- tests/test_context.py | 4 +- tests/test_get_bot.py | 2 +- tests/test_merge_pic.py | 14 +- tests/test_render.py | 8 +- tests/test_send.py | 16 +- tests/theme/test_registry.py | 2 +- tests/theme/test_themes.py | 27 ++-- tests/utils.py | 9 +- 126 files changed, 875 insertions(+), 933 deletions(-) diff --git a/.github/workflows/ruff.yml b/.github/workflows/ruff.yml index 7269cd8..cbec41c 100644 --- a/.github/workflows/ruff.yml +++ b/.github/workflows/ruff.yml @@ -19,4 +19,9 @@ jobs: - uses: actions/checkout@v4 - name: Run Ruff Lint - uses: chartboost/ruff-action@v1 + uses: astral-sh/ruff-action@v2 + with: + src: >- + nonebot_bison/ + extra_plugins/ + tests/ diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index a8c8b66..c5a1554 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -7,22 +7,12 @@ ci: autoupdate_commit_msg: ":arrow_up: auto update by pre-commit hooks" repos: - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.8.1 + rev: v0.8.2 hooks: - id: ruff - args: [--fix, --exit-non-zero-on-fix] + args: [--fix] stages: [pre-commit] - - - repo: https://github.com/pycqa/isort - rev: 5.13.2 - hooks: - - id: isort - stages: [pre-commit] - - - repo: https://github.com/psf/black - rev: 24.10.0 - hooks: - - id: black + - id: ruff-format stages: [pre-commit] - repo: https://github.com/pre-commit/mirrors-prettier diff --git a/README.md b/README.md index 266bb16..4419b70 100644 --- a/README.md +++ b/README.md @@ -17,9 +17,6 @@ _✨ 通用订阅推送插件 ✨_ pypi python - - black - ruff diff --git a/extra_plugins/auto_agree.py b/extra_plugins/auto_agree.py index 53a85a4..8078a72 100644 --- a/extra_plugins/auto_agree.py +++ b/extra_plugins/auto_agree.py @@ -1,7 +1,7 @@ from nonebot import on_request -from nonebot.log import logger from nonebot.adapters.onebot.v11 import Bot -from nonebot.adapters.onebot.v11.event import GroupRequestEvent, FriendRequestEvent +from nonebot.adapters.onebot.v11.event import FriendRequestEvent, GroupRequestEvent +from nonebot.log import logger friend_req = on_request(priority=5) diff --git a/nonebot_bison/__init__.py b/nonebot_bison/__init__.py index 90da7a1..e939ec9 100644 --- a/nonebot_bison/__init__.py +++ b/nonebot_bison/__init__.py @@ -6,8 +6,8 @@ require("nonebot_plugin_saa") import nonebot_plugin_saa +from . import admin_page, bootstrap, config, platform, post, scheduler, send, sub_manager, theme, types, utils from .plugin_config import PlugConfig, plugin_config -from . import post, send, theme, types, utils, config, platform, bootstrap, scheduler, admin_page, sub_manager __help__version__ = "0.8.2" nonebot_plugin_saa.enable_auto_select_bot() @@ -36,12 +36,12 @@ __all__ = [ "admin_page", "bootstrap", "config", - "sub_manager", + "platform", "post", "scheduler", "send", - "platform", + "sub_manager", + "theme", "types", "utils", - "theme", ] diff --git a/nonebot_bison/admin_page/__init__.py b/nonebot_bison/admin_page/__init__.py index c888bf0..02d0fb6 100644 --- a/nonebot_bison/admin_page/__init__.py +++ b/nonebot_bison/admin_page/__init__.py @@ -2,15 +2,16 @@ import os from pathlib import Path from typing import TYPE_CHECKING -from nonebot.log import logger -from nonebot.rule import to_me -from nonebot.typing import T_State from nonebot import get_driver, on_command from nonebot.adapters.onebot.v11 import Bot from nonebot.adapters.onebot.v11.event import PrivateMessageEvent +from nonebot.log import logger +from nonebot.rule import to_me +from nonebot.typing import T_State + +from nonebot_bison.plugin_config import plugin_config from .api import router as api_router -from ..plugin_config import plugin_config from .token_manager import token_manager as tm if TYPE_CHECKING: @@ -21,9 +22,9 @@ STATIC_PATH = (Path(__file__).parent / "dist").resolve() def init_fastapi(driver: "Driver"): - import socketio from fastapi.applications import FastAPI from fastapi.staticfiles import StaticFiles + import socketio sio = socketio.AsyncServer(async_mode="asgi", cors_allowed_origins="*") socket_app = socketio.ASGIApp(sio, socketio_path="socket") diff --git a/nonebot_bison/admin_page/api.py b/nonebot_bison/admin_page/api.py index da8208c..c816e75 100644 --- a/nonebot_bison/admin_page/api.py +++ b/nonebot_bison/admin_page/api.py @@ -1,38 +1,39 @@ from typing import cast -import nonebot from fastapi import status -from fastapi.routing import APIRouter -from fastapi.param_functions import Depends from fastapi.exceptions import HTTPException +from fastapi.param_functions import Depends +from fastapi.routing import APIRouter +from fastapi.security.oauth2 import OAuth2PasswordBearer +import nonebot from nonebot_plugin_saa import TargetQQGroup from nonebot_plugin_saa.auto_select_bot import get_bot -from fastapi.security.oauth2 import OAuth2PasswordBearer -from ..types import WeightConfig -from ..apis import check_sub_target +from nonebot_bison.apis import check_sub_target +from nonebot_bison.config import NoSuchSubscribeException, NoSuchTargetException, NoSuchUserException, config +from nonebot_bison.config.db_config import SubscribeDupException +from nonebot_bison.platform import platform_manager +from nonebot_bison.scheduler import scheduler_dict +from nonebot_bison.types import Target as T_Target +from nonebot_bison.types import WeightConfig +from nonebot_bison.utils.get_bot import get_groups +from nonebot_bison.utils.site import CookieClientManager, is_cookie_client_manager, site_manager + from .jwt import load_jwt, pack_jwt -from ..scheduler import scheduler_dict -from ..types import Target as T_Target -from ..utils.get_bot import get_groups -from ..platform import platform_manager from .token_manager import token_manager -from ..config.db_config import SubscribeDupException -from ..utils.site import CookieClientManager, site_manager, is_cookie_client_manager -from ..config import NoSuchUserException, NoSuchTargetException, NoSuchSubscribeException, config from .types import ( + AddSubscribeReq, Cookie, - Target, - TokenResp, + CookieTarget, GlobalConf, + PlatformConfig, SiteConfig, StatusResp, - CookieTarget, - SubscribeResp, - PlatformConfig, - AddSubscribeReq, SubscribeConfig, SubscribeGroupDetail, + SubscribeResp, + Target, + TokenResp, ) router = APIRouter(prefix="/api", tags=["api"]) diff --git a/nonebot_bison/admin_page/jwt.py b/nonebot_bison/admin_page/jwt.py index 866c184..16cb1aa 100644 --- a/nonebot_bison/admin_page/jwt.py +++ b/nonebot_bison/admin_page/jwt.py @@ -1,6 +1,6 @@ +import datetime import random import string -import datetime import jwt diff --git a/nonebot_bison/admin_page/token_manager.py b/nonebot_bison/admin_page/token_manager.py index 365ee64..90c3e31 100644 --- a/nonebot_bison/admin_page/token_manager.py +++ b/nonebot_bison/admin_page/token_manager.py @@ -1,6 +1,6 @@ +from datetime import timedelta import random import string -from datetime import timedelta from expiringdictx import ExpiringDict diff --git a/nonebot_bison/admin_page/types.py b/nonebot_bison/admin_page/types.py index a43e90d..316dc7c 100644 --- a/nonebot_bison/admin_page/types.py +++ b/nonebot_bison/admin_page/types.py @@ -60,8 +60,8 @@ class StatusResp(BaseModel): msg: str -from typing import Any from datetime import datetime +from typing import Any from pydantic import BaseModel diff --git a/nonebot_bison/apis.py b/nonebot_bison/apis.py index f13580b..ef81f4c 100644 --- a/nonebot_bison/apis.py +++ b/nonebot_bison/apis.py @@ -1,6 +1,6 @@ -from .types import Target -from .scheduler import scheduler_dict from .platform import platform_manager +from .scheduler import scheduler_dict +from .types import Target async def check_sub_target(platform_name: str, target: Target): diff --git a/nonebot_bison/bootstrap.py b/nonebot_bison/bootstrap.py index 92d06a8..b655966 100644 --- a/nonebot_bison/bootstrap.py +++ b/nonebot_bison/bootstrap.py @@ -1,10 +1,10 @@ from nonebot.log import logger -from sqlalchemy import text, inspect -from nonebot_plugin_datastore.db import get_engine, pre_db_init, post_db_init +from nonebot_plugin_datastore.db import get_engine, post_db_init, pre_db_init +from sqlalchemy import inspect, text +from .config.config_legacy import start_up as legacy_db_startup from .config.db_migration import data_migrate from .scheduler.manager import init_scheduler -from .config.config_legacy import start_up as legacy_db_startup @pre_db_init diff --git a/nonebot_bison/compat.py b/nonebot_bison/compat.py index d4a65a5..2d40fdb 100644 --- a/nonebot_bison/compat.py +++ b/nonebot_bison/compat.py @@ -1,9 +1,9 @@ from typing import Literal, overload -from pydantic import BaseModel from nonebot.compat import PYDANTIC_V2 +from pydantic import BaseModel -__all__ = ("model_validator", "model_rebuild") +__all__ = ("model_rebuild", "model_validator") if PYDANTIC_V2: diff --git a/nonebot_bison/config/__init__.py b/nonebot_bison/config/__init__.py index a04d41f..b3e2d76 100644 --- a/nonebot_bison/config/__init__.py +++ b/nonebot_bison/config/__init__.py @@ -1,4 +1,4 @@ from .db_config import config as config -from .utils import NoSuchUserException as NoSuchUserException -from .utils import NoSuchTargetException as NoSuchTargetException from .utils import NoSuchSubscribeException as NoSuchSubscribeException +from .utils import NoSuchTargetException as NoSuchTargetException +from .utils import NoSuchUserException as NoSuchUserException diff --git a/nonebot_bison/config/config_legacy.py b/nonebot_bison/config/config_legacy.py index 24e7e4d..a0b4c08 100644 --- a/nonebot_bison/config/config_legacy.py +++ b/nonebot_bison/config/config_legacy.py @@ -1,19 +1,20 @@ -import os +from collections import defaultdict +from datetime import datetime import json +import os from os import path from pathlib import Path -from datetime import datetime -from collections import defaultdict from typing import Literal, TypedDict from nonebot.log import logger from tinydb import Query, TinyDB -from ..utils import Singleton -from ..types import User, Target -from ..platform import platform_manager -from ..plugin_config import plugin_config -from .utils import NoSuchUserException, NoSuchSubscribeException +from nonebot_bison.platform import platform_manager +from nonebot_bison.plugin_config import plugin_config +from nonebot_bison.types import Target, User +from nonebot_bison.utils import Singleton + +from .utils import NoSuchSubscribeException, NoSuchUserException supported_target_type = platform_manager.keys() diff --git a/nonebot_bison/config/db_config.py b/nonebot_bison/config/db_config.py index c76078c..f6c6157 100644 --- a/nonebot_bison/config/db_config.py +++ b/nonebot_bison/config/db_config.py @@ -1,20 +1,20 @@ import asyncio from collections import defaultdict -from datetime import time, datetime -from collections.abc import Callable, Sequence, Awaitable +from collections.abc import Awaitable, Callable, Sequence +from datetime import datetime, time from nonebot.compat import model_dump -from sqlalchemy.orm import selectinload -from sqlalchemy.exc import IntegrityError -from sqlalchemy import func, delete, select -from nonebot_plugin_saa import PlatformTarget from nonebot_plugin_datastore import create_session +from nonebot_plugin_saa import PlatformTarget +from sqlalchemy import delete, func, select +from sqlalchemy.exc import IntegrityError +from sqlalchemy.orm import selectinload -from ..types import Tag -from ..types import Target as T_Target -from .utils import NoSuchTargetException, DuplicateCookieTargetException -from .db_model import User, Cookie, Target, Subscribe, CookieTarget, ScheduleTimeWeight -from ..types import Category, UserSubInfo, WeightConfig, TimeWeightConfig, PlatformWeightConfigResp +from nonebot_bison.types import Category, PlatformWeightConfigResp, Tag, TimeWeightConfig, UserSubInfo, WeightConfig +from nonebot_bison.types import Target as T_Target + +from .db_model import Cookie, CookieTarget, ScheduleTimeWeight, Subscribe, Target, User +from .utils import DuplicateCookieTargetException, NoSuchTargetException def _get_time(): diff --git a/nonebot_bison/config/db_migration.py b/nonebot_bison/config/db_migration.py index 75080ad..1ff802a 100644 --- a/nonebot_bison/config/db_migration.py +++ b/nonebot_bison/config/db_migration.py @@ -1,11 +1,11 @@ -from nonebot.log import logger from nonebot.compat import model_dump +from nonebot.log import logger from nonebot_plugin_datastore.db import get_engine -from sqlalchemy.ext.asyncio.session import AsyncSession from nonebot_plugin_saa import TargetQQGroup, TargetQQPrivate +from sqlalchemy.ext.asyncio.session import AsyncSession -from .db_model import User, Target, Subscribe from .config_legacy import Config, ConfigContent, drop +from .db_model import Subscribe, Target, User async def data_migrate(): diff --git a/nonebot_bison/config/db_model.py b/nonebot_bison/config/db_model.py index 94c7d0c..93991a7 100644 --- a/nonebot_bison/config/db_model.py +++ b/nonebot_bison/config/db_model.py @@ -1,15 +1,15 @@ import datetime -from typing import Any from pathlib import Path +from typing import Any -from nonebot_plugin_saa import PlatformTarget -from sqlalchemy.dialects.postgresql import JSONB from nonebot.compat import PYDANTIC_V2, ConfigDict from nonebot_plugin_datastore import get_plugin_data -from sqlalchemy.orm import Mapped, relationship, mapped_column -from sqlalchemy import JSON, String, DateTime, ForeignKey, UniqueConstraint +from nonebot_plugin_saa import PlatformTarget +from sqlalchemy import JSON, DateTime, ForeignKey, String, UniqueConstraint +from sqlalchemy.dialects.postgresql import JSONB +from sqlalchemy.orm import Mapped, mapped_column, relationship -from ..types import Tag, Category +from nonebot_bison.types import Category, Tag Model = get_plugin_data().Model get_plugin_data().set_migration_dir(Path(__file__).parent / "migrations") diff --git a/nonebot_bison/config/migrations/0571870f5222_init_db.py b/nonebot_bison/config/migrations/0571870f5222_init_db.py index 391433f..9f7f334 100644 --- a/nonebot_bison/config/migrations/0571870f5222_init_db.py +++ b/nonebot_bison/config/migrations/0571870f5222_init_db.py @@ -6,8 +6,8 @@ Create Date: 2022-03-21 19:18:13.762626 """ -import sqlalchemy as sa from alembic import op +import sqlalchemy as sa # revision identifiers, used by Alembic. revision = "0571870f5222" diff --git a/nonebot_bison/config/migrations/4a46ba54a3f3_alter_type.py b/nonebot_bison/config/migrations/4a46ba54a3f3_alter_type.py index 4dbeefe..e2e8c13 100644 --- a/nonebot_bison/config/migrations/4a46ba54a3f3_alter_type.py +++ b/nonebot_bison/config/migrations/4a46ba54a3f3_alter_type.py @@ -6,8 +6,8 @@ Create Date: 2022-03-27 21:50:10.911649 """ -import sqlalchemy as sa from alembic import op +import sqlalchemy as sa # revision identifiers, used by Alembic. revision = "4a46ba54a3f3" diff --git a/nonebot_bison/config/migrations/5f3370328e44_add_time_weight_table.py b/nonebot_bison/config/migrations/5f3370328e44_add_time_weight_table.py index 696dfa7..bbfd27b 100644 --- a/nonebot_bison/config/migrations/5f3370328e44_add_time_weight_table.py +++ b/nonebot_bison/config/migrations/5f3370328e44_add_time_weight_table.py @@ -6,8 +6,8 @@ Create Date: 2022-05-31 22:05:13.235981 """ -import sqlalchemy as sa from alembic import op +import sqlalchemy as sa # revision identifiers, used by Alembic. revision = "5f3370328e44" diff --git a/nonebot_bison/config/migrations/632b8086bc2b_add_user_target.py b/nonebot_bison/config/migrations/632b8086bc2b_add_user_target.py index a6f5e3a..26cc354 100644 --- a/nonebot_bison/config/migrations/632b8086bc2b_add_user_target.py +++ b/nonebot_bison/config/migrations/632b8086bc2b_add_user_target.py @@ -6,8 +6,8 @@ Create Date: 2023-03-20 00:39:30.199915 """ -import sqlalchemy as sa from alembic import op +import sqlalchemy as sa from sqlalchemy.dialects.postgresql import JSONB # revision identifiers, used by Alembic. diff --git a/nonebot_bison/config/migrations/67c38b3f39c2_make_user_target_not_nullable.py b/nonebot_bison/config/migrations/67c38b3f39c2_make_user_target_not_nullable.py index 1f3e07a..dabcd10 100644 --- a/nonebot_bison/config/migrations/67c38b3f39c2_make_user_target_not_nullable.py +++ b/nonebot_bison/config/migrations/67c38b3f39c2_make_user_target_not_nullable.py @@ -6,8 +6,8 @@ Create Date: 2023-03-20 11:08:42.883556 """ -import sqlalchemy as sa from alembic import op +import sqlalchemy as sa from sqlalchemy.dialects.postgresql import JSONB # revision identifiers, used by Alembic. diff --git a/nonebot_bison/config/migrations/8d3863e9d74b_remove_uid_and_type.py b/nonebot_bison/config/migrations/8d3863e9d74b_remove_uid_and_type.py index 649e7f6..4a272aa 100644 --- a/nonebot_bison/config/migrations/8d3863e9d74b_remove_uid_and_type.py +++ b/nonebot_bison/config/migrations/8d3863e9d74b_remove_uid_and_type.py @@ -6,8 +6,8 @@ Create Date: 2023-03-20 15:38:20.220599 """ -import sqlalchemy as sa from alembic import op +import sqlalchemy as sa # revision identifiers, used by Alembic. revision = "8d3863e9d74b" diff --git a/nonebot_bison/config/migrations/a333d6224193_add_last_scheduled_time.py b/nonebot_bison/config/migrations/a333d6224193_add_last_scheduled_time.py index ad0892b..6f06592 100644 --- a/nonebot_bison/config/migrations/a333d6224193_add_last_scheduled_time.py +++ b/nonebot_bison/config/migrations/a333d6224193_add_last_scheduled_time.py @@ -6,8 +6,8 @@ Create Date: 2022-03-29 21:01:38.213153 """ -import sqlalchemy as sa from alembic import op +import sqlalchemy as sa # revision identifiers, used by Alembic. revision = "a333d6224193" diff --git a/nonebot_bison/config/migrations/a5466912fad0_map_user.py b/nonebot_bison/config/migrations/a5466912fad0_map_user.py index c89098f..a87853e 100644 --- a/nonebot_bison/config/migrations/a5466912fad0_map_user.py +++ b/nonebot_bison/config/migrations/a5466912fad0_map_user.py @@ -6,10 +6,10 @@ Create Date: 2023-03-20 01:14:42.623789 """ -import sqlalchemy as sa from alembic import op -from sqlalchemy.orm import Session +import sqlalchemy as sa from sqlalchemy.ext.automap import automap_base +from sqlalchemy.orm import Session # revision identifiers, used by Alembic. revision = "a5466912fad0" diff --git a/nonebot_bison/config/migrations/aceef470d69c_alter_fields_not_null.py b/nonebot_bison/config/migrations/aceef470d69c_alter_fields_not_null.py index c51a400..07f9bd1 100644 --- a/nonebot_bison/config/migrations/aceef470d69c_alter_fields_not_null.py +++ b/nonebot_bison/config/migrations/aceef470d69c_alter_fields_not_null.py @@ -6,8 +6,8 @@ Create Date: 2023-03-09 19:10:42.168133 """ -import sqlalchemy as sa from alembic import op +import sqlalchemy as sa # revision identifiers, used by Alembic. revision = "aceef470d69c" diff --git a/nonebot_bison/config/migrations/bd92923c218f_alter_json_not_null.py b/nonebot_bison/config/migrations/bd92923c218f_alter_json_not_null.py index aa3f2ff..fddec32 100644 --- a/nonebot_bison/config/migrations/bd92923c218f_alter_json_not_null.py +++ b/nonebot_bison/config/migrations/bd92923c218f_alter_json_not_null.py @@ -6,11 +6,11 @@ Create Date: 2023-03-02 14:04:16.492133 """ -import sqlalchemy as sa from alembic import op +import sqlalchemy as sa from sqlalchemy import select -from sqlalchemy.orm import Session from sqlalchemy.ext.automap import automap_base +from sqlalchemy.orm import Session # revision identifiers, used by Alembic. revision = "bd92923c218f" diff --git a/nonebot_bison/config/migrations/f90b712557a9_add_cookie.py b/nonebot_bison/config/migrations/f90b712557a9_add_cookie.py index b89ce04..e759243 100644 --- a/nonebot_bison/config/migrations/f90b712557a9_add_cookie.py +++ b/nonebot_bison/config/migrations/f90b712557a9_add_cookie.py @@ -6,8 +6,8 @@ Create Date: 2024-09-23 10:03:30.593263 """ -import sqlalchemy as sa from alembic import op +import sqlalchemy as sa from sqlalchemy import Text from sqlalchemy.dialects import postgresql diff --git a/nonebot_bison/config/migrations/f9baef347cc8_remove_old_target.py b/nonebot_bison/config/migrations/f9baef347cc8_remove_old_target.py index fbed082..b78a09a 100644 --- a/nonebot_bison/config/migrations/f9baef347cc8_remove_old_target.py +++ b/nonebot_bison/config/migrations/f9baef347cc8_remove_old_target.py @@ -6,10 +6,10 @@ Create Date: 2023-08-25 00:20:51.511329 """ -import sqlalchemy as sa from alembic import op -from sqlalchemy.orm import Session +import sqlalchemy as sa from sqlalchemy.ext.automap import automap_base +from sqlalchemy.orm import Session # revision identifiers, used by Alembic. revision = "f9baef347cc8" diff --git a/nonebot_bison/config/subs_io/nbesf_model/__init__.py b/nonebot_bison/config/subs_io/nbesf_model/__init__.py index dff07d0..3a57855 100644 --- a/nonebot_bison/config/subs_io/nbesf_model/__init__.py +++ b/nonebot_bison/config/subs_io/nbesf_model/__init__.py @@ -3,4 +3,4 @@ from . import v1, v2, v3 from .base import NBESFBase -__all__ = ["v1", "v2", "v3", "NBESFBase"] +__all__ = ["NBESFBase", "v1", "v2", "v3"] diff --git a/nonebot_bison/config/subs_io/nbesf_model/base.py b/nonebot_bison/config/subs_io/nbesf_model/base.py index 426c819..eab9bf5 100644 --- a/nonebot_bison/config/subs_io/nbesf_model/base.py +++ b/nonebot_bison/config/subs_io/nbesf_model/base.py @@ -1,10 +1,10 @@ from abc import ABC -from pydantic import BaseModel from nonebot.compat import PYDANTIC_V2, ConfigDict from nonebot_plugin_saa.registries import AllSupportedPlatformTarget as UserInfo +from pydantic import BaseModel -from ....types import Tag, Category +from nonebot_bison.types import Category, Tag class NBESFBase(BaseModel, ABC): diff --git a/nonebot_bison/config/subs_io/nbesf_model/v1.py b/nonebot_bison/config/subs_io/nbesf_model/v1.py index 717deba..63ef67a 100644 --- a/nonebot_bison/config/subs_io/nbesf_model/v1.py +++ b/nonebot_bison/config/subs_io/nbesf_model/v1.py @@ -1,17 +1,18 @@ """nbesf is Nonebot Bison Enchangable Subscribes File! ver.1""" -from typing import Any from functools import partial +from typing import Any -from nonebot.log import logger -from pydantic import BaseModel -from nonebot_plugin_saa import TargetQQGroup, TargetQQPrivate from nonebot.compat import PYDANTIC_V2, ConfigDict, model_dump, type_validate_json, type_validate_python +from nonebot.log import logger +from nonebot_plugin_saa import TargetQQGroup, TargetQQPrivate +from pydantic import BaseModel, Field + +from nonebot_bison.config.db_config import SubscribeDupException, config +from nonebot_bison.config.subs_io.utils import NBESFParseErr +from nonebot_bison.types import Category, Tag -from ..utils import NBESFParseErr -from ....types import Tag, Category from .base import NBESFBase, SubReceipt -from ...db_config import SubscribeDupException, config # ===== nbesf 定义格式 ====== # NBESF_VERSION = 1 @@ -79,7 +80,7 @@ class SubGroup( """ version: int = NBESF_VERSION - groups: list[SubPack] = [] + groups: list[SubPack] = Field(default_factory=list) # ======================= # @@ -108,11 +109,11 @@ async def subs_receipt_gen(nbesf_data: SubGroup): try: await config.add_subscribe(receipt.user, **model_dump(receipt, exclude={"user"})) except SubscribeDupException: - logger.warning(f"!添加订阅条目 {repr(receipt)} 失败: 相同的订阅已存在") + logger.warning(f"!添加订阅条目 {receipt!r} 失败: 相同的订阅已存在") except Exception as e: - logger.error(f"!添加订阅条目 {repr(receipt)} 失败: {repr(e)}") + logger.error(f"!添加订阅条目 {receipt!r} 失败: {e!r}") else: - logger.success(f"添加订阅条目 {repr(receipt)} 成功!") + logger.success(f"添加订阅条目 {receipt!r} 成功!") def nbesf_parser(raw_data: Any) -> SubGroup: diff --git a/nonebot_bison/config/subs_io/nbesf_model/v2.py b/nonebot_bison/config/subs_io/nbesf_model/v2.py index 714704f..a34383a 100644 --- a/nonebot_bison/config/subs_io/nbesf_model/v2.py +++ b/nonebot_bison/config/subs_io/nbesf_model/v2.py @@ -1,17 +1,18 @@ """nbesf is Nonebot Bison Enchangable Subscribes File! ver.2""" -from typing import Any from functools import partial +from typing import Any -from nonebot.log import logger -from pydantic import BaseModel -from nonebot_plugin_saa.registries import AllSupportedPlatformTarget from nonebot.compat import PYDANTIC_V2, ConfigDict, model_dump, type_validate_json, type_validate_python +from nonebot.log import logger +from nonebot_plugin_saa.registries import AllSupportedPlatformTarget +from pydantic import BaseModel, Field + +from nonebot_bison.config.db_config import SubscribeDupException, config +from nonebot_bison.config.subs_io.utils import NBESFParseErr +from nonebot_bison.types import Category, Tag -from ..utils import NBESFParseErr -from ....types import Tag, Category from .base import NBESFBase, SubReceipt -from ...db_config import SubscribeDupException, config # ===== nbesf 定义格式 ====== # NBESF_VERSION = 2 @@ -64,7 +65,7 @@ class SubGroup(NBESFBase): """ version: int = NBESF_VERSION - groups: list[SubPack] = [] + groups: list[SubPack] = Field(default_factory=list) # ======================= # @@ -85,11 +86,11 @@ async def subs_receipt_gen(nbesf_data: SubGroup): try: await config.add_subscribe(receipt.user, **model_dump(receipt, exclude={"user"})) except SubscribeDupException: - logger.warning(f"!添加订阅条目 {repr(receipt)} 失败: 相同的订阅已存在") + logger.warning(f"!添加订阅条目 {receipt!r} 失败: 相同的订阅已存在") except Exception as e: - logger.error(f"!添加订阅条目 {repr(receipt)} 失败: {repr(e)}") + logger.error(f"!添加订阅条目 {receipt!r} 失败: {e!r}") else: - logger.success(f"添加订阅条目 {repr(receipt)} 成功!") + logger.success(f"添加订阅条目 {receipt!r} 成功!") def nbesf_parser(raw_data: Any) -> SubGroup: diff --git a/nonebot_bison/config/subs_io/nbesf_model/v3.py b/nonebot_bison/config/subs_io/nbesf_model/v3.py index c6f1c03..a24b0b2 100644 --- a/nonebot_bison/config/subs_io/nbesf_model/v3.py +++ b/nonebot_bison/config/subs_io/nbesf_model/v3.py @@ -1,21 +1,20 @@ """nbesf is Nonebot Bison Enchangable Subscribes File! ver.2""" -from typing import Any from functools import partial +from typing import Any -from nonebot.log import logger -from pydantic import BaseModel -from nonebot_plugin_saa.registries import AllSupportedPlatformTarget from nonebot.compat import PYDANTIC_V2, ConfigDict, model_dump, type_validate_json, type_validate_python +from nonebot.log import logger +from nonebot_plugin_saa.registries import AllSupportedPlatformTarget +from pydantic import BaseModel, Field -from nonebot_bison.types import Tag -from nonebot_bison.types import Category +from nonebot_bison.config.db_config import SubscribeDupException, config +from nonebot_bison.config.db_model import Cookie as DBCookie +from nonebot_bison.config.subs_io.utils import NBESFParseErr +from nonebot_bison.types import Category, Tag from nonebot_bison.types import Target as T_Target -from ..utils import NBESFParseErr from .base import NBESFBase, SubReceipt -from ...db_model import Cookie as DBCookie -from ...db_config import SubscribeDupException, config # ===== nbesf 定义格式 ====== # NBESF_VERSION = 3 @@ -80,8 +79,8 @@ class SubGroup(NBESFBase): """ version: int = NBESF_VERSION - groups: list[SubPack] = [] - cookies: list[Cookie] = [] + groups: list[SubPack] = Field(default_factory=list) + cookies: list[Cookie] = Field(default_factory=list) # ======================= # @@ -103,11 +102,11 @@ async def subs_receipt_gen(nbesf_data: SubGroup): try: await config.add_subscribe(receipt.user, **model_dump(receipt, exclude={"user"})) except SubscribeDupException: - logger.warning(f"!添加订阅条目 {repr(receipt)} 失败: 相同的订阅已存在") + logger.warning(f"!添加订阅条目 {receipt!r} 失败: 相同的订阅已存在") except Exception as e: - logger.error(f"!添加订阅条目 {repr(receipt)} 失败: {repr(e)}") + logger.error(f"!添加订阅条目 {receipt!r} 失败: {e!r}") else: - logger.success(f"添加订阅条目 {repr(receipt)} 成功!") + logger.success(f"添加订阅条目 {receipt!r} 成功!") async def magic_cookie_gen(nbesf_data: SubGroup): @@ -119,9 +118,9 @@ async def magic_cookie_gen(nbesf_data: SubGroup): for target in cookie.targets: await config.add_cookie_target(T_Target(target.target), target.platform_name, cookie_id) except Exception as e: - logger.error(f"!添加 Cookie 条目 {repr(cookie)} 失败: {repr(e)}") + logger.error(f"!添加 Cookie 条目 {cookie!r} 失败: {e!r}") else: - logger.success(f"添加 Cookie 条目 {repr(cookie)} 成功!") + logger.success(f"添加 Cookie 条目 {cookie!r} 成功!") def nbesf_parser(raw_data: Any) -> SubGroup: diff --git a/nonebot_bison/config/subs_io/subs_io.py b/nonebot_bison/config/subs_io/subs_io.py index c871096..a0e1f23 100644 --- a/nonebot_bison/config/subs_io/subs_io.py +++ b/nonebot_bison/config/subs_io/subs_io.py @@ -1,19 +1,20 @@ -from typing import cast from collections import defaultdict from collections.abc import Callable +from typing import cast -from sqlalchemy import select -from nonebot.log import logger -from sqlalchemy.sql.selectable import Select -from nonebot_plugin_saa import PlatformTarget from nonebot.compat import type_validate_python +from nonebot.log import logger from nonebot_plugin_datastore.db import create_session +from nonebot_plugin_saa import PlatformTarget +from sqlalchemy import select from sqlalchemy.orm.strategy_options import selectinload +from sqlalchemy.sql.selectable import Select + +from nonebot_bison.config import config +from nonebot_bison.config.db_model import Cookie, CookieTarget, Subscribe, Target, User -from .. import config -from .utils import NBESFVerMatchErr, row2dict from .nbesf_model import NBESFBase, v1, v2, v3 -from ..db_model import User, Cookie, Target, Subscribe, CookieTarget +from .utils import NBESFVerMatchErr, row2dict async def subscribes_export(selector: Callable[[Select], Select]) -> v3.SubGroup: diff --git a/nonebot_bison/platform/__init__.py b/nonebot_bison/platform/__init__.py index accdf83..19ebc31 100644 --- a/nonebot_bison/platform/__init__.py +++ b/nonebot_bison/platform/__init__.py @@ -1,9 +1,10 @@ -from pathlib import Path -from pkgutil import iter_modules from collections import defaultdict from importlib import import_module +from pathlib import Path +from pkgutil import iter_modules + +from nonebot_bison.plugin_config import plugin_config -from ..plugin_config import plugin_config from .platform import Platform, make_no_target_group _package_dir = str(Path(__file__).resolve().parent) diff --git a/nonebot_bison/platform/arknights.py b/nonebot_bison/platform/arknights.py index f22fd28..f15a368 100644 --- a/nonebot_bison/platform/arknights.py +++ b/nonebot_bison/platform/arknights.py @@ -1,18 +1,19 @@ -import re -import html -from typing import Any from functools import partial +import html +import re +from typing import Any, ClassVar -from yarl import URL -from httpx import AsyncClient from bs4 import BeautifulSoup as bs -from pydantic import Field, BaseModel +from httpx import AsyncClient from nonebot.compat import type_validate_python +from pydantic import BaseModel, Field +from yarl import URL + +from nonebot_bison.post import Post +from nonebot_bison.post.protocol import HTMLContentSupport +from nonebot_bison.types import Category, RawPost, Target +from nonebot_bison.utils import Site -from ..post import Post -from ..utils import Site -from ..types import Target, RawPost, Category -from ..post.protocol import HTMLContentSupport from .platform import NewMessage, StatusChange @@ -58,7 +59,7 @@ class ArkBulletinResponse(ArkResponseBase): class ArknightsSite(Site): name = "arknights" schedule_type = "interval" - schedule_setting = {"seconds": 30} + schedule_setting: ClassVar[dict] = {"seconds": 30} class ArknightsPost(Post, HTMLContentSupport): @@ -95,7 +96,7 @@ class ArknightsPost(Post, HTMLContentSupport): class Arknights(NewMessage): - categories = {1: "游戏公告"} + categories: ClassVar[dict[Category, str]] = {1: "游戏公告"} platform_name = "arknights" name = "明日方舟游戏信息" enable_tag = False @@ -157,7 +158,7 @@ class Arknights(NewMessage): class AkVersion(StatusChange): - categories = {2: "更新信息"} + categories: ClassVar[dict[Category, str]] = {2: "更新信息"} platform_name = "arknights" name = "明日方舟游戏信息" enable_tag = False @@ -202,7 +203,7 @@ class AkVersion(StatusChange): class MonsterSiren(NewMessage): - categories = {3: "塞壬唱片新闻"} + categories: ClassVar[dict[Category, str]] = {3: "塞壬唱片新闻"} platform_name = "arknights" name = "明日方舟游戏信息" enable_tag = False @@ -250,7 +251,7 @@ class MonsterSiren(NewMessage): class TerraHistoricusComic(NewMessage): - categories = {4: "泰拉记事社漫画"} + categories: ClassVar[dict[Category, str]] = {4: "泰拉记事社漫画"} platform_name = "arknights" name = "明日方舟游戏信息" enable_tag = False diff --git a/nonebot_bison/platform/bilibili/__init__.py b/nonebot_bison/platform/bilibili/__init__.py index 524529e..c3db36e 100644 --- a/nonebot_bison/platform/bilibili/__init__.py +++ b/nonebot_bison/platform/bilibili/__init__.py @@ -1,7 +1,7 @@ from .platforms import Bilibili as Bilibili -from .platforms import Bilibililive as Bilibililive -from .scheduler import BilibiliSite as BilibiliSite -from .scheduler import BililiveSite as BililiveSite from .platforms import BilibiliBangumi as BilibiliBangumi +from .platforms import Bilibililive as Bilibililive from .scheduler import BiliBangumiSite as BiliBangumiSite from .scheduler import BilibiliClientManager as BilibiliClientManager +from .scheduler import BilibiliSite as BilibiliSite +from .scheduler import BililiveSite as BililiveSite diff --git a/nonebot_bison/platform/bilibili/fsm.py b/nonebot_bison/platform/bilibili/fsm.py index 6252f53..93949c2 100644 --- a/nonebot_bison/platform/bilibili/fsm.py +++ b/nonebot_bison/platform/bilibili/fsm.py @@ -1,22 +1,22 @@ -import sys import asyncio -import inspect +from collections.abc import AsyncGenerator, Awaitable, Callable, Sequence +from collections.abc import Set as AbstractSet +from dataclasses import dataclass from enum import Enum from functools import wraps -from dataclasses import dataclass -from collections.abc import Set as AbstractSet -from collections.abc import Callable, Sequence, Awaitable, AsyncGenerator +import inspect +import sys from typing import ( TYPE_CHECKING, Any, + Concatenate, Generic, - TypeVar, - Protocol, + NamedTuple, ParamSpec, + Protocol, TypeAlias, TypedDict, - NamedTuple, - Concatenate, + TypeVar, overload, runtime_checkable, ) diff --git a/nonebot_bison/platform/bilibili/models.py b/nonebot_bison/platform/bilibili/models.py index c7de84f..5e040c5 100644 --- a/nonebot_bison/platform/bilibili/models.py +++ b/nonebot_bison/platform/bilibili/models.py @@ -1,7 +1,7 @@ -from typing import Any, Literal, TypeVar, TypeAlias +from typing import Any, Literal, TypeAlias, TypeVar -from pydantic import BaseModel from nonebot.compat import PYDANTIC_V2, ConfigDict +from pydantic import BaseModel from nonebot_bison.compat import model_rebuild @@ -13,7 +13,7 @@ TBaseModel = TypeVar("TBaseModel", bound=type[BaseModel]) def model_rebuild_recurse(cls: TBaseModel) -> TBaseModel: """Recursively rebuild all BaseModel subclasses in the class.""" if not PYDANTIC_V2: - from inspect import isclass, getmembers + from inspect import getmembers, isclass for _, sub_cls in getmembers(cls, lambda x: isclass(x) and issubclass(x, BaseModel)): model_rebuild_recurse(sub_cls) diff --git a/nonebot_bison/platform/bilibili/platforms.py b/nonebot_bison/platform/bilibili/platforms.py index dbdd52e..31e5dea 100644 --- a/nonebot_bison/platform/bilibili/platforms.py +++ b/nonebot_bison/platform/bilibili/platforms.py @@ -1,41 +1,41 @@ -import re -import json from copy import deepcopy from enum import Enum, unique -from typing import NamedTuple +import json +import re +from typing import ClassVar, NamedTuple from typing_extensions import Self -from yarl import URL -from nonebot import logger from httpx import AsyncClient -from pydantic import Field, BaseModel, ValidationError +from nonebot import logger from nonebot.compat import type_validate_json, type_validate_python +from pydantic import BaseModel, Field, ValidationError +from yarl import URL -from nonebot_bison.post.post import Post from nonebot_bison.compat import model_rebuild -from nonebot_bison.utils import text_similarity, decode_unicode_escapes -from nonebot_bison.types import Tag, Target, RawPost, ApiError, Category +from nonebot_bison.platform.platform import CategoryNotRecognize, CategoryNotSupport, NewMessage, StatusChange +from nonebot_bison.post.post import Post +from nonebot_bison.types import ApiError, Category, RawPost, Tag, Target +from nonebot_bison.utils import decode_unicode_escapes, text_similarity -from .retry import ApiCode352Error, retry_for_352 -from .scheduler import BilibiliSite, BililiveSite, BiliBangumiSite -from ..platform import NewMessage, StatusChange, CategoryNotSupport, CategoryNotRecognize from .models import ( - PostAPI, - UserAPI, - PGCMajor, - DrawMajor, - LiveMajor, - OPUSMajor, - DynRawPost, - VideoMajor, - CommonMajor, - DynamicType, ArticleMajor, + CommonMajor, CoursesMajor, DeletedMajor, - UnknownMajor, + DrawMajor, + DynamicType, + DynRawPost, + LiveMajor, LiveRecommendMajor, + OPUSMajor, + PGCMajor, + PostAPI, + UnknownMajor, + UserAPI, + VideoMajor, ) +from .retry import ApiCode352Error, retry_for_352 +from .scheduler import BiliBangumiSite, BilibiliSite, BililiveSite class _ProcessedText(NamedTuple): @@ -51,7 +51,7 @@ class _ParsedMojarPost(NamedTuple): class Bilibili(NewMessage): - categories = { + categories: ClassVar[dict[Category, str]] = { 1: "一般动态", 2: "专栏文章", 3: "视频", @@ -162,7 +162,6 @@ class Bilibili(NewMessage): return tags def _text_process(self, dynamic: str, desc: str, title: str) -> _ProcessedText: - # 计算视频标题和视频描述相似度 title_similarity = 0.0 if len(title) == 0 or len(desc) == 0 else text_similarity(title, desc[: len(title)]) if title_similarity > 0.9: @@ -308,7 +307,7 @@ class Bilibili(NewMessage): class Bilibililive(StatusChange): - categories = {1: "开播提醒", 2: "标题更新提醒", 3: "下播提醒"} + categories: ClassVar[dict[Category, str]] = {1: "开播提醒", 2: "标题更新提醒", 3: "下播提醒"} platform_name = "bilibili-live" enable_tag = False enabled = True @@ -458,7 +457,7 @@ class Bilibililive(StatusChange): class BilibiliBangumi(StatusChange): - categories = {} + categories: ClassVar[dict[Category, str]] = {} platform_name = "bilibili-bangumi" enable_tag = False enabled = True diff --git a/nonebot_bison/platform/bilibili/retry.py b/nonebot_bison/platform/bilibili/retry.py index 20cc9ed..09e917c 100644 --- a/nonebot_bison/platform/bilibili/retry.py +++ b/nonebot_bison/platform/bilibili/retry.py @@ -1,20 +1,20 @@ -import random -from enum import Enum -from functools import wraps +from collections.abc import Awaitable, Callable from dataclasses import dataclass from datetime import datetime, timedelta -from collections.abc import Callable, Awaitable -from typing_extensions import override, assert_never +from enum import Enum +from functools import wraps +import random from typing import TYPE_CHECKING, Generic, Literal, TypeVar +from typing_extensions import assert_never, override -from strenum import StrEnum -from nonebot.log import logger from httpx import URL as HttpxURL +from nonebot.log import logger +from strenum import StrEnum from nonebot_bison.types import Target +from .fsm import FSM, ActionReturn, Condition, StateGraph, Transition, reset_on_exception from .models import DynRawPost -from .fsm import FSM, Condition, StateGraph, Transition, ActionReturn, reset_on_exception if TYPE_CHECKING: from .platforms import Bilibili @@ -115,8 +115,7 @@ class RetryAddon(Generic[TBilibili]): def record_backoff_finish_time(self): self.backoff_finish_time = ( - datetime.now() - + self.backoff_timedelta * self.backoff_count**2 + datetime.now() + self.backoff_timedelta * self.backoff_count**2 # + timedelta(seconds=random.randint(1, 60)) # jitter ) logger.trace(f"set backoff finish time: {self.backoff_finish_time}") diff --git a/nonebot_bison/platform/bilibili/scheduler.py b/nonebot_bison/platform/bilibili/scheduler.py index 1dddbec..b63fa3b 100644 --- a/nonebot_bison/platform/bilibili/scheduler.py +++ b/nonebot_bison/platform/bilibili/scheduler.py @@ -1,17 +1,16 @@ +from datetime import datetime, timedelta import json import random +from typing import TYPE_CHECKING, ClassVar, TypeVar from typing_extensions import override -from datetime import datetime, timedelta -from typing import TYPE_CHECKING, TypeVar from httpx import AsyncClient from nonebot import logger, require from playwright.async_api import Cookie +from nonebot_bison.config.db_model import Cookie as CookieModel from nonebot_bison.utils import Site, http_client - -from ...utils.site import CookieClientManager -from ...config.db_model import Cookie as CookieModel +from nonebot_bison.utils.site import CookieClientManager if TYPE_CHECKING: from .platforms import Bilibili @@ -23,7 +22,6 @@ B = TypeVar("B", bound="Bilibili") class BilibiliClientManager(CookieClientManager): - _default_cookie_cd = timedelta(seconds=120) async def _get_cookies(self) -> list[Cookie]: @@ -75,7 +73,7 @@ class BilibiliClientManager(CookieClientManager): class BilibiliSite(Site): name = "bilibili.com" - schedule_setting = {"seconds": 60} + schedule_setting: ClassVar[dict] = {"seconds": 60} schedule_type = "interval" client_mgr = BilibiliClientManager require_browser = True @@ -83,11 +81,11 @@ class BilibiliSite(Site): class BililiveSite(Site): name = "live.bilibili.com" - schedule_setting = {"seconds": 5} + schedule_setting: ClassVar[dict] = {"seconds": 5} schedule_type = "interval" class BiliBangumiSite(Site): name = "bilibili.com/bangumi" - schedule_setting = {"seconds": 30} + schedule_setting: ClassVar[dict] = {"seconds": 30} schedule_type = "interval" diff --git a/nonebot_bison/platform/ceobecanteen/cache.py b/nonebot_bison/platform/ceobecanteen/cache.py index b157d56..6343cdd 100644 --- a/nonebot_bison/platform/ceobecanteen/cache.py +++ b/nonebot_bison/platform/ceobecanteen/cache.py @@ -1,16 +1,16 @@ -from typing import TypeAlias -from functools import partial -from datetime import timedelta -from types import MappingProxyType from collections.abc import Callable +from datetime import timedelta +from functools import partial +from types import MappingProxyType +from typing import TypeAlias +from expiringdictx import ExpiringDict, SimpleCache +from hishel import AsyncCacheTransport, AsyncInMemoryStorage, Controller from httpx import AsyncClient, AsyncHTTPTransport -from expiringdictx import SimpleCache, ExpiringDict -from hishel import Controller, AsyncCacheTransport, AsyncInMemoryStorage from .const import DATASOURCE_URL -from .utils import process_response from .models import CeobeSource, CeobeTarget, DataSourceResponse +from .utils import process_response cache_transport = AsyncCacheTransport( AsyncHTTPTransport(), diff --git a/nonebot_bison/platform/ceobecanteen/models.py b/nonebot_bison/platform/ceobecanteen/models.py index 1987948..bb857e3 100644 --- a/nonebot_bison/platform/ceobecanteen/models.py +++ b/nonebot_bison/platform/ceobecanteen/models.py @@ -1,4 +1,4 @@ -from typing import Literal, TypeVar, NamedTuple +from typing import Literal, NamedTuple, TypeVar from pydantic import BaseModel diff --git a/nonebot_bison/platform/ceobecanteen/platform.py b/nonebot_bison/platform/ceobecanteen/platform.py index a3674be..1fd9998 100644 --- a/nonebot_bison/platform/ceobecanteen/platform.py +++ b/nonebot_bison/platform/ceobecanteen/platform.py @@ -1,23 +1,23 @@ -from typing import ParamSpec -from functools import partial -from datetime import timedelta from collections import defaultdict +from datetime import timedelta +from functools import partial +from typing import ClassVar, ParamSpec from httpx import AsyncClient from nonebot import logger, require from rapidfuzz import fuzz, process -from nonebot_bison.post import Post +from nonebot_bison.platform.platform import NewMessage from nonebot_bison.plugin_config import plugin_config -from nonebot_bison.types import Target, RawPost, Category -from nonebot_bison.utils import Site, ClientManager, capture_html +from nonebot_bison.post import Post +from nonebot_bison.types import Category, RawPost, Target +from nonebot_bison.utils import ClientManager, Site, capture_html -from ..platform import NewMessage -from .utils import process_response -from .const import COMB_ID_URL, COOKIES_URL, COOKIE_ID_URL -from .exception import CeobeSnapshotSkip, CeobeSnapshotFailed from .cache import CeobeCache, CeobeClient, CeobeDataSourceCache -from .models import CeobeImage, CeobeCookie, CeobeTextPic, CombIdResponse, CookiesResponse, CookieIdResponse +from .const import COMB_ID_URL, COOKIE_ID_URL, COOKIES_URL +from .exception import CeobeSnapshotFailed, CeobeSnapshotSkip +from .models import CeobeCookie, CeobeImage, CeobeTextPic, CombIdResponse, CookieIdResponse, CookiesResponse +from .utils import process_response P = ParamSpec("P") @@ -49,7 +49,7 @@ class CeobeCanteenSite(Site): name = "ceobe_canteen" schedule_type = "interval" # lwt の 推荐间隔 - schedule_setting = {"seconds": 15} + schedule_setting: ClassVar[dict] = {"seconds": 15} client_mgr = CeobeCanteenClientManager @@ -64,7 +64,7 @@ class CeobeCanteen(NewMessage): use_batch: bool = True default_theme: str = "ceobecanteen" - categories: dict[Category, str] = {1: "普通", 2: "转发"} + categories: ClassVar[dict[Category, str]] = {1: "普通", 2: "转发"} data_source_cache = CeobeDataSourceCache() @@ -213,7 +213,9 @@ class CeobeCanteen(NewMessage): logger.debug(f"snapshot official website url: {url}") # /html/body/div[1]/div[1]/div/div[1]/div[1]/div - snapshot_selector = "html > body > div:nth-child(1) > div:nth-child(1) > div > div:nth-child(1) > div:nth-child(1) > div" # noqa: E501 + snapshot_selector = ( + "html > body > div:nth-child(1) > div:nth-child(1) > div > div:nth-child(1) > div:nth-child(1) > div" + ) # /html/body/div[1]/div[1]/div/div[1]/div[1]/div/div[4]/div/div/div calculate_selector = "html > body > div:nth-child(1) > div:nth-child(1) > div > div:nth-child(1) > div:nth-child(1) > div > div:nth-child(4) > div > div > div" # noqa: E501 viewport = {"width": 1024, "height": 19990} diff --git a/nonebot_bison/platform/ceobecanteen/utils.py b/nonebot_bison/platform/ceobecanteen/utils.py index 83667d5..b9284be 100644 --- a/nonebot_bison/platform/ceobecanteen/utils.py +++ b/nonebot_bison/platform/ceobecanteen/utils.py @@ -3,7 +3,7 @@ from nonebot import logger from nonebot.compat import type_validate_python from .exception import CeobeResponseError -from .models import ResponseModel, CookieIdResponse +from .models import CookieIdResponse, ResponseModel def process_response(response: Response, parse_model: type[ResponseModel]) -> ResponseModel: diff --git a/nonebot_bison/platform/ff14.py b/nonebot_bison/platform/ff14.py index 412a463..81f004c 100644 --- a/nonebot_bison/platform/ff14.py +++ b/nonebot_bison/platform/ff14.py @@ -1,15 +1,16 @@ -from typing import Any +from typing import Any, ClassVar from httpx import AsyncClient -from ..post import Post +from nonebot_bison.post import Post +from nonebot_bison.types import RawPost, Target +from nonebot_bison.utils import anonymous_site + from .platform import NewMessage -from ..utils import anonymous_site -from ..types import Target, RawPost class FF14(NewMessage): - categories = {} + categories: ClassVar[dict] = {} platform_name = "ff14" name = "最终幻想XIV官方公告" enable_tag = False diff --git a/nonebot_bison/platform/ncm.py b/nonebot_bison/platform/ncm.py index 069ef9c..39cee5c 100644 --- a/nonebot_bison/platform/ncm.py +++ b/nonebot_bison/platform/ncm.py @@ -1,22 +1,23 @@ import re -from typing import Any +from typing import Any, ClassVar from httpx import AsyncClient -from ..post import Post -from ..utils import Site +from nonebot_bison.post import Post +from nonebot_bison.types import ApiError, Category, RawPost, Target +from nonebot_bison.utils import Site + from .platform import NewMessage -from ..types import Target, RawPost, ApiError class NcmSite(Site): name = "music.163.com" schedule_type = "interval" - schedule_setting = {"minutes": 1} + schedule_setting: ClassVar[dict] = {"minutes": 1} class NcmArtist(NewMessage): - categories = {} + categories: ClassVar[dict[Category, str]] = {} platform_name = "ncm-artist" enable_tag = False enabled = True @@ -73,7 +74,7 @@ class NcmArtist(NewMessage): class NcmRadio(NewMessage): - categories = {} + categories: ClassVar[dict[Category, str]] = {} platform_name = "ncm-radio" enable_tag = False enabled = True diff --git a/nonebot_bison/platform/platform.py b/nonebot_bison/platform/platform.py index ecbafe6..f018f88 100644 --- a/nonebot_bison/platform/platform.py +++ b/nonebot_bison/platform/platform.py @@ -1,22 +1,22 @@ -import ssl -import json -import time -import typing -from dataclasses import dataclass from abc import ABC, abstractmethod from collections import defaultdict -from typing import Any, TypeVar, ParamSpec -from collections.abc import Callable, Awaitable, Collection +from collections.abc import Awaitable, Callable, Collection +from dataclasses import dataclass +import json +import ssl +import time +import typing +from typing import Any, ParamSpec, TypeVar import httpx from httpx import AsyncClient from nonebot.log import logger from nonebot_plugin_saa import PlatformTarget -from ..post import Post -from ..utils import Site, ProcessContext -from ..plugin_config import plugin_config -from ..types import Tag, Target, RawPost, SubUnit, Category +from nonebot_bison.plugin_config import plugin_config +from nonebot_bison.post import Post +from nonebot_bison.types import Category, RawPost, SubUnit, Tag, Target +from nonebot_bison.utils import ProcessContext, Site class CategoryNotSupport(Exception): diff --git a/nonebot_bison/platform/rss.py b/nonebot_bison/platform/rss.py index 1437965..e80dfa8 100644 --- a/nonebot_bison/platform/rss.py +++ b/nonebot_bison/platform/rss.py @@ -1,27 +1,27 @@ -import time import calendar -from typing import Any +import time +from typing import Any, ClassVar +from bs4 import BeautifulSoup as bs import feedparser from httpx import AsyncClient -from bs4 import BeautifulSoup as bs -from ..post import Post +from nonebot_bison.post import Post +from nonebot_bison.types import Category, RawPost, Target +from nonebot_bison.utils import text_similarity +from nonebot_bison.utils.site import CookieClientManager, Site + from .platform import NewMessage -from ..types import Target, RawPost -from ..utils import text_similarity -from ..utils.site import Site, CookieClientManager class RssSite(Site): name = "rss" schedule_type = "interval" - schedule_setting = {"seconds": 30} + schedule_setting: ClassVar[dict] = {"seconds": 30} client_mgr = CookieClientManager.from_name(name) class RssPost(Post): - async def get_plain_content(self) -> str: soup = bs(self.content, "html.parser") @@ -38,7 +38,7 @@ class RssPost(Post): class Rss(NewMessage): - categories = {} + categories: ClassVar[dict[Category, str]] = {} enable_tag = False platform_name = "rss" name = "Rss" diff --git a/nonebot_bison/platform/weibo.py b/nonebot_bison/platform/weibo.py index f6c276d..c7b137f 100644 --- a/nonebot_bison/platform/weibo.py +++ b/nonebot_bison/platform/weibo.py @@ -1,21 +1,22 @@ -import re -import json -from typing import Any from datetime import datetime -from urllib.parse import unquote +import json +import re +from typing import Any, ClassVar from typing_extensions import override +from urllib.parse import unquote -from yarl import URL -from lxml.etree import HTML -from httpx import AsyncClient -from nonebot.log import logger from bs4 import BeautifulSoup as bs +from httpx import AsyncClient +from lxml.etree import HTML +from nonebot.log import logger +from yarl import URL + +from nonebot_bison.post import Post +from nonebot_bison.types import ApiError, Category, RawPost, Tag, Target +from nonebot_bison.utils import http_client, text_fletten +from nonebot_bison.utils.site import CookieClientManager, Site -from ..post import Post from .platform import NewMessage -from ..utils import http_client, text_fletten -from ..utils.site import Site, CookieClientManager -from ..types import Tag, Target, RawPost, ApiError, Category _HEADER = { "accept": ( @@ -59,12 +60,12 @@ class WeiboClientManager(CookieClientManager): class WeiboSite(Site): name = "weibo.com" schedule_type = "interval" - schedule_setting = {"seconds": 3} + schedule_setting: ClassVar[dict] = {"seconds": 3} client_mgr = WeiboClientManager class Weibo(NewMessage): - categories = { + categories: ClassVar[dict[Category, str]] = { 1: "转发", 2: "视频", 3: "图文", diff --git a/nonebot_bison/plugin_config.py b/nonebot_bison/plugin_config.py index b7f7307..b330224 100644 --- a/nonebot_bison/plugin_config.py +++ b/nonebot_bison/plugin_config.py @@ -1,8 +1,8 @@ import nonebot -from yarl import URL from nonebot import get_plugin_config -from pydantic import Field, BaseModel from nonebot.compat import PYDANTIC_V2, ConfigDict +from pydantic import BaseModel, Field +from yarl import URL global_config = nonebot.get_driver().config PlatformName = str diff --git a/nonebot_bison/post/abstract_post.py b/nonebot_bison/post/abstract_post.py index 2a76a44..1260327 100644 --- a/nonebot_bison/post/abstract_post.py +++ b/nonebot_bison/post/abstract_post.py @@ -1,10 +1,10 @@ -from dataclasses import dataclass from abc import ABC, abstractmethod +from dataclasses import dataclass -from nonebot_plugin_saa import Text, MessageFactory, MessageSegmentFactory +from nonebot_plugin_saa import MessageFactory, MessageSegmentFactory, Text -from ..utils import text_to_image -from ..plugin_config import plugin_config +from nonebot_bison.plugin_config import plugin_config +from nonebot_bison.utils import text_to_image @dataclass(kw_only=True) diff --git a/nonebot_bison/post/post.py b/nonebot_bison/post/post.py index 577f81e..1dd1087 100644 --- a/nonebot_bison/post/post.py +++ b/nonebot_bison/post/post.py @@ -1,21 +1,22 @@ -import reprlib +from collections.abc import Sequence +from dataclasses import dataclass, fields from io import BytesIO from pathlib import Path +import reprlib from typing import TYPE_CHECKING -from collections.abc import Sequence -from dataclasses import fields, dataclass from nonebot.log import logger from nonebot_plugin_saa import MessageSegmentFactory -from ..theme import theme_manager +from nonebot_bison.plugin_config import plugin_config +from nonebot_bison.theme import theme_manager +from nonebot_bison.theme.types import ThemeRenderError, ThemeRenderUnsupportError + from .abstract_post import AbstractPost -from ..plugin_config import plugin_config from .protocol import PlainContentSupport -from ..theme.types import ThemeRenderError, ThemeRenderUnsupportError if TYPE_CHECKING: - from ..platform import Platform + from nonebot_bison.platform import Platform @dataclass diff --git a/nonebot_bison/scheduler/__init__.py b/nonebot_bison/scheduler/__init__.py index 19c9284..87ba97a 100644 --- a/nonebot_bison/scheduler/__init__.py +++ b/nonebot_bison/scheduler/__init__.py @@ -1,3 +1,3 @@ -from .manager import init_scheduler, scheduler_dict, handle_delete_target, handle_insert_new_target +from .manager import handle_delete_target, handle_insert_new_target, init_scheduler, scheduler_dict -__all__ = ["init_scheduler", "handle_delete_target", "handle_insert_new_target", "scheduler_dict"] +__all__ = ["handle_delete_target", "handle_insert_new_target", "init_scheduler", "scheduler_dict"] diff --git a/nonebot_bison/scheduler/manager.py b/nonebot_bison/scheduler/manager.py index 5a94cf1..a5184ec 100644 --- a/nonebot_bison/scheduler/manager.py +++ b/nonebot_bison/scheduler/manager.py @@ -2,14 +2,15 @@ from typing import cast from nonebot.log import logger -from ..utils import Site -from ..config import config +from nonebot_bison.config import config +from nonebot_bison.config.db_model import Target +from nonebot_bison.platform import platform_manager +from nonebot_bison.plugin_config import plugin_config +from nonebot_bison.types import Target as T_Target +from nonebot_bison.utils import Site +from nonebot_bison.utils.site import CookieClientManager, is_cookie_client_manager + from .scheduler import Scheduler -from ..config.db_model import Target -from ..types import Target as T_Target -from ..platform import platform_manager -from ..plugin_config import plugin_config -from ..utils.site import CookieClientManager, is_cookie_client_manager scheduler_dict: dict[type[Site], Scheduler] = {} diff --git a/nonebot_bison/scheduler/scheduler.py b/nonebot_bison/scheduler/scheduler.py index f94ea87..883114e 100644 --- a/nonebot_bison/scheduler/scheduler.py +++ b/nonebot_bison/scheduler/scheduler.py @@ -1,18 +1,16 @@ -from dataclasses import dataclass from collections import defaultdict +from dataclasses import dataclass from nonebot.log import logger from nonebot_plugin_apscheduler import scheduler from nonebot_plugin_saa.utils.exceptions import NoBotFound -from nonebot_bison.utils import ClientManager - -from ..config import config -from ..send import send_msgs -from ..types import Target, SubUnit -from ..platform import platform_manager -from ..utils import Site, ProcessContext -from ..utils.site import SkipRequestException +from nonebot_bison.config import config +from nonebot_bison.platform import platform_manager +from nonebot_bison.send import send_msgs +from nonebot_bison.types import SubUnit, Target +from nonebot_bison.utils import ClientManager, ProcessContext, Site +from nonebot_bison.utils.site import SkipRequestException @dataclass diff --git a/nonebot_bison/script/cli.py b/nonebot_bison/script/cli.py index f17e431..420b1ee 100644 --- a/nonebot_bison/script/cli.py +++ b/nonebot_bison/script/cli.py @@ -1,25 +1,26 @@ -import json -import time +from collections.abc import Callable, Coroutine +from functools import partial, wraps import importlib +import json from pathlib import Path +import time from types import ModuleType from typing import Any, TypeVar -from functools import wraps, partial -from collections.abc import Callable, Coroutine -from nonebot.log import logger +from anyio import open_file from nonebot.compat import model_dump +from nonebot.log import logger -from ..scheduler.manager import init_scheduler -from ..config.subs_io.nbesf_model import v1, v2, v3 -from ..config.subs_io import subscribes_export, subscribes_import +from nonebot_bison.config.subs_io import subscribes_export, subscribes_import +from nonebot_bison.config.subs_io.nbesf_model import v1, v2, v3 +from nonebot_bison.scheduler.manager import init_scheduler try: from typing_extensions import ParamSpec import anyio + from anyio import from_thread, to_thread import click - from anyio import to_thread, from_thread except ImportError as e: # pragma: no cover raise ImportError("请使用 `pip install nonebot-bison[cli]` 安装所需依赖") from e @@ -127,18 +128,18 @@ async def subs_import(path: str, format: str): import_file_path = Path(path) assert import_file_path.is_file(), "该路径不是文件!" - with import_file_path.open("r", encoding="utf-8") as f: + async with await open_file(import_file_path, "r", encoding="utf-8") as f: match format: case "yaml" | "yml": logger.info("正在从yaml导入...") pyyaml = import_yaml_module() - import_items = pyyaml.safe_load(f) + import_items = pyyaml.safe_load(await f.read()) case "json": logger.info("正在从json导入...") - import_items = json.load(f) + import_items = json.loads(await f.read()) case _: raise click.BadParameter(message=f"不支持的导入格式: {format}") diff --git a/nonebot_bison/send.py b/nonebot_bison/send.py index b48127d..98fa91f 100644 --- a/nonebot_bison/send.py +++ b/nonebot_bison/send.py @@ -1,10 +1,10 @@ import asyncio from collections import deque -from nonebot.log import logger -from nonebot_plugin_saa.auto_select_bot import refresh_bots from nonebot.adapters.onebot.v11.exception import ActionFailed -from nonebot_plugin_saa import MessageFactory, PlatformTarget, AggregatedMessageFactory +from nonebot.log import logger +from nonebot_plugin_saa import AggregatedMessageFactory, MessageFactory, PlatformTarget +from nonebot_plugin_saa.auto_select_bot import refresh_bots from .plugin_config import plugin_config @@ -14,6 +14,8 @@ QUEUE: deque[tuple[PlatformTarget, Sendable, int]] = deque() MESSGE_SEND_INTERVAL = 1.5 +_MESSAGE_DISPATCH_TASKS: set[asyncio.Task] = set() + async def _do_send(send_target: PlatformTarget, msg: Sendable): try: @@ -59,7 +61,9 @@ async def _send_msgs_dispatch(send_target: PlatformTarget, msg: Sendable): QUEUE.append((send_target, msg, plugin_config.bison_resend_times)) # len(QUEUE) before append was 0 if len(QUEUE) == 1: - asyncio.create_task(do_send_msgs()) + task = asyncio.create_task(do_send_msgs()) + _MESSAGE_DISPATCH_TASKS.add(task) + task.add_done_callback(_MESSAGE_DISPATCH_TASKS.discard) else: await _do_send(send_target, msg) diff --git a/nonebot_bison/sub_manager/__init__.py b/nonebot_bison/sub_manager/__init__.py index 9a3e5c2..f73f528 100644 --- a/nonebot_bison/sub_manager/__init__.py +++ b/nonebot_bison/sub_manager/__init__.py @@ -2,23 +2,25 @@ import asyncio from datetime import datetime from nonebot import on_command -from nonebot.typing import T_State -from nonebot.matcher import Matcher -from nonebot.rule import Rule, to_me -from nonebot.permission import SUPERUSER -from nonebot_plugin_saa import TargetQQGroup -from nonebot.params import ArgStr, ArgPlainText from nonebot.adapters import Bot, MessageTemplate from nonebot.adapters.onebot.v11.event import PrivateMessageEvent +from nonebot.matcher import Matcher +from nonebot.params import ArgPlainText, ArgStr +from nonebot.permission import SUPERUSER +from nonebot.rule import Rule, to_me +from nonebot.typing import T_State +from nonebot_plugin_saa import TargetQQGroup +from .add_cookie import do_add_cookie +from .add_cookie_target import do_add_cookie_target from .add_sub import do_add_sub +from .del_cookie import do_del_cookie +from .del_cookie_target import do_del_cookie_target from .del_sub import do_del_sub from .query_sub import do_query_sub -from .add_cookie import do_add_cookie -from .del_cookie import do_del_cookie -from .add_cookie_target import do_add_cookie_target -from .del_cookie_target import do_del_cookie_target -from .utils import common_platform, admin_permission, gen_handle_cancel, configurable_to_me, set_target_user_info +from .utils import admin_permission, common_platform, configurable_to_me, gen_handle_cancel, set_target_user_info + +_COMMAND_DISPATCH_TASKS: set[asyncio.Task] = set() add_sub_matcher = on_command( "添加订阅", @@ -149,7 +151,10 @@ async def do_dispatch_command( else: do_del_sub(new_matcher) new_matcher_ins = new_matcher() - asyncio.create_task(new_matcher_ins.run(bot, event, state)) + + task = asyncio.create_task(new_matcher_ins.run(bot, event, state)) + _COMMAND_DISPATCH_TASKS.add(task) + task.add_done_callback(_COMMAND_DISPATCH_TASKS.discard) no_permission_matcher = on_command( @@ -167,14 +172,14 @@ async def send_no_permission(): __all__ = [ - "common_platform", + "add_cookie_matcher", + "add_cookie_target_matcher", "add_sub_matcher", - "query_sub_matcher", + "common_platform", + "del_cookie_matcher", + "del_cookie_target_matcher", "del_sub_matcher", "group_manage_matcher", "no_permission_matcher", - "add_cookie_matcher", - "add_cookie_target_matcher", - "del_cookie_target_matcher", - "del_cookie_matcher", + "query_sub_matcher", ] diff --git a/nonebot_bison/sub_manager/add_cookie.py b/nonebot_bison/sub_manager/add_cookie.py index 7e6461f..a57d79f 100644 --- a/nonebot_bison/sub_manager/add_cookie.py +++ b/nonebot_bison/sub_manager/add_cookie.py @@ -1,16 +1,17 @@ -from typing import cast from json import JSONDecodeError +from typing import cast +from nonebot.adapters import Message, MessageTemplate +from nonebot.adapters.onebot.v11 import MessageEvent from nonebot.log import logger -from nonebot.typing import T_State from nonebot.matcher import Matcher from nonebot.params import Arg, ArgPlainText -from nonebot.adapters.onebot.v11 import MessageEvent -from nonebot.adapters import Message, MessageTemplate +from nonebot.typing import T_State + +from nonebot_bison.platform import platform_manager +from nonebot_bison.scheduler import scheduler_dict +from nonebot_bison.utils.site import CookieClientManager, is_cookie_client_manager -from ..scheduler import scheduler_dict -from ..platform import platform_manager -from ..utils.site import CookieClientManager, is_cookie_client_manager from .utils import common_platform, gen_handle_cancel, only_allow_private diff --git a/nonebot_bison/sub_manager/add_cookie_target.py b/nonebot_bison/sub_manager/add_cookie_target.py index 919d0ca..4facd6a 100644 --- a/nonebot_bison/sub_manager/add_cookie_target.py +++ b/nonebot_bison/sub_manager/add_cookie_target.py @@ -1,14 +1,15 @@ -from nonebot.typing import T_State -from nonebot.matcher import Matcher -from nonebot.params import ArgPlainText -from nonebot_plugin_saa import MessageFactory from nonebot.adapters.onebot.v11 import MessageEvent from nonebot.internal.adapter import MessageTemplate +from nonebot.matcher import Matcher +from nonebot.params import ArgPlainText +from nonebot.typing import T_State +from nonebot_plugin_saa import MessageFactory -from ..config import config -from ..utils import parse_text -from ..platform import platform_manager -from .utils import gen_handle_cancel, only_allow_private, generate_sub_list_text +from nonebot_bison.config import config +from nonebot_bison.platform import platform_manager +from nonebot_bison.utils import parse_text + +from .utils import gen_handle_cancel, generate_sub_list_text, only_allow_private def do_add_cookie_target(add_cookie_target_matcher: type[Matcher]): @@ -33,7 +34,6 @@ def do_add_cookie_target(add_cookie_target_matcher: type[Matcher]): @add_cookie_target_matcher.handle() async def init_promote_cookie(state: T_State): - # 获取 site 的所有用户 cookie,再排除掉已经关联的 cookie,剩下的就是可以关联的 cookie cookies = await config.get_cookie(site_name=state["site"].name, is_anonymous=False) associated_cookies = await config.get_cookie( diff --git a/nonebot_bison/sub_manager/add_sub.py b/nonebot_bison/sub_manager/add_sub.py index 107b9b5..6e26d3a 100644 --- a/nonebot_bison/sub_manager/add_sub.py +++ b/nonebot_bison/sub_manager/add_sub.py @@ -1,17 +1,18 @@ import contextlib -from nonebot.typing import T_State +from nonebot.adapters import Message, MessageTemplate from nonebot.matcher import Matcher from nonebot.params import Arg, ArgPlainText -from nonebot.adapters import Message, MessageTemplate -from nonebot_plugin_saa import Text, PlatformTarget, SupportedAdapters +from nonebot.typing import T_State +from nonebot_plugin_saa import PlatformTarget, SupportedAdapters, Text + +from nonebot_bison.apis import check_sub_target +from nonebot_bison.config import config +from nonebot_bison.config.db_config import SubscribeDupException +from nonebot_bison.platform import Platform, platform_manager, unavailable_paltforms +from nonebot_bison.types import Target -from ..types import Target -from ..config import config -from ..apis import check_sub_target -from ..config.db_config import SubscribeDupException from .utils import common_platform, ensure_user_info, gen_handle_cancel -from ..platform import Platform, platform_manager, unavailable_paltforms def do_add_sub(add_sub: type[Matcher]): diff --git a/nonebot_bison/sub_manager/del_cookie.py b/nonebot_bison/sub_manager/del_cookie.py index 680d3c0..dfad326 100644 --- a/nonebot_bison/sub_manager/del_cookie.py +++ b/nonebot_bison/sub_manager/del_cookie.py @@ -1,11 +1,12 @@ -from nonebot.typing import T_State +from nonebot.adapters.onebot.v11 import MessageEvent from nonebot.matcher import Matcher from nonebot.params import EventPlainText +from nonebot.typing import T_State from nonebot_plugin_saa import MessageFactory -from nonebot.adapters.onebot.v11 import MessageEvent -from ..config import config -from ..utils import parse_text +from nonebot_bison.config import config +from nonebot_bison.utils import parse_text + from .utils import gen_handle_cancel, only_allow_private diff --git a/nonebot_bison/sub_manager/del_cookie_target.py b/nonebot_bison/sub_manager/del_cookie_target.py index 656e1d2..4bf698e 100644 --- a/nonebot_bison/sub_manager/del_cookie_target.py +++ b/nonebot_bison/sub_manager/del_cookie_target.py @@ -1,11 +1,12 @@ -from nonebot.typing import T_State +from nonebot.adapters.onebot.v11 import MessageEvent from nonebot.matcher import Matcher from nonebot.params import EventPlainText +from nonebot.typing import T_State from nonebot_plugin_saa import MessageFactory -from nonebot.adapters.onebot.v11 import MessageEvent -from ..config import config -from ..utils import parse_text +from nonebot_bison.config import config +from nonebot_bison.utils import parse_text + from .utils import gen_handle_cancel, only_allow_private diff --git a/nonebot_bison/sub_manager/del_sub.py b/nonebot_bison/sub_manager/del_sub.py index b70d923..d54127c 100644 --- a/nonebot_bison/sub_manager/del_sub.py +++ b/nonebot_bison/sub_manager/del_sub.py @@ -1,12 +1,13 @@ -from nonebot.typing import T_State from nonebot.matcher import Matcher from nonebot.params import Arg, EventPlainText +from nonebot.typing import T_State from nonebot_plugin_saa import MessageFactory, PlatformTarget -from ..config import config -from ..types import Category -from ..utils import parse_text -from ..platform import platform_manager +from nonebot_bison.config import config +from nonebot_bison.platform import platform_manager +from nonebot_bison.types import Category +from nonebot_bison.utils import parse_text + from .utils import ensure_user_info, gen_handle_cancel diff --git a/nonebot_bison/sub_manager/query_sub.py b/nonebot_bison/sub_manager/query_sub.py index 8f4d7ba..f1c6154 100644 --- a/nonebot_bison/sub_manager/query_sub.py +++ b/nonebot_bison/sub_manager/query_sub.py @@ -1,12 +1,13 @@ -from nonebot.params import Arg from nonebot.matcher import Matcher +from nonebot.params import Arg from nonebot_plugin_saa import MessageFactory, PlatformTarget -from ..config import config -from ..types import Category -from ..utils import parse_text +from nonebot_bison.config import config +from nonebot_bison.platform import platform_manager +from nonebot_bison.types import Category +from nonebot_bison.utils import parse_text + from .utils import ensure_user_info -from ..platform import platform_manager def do_query_sub(query_sub: type[Matcher]): diff --git a/nonebot_bison/sub_manager/utils.py b/nonebot_bison/sub_manager/utils.py index 2418cfc..6c3e100 100644 --- a/nonebot_bison/sub_manager/utils.py +++ b/nonebot_bison/sub_manager/utils.py @@ -1,22 +1,22 @@ import contextlib -from typing import Annotated from itertools import groupby from operator import attrgetter +from typing import Annotated -from nonebot.rule import Rule from nonebot.adapters import Event -from nonebot.typing import T_State from nonebot.matcher import Matcher +from nonebot.params import Depends, EventPlainText, EventToMe from nonebot.permission import SUPERUSER -from nonebot.params import Depends, EventToMe, EventPlainText +from nonebot.rule import Rule +from nonebot.typing import T_State from nonebot_plugin_saa import PlatformTarget, extract_target -from ..config import config -from ..types import Category -from ..types import Target as T_Target -from ..platform import platform_manager -from ..plugin_config import plugin_config -from ..utils.site import is_cookie_client_manager +from nonebot_bison.config import config +from nonebot_bison.platform import platform_manager +from nonebot_bison.plugin_config import plugin_config +from nonebot_bison.types import Category +from nonebot_bison.types import Target as T_Target +from nonebot_bison.utils.site import is_cookie_client_manager def _configurable_to_me(to_me: bool = EventToMe()): diff --git a/nonebot_bison/theme/__init__.py b/nonebot_bison/theme/__init__.py index fef5cb1..00dcae6 100644 --- a/nonebot_bison/theme/__init__.py +++ b/nonebot_bison/theme/__init__.py @@ -1,10 +1,9 @@ +from importlib import import_module from pathlib import Path from pkgutil import iter_modules -from importlib import import_module -from .types import Theme from .registry import theme_manager -from .types import ThemeRegistrationError +from .types import Theme, ThemeRegistrationError from .types import ThemeRenderError as ThemeRenderError from .types import ThemeRenderUnsupportError as ThemeRenderUnsupportError diff --git a/nonebot_bison/theme/registry.py b/nonebot_bison/theme/registry.py index 7c8f76f..14afd82 100644 --- a/nonebot_bison/theme/registry.py +++ b/nonebot_bison/theme/registry.py @@ -1,11 +1,14 @@ +from typing import ClassVar + from nonebot import logger -from ..plugin_config import plugin_config +from nonebot_bison.plugin_config import plugin_config + from .types import Theme, ThemeRegistrationError class ThemeManager: - __themes: dict[str, Theme] = {} + __themes: ClassVar[dict[str, Theme]] = {} def register(self, theme: Theme): logger.trace(f"Registering theme: {theme}") diff --git a/nonebot_bison/theme/themes/arknights/build.py b/nonebot_bison/theme/themes/arknights/build.py index ec6265d..2fe0b22 100644 --- a/nonebot_bison/theme/themes/arknights/build.py +++ b/nonebot_bison/theme/themes/arknights/build.py @@ -1,13 +1,13 @@ +from dataclasses import dataclass from io import BytesIO from pathlib import Path -from dataclasses import dataclass from typing import TYPE_CHECKING, Literal -from nonebot_plugin_saa import Text, Image, MessageSegmentFactory +from nonebot_plugin_saa import Image, MessageSegmentFactory, Text -from nonebot_bison.utils import text_fletten -from nonebot_bison.theme.utils import web_embed_image from nonebot_bison.theme import Theme, ThemeRenderError, ThemeRenderUnsupportError +from nonebot_bison.theme.utils import web_embed_image +from nonebot_bison.utils import text_fletten if TYPE_CHECKING: from nonebot_bison.platform.arknights import ArknightsPost diff --git a/nonebot_bison/theme/themes/basic/build.py b/nonebot_bison/theme/themes/basic/build.py index 95d2249..3602a62 100644 --- a/nonebot_bison/theme/themes/basic/build.py +++ b/nonebot_bison/theme/themes/basic/build.py @@ -1,11 +1,12 @@ +from collections.abc import Sequence from io import BytesIO from pathlib import Path from typing import TYPE_CHECKING, Literal -from nonebot_plugin_saa import Text, Image, MessageSegmentFactory +from nonebot_plugin_saa import Image, MessageSegmentFactory, Text from nonebot_bison.theme import Theme -from nonebot_bison.utils import pic_merge, is_pics_mergable +from nonebot_bison.utils import is_pics_mergable, pic_merge if TYPE_CHECKING: from nonebot_bison.post import Post @@ -50,7 +51,7 @@ class BasicTheme(Theme): client = await post.platform.ctx.get_client_for_static() msgs: list[MessageSegmentFactory] = [Text(text)] - pics_group: list[list[str | bytes | Path | BytesIO]] = [] + pics_group: list[Sequence[str | bytes | Path | BytesIO]] = [] if post.images: pics_group.append(post.images) if rp and rp.images: diff --git a/nonebot_bison/theme/themes/brief/build.py b/nonebot_bison/theme/themes/brief/build.py index 612d41a..57d6290 100644 --- a/nonebot_bison/theme/themes/brief/build.py +++ b/nonebot_bison/theme/themes/brief/build.py @@ -1,9 +1,9 @@ from typing import TYPE_CHECKING, Literal -from nonebot_plugin_saa import Text, Image, MessageSegmentFactory +from nonebot_plugin_saa import Image, MessageSegmentFactory, Text -from nonebot_bison.utils import pic_merge, is_pics_mergable from nonebot_bison.theme import Theme, ThemeRenderUnsupportError +from nonebot_bison.utils import is_pics_mergable, pic_merge if TYPE_CHECKING: from nonebot_bison.post import Post diff --git a/nonebot_bison/theme/themes/ceobe_canteen/build.py b/nonebot_bison/theme/themes/ceobe_canteen/build.py index 9d3a2be..551fded 100644 --- a/nonebot_bison/theme/themes/ceobe_canteen/build.py +++ b/nonebot_bison/theme/themes/ceobe_canteen/build.py @@ -1,19 +1,20 @@ +from collections.abc import Sequence +from datetime import datetime from io import BytesIO from pathlib import Path -from datetime import datetime from typing import TYPE_CHECKING, Literal -import jinja2 -from yarl import URL from httpx import AsyncClient -from pydantic import BaseModel +import jinja2 +from nonebot_plugin_saa import Image, MessageSegmentFactory, Text from PIL import Image as PILImage -from nonebot_plugin_saa import Text, Image, MessageSegmentFactory +from pydantic import BaseModel +from yarl import URL from nonebot_bison.compat import model_validator -from nonebot_bison.utils import pic_merge, is_pics_mergable -from nonebot_bison.theme.utils import convert_to_qr, web_embed_image from nonebot_bison.theme import Theme, ThemeRenderError, ThemeRenderUnsupportError +from nonebot_bison.theme.utils import convert_to_qr, web_embed_image +from nonebot_bison.utils import is_pics_mergable, pic_merge if TYPE_CHECKING: from nonebot_bison.post import Post @@ -122,7 +123,7 @@ class CeobeCanteenTheme(Theme): @staticmethod async def merge_pics( - images: list[str | bytes | Path | BytesIO], + images: Sequence[str | bytes | Path | BytesIO], client: AsyncClient, ) -> list[str | bytes | Path | BytesIO]: if is_pics_mergable(images): @@ -224,7 +225,7 @@ class CeobeCanteenTheme(Theme): text += f"详情: {post.url}" msgs.append(Text(text)) - pics_group: list[list[str | bytes | Path | BytesIO]] = [] + pics_group: list[Sequence[str | bytes | Path | BytesIO]] = [] if post.images: pics_group.append(post.images) if post.repost and post.repost.images: diff --git a/nonebot_bison/theme/themes/ht2i/build.py b/nonebot_bison/theme/themes/ht2i/build.py index 4f95fa4..8ef56c1 100644 --- a/nonebot_bison/theme/themes/ht2i/build.py +++ b/nonebot_bison/theme/themes/ht2i/build.py @@ -1,12 +1,13 @@ +from collections.abc import Sequence from io import BytesIO from pathlib import Path from typing import TYPE_CHECKING, Literal -from nonebot_plugin_saa import Text, Image, MessageSegmentFactory +from nonebot_plugin_saa import Image, MessageSegmentFactory, Text -from nonebot_bison.theme import Theme, ThemeRenderError from nonebot_bison.post.protocol import HTMLContentSupport -from nonebot_bison.utils import pic_merge, is_pics_mergable +from nonebot_bison.theme import Theme, ThemeRenderError +from nonebot_bison.utils import is_pics_mergable, pic_merge if TYPE_CHECKING: from nonebot_bison.post import Post @@ -31,7 +32,6 @@ class Ht2iTheme(Theme): raise ThemeRenderError(f"渲染文本失败: {e}") async def render(self, post: "Post"): - md_text = "" md_text += f"## {post.title}\n\n" if post.title else "" @@ -50,9 +50,7 @@ class Ht2iTheme(Theme): else: rp_content = await rp.get_content() - md_text += ( - "> \n> " + rp_content if len(rp_content) < 500 else f"{rp_content[:500]}..." + " \n" # noqa: E501 - ) # noqa: E501 + md_text += "> \n> " + rp_content if len(rp_content) < 500 else f"{rp_content[:500]}..." + " \n" md_text += "\n\n" md_text += f"###### 来源: {post.platform.name} {post.nickname or ''}\n" @@ -68,7 +66,7 @@ class Ht2iTheme(Theme): if urls: msgs.append(Text("\n".join(urls))) - pics_group: list[list[str | bytes | Path | BytesIO]] = [] + pics_group: list[Sequence[str | bytes | Path | BytesIO]] = [] if post.images: pics_group.append(post.images) if rp and rp.images: diff --git a/nonebot_bison/theme/types.py b/nonebot_bison/theme/types.py index 8802a08..c81aca8 100644 --- a/nonebot_bison/theme/types.py +++ b/nonebot_bison/theme/types.py @@ -1,14 +1,14 @@ -from typing import TYPE_CHECKING from abc import ABC, abstractmethod +from typing import TYPE_CHECKING from nonebot import logger, require -from pydantic import BaseModel, PrivateAttr from nonebot_plugin_saa import MessageSegmentFactory +from pydantic import BaseModel, PrivateAttr -from ..plugin_config import plugin_config +from nonebot_bison.plugin_config import plugin_config if TYPE_CHECKING: - from ..post.abstract_post import AbstractPost + from nonebot_bison.post.abstract_post import AbstractPost class Theme(ABC, BaseModel): diff --git a/nonebot_bison/theme/utils.py b/nonebot_bison/theme/utils.py index cfc03ce..7088737 100644 --- a/nonebot_bison/theme/utils.py +++ b/nonebot_bison/theme/utils.py @@ -1,10 +1,10 @@ +from base64 import b64encode from io import BytesIO from pathlib import Path -from base64 import b64encode from qrcode import constants -from qrcode.main import QRCode from qrcode.image.pil import PilImage +from qrcode.main import QRCode def convert_to_qr(data: str, **kwarg) -> bytes: diff --git a/nonebot_bison/types.py b/nonebot_bison/types.py index 0d08bfd..8bcbe8b 100644 --- a/nonebot_bison/types.py +++ b/nonebot_bison/types.py @@ -1,10 +1,10 @@ -from datetime import time from dataclasses import dataclass -from typing import Any, Literal, NewType, NamedTuple +from datetime import time +from typing import Any, Literal, NamedTuple, NewType from httpx import URL -from pydantic import BaseModel from nonebot_plugin_saa import PlatformTarget as SendTarget +from pydantic import BaseModel RawPost = Any Target = NewType("Target", str) diff --git a/nonebot_bison/utils/__init__.py b/nonebot_bison/utils/__init__.py index 5da51f3..32ba253 100644 --- a/nonebot_bison/utils/__init__.py +++ b/nonebot_bison/utils/__init__.py @@ -1,29 +1,31 @@ +import difflib import re import sys -import difflib +from typing import Any, ClassVar -import nonebot -from nonebot.plugin import require from bs4 import BeautifulSoup as bs -from nonebot.log import logger, default_format -from nonebot_plugin_saa import Text, Image, MessageSegmentFactory +import nonebot +from nonebot.log import default_format, logger +from nonebot.plugin import require +from nonebot_plugin_saa import Image, MessageSegmentFactory, Text -from .site import Site as Site -from ..plugin_config import plugin_config -from .image import pic_merge as pic_merge +from nonebot_bison.plugin_config import plugin_config + +from .context import ProcessContext as ProcessContext from .http import http_client as http_client from .image import capture_html as capture_html -from .site import ClientManager as ClientManager -from .image import text_to_image as text_to_image -from .site import anonymous_site as anonymous_site -from .context import ProcessContext as ProcessContext from .image import is_pics_mergable as is_pics_mergable +from .image import pic_merge as pic_merge from .image import pic_url_to_image as pic_url_to_image +from .image import text_to_image as text_to_image +from .site import ClientManager as ClientManager from .site import DefaultClientManager as DefaultClientManager +from .site import Site as Site +from .site import anonymous_site as anonymous_site class Singleton(type): - _instances = {} + _instances: ClassVar[dict[Any, Any]] = {} def __call__(cls, *args, **kwargs): if cls not in cls._instances: diff --git a/nonebot_bison/utils/context.py b/nonebot_bison/utils/context.py index 5359969..373498f 100644 --- a/nonebot_bison/utils/context.py +++ b/nonebot_bison/utils/context.py @@ -1,6 +1,6 @@ from base64 import b64encode -from httpx import Response, AsyncClient +from httpx import AsyncClient, Response from nonebot_bison.types import Target diff --git a/nonebot_bison/utils/get_bot.py b/nonebot_bison/utils/get_bot.py index 2ac1e84..6f360e9 100644 --- a/nonebot_bison/utils/get_bot.py +++ b/nonebot_bison/utils/get_bot.py @@ -1,12 +1,12 @@ """提供获取 Bot 的方法""" -from typing import Any from collections import defaultdict +from typing import Any import nonebot from nonebot.adapters import Bot -from nonebot_plugin_saa import PlatformTarget from nonebot.adapters.onebot.v11 import Bot as Ob11Bot +from nonebot_plugin_saa import PlatformTarget GROUP: dict[int, list[Bot]] = {} USER: dict[int, list[Bot]] = {} diff --git a/nonebot_bison/utils/http.py b/nonebot_bison/utils/http.py index 08bfb43..4b7f477 100644 --- a/nonebot_bison/utils/http.py +++ b/nonebot_bison/utils/http.py @@ -1,6 +1,6 @@ import httpx -from ..plugin_config import plugin_config +from nonebot_bison.plugin_config import plugin_config http_args = { "proxies": plugin_config.bison_proxy or None, diff --git a/nonebot_bison/utils/image.py b/nonebot_bison/utils/image.py index ac188ff..3857497 100644 --- a/nonebot_bison/utils/image.py +++ b/nonebot_bison/utils/image.py @@ -1,16 +1,17 @@ -from io import BytesIO +from collections.abc import Sequence from functools import partial +from io import BytesIO from typing import Literal, TypeGuard -from yarl import URL -from PIL import Image from httpx import AsyncClient from nonebot import logger, require -from PIL.Image import Image as PILImage -from nonebot_plugin_saa import Text as SaaText from nonebot_plugin_saa import Image as SaaImage +from nonebot_plugin_saa import Text as SaaText +from PIL import Image +from PIL.Image import Image as PILImage +from yarl import URL -from ..plugin_config import plugin_config +from nonebot_bison.plugin_config import plugin_config async def pic_url_to_image(data: str | bytes, http_client: AsyncClient) -> PILImage: @@ -96,7 +97,7 @@ async def pic_merge(pics: list[str | bytes], http_client: AsyncClient) -> list[s return pics -def is_pics_mergable(imgs: list) -> TypeGuard[list[str | bytes]]: +def is_pics_mergable(imgs: Sequence) -> TypeGuard[list[str | bytes]]: if any(not isinstance(img, str | bytes) for img in imgs): return False diff --git a/nonebot_bison/utils/site.py b/nonebot_bison/utils/site.py index aecb00f..618a4d7 100644 --- a/nonebot_bison/utils/site.py +++ b/nonebot_bison/utils/site.py @@ -1,18 +1,19 @@ -import json -from typing import Literal -from json import JSONDecodeError from abc import ABC, abstractmethod from collections.abc import Callable from datetime import datetime, timedelta +import json +from json import JSONDecodeError +from typing import Literal import httpx from httpx import AsyncClient from nonebot.log import logger -from ..types import Target -from ..config import config +from nonebot_bison.config import config +from nonebot_bison.config.db_model import Cookie +from nonebot_bison.types import Target + from .http import http_client -from ..config.db_model import Cookie class ClientManager(ABC): diff --git a/poetry.lock b/poetry.lock index 1d635c1..da7bc2b 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.8.3 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.8.4 and should not be changed by hand. [[package]] name = "aiodns" @@ -470,57 +470,6 @@ type = "legacy" url = "https://pypi.org/simple" reference = "offical-source" -[[package]] -name = "black" -version = "24.8.0" -description = "The uncompromising code formatter." -optional = false -python-versions = ">=3.8" -files = [ - {file = "black-24.8.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:09cdeb74d494ec023ded657f7092ba518e8cf78fa8386155e4a03fdcc44679e6"}, - {file = "black-24.8.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:81c6742da39f33b08e791da38410f32e27d632260e599df7245cccee2064afeb"}, - {file = "black-24.8.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:707a1ca89221bc8a1a64fb5e15ef39cd755633daa672a9db7498d1c19de66a42"}, - {file = "black-24.8.0-cp310-cp310-win_amd64.whl", hash = "sha256:d6417535d99c37cee4091a2f24eb2b6d5ec42b144d50f1f2e436d9fe1916fe1a"}, - {file = "black-24.8.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:fb6e2c0b86bbd43dee042e48059c9ad7830abd5c94b0bc518c0eeec57c3eddc1"}, - {file = "black-24.8.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:837fd281f1908d0076844bc2b801ad2d369c78c45cf800cad7b61686051041af"}, - {file = "black-24.8.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:62e8730977f0b77998029da7971fa896ceefa2c4c4933fcd593fa599ecbf97a4"}, - {file = "black-24.8.0-cp311-cp311-win_amd64.whl", hash = "sha256:72901b4913cbac8972ad911dc4098d5753704d1f3c56e44ae8dce99eecb0e3af"}, - {file = "black-24.8.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:7c046c1d1eeb7aea9335da62472481d3bbf3fd986e093cffd35f4385c94ae368"}, - {file = "black-24.8.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:649f6d84ccbae73ab767e206772cc2d7a393a001070a4c814a546afd0d423aed"}, - {file = "black-24.8.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2b59b250fdba5f9a9cd9d0ece6e6d993d91ce877d121d161e4698af3eb9c1018"}, - {file = "black-24.8.0-cp312-cp312-win_amd64.whl", hash = "sha256:6e55d30d44bed36593c3163b9bc63bf58b3b30e4611e4d88a0c3c239930ed5b2"}, - {file = "black-24.8.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:505289f17ceda596658ae81b61ebbe2d9b25aa78067035184ed0a9d855d18afd"}, - {file = "black-24.8.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:b19c9ad992c7883ad84c9b22aaa73562a16b819c1d8db7a1a1a49fb7ec13c7d2"}, - {file = "black-24.8.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1f13f7f386f86f8121d76599114bb8c17b69d962137fc70efe56137727c7047e"}, - {file = "black-24.8.0-cp38-cp38-win_amd64.whl", hash = "sha256:f490dbd59680d809ca31efdae20e634f3fae27fba3ce0ba3208333b713bc3920"}, - {file = "black-24.8.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:eab4dd44ce80dea27dc69db40dab62d4ca96112f87996bca68cd75639aeb2e4c"}, - {file = "black-24.8.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3c4285573d4897a7610054af5a890bde7c65cb466040c5f0c8b732812d7f0e5e"}, - {file = "black-24.8.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9e84e33b37be070ba135176c123ae52a51f82306def9f7d063ee302ecab2cf47"}, - {file = "black-24.8.0-cp39-cp39-win_amd64.whl", hash = "sha256:73bbf84ed136e45d451a260c6b73ed674652f90a2b3211d6a35e78054563a9bb"}, - {file = "black-24.8.0-py3-none-any.whl", hash = "sha256:972085c618ee94f402da1af548a4f218c754ea7e5dc70acb168bfaca4c2542ed"}, - {file = "black-24.8.0.tar.gz", hash = "sha256:2500945420b6784c38b9ee885af039f5e7471ef284ab03fa35ecdde4688cd83f"}, -] - -[package.dependencies] -click = ">=8.0.0" -mypy-extensions = ">=0.4.3" -packaging = ">=22.0" -pathspec = ">=0.9.0" -platformdirs = ">=2" -tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} -typing-extensions = {version = ">=4.0.1", markers = "python_version < \"3.11\""} - -[package.extras] -colorama = ["colorama (>=0.4.3)"] -d = ["aiohttp (>=3.7.4)", "aiohttp (>=3.7.4,!=3.9.0)"] -jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"] -uvloop = ["uvloop (>=0.15.2)"] - -[package.source] -type = "legacy" -url = "https://pypi.org/simple" -reference = "offical-source" - [[package]] name = "brotli" version = "1.1.0" @@ -1864,25 +1813,6 @@ type = "legacy" url = "https://pypi.org/simple" reference = "offical-source" -[[package]] -name = "isort" -version = "5.13.2" -description = "A Python utility / library to sort Python imports." -optional = false -python-versions = ">=3.8.0" -files = [ - {file = "isort-5.13.2-py3-none-any.whl", hash = "sha256:8ca5e72a8d85860d5a3fa69b8745237f2939afe12dbf656afbcb47fe72d947a6"}, - {file = "isort-5.13.2.tar.gz", hash = "sha256:48fdfcb9face5d58a4f6dde2e72a1fb8dcaf8ab26f95ab49fab84c2ddefb0109"}, -] - -[package.extras] -colors = ["colorama (>=0.4.6)"] - -[package.source] -type = "legacy" -url = "https://pypi.org/simple" -reference = "offical-source" - [[package]] name = "jedi" version = "0.19.1" @@ -2565,22 +2495,6 @@ type = "legacy" url = "https://pypi.org/simple" reference = "offical-source" -[[package]] -name = "mypy-extensions" -version = "1.0.0" -description = "Type system extensions for programs checked with the mypy type checker." -optional = false -python-versions = ">=3.5" -files = [ - {file = "mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"}, - {file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"}, -] - -[package.source] -type = "legacy" -url = "https://pypi.org/simple" -reference = "offical-source" - [[package]] name = "nb-cli" version = "1.4.2" @@ -2970,22 +2884,6 @@ type = "legacy" url = "https://pypi.org/simple" reference = "offical-source" -[[package]] -name = "pathspec" -version = "0.12.1" -description = "Utility library for gitignore style pattern matching of file paths." -optional = false -python-versions = ">=3.8" -files = [ - {file = "pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08"}, - {file = "pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712"}, -] - -[package.source] -type = "legacy" -url = "https://pypi.org/simple" -reference = "offical-source" - [[package]] name = "pexpect" version = "4.9.0" @@ -4222,29 +4120,29 @@ reference = "offical-source" [[package]] name = "ruff" -version = "0.6.5" +version = "0.8.2" description = "An extremely fast Python linter and code formatter, written in Rust." optional = false python-versions = ">=3.7" files = [ - {file = "ruff-0.6.5-py3-none-linux_armv6l.whl", hash = "sha256:7e4e308f16e07c95fc7753fc1aaac690a323b2bb9f4ec5e844a97bb7fbebd748"}, - {file = "ruff-0.6.5-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:932cd69eefe4daf8c7d92bd6689f7e8182571cb934ea720af218929da7bd7d69"}, - {file = "ruff-0.6.5-py3-none-macosx_11_0_arm64.whl", hash = "sha256:3a8d42d11fff8d3143ff4da41742a98f8f233bf8890e9fe23077826818f8d680"}, - {file = "ruff-0.6.5-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a50af6e828ee692fb10ff2dfe53f05caecf077f4210fae9677e06a808275754f"}, - {file = "ruff-0.6.5-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:794ada3400a0d0b89e3015f1a7e01f4c97320ac665b7bc3ade24b50b54cb2972"}, - {file = "ruff-0.6.5-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:381413ec47f71ce1d1c614f7779d88886f406f1fd53d289c77e4e533dc6ea200"}, - {file = "ruff-0.6.5-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:52e75a82bbc9b42e63c08d22ad0ac525117e72aee9729a069d7c4f235fc4d276"}, - {file = "ruff-0.6.5-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:09c72a833fd3551135ceddcba5ebdb68ff89225d30758027280968c9acdc7810"}, - {file = "ruff-0.6.5-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:800c50371bdcb99b3c1551d5691e14d16d6f07063a518770254227f7f6e8c178"}, - {file = "ruff-0.6.5-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8e25ddd9cd63ba1f3bd51c1f09903904a6adf8429df34f17d728a8fa11174253"}, - {file = "ruff-0.6.5-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:7291e64d7129f24d1b0c947ec3ec4c0076e958d1475c61202497c6aced35dd19"}, - {file = "ruff-0.6.5-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:9ad7dfbd138d09d9a7e6931e6a7e797651ce29becd688be8a0d4d5f8177b4b0c"}, - {file = "ruff-0.6.5-py3-none-musllinux_1_2_i686.whl", hash = "sha256:005256d977021790cc52aa23d78f06bb5090dc0bfbd42de46d49c201533982ae"}, - {file = "ruff-0.6.5-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:482c1e6bfeb615eafc5899127b805d28e387bd87db38b2c0c41d271f5e58d8cc"}, - {file = "ruff-0.6.5-py3-none-win32.whl", hash = "sha256:cf4d3fa53644137f6a4a27a2b397381d16454a1566ae5335855c187fbf67e4f5"}, - {file = "ruff-0.6.5-py3-none-win_amd64.whl", hash = "sha256:3e42a57b58e3612051a636bc1ac4e6b838679530235520e8f095f7c44f706ff9"}, - {file = "ruff-0.6.5-py3-none-win_arm64.whl", hash = "sha256:51935067740773afdf97493ba9b8231279e9beef0f2a8079188c4776c25688e0"}, - {file = "ruff-0.6.5.tar.gz", hash = "sha256:4d32d87fab433c0cf285c3683dd4dae63be05fd7a1d65b3f5bf7cdd05a6b96fb"}, + {file = "ruff-0.8.2-py3-none-linux_armv6l.whl", hash = "sha256:c49ab4da37e7c457105aadfd2725e24305ff9bc908487a9bf8d548c6dad8bb3d"}, + {file = "ruff-0.8.2-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:ec016beb69ac16be416c435828be702ee694c0d722505f9c1f35e1b9c0cc1bf5"}, + {file = "ruff-0.8.2-py3-none-macosx_11_0_arm64.whl", hash = "sha256:f05cdf8d050b30e2ba55c9b09330b51f9f97d36d4673213679b965d25a785f3c"}, + {file = "ruff-0.8.2-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:60f578c11feb1d3d257b2fb043ddb47501ab4816e7e221fbb0077f0d5d4e7b6f"}, + {file = "ruff-0.8.2-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:cbd5cf9b0ae8f30eebc7b360171bd50f59ab29d39f06a670b3e4501a36ba5897"}, + {file = "ruff-0.8.2-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b402ddee3d777683de60ff76da801fa7e5e8a71038f57ee53e903afbcefdaa58"}, + {file = "ruff-0.8.2-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:705832cd7d85605cb7858d8a13d75993c8f3ef1397b0831289109e953d833d29"}, + {file = "ruff-0.8.2-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:32096b41aaf7a5cc095fa45b4167b890e4c8d3fd217603f3634c92a541de7248"}, + {file = "ruff-0.8.2-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e769083da9439508833cfc7c23e351e1809e67f47c50248250ce1ac52c21fb93"}, + {file = "ruff-0.8.2-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5fe716592ae8a376c2673fdfc1f5c0c193a6d0411f90a496863c99cd9e2ae25d"}, + {file = "ruff-0.8.2-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:81c148825277e737493242b44c5388a300584d73d5774defa9245aaef55448b0"}, + {file = "ruff-0.8.2-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:d261d7850c8367704874847d95febc698a950bf061c9475d4a8b7689adc4f7fa"}, + {file = "ruff-0.8.2-py3-none-musllinux_1_2_i686.whl", hash = "sha256:1ca4e3a87496dc07d2427b7dd7ffa88a1e597c28dad65ae6433ecb9f2e4f022f"}, + {file = "ruff-0.8.2-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:729850feed82ef2440aa27946ab39c18cb4a8889c1128a6d589ffa028ddcfc22"}, + {file = "ruff-0.8.2-py3-none-win32.whl", hash = "sha256:ac42caaa0411d6a7d9594363294416e0e48fc1279e1b0e948391695db2b3d5b1"}, + {file = "ruff-0.8.2-py3-none-win_amd64.whl", hash = "sha256:2aae99ec70abf43372612a838d97bfe77d45146254568d94926e8ed5bbb409ea"}, + {file = "ruff-0.8.2-py3-none-win_arm64.whl", hash = "sha256:fb88e2a506b70cfbc2de6fae6681c4f944f7dd5f2fe87233a7233d888bad73e8"}, + {file = "ruff-0.8.2.tar.gz", hash = "sha256:b84f4f414dda8ac7f75075c1fa0b905ac0ff25361f42e6d5da681a465e0f78e5"}, ] [package.source] @@ -5166,4 +5064,4 @@ yaml = [] [metadata] lock-version = "2.0" python-versions = ">=3.10,<4.0.0" -content-hash = "3d3bd947b91b8053fc5fed4873b6d0ed4017a5be118611cd93d30ffa265e04fb" +content-hash = "c66f1511368c8de33a7706df2a20ef24d4191769fa29bf69bd2d5985381218d4" diff --git a/pyproject.toml b/pyproject.toml index 148b15c..ad1445a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -44,13 +44,11 @@ expiringdictx = "^1.1.0" rapidfuzz = "^3.9.7" [tool.poetry.group.dev.dependencies] -black = ">=24.8.0,<25.0" ipdb = "^0.13.13" -isort = "^5.13.2" nonemoji = "^0.1.4" nb-cli = "^1.4.2" pre-commit = "^4.0.1" -ruff = "^0.6.5" +ruff = "^0.8.2" [tool.poetry.group.test.dependencies] flaky = "^3.8.1" @@ -99,25 +97,44 @@ line-length = 120 target-version = "py310" [tool.ruff.lint] -select = ["E", "W", "F", "UP", "C", "T", "PYI", "PT", "Q"] -ignore = ["E402", "C901", "PT023"] +select = [ + "F", # Pyflakes + "W", # pycodestyle warnings + "E", # pycodestyle errors + "I", # isort + "UP", # pyupgrade + "ASYNC", # flake8-async + "C4", # flake8-comprehensions + "T10", # flake8-debugger + "T20", # flake8-print + "PYI", # flake8-pyi + "PT", # flake8-pytest-style + "Q", # flake8-quotes + "TID", # flake8-tidy-imports + "RUF", # Ruff-specific rules +] +ignore = [ + "E402", # module-import-not-at-top-of-file + "UP037", # quoted-annotation + "RUF001", # ambiguous-unicode-character-string + "RUF002", # ambiguous-unicode-character-docstring + "RUF003", # ambiguous-unicode-character-comment +] -[tool.black] -line-length = 120 -preview = true -target-version = ["py310", "py311", "py312"] -include = '\.pyi?$' -extend-exclude = ''' -''' +[tool.ruff.format] +line-ending = "lf" -[tool.isort] -profile = "black" -line_length = 120 -skip_gitignore = true -length_sort = true -force_sort_within_sections = true -src_paths = ["nonebot_bison", "tests"] -extra_standard_library = ["typing_extensions"] +[tool.ruff.lint.isort] +force-sort-within-sections = true +known-first-party = ["nonebot_bison", "tests/*"] +extra-standard-library = ["typing_extensions"] + +[tool.ruff.lint.flake8-pytest-style] +fixture-parentheses = false +mark-parentheses = false + +[tool.ruff.lint.pyupgrade] +keep-runtime-typing = true [tool.nonebot] adapters = [ @@ -130,6 +147,7 @@ builtin_plugins = ["echo"] [tool.pyright] typeCheckingMode = "basic" reportShadowedImports = false +disableBytesTypePromotions = true pythonVersion = "3.10" pythonPlatform = "All" executionEnvironments = [ diff --git a/tests/config/test_config_legacy.py b/tests/config/test_config_legacy.py index 348d44e..6b485d2 100644 --- a/tests/config/test_config_legacy.py +++ b/tests/config/test_config_legacy.py @@ -1,7 +1,7 @@ import typing -import pytest from nonebug.app import App +import pytest if typing.TYPE_CHECKING: import sys diff --git a/tests/config/test_config_operation.py b/tests/config/test_config_operation.py index f067603..49e7ed3 100644 --- a/tests/config/test_config_operation.py +++ b/tests/config/test_config_operation.py @@ -1,16 +1,16 @@ -import pytest from nonebug.app import App +import pytest async def test_add_subscribe(app: App, init_scheduler): - from nonebot_plugin_saa import TargetQQGroup - from sqlalchemy.sql.expression import select from nonebot_plugin_datastore.db import get_engine + from nonebot_plugin_saa import TargetQQGroup from sqlalchemy.ext.asyncio.session import AsyncSession + from sqlalchemy.sql.expression import select from nonebot_bison.config.db_config import config + from nonebot_bison.config.db_model import Subscribe, Target, User from nonebot_bison.types import Target as TTarget - from nonebot_bison.config.db_model import User, Target, Subscribe await config.add_subscribe( TargetQQGroup(group_id=123), @@ -69,8 +69,8 @@ async def test_add_subscribe(app: App, init_scheduler): async def test_add_dup_sub(init_scheduler): from nonebot_plugin_saa import TargetQQGroup - from nonebot_bison.types import Target as TTarget from nonebot_bison.config.db_config import SubscribeDupException, config + from nonebot_bison.types import Target as TTarget await config.add_subscribe( TargetQQGroup(group_id=123), @@ -93,15 +93,15 @@ async def test_add_dup_sub(init_scheduler): async def test_del_subsribe(init_scheduler): - from sqlalchemy.sql.functions import func - from nonebot_plugin_saa import TargetQQGroup - from sqlalchemy.sql.expression import select from nonebot_plugin_datastore.db import get_engine + from nonebot_plugin_saa import TargetQQGroup from sqlalchemy.ext.asyncio.session import AsyncSession + from sqlalchemy.sql.expression import select + from sqlalchemy.sql.functions import func from nonebot_bison.config.db_config import config + from nonebot_bison.config.db_model import Subscribe, Target from nonebot_bison.types import Target as TTarget - from nonebot_bison.config.db_model import Target, Subscribe await config.add_subscribe( TargetQQGroup(group_id=123), diff --git a/tests/config/test_cookie.py b/tests/config/test_cookie.py index 8d463d4..120caf4 100644 --- a/tests/config/test_cookie.py +++ b/tests/config/test_cookie.py @@ -1,9 +1,9 @@ +from datetime import datetime import json from typing import cast -from datetime import datetime -import pytest from nonebug import App +import pytest @pytest.mark.usefixtures("_patch_weibo_get_cookie_name") @@ -11,9 +11,9 @@ async def test_cookie(app: App, init_scheduler): from nonebot_plugin_saa import TargetQQGroup from nonebot_bison.config.db_config import config + from nonebot_bison.config.utils import DuplicateCookieTargetException from nonebot_bison.scheduler import scheduler_dict from nonebot_bison.types import Target as T_Target - from nonebot_bison.config.utils import DuplicateCookieTargetException from nonebot_bison.utils.site import CookieClientManager, site_manager target = T_Target("weibo_id") diff --git a/tests/config/test_data_migration.py b/tests/config/test_data_migration.py index 61e4575..06154cf 100644 --- a/tests/config/test_data_migration.py +++ b/tests/config/test_data_migration.py @@ -1,9 +1,9 @@ async def test_migration(use_legacy_config): - from nonebot_plugin_saa import TargetQQGroup from nonebot_plugin_datastore.db import init_db + from nonebot_plugin_saa import TargetQQGroup - from nonebot_bison.config.db_config import config from nonebot_bison.config.config_legacy import Config + from nonebot_bison.config.db_config import config config_legacy = Config() config_legacy.add_subscribe( @@ -57,11 +57,11 @@ async def test_migration(use_legacy_config): async def test_migrate_dup(use_legacy_config): - from nonebot_plugin_saa import TargetQQGroup from nonebot_plugin_datastore.db import init_db + from nonebot_plugin_saa import TargetQQGroup - from nonebot_bison.config.db_config import config from nonebot_bison.config.config_legacy import Config + from nonebot_bison.config.db_config import config config_legacy = Config() config_legacy.add_subscribe( diff --git a/tests/config/test_scheduler_conf.py b/tests/config/test_scheduler_conf.py index 5da8127..2874aea 100644 --- a/tests/config/test_scheduler_conf.py +++ b/tests/config/test_scheduler_conf.py @@ -7,8 +7,8 @@ from pytest_mock import MockerFixture async def test_create_config(init_scheduler): from nonebot_plugin_saa import TargetQQGroup + from nonebot_bison.config.db_config import TimeWeightConfig, WeightConfig, config from nonebot_bison.types import Target as T_Target - from nonebot_bison.config.db_config import WeightConfig, TimeWeightConfig, config await config.add_subscribe( TargetQQGroup(group_id=123), @@ -49,8 +49,8 @@ async def test_get_current_weight(init_scheduler, mocker: MockerFixture): from nonebot_plugin_saa import TargetQQGroup from nonebot_bison.config import db_config + from nonebot_bison.config.db_config import TimeWeightConfig, WeightConfig, config from nonebot_bison.types import Target as T_Target - from nonebot_bison.config.db_config import WeightConfig, TimeWeightConfig, config await config.add_subscribe( TargetQQGroup(group_id=123), @@ -108,13 +108,13 @@ async def test_get_current_weight(init_scheduler, mocker: MockerFixture): async def test_get_platform_target(app: App, init_scheduler): - from nonebot_plugin_saa import TargetQQGroup - from sqlalchemy.sql.expression import select from nonebot_plugin_datastore.db import get_engine + from nonebot_plugin_saa import TargetQQGroup from sqlalchemy.ext.asyncio.session import AsyncSession + from sqlalchemy.sql.expression import select - from nonebot_bison.config.db_model import Target from nonebot_bison.config.db_config import config + from nonebot_bison.config.db_model import Target from nonebot_bison.types import Target as T_Target await config.add_subscribe( @@ -158,9 +158,9 @@ async def test_get_platform_target(app: App, init_scheduler): async def test_get_platform_target_subscribers(app: App, init_scheduler): from nonebot_plugin_saa import TargetQQGroup - from nonebot_bison.types import UserSubInfo from nonebot_bison.config.db_config import config from nonebot_bison.types import Target as T_Target + from nonebot_bison.types import UserSubInfo await config.add_subscribe( TargetQQGroup(group_id=123), diff --git a/tests/conftest.py b/tests/conftest.py index 9e6085e..f5368f0 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,13 +1,13 @@ -import sys from pathlib import Path from shutil import rmtree +import sys -import pytest import nonebot -from sqlalchemy import delete -from nonebug import NONEBOT_INIT_KWARGS, App -from pytest_mock.plugin import MockerFixture from nonebot.adapters.onebot.v11 import Adapter as OnebotV11Adapter +from nonebug import NONEBOT_INIT_KWARGS, App +import pytest +from pytest_mock.plugin import MockerFixture +from sqlalchemy import delete from .utils import AppReq @@ -44,12 +44,12 @@ async def app(tmp_path: Path, request: pytest.FixtureRequest, mocker: MockerFixt sys.path.append(str(Path(__file__).parent.parent / "src" / "plugins")) nonebot.require("nonebot_bison") - from nonebot_plugin_htmlrender.browser import shutdown_browser - from nonebot_plugin_datastore.db import init_db, create_session from nonebot_plugin_datastore.config import plugin_config as datastore_config + from nonebot_plugin_datastore.db import create_session, init_db + from nonebot_plugin_htmlrender.browser import shutdown_browser from nonebot_bison import plugin_config - from nonebot_bison.config.db_model import User, Target, Subscribe, ScheduleTimeWeight + from nonebot_bison.config.db_model import ScheduleTimeWeight, Subscribe, Target, User plugin_config.bison_config_path = str(tmp_path / "legacy_config") plugin_config.bison_filter_log = False @@ -111,8 +111,8 @@ async def init_scheduler(app: App): async def use_legacy_config(app: App): import aiofiles - from nonebot_bison.utils import Singleton from nonebot_bison.config.config_legacy import Config, get_config_path + from nonebot_bison.utils import Singleton # 默认不创建配置所在的文件夹 # 如果需要测试需要手动创建相关文件夹 @@ -132,8 +132,8 @@ async def use_legacy_config(app: App): @pytest.fixture async def _no_browser(app: App, mocker: MockerFixture): - from nonebot_bison.plugin_config import plugin_config from nonebot_bison.platform import _get_unavailable_platforms + from nonebot_bison.plugin_config import plugin_config mocker.patch.object(plugin_config, "bison_use_browser", False) mocker.patch("nonebot_bison.platform.unavailable_paltforms", _get_unavailable_platforms()) diff --git a/tests/platforms/test_arknights.py b/tests/platforms/test_arknights.py index 92dd0b9..e58e4ca 100644 --- a/tests/platforms/test_arknights.py +++ b/tests/platforms/test_arknights.py @@ -1,10 +1,10 @@ from time import time -import respx -import pytest from httpx import Response -from nonebug.app import App from nonebot.compat import model_dump, type_validate_python +from nonebug.app import App +import pytest +import respx from .utils import get_file, get_json @@ -12,7 +12,7 @@ from .utils import get_file, get_json @pytest.fixture def arknights(app: App): from nonebot_bison.platform import platform_manager - from nonebot_bison.utils import ProcessContext, DefaultClientManager + from nonebot_bison.utils import DefaultClientManager, ProcessContext return platform_manager["arknights"](ProcessContext(DefaultClientManager())) @@ -44,8 +44,8 @@ def monster_siren_list_1(): @respx.mock async def test_url_parse(app: App): - from nonebot_bison.utils import ProcessContext, DefaultClientManager - from nonebot_bison.platform.arknights import Arknights, BulletinData, BulletinListItem, ArkBulletinResponse + from nonebot_bison.platform.arknights import ArkBulletinResponse, Arknights, BulletinData, BulletinListItem + from nonebot_bison.utils import DefaultClientManager, ProcessContext cid_router = respx.get("https://ak-webview.hypergryph.com/api/game/bulletin/1") @@ -110,10 +110,10 @@ async def test_url_parse(app: App): assert p4.url == "http://www.baidu.com/" -@pytest.mark.asyncio() +@pytest.mark.asyncio async def test_get_date_in_bulletin(app: App): - from nonebot_bison.utils import ProcessContext, DefaultClientManager from nonebot_bison.platform.arknights import Arknights, BulletinListItem + from nonebot_bison.utils import DefaultClientManager, ProcessContext arknights = Arknights(ProcessContext(DefaultClientManager())) assert ( @@ -131,11 +131,11 @@ async def test_get_date_in_bulletin(app: App): ) -@pytest.mark.asyncio() +@pytest.mark.asyncio @respx.mock async def test_parse_with_breakline(app: App): - from nonebot_bison.utils import ProcessContext, DefaultClientManager from nonebot_bison.platform.arknights import Arknights, BulletinListItem + from nonebot_bison.utils import DefaultClientManager, ProcessContext detail = get_json("arknights-detail-805") detail["data"]["header"] = "" @@ -158,7 +158,7 @@ async def test_parse_with_breakline(app: App): assert post.title == "【公开招募】 - 标签刷新通知" -@pytest.mark.asyncio() +@pytest.mark.asyncio @respx.mock async def test_fetch_new( arknights, @@ -168,9 +168,9 @@ async def test_fetch_new( monster_siren_list_0, monster_siren_list_1, ): - from nonebot_bison.post import Post - from nonebot_bison.types import Target, SubUnit from nonebot_bison.platform.arknights import ArknightsPost + from nonebot_bison.post import Post + from nonebot_bison.types import SubUnit, Target ak_list_router = respx.get("https://ak-webview.hypergryph.com/api/game/bulletinList?target=IOS") detail_router = respx.get("https://ak-webview.hypergryph.com/api/game/bulletin/5716") @@ -229,7 +229,7 @@ async def test_fetch_new( assert "brief" == post3.get_priority_themes()[0] -@pytest.mark.render() +@pytest.mark.render @respx.mock async def test_send_with_render( arknights, @@ -239,8 +239,8 @@ async def test_send_with_render( monster_siren_list_0, monster_siren_list_1, ): - from nonebot_bison.types import Target, SubUnit from nonebot_bison.platform.arknights import ArknightsPost + from nonebot_bison.types import SubUnit, Target ak_list_router = respx.get("https://ak-webview.hypergryph.com/api/game/bulletinList?target=IOS") detail_router = respx.get("https://ak-webview.hypergryph.com/api/game/bulletin/8397") @@ -284,13 +284,13 @@ async def test_send_with_render( assert r -@pytest.mark.render() +@pytest.mark.render @respx.mock async def test_parse_title( app: App, ): - from nonebot_bison.utils import ProcessContext, DefaultClientManager from nonebot_bison.platform.arknights import Arknights, BulletinListItem + from nonebot_bison.utils import DefaultClientManager, ProcessContext detail_router = respx.get("https://ak-webview.hypergryph.com/api/game/bulletin/8397") diff --git a/tests/platforms/test_bilibili.py b/tests/platforms/test_bilibili.py index 0d48679..c0c7442 100644 --- a/tests/platforms/test_bilibili.py +++ b/tests/platforms/test_bilibili.py @@ -1,16 +1,16 @@ +from datetime import datetime import random from time import time -from datetime import datetime -from typing import TYPE_CHECKING, Any +from typing import TYPE_CHECKING, Any, ClassVar -import respx -import pytest -from loguru import logger -from nonebug.app import App -from httpx import URL, Response from freezegun import freeze_time -from pytest_mock import MockerFixture +from httpx import URL, Response +from loguru import logger from nonebot.compat import model_dump, type_validate_python +from nonebug.app import App +import pytest +from pytest_mock import MockerFixture +import respx from .utils import get_json @@ -28,9 +28,9 @@ if TYPE_CHECKING: @pytest.fixture def bilibili(app: App) -> "Bilibili": - from nonebot_bison.utils import ProcessContext from nonebot_bison.platform import platform_manager from nonebot_bison.platform.bilibili import BilibiliClientManager + from nonebot_bison.utils import ProcessContext return platform_manager["bilibili"](ProcessContext(BilibiliClientManager())) # type: ignore @@ -62,7 +62,7 @@ def without_dynamic(app: App): async def test_reset_on_exception(app: App): from strenum import StrEnum - from nonebot_bison.platform.bilibili.fsm import FSM, StateGraph, Transition, ActionReturn, reset_on_exception + from nonebot_bison.platform.bilibili.fsm import FSM, ActionReturn, StateGraph, Transition, reset_on_exception class State(StrEnum): A = "A" @@ -146,12 +146,12 @@ async def test_reset_on_exception(app: App): @pytest.mark.asyncio async def test_retry_for_352(app: App, mocker: MockerFixture): - from nonebot_bison.post import Post - from nonebot_bison.types import Target, RawPost - from nonebot_bison.platform.platform import NewMessage from nonebot_bison.platform.bilibili.platforms import ApiCode352Error - from nonebot_bison.utils import ClientManager, ProcessContext, http_client from nonebot_bison.platform.bilibili.retry import RetryAddon, RetryState, _retry_fsm, retry_for_352 + from nonebot_bison.platform.platform import NewMessage + from nonebot_bison.post import Post + from nonebot_bison.types import RawPost, Target + from nonebot_bison.utils import ClientManager, ProcessContext, http_client mocker.patch.object(random, "random", return_value=0.0) # 稳定触发RAISE阶段的随缘刷新 @@ -166,7 +166,7 @@ async def test_retry_for_352(app: App, mocker: MockerFixture): is_common = True schedule_interval = 10 enable_tag = False - categories = {} + categories: ClassVar[dict] = {} has_target = True raise352 = False @@ -422,7 +422,7 @@ async def test_dynamic_forword_deleted(bilibili: "Bilibili", bing_dy_list: list) @pytest.mark.asyncio @respx.mock async def test_fetch_new_without_dynamic(bilibili, dummy_user_subinfo, without_dynamic): - from nonebot_bison.types import Target, SubUnit + from nonebot_bison.types import SubUnit, Target target = Target("161775300") post_router = respx.get( @@ -439,8 +439,8 @@ async def test_fetch_new_without_dynamic(bilibili, dummy_user_subinfo, without_d async def test_fetch_new(bilibili, dummy_user_subinfo): from nonebot.compat import model_dump, type_validate_python - from nonebot_bison.types import Target, SubUnit from nonebot_bison.platform.bilibili.models import PostAPI + from nonebot_bison.types import SubUnit, Target target = Target("161775300") @@ -483,8 +483,8 @@ async def test_fetch_new(bilibili, dummy_user_subinfo): async def test_fetch_new_live_rcmd(bilibili: "Bilibili", dummy_user_subinfo): from nonebot.compat import model_dump, type_validate_python - from nonebot_bison.types import Target, SubUnit from nonebot_bison.platform.bilibili.models import PostAPI + from nonebot_bison.types import SubUnit, Target target = Target("13164144") diff --git a/tests/platforms/test_bilibili_bangumi.py b/tests/platforms/test_bilibili_bangumi.py index d4c9c71..9f83491 100644 --- a/tests/platforms/test_bilibili_bangumi.py +++ b/tests/platforms/test_bilibili_bangumi.py @@ -1,9 +1,9 @@ import typing -import respx -import pytest from httpx import Response from nonebug.app import App +import pytest +import respx from .utils import get_json @@ -14,7 +14,7 @@ if typing.TYPE_CHECKING: @pytest.fixture def bili_bangumi(app: App): from nonebot_bison.platform import platform_manager - from nonebot_bison.utils import ProcessContext, DefaultClientManager + from nonebot_bison.utils import DefaultClientManager, ProcessContext return platform_manager["bilibili-bangumi"](ProcessContext(DefaultClientManager())) @@ -38,7 +38,7 @@ async def test_parse_target(bili_bangumi: "BilibiliBangumi"): @pytest.mark.asyncio @respx.mock async def test_fetch_bilibili_bangumi_status(bili_bangumi: "BilibiliBangumi", dummy_user_subinfo): - from nonebot_bison.types import Target, SubUnit + from nonebot_bison.types import SubUnit, Target bili_bangumi_router = respx.get("https://api.bilibili.com/pgc/review/user?media_id=28235413") bili_bangumi_detail_router = respx.get("https://api.bilibili.com/pgc/view/web/season?season_id=39719") diff --git a/tests/platforms/test_bilibili_live.py b/tests/platforms/test_bilibili_live.py index 65762f5..2c7e713 100644 --- a/tests/platforms/test_bilibili_live.py +++ b/tests/platforms/test_bilibili_live.py @@ -1,10 +1,10 @@ from copy import deepcopy from typing import TYPE_CHECKING -import respx -import pytest from httpx import Response from nonebug.app import App +import pytest +import respx from .utils import get_json @@ -15,7 +15,7 @@ if TYPE_CHECKING: @pytest.fixture def bili_live(app: App): from nonebot_bison.platform import platform_manager - from nonebot_bison.utils import ProcessContext, DefaultClientManager + from nonebot_bison.utils import DefaultClientManager, ProcessContext return platform_manager["bilibili-live"](ProcessContext(DefaultClientManager())) @@ -33,7 +33,7 @@ def dummy_only_open_user_subinfo(app: App): @pytest.mark.asyncio @respx.mock async def test_fetch_bililive_no_room(bili_live, dummy_only_open_user_subinfo): - from nonebot_bison.types import Target, SubUnit + from nonebot_bison.types import SubUnit, Target mock_bili_live_status = get_json("bili_live_status.json") mock_bili_live_status["data"] = {} @@ -53,7 +53,7 @@ async def test_fetch_bililive_no_room(bili_live, dummy_only_open_user_subinfo): @respx.mock async def test_fetch_first_live(bili_live, dummy_only_open_user_subinfo): from nonebot_bison.post import Post - from nonebot_bison.types import Target, SubUnit + from nonebot_bison.types import SubUnit, Target mock_bili_live_status = get_json("bili_live_status.json") empty_bili_live_status = deepcopy(mock_bili_live_status) @@ -90,7 +90,7 @@ async def test_fetch_first_live(bili_live, dummy_only_open_user_subinfo): @respx.mock async def test_fetch_bililive_only_live_open(bili_live: "Bilibililive", dummy_only_open_user_subinfo): from nonebot_bison.post import Post - from nonebot_bison.types import Target, SubUnit + from nonebot_bison.types import SubUnit, Target mock_bili_live_status = get_json("bili_live_status.json") @@ -141,11 +141,11 @@ def dummy_only_title_user_subinfo(app: App): return UserSubInfo(user=user, categories=[2], tags=[]) -@pytest.mark.asyncio() +@pytest.mark.asyncio @respx.mock async def test_fetch_bililive_only_title_change(bili_live, dummy_only_title_user_subinfo): from nonebot_bison.post import Post - from nonebot_bison.types import Target, SubUnit + from nonebot_bison.types import SubUnit, Target mock_bili_live_status = get_json("bili_live_status.json") target = Target("13164144") @@ -204,7 +204,7 @@ def dummy_only_close_user_subinfo(app: App): @respx.mock async def test_fetch_bililive_only_close(bili_live, dummy_only_close_user_subinfo): from nonebot_bison.post import Post - from nonebot_bison.types import Target, SubUnit + from nonebot_bison.types import SubUnit, Target mock_bili_live_status = get_json("bili_live_status.json") target = Target("13164144") @@ -264,7 +264,7 @@ def dummy_bililive_user_subinfo(app: App): @respx.mock async def test_fetch_bililive_combo(bili_live, dummy_bililive_user_subinfo): from nonebot_bison.post import Post - from nonebot_bison.types import Target, SubUnit + from nonebot_bison.types import SubUnit, Target mock_bili_live_status = get_json("bili_live_status.json") target = Target("13164144") diff --git a/tests/platforms/test_ceobecanteen.py b/tests/platforms/test_ceobecanteen.py index d2e3988..67186eb 100644 --- a/tests/platforms/test_ceobecanteen.py +++ b/tests/platforms/test_ceobecanteen.py @@ -1,10 +1,10 @@ from typing import TYPE_CHECKING -import respx -import pytest from httpx import Response -from nonebug.app import App from nonebot.compat import type_validate_python +from nonebug.app import App +import pytest +import respx from .utils import get_json @@ -24,9 +24,9 @@ def dummy_only_open_user_subinfo(app: App): @pytest.fixture def ceobecanteen(app: App): - from nonebot_bison.utils import ProcessContext from nonebot_bison.platform import platform_manager from nonebot_bison.platform.ceobecanteen.platform import CeobeCanteenClientManager + from nonebot_bison.utils import ProcessContext return platform_manager["ceobecanteen"](ProcessContext(CeobeCanteenClientManager())) @@ -71,7 +71,7 @@ def ceobecanteen_cookies_1() -> dict: return get_json("ceobecanteen_cookies_1.json") -@pytest.mark.asyncio() +@pytest.mark.asyncio async def test_parse_retweet(app: App): from nonebot_bison.platform.ceobecanteen.models import CookiesResponse @@ -79,7 +79,7 @@ async def test_parse_retweet(app: App): assert cookie_with_retweet.data.cookies[0].item.retweeted -@pytest.mark.render() +@pytest.mark.render async def test_ceobe_snapshot(app: App, ceobecanteen: "CeobeCanteen"): from nonebot_bison.platform.ceobecanteen.models import CeobeCookie @@ -113,7 +113,7 @@ async def test_ceobe_snapshot(app: App, ceobecanteen: "CeobeCanteen"): @pytest.mark.skip("极限测试, 不在CI中运行") -@pytest.mark.asyncio() +@pytest.mark.asyncio async def test_parse_crazy(app: App, ceobecanteen): from nonebot_plugin_saa import Image @@ -139,7 +139,7 @@ async def test_parse_crazy(app: App, ceobecanteen): show(ext((await post4.generate_messages())[0][0])) # type: ignore -@pytest.mark.asyncio() +@pytest.mark.asyncio @respx.mock async def test_batch_fetch_new_with_single( app: App, @@ -220,7 +220,7 @@ async def test_batch_fetch_new_with_single( await post3.generate_messages() -@pytest.mark.asyncio() +@pytest.mark.asyncio @respx.mock async def test_parse_target_fuzzy(app: App, ceobecanteen: "CeobeCanteen", dummy_target, ceobecanteen_targets): from nonebot_bison.platform.ceobecanteen import CeobeCanteen diff --git a/tests/platforms/test_ff14.py b/tests/platforms/test_ff14.py index c6512f8..7b0bf03 100644 --- a/tests/platforms/test_ff14.py +++ b/tests/platforms/test_ff14.py @@ -1,7 +1,7 @@ -import respx -import pytest from httpx import Response from nonebug.app import App +import pytest +import respx from .utils import get_json @@ -9,7 +9,7 @@ from .utils import get_json @pytest.fixture def ff14(app: App): from nonebot_bison.platform import platform_manager - from nonebot_bison.utils import ProcessContext, DefaultClientManager + from nonebot_bison.utils import DefaultClientManager, ProcessContext return platform_manager["ff14"](ProcessContext(DefaultClientManager())) @@ -28,7 +28,7 @@ def ff14_newdata_json_1(): @respx.mock async def test_fetch_new(ff14, dummy_user_subinfo, ff14_newdata_json_0, ff14_newdata_json_1): from nonebot_bison.post import Post - from nonebot_bison.types import Target, SubUnit + from nonebot_bison.types import SubUnit, Target newdata = respx.get( "https://cqnews.web.sdo.com/api/news/newsList?gameCode=ff&CategoryCode=5309,5310,5311,5312,5313&pageIndex=0&pageSize=5" diff --git a/tests/platforms/test_ncm_artist.py b/tests/platforms/test_ncm_artist.py index 91b5921..fc9c716 100644 --- a/tests/platforms/test_ncm_artist.py +++ b/tests/platforms/test_ncm_artist.py @@ -1,10 +1,10 @@ import time import typing -import respx -import pytest from httpx import Response from nonebug.app import App +import pytest +import respx from .utils import get_json @@ -15,7 +15,7 @@ if typing.TYPE_CHECKING: @pytest.fixture def ncm_artist(app: App): from nonebot_bison.platform import platform_manager - from nonebot_bison.utils import ProcessContext, DefaultClientManager + from nonebot_bison.utils import DefaultClientManager, ProcessContext return platform_manager["ncm-artist"](ProcessContext(DefaultClientManager())) @@ -41,7 +41,7 @@ def ncm_artist_1(ncm_artist_raw: dict): @pytest.mark.asyncio @respx.mock async def test_fetch_new(ncm_artist, ncm_artist_0, ncm_artist_1, dummy_user_subinfo): - from nonebot_bison.types import Target, SubUnit + from nonebot_bison.types import SubUnit, Target ncm_router = respx.get("https://music.163.com/api/artist/albums/32540734") ncm_router.mock(return_value=Response(200, json=ncm_artist_0)) diff --git a/tests/platforms/test_ncm_radio.py b/tests/platforms/test_ncm_radio.py index 37b9d45..bc9cae9 100644 --- a/tests/platforms/test_ncm_radio.py +++ b/tests/platforms/test_ncm_radio.py @@ -1,10 +1,10 @@ import time import typing -import respx -import pytest from httpx import Response from nonebug.app import App +import pytest +import respx from .utils import get_json @@ -15,7 +15,7 @@ if typing.TYPE_CHECKING: @pytest.fixture def ncm_radio(app: App): from nonebot_bison.platform import platform_manager - from nonebot_bison.utils import ProcessContext, DefaultClientManager + from nonebot_bison.utils import DefaultClientManager, ProcessContext return platform_manager["ncm-radio"](ProcessContext(DefaultClientManager())) @@ -42,7 +42,7 @@ def ncm_radio_1(ncm_radio_raw: dict): @respx.mock async def test_fetch_new(ncm_radio, ncm_radio_0, ncm_radio_1, dummy_user_subinfo): from nonebot_bison.post import Post - from nonebot_bison.types import Target, SubUnit + from nonebot_bison.types import SubUnit, Target ncm_router = respx.post("http://music.163.com/api/dj/program/byradio") ncm_router.mock(return_value=Response(200, json=ncm_radio_0)) diff --git a/tests/platforms/test_platform.py b/tests/platforms/test_platform.py index 689607b..5efedae 100644 --- a/tests/platforms/test_platform.py +++ b/tests/platforms/test_platform.py @@ -1,15 +1,16 @@ from time import time -from typing import Any +from typing import Any, ClassVar -import pytest from nonebug.app import App +import pytest now = time() passed = now - 3 * 60 * 60 raw_post_list_1 = [{"id": 1, "text": "p1", "date": now, "tags": ["tag1"], "category": 1}] -raw_post_list_2 = raw_post_list_1 + [ +raw_post_list_2 = [ + *raw_post_list_1, {"id": 2, "text": "p2", "date": now, "tags": ["tag1"], "category": 1}, {"id": 3, "text": "p3", "date": now, "tags": ["tag2"], "category": 2}, {"id": 4, "text": "p4", "date": now, "tags": ["tag2"], "category": 3}, @@ -36,9 +37,9 @@ def user_info_factory(app: App, dummy_user): @pytest.fixture def mock_platform_without_cats_tags(app: App): - from nonebot_bison.post import Post - from nonebot_bison.types import Target, RawPost from nonebot_bison.platform.platform import NewMessage + from nonebot_bison.post import Post + from nonebot_bison.types import RawPost, Target class MockPlatform(NewMessage): platform_name = "mock_platform" @@ -47,7 +48,7 @@ def mock_platform_without_cats_tags(app: App): is_common = True schedule_interval = 10 enable_tag = False - categories = {} + categories: ClassVar[dict] = {} has_target = True sub_index = 0 @@ -83,15 +84,15 @@ def mock_platform_without_cats_tags(app: App): @pytest.fixture def mock_platform(app: App): - from nonebot_bison.post import Post - from nonebot_bison.utils import Site from nonebot_bison.platform.platform import NewMessage - from nonebot_bison.types import Tag, Target, RawPost, Category + from nonebot_bison.post import Post + from nonebot_bison.types import Category, RawPost, Tag, Target + from nonebot_bison.utils import Site class MockSite(Site): name = "mock_site" schedule_type = "interval" - schedule_setting = {"seconds": 100} + schedule_setting: ClassVar[dict] = {"seconds": 100} class MockPlatform(NewMessage): platform_name = "mock_platform" @@ -101,7 +102,7 @@ def mock_platform(app: App): enable_tag = True has_target = True site = MockSite - categories = { + categories: ClassVar[dict] = { Category(1): "转发", Category(2): "视频", } @@ -150,16 +151,16 @@ def mock_site(app): class MockSite(Site): name = "mock_site" schedule_type = "interval" - schedule_setting = {"seconds": 100} + schedule_setting: ClassVar[dict] = {"seconds": 100} return MockSite @pytest.fixture def mock_platform_no_target(app: App, mock_site): + from nonebot_bison.platform.platform import CategoryNotSupport, NewMessage from nonebot_bison.post import Post - from nonebot_bison.types import Tag, Target, RawPost, Category - from nonebot_bison.platform.platform import NewMessage, CategoryNotSupport + from nonebot_bison.types import Category, RawPost, Tag, Target class MockPlatform(NewMessage): platform_name = "mock_platform" @@ -169,7 +170,7 @@ def mock_platform_no_target(app: App, mock_site): site = mock_site enable_tag = True has_target = False - categories = {Category(1): "转发", Category(2): "视频", Category(3): "不支持"} + categories: ClassVar[dict] = {Category(1): "转发", Category(2): "视频", Category(3): "不支持"} sub_index = 0 @@ -212,9 +213,9 @@ def mock_platform_no_target(app: App, mock_site): @pytest.fixture def mock_platform_no_target_2(app: App, mock_site): - from nonebot_bison.post import Post from nonebot_bison.platform.platform import NewMessage - from nonebot_bison.types import Tag, Target, RawPost, Category + from nonebot_bison.post import Post + from nonebot_bison.types import Category, RawPost, Tag, Target class MockPlatform(NewMessage): platform_name = "mock_platform" @@ -224,7 +225,7 @@ def mock_platform_no_target_2(app: App, mock_site): is_common = True enable_tag = True has_target = False - categories = { + categories: ClassVar[dict] = { Category(4): "leixing4", Category(5): "leixing5", } @@ -259,7 +260,8 @@ def mock_platform_no_target_2(app: App, mock_site): async def get_sub_list(cls, _: "Target"): list_1 = [{"id": 5, "text": "p5", "date": now, "tags": ["tag1"], "category": 4}] - list_2 = list_1 + [ + list_2 = [ + *list_1, {"id": 6, "text": "p6", "date": now, "tags": ["tag1"], "category": 4}, {"id": 7, "text": "p7", "date": now, "tags": ["tag2"], "category": 5}, ] @@ -274,9 +276,9 @@ def mock_platform_no_target_2(app: App, mock_site): @pytest.fixture def mock_status_change(app: App): - from nonebot_bison.post import Post from nonebot_bison.platform.platform import StatusChange - from nonebot_bison.types import Target, RawPost, Category + from nonebot_bison.post import Post + from nonebot_bison.types import Category, RawPost, Target class MockPlatform(StatusChange): platform_name = "mock_platform" @@ -285,9 +287,9 @@ def mock_status_change(app: App): is_common = True enable_tag = False schedule_type = "interval" - schedule_kw = {"seconds": 10} + schedule_kw: ClassVar[dict] = {"seconds": 10} has_target = False - categories = { + categories: ClassVar[dict] = { Category(1): "转发", Category(2): "视频", } @@ -323,8 +325,8 @@ def mock_status_change(app: App): @pytest.mark.asyncio async def test_new_message_target_without_cats_tags(mock_platform_without_cats_tags, user_info_factory): - from nonebot_bison.types import Target, SubUnit - from nonebot_bison.utils import ProcessContext, DefaultClientManager + from nonebot_bison.types import SubUnit, Target + from nonebot_bison.utils import DefaultClientManager, ProcessContext res1 = await mock_platform_without_cats_tags(ProcessContext(DefaultClientManager())).fetch_new_post( SubUnit(Target("dummy"), [user_info_factory([1, 2], [])]) @@ -344,8 +346,8 @@ async def test_new_message_target_without_cats_tags(mock_platform_without_cats_t @pytest.mark.asyncio async def test_new_message_target(mock_platform, user_info_factory): - from nonebot_bison.types import Target, SubUnit - from nonebot_bison.utils import ProcessContext, DefaultClientManager + from nonebot_bison.types import SubUnit, Target + from nonebot_bison.utils import DefaultClientManager, ProcessContext res1 = await mock_platform(ProcessContext(DefaultClientManager())).fetch_new_post( SubUnit(Target("dummy"), [user_info_factory([1, 2], [])]) @@ -379,8 +381,8 @@ async def test_new_message_target(mock_platform, user_info_factory): @pytest.mark.asyncio async def test_new_message_no_target(mock_platform_no_target, user_info_factory): - from nonebot_bison.types import Target, SubUnit - from nonebot_bison.utils import ProcessContext, DefaultClientManager + from nonebot_bison.types import SubUnit, Target + from nonebot_bison.utils import DefaultClientManager, ProcessContext res1 = await mock_platform_no_target(ProcessContext(DefaultClientManager())).fetch_new_post( SubUnit(Target("dummy"), [user_info_factory([1, 2], [])]) @@ -418,8 +420,8 @@ async def test_new_message_no_target(mock_platform_no_target, user_info_factory) @pytest.mark.asyncio async def test_status_change(mock_status_change, user_info_factory): - from nonebot_bison.types import Target, SubUnit - from nonebot_bison.utils import ProcessContext, DefaultClientManager + from nonebot_bison.types import SubUnit, Target + from nonebot_bison.utils import DefaultClientManager, ProcessContext res1 = await mock_status_change(ProcessContext(DefaultClientManager())).fetch_new_post( SubUnit(Target("dummy"), [user_info_factory([1, 2], [])]) @@ -458,9 +460,9 @@ async def test_group( mock_platform_no_target_2, user_info_factory, ): - from nonebot_bison.types import Target, SubUnit from nonebot_bison.platform.platform import make_no_target_group - from nonebot_bison.utils import ProcessContext, DefaultClientManager + from nonebot_bison.types import SubUnit, Target + from nonebot_bison.utils import DefaultClientManager, ProcessContext dummy = Target("dummy") @@ -482,11 +484,11 @@ async def test_group( async def test_batch_fetch_new_message(app: App): from nonebot_plugin_saa import TargetQQGroup - from nonebot_bison.post import Post - from nonebot_bison.utils import DefaultClientManager from nonebot_bison.platform.platform import NewMessage + from nonebot_bison.post import Post + from nonebot_bison.types import RawPost, SubUnit, Target, UserSubInfo + from nonebot_bison.utils import DefaultClientManager from nonebot_bison.utils.context import ProcessContext - from nonebot_bison.types import Target, RawPost, SubUnit, UserSubInfo class BatchNewMessage(NewMessage): platform_name = "mock_platform" @@ -495,7 +497,7 @@ async def test_batch_fetch_new_message(app: App): is_common = True schedule_interval = 10 enable_tag = False - categories = {} + categories: ClassVar[dict] = {} has_target = True sub_index = 0 @@ -569,11 +571,11 @@ async def test_batch_fetch_new_message(app: App): async def test_batch_fetch_compare_status(app: App): from nonebot_plugin_saa import TargetQQGroup + from nonebot_bison.platform.platform import StatusChange from nonebot_bison.post import Post + from nonebot_bison.types import Category, RawPost, SubUnit, Target, UserSubInfo from nonebot_bison.utils import DefaultClientManager from nonebot_bison.utils.context import ProcessContext - from nonebot_bison.platform.platform import StatusChange - from nonebot_bison.types import Target, RawPost, SubUnit, Category, UserSubInfo class BatchStatusChange(StatusChange): platform_name = "mock_platform" @@ -582,9 +584,9 @@ async def test_batch_fetch_compare_status(app: App): is_common = True enable_tag = False schedule_type = "interval" - schedule_kw = {"seconds": 10} + schedule_kw: ClassVar[dict] = {"seconds": 10} has_target = True - categories = { + categories: ClassVar[dict] = { Category(1): "转发", Category(2): "视频", } diff --git a/tests/platforms/test_platform_tag_filter.py b/tests/platforms/test_platform_tag_filter.py index 1e02fa8..6272821 100644 --- a/tests/platforms/test_platform_tag_filter.py +++ b/tests/platforms/test_platform_tag_filter.py @@ -1,5 +1,5 @@ -import pytest from nonebug.app import App +import pytest from .utils import get_json @@ -13,7 +13,7 @@ def test_cases(): @pytest.mark.asyncio async def test_filter_user_custom_tag(app: App, test_cases): from nonebot_bison.platform import platform_manager - from nonebot_bison.utils import ProcessContext, DefaultClientManager + from nonebot_bison.utils import DefaultClientManager, ProcessContext bilibili = platform_manager["bilibili"](ProcessContext(DefaultClientManager())) for case in test_cases: @@ -25,7 +25,7 @@ async def test_filter_user_custom_tag(app: App, test_cases): @pytest.mark.asyncio async def test_tag_separator(app: App): from nonebot_bison.platform import platform_manager - from nonebot_bison.utils import ProcessContext, DefaultClientManager + from nonebot_bison.utils import DefaultClientManager, ProcessContext bilibili = platform_manager["bilibili"](ProcessContext(DefaultClientManager())) tags = ["~111", "222", "333", "~444", "555"] diff --git a/tests/platforms/test_rss.py b/tests/platforms/test_rss.py index dc3a715..cddd3d1 100644 --- a/tests/platforms/test_rss.py +++ b/tests/platforms/test_rss.py @@ -1,12 +1,12 @@ -import typing from datetime import datetime +import typing import xml.etree.ElementTree as ET -import pytz -import respx -import pytest from httpx import Response from nonebug.app import App +import pytest +import pytz +import respx from .utils import get_file @@ -35,7 +35,7 @@ def user_info_factory(app: App, dummy_user): @pytest.fixture def rss(app: App): from nonebot_bison.platform import platform_manager - from nonebot_bison.utils import ProcessContext, DefaultClientManager + from nonebot_bison.utils import DefaultClientManager, ProcessContext return platform_manager["rss"](ProcessContext(DefaultClientManager())) @@ -71,7 +71,7 @@ async def test_fetch_new_1( user_info_factory, update_time_feed_1, ): - from nonebot_bison.types import Target, SubUnit + from nonebot_bison.types import SubUnit, Target ## 标题重复的情况 rss_router = respx.get("https://rsshub.app/twitter/user/ArknightsStaff") @@ -113,7 +113,7 @@ async def test_fetch_new_2( user_info_factory, update_time_feed_2, ): - from nonebot_bison.types import Target, SubUnit + from nonebot_bison.types import SubUnit, Target ## 标题与正文不重复的情况 rss_router = respx.get("https://www.ruanyifeng.com/blog/atom.xml") @@ -148,7 +148,7 @@ async def test_fetch_new_3( user_info_factory, update_time_feed_3, ): - from nonebot_bison.types import Target, SubUnit + from nonebot_bison.types import SubUnit, Target ## 只有没有 rss_router = respx.get("https://github.com/R3nzTheCodeGOD/R3nzSkin/releases.atom") @@ -172,7 +172,7 @@ async def test_fetch_new_4( rss, user_info_factory, ): - from nonebot_bison.types import Target, SubUnit + from nonebot_bison.types import SubUnit, Target ## 没有日期信息的情况 rss_router = respx.get("https://rsshub.app/wallhaven/hot?limit=5") diff --git a/tests/platforms/test_weibo.py b/tests/platforms/test_weibo.py index e499660..c82a851 100644 --- a/tests/platforms/test_weibo.py +++ b/tests/platforms/test_weibo.py @@ -1,12 +1,12 @@ -import typing from datetime import datetime +import typing -import respx -import pytest import feedparser -from pytz import timezone +from httpx import AsyncClient, Response from nonebug.app import App -from httpx import Response, AsyncClient +import pytest +from pytz import timezone +import respx from .utils import get_file, get_json @@ -19,7 +19,7 @@ image_cdn_router = respx.route(host__regex=r"wx\d.sinaimg.cn", path__startswith= @pytest.fixture def weibo(app: App): from nonebot_bison.platform import platform_manager - from nonebot_bison.utils import ProcessContext, DefaultClientManager + from nonebot_bison.utils import DefaultClientManager, ProcessContext return platform_manager["weibo"](ProcessContext(DefaultClientManager())) @@ -42,7 +42,7 @@ async def test_get_name(weibo): @respx.mock async def test_fetch_new(weibo, dummy_user_subinfo): from nonebot_bison.post import Post - from nonebot_bison.types import Target, SubUnit + from nonebot_bison.types import SubUnit, Target ak_list_router = respx.get("https://m.weibo.cn/api/container/getIndex?containerid=1076036279793937") detail_router = respx.get("https://m.weibo.cn/statuses/extend?id=4649031014551911") @@ -184,7 +184,7 @@ async def test_rsshub_compare(weibo): test_post = { "mblog": { - "text": ( # noqa + "text": ( '#刚出生的小羊驼长啥样#
小羊驼三三来也[好喜欢]' bytes: @pytest.fixture def mock_platform(app: App): - from nonebot_bison.post import Post - from nonebot_bison.types import Target, RawPost from nonebot_bison.platform.platform import NewMessage + from nonebot_bison.post import Post + from nonebot_bison.types import RawPost, Target class MockPlatform(NewMessage): platform_name = "mock_platform" @@ -47,7 +48,7 @@ def mock_platform(app: App): is_common = True schedule_interval = 10 enable_tag = False - categories = {} + categories: ClassVar[dict] = {} has_target = True sub_index = 0 @@ -84,7 +85,7 @@ def mock_platform(app: App): @pytest.fixture def mock_post(app: App, mock_platform): from nonebot_bison.post import Post - from nonebot_bison.utils import ProcessContext, DefaultClientManager + from nonebot_bison.utils import DefaultClientManager, ProcessContext return Post( m := mock_platform(ProcessContext(DefaultClientManager())), @@ -161,7 +162,7 @@ async def test_theme_no_enable_use_browser(app: App, mock_post, mocker: MockerFi @pytest.mark.asyncio @flaky(max_runs=3, min_passes=1) async def test_arknights_theme(app: App, mock_post): - from nonebot_plugin_saa import Text, Image + from nonebot_plugin_saa import Image, Text from nonebot_bison.theme import theme_manager from nonebot_bison.theme.themes.arknights import ArknightsTheme @@ -178,7 +179,7 @@ async def test_arknights_theme(app: App, mock_post): @pytest.mark.asyncio async def test_basic_theme(app: App, mock_post: "Post", MERGEABLE_PNG_DATA, SIMPLE_PNG_DATA): - from nonebot_plugin_saa import Text, Image + from nonebot_plugin_saa import Image, Text from nonebot_bison.theme import theme_manager from nonebot_bison.theme.themes.basic import BasicTheme @@ -233,7 +234,7 @@ async def test_basic_theme(app: App, mock_post: "Post", MERGEABLE_PNG_DATA, SIMP @pytest.mark.asyncio async def test_brief_theme(app: App, mock_post): - from nonebot_plugin_saa import Text, Image + from nonebot_plugin_saa import Image, Text from nonebot_bison.theme import theme_manager from nonebot_bison.theme.themes.brief import BriefTheme @@ -275,7 +276,7 @@ async def test_brief_theme(app: App, mock_post): @pytest.mark.asyncio @flaky(max_runs=3, min_passes=1) async def test_ceobecanteen_theme(app: App, mock_post: "Post", MERGEABLE_PNG_DATA, SIMPLE_PNG_DATA): - from nonebot_plugin_saa import Text, Image + from nonebot_plugin_saa import Image, Text from nonebot_bison.theme import theme_manager from nonebot_bison.theme.themes.ceobe_canteen import CeobeCanteenTheme @@ -301,7 +302,7 @@ async def test_ceobecanteen_theme(app: App, mock_post: "Post", MERGEABLE_PNG_DAT @pytest.mark.asyncio @flaky(max_runs=3, min_passes=1) async def test_ht2i_theme(app: App, mock_post: "Post", MERGEABLE_PNG_DATA, SIMPLE_PNG_DATA): - from nonebot_plugin_saa import Text, Image + from nonebot_plugin_saa import Image, Text from nonebot_bison.theme import theme_manager from nonebot_bison.theme.themes.ht2i import Ht2iTheme diff --git a/tests/utils.py b/tests/utils.py index 24f459e..21c225a 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -12,9 +12,9 @@ class AppReq(TypedDict, total=False): def fake_group_message_event(**field) -> "GroupMessageEvent": - from pydantic import create_model + from nonebot.adapters.onebot.v11 import GroupMessageEvent, Message from nonebot.adapters.onebot.v11.event import Sender - from nonebot.adapters.onebot.v11 import Message, GroupMessageEvent + from pydantic import create_model _Fake = create_model("_Fake", __base__=GroupMessageEvent) @@ -48,9 +48,9 @@ def fake_group_message_event(**field) -> "GroupMessageEvent": def fake_private_message_event(**field) -> "PrivateMessageEvent": - from pydantic import create_model - from nonebot.adapters.onebot.v11.event import Sender from nonebot.adapters.onebot.v11 import Message, PrivateMessageEvent + from nonebot.adapters.onebot.v11.event import Sender + from pydantic import create_model _Fake = create_model("_Fake", __base__=PrivateMessageEvent) @@ -89,7 +89,6 @@ add_reply_on_id_input_search = ( class BotReply: - @staticmethod def add_reply_on_platform(platform_manager, common_platform): return (