From d69f5eef4a0cd2729bb150ca77b388ebe7bd307f Mon Sep 17 00:00:00 2001 From: Azide Date: Mon, 13 Nov 2023 23:27:37 +0800 Subject: [PATCH] =?UTF-8?q?:sparkles:=20=E9=80=82=E9=85=8D=20DoDo?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 1 + nonebot_plugin_saa/adapters/__init__.py | 1 + nonebot_plugin_saa/adapters/dodo.py | 211 ++++++++++++++++++ nonebot_plugin_saa/registries/__init__.py | 2 + .../registries/platform_send_target.py | 30 +++ nonebot_plugin_saa/utils/const.py | 3 + poetry.lock | 106 ++------- pyproject.toml | 1 + 8 files changed, 270 insertions(+), 85 deletions(-) create mode 100644 nonebot_plugin_saa/adapters/dodo.py diff --git a/.gitignore b/.gitignore index 4f6656e3..f88fc0f4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ # ----- Project ----- +.env* # Created by https://www.toptal.com/developers/gitignore/api/python,node,visualstudiocode,jetbrains,macos,windows,linux # Edit at https://www.toptal.com/developers/gitignore?templates=python,node,visualstudiocode,jetbrains,macos,windows,linux diff --git a/nonebot_plugin_saa/adapters/__init__.py b/nonebot_plugin_saa/adapters/__init__.py index abea08b8..4eb90a4a 100644 --- a/nonebot_plugin_saa/adapters/__init__.py +++ b/nonebot_plugin_saa/adapters/__init__.py @@ -1,4 +1,5 @@ from . import red as red +from . import dodo as dodo from . import feishu as feishu from . import qqguild as qqguild from . import kaiheila as kaiheila diff --git a/nonebot_plugin_saa/adapters/dodo.py b/nonebot_plugin_saa/adapters/dodo.py new file mode 100644 index 00000000..4c09a81a --- /dev/null +++ b/nonebot_plugin_saa/adapters/dodo.py @@ -0,0 +1,211 @@ +from functools import partial +from contextlib import suppress +from typing import Any, Dict, List, Literal, Optional, cast + +from nonebot import logger +from nonebot.adapters import Event +from nonebot.drivers import Request +from nonebot.adapters import Bot as BaseBot + +from ..types import Text, Image, Reply, Mention +from ..auto_select_bot import register_list_targets +from ..utils import SupportedAdapters, SupportedPlatform +from ..abstract_factories import ( + MessageFactory, + MessageSegmentFactory, + register_ms_adapter, + assamble_message_factory, +) +from ..registries import ( + Receipt, + MessageId, + PlatformTarget, + TargetDoDoChannel, + TargetDoDoPrivate, + register_sender, + register_convert_to_arg, + register_target_extractor, + register_message_id_getter, +) + +with suppress(ImportError): + from nonebot.adapters.dodo import Bot as BotDodo + from nonebot.adapters.dodo.models import MessageBody + from nonebot.adapters.dodo.message import Message, MessageSegment + from nonebot.adapters.dodo.event import ( + MessageEvent, + ChannelMessageEvent, + PersonalMessageEvent, + ) + + adapter = SupportedAdapters.dodo + register_dodo = partial(register_ms_adapter, adapter) + + class DodoMessageId(MessageId): + adapter_name: Literal[adapter] = adapter + + message_id: str + reason: Optional[None] = None + + @register_message_id_getter(MessageEvent) + def _get_message_id(event: Event) -> DodoMessageId: + assert isinstance(event, MessageEvent) + return DodoMessageId(message_id=event.message_id) + + @register_dodo(Text) + def _text(text: Text) -> MessageSegment: + return MessageSegment.text(text.data["text"]) + + @register_dodo(Image) + async def _image(image: Image, bot: BaseBot) -> MessageSegment: + if not isinstance(bot, BotDodo): + raise TypeError(f"Unsupported type of bot: {type(bot)}") + + file = image.data["image"] + if isinstance(file, str): + # 要求必须是官方链接,因此需要下载一遍 + logger.debug(f"Downloading image: {file}") + req = Request("GET", file, timeout=10) + resp = await bot.adapter.request(req) + if resp.status_code != 200: + raise RuntimeError( + f"Failed to download image: {resp.status_code}, url: {file}" + ) + file = resp.content + logger.trace(f"Downloaded image: {file}") + logger.debug( + f"Downloaded image type: {type(file)}, size: {len(file or '')}" + ) + if not isinstance(file, bytes): + raise TypeError(f"Unsupported type of file: {type(file)}, need bytes") + + logger.debug("Uploading image...") + upload_result = await bot.set_resouce_picture_upload( + file=file, file_name=image.data["name"] + ".png" # 上传是文件名必须携带有效后缀 + ) + logger.debug(f"Uploaded result: {upload_result}") + return MessageSegment.picture(**upload_result.dict()) + + @register_dodo(Reply) + def _reply(reply: Reply) -> MessageSegment: + assert isinstance(reply.data, DodoMessageId) + return MessageSegment.reference(reply.data.message_id) + + @register_dodo(Mention) + def _mention(mention: Mention) -> MessageSegment: + return MessageSegment.at_user(dodo_id=mention.data["user_id"]) + + @register_target_extractor(ChannelMessageEvent) + def _extract_channel_msg_event(event: Event) -> TargetDoDoChannel: + assert isinstance(event, ChannelMessageEvent) + return TargetDoDoChannel(channel_id=event.channel_id) + + @register_target_extractor(PersonalMessageEvent) + def _extract_personal_msg_event(event: Event) -> TargetDoDoPrivate: + assert isinstance(event, PersonalMessageEvent) + island_source_id = event.island_source_id + if island_source_id is None: + raise ValueError("island_source_id is None") + return TargetDoDoPrivate( + dodo_source_id=event.dodo_source_id, island_source_id=island_source_id + ) + + @register_convert_to_arg(adapter, SupportedPlatform.dodo_channel) + def _gen_channel(target: PlatformTarget) -> Dict[str, Any]: + assert isinstance(target, TargetDoDoChannel) + return { + "channel_id": target.channel_id, + } + + @register_convert_to_arg(adapter, SupportedPlatform.dodo_private) + def _gen_private(target: PlatformTarget) -> Dict[str, Any]: + assert isinstance(target, TargetDoDoPrivate) + return { + "dodo_source_id": target.dodo_source_id, + "island_source_id": target.island_source_id, + } + + class DodoReceipt(Receipt): + adapter_name: Literal[adapter] = adapter + message_id: str + reason: Optional[str] = None + + async def revoke(self): + return await cast(BotDodo, self._get_bot()).set_channel_message_withdraw( + message_id=self.message_id, reason=self.reason + ) + + async def edit(self, mesaage_body: MessageBody): + return await cast(BotDodo, self._get_bot()).set_channel_message_edit( + message_id=self.message_id, message_body=mesaage_body + ) + + async def pin(self, is_cancel: bool = False): + """置顶消息""" + return await cast(BotDodo, self._get_bot()).set_channel_message_top( + message_id=self.message_id, is_cancel=is_cancel + ) + + @property + def raw(self) -> str: + return self.message_id + + @register_sender(adapter) + async def send( + bot, + msg: MessageFactory[MessageSegmentFactory], + target, + event, + at_sender: bool, + reply: bool, + ) -> DodoReceipt: + assert isinstance(bot, BotDodo) + assert isinstance(target, (TargetDoDoChannel, TargetDoDoPrivate)) + + if event: + assert isinstance(event, MessageEvent) + full_msg = assamble_message_factory( + msg, + Mention(event.get_user_id()), + Reply(DodoMessageId(message_id=event.message_id)), + at_sender, + reply, + ) + else: + full_msg = msg + + message_to_send = Message() + for segment_factory in full_msg: + message_segment = await segment_factory.build(bot) + message_to_send += message_segment + + if isinstance(target, TargetDoDoChannel): + if target.dodo_source_id: + resp = await bot.send_to_channel_personal( + message=message_to_send, **target.arg_dict(bot) + ) + else: + resp = await bot.send_to_channel( + message=message_to_send, **target.arg_dict(bot) + ) + else: + logger.debug(f"Sending to personal: {target.arg_dict(bot)}") + resp = await bot.send_to_personal( + message=message_to_send, **target.arg_dict(bot) + ) + + return DodoReceipt(message_id=resp, bot_id=bot.self_id) + + @register_list_targets(adapter) + async def list_targets(bot: BaseBot) -> List[PlatformTarget]: + assert isinstance(bot, BotDodo) + targets = [] + for island in await bot.get_island_list(): + for channel in await bot.get_channel_list( + island_source_id=island.island_source_id + ): + targets.append(TargetDoDoChannel(channel_id=channel.channel_id)) + + # TODO: 私聊 + + return targets diff --git a/nonebot_plugin_saa/registries/__init__.py b/nonebot_plugin_saa/registries/__init__.py index cb35b3b5..9e853e2d 100644 --- a/nonebot_plugin_saa/registries/__init__.py +++ b/nonebot_plugin_saa/registries/__init__.py @@ -12,6 +12,8 @@ from .platform_send_target import register_sender as register_sender from .platform_send_target import TargetOB12Unknow as TargetOB12Unknow from .platform_send_target import QQGuildDMSManager as QQGuildDMSManager +from .platform_send_target import TargetDoDoChannel as TargetDoDoChannel +from .platform_send_target import TargetDoDoPrivate as TargetDoDoPrivate from .platform_send_target import TargetFeishuGroup as TargetFeishuGroup from .platform_send_target import TargetFeishuPrivate as TargetFeishuPrivate from .platform_send_target import TargetQQGuildDirect as TargetQQGuildDirect diff --git a/nonebot_plugin_saa/registries/platform_send_target.py b/nonebot_plugin_saa/registries/platform_send_target.py index 3419e161..8f593b11 100644 --- a/nonebot_plugin_saa/registries/platform_send_target.py +++ b/nonebot_plugin_saa/registries/platform_send_target.py @@ -191,6 +191,36 @@ class TargetFeishuGroup(PlatformTarget): chat_id: str +class TargetDoDoChannel(PlatformTarget): + """DoDo Channel + + 参数 + channel_id: 频道ID + dodo_source_id: 用户 ID(可选) + """ + + platform_type: Literal[ + SupportedPlatform.dodo_channel + ] = SupportedPlatform.dodo_channel + channel_id: str + dodo_source_id: Optional[str] = None + + +class TargetDoDoPrivate(PlatformTarget): + """DoDo Private + + 参数 + dodo_source_id: 用户 ID + island_source_id: 群 ID + """ + + platform_type: Literal[ + SupportedPlatform.dodo_private + ] = SupportedPlatform.dodo_private + island_source_id: str + dodo_source_id: str + + # this union type is for deserialize pydantic model with nested PlatformTarget AllSupportedPlatformTarget = Union[ TargetQQGroup, diff --git a/nonebot_plugin_saa/utils/const.py b/nonebot_plugin_saa/utils/const.py index 629826bc..a04021b7 100644 --- a/nonebot_plugin_saa/utils/const.py +++ b/nonebot_plugin_saa/utils/const.py @@ -9,6 +9,7 @@ class SupportedAdapters(StrEnum): telegram = "Telegram" feishu = "Feishu" red = "RedProtocol" + dodo = "DoDo" fake = "fake" # for nonebug @@ -25,6 +26,8 @@ class SupportedPlatform(StrEnum): telegram_forum = "Telegram Forum" feishu_private = "Feishu Private" feishu_group = "Feishu Group" + dodo_channel = "DoDo Channel" + dodo_private = "DoDo Private" supported_adapter_names = set(SupportedAdapters._member_map_.values()) # noqa: SLF001 diff --git a/poetry.lock b/poetry.lock index abe8bfff..74167515 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,10 +1,9 @@ -# This file is automatically @generated by Poetry and should not be changed by hand. +# This file is automatically @generated by Poetry 1.6.1 and should not be changed by hand. [[package]] name = "anyio" version = "3.7.1" description = "High level compatibility layer for multiple asynchronous event loop implementations" -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -26,7 +25,6 @@ trio = ["trio (<0.22)"] name = "appnope" version = "0.1.3" description = "Disable App Nap on macOS >= 10.9" -category = "dev" optional = false python-versions = "*" files = [ @@ -38,7 +36,6 @@ files = [ name = "asgiref" version = "3.7.2" description = "ASGI specs, helper code, and adapters" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -56,7 +53,6 @@ tests = ["mypy (>=0.800)", "pytest", "pytest-asyncio"] name = "asttokens" version = "2.4.0" description = "Annotate AST trees with source code positions" -category = "dev" optional = false python-versions = "*" files = [ @@ -74,7 +70,6 @@ test = ["astroid", "pytest"] name = "async-asgi-testclient" version = "1.4.11" description = "Async client for testing ASGI web applications" -category = "dev" optional = false python-versions = "*" files = [ @@ -89,7 +84,6 @@ requests = ">=2.21,<3.0" name = "backcall" version = "0.2.0" description = "Specifications for callback functions passed in to an API" -category = "dev" optional = false python-versions = "*" files = [ @@ -101,7 +95,6 @@ files = [ name = "cashews" version = "6.3.0" description = "cache tools with async power" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -120,7 +113,6 @@ tests = ["hypothesis", "pytest", "pytest-asyncio"] name = "certifi" version = "2023.7.22" description = "Python package for providing Mozilla's CA Bundle." -category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -132,7 +124,6 @@ files = [ name = "charset-normalizer" version = "3.3.1" description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." -category = "dev" optional = false python-versions = ">=3.7.0" files = [ @@ -232,7 +223,6 @@ files = [ name = "click" version = "8.1.7" description = "Composable command line interface toolkit" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -247,7 +237,6 @@ colorama = {version = "*", markers = "platform_system == \"Windows\""} name = "colorama" version = "0.4.6" description = "Cross-platform colored terminal text." -category = "main" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" files = [ @@ -259,7 +248,6 @@ files = [ name = "coverage" version = "7.3.2" description = "Code coverage measurement for Python" -category = "dev" optional = false python-versions = ">=3.8" files = [ @@ -327,7 +315,6 @@ toml = ["tomli"] name = "decorator" version = "5.1.1" description = "Decorators for Humans" -category = "dev" optional = false python-versions = ">=3.5" files = [ @@ -339,7 +326,6 @@ files = [ name = "exceptiongroup" version = "1.1.3" description = "Backport of PEP 654 (exception groups)" -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -354,7 +340,6 @@ test = ["pytest (>=6)"] name = "executing" version = "2.0.0" description = "Get the currently executing AST node of a frame, and other information" -category = "dev" optional = false python-versions = "*" files = [ @@ -369,7 +354,6 @@ tests = ["asttokens (>=2.1.0)", "coverage", "coverage-enable-subprocess", "ipyth name = "fastapi" version = "0.104.0" description = "FastAPI framework, high performance, easy to learn, fast to code, ready for production" -category = "dev" optional = false python-versions = ">=3.8" files = [ @@ -390,7 +374,6 @@ all = ["email-validator (>=2.0.0)", "httpx (>=0.23.0)", "itsdangerous (>=1.1.0)" name = "h11" version = "0.14.0" description = "A pure-Python, bring-your-own-I/O implementation of HTTP/1.1" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -402,7 +385,6 @@ files = [ name = "h2" version = "4.1.0" description = "HTTP/2 State-Machine based protocol implementation" -category = "dev" optional = false python-versions = ">=3.6.1" files = [ @@ -418,7 +400,6 @@ hyperframe = ">=6.0,<7" name = "hpack" version = "4.0.0" description = "Pure-Python HPACK header compression" -category = "dev" optional = false python-versions = ">=3.6.1" files = [ @@ -430,7 +411,6 @@ files = [ name = "httpcore" version = "0.18.0" description = "A minimal low-level HTTP client." -category = "dev" optional = false python-versions = ">=3.8" files = [ @@ -442,17 +422,16 @@ files = [ anyio = ">=3.0,<5.0" certifi = "*" h11 = ">=0.13,<0.15" -sniffio = ">=1.0.0,<2.0.0" +sniffio = "==1.*" [package.extras] http2 = ["h2 (>=3,<5)"] -socks = ["socksio (>=1.0.0,<2.0.0)"] +socks = ["socksio (==1.*)"] [[package]] name = "httptools" version = "0.6.1" description = "A collection of framework independent HTTP protocol utils." -category = "dev" optional = false python-versions = ">=3.8.0" files = [ @@ -501,7 +480,6 @@ test = ["Cython (>=0.29.24,<0.30.0)"] name = "httpx" version = "0.25.0" description = "The next generation HTTP client." -category = "dev" optional = false python-versions = ">=3.8" files = [ @@ -518,15 +496,14 @@ sniffio = "*" [package.extras] brotli = ["brotli", "brotlicffi"] -cli = ["click (>=8.0.0,<9.0.0)", "pygments (>=2.0.0,<3.0.0)", "rich (>=10,<14)"] +cli = ["click (==8.*)", "pygments (==2.*)", "rich (>=10,<14)"] http2 = ["h2 (>=3,<5)"] -socks = ["socksio (>=1.0.0,<2.0.0)"] +socks = ["socksio (==1.*)"] [[package]] name = "hyperframe" version = "6.0.1" description = "HTTP/2 framing layer for Python" -category = "dev" optional = false python-versions = ">=3.6.1" files = [ @@ -538,7 +515,6 @@ files = [ name = "idna" version = "3.4" description = "Internationalized Domain Names in Applications (IDNA)" -category = "main" optional = false python-versions = ">=3.5" files = [ @@ -550,7 +526,6 @@ files = [ name = "iniconfig" version = "2.0.0" description = "brain-dead simple config-ini parsing" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -562,7 +537,6 @@ files = [ name = "ipdb" version = "0.13.13" description = "IPython-enabled pdb" -category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" files = [ @@ -579,7 +553,6 @@ tomli = {version = "*", markers = "python_version > \"3.6\" and python_version < name = "ipython" version = "8.12.3" description = "IPython: Productive Interactive Computing" -category = "dev" optional = false python-versions = ">=3.8" files = [ @@ -619,7 +592,6 @@ test-extra = ["curio", "matplotlib (!=3.2.0)", "nbformat", "numpy (>=1.21)", "pa name = "jedi" version = "0.19.1" description = "An autocompletion tool for Python that can be used for text editors." -category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -639,7 +611,6 @@ testing = ["Django", "attrs", "colorama", "docopt", "pytest (<7.0.0)"] name = "loguru" version = "0.7.2" description = "Python logging made (stupidly) simple" -category = "main" optional = false python-versions = ">=3.5" files = [ @@ -658,7 +629,6 @@ dev = ["Sphinx (==7.2.5)", "colorama (==0.4.5)", "colorama (==0.4.6)", "exceptio name = "matplotlib-inline" version = "0.1.6" description = "Inline Matplotlib backend for Jupyter" -category = "dev" optional = false python-versions = ">=3.5" files = [ @@ -673,7 +643,6 @@ traitlets = "*" name = "msgpack" version = "1.0.7" description = "MessagePack serializer" -category = "dev" optional = false python-versions = ">=3.8" files = [ @@ -739,7 +708,6 @@ files = [ name = "multidict" version = "6.0.4" description = "multidict implementation" -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -819,11 +787,24 @@ files = [ {file = "multidict-6.0.4.tar.gz", hash = "sha256:3666906492efb76453c0e7b97f2cf459b0682e7402c0489a95484965dbc1da49"}, ] +[[package]] +name = "nonebot-adapter-dodo" +version = "0.1.2" +description = "Dodo adapter for nonebot2" +optional = false +python-versions = ">=3.8,<4.0" +files = [ + {file = "nonebot_adapter_dodo-0.1.2-py3-none-any.whl", hash = "sha256:9440527d362f02c7ab4963f2d70fc7505c464fc941d8c49ceee71e5e090605a8"}, + {file = "nonebot_adapter_dodo-0.1.2.tar.gz", hash = "sha256:ccc9583cd0c54582d13f2ebbd7ee7587fa9c87c8f2c693c64d08034a5f69de95"}, +] + +[package.dependencies] +nonebot2 = ">=2.0.0,<3.0.0" + [[package]] name = "nonebot-adapter-feishu" version = "2.2.1" description = "feishu(larksuite) adapter for nonebot2" -category = "dev" optional = false python-versions = ">=3.8,<4.0" files = [ @@ -841,7 +822,6 @@ pycryptodome = ">=3.18.0,<4.0.0" name = "nonebot-adapter-kaiheila" version = "0.2.12" description = "kaiheila adapter for nonebot2" -category = "dev" optional = false python-versions = ">=3.8,<4.0" files = [ @@ -856,7 +836,6 @@ nonebot2 = ">=2.0.0,<3.0.0" name = "nonebot-adapter-onebot" version = "2.3.1" description = "OneBot(CQHTTP) adapter for nonebot2" -category = "dev" optional = false python-versions = ">=3.8,<4.0" files = [ @@ -873,7 +852,6 @@ typing-extensions = ">=4.0.0,<5.0.0" name = "nonebot-adapter-qqguild" version = "0.4.0" description = "QQ Guild adapter for nonebot2" -category = "dev" optional = false python-versions = ">=3.8,<4.0" files = [ @@ -890,7 +868,6 @@ typing-extensions = ">=4.4.0,<5.0.0" name = "nonebot-adapter-red" version = "0.6.1" description = "Red Protocol Adapter for Nonebot2" -category = "dev" optional = false python-versions = ">=3.8" files = [ @@ -909,7 +886,6 @@ auto-detect = ["PyYAML"] name = "nonebot-adapter-telegram" version = "0.1.0b14" description = "Telegram Adapter for NoneBot2" -category = "dev" optional = false python-versions = ">=3.8,<4.0" files = [ @@ -925,7 +901,6 @@ nonebot2 = ">=2.0.0b1,<3.0.0" name = "nonebot2" version = "2.1.1" description = "An asynchronous python bot framework." -category = "main" optional = false python-versions = ">=3.8,<4.0" files = [ @@ -957,7 +932,6 @@ websockets = ["websockets (>=10.0)"] name = "nonebug" version = "0.3.5" description = "nonebot2 test framework" -category = "dev" optional = false python-versions = ">=3.8,<4.0" files = [ @@ -976,7 +950,6 @@ typing-extensions = ">=4.0.0,<5.0.0" name = "packaging" version = "23.2" description = "Core utilities for Python packages" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -988,7 +961,6 @@ files = [ name = "parso" version = "0.8.3" description = "A Python Parser" -category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -1004,7 +976,6 @@ testing = ["docopt", "pytest (<6.0.0)"] name = "pexpect" version = "4.8.0" description = "Pexpect allows easy control of interactive console applications." -category = "dev" optional = false python-versions = "*" files = [ @@ -1019,7 +990,6 @@ ptyprocess = ">=0.5" name = "pickleshare" version = "0.7.5" description = "Tiny 'shelve'-like database with concurrency support" -category = "dev" optional = false python-versions = "*" files = [ @@ -1031,7 +1001,6 @@ files = [ name = "pip" version = "23.3.1" description = "The PyPA recommended tool for installing Python packages." -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1043,7 +1012,6 @@ files = [ name = "pluggy" version = "1.3.0" description = "plugin and hook calling mechanisms for python" -category = "dev" optional = false python-versions = ">=3.8" files = [ @@ -1059,7 +1027,6 @@ testing = ["pytest", "pytest-benchmark"] name = "prompt-toolkit" version = "3.0.39" description = "Library for building powerful interactive command lines in Python" -category = "dev" optional = false python-versions = ">=3.7.0" files = [ @@ -1074,7 +1041,6 @@ wcwidth = "*" name = "ptyprocess" version = "0.7.0" description = "Run a subprocess in a pseudo terminal" -category = "dev" optional = false python-versions = "*" files = [ @@ -1086,7 +1052,6 @@ files = [ name = "pure-eval" version = "0.2.2" description = "Safely evaluate AST nodes without side effects" -category = "dev" optional = false python-versions = "*" files = [ @@ -1101,7 +1066,6 @@ tests = ["pytest"] name = "pycryptodome" version = "3.19.0" description = "Cryptographic library for Python" -category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" files = [ @@ -1143,7 +1107,6 @@ files = [ name = "pydantic" version = "1.10.13" description = "Data validation and settings management using python type hints" -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -1197,7 +1160,6 @@ email = ["email-validator (>=1.0.3)"] name = "pygments" version = "2.16.1" description = "Pygments is a syntax highlighting package written in Python." -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1212,7 +1174,6 @@ plugins = ["importlib-metadata"] name = "pygtrie" version = "2.5.0" description = "A pure Python trie data structure implementation." -category = "main" optional = false python-versions = "*" files = [ @@ -1224,7 +1185,6 @@ files = [ name = "pytest" version = "7.4.3" description = "pytest: simple powerful testing with Python" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1247,7 +1207,6 @@ testing = ["argcomplete", "attrs (>=19.2.0)", "hypothesis (>=3.56)", "mock", "no name = "pytest-asyncio" version = "0.20.3" description = "Pytest support for asyncio" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1266,7 +1225,6 @@ testing = ["coverage (>=6.2)", "flaky (>=3.5.0)", "hypothesis (>=5.7.1)", "mypy name = "pytest-cov" version = "4.1.0" description = "Pytest plugin for measuring coverage." -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1285,7 +1243,6 @@ testing = ["fields", "hunter", "process-tests", "pytest-xdist", "six", "virtuale name = "pytest-mock" version = "3.12.0" description = "Thin-wrapper around the mock package for easier use with pytest" -category = "dev" optional = false python-versions = ">=3.8" files = [ @@ -1303,7 +1260,6 @@ dev = ["pre-commit", "pytest-asyncio", "tox"] name = "python-dotenv" version = "1.0.0" description = "Read key-value pairs from a .env file and set them as environment variables" -category = "main" optional = false python-versions = ">=3.8" files = [ @@ -1318,7 +1274,6 @@ cli = ["click (>=5.0)"] name = "pyyaml" version = "6.0.1" description = "YAML parser and emitter for Python" -category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -1368,7 +1323,6 @@ files = [ name = "requests" version = "2.31.0" description = "Python HTTP for Humans." -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1390,7 +1344,6 @@ use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] name = "respx" version = "0.20.2" description = "A utility for mocking out the Python HTTPX and HTTP Core libraries." -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1405,7 +1358,6 @@ httpx = ">=0.21.0" name = "ruff" version = "0.0.253" description = "An extremely fast Python linter, written in Rust." -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1432,7 +1384,6 @@ files = [ name = "six" version = "1.16.0" description = "Python 2 and 3 compatibility utilities" -category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" files = [ @@ -1444,7 +1395,6 @@ files = [ name = "sniffio" version = "1.3.0" description = "Sniff out which async library your code is running under" -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -1456,7 +1406,6 @@ files = [ name = "stack-data" version = "0.6.3" description = "Extract data from python stack frames and tracebacks for informative displays" -category = "dev" optional = false python-versions = "*" files = [ @@ -1476,7 +1425,6 @@ tests = ["cython", "littleutils", "pygments", "pytest", "typeguard"] name = "starlette" version = "0.27.0" description = "The little ASGI library that shines." -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1495,7 +1443,6 @@ full = ["httpx (>=0.22.0)", "itsdangerous", "jinja2", "python-multipart", "pyyam name = "strenum" version = "0.4.15" description = "An Enum that inherits from str." -category = "main" optional = false python-versions = "*" files = [ @@ -1512,7 +1459,6 @@ test = ["pylint", "pytest", "pytest-black", "pytest-cov", "pytest-pylint"] name = "tomli" version = "2.0.1" description = "A lil' TOML parser" -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -1524,7 +1470,6 @@ files = [ name = "traitlets" version = "5.12.0" description = "Traitlets Python configuration system" -category = "dev" optional = false python-versions = ">=3.8" files = [ @@ -1540,7 +1485,6 @@ test = ["argcomplete (>=3.0.3)", "mypy (>=1.6.0)", "pre-commit", "pytest (>=7.0, name = "typing-extensions" version = "4.8.0" description = "Backported and Experimental Type Hints for Python 3.8+" -category = "main" optional = false python-versions = ">=3.8" files = [ @@ -1552,7 +1496,6 @@ files = [ name = "urllib3" version = "2.0.7" description = "HTTP library with thread-safe connection pooling, file post, and more." -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1570,7 +1513,6 @@ zstd = ["zstandard (>=0.18.0)"] name = "uvicorn" version = "0.23.2" description = "The lightning-fast ASGI server." -category = "dev" optional = false python-versions = ">=3.8" files = [ @@ -1586,7 +1528,7 @@ httptools = {version = ">=0.5.0", optional = true, markers = "extra == \"standar python-dotenv = {version = ">=0.13", optional = true, markers = "extra == \"standard\""} pyyaml = {version = ">=5.1", optional = true, markers = "extra == \"standard\""} typing-extensions = {version = ">=4.0", markers = "python_version < \"3.11\""} -uvloop = {version = ">=0.14.0,<0.15.0 || >0.15.0,<0.15.1 || >0.15.1", optional = true, markers = "sys_platform != \"win32\" and sys_platform != \"cygwin\" and platform_python_implementation != \"PyPy\" and extra == \"standard\""} +uvloop = {version = ">=0.14.0,<0.15.0 || >0.15.0,<0.15.1 || >0.15.1", optional = true, markers = "(sys_platform != \"win32\" and sys_platform != \"cygwin\") and platform_python_implementation != \"PyPy\" and extra == \"standard\""} watchfiles = {version = ">=0.13", optional = true, markers = "extra == \"standard\""} websockets = {version = ">=10.4", optional = true, markers = "extra == \"standard\""} @@ -1597,7 +1539,6 @@ standard = ["colorama (>=0.4)", "httptools (>=0.5.0)", "python-dotenv (>=0.13)", name = "uvloop" version = "0.19.0" description = "Fast implementation of asyncio event loop on top of libuv" -category = "dev" optional = false python-versions = ">=3.8.0" files = [ @@ -1642,7 +1583,6 @@ test = ["Cython (>=0.29.36,<0.30.0)", "aiohttp (==3.9.0b0)", "aiohttp (>=3.8.1)" name = "watchfiles" version = "0.21.0" description = "Simple, modern and high performance file watching and code reload in python." -category = "dev" optional = false python-versions = ">=3.8" files = [ @@ -1730,7 +1670,6 @@ anyio = ">=3.0.0" name = "wcwidth" version = "0.2.8" description = "Measures the displayed width of unicode strings in a terminal" -category = "dev" optional = false python-versions = "*" files = [ @@ -1742,7 +1681,6 @@ files = [ name = "websockets" version = "12.0" description = "An implementation of the WebSocket Protocol (RFC 6455 & 7692)" -category = "dev" optional = false python-versions = ">=3.8" files = [ @@ -1824,7 +1762,6 @@ files = [ name = "win32-setctime" version = "1.1.0" description = "A small Python utility to set file creation time on Windows" -category = "main" optional = false python-versions = ">=3.5" files = [ @@ -1839,7 +1776,6 @@ dev = ["black (>=19.3b0)", "pytest (>=4.6.2)"] name = "yarl" version = "1.9.2" description = "Yet another URL library" -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -1926,4 +1862,4 @@ multidict = ">=4.0" [metadata] lock-version = "2.0" python-versions = "^3.8" -content-hash = "f2aa48fbcae2b9dc6be41ccf70e28eb1761093e3d184bd4209582817e483fb84" +content-hash = "e422e58ae5a77208f0e0425f2a9e79e96bfa04af48db0bbe3a5c721920e95141" diff --git a/pyproject.toml b/pyproject.toml index f68b31f4..bf66d1fc 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -50,6 +50,7 @@ nonebot-adapter-kaiheila = "^0.2.12" nonebot-adapter-telegram = "^0.1.0b12" nonebot-adapter-feishu = "^2.1.1" nonebot-adapter-red = ">=0.4.1" +nonebot-adapter-dodo = "^0.1.2" [tool.black] line-length = 88