mirror of
				https://github.com/nonebot/nonebot2.git
				synced 2025-10-31 15:06:42 +00:00 
			
		
		
		
	⬆️ update dependencies
This commit is contained in:
		| @@ -12,6 +12,12 @@ NoneBot.adapters 模块 | ||||
|    :special-members: __init__ | ||||
|    :show-inheritance: | ||||
|  | ||||
| .. automodule:: nonebot.adapters._adapter | ||||
|    :members: | ||||
|    :private-members: | ||||
|    :special-members: __init__ | ||||
|    :show-inheritance: | ||||
|  | ||||
| .. automodule:: nonebot.adapters._bot | ||||
|    :members: | ||||
|    :private-members: | ||||
|   | ||||
| @@ -1,45 +0,0 @@ | ||||
|  | ||||
|  | ||||
| NoneBot.adapters.ding 模块 | ||||
| =========================== | ||||
|  | ||||
| .. automodule:: nonebot.adapters.ding | ||||
|  | ||||
| NoneBot.adapters.ding.config 模块 | ||||
| =================================== | ||||
|  | ||||
| .. automodule:: nonebot.adapters.ding.config | ||||
|    :members: | ||||
|  | ||||
| NoneBot.adapters.ding.exception 模块 | ||||
| ===================================== | ||||
|  | ||||
| .. automodule:: nonebot.adapters.ding.exception | ||||
|    :members: | ||||
|    :show-inheritance: | ||||
|  | ||||
|  | ||||
| NoneBot.adapters.ding.bot 模块 | ||||
| =============================== | ||||
|  | ||||
| .. automodule:: nonebot.adapters.ding.bot | ||||
|    :members: | ||||
|    :private-members: | ||||
|    :show-inheritance: | ||||
|  | ||||
|  | ||||
| NoneBot.adapters.ding.message 模块 | ||||
| =================================== | ||||
|  | ||||
| .. automodule:: nonebot.adapters.ding.message | ||||
|    :members: | ||||
|    :private-members: | ||||
|    :show-inheritance: | ||||
|  | ||||
|  | ||||
| NoneBot.adapters.ding.event 模块 | ||||
| ================================= | ||||
|  | ||||
| .. automodule:: nonebot.adapters.ding.event | ||||
|    :members: | ||||
|    :show-inheritance: | ||||
| @@ -1,45 +0,0 @@ | ||||
|  | ||||
|  | ||||
| NoneBot.adapters.feishu 模块 | ||||
| ============================ | ||||
|  | ||||
| .. automodule:: nonebot.adapters.feishu | ||||
|  | ||||
| NoneBot.adapters.feishu.config 模块 | ||||
| =================================== | ||||
|  | ||||
| .. automodule:: nonebot.adapters.feishu.config | ||||
|    :members: | ||||
|  | ||||
| NoneBot.adapters.feishu.exception 模块 | ||||
| ====================================== | ||||
|  | ||||
| .. automodule:: nonebot.adapters.feishu.exception | ||||
|    :members: | ||||
|    :show-inheritance: | ||||
|  | ||||
|  | ||||
| NoneBot.adapters.feishu.bot 模块 | ||||
| ================================ | ||||
|  | ||||
| .. automodule:: nonebot.adapters.feishu.bot | ||||
|    :members: | ||||
|    :private-members: | ||||
|    :show-inheritance: | ||||
|  | ||||
|  | ||||
| NoneBot.adapters.feishu.message 模块 | ||||
| ==================================== | ||||
|  | ||||
| .. automodule:: nonebot.adapters.feishu.message | ||||
|    :members: | ||||
|    :private-members: | ||||
|    :show-inheritance: | ||||
|  | ||||
|  | ||||
| NoneBot.adapters.feishu.event 模块 | ||||
| ================================== | ||||
|  | ||||
| .. automodule:: nonebot.adapters.feishu.event | ||||
|    :members: | ||||
|    :show-inheritance: | ||||
| @@ -1,75 +0,0 @@ | ||||
|  | ||||
|  | ||||
| NoneBot.adapters.mirai 模块 | ||||
| =========================== | ||||
|  | ||||
| .. automodule:: nonebot.adapters.mirai | ||||
|  | ||||
| NoneBot.adapters.mirai.config 模块 | ||||
| ================================== | ||||
|  | ||||
| .. automodule:: nonebot.adapters.mirai.config | ||||
|    :members: | ||||
|  | ||||
| NoneBot.adapters.mirai.bot 模块 | ||||
| =============================== | ||||
|  | ||||
| .. automodule:: nonebot.adapters.mirai.bot | ||||
|    :members: | ||||
|    :show-inheritance: | ||||
|  | ||||
| NoneBot.adapters.mirai.message 模块 | ||||
| =================================== | ||||
|  | ||||
| .. automodule:: nonebot.adapters.mirai.message | ||||
|    :members: | ||||
|    :show-inheritance: | ||||
|  | ||||
| NoneBot.adapters.mirai.utils 模块 | ||||
| =================================== | ||||
|  | ||||
| .. automodule:: nonebot.adapters.mirai.utils | ||||
|    :members: | ||||
|    :show-inheritance: | ||||
|  | ||||
| NoneBot.adapters.mirai.event 模块 | ||||
| ================================= | ||||
|  | ||||
| .. automodule:: nonebot.adapters.mirai.event | ||||
|    :members: | ||||
|    :show-inheritance: | ||||
|  | ||||
| NoneBot.adapters.mirai.event.base 模块 | ||||
| ====================================== | ||||
|  | ||||
| .. automodule:: nonebot.adapters.mirai.event.base | ||||
|    :members: | ||||
|    :show-inheritance: | ||||
|  | ||||
| NoneBot.adapters.mirai.event.meta 模块 | ||||
| ====================================== | ||||
|  | ||||
| .. automodule:: nonebot.adapters.mirai.event.meta | ||||
|    :members: | ||||
|    :show-inheritance: | ||||
|  | ||||
| NoneBot.adapters.mirai.event.message 模块 | ||||
| ========================================= | ||||
|  | ||||
| .. automodule:: nonebot.adapters.mirai.event.message | ||||
|    :members: | ||||
|    :show-inheritance: | ||||
|  | ||||
| NoneBot.adapters.mirai.event.notice 模块 | ||||
| ========================================= | ||||
|  | ||||
| .. automodule:: nonebot.adapters.mirai.event.notice | ||||
|    :members: | ||||
|    :show-inheritance: | ||||
|  | ||||
| NoneBot.adapters.mirai.event.request 模块 | ||||
| ========================================= | ||||
|  | ||||
| .. automodule:: nonebot.adapters.mirai.event.request | ||||
|    :members: | ||||
|    :show-inheritance: | ||||
| @@ -1,11 +0,0 @@ | ||||
| <p align="center"> | ||||
|   <a href="https://v2.nonebot.dev/"><img src="https://raw.githubusercontent.com/nonebot/nonebot2/master/docs/.vuepress/public/logo.png" width="200" height="200" alt="nonebot"></a> | ||||
| </p> | ||||
|  | ||||
| <div align="center"> | ||||
|  | ||||
| # NoneBot-Adapter-DING | ||||
|  | ||||
| _✨ 钉钉协议适配 ✨_ | ||||
|  | ||||
| </div> | ||||
| @@ -1,23 +0,0 @@ | ||||
| """ | ||||
| 钉钉群机器人 协议适配 | ||||
| ============================ | ||||
|  | ||||
| 协议详情请看: `钉钉文档`_ | ||||
|  | ||||
| .. _钉钉文档: | ||||
|     https://ding-doc.dingtalk.com/document#/org-dev-guide/elzz1p | ||||
| """ | ||||
|  | ||||
| from .bot import Bot as Bot | ||||
| from .utils import log as log | ||||
| from .event import Event as Event | ||||
| from .message import Message as Message | ||||
| from .event import MessageEvent as MessageEvent | ||||
| from .exception import ActionFailed as ActionFailed | ||||
| from .exception import NetworkError as NetworkError | ||||
| from .message import MessageSegment as MessageSegment | ||||
| from .exception import SessionExpired as SessionExpired | ||||
| from .event import GroupMessageEvent as GroupMessageEvent | ||||
| from .exception import ApiNotAvailable as ApiNotAvailable | ||||
| from .event import PrivateMessageEvent as PrivateMessageEvent | ||||
| from .exception import DingAdapterException as DingAdapterException | ||||
| @@ -1,271 +0,0 @@ | ||||
| import json | ||||
| import time | ||||
| import urllib.parse | ||||
| from datetime import datetime | ||||
| from typing import TYPE_CHECKING, Any, Tuple, Union, Optional | ||||
|  | ||||
| import httpx | ||||
|  | ||||
| from nonebot.log import logger | ||||
| from nonebot.typing import overrides | ||||
| from nonebot.utils import escape_tag | ||||
| from nonebot.message import handle_event | ||||
| from nonebot.adapters import Bot as BaseBot | ||||
| from nonebot.drivers import Driver, HTTPRequest, HTTPResponse, HTTPConnection | ||||
|  | ||||
| from .config import Config as DingConfig | ||||
| from .utils import log, calc_hmac_base64 | ||||
| from .message import Message, MessageSegment | ||||
| from .exception import ( | ||||
|     ActionFailed, | ||||
|     NetworkError, | ||||
|     SessionExpired, | ||||
|     ApiNotAvailable, | ||||
| ) | ||||
| from .event import ( | ||||
|     MessageEvent, | ||||
|     ConversationType, | ||||
|     GroupMessageEvent, | ||||
|     PrivateMessageEvent, | ||||
| ) | ||||
|  | ||||
| if TYPE_CHECKING: | ||||
|     from nonebot.config import Config | ||||
|  | ||||
| SEND = "send" | ||||
|  | ||||
|  | ||||
| class Bot(BaseBot): | ||||
|     """ | ||||
|     钉钉 协议 Bot 适配。继承属性参考 `BaseBot <README.md#class-bot>`_ 。 | ||||
|     """ | ||||
|  | ||||
|     ding_config: DingConfig | ||||
|  | ||||
|     @property | ||||
|     def type(self) -> str: | ||||
|         """ | ||||
|         - 返回: ``"ding"`` | ||||
|         """ | ||||
|         return "ding" | ||||
|  | ||||
|     @classmethod | ||||
|     def register(cls, driver: Driver, config: "Config"): | ||||
|         super().register(driver, config) | ||||
|         cls.ding_config = DingConfig(**config.dict()) | ||||
|  | ||||
|     @classmethod | ||||
|     @overrides(BaseBot) | ||||
|     async def check_permission( | ||||
|         cls, driver: Driver, request: HTTPConnection | ||||
|     ) -> Tuple[Optional[str], HTTPResponse]: | ||||
|         """ | ||||
|         :说明: | ||||
|  | ||||
|           钉钉协议鉴权。参考 `鉴权 <https://ding-doc.dingtalk.com/doc#/serverapi2/elzz1p>`_ | ||||
|         """ | ||||
|         timestamp = request.headers.get("timestamp") | ||||
|         sign = request.headers.get("sign") | ||||
|  | ||||
|         # 检查连接方式 | ||||
|         if not isinstance(request, HTTPRequest): | ||||
|             return None, HTTPResponse( | ||||
|                 405, b"Unsupported connection type, available type: `http`" | ||||
|             ) | ||||
|  | ||||
|         # 检查 timestamp | ||||
|         if not timestamp: | ||||
|             return None, HTTPResponse(400, b"Missing `timestamp` Header") | ||||
|  | ||||
|         # 检查 sign | ||||
|         secret = cls.ding_config.secret | ||||
|         if secret: | ||||
|             if not sign: | ||||
|                 log("WARNING", "Missing Signature Header") | ||||
|                 return None, HTTPResponse(400, b"Missing `sign` Header") | ||||
|             sign_base64 = calc_hmac_base64(str(timestamp), secret) | ||||
|             if sign != sign_base64.decode("utf-8"): | ||||
|                 log("WARNING", "Signature Header is invalid") | ||||
|                 return None, HTTPResponse(403, b"Signature is invalid") | ||||
|         else: | ||||
|             log("WARNING", "Ding signature check ignored!") | ||||
|         return ( | ||||
|             json.loads(request.body.decode())["chatbotUserId"], | ||||
|             HTTPResponse(204, b""), | ||||
|         ) | ||||
|  | ||||
|     @overrides(BaseBot) | ||||
|     async def handle_message(self, message: bytes): | ||||
|         data: dict = json.loads(message) | ||||
|  | ||||
|         if not data: | ||||
|             return | ||||
|  | ||||
|         # 判断消息类型,生成不同的 Event | ||||
|         try: | ||||
|             conversation_type = data["conversationType"] | ||||
|             if conversation_type == ConversationType.private: | ||||
|                 event = PrivateMessageEvent.parse_obj(data) | ||||
|             elif conversation_type == ConversationType.group: | ||||
|                 event = GroupMessageEvent.parse_obj(data) | ||||
|             else: | ||||
|                 raise ValueError("Unsupported conversation type") | ||||
|         except Exception as e: | ||||
|             log("ERROR", "Event Parser Error", e) | ||||
|             return | ||||
|  | ||||
|         try: | ||||
|             await handle_event(self, event) | ||||
|         except Exception as e: | ||||
|             logger.opt(colors=True, exception=e).error( | ||||
|                 f"<r><bg #f8bbd0>Failed to handle event. Raw: {escape_tag(str(data))}</bg #f8bbd0></r>" | ||||
|             ) | ||||
|         return | ||||
|  | ||||
|     @overrides(BaseBot) | ||||
|     async def _call_api( | ||||
|         self, api: str, event: Optional[MessageEvent] = None, **data | ||||
|     ) -> Any: | ||||
|         if not isinstance(self.request, HTTPRequest): | ||||
|             log("ERROR", "Only support http connection.") | ||||
|             return | ||||
|  | ||||
|         log("DEBUG", f"Calling API <y>{api}</y>") | ||||
|         params = {} | ||||
|         # 传入参数有 webhook,则使用传入的 webhook | ||||
|         webhook = data.get("webhook") | ||||
|  | ||||
|         if webhook: | ||||
|             secret = data.get("secret") | ||||
|             if secret: | ||||
|                 # 有这个参数的时候再计算加签的值 | ||||
|                 timestamp = str(round(time.time() * 1000)) | ||||
|                 params["timestamp"] = timestamp | ||||
|                 hmac_code_base64 = calc_hmac_base64(timestamp, secret) | ||||
|                 sign = urllib.parse.quote_plus(hmac_code_base64) | ||||
|                 params["sign"] = sign | ||||
|         else: | ||||
|             # webhook 不存在则使用 event 中的 sessionWebhook | ||||
|             if event: | ||||
|                 # 确保 sessionWebhook 没有过期 | ||||
|                 if int(datetime.now().timestamp()) > int( | ||||
|                     event.sessionWebhookExpiredTime / 1000 | ||||
|                 ): | ||||
|                     raise SessionExpired | ||||
|  | ||||
|                 webhook = event.sessionWebhook | ||||
|             else: | ||||
|                 raise ApiNotAvailable | ||||
|  | ||||
|         headers = {} | ||||
|         message: Message = data.get("message", None) | ||||
|         if not message: | ||||
|             raise ValueError("Message not found") | ||||
|         try: | ||||
|             async with httpx.AsyncClient( | ||||
|                 headers=headers, follow_redirects=True | ||||
|             ) as client: | ||||
|                 response = await client.post( | ||||
|                     webhook, | ||||
|                     params=params, | ||||
|                     json=message._produce(), | ||||
|                     timeout=self.config.api_timeout, | ||||
|                 ) | ||||
|  | ||||
|             if 200 <= response.status_code < 300: | ||||
|                 result = response.json() | ||||
|                 if isinstance(result, dict): | ||||
|                     if result.get("errcode") != 0: | ||||
|                         raise ActionFailed( | ||||
|                             errcode=result.get("errcode"), errmsg=result.get("errmsg") | ||||
|                         ) | ||||
|                     return result | ||||
|             raise NetworkError( | ||||
|                 f"HTTP request received unexpected " | ||||
|                 f"status code: {response.status_code}" | ||||
|             ) | ||||
|         except httpx.InvalidURL: | ||||
|             raise NetworkError("API root url invalid") | ||||
|         except httpx.HTTPError: | ||||
|             raise NetworkError("HTTP request failed") | ||||
|  | ||||
|     @overrides(BaseBot) | ||||
|     async def call_api( | ||||
|         self, api: str, event: Optional[MessageEvent] = None, **data | ||||
|     ) -> Any: | ||||
|         """ | ||||
|         :说明: | ||||
|  | ||||
|           调用 钉钉 协议 API | ||||
|  | ||||
|         :参数: | ||||
|  | ||||
|           * ``api: str``: API 名称 | ||||
|           * ``event: Optional[MessageEvent]``: Event 对象 | ||||
|           * ``**data: Any``: API 参数 | ||||
|  | ||||
|         :返回: | ||||
|  | ||||
|           - ``Any``: API 调用返回数据 | ||||
|  | ||||
|         :异常: | ||||
|  | ||||
|           - ``NetworkError``: 网络错误 | ||||
|           - ``ActionFailed``: API 调用失败 | ||||
|         """ | ||||
|         return await super().call_api(api, event=event, **data) | ||||
|  | ||||
|     @overrides(BaseBot) | ||||
|     async def send( | ||||
|         self, | ||||
|         event: MessageEvent, | ||||
|         message: Union[str, "Message", "MessageSegment"], | ||||
|         at_sender: bool = False, | ||||
|         webhook: Optional[str] = None, | ||||
|         secret: Optional[str] = None, | ||||
|         **kwargs, | ||||
|     ) -> Any: | ||||
|         """ | ||||
|         :说明: | ||||
|  | ||||
|           根据 ``event``  向触发事件的主体发送消息。 | ||||
|  | ||||
|         :参数: | ||||
|  | ||||
|           * ``event: Event``: Event 对象 | ||||
|           * ``message: Union[str, Message, MessageSegment]``: 要发送的消息 | ||||
|           * ``at_sender: bool``: 是否 @ 事件主体 | ||||
|           * ``webhook: Optional[str]``: 该条消息将调用的 webhook 地址。不传则将使用 sessionWebhook,若其也不存在,该条消息不发送,使用自定义 webhook 时注意你设置的安全方式,如加关键词,IP地址,加签等等。 | ||||
|           * ``secret: Optional[str]``: 如果你使用自定义的 webhook 地址,推荐使用加签方式对消息进行验证,将 `机器人安全设置页面,加签一栏下面显示的SEC开头的字符串` 传入这个参数即可。 | ||||
|           * ``**kwargs``: 覆盖默认参数 | ||||
|  | ||||
|         :返回: | ||||
|  | ||||
|           - ``Any``: API 调用返回数据 | ||||
|  | ||||
|         :异常: | ||||
|  | ||||
|           - ``ValueError``: 缺少 ``user_id``, ``group_id`` | ||||
|           - ``NetworkError``: 网络错误 | ||||
|           - ``ActionFailed``: API 调用失败 | ||||
|         """ | ||||
|         msg = message if isinstance(message, Message) else Message(message) | ||||
|  | ||||
|         at_sender = at_sender and bool(event.senderId) | ||||
|         params = {} | ||||
|         params["event"] = event | ||||
|         if webhook: | ||||
|             params["webhook"] = webhook | ||||
|             params["secret"] = secret | ||||
|         params.update(kwargs) | ||||
|  | ||||
|         if at_sender and event.conversationType != ConversationType.private: | ||||
|             params["message"] = ( | ||||
|                 f"@{event.senderId} " | ||||
|                 + msg | ||||
|                 + MessageSegment.atDingtalkIds(event.senderId) | ||||
|             ) | ||||
|         else: | ||||
|             params["message"] = msg | ||||
|  | ||||
|         return await self.call_api(SEND, **params) | ||||
| @@ -1,21 +0,0 @@ | ||||
| from typing import Optional | ||||
|  | ||||
| from pydantic import Field, BaseModel | ||||
|  | ||||
|  | ||||
| class Config(BaseModel): | ||||
|     """ | ||||
|     钉钉配置类 | ||||
|  | ||||
|     :配置项: | ||||
|  | ||||
|       - ``access_token`` / ``ding_access_token``: 钉钉令牌 | ||||
|       - ``secret`` / ``ding_secret``: 钉钉 HTTP 上报数据签名口令 | ||||
|     """ | ||||
|  | ||||
|     secret: Optional[str] = Field(default=None, alias="ding_secret") | ||||
|     access_token: Optional[str] = Field(default=None, alias="ding_access_token") | ||||
|  | ||||
|     class Config: | ||||
|         extra = "ignore" | ||||
|         allow_population_by_field_name = True | ||||
| @@ -1,151 +0,0 @@ | ||||
| from enum import Enum | ||||
| from typing import List, Optional | ||||
| from typing_extensions import Literal | ||||
|  | ||||
| from pydantic import BaseModel, root_validator | ||||
|  | ||||
| from nonebot.typing import overrides | ||||
| from nonebot.adapters import Event as BaseEvent | ||||
|  | ||||
| from .message import Message | ||||
|  | ||||
|  | ||||
| class Event(BaseEvent): | ||||
|     """ | ||||
|     钉钉协议事件。各事件字段参考 `钉钉文档`_ | ||||
|  | ||||
|     .. _钉钉文档: | ||||
|         https://ding-doc.dingtalk.com/document#/org-dev-guide/elzz1p | ||||
|     """ | ||||
|  | ||||
|     chatbotUserId: str | ||||
|  | ||||
|     @overrides(BaseEvent) | ||||
|     def get_type(self) -> Literal["message", "notice", "request", "meta_event"]: | ||||
|         raise ValueError("Event has no type!") | ||||
|  | ||||
|     @overrides(BaseEvent) | ||||
|     def get_event_name(self) -> str: | ||||
|         raise ValueError("Event has no name!") | ||||
|  | ||||
|     @overrides(BaseEvent) | ||||
|     def get_event_description(self) -> str: | ||||
|         raise ValueError("Event has no description!") | ||||
|  | ||||
|     @overrides(BaseEvent) | ||||
|     def get_message(self) -> "Message": | ||||
|         raise ValueError("Event has no message!") | ||||
|  | ||||
|     @overrides(BaseEvent) | ||||
|     def get_plaintext(self) -> str: | ||||
|         raise ValueError("Event has no plaintext!") | ||||
|  | ||||
|     @overrides(BaseEvent) | ||||
|     def get_user_id(self) -> str: | ||||
|         raise ValueError("Event has no user_id!") | ||||
|  | ||||
|     @overrides(BaseEvent) | ||||
|     def get_session_id(self) -> str: | ||||
|         raise ValueError("Event has no session_id!") | ||||
|  | ||||
|     @overrides(BaseEvent) | ||||
|     def is_tome(self) -> bool: | ||||
|         return True | ||||
|  | ||||
|  | ||||
| class TextMessage(BaseModel): | ||||
|     content: str | ||||
|  | ||||
|  | ||||
| class AtUsersItem(BaseModel): | ||||
|     dingtalkId: str | ||||
|     staffId: Optional[str] | ||||
|  | ||||
|  | ||||
| class ConversationType(str, Enum): | ||||
|     private = "1" | ||||
|     group = "2" | ||||
|  | ||||
|  | ||||
| class MessageEvent(Event): | ||||
|     """消息事件""" | ||||
|  | ||||
|     msgtype: str | ||||
|     text: TextMessage | ||||
|     msgId: str | ||||
|     createAt: int  # ms | ||||
|     conversationType: ConversationType | ||||
|     conversationId: str | ||||
|     senderId: str | ||||
|     senderNick: str | ||||
|     senderCorpId: Optional[str] | ||||
|     sessionWebhook: str | ||||
|     sessionWebhookExpiredTime: int | ||||
|     isAdmin: bool | ||||
|  | ||||
|     message: Message | ||||
|  | ||||
|     @root_validator(pre=True) | ||||
|     def gen_message(cls, values: dict): | ||||
|         assert "msgtype" in values, "msgtype must be specified" | ||||
|         # 其实目前钉钉机器人只能接收到 text 类型的消息 | ||||
|         assert values["msgtype"] in values, f"{values['msgtype']} must be specified" | ||||
|         content = values[values["msgtype"]]["content"] | ||||
|         # 如果是被 @,第一个字符将会为空格,移除特殊情况 | ||||
|         if content[0] == " ": | ||||
|             content = content[1:] | ||||
|         values["message"] = content | ||||
|         return values | ||||
|  | ||||
|     @overrides(Event) | ||||
|     def get_type(self) -> Literal["message", "notice", "request", "meta_event"]: | ||||
|         return "message" | ||||
|  | ||||
|     @overrides(Event) | ||||
|     def get_event_name(self) -> str: | ||||
|         return f"{self.get_type()}.{self.conversationType.name}" | ||||
|  | ||||
|     @overrides(Event) | ||||
|     def get_event_description(self) -> str: | ||||
|         return f'Message[{self.msgtype}] {self.msgId} from {self.senderId} "{self.text.content}"' | ||||
|  | ||||
|     @overrides(Event) | ||||
|     def get_message(self) -> Message: | ||||
|         return self.message | ||||
|  | ||||
|     @overrides(Event) | ||||
|     def get_plaintext(self) -> str: | ||||
|         return self.text.content | ||||
|  | ||||
|     @overrides(Event) | ||||
|     def get_user_id(self) -> str: | ||||
|         return self.senderId | ||||
|  | ||||
|     @overrides(Event) | ||||
|     def get_session_id(self) -> str: | ||||
|         return self.senderId | ||||
|  | ||||
|  | ||||
| class PrivateMessageEvent(MessageEvent): | ||||
|     """私聊消息事件""" | ||||
|  | ||||
|     chatbotCorpId: str | ||||
|     senderStaffId: Optional[str] | ||||
|     conversationType: ConversationType = ConversationType.private | ||||
|  | ||||
|  | ||||
| class GroupMessageEvent(MessageEvent): | ||||
|     """群消息事件""" | ||||
|  | ||||
|     atUsers: List[AtUsersItem] | ||||
|     conversationType: ConversationType = ConversationType.group | ||||
|     conversationTitle: str | ||||
|     isInAtList: bool | ||||
|  | ||||
|     @overrides(MessageEvent) | ||||
|     def is_tome(self) -> bool: | ||||
|         return self.isInAtList | ||||
|  | ||||
|     @overrides(MessageEvent) | ||||
|     def get_session_id(self) -> str: | ||||
|         return f"group_{self.conversationId}_{self.senderId}" | ||||
| @@ -1,81 +0,0 @@ | ||||
| from typing import Optional | ||||
|  | ||||
| from nonebot.exception import AdapterException | ||||
| from nonebot.exception import ActionFailed as BaseActionFailed | ||||
| from nonebot.exception import NetworkError as BaseNetworkError | ||||
| from nonebot.exception import ApiNotAvailable as BaseApiNotAvailable | ||||
|  | ||||
|  | ||||
| class DingAdapterException(AdapterException): | ||||
|     """ | ||||
|     :说明: | ||||
|  | ||||
|       钉钉 Adapter 错误基类 | ||||
|     """ | ||||
|  | ||||
|     def __init__(self) -> None: | ||||
|         super().__init__("ding") | ||||
|  | ||||
|  | ||||
| class ActionFailed(BaseActionFailed, DingAdapterException): | ||||
|     """ | ||||
|     :说明: | ||||
|  | ||||
|       API 请求返回错误信息。 | ||||
|  | ||||
|     :参数: | ||||
|  | ||||
|       * ``errcode: Optional[int]``: 错误码 | ||||
|       * ``errmsg: Optional[str]``: 错误信息 | ||||
|     """ | ||||
|  | ||||
|     def __init__(self, errcode: Optional[int] = None, errmsg: Optional[str] = None): | ||||
|         super().__init__() | ||||
|         self.errcode = errcode | ||||
|         self.errmsg = errmsg | ||||
|  | ||||
|     def __repr__(self): | ||||
|         return f'<ApiError errcode={self.errcode} errmsg="{self.errmsg}">' | ||||
|  | ||||
|     def __str__(self): | ||||
|         return self.__repr__() | ||||
|  | ||||
|  | ||||
| class ApiNotAvailable(BaseApiNotAvailable, DingAdapterException): | ||||
|     pass | ||||
|  | ||||
|  | ||||
| class NetworkError(BaseNetworkError, DingAdapterException): | ||||
|     """ | ||||
|     :说明: | ||||
|  | ||||
|       网络错误。 | ||||
|  | ||||
|     :参数: | ||||
|  | ||||
|       * ``retcode: Optional[int]``: 错误码 | ||||
|     """ | ||||
|  | ||||
|     def __init__(self, msg: Optional[str] = None): | ||||
|         super().__init__() | ||||
|         self.msg = msg | ||||
|  | ||||
|     def __repr__(self): | ||||
|         return f"<NetWorkError message={self.msg}>" | ||||
|  | ||||
|     def __str__(self): | ||||
|         return self.__repr__() | ||||
|  | ||||
|  | ||||
| class SessionExpired(ApiNotAvailable, DingAdapterException): | ||||
|     """ | ||||
|     :说明: | ||||
|  | ||||
|       发消息的 session 已经过期。 | ||||
|     """ | ||||
|  | ||||
|     def __repr__(self) -> str: | ||||
|         return f"<Session Webhook is Expired>" | ||||
|  | ||||
|     def __str__(self): | ||||
|         return self.__repr__() | ||||
| @@ -1,201 +0,0 @@ | ||||
| from copy import copy | ||||
| from typing import Any, Dict, Type, Union, Mapping, Iterable, cast | ||||
|  | ||||
| from nonebot.typing import overrides | ||||
| from nonebot.adapters import Message as BaseMessage | ||||
| from nonebot.adapters import MessageSegment as BaseMessageSegment | ||||
|  | ||||
|  | ||||
| class MessageSegment(BaseMessageSegment["Message"]): | ||||
|     """ | ||||
|     钉钉 协议 MessageSegment 适配。具体方法参考协议消息段类型或源码。 | ||||
|     """ | ||||
|  | ||||
|     @classmethod | ||||
|     @overrides(BaseMessageSegment) | ||||
|     def get_message_class(cls) -> Type["Message"]: | ||||
|         return Message | ||||
|  | ||||
|     @overrides(BaseMessageSegment) | ||||
|     def __str__(self) -> str: | ||||
|         """ | ||||
|         该消息段所代表的 str,在命令匹配部分使用, | ||||
|         钉钉目前只支持匹配 text 命令 | ||||
|         """ | ||||
|         if self.type == "text": | ||||
|             return str(self.data["content"]) | ||||
|         return "" | ||||
|  | ||||
|     def __bool__(self) -> bool: | ||||
|         """ | ||||
|         因为暂时还不支持 text 和 markdown 之外的其他复杂消息段的 `__str__`(也不太需要), | ||||
|         会导致判断非这两种类型的消息段的布尔值为 true 的时候出错 | ||||
|         """ | ||||
|         return self.data is not None | ||||
|  | ||||
|     @overrides(BaseMessageSegment) | ||||
|     def is_text(self) -> bool: | ||||
|         return self.type == "text" | ||||
|  | ||||
|     @staticmethod | ||||
|     def atAll() -> "MessageSegment": | ||||
|         """@全体""" | ||||
|         return MessageSegment("at", {"isAtAll": True}) | ||||
|  | ||||
|     @staticmethod | ||||
|     def atMobiles(*mobileNumber: str) -> "MessageSegment": | ||||
|         """@指定手机号人员""" | ||||
|         return MessageSegment("at", {"atMobiles": list(mobileNumber)}) | ||||
|  | ||||
|     @staticmethod | ||||
|     def atDingtalkIds(*dingtalkIds: str) -> "MessageSegment": | ||||
|         """@指定 id,@ 默认会在消息段末尾。 | ||||
|         所以你可以在消息中使用 @{senderId} 占位,发送出去之后 @ 就会出现在占位的位置: | ||||
|         ```python | ||||
|         message = MessageSegment.text(f"@{event.senderId},你好") | ||||
|         message += MessageSegment.atDingtalkIds(event.senderId) | ||||
|         ``` | ||||
|         """ | ||||
|         return MessageSegment("at", {"atDingtalkIds": list(dingtalkIds)}) | ||||
|  | ||||
|     @staticmethod | ||||
|     def text(text: str) -> "MessageSegment": | ||||
|         """发送 ``text`` 类型消息""" | ||||
|         return MessageSegment("text", {"content": text}) | ||||
|  | ||||
|     @staticmethod | ||||
|     def image(picURL: str) -> "MessageSegment": | ||||
|         """发送 ``image`` 类型消息""" | ||||
|         return MessageSegment("image", {"picURL": picURL}) | ||||
|  | ||||
|     @staticmethod | ||||
|     def extension(dict_: dict) -> "MessageSegment": | ||||
|         """标记 text 文本的 extension 属性,需要与 text 消息段相加。""" | ||||
|         return MessageSegment("extension", dict_) | ||||
|  | ||||
|     @staticmethod | ||||
|     def code(code_language: str, code: str) -> "Message": | ||||
|         """发送 code 消息段""" | ||||
|         message = MessageSegment.text(code) | ||||
|         message += MessageSegment.extension( | ||||
|             {"text_type": "code_snippet", "code_language": code_language} | ||||
|         ) | ||||
|         return message | ||||
|  | ||||
|     @staticmethod | ||||
|     def markdown(title: str, text: str) -> "MessageSegment": | ||||
|         """发送 ``markdown`` 类型消息""" | ||||
|         return MessageSegment( | ||||
|             "markdown", | ||||
|             { | ||||
|                 "title": title, | ||||
|                 "text": text, | ||||
|             }, | ||||
|         ) | ||||
|  | ||||
|     @staticmethod | ||||
|     def actionCardSingleBtn( | ||||
|         title: str, text: str, singleTitle: str, singleURL | ||||
|     ) -> "MessageSegment": | ||||
|         """发送 ``actionCardSingleBtn`` 类型消息""" | ||||
|         return MessageSegment( | ||||
|             "actionCard", | ||||
|             { | ||||
|                 "title": title, | ||||
|                 "text": text, | ||||
|                 "singleTitle": singleTitle, | ||||
|                 "singleURL": singleURL, | ||||
|             }, | ||||
|         ) | ||||
|  | ||||
|     @staticmethod | ||||
|     def actionCardMultiBtns( | ||||
|         title: str, | ||||
|         text: str, | ||||
|         btns: list, | ||||
|         hideAvatar: bool = False, | ||||
|         btnOrientation: str = "1", | ||||
|     ) -> "MessageSegment": | ||||
|         """ | ||||
|         发送 ``actionCardMultiBtn`` 类型消息 | ||||
|  | ||||
|         :参数: | ||||
|  | ||||
|             * ``btnOrientation``: 0:按钮竖直排列 1:按钮横向排列 | ||||
|             * ``btns``: ``[{ "title": title, "actionURL": actionURL }, ...]`` | ||||
|         """ | ||||
|         return MessageSegment( | ||||
|             "actionCard", | ||||
|             { | ||||
|                 "title": title, | ||||
|                 "text": text, | ||||
|                 "hideAvatar": "1" if hideAvatar else "0", | ||||
|                 "btnOrientation": btnOrientation, | ||||
|                 "btns": btns, | ||||
|             }, | ||||
|         ) | ||||
|  | ||||
|     @staticmethod | ||||
|     def feedCard(links: list) -> "MessageSegment": | ||||
|         """ | ||||
|         发送 ``feedCard`` 类型消息 | ||||
|  | ||||
|         :参数: | ||||
|  | ||||
|             * ``links``: ``[{ "title": xxx, "messageURL": xxx, "picURL": xxx }, ...]`` | ||||
|         """ | ||||
|         return MessageSegment("feedCard", {"links": links}) | ||||
|  | ||||
|     @staticmethod | ||||
|     def raw(data) -> "MessageSegment": | ||||
|         return MessageSegment("raw", data) | ||||
|  | ||||
|     def to_dict(self) -> Dict[str, Any]: | ||||
|         # 让用户可以直接发送原始的消息格式 | ||||
|         if self.type == "raw": | ||||
|             return copy(self.data) | ||||
|  | ||||
|         # 不属于消息内容,只是作为消息段的辅助 | ||||
|         if self.type in ["at", "extension"]: | ||||
|             return {self.type: copy(self.data)} | ||||
|  | ||||
|         return {"msgtype": self.type, self.type: copy(self.data)} | ||||
|  | ||||
|  | ||||
| class Message(BaseMessage[MessageSegment]): | ||||
|     """ | ||||
|     钉钉 协议 Message 适配。 | ||||
|     """ | ||||
|  | ||||
|     @classmethod | ||||
|     @overrides(BaseMessage) | ||||
|     def get_segment_class(cls) -> Type[MessageSegment]: | ||||
|         return MessageSegment | ||||
|  | ||||
|     @staticmethod | ||||
|     @overrides(BaseMessage) | ||||
|     def _construct( | ||||
|         msg: Union[str, Mapping, Iterable[Mapping]] | ||||
|     ) -> Iterable[MessageSegment]: | ||||
|         if isinstance(msg, Mapping): | ||||
|             msg = cast(Mapping[str, Any], msg) | ||||
|             yield MessageSegment(msg["type"], msg.get("data") or {}) | ||||
|         elif isinstance(msg, str): | ||||
|             yield MessageSegment.text(msg) | ||||
|         elif isinstance(msg, Iterable): | ||||
|             for seg in msg: | ||||
|                 yield MessageSegment(seg["type"], seg.get("data") or {}) | ||||
|  | ||||
|     def _produce(self) -> dict: | ||||
|         data = {} | ||||
|         segment: MessageSegment | ||||
|         for segment in self: | ||||
|             # text 可以和 text 合并 | ||||
|             if segment.type == "text" and data.get("msgtype") == "text": | ||||
|                 data.setdefault("text", {}) | ||||
|                 data["text"]["content"] = ( | ||||
|                     data["text"].setdefault("content", "") + segment.data["content"] | ||||
|                 ) | ||||
|             else: | ||||
|                 data.update(segment.to_dict()) | ||||
|         return data | ||||
| @@ -1,17 +0,0 @@ | ||||
| import hmac | ||||
| import base64 | ||||
| import hashlib | ||||
|  | ||||
| from nonebot.utils import logger_wrapper | ||||
|  | ||||
| log = logger_wrapper("DING") | ||||
|  | ||||
|  | ||||
| def calc_hmac_base64(timestamp: str, secret: str): | ||||
|     secret_enc = secret.encode("utf-8") | ||||
|     string_to_sign = "{}\n{}".format(timestamp, secret) | ||||
|     string_to_sign_enc = string_to_sign.encode("utf-8") | ||||
|     hmac_code = hmac.new( | ||||
|         secret_enc, string_to_sign_enc, digestmod=hashlib.sha256 | ||||
|     ).digest() | ||||
|     return base64.b64encode(hmac_code) | ||||
							
								
								
									
										649
									
								
								packages/nonebot-adapter-ding/poetry.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										649
									
								
								packages/nonebot-adapter-ding/poetry.lock
									
									
									
										generated
									
									
									
								
							| @@ -1,649 +0,0 @@ | ||||
| [[package]] | ||||
| name = "anyio" | ||||
| version = "3.3.4" | ||||
| description = "High level compatibility layer for multiple asynchronous event loop implementations" | ||||
| category = "main" | ||||
| optional = false | ||||
| python-versions = ">=3.6.2" | ||||
|  | ||||
| [package.dependencies] | ||||
| idna = ">=2.8" | ||||
| sniffio = ">=1.1" | ||||
| typing-extensions = {version = "*", markers = "python_version < \"3.8\""} | ||||
|  | ||||
| [package.extras] | ||||
| doc = ["sphinx-rtd-theme", "sphinx-autodoc-typehints (>=1.2.0)"] | ||||
| test = ["coverage[toml] (>=4.5)", "hypothesis (>=4.0)", "pytest (>=6.0)", "pytest-mock (>=3.6.1)", "trustme", "uvloop (<0.15)", "mock (>=4)", "uvloop (>=0.15)"] | ||||
| trio = ["trio (>=0.16)"] | ||||
|  | ||||
| [[package]] | ||||
| name = "asgiref" | ||||
| version = "3.4.1" | ||||
| description = "ASGI specs, helper code, and adapters" | ||||
| category = "main" | ||||
| optional = false | ||||
| python-versions = ">=3.6" | ||||
|  | ||||
| [package.dependencies] | ||||
| typing-extensions = {version = "*", markers = "python_version < \"3.8\""} | ||||
|  | ||||
| [package.extras] | ||||
| tests = ["pytest", "pytest-asyncio", "mypy (>=0.800)"] | ||||
|  | ||||
| [[package]] | ||||
| name = "certifi" | ||||
| version = "2021.10.8" | ||||
| description = "Python package for providing Mozilla's CA Bundle." | ||||
| category = "main" | ||||
| optional = false | ||||
| python-versions = "*" | ||||
|  | ||||
| [[package]] | ||||
| name = "charset-normalizer" | ||||
| version = "2.0.7" | ||||
| description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." | ||||
| category = "main" | ||||
| optional = false | ||||
| python-versions = ">=3.5.0" | ||||
|  | ||||
| [package.extras] | ||||
| unicode_backport = ["unicodedata2"] | ||||
|  | ||||
| [[package]] | ||||
| name = "click" | ||||
| version = "8.0.3" | ||||
| description = "Composable command line interface toolkit" | ||||
| category = "main" | ||||
| optional = false | ||||
| python-versions = ">=3.6" | ||||
|  | ||||
| [package.dependencies] | ||||
| colorama = {version = "*", markers = "platform_system == \"Windows\""} | ||||
| importlib-metadata = {version = "*", markers = "python_version < \"3.8\""} | ||||
|  | ||||
| [[package]] | ||||
| name = "colorama" | ||||
| version = "0.4.4" | ||||
| description = "Cross-platform colored terminal text." | ||||
| category = "main" | ||||
| optional = false | ||||
| python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" | ||||
|  | ||||
| [[package]] | ||||
| name = "fastapi" | ||||
| version = "0.70.0" | ||||
| description = "FastAPI framework, high performance, easy to learn, fast to code, ready for production" | ||||
| category = "main" | ||||
| optional = false | ||||
| python-versions = ">=3.6.1" | ||||
|  | ||||
| [package.dependencies] | ||||
| pydantic = ">=1.6.2,<1.7 || >1.7,<1.7.1 || >1.7.1,<1.7.2 || >1.7.2,<1.7.3 || >1.7.3,<1.8 || >1.8,<1.8.1 || >1.8.1,<2.0.0" | ||||
| starlette = "0.16.0" | ||||
|  | ||||
| [package.extras] | ||||
| all = ["requests (>=2.24.0,<3.0.0)", "jinja2 (>=2.11.2,<4.0.0)", "python-multipart (>=0.0.5,<0.0.6)", "itsdangerous (>=1.1.0,<3.0.0)", "pyyaml (>=5.3.1,<6.0.0)", "ujson (>=4.0.1,<5.0.0)", "orjson (>=3.2.1,<4.0.0)", "email_validator (>=1.1.1,<2.0.0)", "uvicorn[standard] (>=0.12.0,<0.16.0)"] | ||||
| dev = ["python-jose[cryptography] (>=3.3.0,<4.0.0)", "passlib[bcrypt] (>=1.7.2,<2.0.0)", "autoflake (>=1.4.0,<2.0.0)", "flake8 (>=3.8.3,<4.0.0)", "uvicorn[standard] (>=0.12.0,<0.16.0)"] | ||||
| doc = ["mkdocs (>=1.1.2,<2.0.0)", "mkdocs-material (>=7.1.9,<8.0.0)", "mdx-include (>=1.4.1,<2.0.0)", "mkdocs-markdownextradata-plugin (>=0.1.7,<0.3.0)", "typer-cli (>=0.0.12,<0.0.13)", "pyyaml (>=5.3.1,<6.0.0)"] | ||||
| test = ["pytest (>=6.2.4,<7.0.0)", "pytest-cov (>=2.12.0,<4.0.0)", "mypy (==0.910)", "flake8 (>=3.8.3,<4.0.0)", "black (==21.9b0)", "isort (>=5.0.6,<6.0.0)", "requests (>=2.24.0,<3.0.0)", "httpx (>=0.14.0,<0.19.0)", "email_validator (>=1.1.1,<2.0.0)", "sqlalchemy (>=1.3.18,<1.5.0)", "peewee (>=3.13.3,<4.0.0)", "databases[sqlite] (>=0.3.2,<0.6.0)", "orjson (>=3.2.1,<4.0.0)", "ujson (>=4.0.1,<5.0.0)", "python-multipart (>=0.0.5,<0.0.6)", "flask (>=1.1.2,<3.0.0)", "anyio[trio] (>=3.2.1,<4.0.0)", "types-ujson (==0.1.1)", "types-orjson (==3.6.0)", "types-dataclasses (==0.1.7)"] | ||||
|  | ||||
| [[package]] | ||||
| name = "h11" | ||||
| version = "0.12.0" | ||||
| description = "A pure-Python, bring-your-own-I/O implementation of HTTP/1.1" | ||||
| category = "main" | ||||
| optional = false | ||||
| python-versions = ">=3.6" | ||||
|  | ||||
| [[package]] | ||||
| name = "h2" | ||||
| version = "4.1.0" | ||||
| description = "HTTP/2 State-Machine based protocol implementation" | ||||
| category = "main" | ||||
| optional = false | ||||
| python-versions = ">=3.6.1" | ||||
|  | ||||
| [package.dependencies] | ||||
| hpack = ">=4.0,<5" | ||||
| hyperframe = ">=6.0,<7" | ||||
|  | ||||
| [[package]] | ||||
| name = "hpack" | ||||
| version = "4.0.0" | ||||
| description = "Pure-Python HPACK header compression" | ||||
| category = "main" | ||||
| optional = false | ||||
| python-versions = ">=3.6.1" | ||||
|  | ||||
| [[package]] | ||||
| name = "httpcore" | ||||
| version = "0.13.7" | ||||
| description = "A minimal low-level HTTP client." | ||||
| category = "main" | ||||
| optional = false | ||||
| python-versions = ">=3.6" | ||||
|  | ||||
| [package.dependencies] | ||||
| anyio = ">=3.0.0,<4.0.0" | ||||
| h11 = ">=0.11,<0.13" | ||||
| sniffio = ">=1.0.0,<2.0.0" | ||||
|  | ||||
| [package.extras] | ||||
| http2 = ["h2 (>=3,<5)"] | ||||
|  | ||||
| [[package]] | ||||
| name = "httptools" | ||||
| version = "0.2.0" | ||||
| description = "A collection of framework independent HTTP protocol utils." | ||||
| category = "main" | ||||
| optional = false | ||||
| python-versions = "*" | ||||
|  | ||||
| [package.extras] | ||||
| test = ["Cython (==0.29.22)"] | ||||
|  | ||||
| [[package]] | ||||
| name = "httpx" | ||||
| version = "0.20.0" | ||||
| description = "The next generation HTTP client." | ||||
| category = "main" | ||||
| optional = false | ||||
| python-versions = ">=3.6" | ||||
|  | ||||
| [package.dependencies] | ||||
| certifi = "*" | ||||
| charset-normalizer = "*" | ||||
| h2 = {version = ">=3,<5", optional = true, markers = "extra == \"http2\""} | ||||
| httpcore = ">=0.13.3,<0.14.0" | ||||
| rfc3986 = {version = ">=1.3,<2", extras = ["idna2008"]} | ||||
| sniffio = "*" | ||||
|  | ||||
| [package.extras] | ||||
| brotli = ["brotlicffi", "brotli"] | ||||
| cli = ["click (>=8.0.0,<9.0.0)", "rich (>=10.0.0,<11.0.0)", "pygments (>=2.0.0,<3.0.0)"] | ||||
| http2 = ["h2 (>=3,<5)"] | ||||
|  | ||||
| [[package]] | ||||
| name = "hyperframe" | ||||
| version = "6.0.1" | ||||
| description = "HTTP/2 framing layer for Python" | ||||
| category = "main" | ||||
| optional = false | ||||
| python-versions = ">=3.6.1" | ||||
|  | ||||
| [[package]] | ||||
| name = "idna" | ||||
| version = "3.3" | ||||
| description = "Internationalized Domain Names in Applications (IDNA)" | ||||
| category = "main" | ||||
| optional = false | ||||
| python-versions = ">=3.5" | ||||
|  | ||||
| [[package]] | ||||
| name = "importlib-metadata" | ||||
| version = "4.8.1" | ||||
| description = "Read metadata from Python packages" | ||||
| category = "main" | ||||
| optional = false | ||||
| python-versions = ">=3.6" | ||||
|  | ||||
| [package.dependencies] | ||||
| typing-extensions = {version = ">=3.6.4", markers = "python_version < \"3.8\""} | ||||
| zipp = ">=0.5" | ||||
|  | ||||
| [package.extras] | ||||
| docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"] | ||||
| perf = ["ipython"] | ||||
| testing = ["pytest (>=4.6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "packaging", "pep517", "pyfakefs", "flufl.flake8", "pytest-perf (>=0.9.2)", "pytest-black (>=0.3.7)", "pytest-mypy", "importlib-resources (>=1.3)"] | ||||
|  | ||||
| [[package]] | ||||
| name = "loguru" | ||||
| version = "0.5.3" | ||||
| description = "Python logging made (stupidly) simple" | ||||
| category = "main" | ||||
| optional = false | ||||
| python-versions = ">=3.5" | ||||
|  | ||||
| [package.dependencies] | ||||
| colorama = {version = ">=0.3.4", markers = "sys_platform == \"win32\""} | ||||
| win32-setctime = {version = ">=1.0.0", markers = "sys_platform == \"win32\""} | ||||
|  | ||||
| [package.extras] | ||||
| dev = ["codecov (>=2.0.15)", "colorama (>=0.3.4)", "flake8 (>=3.7.7)", "tox (>=3.9.0)", "tox-travis (>=0.12)", "pytest (>=4.6.2)", "pytest-cov (>=2.7.1)", "Sphinx (>=2.2.1)", "sphinx-autobuild (>=0.7.1)", "sphinx-rtd-theme (>=0.4.3)", "black (>=19.10b0)", "isort (>=5.1.1)"] | ||||
|  | ||||
| [[package]] | ||||
| name = "nonebot2" | ||||
| version = "2.0.0-alpha.16" | ||||
| description = "An asynchronous python bot framework." | ||||
| category = "main" | ||||
| optional = false | ||||
| python-versions = "^3.7.3" | ||||
| develop = true | ||||
|  | ||||
| [package.dependencies] | ||||
| fastapi = "^0.70.0" | ||||
| httpx = {version = ">=0.20.0, <1.0.0", extras = ["http2"]} | ||||
| loguru = "^0.5.1" | ||||
| pydantic = {version = "~1.8.0", extras = ["dotenv"]} | ||||
| pygtrie = "^2.4.1" | ||||
| tomlkit = "^0.7.0" | ||||
| uvicorn = {version = "^0.15.0", extras = ["standard"]} | ||||
| websockets = ">=9.1" | ||||
|  | ||||
| [package.extras] | ||||
| quart = ["Quart (>=0.15.0,<0.16.0)"] | ||||
| aiohttp = ["aiohttp[speedups] (>=3.7.4,<4.0.0)"] | ||||
| all = ["Quart (>=0.15.0,<0.16.0)", "aiohttp[speedups] (>=3.7.4,<4.0.0)"] | ||||
|  | ||||
| [package.source] | ||||
| type = "directory" | ||||
| url = "../.." | ||||
|  | ||||
| [[package]] | ||||
| name = "pydantic" | ||||
| version = "1.8.2" | ||||
| description = "Data validation and settings management using python 3.6 type hinting" | ||||
| category = "main" | ||||
| optional = false | ||||
| python-versions = ">=3.6.1" | ||||
|  | ||||
| [package.dependencies] | ||||
| python-dotenv = {version = ">=0.10.4", optional = true, markers = "extra == \"dotenv\""} | ||||
| typing-extensions = ">=3.7.4.3" | ||||
|  | ||||
| [package.extras] | ||||
| dotenv = ["python-dotenv (>=0.10.4)"] | ||||
| email = ["email-validator (>=1.0.3)"] | ||||
|  | ||||
| [[package]] | ||||
| name = "pygtrie" | ||||
| version = "2.4.2" | ||||
| description = "A pure Python trie data structure implementation." | ||||
| category = "main" | ||||
| optional = false | ||||
| python-versions = "*" | ||||
|  | ||||
| [[package]] | ||||
| name = "python-dotenv" | ||||
| version = "0.19.1" | ||||
| description = "Read key-value pairs from a .env file and set them as environment variables" | ||||
| category = "main" | ||||
| optional = false | ||||
| python-versions = ">=3.5" | ||||
|  | ||||
| [package.extras] | ||||
| cli = ["click (>=5.0)"] | ||||
|  | ||||
| [[package]] | ||||
| name = "pyyaml" | ||||
| version = "6.0" | ||||
| description = "YAML parser and emitter for Python" | ||||
| category = "main" | ||||
| optional = false | ||||
| python-versions = ">=3.6" | ||||
|  | ||||
| [[package]] | ||||
| name = "rfc3986" | ||||
| version = "1.5.0" | ||||
| description = "Validating URI References per RFC 3986" | ||||
| category = "main" | ||||
| optional = false | ||||
| python-versions = "*" | ||||
|  | ||||
| [package.dependencies] | ||||
| idna = {version = "*", optional = true, markers = "extra == \"idna2008\""} | ||||
|  | ||||
| [package.extras] | ||||
| idna2008 = ["idna"] | ||||
|  | ||||
| [[package]] | ||||
| name = "sniffio" | ||||
| version = "1.2.0" | ||||
| description = "Sniff out which async library your code is running under" | ||||
| category = "main" | ||||
| optional = false | ||||
| python-versions = ">=3.5" | ||||
|  | ||||
| [[package]] | ||||
| name = "starlette" | ||||
| version = "0.16.0" | ||||
| description = "The little ASGI library that shines." | ||||
| category = "main" | ||||
| optional = false | ||||
| python-versions = ">=3.6" | ||||
|  | ||||
| [package.dependencies] | ||||
| anyio = ">=3.0.0,<4" | ||||
| typing-extensions = {version = "*", markers = "python_version < \"3.8\""} | ||||
|  | ||||
| [package.extras] | ||||
| full = ["itsdangerous", "jinja2", "python-multipart", "pyyaml", "requests", "graphene"] | ||||
|  | ||||
| [[package]] | ||||
| name = "tomlkit" | ||||
| version = "0.7.2" | ||||
| description = "Style preserving TOML library" | ||||
| category = "main" | ||||
| optional = false | ||||
| python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" | ||||
|  | ||||
| [[package]] | ||||
| name = "typing-extensions" | ||||
| version = "3.10.0.2" | ||||
| description = "Backported and Experimental Type Hints for Python 3.5+" | ||||
| category = "main" | ||||
| optional = false | ||||
| python-versions = "*" | ||||
|  | ||||
| [[package]] | ||||
| name = "uvicorn" | ||||
| version = "0.15.0" | ||||
| description = "The lightning-fast ASGI server." | ||||
| category = "main" | ||||
| optional = false | ||||
| python-versions = "*" | ||||
|  | ||||
| [package.dependencies] | ||||
| asgiref = ">=3.4.0" | ||||
| click = ">=7.0" | ||||
| colorama = {version = ">=0.4", optional = true, markers = "sys_platform == \"win32\" and extra == \"standard\""} | ||||
| h11 = ">=0.8" | ||||
| httptools = {version = ">=0.2.0,<0.3.0", optional = true, markers = "extra == \"standard\""} | ||||
| python-dotenv = {version = ">=0.13", optional = true, markers = "extra == \"standard\""} | ||||
| PyYAML = {version = ">=5.1", optional = true, markers = "extra == \"standard\""} | ||||
| typing-extensions = {version = "*", markers = "python_version < \"3.8\""} | ||||
| 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\""} | ||||
| watchgod = {version = ">=0.6", optional = true, markers = "extra == \"standard\""} | ||||
| websockets = {version = ">=9.1", optional = true, markers = "extra == \"standard\""} | ||||
|  | ||||
| [package.extras] | ||||
| standard = ["websockets (>=9.1)", "httptools (>=0.2.0,<0.3.0)", "watchgod (>=0.6)", "python-dotenv (>=0.13)", "PyYAML (>=5.1)", "uvloop (>=0.14.0,!=0.15.0,!=0.15.1)", "colorama (>=0.4)"] | ||||
|  | ||||
| [[package]] | ||||
| name = "uvloop" | ||||
| version = "0.16.0" | ||||
| description = "Fast implementation of asyncio event loop on top of libuv" | ||||
| category = "main" | ||||
| optional = false | ||||
| python-versions = ">=3.7" | ||||
|  | ||||
| [package.extras] | ||||
| dev = ["Cython (>=0.29.24,<0.30.0)", "pytest (>=3.6.0)", "Sphinx (>=4.1.2,<4.2.0)", "sphinxcontrib-asyncio (>=0.3.0,<0.4.0)", "sphinx-rtd-theme (>=0.5.2,<0.6.0)", "aiohttp", "flake8 (>=3.9.2,<3.10.0)", "psutil", "pycodestyle (>=2.7.0,<2.8.0)", "pyOpenSSL (>=19.0.0,<19.1.0)", "mypy (>=0.800)"] | ||||
| docs = ["Sphinx (>=4.1.2,<4.2.0)", "sphinxcontrib-asyncio (>=0.3.0,<0.4.0)", "sphinx-rtd-theme (>=0.5.2,<0.6.0)"] | ||||
| test = ["aiohttp", "flake8 (>=3.9.2,<3.10.0)", "psutil", "pycodestyle (>=2.7.0,<2.8.0)", "pyOpenSSL (>=19.0.0,<19.1.0)", "mypy (>=0.800)"] | ||||
|  | ||||
| [[package]] | ||||
| name = "watchgod" | ||||
| version = "0.7" | ||||
| description = "Simple, modern file watching and code reload in python." | ||||
| category = "main" | ||||
| optional = false | ||||
| python-versions = ">=3.5" | ||||
|  | ||||
| [[package]] | ||||
| name = "websockets" | ||||
| version = "10.0" | ||||
| description = "An implementation of the WebSocket Protocol (RFC 6455 & 7692)" | ||||
| category = "main" | ||||
| optional = false | ||||
| python-versions = ">=3.7" | ||||
|  | ||||
| [[package]] | ||||
| name = "win32-setctime" | ||||
| version = "1.0.3" | ||||
| description = "A small Python utility to set file creation time on Windows" | ||||
| category = "main" | ||||
| optional = false | ||||
| python-versions = ">=3.5" | ||||
|  | ||||
| [package.extras] | ||||
| dev = ["pytest (>=4.6.2)", "black (>=19.3b0)"] | ||||
|  | ||||
| [[package]] | ||||
| name = "zipp" | ||||
| version = "3.6.0" | ||||
| description = "Backport of pathlib-compatible object wrapper for zip files" | ||||
| category = "main" | ||||
| optional = false | ||||
| python-versions = ">=3.6" | ||||
|  | ||||
| [package.extras] | ||||
| docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"] | ||||
| testing = ["pytest (>=4.6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "jaraco.itertools", "func-timeout", "pytest-black (>=0.3.7)", "pytest-mypy"] | ||||
|  | ||||
| [metadata] | ||||
| lock-version = "1.1" | ||||
| python-versions = "^3.7.3" | ||||
| content-hash = "0cc9df471eb39cfb9b3225370913296535c45171158adc19753cebb7fe791ae3" | ||||
|  | ||||
| [metadata.files] | ||||
| anyio = [ | ||||
|     {file = "anyio-3.3.4-py3-none-any.whl", hash = "sha256:4fd09a25ab7fa01d34512b7249e366cd10358cdafc95022c7ff8c8f8a5026d66"}, | ||||
|     {file = "anyio-3.3.4.tar.gz", hash = "sha256:67da67b5b21f96b9d3d65daa6ea99f5d5282cb09f50eb4456f8fb51dffefc3ff"}, | ||||
| ] | ||||
| asgiref = [ | ||||
|     {file = "asgiref-3.4.1-py3-none-any.whl", hash = "sha256:ffc141aa908e6f175673e7b1b3b7af4fdb0ecb738fc5c8b88f69f055c2415214"}, | ||||
|     {file = "asgiref-3.4.1.tar.gz", hash = "sha256:4ef1ab46b484e3c706329cedeff284a5d40824200638503f5768edb6de7d58e9"}, | ||||
| ] | ||||
| certifi = [ | ||||
|     {file = "certifi-2021.10.8-py2.py3-none-any.whl", hash = "sha256:d62a0163eb4c2344ac042ab2bdf75399a71a2d8c7d47eac2e2ee91b9d6339569"}, | ||||
|     {file = "certifi-2021.10.8.tar.gz", hash = "sha256:78884e7c1d4b00ce3cea67b44566851c4343c120abd683433ce934a68ea58872"}, | ||||
| ] | ||||
| charset-normalizer = [ | ||||
|     {file = "charset-normalizer-2.0.7.tar.gz", hash = "sha256:e019de665e2bcf9c2b64e2e5aa025fa991da8720daa3c1138cadd2fd1856aed0"}, | ||||
|     {file = "charset_normalizer-2.0.7-py3-none-any.whl", hash = "sha256:f7af805c321bfa1ce6714c51f254e0d5bb5e5834039bc17db7ebe3a4cec9492b"}, | ||||
| ] | ||||
| click = [ | ||||
|     {file = "click-8.0.3-py3-none-any.whl", hash = "sha256:353f466495adaeb40b6b5f592f9f91cb22372351c84caeb068132442a4518ef3"}, | ||||
|     {file = "click-8.0.3.tar.gz", hash = "sha256:410e932b050f5eed773c4cda94de75971c89cdb3155a72a0831139a79e5ecb5b"}, | ||||
| ] | ||||
| colorama = [ | ||||
|     {file = "colorama-0.4.4-py2.py3-none-any.whl", hash = "sha256:9f47eda37229f68eee03b24b9748937c7dc3868f906e8ba69fbcbdd3bc5dc3e2"}, | ||||
|     {file = "colorama-0.4.4.tar.gz", hash = "sha256:5941b2b48a20143d2267e95b1c2a7603ce057ee39fd88e7329b0c292aa16869b"}, | ||||
| ] | ||||
| fastapi = [ | ||||
|     {file = "fastapi-0.70.0-py3-none-any.whl", hash = "sha256:a36d5f2fad931aa3575c07a3472c784e81f3e664e3bb5c8b9c88d0ec1104f59c"}, | ||||
|     {file = "fastapi-0.70.0.tar.gz", hash = "sha256:66da43cfe5185ea1df99552acffd201f1832c6b364e0f4136c0a99f933466ced"}, | ||||
| ] | ||||
| h11 = [ | ||||
|     {file = "h11-0.12.0-py3-none-any.whl", hash = "sha256:36a3cb8c0a032f56e2da7084577878a035d3b61d104230d4bd49c0c6b555a9c6"}, | ||||
|     {file = "h11-0.12.0.tar.gz", hash = "sha256:47222cb6067e4a307d535814917cd98fd0a57b6788ce715755fa2b6c28b56042"}, | ||||
| ] | ||||
| h2 = [ | ||||
|     {file = "h2-4.1.0-py3-none-any.whl", hash = "sha256:03a46bcf682256c95b5fd9e9a99c1323584c3eec6440d379b9903d709476bc6d"}, | ||||
|     {file = "h2-4.1.0.tar.gz", hash = "sha256:a83aca08fbe7aacb79fec788c9c0bac936343560ed9ec18b82a13a12c28d2abb"}, | ||||
| ] | ||||
| hpack = [ | ||||
|     {file = "hpack-4.0.0-py3-none-any.whl", hash = "sha256:84a076fad3dc9a9f8063ccb8041ef100867b1878b25ef0ee63847a5d53818a6c"}, | ||||
|     {file = "hpack-4.0.0.tar.gz", hash = "sha256:fc41de0c63e687ebffde81187a948221294896f6bdc0ae2312708df339430095"}, | ||||
| ] | ||||
| httpcore = [ | ||||
|     {file = "httpcore-0.13.7-py3-none-any.whl", hash = "sha256:369aa481b014cf046f7067fddd67d00560f2f00426e79569d99cb11245134af0"}, | ||||
|     {file = "httpcore-0.13.7.tar.gz", hash = "sha256:036f960468759e633574d7c121afba48af6419615d36ab8ede979f1ad6276fa3"}, | ||||
| ] | ||||
| httptools = [ | ||||
|     {file = "httptools-0.2.0-cp35-cp35m-macosx_10_14_x86_64.whl", hash = "sha256:79dbc21f3612a78b28384e989b21872e2e3cf3968532601544696e4ed0007ce5"}, | ||||
|     {file = "httptools-0.2.0-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:78d03dd39b09c99ec917d50189e6743adbfd18c15d5944392d2eabda688bf149"}, | ||||
|     {file = "httptools-0.2.0-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:a23166e5ae2775709cf4f7ad4c2048755ebfb272767d244e1a96d55ac775cca7"}, | ||||
|     {file = "httptools-0.2.0-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:3ab1f390d8867f74b3b5ee2a7ecc9b8d7f53750bd45714bf1cb72a953d7dfa77"}, | ||||
|     {file = "httptools-0.2.0-cp36-cp36m-win_amd64.whl", hash = "sha256:a7594f9a010cdf1e16a58b3bf26c9da39bbf663e3b8d46d39176999d71816658"}, | ||||
|     {file = "httptools-0.2.0-cp37-cp37m-macosx_10_14_x86_64.whl", hash = "sha256:01b392a166adcc8bc2f526a939a8aabf89fe079243e1543fd0e7dc1b58d737cb"}, | ||||
|     {file = "httptools-0.2.0-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:80ffa04fe8c8dfacf6e4cef8277347d35b0442c581f5814f3b0cf41b65c43c6e"}, | ||||
|     {file = "httptools-0.2.0-cp37-cp37m-win_amd64.whl", hash = "sha256:d5682eeb10cca0606c4a8286a3391d4c3c5a36f0c448e71b8bd05be4e1694bfb"}, | ||||
|     {file = "httptools-0.2.0-cp38-cp38-macosx_10_14_x86_64.whl", hash = "sha256:a289c27ccae399a70eacf32df9a44059ca2ba4ac444604b00a19a6c1f0809943"}, | ||||
|     {file = "httptools-0.2.0-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:813871f961edea6cb2fe312f2d9b27d12a51ba92545380126f80d0de1917ea15"}, | ||||
|     {file = "httptools-0.2.0-cp38-cp38-win_amd64.whl", hash = "sha256:cc9be041e428c10f8b6ab358c6b393648f9457094e1dcc11b4906026d43cd380"}, | ||||
|     {file = "httptools-0.2.0-cp39-cp39-macosx_10_14_x86_64.whl", hash = "sha256:b08d00d889a118f68f37f3c43e359aab24ee29eb2e3fe96d64c6a2ba8b9d6557"}, | ||||
|     {file = "httptools-0.2.0-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:fd3b8905e21431ad306eeaf56644a68fdd621bf8f3097eff54d0f6bdf7262065"}, | ||||
|     {file = "httptools-0.2.0-cp39-cp39-win_amd64.whl", hash = "sha256:200fc1cdf733a9ff554c0bb97a4047785cfaad9875307d6087001db3eb2b417f"}, | ||||
|     {file = "httptools-0.2.0.tar.gz", hash = "sha256:94505026be56652d7a530ab03d89474dc6021019d6b8682281977163b3471ea0"}, | ||||
| ] | ||||
| httpx = [ | ||||
|     {file = "httpx-0.20.0-py3-none-any.whl", hash = "sha256:33af5aad9bdc82ef1fc89219c1e36f5693bf9cd0ebe330884df563445682c0f8"}, | ||||
|     {file = "httpx-0.20.0.tar.gz", hash = "sha256:09606d630f070d07f9ff28104fbcea429ea0014c1e89ac90b4d8de8286c40e7b"}, | ||||
| ] | ||||
| hyperframe = [ | ||||
|     {file = "hyperframe-6.0.1-py3-none-any.whl", hash = "sha256:0ec6bafd80d8ad2195c4f03aacba3a8265e57bc4cff261e802bf39970ed02a15"}, | ||||
|     {file = "hyperframe-6.0.1.tar.gz", hash = "sha256:ae510046231dc8e9ecb1a6586f63d2347bf4c8905914aa84ba585ae85f28a914"}, | ||||
| ] | ||||
| idna = [ | ||||
|     {file = "idna-3.3-py3-none-any.whl", hash = "sha256:84d9dd047ffa80596e0f246e2eab0b391788b0503584e8945f2368256d2735ff"}, | ||||
|     {file = "idna-3.3.tar.gz", hash = "sha256:9d643ff0a55b762d5cdb124b8eaa99c66322e2157b69160bc32796e824360e6d"}, | ||||
| ] | ||||
| importlib-metadata = [ | ||||
|     {file = "importlib_metadata-4.8.1-py3-none-any.whl", hash = "sha256:b618b6d2d5ffa2f16add5697cf57a46c76a56229b0ed1c438322e4e95645bd15"}, | ||||
|     {file = "importlib_metadata-4.8.1.tar.gz", hash = "sha256:f284b3e11256ad1e5d03ab86bb2ccd6f5339688ff17a4d797a0fe7df326f23b1"}, | ||||
| ] | ||||
| loguru = [ | ||||
|     {file = "loguru-0.5.3-py3-none-any.whl", hash = "sha256:f8087ac396b5ee5f67c963b495d615ebbceac2796379599820e324419d53667c"}, | ||||
|     {file = "loguru-0.5.3.tar.gz", hash = "sha256:b28e72ac7a98be3d28ad28570299a393dfcd32e5e3f6a353dec94675767b6319"}, | ||||
| ] | ||||
| nonebot2 = [] | ||||
| pydantic = [ | ||||
|     {file = "pydantic-1.8.2-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:05ddfd37c1720c392f4e0d43c484217b7521558302e7069ce8d318438d297739"}, | ||||
|     {file = "pydantic-1.8.2-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:a7c6002203fe2c5a1b5cbb141bb85060cbff88c2d78eccbc72d97eb7022c43e4"}, | ||||
|     {file = "pydantic-1.8.2-cp36-cp36m-manylinux2014_i686.whl", hash = "sha256:589eb6cd6361e8ac341db97602eb7f354551482368a37f4fd086c0733548308e"}, | ||||
|     {file = "pydantic-1.8.2-cp36-cp36m-manylinux2014_x86_64.whl", hash = "sha256:10e5622224245941efc193ad1d159887872776df7a8fd592ed746aa25d071840"}, | ||||
|     {file = "pydantic-1.8.2-cp36-cp36m-win_amd64.whl", hash = "sha256:99a9fc39470010c45c161a1dc584997f1feb13f689ecf645f59bb4ba623e586b"}, | ||||
|     {file = "pydantic-1.8.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:a83db7205f60c6a86f2c44a61791d993dff4b73135df1973ecd9eed5ea0bda20"}, | ||||
|     {file = "pydantic-1.8.2-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:41b542c0b3c42dc17da70554bc6f38cbc30d7066d2c2815a94499b5684582ecb"}, | ||||
|     {file = "pydantic-1.8.2-cp37-cp37m-manylinux2014_i686.whl", hash = "sha256:ea5cb40a3b23b3265f6325727ddfc45141b08ed665458be8c6285e7b85bd73a1"}, | ||||
|     {file = "pydantic-1.8.2-cp37-cp37m-manylinux2014_x86_64.whl", hash = "sha256:18b5ea242dd3e62dbf89b2b0ec9ba6c7b5abaf6af85b95a97b00279f65845a23"}, | ||||
|     {file = "pydantic-1.8.2-cp37-cp37m-win_amd64.whl", hash = "sha256:234a6c19f1c14e25e362cb05c68afb7f183eb931dd3cd4605eafff055ebbf287"}, | ||||
|     {file = "pydantic-1.8.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:021ea0e4133e8c824775a0cfe098677acf6fa5a3cbf9206a376eed3fc09302cd"}, | ||||
|     {file = "pydantic-1.8.2-cp38-cp38-manylinux1_i686.whl", hash = "sha256:e710876437bc07bd414ff453ac8ec63d219e7690128d925c6e82889d674bb505"}, | ||||
|     {file = "pydantic-1.8.2-cp38-cp38-manylinux2014_i686.whl", hash = "sha256:ac8eed4ca3bd3aadc58a13c2aa93cd8a884bcf21cb019f8cfecaae3b6ce3746e"}, | ||||
|     {file = "pydantic-1.8.2-cp38-cp38-manylinux2014_x86_64.whl", hash = "sha256:4a03cbbe743e9c7247ceae6f0d8898f7a64bb65800a45cbdc52d65e370570820"}, | ||||
|     {file = "pydantic-1.8.2-cp38-cp38-win_amd64.whl", hash = "sha256:8621559dcf5afacf0069ed194278f35c255dc1a1385c28b32dd6c110fd6531b3"}, | ||||
|     {file = "pydantic-1.8.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:8b223557f9510cf0bfd8b01316bf6dd281cf41826607eada99662f5e4963f316"}, | ||||
|     {file = "pydantic-1.8.2-cp39-cp39-manylinux1_i686.whl", hash = "sha256:244ad78eeb388a43b0c927e74d3af78008e944074b7d0f4f696ddd5b2af43c62"}, | ||||
|     {file = "pydantic-1.8.2-cp39-cp39-manylinux2014_i686.whl", hash = "sha256:05ef5246a7ffd2ce12a619cbb29f3307b7c4509307b1b49f456657b43529dc6f"}, | ||||
|     {file = "pydantic-1.8.2-cp39-cp39-manylinux2014_x86_64.whl", hash = "sha256:54cd5121383f4a461ff7644c7ca20c0419d58052db70d8791eacbbe31528916b"}, | ||||
|     {file = "pydantic-1.8.2-cp39-cp39-win_amd64.whl", hash = "sha256:4be75bebf676a5f0f87937c6ddb061fa39cbea067240d98e298508c1bda6f3f3"}, | ||||
|     {file = "pydantic-1.8.2-py3-none-any.whl", hash = "sha256:fec866a0b59f372b7e776f2d7308511784dace622e0992a0b59ea3ccee0ae833"}, | ||||
|     {file = "pydantic-1.8.2.tar.gz", hash = "sha256:26464e57ccaafe72b7ad156fdaa4e9b9ef051f69e175dbbb463283000c05ab7b"}, | ||||
| ] | ||||
| pygtrie = [ | ||||
|     {file = "pygtrie-2.4.2.tar.gz", hash = "sha256:43205559d28863358dbbf25045029f58e2ab357317a59b11f11ade278ac64692"}, | ||||
| ] | ||||
| python-dotenv = [ | ||||
|     {file = "python-dotenv-0.19.1.tar.gz", hash = "sha256:14f8185cc8d494662683e6914addcb7e95374771e707601dfc70166946b4c4b8"}, | ||||
|     {file = "python_dotenv-0.19.1-py2.py3-none-any.whl", hash = "sha256:bbd3da593fc49c249397cbfbcc449cf36cb02e75afc8157fcc6a81df6fb7750a"}, | ||||
| ] | ||||
| pyyaml = [ | ||||
|     {file = "PyYAML-6.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d4db7c7aef085872ef65a8fd7d6d09a14ae91f691dec3e87ee5ee0539d516f53"}, | ||||
|     {file = "PyYAML-6.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9df7ed3b3d2e0ecfe09e14741b857df43adb5a3ddadc919a2d94fbdf78fea53c"}, | ||||
|     {file = "PyYAML-6.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:77f396e6ef4c73fdc33a9157446466f1cff553d979bd00ecb64385760c6babdc"}, | ||||
|     {file = "PyYAML-6.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a80a78046a72361de73f8f395f1f1e49f956c6be882eed58505a15f3e430962b"}, | ||||
|     {file = "PyYAML-6.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f84fbc98b019fef2ee9a1cb3ce93e3187a6df0b2538a651bfb890254ba9f90b5"}, | ||||
|     {file = "PyYAML-6.0-cp310-cp310-win32.whl", hash = "sha256:2cd5df3de48857ed0544b34e2d40e9fac445930039f3cfe4bcc592a1f836d513"}, | ||||
|     {file = "PyYAML-6.0-cp310-cp310-win_amd64.whl", hash = "sha256:daf496c58a8c52083df09b80c860005194014c3698698d1a57cbcfa182142a3a"}, | ||||
|     {file = "PyYAML-6.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:897b80890765f037df3403d22bab41627ca8811ae55e9a722fd0392850ec4d86"}, | ||||
|     {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:50602afada6d6cbfad699b0c7bb50d5ccffa7e46a3d738092afddc1f9758427f"}, | ||||
|     {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:48c346915c114f5fdb3ead70312bd042a953a8ce5c7106d5bfb1a5254e47da92"}, | ||||
|     {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:98c4d36e99714e55cfbaaee6dd5badbc9a1ec339ebfc3b1f52e293aee6bb71a4"}, | ||||
|     {file = "PyYAML-6.0-cp36-cp36m-win32.whl", hash = "sha256:0283c35a6a9fbf047493e3a0ce8d79ef5030852c51e9d911a27badfde0605293"}, | ||||
|     {file = "PyYAML-6.0-cp36-cp36m-win_amd64.whl", hash = "sha256:07751360502caac1c067a8132d150cf3d61339af5691fe9e87803040dbc5db57"}, | ||||
|     {file = "PyYAML-6.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:819b3830a1543db06c4d4b865e70ded25be52a2e0631ccd2f6a47a2822f2fd7c"}, | ||||
|     {file = "PyYAML-6.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:473f9edb243cb1935ab5a084eb238d842fb8f404ed2193a915d1784b5a6b5fc0"}, | ||||
|     {file = "PyYAML-6.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0ce82d761c532fe4ec3f87fc45688bdd3a4c1dc5e0b4a19814b9009a29baefd4"}, | ||||
|     {file = "PyYAML-6.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:231710d57adfd809ef5d34183b8ed1eeae3f76459c18fb4a0b373ad56bedcdd9"}, | ||||
|     {file = "PyYAML-6.0-cp37-cp37m-win32.whl", hash = "sha256:c5687b8d43cf58545ade1fe3e055f70eac7a5a1a0bf42824308d868289a95737"}, | ||||
|     {file = "PyYAML-6.0-cp37-cp37m-win_amd64.whl", hash = "sha256:d15a181d1ecd0d4270dc32edb46f7cb7733c7c508857278d3d378d14d606db2d"}, | ||||
|     {file = "PyYAML-6.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0b4624f379dab24d3725ffde76559cff63d9ec94e1736b556dacdfebe5ab6d4b"}, | ||||
|     {file = "PyYAML-6.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:213c60cd50106436cc818accf5baa1aba61c0189ff610f64f4a3e8c6726218ba"}, | ||||
|     {file = "PyYAML-6.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9fa600030013c4de8165339db93d182b9431076eb98eb40ee068700c9c813e34"}, | ||||
|     {file = "PyYAML-6.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:277a0ef2981ca40581a47093e9e2d13b3f1fbbeffae064c1d21bfceba2030287"}, | ||||
|     {file = "PyYAML-6.0-cp38-cp38-win32.whl", hash = "sha256:d4eccecf9adf6fbcc6861a38015c2a64f38b9d94838ac1810a9023a0609e1b78"}, | ||||
|     {file = "PyYAML-6.0-cp38-cp38-win_amd64.whl", hash = "sha256:1e4747bc279b4f613a09eb64bba2ba602d8a6664c6ce6396a4d0cd413a50ce07"}, | ||||
|     {file = "PyYAML-6.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:055d937d65826939cb044fc8c9b08889e8c743fdc6a32b33e2390f66013e449b"}, | ||||
|     {file = "PyYAML-6.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e61ceaab6f49fb8bdfaa0f92c4b57bcfbea54c09277b1b4f7ac376bfb7a7c174"}, | ||||
|     {file = "PyYAML-6.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d67d839ede4ed1b28a4e8909735fc992a923cdb84e618544973d7dfc71540803"}, | ||||
|     {file = "PyYAML-6.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cba8c411ef271aa037d7357a2bc8f9ee8b58b9965831d9e51baf703280dc73d3"}, | ||||
|     {file = "PyYAML-6.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:40527857252b61eacd1d9af500c3337ba8deb8fc298940291486c465c8b46ec0"}, | ||||
|     {file = "PyYAML-6.0-cp39-cp39-win32.whl", hash = "sha256:b5b9eccad747aabaaffbc6064800670f0c297e52c12754eb1d976c57e4f74dcb"}, | ||||
|     {file = "PyYAML-6.0-cp39-cp39-win_amd64.whl", hash = "sha256:b3d267842bf12586ba6c734f89d1f5b871df0273157918b0ccefa29deb05c21c"}, | ||||
|     {file = "PyYAML-6.0.tar.gz", hash = "sha256:68fb519c14306fec9720a2a5b45bc9f0c8d1b9c72adf45c37baedfcd949c35a2"}, | ||||
| ] | ||||
| rfc3986 = [ | ||||
|     {file = "rfc3986-1.5.0-py2.py3-none-any.whl", hash = "sha256:a86d6e1f5b1dc238b218b012df0aa79409667bb209e58da56d0b94704e712a97"}, | ||||
|     {file = "rfc3986-1.5.0.tar.gz", hash = "sha256:270aaf10d87d0d4e095063c65bf3ddbc6ee3d0b226328ce21e036f946e421835"}, | ||||
| ] | ||||
| sniffio = [ | ||||
|     {file = "sniffio-1.2.0-py3-none-any.whl", hash = "sha256:471b71698eac1c2112a40ce2752bb2f4a4814c22a54a3eed3676bc0f5ca9f663"}, | ||||
|     {file = "sniffio-1.2.0.tar.gz", hash = "sha256:c4666eecec1d3f50960c6bdf61ab7bc350648da6c126e3cf6898d8cd4ddcd3de"}, | ||||
| ] | ||||
| starlette = [ | ||||
|     {file = "starlette-0.16.0-py3-none-any.whl", hash = "sha256:38eb24bf705a2c317e15868e384c1b8a12ca396e5a3c3a003db7e667c43f939f"}, | ||||
|     {file = "starlette-0.16.0.tar.gz", hash = "sha256:e1904b5d0007aee24bdd3c43994be9b3b729f4f58e740200de1d623f8c3a8870"}, | ||||
| ] | ||||
| tomlkit = [ | ||||
|     {file = "tomlkit-0.7.2-py2.py3-none-any.whl", hash = "sha256:173ad840fa5d2aac140528ca1933c29791b79a374a0861a80347f42ec9328117"}, | ||||
|     {file = "tomlkit-0.7.2.tar.gz", hash = "sha256:d7a454f319a7e9bd2e249f239168729327e4dd2d27b17dc68be264ad1ce36754"}, | ||||
| ] | ||||
| typing-extensions = [ | ||||
|     {file = "typing_extensions-3.10.0.2-py2-none-any.whl", hash = "sha256:d8226d10bc02a29bcc81df19a26e56a9647f8b0a6d4a83924139f4a8b01f17b7"}, | ||||
|     {file = "typing_extensions-3.10.0.2-py3-none-any.whl", hash = "sha256:f1d25edafde516b146ecd0613dabcc61409817af4766fbbcfb8d1ad4ec441a34"}, | ||||
|     {file = "typing_extensions-3.10.0.2.tar.gz", hash = "sha256:49f75d16ff11f1cd258e1b988ccff82a3ca5570217d7ad8c5f48205dd99a677e"}, | ||||
| ] | ||||
| uvicorn = [ | ||||
|     {file = "uvicorn-0.15.0-py3-none-any.whl", hash = "sha256:17f898c64c71a2640514d4089da2689e5db1ce5d4086c2d53699bf99513421c1"}, | ||||
|     {file = "uvicorn-0.15.0.tar.gz", hash = "sha256:d9a3c0dd1ca86728d3e235182683b4cf94cd53a867c288eaeca80ee781b2caff"}, | ||||
| ] | ||||
| uvloop = [ | ||||
|     {file = "uvloop-0.16.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:6224f1401025b748ffecb7a6e2652b17768f30b1a6a3f7b44660e5b5b690b12d"}, | ||||
|     {file = "uvloop-0.16.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:30ba9dcbd0965f5c812b7c2112a1ddf60cf904c1c160f398e7eed3a6b82dcd9c"}, | ||||
|     {file = "uvloop-0.16.0-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:bd53f7f5db562f37cd64a3af5012df8cac2c464c97e732ed556800129505bd64"}, | ||||
|     {file = "uvloop-0.16.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:772206116b9b57cd625c8a88f2413df2fcfd0b496eb188b82a43bed7af2c2ec9"}, | ||||
|     {file = "uvloop-0.16.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b572256409f194521a9895aef274cea88731d14732343da3ecdb175228881638"}, | ||||
|     {file = "uvloop-0.16.0-cp37-cp37m-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:04ff57aa137230d8cc968f03481176041ae789308b4d5079118331ab01112450"}, | ||||
|     {file = "uvloop-0.16.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3a19828c4f15687675ea912cc28bbcb48e9bb907c801873bd1519b96b04fb805"}, | ||||
|     {file = "uvloop-0.16.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:e814ac2c6f9daf4c36eb8e85266859f42174a4ff0d71b99405ed559257750382"}, | ||||
|     {file = "uvloop-0.16.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:bd8f42ea1ea8f4e84d265769089964ddda95eb2bb38b5cbe26712b0616c3edee"}, | ||||
|     {file = "uvloop-0.16.0-cp38-cp38-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:647e481940379eebd314c00440314c81ea547aa636056f554d491e40503c8464"}, | ||||
|     {file = "uvloop-0.16.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8e0d26fa5875d43ddbb0d9d79a447d2ace4180d9e3239788208527c4784f7cab"}, | ||||
|     {file = "uvloop-0.16.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:6ccd57ae8db17d677e9e06192e9c9ec4bd2066b77790f9aa7dede2cc4008ee8f"}, | ||||
|     {file = "uvloop-0.16.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:089b4834fd299d82d83a25e3335372f12117a7d38525217c2258e9b9f4578897"}, | ||||
|     {file = "uvloop-0.16.0-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:98d117332cc9e5ea8dfdc2b28b0a23f60370d02e1395f88f40d1effd2cb86c4f"}, | ||||
|     {file = "uvloop-0.16.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1e5f2e2ff51aefe6c19ee98af12b4ae61f5be456cd24396953244a30880ad861"}, | ||||
|     {file = "uvloop-0.16.0.tar.gz", hash = "sha256:f74bc20c7b67d1c27c72601c78cf95be99d5c2cdd4514502b4f3eb0933ff1228"}, | ||||
| ] | ||||
| watchgod = [ | ||||
|     {file = "watchgod-0.7-py3-none-any.whl", hash = "sha256:d6c1ea21df37847ac0537ca0d6c2f4cdf513562e95f77bb93abbcf05573407b7"}, | ||||
|     {file = "watchgod-0.7.tar.gz", hash = "sha256:48140d62b0ebe9dd9cf8381337f06351e1f2e70b2203fa9c6eff4e572ca84f29"}, | ||||
| ] | ||||
| websockets = [ | ||||
|     {file = "websockets-10.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:cd8c6f2ec24aedace251017bc7a414525171d4e6578f914acab9349362def4da"}, | ||||
|     {file = "websockets-10.0-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:1f6b814cff6aadc4288297cb3a248614829c6e4ff5556593c44a115e9dd49939"}, | ||||
|     {file = "websockets-10.0-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:01db0ecd1a0ca6702d02a5ed40413e18b7d22f94afb3bbe0d323bac86c42c1c8"}, | ||||
|     {file = "websockets-10.0-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:82b17524b1ce6ae7f7dd93e4d18e9b9474071e28b65dbf1dfe9b5767778db379"}, | ||||
|     {file = "websockets-10.0-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:8bbf8660c3f833ddc8b1afab90213f2e672a9ddac6eecb3cde968e6b2807c1c7"}, | ||||
|     {file = "websockets-10.0-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:b8176deb6be540a46695960a765a77c28ac8b2e3ef2ec95d50a4f5df901edb1c"}, | ||||
|     {file = "websockets-10.0-cp37-cp37m-win32.whl", hash = "sha256:706e200fc7f03bed99ad0574cd1ea8b0951477dd18cc978ccb190683c69dba76"}, | ||||
|     {file = "websockets-10.0-cp37-cp37m-win_amd64.whl", hash = "sha256:5b2600e01c7ca6f840c42c747ffbe0254f319594ed108db847eb3d75f4aacb80"}, | ||||
|     {file = "websockets-10.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:085bb8a6e780d30eaa1ba48ac7f3a6707f925edea787cfb761ce5a39e77ac09b"}, | ||||
|     {file = "websockets-10.0-cp38-cp38-manylinux1_i686.whl", hash = "sha256:9a4d889162bd48588e80950e07fa5e039eee9deb76a58092e8c3ece96d7ef537"}, | ||||
|     {file = "websockets-10.0-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:b4ade7569b6fd17912452f9c3757d96f8e4044016b6d22b3b8391e641ca50456"}, | ||||
|     {file = "websockets-10.0-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:2a43072e434c041a99f2e1eb9b692df0232a38c37c61d00e9f24db79474329e4"}, | ||||
|     {file = "websockets-10.0-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:7f79f02c7f9a8320aff7d3321cd1c7e3a7dbc15d922ac996cca827301ee75238"}, | ||||
|     {file = "websockets-10.0-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:1ac35426fe3e7d3d0fac3d63c8965c76ed67a8fd713937be072bf0ce22808539"}, | ||||
|     {file = "websockets-10.0-cp38-cp38-win32.whl", hash = "sha256:ff59c6bdb87b31f7e2d596f09353d5a38c8c8ff571b0e2238e8ee2d55ad68465"}, | ||||
|     {file = "websockets-10.0-cp38-cp38-win_amd64.whl", hash = "sha256:d67646ddd17a86117ae21c27005d83c1895c0cef5d7be548b7549646372f868a"}, | ||||
|     {file = "websockets-10.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:82bd921885231f4a30d9bc550552495b3fc36b1235add6d374e7c65c3babd805"}, | ||||
|     {file = "websockets-10.0-cp39-cp39-manylinux1_i686.whl", hash = "sha256:7d2e12e4f901f1bc062dfdf91831712c4106ed18a9a4cdb65e2e5f502124ca37"}, | ||||
|     {file = "websockets-10.0-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:71358c7816e2762f3e4af3adf0040f268e219f5a38cb3487a9d0fc2e554fef6a"}, | ||||
|     {file = "websockets-10.0-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:fe83b3ec9ef34063d86dfe1029160a85f24a5a94271036e5714a57acfdd089a1"}, | ||||
|     {file = "websockets-10.0-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:eb282127e9c136f860c6068a4fba5756eb25e755baffb5940b6f1eae071928b2"}, | ||||
|     {file = "websockets-10.0-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:62160772314920397f9d219147f958b33fa27a12c662d4455c9ccbba9a07e474"}, | ||||
|     {file = "websockets-10.0-cp39-cp39-win32.whl", hash = "sha256:e42a1f1e03437b017af341e9bbfdc09252cd48ef32a8c3c3ead769eab3b17368"}, | ||||
|     {file = "websockets-10.0-cp39-cp39-win_amd64.whl", hash = "sha256:c5880442f5fc268f1ef6d37b2c152c114deccca73f48e3a8c48004d2f16f4567"}, | ||||
|     {file = "websockets-10.0.tar.gz", hash = "sha256:c4fc9a1d242317892590abe5b61a9127f1a61740477bfb121743f290b8054002"}, | ||||
| ] | ||||
| win32-setctime = [ | ||||
|     {file = "win32_setctime-1.0.3-py3-none-any.whl", hash = "sha256:dc925662de0a6eb987f0b01f599c01a8236cb8c62831c22d9cada09ad958243e"}, | ||||
|     {file = "win32_setctime-1.0.3.tar.gz", hash = "sha256:4e88556c32fdf47f64165a2180ba4552f8bb32c1103a2fafd05723a0bd42bd4b"}, | ||||
| ] | ||||
| zipp = [ | ||||
|     {file = "zipp-3.6.0-py3-none-any.whl", hash = "sha256:9fe5ea21568a0a70e50f273397638d39b03353731e6cbbb3fd8502a33fec40bc"}, | ||||
|     {file = "zipp-3.6.0.tar.gz", hash = "sha256:71c644c5369f4a6e07636f0aa966270449561fcea2e3d6747b8d23efaa9d7832"}, | ||||
| ] | ||||
| @@ -1,54 +0,0 @@ | ||||
| [tool.poetry] | ||||
| name = "nonebot-adapter-ding" | ||||
| version = "2.0.0-alpha.16" | ||||
| description = "Ding adapter for nonebot2" | ||||
| authors = ["Artin <lengthmin@gmail.com>", "yanyongyu <yyy@nonebot.dev>"] | ||||
| license = "MIT" | ||||
| readme = "README.md" | ||||
| homepage = "https://v2.nonebot.dev/" | ||||
| repository = "https://github.com/nonebot/nonebot2" | ||||
| documentation = "https://v2.nonebot.dev/" | ||||
| keywords = ["bot", "qq", "qqbot", "ding"] | ||||
| classifiers = [ | ||||
|   "Development Status :: 5 - Production/Stable", | ||||
|   "Framework :: Robot Framework", | ||||
|   "Framework :: Robot Framework :: Library", | ||||
|   "Operating System :: OS Independent", | ||||
|   "Programming Language :: Python :: 3" | ||||
| ] | ||||
| packages = [ | ||||
|   { include = "nonebot" } | ||||
| ] | ||||
| exclude = ["nonebot/__init__.py", "nonebot/adapters/__init__.py"] | ||||
|  | ||||
| [tool.poetry.dependencies] | ||||
| python = "^3.7.3" | ||||
| httpx = ">=0.20.0, <1.0.0" | ||||
| nonebot2 = "^2.0.0-alpha.14" | ||||
|  | ||||
| [tool.poetry.dev-dependencies] | ||||
| nonebot2 = { path = "../../", develop = true } | ||||
|  | ||||
| # [[tool.poetry.source]] | ||||
| # name = "aliyun" | ||||
| # url = "https://mirrors.aliyun.com/pypi/simple/" | ||||
| # default = true | ||||
|  | ||||
| [tool.black] | ||||
| line-length = 88 | ||||
| target-version = ["py37", "py38", "py39"] | ||||
| include = '\.pyi?$' | ||||
| extend-exclude = ''' | ||||
| ''' | ||||
|  | ||||
| [tool.isort] | ||||
| profile = "black" | ||||
| line_length = 80 | ||||
| length_sort = true | ||||
| skip_gitignore = true | ||||
| force_sort_within_sections = true | ||||
| extra_standard_library = ["typing_extensions"] | ||||
|  | ||||
| [build-system] | ||||
| requires = ["poetry-core>=1.0.0"] | ||||
| build-backend = "poetry.core.masonry.api" | ||||
| @@ -1,11 +0,0 @@ | ||||
| <p align="center"> | ||||
|   <a href="https://v2.nonebot.dev/"><img src="https://raw.githubusercontent.com/nonebot/nonebot2/master/docs/.vuepress/public/logo.png" width="200" height="200" alt="nonebot"></a> | ||||
| </p> | ||||
|  | ||||
| <div align="center"> | ||||
|  | ||||
| # NoneBot-Adapter-Feishu | ||||
|  | ||||
| _✨ 飞书协议适配 ✨_ | ||||
|  | ||||
| </div> | ||||
| @@ -1,13 +0,0 @@ | ||||
| import logging | ||||
|  | ||||
| from nonebot.log import LoguruHandler, logger | ||||
|  | ||||
| aiocache_logger = logging.getLogger("aiocache.serializers.serializers") | ||||
| aiocache_logger.setLevel(logging.DEBUG) | ||||
| aiocache_logger.handlers.clear() | ||||
| aiocache_logger.addHandler(LoguruHandler()) | ||||
|  | ||||
| from .event import * | ||||
| from .bot import Bot as Bot | ||||
| from .message import Message as Message | ||||
| from .message import MessageSegment as MessageSegment | ||||
| @@ -1,395 +0,0 @@ | ||||
| import re | ||||
| import json | ||||
| from typing import ( | ||||
|     TYPE_CHECKING, | ||||
|     Any, | ||||
|     Dict, | ||||
|     Tuple, | ||||
|     Union, | ||||
|     Iterable, | ||||
|     Optional, | ||||
|     AsyncIterable, | ||||
|     cast, | ||||
| ) | ||||
|  | ||||
| import httpx | ||||
| from aiocache import Cache, cached | ||||
| from aiocache.serializers import PickleSerializer | ||||
|  | ||||
| from nonebot.log import logger | ||||
| from nonebot.typing import overrides | ||||
| from nonebot.utils import escape_tag | ||||
| from nonebot.message import handle_event | ||||
| from nonebot.adapters import Bot as BaseBot | ||||
| from nonebot.drivers import Driver, HTTPRequest, HTTPResponse | ||||
|  | ||||
| from .utils import AESCipher, log | ||||
| from .config import Config as FeishuConfig | ||||
| from .message import Message, MessageSegment, MessageSerializer | ||||
| from .exception import ActionFailed, NetworkError, ApiNotAvailable | ||||
| from .event import ( | ||||
|     Event, | ||||
|     MessageEvent, | ||||
|     GroupMessageEvent, | ||||
|     PrivateMessageEvent, | ||||
|     get_event_model, | ||||
| ) | ||||
|  | ||||
| if TYPE_CHECKING: | ||||
|     from nonebot.config import Config | ||||
|  | ||||
|  | ||||
| def _check_at_me(bot: "Bot", event: "Event"): | ||||
|     """ | ||||
|     :说明: | ||||
|  | ||||
|       检查消息开头或结尾是否存在 @机器人,去除并赋值 ``event.reply``, ``event.to_me`` | ||||
|  | ||||
|     :参数: | ||||
|  | ||||
|       * ``bot: Bot``: Bot 对象 | ||||
|       * ``event: Event``: Event 对象 | ||||
|     """ | ||||
|     if not isinstance(event, MessageEvent): | ||||
|         return | ||||
|  | ||||
|     message = event.get_message() | ||||
|     # ensure message not empty | ||||
|     if not message: | ||||
|         message.append(MessageSegment.text("")) | ||||
|  | ||||
|     if event.event.message.chat_type == "p2p": | ||||
|         event.to_me = True | ||||
|  | ||||
|         for index, segment in enumerate(message): | ||||
|             if ( | ||||
|                 segment.type == "at" | ||||
|                 and segment.data.get("user_name") in bot.config.nickname | ||||
|             ): | ||||
|                 event.to_me = True | ||||
|                 del event.event.message.content[index] | ||||
|                 return | ||||
|             elif segment.type == "text" and segment.data.get("mentions"): | ||||
|                 for mention in segment.data["mentions"].values(): | ||||
|                     if mention["name"] in bot.config.nickname: | ||||
|                         event.to_me = True | ||||
|                         segment.data["text"] = segment.data["text"].replace( | ||||
|                             f"@{mention['name']}", "" | ||||
|                         ) | ||||
|                         segment.data["text"] = segment.data["text"].lstrip() | ||||
|                         break | ||||
|                 else: | ||||
|                     continue | ||||
|                 break | ||||
|  | ||||
|         if not message: | ||||
|             message.append(MessageSegment.text("")) | ||||
|  | ||||
|  | ||||
| def _check_nickname(bot: "Bot", event: "Event"): | ||||
|     """ | ||||
|     :说明: | ||||
|  | ||||
|       检查消息开头是否存在昵称,去除并赋值 ``event.to_me`` | ||||
|  | ||||
|     :参数: | ||||
|  | ||||
|       * ``bot: Bot``: Bot 对象 | ||||
|       * ``event: Event``: Event 对象 | ||||
|     """ | ||||
|     if not isinstance(event, MessageEvent): | ||||
|         return | ||||
|  | ||||
|     first_msg_seg = event.get_message()[0] | ||||
|     if first_msg_seg.type != "text": | ||||
|         return | ||||
|  | ||||
|     first_text = first_msg_seg.data["text"] | ||||
|  | ||||
|     nicknames = set(filter(lambda n: n, bot.config.nickname)) | ||||
|     if nicknames: | ||||
|         # check if the user is calling me with my nickname | ||||
|         nickname_regex = "|".join(nicknames) | ||||
|         m = re.search(rf"^({nickname_regex})([\s,,]*|$)", first_text, re.IGNORECASE) | ||||
|         if m: | ||||
|             nickname = m.group(1) | ||||
|             log("DEBUG", f"User is calling me {nickname}") | ||||
|             event.to_me = True | ||||
|             first_msg_seg.data["text"] = first_text[m.end() :] | ||||
|  | ||||
|  | ||||
| def _handle_api_result( | ||||
|     result: Union[ | ||||
|         Optional[Dict[str, Any]], str, bytes, Iterable[bytes], AsyncIterable[bytes] | ||||
|     ] | ||||
| ) -> Any: | ||||
|     """ | ||||
|     :说明: | ||||
|  | ||||
|       处理 API 请求返回值。 | ||||
|  | ||||
|     :参数: | ||||
|  | ||||
|       * ``result: Optional[Dict[str, Any]]``: API 返回数据 | ||||
|  | ||||
|     :返回: | ||||
|  | ||||
|         - ``Any``: API 调用返回数据 | ||||
|  | ||||
|     :异常: | ||||
|  | ||||
|         - ``ActionFailed``: API 调用失败 | ||||
|     """ | ||||
|     if isinstance(result, dict): | ||||
|         result = cast(Dict[str, Any], result) | ||||
|         if result.get("code") != 0: | ||||
|             raise ActionFailed(**result) | ||||
|         return result.get("data") | ||||
|     else: | ||||
|         return result | ||||
|  | ||||
|  | ||||
| class Bot(BaseBot): | ||||
|     """ | ||||
|     飞书 协议 Bot 适配。继承属性参考 `BaseBot <README.md#class-bot>`_ 。 | ||||
|     """ | ||||
|  | ||||
|     @property | ||||
|     def type(self) -> str: | ||||
|         return "feishu" | ||||
|  | ||||
|     @property | ||||
|     def api_root(self) -> str: | ||||
|         if self.feishu_config.is_lark: | ||||
|             return "https://open.larksuite.com/open-apis/" | ||||
|         else: | ||||
|             return "https://open.feishu.cn/open-apis/" | ||||
|  | ||||
|     @classmethod | ||||
|     def register(cls, driver: Driver, config: "Config"): | ||||
|         super().register(driver, config) | ||||
|         cls.feishu_config = FeishuConfig(**config.dict()) | ||||
|  | ||||
|     @classmethod | ||||
|     @overrides(BaseBot) | ||||
|     async def check_permission( | ||||
|         cls, driver: Driver, request: HTTPRequest | ||||
|     ) -> Tuple[Optional[str], Optional[HTTPResponse]]: | ||||
|         if not isinstance(request, HTTPRequest): | ||||
|             log("WARNING", "Unsupported connection type, available type: `http`") | ||||
|             return None, HTTPResponse( | ||||
|                 405, b"Unsupported connection type, available type: `http`" | ||||
|             ) | ||||
|  | ||||
|         encrypt_key = cls.feishu_config.encrypt_key | ||||
|         if encrypt_key: | ||||
|             encrypted = json.loads(request.body)["encrypt"] | ||||
|             decrypted = AESCipher(encrypt_key).decrypt_string(encrypted) | ||||
|             data = json.loads(decrypted) | ||||
|         else: | ||||
|             data = json.loads(request.body) | ||||
|  | ||||
|         challenge = data.get("challenge") | ||||
|         if challenge: | ||||
|             return data.get("token"), HTTPResponse( | ||||
|                 200, json.dumps({"challenge": challenge}).encode() | ||||
|             ) | ||||
|  | ||||
|         schema = data.get("schema") | ||||
|         if not schema: | ||||
|             return None, HTTPResponse( | ||||
|                 400, b"Missing `schema` in POST body, only accept event of version 2.0" | ||||
|             ) | ||||
|  | ||||
|         headers = data.get("header") | ||||
|         if headers: | ||||
|             token = headers.get("token") | ||||
|             app_id = headers.get("app_id") | ||||
|         else: | ||||
|             log("WARNING", "Missing `header` in POST body") | ||||
|             return None, HTTPResponse(400, b"Missing `header` in POST body") | ||||
|  | ||||
|         if not token: | ||||
|             log("WARNING", "Missing `verification token` in POST body") | ||||
|             return None, HTTPResponse(400, b"Missing `verification token` in POST body") | ||||
|         else: | ||||
|             if token != cls.feishu_config.verification_token: | ||||
|                 log("WARNING", "Verification token check failed") | ||||
|                 return None, HTTPResponse(403, b"Verification token check failed") | ||||
|  | ||||
|         return app_id, HTTPResponse(200, b"") | ||||
|  | ||||
|     async def handle_message(self, message: bytes): | ||||
|         """ | ||||
|         :说明: | ||||
|  | ||||
|           处理事件并转换为 `Event <#class-event>`_ | ||||
|         """ | ||||
|         data: dict = json.loads(message) | ||||
|         if data.get("type") == "url_verification": | ||||
|             return | ||||
|  | ||||
|         try: | ||||
|             header = data["header"] | ||||
|             event_type = header["event_type"] | ||||
|             if data.get("event"): | ||||
|                 if data["event"].get("message"): | ||||
|                     event_type += f".{data['event']['message']['chat_type']}" | ||||
|  | ||||
|             models = get_event_model(event_type) | ||||
|             for model in models: | ||||
|                 try: | ||||
|                     event = model.parse_obj(data) | ||||
|                     break | ||||
|                 except Exception as e: | ||||
|                     log("DEBUG", "Event Parser Error", e) | ||||
|             else: | ||||
|                 event = Event.parse_obj(data) | ||||
|  | ||||
|             _check_at_me(self, event) | ||||
|             _check_nickname(self, event) | ||||
|  | ||||
|             await handle_event(self, event) | ||||
|         except Exception as e: | ||||
|             logger.opt(colors=True, exception=e).error( | ||||
|                 f"<r><bg #f8bbd0>Failed to handle event. Raw: {escape_tag(str(data))}</bg #f8bbd0></r>" | ||||
|             ) | ||||
|  | ||||
|     def _construct_url(self, path: str) -> str: | ||||
|         return self.api_root + path | ||||
|  | ||||
|     @cached( | ||||
|         ttl=60 * 60, | ||||
|         cache=Cache.MEMORY, | ||||
|         key="_feishu_tenant_access_token", | ||||
|         serializer=PickleSerializer(), | ||||
|     ) | ||||
|     async def _fetch_tenant_access_token(self) -> str: | ||||
|         try: | ||||
|             async with httpx.AsyncClient(follow_redirects=True) as client: | ||||
|                 response = await client.post( | ||||
|                     self._construct_url("auth/v3/tenant_access_token/internal/"), | ||||
|                     json={ | ||||
|                         "app_id": self.feishu_config.app_id, | ||||
|                         "app_secret": self.feishu_config.app_secret, | ||||
|                     }, | ||||
|                     timeout=self.config.api_timeout, | ||||
|                 ) | ||||
|  | ||||
|             if 200 <= response.status_code < 300: | ||||
|                 result = response.json() | ||||
|                 return result["tenant_access_token"] | ||||
|             else: | ||||
|                 raise NetworkError( | ||||
|                     f"HTTP request received unexpected " | ||||
|                     f"status code: {response.status_code}" | ||||
|                 ) | ||||
|         except httpx.InvalidURL: | ||||
|             raise NetworkError("API root url invalid") | ||||
|         except httpx.HTTPError: | ||||
|             raise NetworkError("HTTP request failed") | ||||
|  | ||||
|     @overrides(BaseBot) | ||||
|     async def _call_api(self, api: str, **data) -> Any: | ||||
|         log("DEBUG", f"Calling API <y>{api}</y>") | ||||
|         if isinstance(self.request, HTTPRequest): | ||||
|             if not self.api_root: | ||||
|                 raise ApiNotAvailable | ||||
|  | ||||
|             headers = {} | ||||
|             self.feishu_config.tenant_access_token = ( | ||||
|                 await self._fetch_tenant_access_token() | ||||
|             ) | ||||
|             headers["Authorization"] = ( | ||||
|                 "Bearer " + self.feishu_config.tenant_access_token | ||||
|             ) | ||||
|  | ||||
|             try: | ||||
|                 async with httpx.AsyncClient( | ||||
|                     timeout=self.config.api_timeout, follow_redirects=True | ||||
|                 ) as client: | ||||
|                     response = await client.send( | ||||
|                         httpx.Request( | ||||
|                             data["method"], | ||||
|                             self.api_root + api, | ||||
|                             json=data.get("body", {}), | ||||
|                             params=data.get("query", {}), | ||||
|                             headers=headers, | ||||
|                         ) | ||||
|                     ) | ||||
|                 if 200 <= response.status_code < 300: | ||||
|                     if response.headers["content-type"].startswith("application/json"): | ||||
|                         result = response.json() | ||||
|                     else: | ||||
|                         result = response.content | ||||
|                     return _handle_api_result(result) | ||||
|                 raise NetworkError( | ||||
|                     f"HTTP request received unexpected " | ||||
|                     f"status code: {response.status_code} " | ||||
|                     f"response body: {response.text}" | ||||
|                 ) | ||||
|             except httpx.InvalidURL: | ||||
|                 raise NetworkError("API root url invalid") | ||||
|             except httpx.HTTPError: | ||||
|                 raise NetworkError("HTTP request failed") | ||||
|  | ||||
|     @overrides(BaseBot) | ||||
|     async def call_api(self, api: str, **data) -> Any: | ||||
|         """ | ||||
|         :说明: | ||||
|  | ||||
|           调用 飞书 协议 API | ||||
|  | ||||
|         :参数: | ||||
|  | ||||
|           * ``api: str``: API 名称 | ||||
|           * ``**data: Any``: API 参数 | ||||
|  | ||||
|         :返回: | ||||
|  | ||||
|           - ``Any``: API 调用返回数据 | ||||
|  | ||||
|         :异常: | ||||
|  | ||||
|           - ``NetworkError``: 网络错误 | ||||
|           - ``ActionFailed``: API 调用失败 | ||||
|         """ | ||||
|         return await super().call_api(api, **data) | ||||
|  | ||||
|     @overrides(BaseBot) | ||||
|     async def send( | ||||
|         self, | ||||
|         event: Event, | ||||
|         message: Union[str, Message, MessageSegment], | ||||
|         at_sender: bool = False, | ||||
|         **kwargs, | ||||
|     ) -> Any: | ||||
|         msg = message if isinstance(message, Message) else Message(message) | ||||
|  | ||||
|         if isinstance(event, GroupMessageEvent): | ||||
|             receive_id, receive_id_type = event.event.message.chat_id, "chat_id" | ||||
|         elif isinstance(event, PrivateMessageEvent): | ||||
|             receive_id, receive_id_type = event.get_user_id(), "open_id" | ||||
|         else: | ||||
|             raise ValueError( | ||||
|                 "Cannot guess `receive_id` and `receive_id_type` to reply!" | ||||
|             ) | ||||
|  | ||||
|         at_sender = at_sender and bool(event.get_user_id()) | ||||
|  | ||||
|         if at_sender and receive_id_type == "chat_id": | ||||
|             msg = MessageSegment.at(event.get_user_id()) + " " + msg | ||||
|  | ||||
|         msg_type, content = MessageSerializer(msg).serialize() | ||||
|  | ||||
|         params = { | ||||
|             "method": "POST", | ||||
|             "query": {"receive_id_type": receive_id_type}, | ||||
|             "body": { | ||||
|                 "receive_id": receive_id, | ||||
|                 "content": content, | ||||
|                 "msg_type": msg_type, | ||||
|             }, | ||||
|         } | ||||
|  | ||||
|         return await self.call_api(f"im/v1/messages", **params) | ||||
| @@ -1,34 +0,0 @@ | ||||
| from typing import Optional | ||||
|  | ||||
| from pydantic import Field, BaseModel | ||||
|  | ||||
|  | ||||
| class Config(BaseModel): | ||||
|     """ | ||||
|     飞书配置类 | ||||
|  | ||||
|     :配置项: | ||||
|  | ||||
|       - ``app_id`` / ``feishu_app_id``: 飞书开放平台后台“凭证与基础信息”处给出的 App ID | ||||
|       - ``app_secret`` / ``feishu_app_secret``: 飞书开放平台后台“凭证与基础信息”处给出的 App Secret | ||||
|       - ``encrypt_key`` / ``feishu_encrypt_key``: 飞书开放平台后台“事件订阅”处设置的 Encrypt Key | ||||
|       - ``verification_token`` / ``feishu_verification_token``: 飞书开放平台后台“事件订阅”处设置的 Verification Token | ||||
|       - ``tenant_access_token`` / ``feishu_tenant_access_token``: 请求飞书 API 后返回的租户密钥 | ||||
|       - ``is_lark`` / ``feishu_is_lark``: 是否使用Lark(飞书海外版),默认为 false | ||||
|  | ||||
|     """ | ||||
|  | ||||
|     app_id: Optional[str] = Field(default=None, alias="feishu_app_id") | ||||
|     app_secret: Optional[str] = Field(default=None, alias="feishu_app_secret") | ||||
|     encrypt_key: Optional[str] = Field(default=None, alias="feishu_encrypt_key") | ||||
|     verification_token: Optional[str] = Field( | ||||
|         default=None, alias="feishu_verification_token" | ||||
|     ) | ||||
|     tenant_access_token: Optional[str] = Field( | ||||
|         default=None, alias="feishu_tenant_access_token" | ||||
|     ) | ||||
|     is_lark: Optional[str] = Field(default=False, alias="feishu_is_lark") | ||||
|  | ||||
|     class Config: | ||||
|         extra = "ignore" | ||||
|         allow_population_by_field_name = True | ||||
| @@ -1,878 +0,0 @@ | ||||
| import json | ||||
| import inspect | ||||
| from typing import Any, Dict, List, Type, Literal, Optional | ||||
|  | ||||
| from pygtrie import StringTrie | ||||
| from pydantic import Field, BaseModel, root_validator | ||||
|  | ||||
| from nonebot.typing import overrides | ||||
| from nonebot.adapters import Event as BaseEvent | ||||
|  | ||||
| from .message import Message, MessageDeserializer | ||||
|  | ||||
|  | ||||
| class EventHeader(BaseModel): | ||||
|     event_id: str | ||||
|     event_type: str | ||||
|     create_time: str | ||||
|     token: str | ||||
|     app_id: str | ||||
|     tenant_key: str | ||||
|     resource_id: Optional[str] | ||||
|     user_list: Optional[List[dict]] | ||||
|  | ||||
|  | ||||
| class Event(BaseEvent): | ||||
|     """ | ||||
|     飞书协议事件。各事件字段参考 `飞书文档`_ | ||||
|  | ||||
|     .. _飞书文档: | ||||
|         https://open.feishu.cn/document/ukTMukTMukTM/uYDNxYjL2QTM24iN0EjN/event-list | ||||
|     """ | ||||
|  | ||||
|     __event__ = "" | ||||
|     schema_: str = Field("", alias="schema") | ||||
|     header: EventHeader | ||||
|     event: Any | ||||
|  | ||||
|     @overrides(BaseEvent) | ||||
|     def get_type(self) -> str: | ||||
|         return self.header.event_type | ||||
|  | ||||
|     @overrides(BaseEvent) | ||||
|     def get_event_name(self) -> str: | ||||
|         return self.header.event_type | ||||
|  | ||||
|     @overrides(BaseEvent) | ||||
|     def get_event_description(self) -> str: | ||||
|         return str(self.dict()) | ||||
|  | ||||
|     @overrides(BaseEvent) | ||||
|     def get_message(self) -> Message: | ||||
|         raise ValueError("Event has no message!") | ||||
|  | ||||
|     @overrides(BaseEvent) | ||||
|     def get_plaintext(self) -> str: | ||||
|         raise ValueError("Event has no plaintext!") | ||||
|  | ||||
|     @overrides(BaseEvent) | ||||
|     def get_user_id(self) -> str: | ||||
|         raise ValueError("Event has no user_id!") | ||||
|  | ||||
|     @overrides(BaseEvent) | ||||
|     def get_session_id(self) -> str: | ||||
|         raise ValueError("Event has no session_id!") | ||||
|  | ||||
|     @overrides(BaseEvent) | ||||
|     def is_tome(self) -> bool: | ||||
|         return False | ||||
|  | ||||
|  | ||||
| class UserId(BaseModel): | ||||
|     union_id: str | ||||
|     user_id: str | ||||
|     open_id: str | ||||
|  | ||||
|  | ||||
| class Sender(BaseModel): | ||||
|     sender_id: UserId | ||||
|     sender_type: str | ||||
|     tenant_key: str | ||||
|  | ||||
|  | ||||
| class ReplySender(BaseModel): | ||||
|     id: str | ||||
|     id_type: str | ||||
|     sender_type: str | ||||
|     tenant_key: str | ||||
|  | ||||
|  | ||||
| class Mention(BaseModel): | ||||
|     key: str | ||||
|     id: UserId | ||||
|     name: str | ||||
|     tenant_key: str | ||||
|  | ||||
|  | ||||
| class ReplyMention(BaseModel): | ||||
|     id: str | ||||
|     id_type: str | ||||
|     key: str | ||||
|     name: str | ||||
|     tenant_key: str | ||||
|  | ||||
|  | ||||
| class MessageBody(BaseModel): | ||||
|     content: str | ||||
|  | ||||
|  | ||||
| class Reply(BaseModel): | ||||
|     message_id: str | ||||
|     root_id: Optional[str] | ||||
|     parent_id: Optional[str] | ||||
|     msg_type: str | ||||
|     create_time: str | ||||
|     update_time: str | ||||
|     deleted: bool | ||||
|     updated: bool | ||||
|     chat_id: str | ||||
|     sender: ReplySender | ||||
|     body: MessageBody | ||||
|     mentions: List[ReplyMention] | ||||
|     upper_message_id: Optional[str] | ||||
|  | ||||
|     class Config: | ||||
|         extra = "allow" | ||||
|  | ||||
|  | ||||
| class EventMessage(BaseModel): | ||||
|     message_id: str | ||||
|     root_id: Optional[str] | ||||
|     parent_id: Optional[str] | ||||
|     create_time: str | ||||
|     chat_id: str | ||||
|     chat_type: str | ||||
|     message_type: str | ||||
|     content: Message | ||||
|     mentions: Optional[List[Mention]] | ||||
|  | ||||
|     @root_validator(pre=True) | ||||
|     def parse_message(cls, values: dict): | ||||
|         values["content"] = MessageDeserializer( | ||||
|             values["message_type"], | ||||
|             json.loads(values["content"]), | ||||
|             values.get("mentions"), | ||||
|         ).deserialize() | ||||
|         return values | ||||
|  | ||||
|  | ||||
| class GroupEventMessage(EventMessage): | ||||
|     chat_type: Literal["group"] | ||||
|  | ||||
|  | ||||
| class PrivateEventMessage(EventMessage): | ||||
|     chat_type: Literal["p2p"] | ||||
|  | ||||
|  | ||||
| class MessageEventDetail(BaseModel): | ||||
|     sender: Sender | ||||
|     message: EventMessage | ||||
|  | ||||
|  | ||||
| class GroupMessageEventDetail(MessageEventDetail): | ||||
|     message: GroupEventMessage | ||||
|  | ||||
|  | ||||
| class PrivateMessageEventDetail(MessageEventDetail): | ||||
|     message: PrivateEventMessage | ||||
|  | ||||
|  | ||||
| class MessageEvent(Event): | ||||
|     __event__ = "im.message.receive_v1" | ||||
|     event: MessageEventDetail | ||||
|  | ||||
|     to_me: bool = False | ||||
|     """ | ||||
|     :说明: 消息是否与机器人有关 | ||||
|  | ||||
|     :类型: ``bool`` | ||||
|     """ | ||||
|     reply: Optional[Reply] | ||||
|  | ||||
|     @overrides(Event) | ||||
|     def get_type(self) -> Literal["message", "notice"]: | ||||
|         return "message" | ||||
|  | ||||
|     @overrides(Event) | ||||
|     def get_event_name(self) -> str: | ||||
|         return f"{self.get_type()}.{self.event.message.chat_type}" | ||||
|  | ||||
|     @overrides(Event) | ||||
|     def get_event_description(self) -> str: | ||||
|         return ( | ||||
|             f"{self.event.message.message_id} from {self.get_user_id()}" | ||||
|             f"@[{self.event.message.chat_type}:{self.event.message.chat_id}]" | ||||
|             f" {self.get_message()}" | ||||
|         ) | ||||
|  | ||||
|     @overrides(Event) | ||||
|     def get_message(self) -> Message: | ||||
|         return self.event.message.content | ||||
|  | ||||
|     @overrides(Event) | ||||
|     def get_plaintext(self) -> str: | ||||
|         return str(self.get_message()) | ||||
|  | ||||
|     @overrides(Event) | ||||
|     def get_user_id(self) -> str: | ||||
|         return self.event.sender.sender_id.open_id | ||||
|  | ||||
|     def get_all_user_id(self) -> UserId: | ||||
|         return self.event.sender.sender_id | ||||
|  | ||||
|     @overrides(Event) | ||||
|     def get_session_id(self) -> str: | ||||
|         return f"{self.event.message.chat_type}_{self.event.message.chat_id}_{self.get_user_id()}" | ||||
|  | ||||
|  | ||||
| class GroupMessageEvent(MessageEvent): | ||||
|     __event__ = "im.message.receive_v1.group" | ||||
|     event: GroupMessageEventDetail | ||||
|  | ||||
|  | ||||
| class PrivateMessageEvent(MessageEvent): | ||||
|     __event__ = "im.message.receive_v1.p2p" | ||||
|     event: PrivateMessageEventDetail | ||||
|  | ||||
|  | ||||
| class NoticeEvent(Event): | ||||
|     event: Dict[str, Any] | ||||
|  | ||||
|     @overrides(Event) | ||||
|     def get_type(self) -> Literal["message", "notice"]: | ||||
|         return "notice" | ||||
|  | ||||
|     @overrides(Event) | ||||
|     def get_event_name(self) -> str: | ||||
|         return self.header.event_type | ||||
|  | ||||
|     @overrides(Event) | ||||
|     def get_event_description(self) -> str: | ||||
|         return str(self.dict()) | ||||
|  | ||||
|     @overrides(Event) | ||||
|     def get_message(self) -> Message: | ||||
|         raise ValueError("Event has no message!") | ||||
|  | ||||
|     @overrides(Event) | ||||
|     def get_plaintext(self) -> str: | ||||
|         raise ValueError("Event has no plaintext!") | ||||
|  | ||||
|     @overrides(Event) | ||||
|     def get_user_id(self) -> str: | ||||
|         raise ValueError("Event has no user_id!") | ||||
|  | ||||
|     @overrides(Event) | ||||
|     def get_session_id(self) -> str: | ||||
|         raise ValueError("Event has no session_id!") | ||||
|  | ||||
|  | ||||
| class MessageReader(BaseModel): | ||||
|     reader_id: UserId | ||||
|     read_time: str | ||||
|     tenant_key: str | ||||
|  | ||||
|  | ||||
| class MessageReadEventDetail(BaseModel): | ||||
|     reader: MessageReader | ||||
|     message_id_list: List[str] | ||||
|  | ||||
|  | ||||
| class MessageReadEvent(NoticeEvent): | ||||
|     __event__ = "im.message.message_read_v1" | ||||
|     event: MessageReadEventDetail | ||||
|  | ||||
|  | ||||
| class GroupDisbandedEventDetail(BaseModel): | ||||
|     chat_id: str | ||||
|     operator_id: UserId | ||||
|     external: bool | ||||
|     operator_tenant_key: str | ||||
|  | ||||
|  | ||||
| class GroupDisbandedEvent(NoticeEvent): | ||||
|     __event__ = "im.chat.disbanded_v1" | ||||
|     event: GroupDisbandedEventDetail | ||||
|  | ||||
|  | ||||
| class I18nNames(BaseModel): | ||||
|     zh_cn: str | ||||
|     en_us: str | ||||
|     ja_jp: str | ||||
|  | ||||
|  | ||||
| class ChatChange(BaseModel): | ||||
|     avatar: str | ||||
|     name: str | ||||
|     description: str | ||||
|     i18n_names: I18nNames | ||||
|     add_member_permission: str | ||||
|     share_card_permission: str | ||||
|     at_all_permission: str | ||||
|     edit_permission: str | ||||
|     membership_approval: str | ||||
|     join_message_visibility: str | ||||
|     leave_message_visibility: str | ||||
|     moderation_permission: str | ||||
|     owner_id: UserId | ||||
|  | ||||
|  | ||||
| class EventModerator(BaseModel): | ||||
|     tenant_key: str | ||||
|     user_id: UserId | ||||
|  | ||||
|  | ||||
| class ModeratorList(BaseModel): | ||||
|     added_member_list: EventModerator | ||||
|     removed_member_list: EventModerator | ||||
|  | ||||
|  | ||||
| class GroupConfigUpdatedEventDetail(BaseModel): | ||||
|     chat_id: str | ||||
|     operator_id: UserId | ||||
|     external: bool | ||||
|     operator_tenant_key: str | ||||
|     after_change: ChatChange | ||||
|     before_change: ChatChange | ||||
|     moderator_list: ModeratorList | ||||
|  | ||||
|  | ||||
| class GroupConfigUpdatedEvent(NoticeEvent): | ||||
|     __event__ = "im.chat.updated_v1" | ||||
|     event: GroupConfigUpdatedEventDetail | ||||
|  | ||||
|  | ||||
| class GroupMemberBotAddedEventDetail(BaseModel): | ||||
|     chat_id: str | ||||
|     operator_id: UserId | ||||
|     external: bool | ||||
|     operator_tenant_key: str | ||||
|  | ||||
|  | ||||
| class GroupMemberBotAddedEvent(NoticeEvent): | ||||
|     __event__ = "im.chat.member.bot.added_v1" | ||||
|     event: GroupMemberBotAddedEventDetail | ||||
|  | ||||
|  | ||||
| class GroupMemberBotDeletedEventDetail(BaseModel): | ||||
|     chat_id: str | ||||
|     operator_id: UserId | ||||
|     external: bool | ||||
|     operator_tenant_key: str | ||||
|  | ||||
|  | ||||
| class GroupMemberBotDeletedEvent(NoticeEvent): | ||||
|     __event__ = "im.chat.member.bot.deleted_v1" | ||||
|     event: GroupMemberBotDeletedEventDetail | ||||
|  | ||||
|  | ||||
| class ChatMemberUser(BaseModel): | ||||
|     name: str | ||||
|     tenant_key: str | ||||
|     user_id: UserId | ||||
|  | ||||
|  | ||||
| class GroupMemberUserAddedEventDetail(BaseModel): | ||||
|     chat_id: str | ||||
|     operator_id: UserId | ||||
|     external: bool | ||||
|     operator_tenant_key: str | ||||
|     users: List[ChatMemberUser] | ||||
|  | ||||
|  | ||||
| class GroupMemberUserAddedEvent(NoticeEvent): | ||||
|     __event__ = "im.chat.member.user.added_v1" | ||||
|     event: GroupMemberUserAddedEventDetail | ||||
|  | ||||
|  | ||||
| class GroupMemberUserWithdrawnEventDetail(BaseModel): | ||||
|     chat_id: str | ||||
|     operator_id: UserId | ||||
|     external: bool | ||||
|     operator_tenant_key: str | ||||
|     users: List[ChatMemberUser] | ||||
|  | ||||
|  | ||||
| class GroupMemberUserWithdrawnEvent(NoticeEvent): | ||||
|     __event__ = "im.chat.member.user.withdrawn_v1" | ||||
|     event: GroupMemberUserWithdrawnEventDetail | ||||
|  | ||||
|  | ||||
| class GroupMemberUserDeletedEventDetail(BaseModel): | ||||
|     chat_id: str | ||||
|     operator_id: UserId | ||||
|     external: bool | ||||
|     operator_tenant_key: str | ||||
|     users: List[ChatMemberUser] | ||||
|  | ||||
|  | ||||
| class GroupMemberUserDeletedEvent(NoticeEvent): | ||||
|     __event__ = "im.chat.member.user.deleted_v1" | ||||
|     event: GroupMemberUserDeletedEventDetail | ||||
|  | ||||
|  | ||||
| class AvatarInfo(BaseModel): | ||||
|     avatar_72: str | ||||
|     avatar_240: str | ||||
|     avatar_640: str | ||||
|     avatar_origin: str | ||||
|  | ||||
|  | ||||
| class UserStatus(BaseModel): | ||||
|     is_frozen: bool | ||||
|     is_resigned: bool | ||||
|     is_activated: bool | ||||
|  | ||||
|  | ||||
| class UserOrder(BaseModel): | ||||
|     department_id: str | ||||
|     user_order: int | ||||
|     department_order: int | ||||
|  | ||||
|  | ||||
| class UserCustomAttrValue(BaseModel): | ||||
|     text: str | ||||
|     url: str | ||||
|     pc_url: str | ||||
|  | ||||
|  | ||||
| class UserCustomAttr(BaseModel): | ||||
|     type: str | ||||
|     id: str | ||||
|     value: UserCustomAttrValue | ||||
|  | ||||
|  | ||||
| class ContactUser(BaseModel): | ||||
|     open_id: str | ||||
|     user_id: str | ||||
|     name: str | ||||
|     en_name: str | ||||
|     email: str | ||||
|     mobile: str | ||||
|     gender: int | ||||
|     avatar: AvatarInfo | ||||
|     status: UserStatus | ||||
|     department_ids: Optional[List[str]] | ||||
|     leader_user_id: str | ||||
|     city: str | ||||
|     country: str | ||||
|     work_station: str | ||||
|     join_time: int | ||||
|     employee_no: str | ||||
|     employee_type: int | ||||
|     orders: Optional[List[UserOrder]] | ||||
|     custom_attrs: List[UserCustomAttr] | ||||
|  | ||||
|  | ||||
| class OldContactUser(BaseModel): | ||||
|     department_ids: List[str] | ||||
|     open_id: str | ||||
|  | ||||
|  | ||||
| class ContactUserUpdatedEventDetail(BaseModel): | ||||
|     object: ContactUser | ||||
|     old_object: ContactUser | ||||
|  | ||||
|  | ||||
| class ContactUserUpdatedEvent(NoticeEvent): | ||||
|     __event__ = "contact.user.updated_v3" | ||||
|     event: ContactUserUpdatedEventDetail | ||||
|  | ||||
|  | ||||
| class ContactUserDeletedEventDetail(NoticeEvent): | ||||
|     object: ContactUser | ||||
|     old_object: OldContactUser | ||||
|  | ||||
|  | ||||
| class ContactUserDeletedEvent(NoticeEvent): | ||||
|     __event__ = "contact.user.deleted_v3" | ||||
|     event: ContactUserDeletedEventDetail | ||||
|  | ||||
|  | ||||
| class ContactUserCreatedEventDetail(BaseModel): | ||||
|     object: ContactUser | ||||
|  | ||||
|  | ||||
| class ContactUserCreatedEvent(NoticeEvent): | ||||
|     __event__ = "contact.user.created_v3" | ||||
|     event: ContactUserCreatedEventDetail | ||||
|  | ||||
|  | ||||
| class ContactDepartmentStatus(BaseModel): | ||||
|     is_deleted: bool | ||||
|  | ||||
|  | ||||
| class ContactDepartment(BaseModel): | ||||
|     name: str | ||||
|     parent_department_id: str | ||||
|     department_id: str | ||||
|     open_department_id: str | ||||
|     leader_user_id: str | ||||
|     chat_id: str | ||||
|     order: int | ||||
|     status: ContactDepartmentStatus | ||||
|  | ||||
|  | ||||
| class ContactDepartmentUpdatedEventDetail(BaseModel): | ||||
|     object: ContactDepartment | ||||
|     old_object: ContactDepartment | ||||
|  | ||||
|  | ||||
| class ContactDepartmentUpdatedEvent(NoticeEvent): | ||||
|     __event__ = "contact.department.updated_v3" | ||||
|     event: ContactDepartmentUpdatedEventDetail | ||||
|  | ||||
|  | ||||
| class OldContactDepartment(BaseModel): | ||||
|     status: ContactDepartmentStatus | ||||
|     open_department_id: str | ||||
|  | ||||
|  | ||||
| class ContactDepartmentDeletedEventDetail(NoticeEvent): | ||||
|     object: ContactDepartment | ||||
|     old_object: OldContactDepartment | ||||
|  | ||||
|  | ||||
| class ContactDepartmentDeletedEvent(NoticeEvent): | ||||
|     __event__ = "contact.department.deleted_v3" | ||||
|     event: ContactDepartmentDeletedEventDetail | ||||
|  | ||||
|  | ||||
| class ContactDepartmentCreatedEventDetail(BaseModel): | ||||
|     object: ContactDepartment | ||||
|  | ||||
|  | ||||
| class ContactDepartmentCreatedEvent(NoticeEvent): | ||||
|     __event__ = "contact.department.created_v3" | ||||
|     event: ContactDepartmentCreatedEventDetail | ||||
|  | ||||
|  | ||||
| class CalendarAclScope(BaseModel): | ||||
|     type: str | ||||
|     user_id: str | ||||
|  | ||||
|  | ||||
| class CalendarAclCreatedEventDetail(BaseModel): | ||||
|     acl_id: str | ||||
|     role: str | ||||
|     scope: CalendarAclScope | ||||
|  | ||||
|  | ||||
| class CalendarAclCreatedEvent(NoticeEvent): | ||||
|     __event__ = "calendar.calendar.acl.created_v4" | ||||
|     event: CalendarAclCreatedEventDetail | ||||
|  | ||||
|  | ||||
| class CalendarAclDeletedEventDetail(BaseModel): | ||||
|     acl_id: str | ||||
|     role: str | ||||
|     scope: CalendarAclScope | ||||
|  | ||||
|  | ||||
| class CalendarAclDeletedEvent(NoticeEvent): | ||||
|     __event__ = "calendar.calendar.acl.deleted_v4" | ||||
|     event: CalendarAclDeletedEventDetail | ||||
|  | ||||
|  | ||||
| class CalendarChangedEvent(NoticeEvent): | ||||
|     __event__ = "calendar.calendar.changed_v4" | ||||
|     event: dict | ||||
|  | ||||
|  | ||||
| class CalendarEventChangedEventDetail(BaseModel): | ||||
|     calendar_id: str | ||||
|  | ||||
|  | ||||
| class CalendarEventChangedEvent(NoticeEvent): | ||||
|     __event__ = "calendar.calendar.event.changed_v4" | ||||
|     event: CalendarEventChangedEventDetail | ||||
|  | ||||
|  | ||||
| class DriveFileReadEventDetail(BaseModel): | ||||
|     file_token: str | ||||
|     file_type: str | ||||
|     operator_id_list: List[UserId] | ||||
|  | ||||
|  | ||||
| class DriveFileReadEvent(NoticeEvent): | ||||
|     __event__ = "drive.file.read_v1" | ||||
|     event: DriveFileReadEventDetail | ||||
|  | ||||
|  | ||||
| class DriveFileTitleUpdatedEventDetail(BaseModel): | ||||
|     file_token: str | ||||
|     file_type: str | ||||
|     operator_id: UserId | ||||
|  | ||||
|  | ||||
| class DriveFileTitleUpdatedEvent(NoticeEvent): | ||||
|     __event__ = "drive.file.title_updated_v1" | ||||
|     event: DriveFileTitleUpdatedEventDetail | ||||
|  | ||||
|  | ||||
| class DriveFilePermissionMemberAddedEventDetail(BaseModel): | ||||
|     chat_list: List[str] | ||||
|     file_token: str | ||||
|     file_type: str | ||||
|     operator_id: UserId | ||||
|     user_list: List[UserId] | ||||
|  | ||||
|  | ||||
| class DriveFilePermissionMemberAddedEvent(NoticeEvent): | ||||
|     __event__ = "drive.file.permission_member_added_v1" | ||||
|     event: DriveFilePermissionMemberAddedEventDetail | ||||
|  | ||||
|  | ||||
| class DriveFilePermissionMemberRemovedEventDetail(BaseModel): | ||||
|     chat_list: List[str] | ||||
|     file_token: str | ||||
|     file_type: str | ||||
|     operator_id: UserId | ||||
|     user_list: List[UserId] | ||||
|  | ||||
|  | ||||
| class DriveFilePermissionMemberRemovedEvent(NoticeEvent): | ||||
|     __event__ = "drive.file.permission_member_removed_v1" | ||||
|     event: DriveFilePermissionMemberRemovedEventDetail | ||||
|  | ||||
|  | ||||
| class DriveFileTrashedEventDetail(BaseModel): | ||||
|     file_token: str | ||||
|     file_type: str | ||||
|     operator_id: UserId | ||||
|  | ||||
|  | ||||
| class DriveFileTrashedEvent(NoticeEvent): | ||||
|     __event__ = "drive.file.trashed_v1" | ||||
|     event: DriveFileTrashedEventDetail | ||||
|  | ||||
|  | ||||
| class DriveFileDeletedEventDetail(BaseModel): | ||||
|     file_token: str | ||||
|     file_type: str | ||||
|     operator_id: UserId | ||||
|  | ||||
|  | ||||
| class DriveFileDeletedEvent(NoticeEvent): | ||||
|     __event__ = "drive.file.deleted_v1" | ||||
|     event: DriveFileDeletedEventDetail | ||||
|  | ||||
|  | ||||
| class DriveFileEditedEventDetail(BaseModel): | ||||
|     file_token: str | ||||
|     file_type: str | ||||
|     operator_id_list: List[UserId] | ||||
|     subscriber_id_list: List[UserId] | ||||
|  | ||||
|  | ||||
| class DriveFileEditedEvent(NoticeEvent): | ||||
|     __event__ = "drive.file.edit_v1" | ||||
|     event: DriveFileEditedEventDetail | ||||
|  | ||||
|  | ||||
| class MeetingRoomCreatedEventDetail(BaseModel): | ||||
|     room_id: str | ||||
|     room_name: str | ||||
|  | ||||
|  | ||||
| class MeetingRoomCreatedEvent(NoticeEvent): | ||||
|     __event__ = "meeting_room.meeting_room.created_v1" | ||||
|     event: MeetingRoomCreatedEventDetail | ||||
|  | ||||
|  | ||||
| class MeetingRoomUpdatedEventDetail(BaseModel): | ||||
|     room_id: str | ||||
|     room_name: str | ||||
|  | ||||
|  | ||||
| class MeetingRoomUpdatedEvent(NoticeEvent): | ||||
|     __event__ = "meeting_room.meeting_room.updated_v1" | ||||
|     event: MeetingRoomUpdatedEventDetail | ||||
|  | ||||
|  | ||||
| class MeetingRoomDeletedEventDetail(BaseModel): | ||||
|     room_id: str | ||||
|     room_name: str | ||||
|  | ||||
|  | ||||
| class MeetingRoomDeletedEvent(NoticeEvent): | ||||
|     __event__ = "meeting_room.meeting_room.deleted_v1" | ||||
|     event: MeetingRoomDeletedEventDetail | ||||
|  | ||||
|  | ||||
| class MeetingRoomStatusChangedEventDetail(BaseModel): | ||||
|     room_id: str | ||||
|     room_name: str | ||||
|  | ||||
|  | ||||
| class MeetingRoomStatusChangedEvent(NoticeEvent): | ||||
|     __event__ = "meeting_room.meeting_room.status_changed_v1" | ||||
|     event: MeetingRoomStatusChangedEventDetail | ||||
|  | ||||
|  | ||||
| class MeetingUser(BaseModel): | ||||
|     id: UserId | ||||
|     user_role: Optional[int] | ||||
|     user_type: Optional[int] | ||||
|  | ||||
|  | ||||
| class Meeting(BaseModel): | ||||
|     id: str | ||||
|     topic: str | ||||
|     meeting_no: str | ||||
|     start_time: Optional[str] | ||||
|     end_time: Optional[str] | ||||
|     host_user: Optional[MeetingUser] | ||||
|     owner: MeetingUser | ||||
|  | ||||
|  | ||||
| class VCMeetingStartedEventDetail(BaseModel): | ||||
|     meeting: Meeting | ||||
|     operator: MeetingUser | ||||
|  | ||||
|  | ||||
| class VCMeetingStartedEvent(NoticeEvent): | ||||
|     __event__ = "vc.meeting.meeting_started_v1" | ||||
|     event: VCMeetingStartedEventDetail | ||||
|  | ||||
|  | ||||
| class VCMeetingEndedEventDetail(BaseModel): | ||||
|     meeting: Meeting | ||||
|     operator: MeetingUser | ||||
|  | ||||
|  | ||||
| class VCMeetingEndedEvent(NoticeEvent): | ||||
|     __event__ = "vc.meeting.meeting_ended_v1" | ||||
|     event: VCMeetingEndedEventDetail | ||||
|  | ||||
|  | ||||
| class VCMeetingJoinedEventDetail(BaseModel): | ||||
|     meeting: Meeting | ||||
|     operator: MeetingUser | ||||
|  | ||||
|  | ||||
| class VCMeetingJoinedEvent(NoticeEvent): | ||||
|     __event__ = "vc.meeting.join_meeting_v1" | ||||
|     event: VCMeetingJoinedEventDetail | ||||
|  | ||||
|  | ||||
| class VCMeetingLeftEventDetail(BaseModel): | ||||
|     meeting: Meeting | ||||
|     operator: MeetingUser | ||||
|     leave_reason: int | ||||
|  | ||||
|  | ||||
| class VCMeetingLeftEvent(NoticeEvent): | ||||
|     __event__ = "vc.meeting.leave_meeting_v1" | ||||
|     event: VCMeetingLeftEventDetail | ||||
|  | ||||
|  | ||||
| class VCMeetingRecordingStartedEventDetail(BaseModel): | ||||
|     meeting: Meeting | ||||
|     operator: MeetingUser | ||||
|  | ||||
|  | ||||
| class VCMeetingRecordingStartedEvent(NoticeEvent): | ||||
|     __event__ = "vc.meeting.recording_started_v1" | ||||
|     event: VCMeetingRecordingStartedEventDetail | ||||
|  | ||||
|  | ||||
| class VCMeetingRecordingEndedEventDetail(BaseModel): | ||||
|     meeting: Meeting | ||||
|     operator: MeetingUser | ||||
|  | ||||
|  | ||||
| class VCMeetingRecordingEndedEvent(NoticeEvent): | ||||
|     __event__ = "vc.meeting.recording_ended_v1" | ||||
|     event: VCMeetingRecordingEndedEventDetail | ||||
|  | ||||
|  | ||||
| class VCMeetingRecordingReadyEventDetail(BaseModel): | ||||
|     meeting: Meeting | ||||
|     url: str | ||||
|     duration: str | ||||
|  | ||||
|  | ||||
| class VCMeetingRecordingReadyEvent(NoticeEvent): | ||||
|     __event__ = "vc.meeting.recording_ready_v1" | ||||
|     event: VCMeetingRecordingReadyEventDetail | ||||
|  | ||||
|  | ||||
| class VCMeetingShareStartedEventDetail(BaseModel): | ||||
|     meeting: Meeting | ||||
|     operator: MeetingUser | ||||
|  | ||||
|  | ||||
| class VCMeetingShareStartedEvent(NoticeEvent): | ||||
|     __event__ = "vc.meeting.share_started_v1" | ||||
|     event: VCMeetingShareStartedEventDetail | ||||
|  | ||||
|  | ||||
| class VCMeetingShareEndedEventDetail(BaseModel): | ||||
|     meeting: Meeting | ||||
|     operator: MeetingUser | ||||
|  | ||||
|  | ||||
| class VCMeetingShareEndedEvent(NoticeEvent): | ||||
|     __event__ = "vc.meeting.share_ended_v1" | ||||
|     event: VCMeetingShareEndedEventDetail | ||||
|  | ||||
|  | ||||
| class AttendanceUserFlowCreatedEventDetail(BaseModel): | ||||
|     bssid: str | ||||
|     check_time: str | ||||
|     comment: str | ||||
|     employee_id: str | ||||
|     employee_no: str | ||||
|     is_field: bool | ||||
|     is_wifi: bool | ||||
|     latitude: float | ||||
|     location_name: str | ||||
|     longitude: float | ||||
|     photo_urls: Optional[List[str]] | ||||
|     record_id: str | ||||
|     ssid: str | ||||
|     type: int | ||||
|  | ||||
|  | ||||
| class AttendanceUserFlowCreatedEvent(NoticeEvent): | ||||
|     __event__ = "attendance.user_flow.created_v1" | ||||
|     event: AttendanceUserFlowCreatedEventDetail | ||||
|  | ||||
|  | ||||
| class AttendanceUserTaskStatusDiff(BaseModel): | ||||
|     before_status: str | ||||
|     before_supplement: str | ||||
|     current_status: str | ||||
|     current_supplement: str | ||||
|     index: int | ||||
|     work_type: str | ||||
|  | ||||
|  | ||||
| class AttendanceUserTaskUpdatedEventDetail(BaseModel): | ||||
|     date: int | ||||
|     employee_id: str | ||||
|     employee_no: str | ||||
|     group_id: str | ||||
|     shift_id: str | ||||
|     status_changes: List[AttendanceUserTaskStatusDiff] | ||||
|     task_id: str | ||||
|     time_zone: str | ||||
|  | ||||
|  | ||||
| class AttendanceUserTaskUpdatedEvent(NoticeEvent): | ||||
|     __event__ = "attendance.user_task.updated_v1" | ||||
|     event: AttendanceUserTaskUpdatedEventDetail | ||||
|  | ||||
|  | ||||
| _t = StringTrie(separator=".") | ||||
|  | ||||
| # define `model` first to avoid globals changing while `for` | ||||
| model = None | ||||
| for model in globals().values(): | ||||
|     if not inspect.isclass(model) or not issubclass(model, Event): | ||||
|         continue | ||||
|     _t["." + model.__event__] = model | ||||
|  | ||||
|  | ||||
| def get_event_model(event_name) -> List[Type[Event]]: | ||||
|     """ | ||||
|     :说明: | ||||
|  | ||||
|       根据事件名获取对应 ``Event Model`` 及 ``FallBack Event Model`` 列表 | ||||
|  | ||||
|     :返回: | ||||
|  | ||||
|       - ``List[Type[Event]]`` | ||||
|     """ | ||||
|     return [model.value for model in _t.prefixes("." + event_name)][::-1] | ||||
| @@ -1,63 +0,0 @@ | ||||
| from typing import Optional | ||||
|  | ||||
| from nonebot.exception import AdapterException | ||||
| from nonebot.exception import ActionFailed as BaseActionFailed | ||||
| from nonebot.exception import NetworkError as BaseNetworkError | ||||
| from nonebot.exception import ApiNotAvailable as BaseApiNotAvailable | ||||
|  | ||||
|  | ||||
| class FeishuAdapterException(AdapterException): | ||||
|     def __init__(self): | ||||
|         super().__init__("feishu") | ||||
|  | ||||
|  | ||||
| class ActionFailed(BaseActionFailed, FeishuAdapterException): | ||||
|     """ | ||||
|     :说明: | ||||
|  | ||||
|       API 请求返回错误信息。 | ||||
|  | ||||
|     :参数: | ||||
|  | ||||
|       * ``retcode: Optional[int]``: 错误码 | ||||
|     """ | ||||
|  | ||||
|     def __init__(self, **kwargs): | ||||
|         super().__init__() | ||||
|         self.info = kwargs | ||||
|  | ||||
|     def __repr__(self): | ||||
|         return ( | ||||
|             f"<ActionFailed " | ||||
|             + ", ".join(f"{k}={v}" for k, v in self.info.items()) | ||||
|             + ">" | ||||
|         ) | ||||
|  | ||||
|     def __str__(self): | ||||
|         return self.__repr__() | ||||
|  | ||||
|  | ||||
| class NetworkError(BaseNetworkError, FeishuAdapterException): | ||||
|     """ | ||||
|     :说明: | ||||
|  | ||||
|       网络错误。 | ||||
|  | ||||
|     :参数: | ||||
|  | ||||
|       * ``retcode: Optional[int]``: 错误码 | ||||
|     """ | ||||
|  | ||||
|     def __init__(self, msg: Optional[str] = None): | ||||
|         super().__init__() | ||||
|         self.msg = msg | ||||
|  | ||||
|     def __repr__(self): | ||||
|         return f"<NetWorkError message={self.msg}>" | ||||
|  | ||||
|     def __str__(self): | ||||
|         return self.__repr__() | ||||
|  | ||||
|  | ||||
| class ApiNotAvailable(BaseApiNotAvailable, FeishuAdapterException): | ||||
|     pass | ||||
| @@ -1,262 +0,0 @@ | ||||
| import json | ||||
| import itertools | ||||
| from dataclasses import dataclass | ||||
| from typing import ( | ||||
|     Any, | ||||
|     Dict, | ||||
|     List, | ||||
|     Type, | ||||
|     Tuple, | ||||
|     Union, | ||||
|     Mapping, | ||||
|     Iterable, | ||||
|     Optional, | ||||
|     cast, | ||||
| ) | ||||
|  | ||||
| from nonebot.typing import overrides | ||||
| from nonebot.adapters import Message as BaseMessage | ||||
| from nonebot.adapters import MessageSegment as BaseMessageSegment | ||||
|  | ||||
|  | ||||
| class MessageSegment(BaseMessageSegment["Message"]): | ||||
|     """ | ||||
|     飞书 协议 MessageSegment 适配。具体方法参考协议消息段类型或源码。 | ||||
|     """ | ||||
|  | ||||
|     @classmethod | ||||
|     @overrides(BaseMessageSegment) | ||||
|     def get_message_class(cls) -> Type["Message"]: | ||||
|         return Message | ||||
|  | ||||
|     @property | ||||
|     def segment_text(self) -> dict: | ||||
|         return { | ||||
|             "image": "[图片]", | ||||
|             "file": "[文件]", | ||||
|             "audio": "[音频]", | ||||
|             "media": "[视频]", | ||||
|             "sticker": "[表情包]", | ||||
|             "interactive": "[消息卡片]", | ||||
|             "hongbao": "[红包]", | ||||
|             "share_calendar_event": "[日程卡片]", | ||||
|             "share_chat": "[群名片]", | ||||
|             "share_user": "[个人名片]", | ||||
|             "system": "[系统消息]", | ||||
|             "location": "[位置]", | ||||
|             "video_chat": "[视频通话]", | ||||
|         } | ||||
|  | ||||
|     def __str__(self) -> str: | ||||
|         if self.type in ["text", "hongbao", "a"]: | ||||
|             return str(self.data["text"]) | ||||
|         elif self.type == "at": | ||||
|             return str(f"@{self.data['user_name']}") | ||||
|         else: | ||||
|             return self.segment_text.get(self.type, "") | ||||
|  | ||||
|     @overrides(BaseMessageSegment) | ||||
|     def __add__(self, other) -> "Message": | ||||
|         return Message(self) + ( | ||||
|             MessageSegment.text(other) if isinstance(other, str) else other | ||||
|         ) | ||||
|  | ||||
|     @overrides(BaseMessageSegment) | ||||
|     def __radd__(self, other) -> "Message": | ||||
|         return ( | ||||
|             MessageSegment.text(other) if isinstance(other, str) else Message(other) | ||||
|         ) + self | ||||
|  | ||||
|     @overrides(BaseMessageSegment) | ||||
|     def is_text(self) -> bool: | ||||
|         return self.type == "text" | ||||
|  | ||||
|     # 接收消息 | ||||
|     @staticmethod | ||||
|     def at(user_id: str) -> "MessageSegment": | ||||
|         return MessageSegment("at", {"user_id": user_id}) | ||||
|  | ||||
|     # 发送消息 | ||||
|     @staticmethod | ||||
|     def text(text: str) -> "MessageSegment": | ||||
|         return MessageSegment("text", {"text": text}) | ||||
|  | ||||
|     @staticmethod | ||||
|     def post(title: str, content: list) -> "MessageSegment": | ||||
|         return MessageSegment("post", {"title": title, "content": content}) | ||||
|  | ||||
|     @staticmethod | ||||
|     def image(image_key: str) -> "MessageSegment": | ||||
|         return MessageSegment("image", {"image_key": image_key}) | ||||
|  | ||||
|     @staticmethod | ||||
|     def interactive(title: str, elements: list) -> "MessageSegment": | ||||
|         return MessageSegment("interactive", {"title": title, "elements": elements}) | ||||
|  | ||||
|     @staticmethod | ||||
|     def share_chat(chat_id: str) -> "MessageSegment": | ||||
|         return MessageSegment("share_chat", {"chat_id": chat_id}) | ||||
|  | ||||
|     @staticmethod | ||||
|     def share_user(user_id: str) -> "MessageSegment": | ||||
|         return MessageSegment("share_user", {"user_id": user_id}) | ||||
|  | ||||
|     @staticmethod | ||||
|     def audio(file_key: str, duration: int) -> "MessageSegment": | ||||
|         return MessageSegment("audio", {"file_key": file_key, "duration": duration}) | ||||
|  | ||||
|     @staticmethod | ||||
|     def media( | ||||
|         file_key: str, image_key: str, file_name: str, duration: int | ||||
|     ) -> "MessageSegment": | ||||
|         return MessageSegment( | ||||
|             "media", | ||||
|             { | ||||
|                 "file_key": file_key, | ||||
|                 "image_key": image_key, | ||||
|                 "file_name": file_name, | ||||
|                 "duration": duration, | ||||
|             }, | ||||
|         ) | ||||
|  | ||||
|     @staticmethod | ||||
|     def file(file_key: str, file_name: str) -> "MessageSegment": | ||||
|         return MessageSegment("file", {"file_key": file_key, "file_name": file_name}) | ||||
|  | ||||
|     @staticmethod | ||||
|     def sticker(file_key) -> "MessageSegment": | ||||
|         return MessageSegment("sticker", {"file_key": file_key}) | ||||
|  | ||||
|  | ||||
| class Message(BaseMessage[MessageSegment]): | ||||
|     """ | ||||
|     飞书 协议 Message 适配。 | ||||
|     """ | ||||
|  | ||||
|     @classmethod | ||||
|     @overrides(BaseMessage) | ||||
|     def get_segment_class(cls) -> Type[MessageSegment]: | ||||
|         return MessageSegment | ||||
|  | ||||
|     @overrides(BaseMessage) | ||||
|     def __add__(self, other: Union[str, Mapping, Iterable[Mapping]]) -> "Message": | ||||
|         return super(Message, self).__add__( | ||||
|             MessageSegment.text(other) if isinstance(other, str) else other | ||||
|         ) | ||||
|  | ||||
|     @overrides(BaseMessage) | ||||
|     def __radd__(self, other: Union[str, Mapping, Iterable[Mapping]]) -> "Message": | ||||
|         return super(Message, self).__radd__( | ||||
|             MessageSegment.text(other) if isinstance(other, str) else other | ||||
|         ) | ||||
|  | ||||
|     @staticmethod | ||||
|     @overrides(BaseMessage) | ||||
|     def _construct( | ||||
|         msg: Union[str, Mapping, Iterable[Mapping]] | ||||
|     ) -> Iterable[MessageSegment]: | ||||
|         if isinstance(msg, Mapping): | ||||
|             msg = cast(Mapping[str, Any], msg) | ||||
|             yield MessageSegment(msg["type"], msg.get("data") or {}) | ||||
|             return | ||||
|         elif isinstance(msg, str): | ||||
|             yield MessageSegment.text(msg) | ||||
|         elif isinstance(msg, Iterable): | ||||
|             for seg in msg: | ||||
|                 if isinstance(seg, MessageSegment): | ||||
|                     yield seg | ||||
|                 else: | ||||
|                     yield MessageSegment(seg["type"], seg.get("data") or {}) | ||||
|  | ||||
|     def _merge(self) -> "Message": | ||||
|         i: int | ||||
|         seg: MessageSegment | ||||
|         msg: List[MessageSegment] = [] | ||||
|         for i, seg in enumerate(self): | ||||
|             if seg.type == "text" and i != 0 and msg[-1].type == "text": | ||||
|                 msg[-1] = MessageSegment( | ||||
|                     "text", {"text": msg[-1].data["text"] + seg.data["text"]} | ||||
|                 ) | ||||
|             else: | ||||
|                 msg.append(seg) | ||||
|         return Message(msg) | ||||
|  | ||||
|     @overrides(BaseMessage) | ||||
|     def extract_plain_text(self) -> str: | ||||
|         return "".join(seg.data["text"] for seg in self if seg.is_text()) | ||||
|  | ||||
|  | ||||
| @dataclass | ||||
| class MessageSerializer: | ||||
|     """ | ||||
|     飞书 协议 Message 序列化器。 | ||||
|     """ | ||||
|  | ||||
|     message: Message | ||||
|  | ||||
|     def serialize(self) -> Tuple[str, str]: | ||||
|         segments = list(self.message) | ||||
|         last_segment_type: str = "" | ||||
|         if len(segments) > 1: | ||||
|             msg = {"title": "", "content": [[]]} | ||||
|             for segment in segments: | ||||
|                 if segment == "image": | ||||
|                     if last_segment_type != "image": | ||||
|                         msg["content"].append([]) | ||||
|                 else: | ||||
|                     if last_segment_type == "image": | ||||
|                         msg["content"].append([]) | ||||
|                 msg["content"][-1].append( | ||||
|                     { | ||||
|                         "tag": segment.type if segment.type != "image" else "img", | ||||
|                         **segment.data, | ||||
|                     } | ||||
|                 ) | ||||
|                 last_segment_type = segment.type | ||||
|             return "post", json.dumps({"zh_cn": {**msg}}) | ||||
|  | ||||
|         else: | ||||
|             return self.message[0].type, json.dumps(self.message[0].data) | ||||
|  | ||||
|  | ||||
| @dataclass | ||||
| class MessageDeserializer: | ||||
|     """ | ||||
|     飞书 协议 Message 反序列化器。 | ||||
|     """ | ||||
|  | ||||
|     type: str | ||||
|     data: Dict[str, Any] | ||||
|     mentions: Optional[List[dict]] | ||||
|  | ||||
|     def deserialize(self) -> Message: | ||||
|         dict_mention = {} | ||||
|         if self.mentions: | ||||
|             for mention in self.mentions: | ||||
|                 dict_mention[mention["key"]] = mention | ||||
|  | ||||
|         if self.type == "post": | ||||
|             msg = Message() | ||||
|             if self.data["title"] != "": | ||||
|                 msg += MessageSegment("text", {"text": self.data["title"]}) | ||||
|  | ||||
|             for seg in itertools.chain(*self.data["content"]): | ||||
|                 tag = seg.pop("tag") | ||||
|                 if tag == "at": | ||||
|                     seg["user_name"] = dict_mention[seg["user_id"]]["name"] | ||||
|                     seg["user_id"] = dict_mention[seg["user_id"]]["id"]["open_id"] | ||||
|  | ||||
|                 msg += MessageSegment(tag if tag != "img" else "image", seg) | ||||
|  | ||||
|             return msg._merge() | ||||
|         elif self.type == "text": | ||||
|             for key, mention in dict_mention.items(): | ||||
|                 self.data["text"] = self.data["text"].replace( | ||||
|                     key, f"@{mention['name']}" | ||||
|                 ) | ||||
|             self.data["mentions"] = dict_mention | ||||
|  | ||||
|             return Message(MessageSegment(self.type, self.data)) | ||||
|  | ||||
|         else: | ||||
|             return Message(MessageSegment(self.type, self.data)) | ||||
| @@ -1,34 +0,0 @@ | ||||
| import base64 | ||||
| import hashlib | ||||
|  | ||||
| from Crypto.Cipher import AES | ||||
|  | ||||
| from nonebot.utils import logger_wrapper | ||||
|  | ||||
| log = logger_wrapper("FEISHU") | ||||
|  | ||||
|  | ||||
| class AESCipher(object): | ||||
|     def __init__(self, key): | ||||
|         self.block_size = AES.block_size | ||||
|         self.key = hashlib.sha256(AESCipher.str_to_bytes(key)).digest() | ||||
|  | ||||
|     @staticmethod | ||||
|     def str_to_bytes(data): | ||||
|         u_type = type(b"".decode("utf8")) | ||||
|         if isinstance(data, u_type): | ||||
|             return data.encode("utf8") | ||||
|         return data | ||||
|  | ||||
|     @staticmethod | ||||
|     def _unpad(s): | ||||
|         return s[: -ord(s[len(s) - 1 :])] | ||||
|  | ||||
|     def decrypt(self, enc): | ||||
|         iv = enc[: AES.block_size] | ||||
|         cipher = AES.new(self.key, AES.MODE_CBC, iv) | ||||
|         return self._unpad(cipher.decrypt(enc[AES.block_size :])) | ||||
|  | ||||
|     def decrypt_string(self, enc): | ||||
|         enc = base64.b64decode(enc) | ||||
|         return self.decrypt(enc).decode("utf8") | ||||
							
								
								
									
										707
									
								
								packages/nonebot-adapter-feishu/poetry.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										707
									
								
								packages/nonebot-adapter-feishu/poetry.lock
									
									
									
										generated
									
									
									
								
							| @@ -1,707 +0,0 @@ | ||||
| [[package]] | ||||
| name = "aiocache" | ||||
| version = "0.11.1" | ||||
| description = "multi backend asyncio cache" | ||||
| category = "main" | ||||
| optional = false | ||||
| python-versions = "*" | ||||
|  | ||||
| [package.extras] | ||||
| dev = ["asynctest (>=0.11.0)", "codecov", "coverage", "flake8", "ipdb", "marshmallow", "pystache", "pytest", "pytest-asyncio", "pytest-mock", "sphinx", "sphinx-autobuild", "sphinx-rtd-theme", "black"] | ||||
| memcached = ["aiomcache (>=0.5.2)"] | ||||
| msgpack = ["msgpack (>=0.5.5)"] | ||||
| redis = ["aioredis (>=0.3.3)", "aioredis (>=1.0.0)"] | ||||
|  | ||||
| [[package]] | ||||
| name = "anyio" | ||||
| version = "3.3.4" | ||||
| description = "High level compatibility layer for multiple asynchronous event loop implementations" | ||||
| category = "main" | ||||
| optional = false | ||||
| python-versions = ">=3.6.2" | ||||
|  | ||||
| [package.dependencies] | ||||
| idna = ">=2.8" | ||||
| sniffio = ">=1.1" | ||||
| typing-extensions = {version = "*", markers = "python_version < \"3.8\""} | ||||
|  | ||||
| [package.extras] | ||||
| doc = ["sphinx-rtd-theme", "sphinx-autodoc-typehints (>=1.2.0)"] | ||||
| test = ["coverage[toml] (>=4.5)", "hypothesis (>=4.0)", "pytest (>=6.0)", "pytest-mock (>=3.6.1)", "trustme", "uvloop (<0.15)", "mock (>=4)", "uvloop (>=0.15)"] | ||||
| trio = ["trio (>=0.16)"] | ||||
|  | ||||
| [[package]] | ||||
| name = "asgiref" | ||||
| version = "3.4.1" | ||||
| description = "ASGI specs, helper code, and adapters" | ||||
| category = "main" | ||||
| optional = false | ||||
| python-versions = ">=3.6" | ||||
|  | ||||
| [package.dependencies] | ||||
| typing-extensions = {version = "*", markers = "python_version < \"3.8\""} | ||||
|  | ||||
| [package.extras] | ||||
| tests = ["pytest", "pytest-asyncio", "mypy (>=0.800)"] | ||||
|  | ||||
| [[package]] | ||||
| name = "certifi" | ||||
| version = "2021.10.8" | ||||
| description = "Python package for providing Mozilla's CA Bundle." | ||||
| category = "main" | ||||
| optional = false | ||||
| python-versions = "*" | ||||
|  | ||||
| [[package]] | ||||
| name = "charset-normalizer" | ||||
| version = "2.0.7" | ||||
| description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." | ||||
| category = "main" | ||||
| optional = false | ||||
| python-versions = ">=3.5.0" | ||||
|  | ||||
| [package.extras] | ||||
| unicode_backport = ["unicodedata2"] | ||||
|  | ||||
| [[package]] | ||||
| name = "click" | ||||
| version = "8.0.3" | ||||
| description = "Composable command line interface toolkit" | ||||
| category = "main" | ||||
| optional = false | ||||
| python-versions = ">=3.6" | ||||
|  | ||||
| [package.dependencies] | ||||
| colorama = {version = "*", markers = "platform_system == \"Windows\""} | ||||
| importlib-metadata = {version = "*", markers = "python_version < \"3.8\""} | ||||
|  | ||||
| [[package]] | ||||
| name = "colorama" | ||||
| version = "0.4.4" | ||||
| description = "Cross-platform colored terminal text." | ||||
| category = "main" | ||||
| optional = false | ||||
| python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" | ||||
|  | ||||
| [[package]] | ||||
| name = "fastapi" | ||||
| version = "0.70.0" | ||||
| description = "FastAPI framework, high performance, easy to learn, fast to code, ready for production" | ||||
| category = "main" | ||||
| optional = false | ||||
| python-versions = ">=3.6.1" | ||||
|  | ||||
| [package.dependencies] | ||||
| pydantic = ">=1.6.2,<1.7 || >1.7,<1.7.1 || >1.7.1,<1.7.2 || >1.7.2,<1.7.3 || >1.7.3,<1.8 || >1.8,<1.8.1 || >1.8.1,<2.0.0" | ||||
| starlette = "0.16.0" | ||||
|  | ||||
| [package.extras] | ||||
| all = ["requests (>=2.24.0,<3.0.0)", "jinja2 (>=2.11.2,<4.0.0)", "python-multipart (>=0.0.5,<0.0.6)", "itsdangerous (>=1.1.0,<3.0.0)", "pyyaml (>=5.3.1,<6.0.0)", "ujson (>=4.0.1,<5.0.0)", "orjson (>=3.2.1,<4.0.0)", "email_validator (>=1.1.1,<2.0.0)", "uvicorn[standard] (>=0.12.0,<0.16.0)"] | ||||
| dev = ["python-jose[cryptography] (>=3.3.0,<4.0.0)", "passlib[bcrypt] (>=1.7.2,<2.0.0)", "autoflake (>=1.4.0,<2.0.0)", "flake8 (>=3.8.3,<4.0.0)", "uvicorn[standard] (>=0.12.0,<0.16.0)"] | ||||
| doc = ["mkdocs (>=1.1.2,<2.0.0)", "mkdocs-material (>=7.1.9,<8.0.0)", "mdx-include (>=1.4.1,<2.0.0)", "mkdocs-markdownextradata-plugin (>=0.1.7,<0.3.0)", "typer-cli (>=0.0.12,<0.0.13)", "pyyaml (>=5.3.1,<6.0.0)"] | ||||
| test = ["pytest (>=6.2.4,<7.0.0)", "pytest-cov (>=2.12.0,<4.0.0)", "mypy (==0.910)", "flake8 (>=3.8.3,<4.0.0)", "black (==21.9b0)", "isort (>=5.0.6,<6.0.0)", "requests (>=2.24.0,<3.0.0)", "httpx (>=0.14.0,<0.19.0)", "email_validator (>=1.1.1,<2.0.0)", "sqlalchemy (>=1.3.18,<1.5.0)", "peewee (>=3.13.3,<4.0.0)", "databases[sqlite] (>=0.3.2,<0.6.0)", "orjson (>=3.2.1,<4.0.0)", "ujson (>=4.0.1,<5.0.0)", "python-multipart (>=0.0.5,<0.0.6)", "flask (>=1.1.2,<3.0.0)", "anyio[trio] (>=3.2.1,<4.0.0)", "types-ujson (==0.1.1)", "types-orjson (==3.6.0)", "types-dataclasses (==0.1.7)"] | ||||
|  | ||||
| [[package]] | ||||
| name = "h11" | ||||
| version = "0.12.0" | ||||
| description = "A pure-Python, bring-your-own-I/O implementation of HTTP/1.1" | ||||
| category = "main" | ||||
| optional = false | ||||
| python-versions = ">=3.6" | ||||
|  | ||||
| [[package]] | ||||
| name = "h2" | ||||
| version = "4.1.0" | ||||
| description = "HTTP/2 State-Machine based protocol implementation" | ||||
| category = "main" | ||||
| optional = false | ||||
| python-versions = ">=3.6.1" | ||||
|  | ||||
| [package.dependencies] | ||||
| hpack = ">=4.0,<5" | ||||
| hyperframe = ">=6.0,<7" | ||||
|  | ||||
| [[package]] | ||||
| name = "hpack" | ||||
| version = "4.0.0" | ||||
| description = "Pure-Python HPACK header compression" | ||||
| category = "main" | ||||
| optional = false | ||||
| python-versions = ">=3.6.1" | ||||
|  | ||||
| [[package]] | ||||
| name = "httpcore" | ||||
| version = "0.13.7" | ||||
| description = "A minimal low-level HTTP client." | ||||
| category = "main" | ||||
| optional = false | ||||
| python-versions = ">=3.6" | ||||
|  | ||||
| [package.dependencies] | ||||
| anyio = ">=3.0.0,<4.0.0" | ||||
| h11 = ">=0.11,<0.13" | ||||
| sniffio = ">=1.0.0,<2.0.0" | ||||
|  | ||||
| [package.extras] | ||||
| http2 = ["h2 (>=3,<5)"] | ||||
|  | ||||
| [[package]] | ||||
| name = "httptools" | ||||
| version = "0.2.0" | ||||
| description = "A collection of framework independent HTTP protocol utils." | ||||
| category = "main" | ||||
| optional = false | ||||
| python-versions = "*" | ||||
|  | ||||
| [package.extras] | ||||
| test = ["Cython (==0.29.22)"] | ||||
|  | ||||
| [[package]] | ||||
| name = "httpx" | ||||
| version = "0.20.0" | ||||
| description = "The next generation HTTP client." | ||||
| category = "main" | ||||
| optional = false | ||||
| python-versions = ">=3.6" | ||||
|  | ||||
| [package.dependencies] | ||||
| certifi = "*" | ||||
| charset-normalizer = "*" | ||||
| h2 = {version = ">=3,<5", optional = true, markers = "extra == \"http2\""} | ||||
| httpcore = ">=0.13.3,<0.14.0" | ||||
| rfc3986 = {version = ">=1.3,<2", extras = ["idna2008"]} | ||||
| sniffio = "*" | ||||
|  | ||||
| [package.extras] | ||||
| brotli = ["brotlicffi", "brotli"] | ||||
| cli = ["click (>=8.0.0,<9.0.0)", "rich (>=10.0.0,<11.0.0)", "pygments (>=2.0.0,<3.0.0)"] | ||||
| http2 = ["h2 (>=3,<5)"] | ||||
|  | ||||
| [[package]] | ||||
| name = "hyperframe" | ||||
| version = "6.0.1" | ||||
| description = "HTTP/2 framing layer for Python" | ||||
| category = "main" | ||||
| optional = false | ||||
| python-versions = ">=3.6.1" | ||||
|  | ||||
| [[package]] | ||||
| name = "idna" | ||||
| version = "3.3" | ||||
| description = "Internationalized Domain Names in Applications (IDNA)" | ||||
| category = "main" | ||||
| optional = false | ||||
| python-versions = ">=3.5" | ||||
|  | ||||
| [[package]] | ||||
| name = "importlib-metadata" | ||||
| version = "4.8.1" | ||||
| description = "Read metadata from Python packages" | ||||
| category = "main" | ||||
| optional = false | ||||
| python-versions = ">=3.6" | ||||
|  | ||||
| [package.dependencies] | ||||
| typing-extensions = {version = ">=3.6.4", markers = "python_version < \"3.8\""} | ||||
| zipp = ">=0.5" | ||||
|  | ||||
| [package.extras] | ||||
| docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"] | ||||
| perf = ["ipython"] | ||||
| testing = ["pytest (>=4.6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "packaging", "pep517", "pyfakefs", "flufl.flake8", "pytest-perf (>=0.9.2)", "pytest-black (>=0.3.7)", "pytest-mypy", "importlib-resources (>=1.3)"] | ||||
|  | ||||
| [[package]] | ||||
| name = "loguru" | ||||
| version = "0.5.3" | ||||
| description = "Python logging made (stupidly) simple" | ||||
| category = "main" | ||||
| optional = false | ||||
| python-versions = ">=3.5" | ||||
|  | ||||
| [package.dependencies] | ||||
| colorama = {version = ">=0.3.4", markers = "sys_platform == \"win32\""} | ||||
| win32-setctime = {version = ">=1.0.0", markers = "sys_platform == \"win32\""} | ||||
|  | ||||
| [package.extras] | ||||
| dev = ["codecov (>=2.0.15)", "colorama (>=0.3.4)", "flake8 (>=3.7.7)", "tox (>=3.9.0)", "tox-travis (>=0.12)", "pytest (>=4.6.2)", "pytest-cov (>=2.7.1)", "Sphinx (>=2.2.1)", "sphinx-autobuild (>=0.7.1)", "sphinx-rtd-theme (>=0.4.3)", "black (>=19.10b0)", "isort (>=5.1.1)"] | ||||
|  | ||||
| [[package]] | ||||
| name = "nonebot2" | ||||
| version = "2.0.0-alpha.16" | ||||
| description = "An asynchronous python bot framework." | ||||
| category = "main" | ||||
| optional = false | ||||
| python-versions = "^3.7.3" | ||||
| develop = true | ||||
|  | ||||
| [package.dependencies] | ||||
| fastapi = "^0.70.0" | ||||
| httpx = {version = ">=0.20.0, <1.0.0", extras = ["http2"]} | ||||
| loguru = "^0.5.1" | ||||
| pydantic = {version = "~1.8.0", extras = ["dotenv"]} | ||||
| pygtrie = "^2.4.1" | ||||
| tomlkit = "^0.7.0" | ||||
| uvicorn = {version = "^0.15.0", extras = ["standard"]} | ||||
| websockets = ">=9.1" | ||||
|  | ||||
| [package.extras] | ||||
| quart = ["Quart (>=0.15.0,<0.16.0)"] | ||||
| aiohttp = ["aiohttp[speedups] (>=3.7.4,<4.0.0)"] | ||||
| all = ["Quart (>=0.15.0,<0.16.0)", "aiohttp[speedups] (>=3.7.4,<4.0.0)"] | ||||
|  | ||||
| [package.source] | ||||
| type = "directory" | ||||
| url = "../.." | ||||
|  | ||||
| [[package]] | ||||
| name = "pycryptodome" | ||||
| version = "3.11.0" | ||||
| description = "Cryptographic library for Python" | ||||
| category = "main" | ||||
| optional = false | ||||
| python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" | ||||
|  | ||||
| [[package]] | ||||
| name = "pydantic" | ||||
| version = "1.8.2" | ||||
| description = "Data validation and settings management using python 3.6 type hinting" | ||||
| category = "main" | ||||
| optional = false | ||||
| python-versions = ">=3.6.1" | ||||
|  | ||||
| [package.dependencies] | ||||
| python-dotenv = {version = ">=0.10.4", optional = true, markers = "extra == \"dotenv\""} | ||||
| typing-extensions = ">=3.7.4.3" | ||||
|  | ||||
| [package.extras] | ||||
| dotenv = ["python-dotenv (>=0.10.4)"] | ||||
| email = ["email-validator (>=1.0.3)"] | ||||
|  | ||||
| [[package]] | ||||
| name = "pygtrie" | ||||
| version = "2.4.2" | ||||
| description = "A pure Python trie data structure implementation." | ||||
| category = "main" | ||||
| optional = false | ||||
| python-versions = "*" | ||||
|  | ||||
| [[package]] | ||||
| name = "python-dotenv" | ||||
| version = "0.19.1" | ||||
| description = "Read key-value pairs from a .env file and set them as environment variables" | ||||
| category = "main" | ||||
| optional = false | ||||
| python-versions = ">=3.5" | ||||
|  | ||||
| [package.extras] | ||||
| cli = ["click (>=5.0)"] | ||||
|  | ||||
| [[package]] | ||||
| name = "pyyaml" | ||||
| version = "6.0" | ||||
| description = "YAML parser and emitter for Python" | ||||
| category = "main" | ||||
| optional = false | ||||
| python-versions = ">=3.6" | ||||
|  | ||||
| [[package]] | ||||
| name = "rfc3986" | ||||
| version = "1.5.0" | ||||
| description = "Validating URI References per RFC 3986" | ||||
| category = "main" | ||||
| optional = false | ||||
| python-versions = "*" | ||||
|  | ||||
| [package.dependencies] | ||||
| idna = {version = "*", optional = true, markers = "extra == \"idna2008\""} | ||||
|  | ||||
| [package.extras] | ||||
| idna2008 = ["idna"] | ||||
|  | ||||
| [[package]] | ||||
| name = "sniffio" | ||||
| version = "1.2.0" | ||||
| description = "Sniff out which async library your code is running under" | ||||
| category = "main" | ||||
| optional = false | ||||
| python-versions = ">=3.5" | ||||
|  | ||||
| [[package]] | ||||
| name = "starlette" | ||||
| version = "0.16.0" | ||||
| description = "The little ASGI library that shines." | ||||
| category = "main" | ||||
| optional = false | ||||
| python-versions = ">=3.6" | ||||
|  | ||||
| [package.dependencies] | ||||
| anyio = ">=3.0.0,<4" | ||||
| typing-extensions = {version = "*", markers = "python_version < \"3.8\""} | ||||
|  | ||||
| [package.extras] | ||||
| full = ["itsdangerous", "jinja2", "python-multipart", "pyyaml", "requests", "graphene"] | ||||
|  | ||||
| [[package]] | ||||
| name = "tomlkit" | ||||
| version = "0.7.2" | ||||
| description = "Style preserving TOML library" | ||||
| category = "main" | ||||
| optional = false | ||||
| python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" | ||||
|  | ||||
| [[package]] | ||||
| name = "typing-extensions" | ||||
| version = "3.10.0.2" | ||||
| description = "Backported and Experimental Type Hints for Python 3.5+" | ||||
| category = "main" | ||||
| optional = false | ||||
| python-versions = "*" | ||||
|  | ||||
| [[package]] | ||||
| name = "uvicorn" | ||||
| version = "0.15.0" | ||||
| description = "The lightning-fast ASGI server." | ||||
| category = "main" | ||||
| optional = false | ||||
| python-versions = "*" | ||||
|  | ||||
| [package.dependencies] | ||||
| asgiref = ">=3.4.0" | ||||
| click = ">=7.0" | ||||
| colorama = {version = ">=0.4", optional = true, markers = "sys_platform == \"win32\" and extra == \"standard\""} | ||||
| h11 = ">=0.8" | ||||
| httptools = {version = ">=0.2.0,<0.3.0", optional = true, markers = "extra == \"standard\""} | ||||
| python-dotenv = {version = ">=0.13", optional = true, markers = "extra == \"standard\""} | ||||
| PyYAML = {version = ">=5.1", optional = true, markers = "extra == \"standard\""} | ||||
| typing-extensions = {version = "*", markers = "python_version < \"3.8\""} | ||||
| 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\""} | ||||
| watchgod = {version = ">=0.6", optional = true, markers = "extra == \"standard\""} | ||||
| websockets = {version = ">=9.1", optional = true, markers = "extra == \"standard\""} | ||||
|  | ||||
| [package.extras] | ||||
| standard = ["websockets (>=9.1)", "httptools (>=0.2.0,<0.3.0)", "watchgod (>=0.6)", "python-dotenv (>=0.13)", "PyYAML (>=5.1)", "uvloop (>=0.14.0,!=0.15.0,!=0.15.1)", "colorama (>=0.4)"] | ||||
|  | ||||
| [[package]] | ||||
| name = "uvloop" | ||||
| version = "0.16.0" | ||||
| description = "Fast implementation of asyncio event loop on top of libuv" | ||||
| category = "main" | ||||
| optional = false | ||||
| python-versions = ">=3.7" | ||||
|  | ||||
| [package.extras] | ||||
| dev = ["Cython (>=0.29.24,<0.30.0)", "pytest (>=3.6.0)", "Sphinx (>=4.1.2,<4.2.0)", "sphinxcontrib-asyncio (>=0.3.0,<0.4.0)", "sphinx-rtd-theme (>=0.5.2,<0.6.0)", "aiohttp", "flake8 (>=3.9.2,<3.10.0)", "psutil", "pycodestyle (>=2.7.0,<2.8.0)", "pyOpenSSL (>=19.0.0,<19.1.0)", "mypy (>=0.800)"] | ||||
| docs = ["Sphinx (>=4.1.2,<4.2.0)", "sphinxcontrib-asyncio (>=0.3.0,<0.4.0)", "sphinx-rtd-theme (>=0.5.2,<0.6.0)"] | ||||
| test = ["aiohttp", "flake8 (>=3.9.2,<3.10.0)", "psutil", "pycodestyle (>=2.7.0,<2.8.0)", "pyOpenSSL (>=19.0.0,<19.1.0)", "mypy (>=0.800)"] | ||||
|  | ||||
| [[package]] | ||||
| name = "watchgod" | ||||
| version = "0.7" | ||||
| description = "Simple, modern file watching and code reload in python." | ||||
| category = "main" | ||||
| optional = false | ||||
| python-versions = ">=3.5" | ||||
|  | ||||
| [[package]] | ||||
| name = "websockets" | ||||
| version = "10.0" | ||||
| description = "An implementation of the WebSocket Protocol (RFC 6455 & 7692)" | ||||
| category = "main" | ||||
| optional = false | ||||
| python-versions = ">=3.7" | ||||
|  | ||||
| [[package]] | ||||
| name = "win32-setctime" | ||||
| version = "1.0.3" | ||||
| description = "A small Python utility to set file creation time on Windows" | ||||
| category = "main" | ||||
| optional = false | ||||
| python-versions = ">=3.5" | ||||
|  | ||||
| [package.extras] | ||||
| dev = ["pytest (>=4.6.2)", "black (>=19.3b0)"] | ||||
|  | ||||
| [[package]] | ||||
| name = "zipp" | ||||
| version = "3.6.0" | ||||
| description = "Backport of pathlib-compatible object wrapper for zip files" | ||||
| category = "main" | ||||
| optional = false | ||||
| python-versions = ">=3.6" | ||||
|  | ||||
| [package.extras] | ||||
| docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"] | ||||
| testing = ["pytest (>=4.6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "jaraco.itertools", "func-timeout", "pytest-black (>=0.3.7)", "pytest-mypy"] | ||||
|  | ||||
| [metadata] | ||||
| lock-version = "1.1" | ||||
| python-versions = "^3.7.3" | ||||
| content-hash = "c25fec9564d96a549db4b8828e75458d1980e192bdbbcaebeba1e2f35326ea40" | ||||
|  | ||||
| [metadata.files] | ||||
| aiocache = [ | ||||
|     {file = "aiocache-0.11.1-py2.py3-none-any.whl", hash = "sha256:e55c7caaa5753794fd301c3a2e592737fa1d036db9f8d04ae154facdfb48a157"}, | ||||
|     {file = "aiocache-0.11.1.tar.gz", hash = "sha256:f2ebe0b05cec45782e7b5ea0bb74640f157dd4bb1028b4565364dda9fe33be7f"}, | ||||
| ] | ||||
| anyio = [ | ||||
|     {file = "anyio-3.3.4-py3-none-any.whl", hash = "sha256:4fd09a25ab7fa01d34512b7249e366cd10358cdafc95022c7ff8c8f8a5026d66"}, | ||||
|     {file = "anyio-3.3.4.tar.gz", hash = "sha256:67da67b5b21f96b9d3d65daa6ea99f5d5282cb09f50eb4456f8fb51dffefc3ff"}, | ||||
| ] | ||||
| asgiref = [ | ||||
|     {file = "asgiref-3.4.1-py3-none-any.whl", hash = "sha256:ffc141aa908e6f175673e7b1b3b7af4fdb0ecb738fc5c8b88f69f055c2415214"}, | ||||
|     {file = "asgiref-3.4.1.tar.gz", hash = "sha256:4ef1ab46b484e3c706329cedeff284a5d40824200638503f5768edb6de7d58e9"}, | ||||
| ] | ||||
| certifi = [ | ||||
|     {file = "certifi-2021.10.8-py2.py3-none-any.whl", hash = "sha256:d62a0163eb4c2344ac042ab2bdf75399a71a2d8c7d47eac2e2ee91b9d6339569"}, | ||||
|     {file = "certifi-2021.10.8.tar.gz", hash = "sha256:78884e7c1d4b00ce3cea67b44566851c4343c120abd683433ce934a68ea58872"}, | ||||
| ] | ||||
| charset-normalizer = [ | ||||
|     {file = "charset-normalizer-2.0.7.tar.gz", hash = "sha256:e019de665e2bcf9c2b64e2e5aa025fa991da8720daa3c1138cadd2fd1856aed0"}, | ||||
|     {file = "charset_normalizer-2.0.7-py3-none-any.whl", hash = "sha256:f7af805c321bfa1ce6714c51f254e0d5bb5e5834039bc17db7ebe3a4cec9492b"}, | ||||
| ] | ||||
| click = [ | ||||
|     {file = "click-8.0.3-py3-none-any.whl", hash = "sha256:353f466495adaeb40b6b5f592f9f91cb22372351c84caeb068132442a4518ef3"}, | ||||
|     {file = "click-8.0.3.tar.gz", hash = "sha256:410e932b050f5eed773c4cda94de75971c89cdb3155a72a0831139a79e5ecb5b"}, | ||||
| ] | ||||
| colorama = [ | ||||
|     {file = "colorama-0.4.4-py2.py3-none-any.whl", hash = "sha256:9f47eda37229f68eee03b24b9748937c7dc3868f906e8ba69fbcbdd3bc5dc3e2"}, | ||||
|     {file = "colorama-0.4.4.tar.gz", hash = "sha256:5941b2b48a20143d2267e95b1c2a7603ce057ee39fd88e7329b0c292aa16869b"}, | ||||
| ] | ||||
| fastapi = [ | ||||
|     {file = "fastapi-0.70.0-py3-none-any.whl", hash = "sha256:a36d5f2fad931aa3575c07a3472c784e81f3e664e3bb5c8b9c88d0ec1104f59c"}, | ||||
|     {file = "fastapi-0.70.0.tar.gz", hash = "sha256:66da43cfe5185ea1df99552acffd201f1832c6b364e0f4136c0a99f933466ced"}, | ||||
| ] | ||||
| h11 = [ | ||||
|     {file = "h11-0.12.0-py3-none-any.whl", hash = "sha256:36a3cb8c0a032f56e2da7084577878a035d3b61d104230d4bd49c0c6b555a9c6"}, | ||||
|     {file = "h11-0.12.0.tar.gz", hash = "sha256:47222cb6067e4a307d535814917cd98fd0a57b6788ce715755fa2b6c28b56042"}, | ||||
| ] | ||||
| h2 = [ | ||||
|     {file = "h2-4.1.0-py3-none-any.whl", hash = "sha256:03a46bcf682256c95b5fd9e9a99c1323584c3eec6440d379b9903d709476bc6d"}, | ||||
|     {file = "h2-4.1.0.tar.gz", hash = "sha256:a83aca08fbe7aacb79fec788c9c0bac936343560ed9ec18b82a13a12c28d2abb"}, | ||||
| ] | ||||
| hpack = [ | ||||
|     {file = "hpack-4.0.0-py3-none-any.whl", hash = "sha256:84a076fad3dc9a9f8063ccb8041ef100867b1878b25ef0ee63847a5d53818a6c"}, | ||||
|     {file = "hpack-4.0.0.tar.gz", hash = "sha256:fc41de0c63e687ebffde81187a948221294896f6bdc0ae2312708df339430095"}, | ||||
| ] | ||||
| httpcore = [ | ||||
|     {file = "httpcore-0.13.7-py3-none-any.whl", hash = "sha256:369aa481b014cf046f7067fddd67d00560f2f00426e79569d99cb11245134af0"}, | ||||
|     {file = "httpcore-0.13.7.tar.gz", hash = "sha256:036f960468759e633574d7c121afba48af6419615d36ab8ede979f1ad6276fa3"}, | ||||
| ] | ||||
| httptools = [ | ||||
|     {file = "httptools-0.2.0-cp35-cp35m-macosx_10_14_x86_64.whl", hash = "sha256:79dbc21f3612a78b28384e989b21872e2e3cf3968532601544696e4ed0007ce5"}, | ||||
|     {file = "httptools-0.2.0-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:78d03dd39b09c99ec917d50189e6743adbfd18c15d5944392d2eabda688bf149"}, | ||||
|     {file = "httptools-0.2.0-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:a23166e5ae2775709cf4f7ad4c2048755ebfb272767d244e1a96d55ac775cca7"}, | ||||
|     {file = "httptools-0.2.0-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:3ab1f390d8867f74b3b5ee2a7ecc9b8d7f53750bd45714bf1cb72a953d7dfa77"}, | ||||
|     {file = "httptools-0.2.0-cp36-cp36m-win_amd64.whl", hash = "sha256:a7594f9a010cdf1e16a58b3bf26c9da39bbf663e3b8d46d39176999d71816658"}, | ||||
|     {file = "httptools-0.2.0-cp37-cp37m-macosx_10_14_x86_64.whl", hash = "sha256:01b392a166adcc8bc2f526a939a8aabf89fe079243e1543fd0e7dc1b58d737cb"}, | ||||
|     {file = "httptools-0.2.0-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:80ffa04fe8c8dfacf6e4cef8277347d35b0442c581f5814f3b0cf41b65c43c6e"}, | ||||
|     {file = "httptools-0.2.0-cp37-cp37m-win_amd64.whl", hash = "sha256:d5682eeb10cca0606c4a8286a3391d4c3c5a36f0c448e71b8bd05be4e1694bfb"}, | ||||
|     {file = "httptools-0.2.0-cp38-cp38-macosx_10_14_x86_64.whl", hash = "sha256:a289c27ccae399a70eacf32df9a44059ca2ba4ac444604b00a19a6c1f0809943"}, | ||||
|     {file = "httptools-0.2.0-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:813871f961edea6cb2fe312f2d9b27d12a51ba92545380126f80d0de1917ea15"}, | ||||
|     {file = "httptools-0.2.0-cp38-cp38-win_amd64.whl", hash = "sha256:cc9be041e428c10f8b6ab358c6b393648f9457094e1dcc11b4906026d43cd380"}, | ||||
|     {file = "httptools-0.2.0-cp39-cp39-macosx_10_14_x86_64.whl", hash = "sha256:b08d00d889a118f68f37f3c43e359aab24ee29eb2e3fe96d64c6a2ba8b9d6557"}, | ||||
|     {file = "httptools-0.2.0-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:fd3b8905e21431ad306eeaf56644a68fdd621bf8f3097eff54d0f6bdf7262065"}, | ||||
|     {file = "httptools-0.2.0-cp39-cp39-win_amd64.whl", hash = "sha256:200fc1cdf733a9ff554c0bb97a4047785cfaad9875307d6087001db3eb2b417f"}, | ||||
|     {file = "httptools-0.2.0.tar.gz", hash = "sha256:94505026be56652d7a530ab03d89474dc6021019d6b8682281977163b3471ea0"}, | ||||
| ] | ||||
| httpx = [ | ||||
|     {file = "httpx-0.20.0-py3-none-any.whl", hash = "sha256:33af5aad9bdc82ef1fc89219c1e36f5693bf9cd0ebe330884df563445682c0f8"}, | ||||
|     {file = "httpx-0.20.0.tar.gz", hash = "sha256:09606d630f070d07f9ff28104fbcea429ea0014c1e89ac90b4d8de8286c40e7b"}, | ||||
| ] | ||||
| hyperframe = [ | ||||
|     {file = "hyperframe-6.0.1-py3-none-any.whl", hash = "sha256:0ec6bafd80d8ad2195c4f03aacba3a8265e57bc4cff261e802bf39970ed02a15"}, | ||||
|     {file = "hyperframe-6.0.1.tar.gz", hash = "sha256:ae510046231dc8e9ecb1a6586f63d2347bf4c8905914aa84ba585ae85f28a914"}, | ||||
| ] | ||||
| idna = [ | ||||
|     {file = "idna-3.3-py3-none-any.whl", hash = "sha256:84d9dd047ffa80596e0f246e2eab0b391788b0503584e8945f2368256d2735ff"}, | ||||
|     {file = "idna-3.3.tar.gz", hash = "sha256:9d643ff0a55b762d5cdb124b8eaa99c66322e2157b69160bc32796e824360e6d"}, | ||||
| ] | ||||
| importlib-metadata = [ | ||||
|     {file = "importlib_metadata-4.8.1-py3-none-any.whl", hash = "sha256:b618b6d2d5ffa2f16add5697cf57a46c76a56229b0ed1c438322e4e95645bd15"}, | ||||
|     {file = "importlib_metadata-4.8.1.tar.gz", hash = "sha256:f284b3e11256ad1e5d03ab86bb2ccd6f5339688ff17a4d797a0fe7df326f23b1"}, | ||||
| ] | ||||
| loguru = [ | ||||
|     {file = "loguru-0.5.3-py3-none-any.whl", hash = "sha256:f8087ac396b5ee5f67c963b495d615ebbceac2796379599820e324419d53667c"}, | ||||
|     {file = "loguru-0.5.3.tar.gz", hash = "sha256:b28e72ac7a98be3d28ad28570299a393dfcd32e5e3f6a353dec94675767b6319"}, | ||||
| ] | ||||
| nonebot2 = [] | ||||
| pycryptodome = [ | ||||
|     {file = "pycryptodome-3.11.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:ffd0cac13ff41f2d15ed39dc6ba1d2ad88dd2905d656c33d8235852f5d6151fd"}, | ||||
|     {file = "pycryptodome-3.11.0-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:ead516e03dfe062aefeafe4a29445a6449b0fc43bc8cb30194b2754917a63798"}, | ||||
|     {file = "pycryptodome-3.11.0-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:4ce6b09547bf2c7cede3a017f79502eaed3e819c13cdb3cb357aea1b004e4cc6"}, | ||||
|     {file = "pycryptodome-3.11.0-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:014c758af7fa38cab85b357a496b76f4fc9dda1f731eb28358d66fef7ad4a3e1"}, | ||||
|     {file = "pycryptodome-3.11.0-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:a843350d08c3d22f6c09c2f17f020d8dcfa59496165d7425a3fba0045543dda7"}, | ||||
|     {file = "pycryptodome-3.11.0-cp27-cp27m-manylinux2014_aarch64.whl", hash = "sha256:53989477044be41fa4a63da09d5038c2a34b2f4554cfea2e3933b17186ee9e19"}, | ||||
|     {file = "pycryptodome-3.11.0-cp27-cp27m-win32.whl", hash = "sha256:f9bad2220b80b4ed74f089db012ab5ab5419143a33fad6c8aedcc2a9341eac70"}, | ||||
|     {file = "pycryptodome-3.11.0-cp27-cp27m-win_amd64.whl", hash = "sha256:3c7ed5b07274535979c730daf5817db5e983ea80b04c22579eee8da4ca3ae4f8"}, | ||||
|     {file = "pycryptodome-3.11.0-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:8f3a60926be78422e662b0d0b18351b426ce27657101c8a50bad80300de6a701"}, | ||||
|     {file = "pycryptodome-3.11.0-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:fce7e22d96030b35345637c563246c24d4513bd3b413e1c40293114837ab8912"}, | ||||
|     {file = "pycryptodome-3.11.0-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:bc3c61ff92efdcc14af4a7b81da71d849c9acee51d8fd8ac9841a7620140d6c6"}, | ||||
|     {file = "pycryptodome-3.11.0-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:b33c9b3d1327d821e28e9cc3a6512c14f8b17570ddb4cfb9a52247ed0fcc5d8b"}, | ||||
|     {file = "pycryptodome-3.11.0-cp27-cp27mu-manylinux2014_aarch64.whl", hash = "sha256:75e78360d1dd6d02eb288fd8275bb4d147d6e3f5337935c096d11dba1fa84748"}, | ||||
|     {file = "pycryptodome-3.11.0-cp35-abi3-macosx_10_9_x86_64.whl", hash = "sha256:621a90147a5e255fdc2a0fec2d56626b76b5d72ea9e60164c9a5a8976d45b0c9"}, | ||||
|     {file = "pycryptodome-3.11.0-cp35-abi3-manylinux1_i686.whl", hash = "sha256:0ca7a6b4fc1f9fafe990b95c8cda89099797e2cfbf40e55607f2f2f5a3355dcb"}, | ||||
|     {file = "pycryptodome-3.11.0-cp35-abi3-manylinux1_x86_64.whl", hash = "sha256:b59bf823cfafde8ef1105d8984f26d1694dff165adb7198b12e3e068d7999b15"}, | ||||
|     {file = "pycryptodome-3.11.0-cp35-abi3-manylinux2010_i686.whl", hash = "sha256:ce81b9c6aaa0f920e2ab05eb2b9f4ccd102e3016b2f37125593b16a83a4b0cc2"}, | ||||
|     {file = "pycryptodome-3.11.0-cp35-abi3-manylinux2010_x86_64.whl", hash = "sha256:ae29fcd56152f417bfba50a36a56a7a5f9fb74ff80bab98704cac704de6568ab"}, | ||||
|     {file = "pycryptodome-3.11.0-cp35-abi3-manylinux2014_aarch64.whl", hash = "sha256:ae31cb874f6f0cedbed457c6374e7e54d7ed45c1a4e11a65a9c80968da90a650"}, | ||||
|     {file = "pycryptodome-3.11.0-cp35-abi3-win32.whl", hash = "sha256:6db1f9fa1f52226621905f004278ce7bd90c8f5363ffd5d7ab3755363d98549a"}, | ||||
|     {file = "pycryptodome-3.11.0-cp35-abi3-win_amd64.whl", hash = "sha256:d7e5f6f692421e5219aa3b545eb0cffd832cd589a4b9dcd4a5eb4260e2c0d68a"}, | ||||
|     {file = "pycryptodome-3.11.0-pp27-pypy_73-macosx_10_9_x86_64.whl", hash = "sha256:da796e9221dda61a0019d01742337eb8a322de8598b678a4344ca0a436380315"}, | ||||
|     {file = "pycryptodome-3.11.0-pp27-pypy_73-manylinux1_x86_64.whl", hash = "sha256:ed45ef92d21db33685b789de2c015e9d9a18a74760a8df1fc152faee88cdf741"}, | ||||
|     {file = "pycryptodome-3.11.0-pp27-pypy_73-manylinux2010_x86_64.whl", hash = "sha256:4169ed515742425ff21e4bd3fabbb6994ffb64434472fb72230019bdfa36b939"}, | ||||
|     {file = "pycryptodome-3.11.0-pp27-pypy_73-win32.whl", hash = "sha256:f19edd42368e9057c39492947bb99570dc927123e210008f2af7cf9b505c6892"}, | ||||
|     {file = "pycryptodome-3.11.0-pp36-pypy36_pp73-macosx_10_9_x86_64.whl", hash = "sha256:06162fcfed2f9deee8383fd59eaeabc7b7ffc3af50d3fad4000032deb8f700b0"}, | ||||
|     {file = "pycryptodome-3.11.0-pp36-pypy36_pp73-manylinux1_x86_64.whl", hash = "sha256:6eda8a3157c91ba60b26a07bedd6c44ab8bda6cd79b6b5ea9744ba62c39b7b1e"}, | ||||
|     {file = "pycryptodome-3.11.0-pp36-pypy36_pp73-manylinux2010_x86_64.whl", hash = "sha256:7ff701fc283412e651eaab4319b3cd4eaa0827e94569cd37ee9075d5c05fe655"}, | ||||
|     {file = "pycryptodome-3.11.0-pp36-pypy36_pp73-win32.whl", hash = "sha256:2a4bcc8a9977fee0979079cd33a9e9f0d3ddba5660d35ffe874cf84f1dd399d2"}, | ||||
|     {file = "pycryptodome-3.11.0.tar.gz", hash = "sha256:428096bbf7a77e207f418dfd4d7c284df8ade81d2dc80f010e92753a3e406ad0"}, | ||||
| ] | ||||
| pydantic = [ | ||||
|     {file = "pydantic-1.8.2-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:05ddfd37c1720c392f4e0d43c484217b7521558302e7069ce8d318438d297739"}, | ||||
|     {file = "pydantic-1.8.2-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:a7c6002203fe2c5a1b5cbb141bb85060cbff88c2d78eccbc72d97eb7022c43e4"}, | ||||
|     {file = "pydantic-1.8.2-cp36-cp36m-manylinux2014_i686.whl", hash = "sha256:589eb6cd6361e8ac341db97602eb7f354551482368a37f4fd086c0733548308e"}, | ||||
|     {file = "pydantic-1.8.2-cp36-cp36m-manylinux2014_x86_64.whl", hash = "sha256:10e5622224245941efc193ad1d159887872776df7a8fd592ed746aa25d071840"}, | ||||
|     {file = "pydantic-1.8.2-cp36-cp36m-win_amd64.whl", hash = "sha256:99a9fc39470010c45c161a1dc584997f1feb13f689ecf645f59bb4ba623e586b"}, | ||||
|     {file = "pydantic-1.8.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:a83db7205f60c6a86f2c44a61791d993dff4b73135df1973ecd9eed5ea0bda20"}, | ||||
|     {file = "pydantic-1.8.2-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:41b542c0b3c42dc17da70554bc6f38cbc30d7066d2c2815a94499b5684582ecb"}, | ||||
|     {file = "pydantic-1.8.2-cp37-cp37m-manylinux2014_i686.whl", hash = "sha256:ea5cb40a3b23b3265f6325727ddfc45141b08ed665458be8c6285e7b85bd73a1"}, | ||||
|     {file = "pydantic-1.8.2-cp37-cp37m-manylinux2014_x86_64.whl", hash = "sha256:18b5ea242dd3e62dbf89b2b0ec9ba6c7b5abaf6af85b95a97b00279f65845a23"}, | ||||
|     {file = "pydantic-1.8.2-cp37-cp37m-win_amd64.whl", hash = "sha256:234a6c19f1c14e25e362cb05c68afb7f183eb931dd3cd4605eafff055ebbf287"}, | ||||
|     {file = "pydantic-1.8.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:021ea0e4133e8c824775a0cfe098677acf6fa5a3cbf9206a376eed3fc09302cd"}, | ||||
|     {file = "pydantic-1.8.2-cp38-cp38-manylinux1_i686.whl", hash = "sha256:e710876437bc07bd414ff453ac8ec63d219e7690128d925c6e82889d674bb505"}, | ||||
|     {file = "pydantic-1.8.2-cp38-cp38-manylinux2014_i686.whl", hash = "sha256:ac8eed4ca3bd3aadc58a13c2aa93cd8a884bcf21cb019f8cfecaae3b6ce3746e"}, | ||||
|     {file = "pydantic-1.8.2-cp38-cp38-manylinux2014_x86_64.whl", hash = "sha256:4a03cbbe743e9c7247ceae6f0d8898f7a64bb65800a45cbdc52d65e370570820"}, | ||||
|     {file = "pydantic-1.8.2-cp38-cp38-win_amd64.whl", hash = "sha256:8621559dcf5afacf0069ed194278f35c255dc1a1385c28b32dd6c110fd6531b3"}, | ||||
|     {file = "pydantic-1.8.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:8b223557f9510cf0bfd8b01316bf6dd281cf41826607eada99662f5e4963f316"}, | ||||
|     {file = "pydantic-1.8.2-cp39-cp39-manylinux1_i686.whl", hash = "sha256:244ad78eeb388a43b0c927e74d3af78008e944074b7d0f4f696ddd5b2af43c62"}, | ||||
|     {file = "pydantic-1.8.2-cp39-cp39-manylinux2014_i686.whl", hash = "sha256:05ef5246a7ffd2ce12a619cbb29f3307b7c4509307b1b49f456657b43529dc6f"}, | ||||
|     {file = "pydantic-1.8.2-cp39-cp39-manylinux2014_x86_64.whl", hash = "sha256:54cd5121383f4a461ff7644c7ca20c0419d58052db70d8791eacbbe31528916b"}, | ||||
|     {file = "pydantic-1.8.2-cp39-cp39-win_amd64.whl", hash = "sha256:4be75bebf676a5f0f87937c6ddb061fa39cbea067240d98e298508c1bda6f3f3"}, | ||||
|     {file = "pydantic-1.8.2-py3-none-any.whl", hash = "sha256:fec866a0b59f372b7e776f2d7308511784dace622e0992a0b59ea3ccee0ae833"}, | ||||
|     {file = "pydantic-1.8.2.tar.gz", hash = "sha256:26464e57ccaafe72b7ad156fdaa4e9b9ef051f69e175dbbb463283000c05ab7b"}, | ||||
| ] | ||||
| pygtrie = [ | ||||
|     {file = "pygtrie-2.4.2.tar.gz", hash = "sha256:43205559d28863358dbbf25045029f58e2ab357317a59b11f11ade278ac64692"}, | ||||
| ] | ||||
| python-dotenv = [ | ||||
|     {file = "python-dotenv-0.19.1.tar.gz", hash = "sha256:14f8185cc8d494662683e6914addcb7e95374771e707601dfc70166946b4c4b8"}, | ||||
|     {file = "python_dotenv-0.19.1-py2.py3-none-any.whl", hash = "sha256:bbd3da593fc49c249397cbfbcc449cf36cb02e75afc8157fcc6a81df6fb7750a"}, | ||||
| ] | ||||
| pyyaml = [ | ||||
|     {file = "PyYAML-6.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d4db7c7aef085872ef65a8fd7d6d09a14ae91f691dec3e87ee5ee0539d516f53"}, | ||||
|     {file = "PyYAML-6.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9df7ed3b3d2e0ecfe09e14741b857df43adb5a3ddadc919a2d94fbdf78fea53c"}, | ||||
|     {file = "PyYAML-6.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:77f396e6ef4c73fdc33a9157446466f1cff553d979bd00ecb64385760c6babdc"}, | ||||
|     {file = "PyYAML-6.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a80a78046a72361de73f8f395f1f1e49f956c6be882eed58505a15f3e430962b"}, | ||||
|     {file = "PyYAML-6.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f84fbc98b019fef2ee9a1cb3ce93e3187a6df0b2538a651bfb890254ba9f90b5"}, | ||||
|     {file = "PyYAML-6.0-cp310-cp310-win32.whl", hash = "sha256:2cd5df3de48857ed0544b34e2d40e9fac445930039f3cfe4bcc592a1f836d513"}, | ||||
|     {file = "PyYAML-6.0-cp310-cp310-win_amd64.whl", hash = "sha256:daf496c58a8c52083df09b80c860005194014c3698698d1a57cbcfa182142a3a"}, | ||||
|     {file = "PyYAML-6.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:897b80890765f037df3403d22bab41627ca8811ae55e9a722fd0392850ec4d86"}, | ||||
|     {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:50602afada6d6cbfad699b0c7bb50d5ccffa7e46a3d738092afddc1f9758427f"}, | ||||
|     {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:48c346915c114f5fdb3ead70312bd042a953a8ce5c7106d5bfb1a5254e47da92"}, | ||||
|     {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:98c4d36e99714e55cfbaaee6dd5badbc9a1ec339ebfc3b1f52e293aee6bb71a4"}, | ||||
|     {file = "PyYAML-6.0-cp36-cp36m-win32.whl", hash = "sha256:0283c35a6a9fbf047493e3a0ce8d79ef5030852c51e9d911a27badfde0605293"}, | ||||
|     {file = "PyYAML-6.0-cp36-cp36m-win_amd64.whl", hash = "sha256:07751360502caac1c067a8132d150cf3d61339af5691fe9e87803040dbc5db57"}, | ||||
|     {file = "PyYAML-6.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:819b3830a1543db06c4d4b865e70ded25be52a2e0631ccd2f6a47a2822f2fd7c"}, | ||||
|     {file = "PyYAML-6.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:473f9edb243cb1935ab5a084eb238d842fb8f404ed2193a915d1784b5a6b5fc0"}, | ||||
|     {file = "PyYAML-6.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0ce82d761c532fe4ec3f87fc45688bdd3a4c1dc5e0b4a19814b9009a29baefd4"}, | ||||
|     {file = "PyYAML-6.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:231710d57adfd809ef5d34183b8ed1eeae3f76459c18fb4a0b373ad56bedcdd9"}, | ||||
|     {file = "PyYAML-6.0-cp37-cp37m-win32.whl", hash = "sha256:c5687b8d43cf58545ade1fe3e055f70eac7a5a1a0bf42824308d868289a95737"}, | ||||
|     {file = "PyYAML-6.0-cp37-cp37m-win_amd64.whl", hash = "sha256:d15a181d1ecd0d4270dc32edb46f7cb7733c7c508857278d3d378d14d606db2d"}, | ||||
|     {file = "PyYAML-6.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0b4624f379dab24d3725ffde76559cff63d9ec94e1736b556dacdfebe5ab6d4b"}, | ||||
|     {file = "PyYAML-6.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:213c60cd50106436cc818accf5baa1aba61c0189ff610f64f4a3e8c6726218ba"}, | ||||
|     {file = "PyYAML-6.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9fa600030013c4de8165339db93d182b9431076eb98eb40ee068700c9c813e34"}, | ||||
|     {file = "PyYAML-6.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:277a0ef2981ca40581a47093e9e2d13b3f1fbbeffae064c1d21bfceba2030287"}, | ||||
|     {file = "PyYAML-6.0-cp38-cp38-win32.whl", hash = "sha256:d4eccecf9adf6fbcc6861a38015c2a64f38b9d94838ac1810a9023a0609e1b78"}, | ||||
|     {file = "PyYAML-6.0-cp38-cp38-win_amd64.whl", hash = "sha256:1e4747bc279b4f613a09eb64bba2ba602d8a6664c6ce6396a4d0cd413a50ce07"}, | ||||
|     {file = "PyYAML-6.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:055d937d65826939cb044fc8c9b08889e8c743fdc6a32b33e2390f66013e449b"}, | ||||
|     {file = "PyYAML-6.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e61ceaab6f49fb8bdfaa0f92c4b57bcfbea54c09277b1b4f7ac376bfb7a7c174"}, | ||||
|     {file = "PyYAML-6.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d67d839ede4ed1b28a4e8909735fc992a923cdb84e618544973d7dfc71540803"}, | ||||
|     {file = "PyYAML-6.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cba8c411ef271aa037d7357a2bc8f9ee8b58b9965831d9e51baf703280dc73d3"}, | ||||
|     {file = "PyYAML-6.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:40527857252b61eacd1d9af500c3337ba8deb8fc298940291486c465c8b46ec0"}, | ||||
|     {file = "PyYAML-6.0-cp39-cp39-win32.whl", hash = "sha256:b5b9eccad747aabaaffbc6064800670f0c297e52c12754eb1d976c57e4f74dcb"}, | ||||
|     {file = "PyYAML-6.0-cp39-cp39-win_amd64.whl", hash = "sha256:b3d267842bf12586ba6c734f89d1f5b871df0273157918b0ccefa29deb05c21c"}, | ||||
|     {file = "PyYAML-6.0.tar.gz", hash = "sha256:68fb519c14306fec9720a2a5b45bc9f0c8d1b9c72adf45c37baedfcd949c35a2"}, | ||||
| ] | ||||
| rfc3986 = [ | ||||
|     {file = "rfc3986-1.5.0-py2.py3-none-any.whl", hash = "sha256:a86d6e1f5b1dc238b218b012df0aa79409667bb209e58da56d0b94704e712a97"}, | ||||
|     {file = "rfc3986-1.5.0.tar.gz", hash = "sha256:270aaf10d87d0d4e095063c65bf3ddbc6ee3d0b226328ce21e036f946e421835"}, | ||||
| ] | ||||
| sniffio = [ | ||||
|     {file = "sniffio-1.2.0-py3-none-any.whl", hash = "sha256:471b71698eac1c2112a40ce2752bb2f4a4814c22a54a3eed3676bc0f5ca9f663"}, | ||||
|     {file = "sniffio-1.2.0.tar.gz", hash = "sha256:c4666eecec1d3f50960c6bdf61ab7bc350648da6c126e3cf6898d8cd4ddcd3de"}, | ||||
| ] | ||||
| starlette = [ | ||||
|     {file = "starlette-0.16.0-py3-none-any.whl", hash = "sha256:38eb24bf705a2c317e15868e384c1b8a12ca396e5a3c3a003db7e667c43f939f"}, | ||||
|     {file = "starlette-0.16.0.tar.gz", hash = "sha256:e1904b5d0007aee24bdd3c43994be9b3b729f4f58e740200de1d623f8c3a8870"}, | ||||
| ] | ||||
| tomlkit = [ | ||||
|     {file = "tomlkit-0.7.2-py2.py3-none-any.whl", hash = "sha256:173ad840fa5d2aac140528ca1933c29791b79a374a0861a80347f42ec9328117"}, | ||||
|     {file = "tomlkit-0.7.2.tar.gz", hash = "sha256:d7a454f319a7e9bd2e249f239168729327e4dd2d27b17dc68be264ad1ce36754"}, | ||||
| ] | ||||
| typing-extensions = [ | ||||
|     {file = "typing_extensions-3.10.0.2-py2-none-any.whl", hash = "sha256:d8226d10bc02a29bcc81df19a26e56a9647f8b0a6d4a83924139f4a8b01f17b7"}, | ||||
|     {file = "typing_extensions-3.10.0.2-py3-none-any.whl", hash = "sha256:f1d25edafde516b146ecd0613dabcc61409817af4766fbbcfb8d1ad4ec441a34"}, | ||||
|     {file = "typing_extensions-3.10.0.2.tar.gz", hash = "sha256:49f75d16ff11f1cd258e1b988ccff82a3ca5570217d7ad8c5f48205dd99a677e"}, | ||||
| ] | ||||
| uvicorn = [ | ||||
|     {file = "uvicorn-0.15.0-py3-none-any.whl", hash = "sha256:17f898c64c71a2640514d4089da2689e5db1ce5d4086c2d53699bf99513421c1"}, | ||||
|     {file = "uvicorn-0.15.0.tar.gz", hash = "sha256:d9a3c0dd1ca86728d3e235182683b4cf94cd53a867c288eaeca80ee781b2caff"}, | ||||
| ] | ||||
| uvloop = [ | ||||
|     {file = "uvloop-0.16.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:6224f1401025b748ffecb7a6e2652b17768f30b1a6a3f7b44660e5b5b690b12d"}, | ||||
|     {file = "uvloop-0.16.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:30ba9dcbd0965f5c812b7c2112a1ddf60cf904c1c160f398e7eed3a6b82dcd9c"}, | ||||
|     {file = "uvloop-0.16.0-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:bd53f7f5db562f37cd64a3af5012df8cac2c464c97e732ed556800129505bd64"}, | ||||
|     {file = "uvloop-0.16.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:772206116b9b57cd625c8a88f2413df2fcfd0b496eb188b82a43bed7af2c2ec9"}, | ||||
|     {file = "uvloop-0.16.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b572256409f194521a9895aef274cea88731d14732343da3ecdb175228881638"}, | ||||
|     {file = "uvloop-0.16.0-cp37-cp37m-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:04ff57aa137230d8cc968f03481176041ae789308b4d5079118331ab01112450"}, | ||||
|     {file = "uvloop-0.16.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3a19828c4f15687675ea912cc28bbcb48e9bb907c801873bd1519b96b04fb805"}, | ||||
|     {file = "uvloop-0.16.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:e814ac2c6f9daf4c36eb8e85266859f42174a4ff0d71b99405ed559257750382"}, | ||||
|     {file = "uvloop-0.16.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:bd8f42ea1ea8f4e84d265769089964ddda95eb2bb38b5cbe26712b0616c3edee"}, | ||||
|     {file = "uvloop-0.16.0-cp38-cp38-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:647e481940379eebd314c00440314c81ea547aa636056f554d491e40503c8464"}, | ||||
|     {file = "uvloop-0.16.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8e0d26fa5875d43ddbb0d9d79a447d2ace4180d9e3239788208527c4784f7cab"}, | ||||
|     {file = "uvloop-0.16.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:6ccd57ae8db17d677e9e06192e9c9ec4bd2066b77790f9aa7dede2cc4008ee8f"}, | ||||
|     {file = "uvloop-0.16.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:089b4834fd299d82d83a25e3335372f12117a7d38525217c2258e9b9f4578897"}, | ||||
|     {file = "uvloop-0.16.0-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:98d117332cc9e5ea8dfdc2b28b0a23f60370d02e1395f88f40d1effd2cb86c4f"}, | ||||
|     {file = "uvloop-0.16.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1e5f2e2ff51aefe6c19ee98af12b4ae61f5be456cd24396953244a30880ad861"}, | ||||
|     {file = "uvloop-0.16.0.tar.gz", hash = "sha256:f74bc20c7b67d1c27c72601c78cf95be99d5c2cdd4514502b4f3eb0933ff1228"}, | ||||
| ] | ||||
| watchgod = [ | ||||
|     {file = "watchgod-0.7-py3-none-any.whl", hash = "sha256:d6c1ea21df37847ac0537ca0d6c2f4cdf513562e95f77bb93abbcf05573407b7"}, | ||||
|     {file = "watchgod-0.7.tar.gz", hash = "sha256:48140d62b0ebe9dd9cf8381337f06351e1f2e70b2203fa9c6eff4e572ca84f29"}, | ||||
| ] | ||||
| websockets = [ | ||||
|     {file = "websockets-10.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:cd8c6f2ec24aedace251017bc7a414525171d4e6578f914acab9349362def4da"}, | ||||
|     {file = "websockets-10.0-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:1f6b814cff6aadc4288297cb3a248614829c6e4ff5556593c44a115e9dd49939"}, | ||||
|     {file = "websockets-10.0-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:01db0ecd1a0ca6702d02a5ed40413e18b7d22f94afb3bbe0d323bac86c42c1c8"}, | ||||
|     {file = "websockets-10.0-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:82b17524b1ce6ae7f7dd93e4d18e9b9474071e28b65dbf1dfe9b5767778db379"}, | ||||
|     {file = "websockets-10.0-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:8bbf8660c3f833ddc8b1afab90213f2e672a9ddac6eecb3cde968e6b2807c1c7"}, | ||||
|     {file = "websockets-10.0-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:b8176deb6be540a46695960a765a77c28ac8b2e3ef2ec95d50a4f5df901edb1c"}, | ||||
|     {file = "websockets-10.0-cp37-cp37m-win32.whl", hash = "sha256:706e200fc7f03bed99ad0574cd1ea8b0951477dd18cc978ccb190683c69dba76"}, | ||||
|     {file = "websockets-10.0-cp37-cp37m-win_amd64.whl", hash = "sha256:5b2600e01c7ca6f840c42c747ffbe0254f319594ed108db847eb3d75f4aacb80"}, | ||||
|     {file = "websockets-10.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:085bb8a6e780d30eaa1ba48ac7f3a6707f925edea787cfb761ce5a39e77ac09b"}, | ||||
|     {file = "websockets-10.0-cp38-cp38-manylinux1_i686.whl", hash = "sha256:9a4d889162bd48588e80950e07fa5e039eee9deb76a58092e8c3ece96d7ef537"}, | ||||
|     {file = "websockets-10.0-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:b4ade7569b6fd17912452f9c3757d96f8e4044016b6d22b3b8391e641ca50456"}, | ||||
|     {file = "websockets-10.0-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:2a43072e434c041a99f2e1eb9b692df0232a38c37c61d00e9f24db79474329e4"}, | ||||
|     {file = "websockets-10.0-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:7f79f02c7f9a8320aff7d3321cd1c7e3a7dbc15d922ac996cca827301ee75238"}, | ||||
|     {file = "websockets-10.0-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:1ac35426fe3e7d3d0fac3d63c8965c76ed67a8fd713937be072bf0ce22808539"}, | ||||
|     {file = "websockets-10.0-cp38-cp38-win32.whl", hash = "sha256:ff59c6bdb87b31f7e2d596f09353d5a38c8c8ff571b0e2238e8ee2d55ad68465"}, | ||||
|     {file = "websockets-10.0-cp38-cp38-win_amd64.whl", hash = "sha256:d67646ddd17a86117ae21c27005d83c1895c0cef5d7be548b7549646372f868a"}, | ||||
|     {file = "websockets-10.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:82bd921885231f4a30d9bc550552495b3fc36b1235add6d374e7c65c3babd805"}, | ||||
|     {file = "websockets-10.0-cp39-cp39-manylinux1_i686.whl", hash = "sha256:7d2e12e4f901f1bc062dfdf91831712c4106ed18a9a4cdb65e2e5f502124ca37"}, | ||||
|     {file = "websockets-10.0-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:71358c7816e2762f3e4af3adf0040f268e219f5a38cb3487a9d0fc2e554fef6a"}, | ||||
|     {file = "websockets-10.0-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:fe83b3ec9ef34063d86dfe1029160a85f24a5a94271036e5714a57acfdd089a1"}, | ||||
|     {file = "websockets-10.0-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:eb282127e9c136f860c6068a4fba5756eb25e755baffb5940b6f1eae071928b2"}, | ||||
|     {file = "websockets-10.0-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:62160772314920397f9d219147f958b33fa27a12c662d4455c9ccbba9a07e474"}, | ||||
|     {file = "websockets-10.0-cp39-cp39-win32.whl", hash = "sha256:e42a1f1e03437b017af341e9bbfdc09252cd48ef32a8c3c3ead769eab3b17368"}, | ||||
|     {file = "websockets-10.0-cp39-cp39-win_amd64.whl", hash = "sha256:c5880442f5fc268f1ef6d37b2c152c114deccca73f48e3a8c48004d2f16f4567"}, | ||||
|     {file = "websockets-10.0.tar.gz", hash = "sha256:c4fc9a1d242317892590abe5b61a9127f1a61740477bfb121743f290b8054002"}, | ||||
| ] | ||||
| win32-setctime = [ | ||||
|     {file = "win32_setctime-1.0.3-py3-none-any.whl", hash = "sha256:dc925662de0a6eb987f0b01f599c01a8236cb8c62831c22d9cada09ad958243e"}, | ||||
|     {file = "win32_setctime-1.0.3.tar.gz", hash = "sha256:4e88556c32fdf47f64165a2180ba4552f8bb32c1103a2fafd05723a0bd42bd4b"}, | ||||
| ] | ||||
| zipp = [ | ||||
|     {file = "zipp-3.6.0-py3-none-any.whl", hash = "sha256:9fe5ea21568a0a70e50f273397638d39b03353731e6cbbb3fd8502a33fec40bc"}, | ||||
|     {file = "zipp-3.6.0.tar.gz", hash = "sha256:71c644c5369f4a6e07636f0aa966270449561fcea2e3d6747b8d23efaa9d7832"}, | ||||
| ] | ||||
| @@ -1,56 +0,0 @@ | ||||
| [tool.poetry] | ||||
| name = "nonebot-adapter-feishu" | ||||
| version = "2.0.0-alpha.16" | ||||
| description = "feishu(larksuite) adapter for nonebot2" | ||||
| authors = ["StarHeartHunt <starheart233@gmail.com>"] | ||||
| license = "MIT" | ||||
| readme = "README.md" | ||||
| homepage = "https://v2.nonebot.dev/" | ||||
| repository = "https://github.com/nonebot/nonebot2" | ||||
| documentation = "https://v2.nonebot.dev/" | ||||
| keywords = ["bot", "qq", "qqbot", "feishu", "larksuite"] | ||||
| classifiers = [ | ||||
|   "Development Status :: 5 - Production/Stable", | ||||
|   "Framework :: Robot Framework", | ||||
|   "Framework :: Robot Framework :: Library", | ||||
|   "Operating System :: OS Independent", | ||||
|   "Programming Language :: Python :: 3" | ||||
| ] | ||||
| packages = [ | ||||
|   { include = "nonebot" } | ||||
| ] | ||||
| exclude = ["nonebot/__init__.py", "nonebot/adapters/__init__.py"] | ||||
|  | ||||
| [tool.poetry.dependencies] | ||||
| python = "^3.7.3" | ||||
| aiocache = "^0.11.1" | ||||
| pycryptodome = "^3.10.1" | ||||
| httpx = ">=0.20.0, <1.0.0" | ||||
| nonebot2 = "^2.0.0-alpha.14" | ||||
|  | ||||
| [tool.poetry.dev-dependencies] | ||||
| nonebot2 = { path = "../../", develop = true } | ||||
|  | ||||
| # [[tool.poetry.source]] | ||||
| # name = "aliyun" | ||||
| # url = "https://mirrors.aliyun.com/pypi/simple/" | ||||
| # default = true | ||||
|  | ||||
| [tool.black] | ||||
| line-length = 88 | ||||
| target-version = ["py37", "py38", "py39"] | ||||
| include = '\.pyi?$' | ||||
| extend-exclude = ''' | ||||
| ''' | ||||
|  | ||||
| [tool.isort] | ||||
| profile = "black" | ||||
| line_length = 80 | ||||
| length_sort = true | ||||
| skip_gitignore = true | ||||
| force_sort_within_sections = true | ||||
| extra_standard_library = ["typing_extensions"] | ||||
|  | ||||
| [build-system] | ||||
| requires = ["poetry-core>=1.0.0"] | ||||
| build-backend = "poetry.core.masonry.api" | ||||
| @@ -1,661 +0,0 @@ | ||||
|                     GNU AFFERO GENERAL PUBLIC LICENSE | ||||
|                        Version 3, 19 November 2007 | ||||
|  | ||||
|  Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/> | ||||
|  Everyone is permitted to copy and distribute verbatim copies | ||||
|  of this license document, but changing it is not allowed. | ||||
|  | ||||
|                             Preamble | ||||
|  | ||||
|   The GNU Affero General Public License is a free, copyleft license for | ||||
| software and other kinds of works, specifically designed to ensure | ||||
| cooperation with the community in the case of network server software. | ||||
|  | ||||
|   The licenses for most software and other practical works are designed | ||||
| to take away your freedom to share and change the works.  By contrast, | ||||
| our General Public Licenses are intended to guarantee your freedom to | ||||
| share and change all versions of a program--to make sure it remains free | ||||
| software for all its users. | ||||
|  | ||||
|   When we speak of free software, we are referring to freedom, not | ||||
| price.  Our General Public Licenses are designed to make sure that you | ||||
| have the freedom to distribute copies of free software (and charge for | ||||
| them if you wish), that you receive source code or can get it if you | ||||
| want it, that you can change the software or use pieces of it in new | ||||
| free programs, and that you know you can do these things. | ||||
|  | ||||
|   Developers that use our General Public Licenses protect your rights | ||||
| with two steps: (1) assert copyright on the software, and (2) offer | ||||
| you this License which gives you legal permission to copy, distribute | ||||
| and/or modify the software. | ||||
|  | ||||
|   A secondary benefit of defending all users' freedom is that | ||||
| improvements made in alternate versions of the program, if they | ||||
| receive widespread use, become available for other developers to | ||||
| incorporate.  Many developers of free software are heartened and | ||||
| encouraged by the resulting cooperation.  However, in the case of | ||||
| software used on network servers, this result may fail to come about. | ||||
| The GNU General Public License permits making a modified version and | ||||
| letting the public access it on a server without ever releasing its | ||||
| source code to the public. | ||||
|  | ||||
|   The GNU Affero General Public License is designed specifically to | ||||
| ensure that, in such cases, the modified source code becomes available | ||||
| to the community.  It requires the operator of a network server to | ||||
| provide the source code of the modified version running there to the | ||||
| users of that server.  Therefore, public use of a modified version, on | ||||
| a publicly accessible server, gives the public access to the source | ||||
| code of the modified version. | ||||
|  | ||||
|   An older license, called the Affero General Public License and | ||||
| published by Affero, was designed to accomplish similar goals.  This is | ||||
| a different license, not a version of the Affero GPL, but Affero has | ||||
| released a new version of the Affero GPL which permits relicensing under | ||||
| this license. | ||||
|  | ||||
|   The precise terms and conditions for copying, distribution and | ||||
| modification follow. | ||||
|  | ||||
|                        TERMS AND CONDITIONS | ||||
|  | ||||
|   0. Definitions. | ||||
|  | ||||
|   "This License" refers to version 3 of the GNU Affero General Public License. | ||||
|  | ||||
|   "Copyright" also means copyright-like laws that apply to other kinds of | ||||
| works, such as semiconductor masks. | ||||
|  | ||||
|   "The Program" refers to any copyrightable work licensed under this | ||||
| License.  Each licensee is addressed as "you".  "Licensees" and | ||||
| "recipients" may be individuals or organizations. | ||||
|  | ||||
|   To "modify" a work means to copy from or adapt all or part of the work | ||||
| in a fashion requiring copyright permission, other than the making of an | ||||
| exact copy.  The resulting work is called a "modified version" of the | ||||
| earlier work or a work "based on" the earlier work. | ||||
|  | ||||
|   A "covered work" means either the unmodified Program or a work based | ||||
| on the Program. | ||||
|  | ||||
|   To "propagate" a work means to do anything with it that, without | ||||
| permission, would make you directly or secondarily liable for | ||||
| infringement under applicable copyright law, except executing it on a | ||||
| computer or modifying a private copy.  Propagation includes copying, | ||||
| distribution (with or without modification), making available to the | ||||
| public, and in some countries other activities as well. | ||||
|  | ||||
|   To "convey" a work means any kind of propagation that enables other | ||||
| parties to make or receive copies.  Mere interaction with a user through | ||||
| a computer network, with no transfer of a copy, is not conveying. | ||||
|  | ||||
|   An interactive user interface displays "Appropriate Legal Notices" | ||||
| to the extent that it includes a convenient and prominently visible | ||||
| feature that (1) displays an appropriate copyright notice, and (2) | ||||
| tells the user that there is no warranty for the work (except to the | ||||
| extent that warranties are provided), that licensees may convey the | ||||
| work under this License, and how to view a copy of this License.  If | ||||
| the interface presents a list of user commands or options, such as a | ||||
| menu, a prominent item in the list meets this criterion. | ||||
|  | ||||
|   1. Source Code. | ||||
|  | ||||
|   The "source code" for a work means the preferred form of the work | ||||
| for making modifications to it.  "Object code" means any non-source | ||||
| form of a work. | ||||
|  | ||||
|   A "Standard Interface" means an interface that either is an official | ||||
| standard defined by a recognized standards body, or, in the case of | ||||
| interfaces specified for a particular programming language, one that | ||||
| is widely used among developers working in that language. | ||||
|  | ||||
|   The "System Libraries" of an executable work include anything, other | ||||
| than the work as a whole, that (a) is included in the normal form of | ||||
| packaging a Major Component, but which is not part of that Major | ||||
| Component, and (b) serves only to enable use of the work with that | ||||
| Major Component, or to implement a Standard Interface for which an | ||||
| implementation is available to the public in source code form.  A | ||||
| "Major Component", in this context, means a major essential component | ||||
| (kernel, window system, and so on) of the specific operating system | ||||
| (if any) on which the executable work runs, or a compiler used to | ||||
| produce the work, or an object code interpreter used to run it. | ||||
|  | ||||
|   The "Corresponding Source" for a work in object code form means all | ||||
| the source code needed to generate, install, and (for an executable | ||||
| work) run the object code and to modify the work, including scripts to | ||||
| control those activities.  However, it does not include the work's | ||||
| System Libraries, or general-purpose tools or generally available free | ||||
| programs which are used unmodified in performing those activities but | ||||
| which are not part of the work.  For example, Corresponding Source | ||||
| includes interface definition files associated with source files for | ||||
| the work, and the source code for shared libraries and dynamically | ||||
| linked subprograms that the work is specifically designed to require, | ||||
| such as by intimate data communication or control flow between those | ||||
| subprograms and other parts of the work. | ||||
|  | ||||
|   The Corresponding Source need not include anything that users | ||||
| can regenerate automatically from other parts of the Corresponding | ||||
| Source. | ||||
|  | ||||
|   The Corresponding Source for a work in source code form is that | ||||
| same work. | ||||
|  | ||||
|   2. Basic Permissions. | ||||
|  | ||||
|   All rights granted under this License are granted for the term of | ||||
| copyright on the Program, and are irrevocable provided the stated | ||||
| conditions are met.  This License explicitly affirms your unlimited | ||||
| permission to run the unmodified Program.  The output from running a | ||||
| covered work is covered by this License only if the output, given its | ||||
| content, constitutes a covered work.  This License acknowledges your | ||||
| rights of fair use or other equivalent, as provided by copyright law. | ||||
|  | ||||
|   You may make, run and propagate covered works that you do not | ||||
| convey, without conditions so long as your license otherwise remains | ||||
| in force.  You may convey covered works to others for the sole purpose | ||||
| of having them make modifications exclusively for you, or provide you | ||||
| with facilities for running those works, provided that you comply with | ||||
| the terms of this License in conveying all material for which you do | ||||
| not control copyright.  Those thus making or running the covered works | ||||
| for you must do so exclusively on your behalf, under your direction | ||||
| and control, on terms that prohibit them from making any copies of | ||||
| your copyrighted material outside their relationship with you. | ||||
|  | ||||
|   Conveying under any other circumstances is permitted solely under | ||||
| the conditions stated below.  Sublicensing is not allowed; section 10 | ||||
| makes it unnecessary. | ||||
|  | ||||
|   3. Protecting Users' Legal Rights From Anti-Circumvention Law. | ||||
|  | ||||
|   No covered work shall be deemed part of an effective technological | ||||
| measure under any applicable law fulfilling obligations under article | ||||
| 11 of the WIPO copyright treaty adopted on 20 December 1996, or | ||||
| similar laws prohibiting or restricting circumvention of such | ||||
| measures. | ||||
|  | ||||
|   When you convey a covered work, you waive any legal power to forbid | ||||
| circumvention of technological measures to the extent such circumvention | ||||
| is effected by exercising rights under this License with respect to | ||||
| the covered work, and you disclaim any intention to limit operation or | ||||
| modification of the work as a means of enforcing, against the work's | ||||
| users, your or third parties' legal rights to forbid circumvention of | ||||
| technological measures. | ||||
|  | ||||
|   4. Conveying Verbatim Copies. | ||||
|  | ||||
|   You may convey verbatim copies of the Program's source code as you | ||||
| receive it, in any medium, provided that you conspicuously and | ||||
| appropriately publish on each copy an appropriate copyright notice; | ||||
| keep intact all notices stating that this License and any | ||||
| non-permissive terms added in accord with section 7 apply to the code; | ||||
| keep intact all notices of the absence of any warranty; and give all | ||||
| recipients a copy of this License along with the Program. | ||||
|  | ||||
|   You may charge any price or no price for each copy that you convey, | ||||
| and you may offer support or warranty protection for a fee. | ||||
|  | ||||
|   5. Conveying Modified Source Versions. | ||||
|  | ||||
|   You may convey a work based on the Program, or the modifications to | ||||
| produce it from the Program, in the form of source code under the | ||||
| terms of section 4, provided that you also meet all of these conditions: | ||||
|  | ||||
|     a) The work must carry prominent notices stating that you modified | ||||
|     it, and giving a relevant date. | ||||
|  | ||||
|     b) The work must carry prominent notices stating that it is | ||||
|     released under this License and any conditions added under section | ||||
|     7.  This requirement modifies the requirement in section 4 to | ||||
|     "keep intact all notices". | ||||
|  | ||||
|     c) You must license the entire work, as a whole, under this | ||||
|     License to anyone who comes into possession of a copy.  This | ||||
|     License will therefore apply, along with any applicable section 7 | ||||
|     additional terms, to the whole of the work, and all its parts, | ||||
|     regardless of how they are packaged.  This License gives no | ||||
|     permission to license the work in any other way, but it does not | ||||
|     invalidate such permission if you have separately received it. | ||||
|  | ||||
|     d) If the work has interactive user interfaces, each must display | ||||
|     Appropriate Legal Notices; however, if the Program has interactive | ||||
|     interfaces that do not display Appropriate Legal Notices, your | ||||
|     work need not make them do so. | ||||
|  | ||||
|   A compilation of a covered work with other separate and independent | ||||
| works, which are not by their nature extensions of the covered work, | ||||
| and which are not combined with it such as to form a larger program, | ||||
| in or on a volume of a storage or distribution medium, is called an | ||||
| "aggregate" if the compilation and its resulting copyright are not | ||||
| used to limit the access or legal rights of the compilation's users | ||||
| beyond what the individual works permit.  Inclusion of a covered work | ||||
| in an aggregate does not cause this License to apply to the other | ||||
| parts of the aggregate. | ||||
|  | ||||
|   6. Conveying Non-Source Forms. | ||||
|  | ||||
|   You may convey a covered work in object code form under the terms | ||||
| of sections 4 and 5, provided that you also convey the | ||||
| machine-readable Corresponding Source under the terms of this License, | ||||
| in one of these ways: | ||||
|  | ||||
|     a) Convey the object code in, or embodied in, a physical product | ||||
|     (including a physical distribution medium), accompanied by the | ||||
|     Corresponding Source fixed on a durable physical medium | ||||
|     customarily used for software interchange. | ||||
|  | ||||
|     b) Convey the object code in, or embodied in, a physical product | ||||
|     (including a physical distribution medium), accompanied by a | ||||
|     written offer, valid for at least three years and valid for as | ||||
|     long as you offer spare parts or customer support for that product | ||||
|     model, to give anyone who possesses the object code either (1) a | ||||
|     copy of the Corresponding Source for all the software in the | ||||
|     product that is covered by this License, on a durable physical | ||||
|     medium customarily used for software interchange, for a price no | ||||
|     more than your reasonable cost of physically performing this | ||||
|     conveying of source, or (2) access to copy the | ||||
|     Corresponding Source from a network server at no charge. | ||||
|  | ||||
|     c) Convey individual copies of the object code with a copy of the | ||||
|     written offer to provide the Corresponding Source.  This | ||||
|     alternative is allowed only occasionally and noncommercially, and | ||||
|     only if you received the object code with such an offer, in accord | ||||
|     with subsection 6b. | ||||
|  | ||||
|     d) Convey the object code by offering access from a designated | ||||
|     place (gratis or for a charge), and offer equivalent access to the | ||||
|     Corresponding Source in the same way through the same place at no | ||||
|     further charge.  You need not require recipients to copy the | ||||
|     Corresponding Source along with the object code.  If the place to | ||||
|     copy the object code is a network server, the Corresponding Source | ||||
|     may be on a different server (operated by you or a third party) | ||||
|     that supports equivalent copying facilities, provided you maintain | ||||
|     clear directions next to the object code saying where to find the | ||||
|     Corresponding Source.  Regardless of what server hosts the | ||||
|     Corresponding Source, you remain obligated to ensure that it is | ||||
|     available for as long as needed to satisfy these requirements. | ||||
|  | ||||
|     e) Convey the object code using peer-to-peer transmission, provided | ||||
|     you inform other peers where the object code and Corresponding | ||||
|     Source of the work are being offered to the general public at no | ||||
|     charge under subsection 6d. | ||||
|  | ||||
|   A separable portion of the object code, whose source code is excluded | ||||
| from the Corresponding Source as a System Library, need not be | ||||
| included in conveying the object code work. | ||||
|  | ||||
|   A "User Product" is either (1) a "consumer product", which means any | ||||
| tangible personal property which is normally used for personal, family, | ||||
| or household purposes, or (2) anything designed or sold for incorporation | ||||
| into a dwelling.  In determining whether a product is a consumer product, | ||||
| doubtful cases shall be resolved in favor of coverage.  For a particular | ||||
| product received by a particular user, "normally used" refers to a | ||||
| typical or common use of that class of product, regardless of the status | ||||
| of the particular user or of the way in which the particular user | ||||
| actually uses, or expects or is expected to use, the product.  A product | ||||
| is a consumer product regardless of whether the product has substantial | ||||
| commercial, industrial or non-consumer uses, unless such uses represent | ||||
| the only significant mode of use of the product. | ||||
|  | ||||
|   "Installation Information" for a User Product means any methods, | ||||
| procedures, authorization keys, or other information required to install | ||||
| and execute modified versions of a covered work in that User Product from | ||||
| a modified version of its Corresponding Source.  The information must | ||||
| suffice to ensure that the continued functioning of the modified object | ||||
| code is in no case prevented or interfered with solely because | ||||
| modification has been made. | ||||
|  | ||||
|   If you convey an object code work under this section in, or with, or | ||||
| specifically for use in, a User Product, and the conveying occurs as | ||||
| part of a transaction in which the right of possession and use of the | ||||
| User Product is transferred to the recipient in perpetuity or for a | ||||
| fixed term (regardless of how the transaction is characterized), the | ||||
| Corresponding Source conveyed under this section must be accompanied | ||||
| by the Installation Information.  But this requirement does not apply | ||||
| if neither you nor any third party retains the ability to install | ||||
| modified object code on the User Product (for example, the work has | ||||
| been installed in ROM). | ||||
|  | ||||
|   The requirement to provide Installation Information does not include a | ||||
| requirement to continue to provide support service, warranty, or updates | ||||
| for a work that has been modified or installed by the recipient, or for | ||||
| the User Product in which it has been modified or installed.  Access to a | ||||
| network may be denied when the modification itself materially and | ||||
| adversely affects the operation of the network or violates the rules and | ||||
| protocols for communication across the network. | ||||
|  | ||||
|   Corresponding Source conveyed, and Installation Information provided, | ||||
| in accord with this section must be in a format that is publicly | ||||
| documented (and with an implementation available to the public in | ||||
| source code form), and must require no special password or key for | ||||
| unpacking, reading or copying. | ||||
|  | ||||
|   7. Additional Terms. | ||||
|  | ||||
|   "Additional permissions" are terms that supplement the terms of this | ||||
| License by making exceptions from one or more of its conditions. | ||||
| Additional permissions that are applicable to the entire Program shall | ||||
| be treated as though they were included in this License, to the extent | ||||
| that they are valid under applicable law.  If additional permissions | ||||
| apply only to part of the Program, that part may be used separately | ||||
| under those permissions, but the entire Program remains governed by | ||||
| this License without regard to the additional permissions. | ||||
|  | ||||
|   When you convey a copy of a covered work, you may at your option | ||||
| remove any additional permissions from that copy, or from any part of | ||||
| it.  (Additional permissions may be written to require their own | ||||
| removal in certain cases when you modify the work.)  You may place | ||||
| additional permissions on material, added by you to a covered work, | ||||
| for which you have or can give appropriate copyright permission. | ||||
|  | ||||
|   Notwithstanding any other provision of this License, for material you | ||||
| add to a covered work, you may (if authorized by the copyright holders of | ||||
| that material) supplement the terms of this License with terms: | ||||
|  | ||||
|     a) Disclaiming warranty or limiting liability differently from the | ||||
|     terms of sections 15 and 16 of this License; or | ||||
|  | ||||
|     b) Requiring preservation of specified reasonable legal notices or | ||||
|     author attributions in that material or in the Appropriate Legal | ||||
|     Notices displayed by works containing it; or | ||||
|  | ||||
|     c) Prohibiting misrepresentation of the origin of that material, or | ||||
|     requiring that modified versions of such material be marked in | ||||
|     reasonable ways as different from the original version; or | ||||
|  | ||||
|     d) Limiting the use for publicity purposes of names of licensors or | ||||
|     authors of the material; or | ||||
|  | ||||
|     e) Declining to grant rights under trademark law for use of some | ||||
|     trade names, trademarks, or service marks; or | ||||
|  | ||||
|     f) Requiring indemnification of licensors and authors of that | ||||
|     material by anyone who conveys the material (or modified versions of | ||||
|     it) with contractual assumptions of liability to the recipient, for | ||||
|     any liability that these contractual assumptions directly impose on | ||||
|     those licensors and authors. | ||||
|  | ||||
|   All other non-permissive additional terms are considered "further | ||||
| restrictions" within the meaning of section 10.  If the Program as you | ||||
| received it, or any part of it, contains a notice stating that it is | ||||
| governed by this License along with a term that is a further | ||||
| restriction, you may remove that term.  If a license document contains | ||||
| a further restriction but permits relicensing or conveying under this | ||||
| License, you may add to a covered work material governed by the terms | ||||
| of that license document, provided that the further restriction does | ||||
| not survive such relicensing or conveying. | ||||
|  | ||||
|   If you add terms to a covered work in accord with this section, you | ||||
| must place, in the relevant source files, a statement of the | ||||
| additional terms that apply to those files, or a notice indicating | ||||
| where to find the applicable terms. | ||||
|  | ||||
|   Additional terms, permissive or non-permissive, may be stated in the | ||||
| form of a separately written license, or stated as exceptions; | ||||
| the above requirements apply either way. | ||||
|  | ||||
|   8. Termination. | ||||
|  | ||||
|   You may not propagate or modify a covered work except as expressly | ||||
| provided under this License.  Any attempt otherwise to propagate or | ||||
| modify it is void, and will automatically terminate your rights under | ||||
| this License (including any patent licenses granted under the third | ||||
| paragraph of section 11). | ||||
|  | ||||
|   However, if you cease all violation of this License, then your | ||||
| license from a particular copyright holder is reinstated (a) | ||||
| provisionally, unless and until the copyright holder explicitly and | ||||
| finally terminates your license, and (b) permanently, if the copyright | ||||
| holder fails to notify you of the violation by some reasonable means | ||||
| prior to 60 days after the cessation. | ||||
|  | ||||
|   Moreover, your license from a particular copyright holder is | ||||
| reinstated permanently if the copyright holder notifies you of the | ||||
| violation by some reasonable means, this is the first time you have | ||||
| received notice of violation of this License (for any work) from that | ||||
| copyright holder, and you cure the violation prior to 30 days after | ||||
| your receipt of the notice. | ||||
|  | ||||
|   Termination of your rights under this section does not terminate the | ||||
| licenses of parties who have received copies or rights from you under | ||||
| this License.  If your rights have been terminated and not permanently | ||||
| reinstated, you do not qualify to receive new licenses for the same | ||||
| material under section 10. | ||||
|  | ||||
|   9. Acceptance Not Required for Having Copies. | ||||
|  | ||||
|   You are not required to accept this License in order to receive or | ||||
| run a copy of the Program.  Ancillary propagation of a covered work | ||||
| occurring solely as a consequence of using peer-to-peer transmission | ||||
| to receive a copy likewise does not require acceptance.  However, | ||||
| nothing other than this License grants you permission to propagate or | ||||
| modify any covered work.  These actions infringe copyright if you do | ||||
| not accept this License.  Therefore, by modifying or propagating a | ||||
| covered work, you indicate your acceptance of this License to do so. | ||||
|  | ||||
|   10. Automatic Licensing of Downstream Recipients. | ||||
|  | ||||
|   Each time you convey a covered work, the recipient automatically | ||||
| receives a license from the original licensors, to run, modify and | ||||
| propagate that work, subject to this License.  You are not responsible | ||||
| for enforcing compliance by third parties with this License. | ||||
|  | ||||
|   An "entity transaction" is a transaction transferring control of an | ||||
| organization, or substantially all assets of one, or subdividing an | ||||
| organization, or merging organizations.  If propagation of a covered | ||||
| work results from an entity transaction, each party to that | ||||
| transaction who receives a copy of the work also receives whatever | ||||
| licenses to the work the party's predecessor in interest had or could | ||||
| give under the previous paragraph, plus a right to possession of the | ||||
| Corresponding Source of the work from the predecessor in interest, if | ||||
| the predecessor has it or can get it with reasonable efforts. | ||||
|  | ||||
|   You may not impose any further restrictions on the exercise of the | ||||
| rights granted or affirmed under this License.  For example, you may | ||||
| not impose a license fee, royalty, or other charge for exercise of | ||||
| rights granted under this License, and you may not initiate litigation | ||||
| (including a cross-claim or counterclaim in a lawsuit) alleging that | ||||
| any patent claim is infringed by making, using, selling, offering for | ||||
| sale, or importing the Program or any portion of it. | ||||
|  | ||||
|   11. Patents. | ||||
|  | ||||
|   A "contributor" is a copyright holder who authorizes use under this | ||||
| License of the Program or a work on which the Program is based.  The | ||||
| work thus licensed is called the contributor's "contributor version". | ||||
|  | ||||
|   A contributor's "essential patent claims" are all patent claims | ||||
| owned or controlled by the contributor, whether already acquired or | ||||
| hereafter acquired, that would be infringed by some manner, permitted | ||||
| by this License, of making, using, or selling its contributor version, | ||||
| but do not include claims that would be infringed only as a | ||||
| consequence of further modification of the contributor version.  For | ||||
| purposes of this definition, "control" includes the right to grant | ||||
| patent sublicenses in a manner consistent with the requirements of | ||||
| this License. | ||||
|  | ||||
|   Each contributor grants you a non-exclusive, worldwide, royalty-free | ||||
| patent license under the contributor's essential patent claims, to | ||||
| make, use, sell, offer for sale, import and otherwise run, modify and | ||||
| propagate the contents of its contributor version. | ||||
|  | ||||
|   In the following three paragraphs, a "patent license" is any express | ||||
| agreement or commitment, however denominated, not to enforce a patent | ||||
| (such as an express permission to practice a patent or covenant not to | ||||
| sue for patent infringement).  To "grant" such a patent license to a | ||||
| party means to make such an agreement or commitment not to enforce a | ||||
| patent against the party. | ||||
|  | ||||
|   If you convey a covered work, knowingly relying on a patent license, | ||||
| and the Corresponding Source of the work is not available for anyone | ||||
| to copy, free of charge and under the terms of this License, through a | ||||
| publicly available network server or other readily accessible means, | ||||
| then you must either (1) cause the Corresponding Source to be so | ||||
| available, or (2) arrange to deprive yourself of the benefit of the | ||||
| patent license for this particular work, or (3) arrange, in a manner | ||||
| consistent with the requirements of this License, to extend the patent | ||||
| license to downstream recipients.  "Knowingly relying" means you have | ||||
| actual knowledge that, but for the patent license, your conveying the | ||||
| covered work in a country, or your recipient's use of the covered work | ||||
| in a country, would infringe one or more identifiable patents in that | ||||
| country that you have reason to believe are valid. | ||||
|  | ||||
|   If, pursuant to or in connection with a single transaction or | ||||
| arrangement, you convey, or propagate by procuring conveyance of, a | ||||
| covered work, and grant a patent license to some of the parties | ||||
| receiving the covered work authorizing them to use, propagate, modify | ||||
| or convey a specific copy of the covered work, then the patent license | ||||
| you grant is automatically extended to all recipients of the covered | ||||
| work and works based on it. | ||||
|  | ||||
|   A patent license is "discriminatory" if it does not include within | ||||
| the scope of its coverage, prohibits the exercise of, or is | ||||
| conditioned on the non-exercise of one or more of the rights that are | ||||
| specifically granted under this License.  You may not convey a covered | ||||
| work if you are a party to an arrangement with a third party that is | ||||
| in the business of distributing software, under which you make payment | ||||
| to the third party based on the extent of your activity of conveying | ||||
| the work, and under which the third party grants, to any of the | ||||
| parties who would receive the covered work from you, a discriminatory | ||||
| patent license (a) in connection with copies of the covered work | ||||
| conveyed by you (or copies made from those copies), or (b) primarily | ||||
| for and in connection with specific products or compilations that | ||||
| contain the covered work, unless you entered into that arrangement, | ||||
| or that patent license was granted, prior to 28 March 2007. | ||||
|  | ||||
|   Nothing in this License shall be construed as excluding or limiting | ||||
| any implied license or other defenses to infringement that may | ||||
| otherwise be available to you under applicable patent law. | ||||
|  | ||||
|   12. No Surrender of Others' Freedom. | ||||
|  | ||||
|   If conditions are imposed on you (whether by court order, agreement or | ||||
| otherwise) that contradict the conditions of this License, they do not | ||||
| excuse you from the conditions of this License.  If you cannot convey a | ||||
| covered work so as to satisfy simultaneously your obligations under this | ||||
| License and any other pertinent obligations, then as a consequence you may | ||||
| not convey it at all.  For example, if you agree to terms that obligate you | ||||
| to collect a royalty for further conveying from those to whom you convey | ||||
| the Program, the only way you could satisfy both those terms and this | ||||
| License would be to refrain entirely from conveying the Program. | ||||
|  | ||||
|   13. Remote Network Interaction; Use with the GNU General Public License. | ||||
|  | ||||
|   Notwithstanding any other provision of this License, if you modify the | ||||
| Program, your modified version must prominently offer all users | ||||
| interacting with it remotely through a computer network (if your version | ||||
| supports such interaction) an opportunity to receive the Corresponding | ||||
| Source of your version by providing access to the Corresponding Source | ||||
| from a network server at no charge, through some standard or customary | ||||
| means of facilitating copying of software.  This Corresponding Source | ||||
| shall include the Corresponding Source for any work covered by version 3 | ||||
| of the GNU General Public License that is incorporated pursuant to the | ||||
| following paragraph. | ||||
|  | ||||
|   Notwithstanding any other provision of this License, you have | ||||
| permission to link or combine any covered work with a work licensed | ||||
| under version 3 of the GNU General Public License into a single | ||||
| combined work, and to convey the resulting work.  The terms of this | ||||
| License will continue to apply to the part which is the covered work, | ||||
| but the work with which it is combined will remain governed by version | ||||
| 3 of the GNU General Public License. | ||||
|  | ||||
|   14. Revised Versions of this License. | ||||
|  | ||||
|   The Free Software Foundation may publish revised and/or new versions of | ||||
| the GNU Affero General Public License from time to time.  Such new versions | ||||
| will be similar in spirit to the present version, but may differ in detail to | ||||
| address new problems or concerns. | ||||
|  | ||||
|   Each version is given a distinguishing version number.  If the | ||||
| Program specifies that a certain numbered version of the GNU Affero General | ||||
| Public License "or any later version" applies to it, you have the | ||||
| option of following the terms and conditions either of that numbered | ||||
| version or of any later version published by the Free Software | ||||
| Foundation.  If the Program does not specify a version number of the | ||||
| GNU Affero General Public License, you may choose any version ever published | ||||
| by the Free Software Foundation. | ||||
|  | ||||
|   If the Program specifies that a proxy can decide which future | ||||
| versions of the GNU Affero General Public License can be used, that proxy's | ||||
| public statement of acceptance of a version permanently authorizes you | ||||
| to choose that version for the Program. | ||||
|  | ||||
|   Later license versions may give you additional or different | ||||
| permissions.  However, no additional obligations are imposed on any | ||||
| author or copyright holder as a result of your choosing to follow a | ||||
| later version. | ||||
|  | ||||
|   15. Disclaimer of Warranty. | ||||
|  | ||||
|   THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY | ||||
| APPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT | ||||
| HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY | ||||
| OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, | ||||
| THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | ||||
| PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM | ||||
| IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF | ||||
| ALL NECESSARY SERVICING, REPAIR OR CORRECTION. | ||||
|  | ||||
|   16. Limitation of Liability. | ||||
|  | ||||
|   IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING | ||||
| WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS | ||||
| THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY | ||||
| GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE | ||||
| USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF | ||||
| DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD | ||||
| PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), | ||||
| EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF | ||||
| SUCH DAMAGES. | ||||
|  | ||||
|   17. Interpretation of Sections 15 and 16. | ||||
|  | ||||
|   If the disclaimer of warranty and limitation of liability provided | ||||
| above cannot be given local legal effect according to their terms, | ||||
| reviewing courts shall apply local law that most closely approximates | ||||
| an absolute waiver of all civil liability in connection with the | ||||
| Program, unless a warranty or assumption of liability accompanies a | ||||
| copy of the Program in return for a fee. | ||||
|  | ||||
|                      END OF TERMS AND CONDITIONS | ||||
|  | ||||
|             How to Apply These Terms to Your New Programs | ||||
|  | ||||
|   If you develop a new program, and you want it to be of the greatest | ||||
| possible use to the public, the best way to achieve this is to make it | ||||
| free software which everyone can redistribute and change under these terms. | ||||
|  | ||||
|   To do so, attach the following notices to the program.  It is safest | ||||
| to attach them to the start of each source file to most effectively | ||||
| state the exclusion of warranty; and each file should have at least | ||||
| the "copyright" line and a pointer to where the full notice is found. | ||||
|  | ||||
|     <one line to give the program's name and a brief idea of what it does.> | ||||
|     Copyright (C) <year>  <name of author> | ||||
|  | ||||
|     This program is free software: you can redistribute it and/or modify | ||||
|     it under the terms of the GNU Affero General Public License as published by | ||||
|     the Free Software Foundation, either version 3 of the License, or | ||||
|     (at your option) any later version. | ||||
|  | ||||
|     This program is distributed in the hope that it will be useful, | ||||
|     but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|     GNU Affero General Public License for more details. | ||||
|  | ||||
|     You should have received a copy of the GNU Affero General Public License | ||||
|     along with this program.  If not, see <https://www.gnu.org/licenses/>. | ||||
|  | ||||
| Also add information on how to contact you by electronic and paper mail. | ||||
|  | ||||
|   If your software can interact with users remotely through a computer | ||||
| network, you should also make sure that it provides a way for users to | ||||
| get its source.  For example, if your program is a web application, its | ||||
| interface could display a "Source" link that leads users to an archive | ||||
| of the code.  There are many ways you could offer source, and different | ||||
| solutions will be better for different programs; see section 13 for the | ||||
| specific requirements. | ||||
|  | ||||
|   You should also get your employer (if you work as a programmer) or school, | ||||
| if any, to sign a "copyright disclaimer" for the program, if necessary. | ||||
| For more information on this, and how to apply and follow the GNU AGPL, see | ||||
| <https://www.gnu.org/licenses/>. | ||||
| @@ -1,11 +0,0 @@ | ||||
| <p align="center"> | ||||
|   <a href="https://v2.nonebot.dev/"><img src="https://raw.githubusercontent.com/nonebot/nonebot2/master/docs/.vuepress/public/logo.png" width="200" height="200" alt="nonebot"></a> | ||||
| </p> | ||||
|  | ||||
| <div align="center"> | ||||
|  | ||||
| # NoneBot-Adapter-MIRAI | ||||
|  | ||||
| _✨ mirai-api-http 协议适配 ✨_ | ||||
|  | ||||
| </div> | ||||
| @@ -1,37 +0,0 @@ | ||||
| r""" | ||||
| Mirai-API-HTTP 协议适配 | ||||
| ============================ | ||||
|  | ||||
| 协议详情请看: `mirai-api-http 文档`_ | ||||
|  | ||||
| \:\:\: tip | ||||
| 该Adapter目前仍然处在早期实验性阶段, 并未经过充分测试 | ||||
|  | ||||
| 如果你在使用过程中遇到了任何问题, 请前往 `Issue页面`_ 为我们提供反馈 | ||||
| \:\:\: | ||||
|  | ||||
| \:\:\: danger | ||||
| Mirai-API-HTTP 的适配器以 `AGPLv3许可`_ 单独开源 | ||||
|  | ||||
| 这意味着在使用该适配器时需要 **以该许可开源您的完整程序代码** | ||||
| \:\:\: | ||||
|  | ||||
| .. _mirai-api-http 文档: | ||||
|     https://github.com/project-mirai/mirai-api-http/tree/master/docs | ||||
|  | ||||
| .. _Issue页面: | ||||
|     https://github.com/nonebot/nonebot2/issues | ||||
|  | ||||
| .. _AGPLv3许可: | ||||
|     https://opensource.org/licenses/AGPL-3.0 | ||||
|  | ||||
| """ | ||||
|  | ||||
| from .bot import Bot | ||||
| from .event import * | ||||
| from .message import MessageChain, MessageSegment | ||||
|  | ||||
| WebsocketBot = Bot | ||||
| """ | ||||
| ``WebsocketBot``现在已经和``Bot``合并, 并已经被弃用, 请直接使用``Bot`` | ||||
| """ | ||||
| @@ -1,749 +0,0 @@ | ||||
| import json | ||||
| import asyncio | ||||
| from io import BytesIO | ||||
| from functools import partial | ||||
| from ipaddress import IPv4Address | ||||
| from typing import Any, Dict, List, Tuple, Union, NoReturn, Optional | ||||
|  | ||||
| import httpx | ||||
| from loguru import logger | ||||
|  | ||||
| from nonebot.config import Config | ||||
| from nonebot.typing import overrides | ||||
| from nonebot.adapters import Bot as BaseBot | ||||
| from nonebot.exception import ApiNotAvailable | ||||
| from nonebot.drivers import ( | ||||
|     Driver, | ||||
|     WebSocket, | ||||
|     HTTPResponse, | ||||
|     ForwardDriver, | ||||
|     ReverseDriver, | ||||
|     HTTPConnection, | ||||
|     WebSocketSetup, | ||||
| ) | ||||
|  | ||||
| from .config import Config as MiraiConfig | ||||
| from .message import MessageChain, MessageSegment | ||||
| from .event import Event, TempMessage, GroupMessage, FriendMessage | ||||
| from .utils import Log, process_event, argument_validation, catch_network_error | ||||
|  | ||||
|  | ||||
| class SessionManager: | ||||
|     """Bot会话管理器, 提供API主动调用接口""" | ||||
|  | ||||
|     sessions: Dict[int, Tuple[str, httpx.AsyncClient]] = {} | ||||
|  | ||||
|     def __init__(self, session_key: str, client: httpx.AsyncClient): | ||||
|         self.session_key, self.client = session_key, client | ||||
|  | ||||
|     @catch_network_error | ||||
|     async def post(self, path: str, *, params: Optional[Dict[str, Any]] = None) -> Any: | ||||
|         """ | ||||
|         :说明: | ||||
|  | ||||
|           以POST方式主动提交API请求 | ||||
|  | ||||
|         :参数: | ||||
|  | ||||
|           * ``path: str``: 对应API路径 | ||||
|           * ``params: Optional[Dict[str, Any]]``: 请求参数 (无需sessionKey) | ||||
|  | ||||
|         :返回: | ||||
|  | ||||
|           - ``Dict[str, Any]``: API 返回值 | ||||
|         """ | ||||
|         response = await self.client.post( | ||||
|             path, | ||||
|             json={ | ||||
|                 **(params or {}), | ||||
|                 "sessionKey": self.session_key, | ||||
|             }, | ||||
|             timeout=3, | ||||
|         ) | ||||
|         response.raise_for_status() | ||||
|         return response.json() | ||||
|  | ||||
|     @catch_network_error | ||||
|     async def request( | ||||
|         self, path: str, *, params: Optional[Dict[str, Any]] = None | ||||
|     ) -> Any: | ||||
|         """ | ||||
|         :说明: | ||||
|  | ||||
|           以GET方式主动提交API请求 | ||||
|  | ||||
|         :参数: | ||||
|  | ||||
|           * ``path: str``: 对应API路径 | ||||
|           * ``params: Optional[Dict[str, Any]]``: 请求参数 (无需sessionKey) | ||||
|         """ | ||||
|         response = await self.client.get( | ||||
|             path, | ||||
|             params={ | ||||
|                 **(params or {}), | ||||
|                 "sessionKey": self.session_key, | ||||
|             }, | ||||
|             timeout=3, | ||||
|         ) | ||||
|         response.raise_for_status() | ||||
|         return response.json() | ||||
|  | ||||
|     @catch_network_error | ||||
|     async def upload(self, path: str, *, params: Dict[str, Any]) -> Any: | ||||
|         """ | ||||
|         :说明: | ||||
|  | ||||
|             以表单(``multipart/form-data``)形式主动提交API请求 | ||||
|  | ||||
|         :参数: | ||||
|  | ||||
|             * ``path: str``: 对应API路径 | ||||
|             * ``params: Dict[str, Any]``: 请求参数 (无需sessionKey) | ||||
|         """ | ||||
|         files = {k: v for k, v in params.items() if isinstance(v, BytesIO)} | ||||
|         form = {k: v for k, v in params.items() if k not in files} | ||||
|         form["sessionKey"] = self.session_key | ||||
|         response = await self.client.post( | ||||
|             path, | ||||
|             data=form, | ||||
|             files=files, | ||||
|             timeout=6, | ||||
|         ) | ||||
|         response.raise_for_status() | ||||
|         return response.json() | ||||
|  | ||||
|     @classmethod | ||||
|     async def new( | ||||
|         cls, self_id: int, *, host: IPv4Address, port: int, auth_key: str | ||||
|     ) -> "SessionManager": | ||||
|         session = cls.get(self_id) | ||||
|         if session is not None: | ||||
|             return session | ||||
|  | ||||
|         client = httpx.AsyncClient( | ||||
|             base_url=f"http://{host}:{port}", follow_redirects=True | ||||
|         ) | ||||
|         response = await client.post("/auth", json={"authKey": auth_key}) | ||||
|         response.raise_for_status() | ||||
|         auth = response.json() | ||||
|         assert auth["code"] == 0 | ||||
|         session_key = auth["session"] | ||||
|         response = await client.post( | ||||
|             "/verify", json={"sessionKey": session_key, "qq": self_id} | ||||
|         ) | ||||
|         assert response.json()["code"] == 0 | ||||
|         cls.sessions[self_id] = session_key, client | ||||
|  | ||||
|         return cls(session_key, client) | ||||
|  | ||||
|     @classmethod | ||||
|     def get(cls, self_id: int): | ||||
|         if self_id not in cls.sessions: | ||||
|             return None | ||||
|         key, client = cls.sessions[self_id] | ||||
|         return cls(key, client) | ||||
|  | ||||
|  | ||||
| class Bot(BaseBot): | ||||
|     r""" | ||||
|     mirai-api-http 协议 Bot 适配。 | ||||
|  | ||||
|     \:\:\: warning | ||||
|     API中为了使代码更加整洁, 我们采用了与PEP8相符的命名规则取代Mirai原有的驼峰命名 | ||||
|  | ||||
|     部分字段可能与文档在符号上不一致 | ||||
|     \:\:\: | ||||
|  | ||||
|     """ | ||||
|  | ||||
|     _type = "mirai" | ||||
|  | ||||
|     @property | ||||
|     @overrides(BaseBot) | ||||
|     def type(self) -> str: | ||||
|         return self._type | ||||
|  | ||||
|     @property | ||||
|     def api(self) -> SessionManager: | ||||
|         """返回该Bot对象的会话管理实例以提供API主动调用""" | ||||
|         api = SessionManager.get(self_id=int(self.self_id)) | ||||
|         if api is None: | ||||
|             if isinstance(self.request, WebSocket): | ||||
|                 asyncio.create_task(self.request.close(1000)) | ||||
|         assert api is not None, "SessionManager has not been initialized" | ||||
|         return api | ||||
|  | ||||
|     @classmethod | ||||
|     @overrides(BaseBot) | ||||
|     async def check_permission( | ||||
|         cls, driver: Driver, request: HTTPConnection | ||||
|     ) -> Tuple[Optional[str], HTTPResponse]: | ||||
|         if isinstance(request, WebSocket): | ||||
|             return None, HTTPResponse(501, b"Websocket connection is not implemented") | ||||
|         self_id: Optional[str] = request.headers.get("bot") | ||||
|         if self_id is None: | ||||
|             return None, HTTPResponse(400, b"Header `Bot` is required.") | ||||
|         self_id = str(self_id).strip() | ||||
|         await SessionManager.new( | ||||
|             int(self_id), | ||||
|             host=cls.mirai_config.host,  # type: ignore | ||||
|             port=cls.mirai_config.port,  # type: ignore | ||||
|             auth_key=cls.mirai_config.auth_key,  # type: ignore | ||||
|         ) | ||||
|         return self_id, HTTPResponse(204, b"") | ||||
|  | ||||
|     @classmethod | ||||
|     @overrides(BaseBot) | ||||
|     def register( | ||||
|         cls, | ||||
|         driver: Driver, | ||||
|         config: "Config", | ||||
|         qq: Optional[Union[int, List[int]]] = None, | ||||
|     ): | ||||
|         cls.mirai_config = MiraiConfig(**config.dict()) | ||||
|         if ( | ||||
|             cls.mirai_config.auth_key | ||||
|             and cls.mirai_config.host | ||||
|             and cls.mirai_config.port | ||||
|         ) is None: | ||||
|             raise ApiNotAvailable(cls._type) | ||||
|  | ||||
|         super().register(driver, config) | ||||
|  | ||||
|         if not isinstance(driver, ForwardDriver) and qq: | ||||
|             logger.warning( | ||||
|                 f"Current driver {cls.config.driver} don't support forward connections" | ||||
|             ) | ||||
|         elif isinstance(driver, ForwardDriver) and qq: | ||||
|             self_ids = [qq] if isinstance(qq, int) else qq | ||||
|  | ||||
|             async def url_factory(qq: int): | ||||
|                 assert ( | ||||
|                     cls.mirai_config.host | ||||
|                     and cls.mirai_config.port | ||||
|                     and cls.mirai_config.auth_key | ||||
|                 ) | ||||
|                 session = await SessionManager.new( | ||||
|                     qq, | ||||
|                     host=cls.mirai_config.host, | ||||
|                     port=cls.mirai_config.port, | ||||
|                     auth_key=cls.mirai_config.auth_key, | ||||
|                 ) | ||||
|                 return WebSocketSetup( | ||||
|                     adapter=cls._type, | ||||
|                     self_id=str(qq), | ||||
|                     url=( | ||||
|                         f"ws://{cls.mirai_config.host}:{cls.mirai_config.port}" | ||||
|                         f"/all?sessionKey={session.session_key}" | ||||
|                     ), | ||||
|                 ) | ||||
|  | ||||
|             for self_id in self_ids: | ||||
|                 driver.setup_websocket(partial(url_factory, qq=self_id)) | ||||
|  | ||||
|         elif isinstance(driver, ReverseDriver): | ||||
|             logger.debug( | ||||
|                 'Param "qq" does not set for mirai adapter, use http post instead' | ||||
|             ) | ||||
|  | ||||
|     @overrides(BaseBot) | ||||
|     async def handle_message(self, message: bytes): | ||||
|         try: | ||||
|             await process_event( | ||||
|                 bot=self, | ||||
|                 event=Event.new( | ||||
|                     { | ||||
|                         **json.loads(message), | ||||
|                         "self_id": self.self_id, | ||||
|                     } | ||||
|                 ), | ||||
|             ) | ||||
|         except Exception as e: | ||||
|             Log.error(f"Failed to handle message: {message}", e) | ||||
|  | ||||
|     @overrides(BaseBot) | ||||
|     async def _call_api(self, api: str, **data) -> NoReturn: | ||||
|         raise NotImplementedError | ||||
|  | ||||
|     @overrides(BaseBot) | ||||
|     async def call_api(self, api: str, **data) -> NoReturn: | ||||
|         r""" | ||||
|         \:\:\: danger | ||||
|         由于Mirai的HTTP API特殊性, 该API暂时无法实现 | ||||
|         \:\:\: | ||||
|  | ||||
|         \:\:\: tip | ||||
|         你可以使用 ``MiraiBot.api`` 中提供的调用方法来代替 | ||||
|         \:\:\: | ||||
|         """ | ||||
|         raise NotImplementedError | ||||
|  | ||||
|     @overrides(BaseBot) | ||||
|     def __getattr__(self, key: str) -> NoReturn: | ||||
|         """由于Mirai的HTTP API特殊性, 该API暂时无法实现""" | ||||
|         raise NotImplementedError | ||||
|  | ||||
|     @overrides(BaseBot) | ||||
|     @argument_validation | ||||
|     async def send( | ||||
|         self, | ||||
|         event: Event, | ||||
|         message: Union[MessageChain, MessageSegment, str], | ||||
|         at_sender: bool = False, | ||||
|     ): | ||||
|         """ | ||||
|         :说明: | ||||
|  | ||||
|           根据 ``event`` 向触发事件的主体发送信息 | ||||
|  | ||||
|         :参数: | ||||
|  | ||||
|           * ``event: Event``: Event对象 | ||||
|           * ``message: Union[MessageChain, MessageSegment, str]``: 要发送的消息 | ||||
|           * ``at_sender: bool``: 是否 @ 事件主体 | ||||
|         """ | ||||
|         if not isinstance(message, MessageChain): | ||||
|             message = MessageChain(message) | ||||
|         if isinstance(event, FriendMessage): | ||||
|             return await self.send_friend_message( | ||||
|                 target=event.sender.id, message_chain=message | ||||
|             ) | ||||
|         elif isinstance(event, GroupMessage): | ||||
|             if at_sender: | ||||
|                 message = MessageSegment.at(event.sender.id) + message | ||||
|             return await self.send_group_message( | ||||
|                 group=event.sender.group.id, message_chain=message | ||||
|             ) | ||||
|         elif isinstance(event, TempMessage): | ||||
|             return await self.send_temp_message( | ||||
|                 qq=event.sender.id, group=event.sender.group.id, message_chain=message | ||||
|             ) | ||||
|         else: | ||||
|             raise ValueError(f"Unsupported event type {event!r}.") | ||||
|  | ||||
|     @argument_validation | ||||
|     async def send_friend_message(self, target: int, message_chain: MessageChain): | ||||
|         """ | ||||
|         :说明: | ||||
|  | ||||
|           使用此方法向指定好友发送消息 | ||||
|  | ||||
|         :参数: | ||||
|  | ||||
|           * ``target: int``: 发送消息目标好友的 QQ 号 | ||||
|           * ``message_chain: MessageChain``: 消息链,是一个消息对象构成的数组 | ||||
|         """ | ||||
|         return await self.api.post( | ||||
|             "sendFriendMessage", | ||||
|             params={"target": target, "messageChain": message_chain.export()}, | ||||
|         ) | ||||
|  | ||||
|     @argument_validation | ||||
|     async def send_temp_message(self, qq: int, group: int, message_chain: MessageChain): | ||||
|         """ | ||||
|         :说明: | ||||
|  | ||||
|           使用此方法向临时会话对象发送消息 | ||||
|  | ||||
|         :参数: | ||||
|  | ||||
|           * ``qq: int``: 临时会话对象 QQ 号 | ||||
|           * ``group: int``: 临时会话群号 | ||||
|           * ``message_chain: MessageChain``: 消息链,是一个消息对象构成的数组 | ||||
|         """ | ||||
|         return await self.api.post( | ||||
|             "sendTempMessage", | ||||
|             params={"qq": qq, "group": group, "messageChain": message_chain.export()}, | ||||
|         ) | ||||
|  | ||||
|     @argument_validation | ||||
|     async def send_group_message( | ||||
|         self, group: int, message_chain: MessageChain, quote: Optional[int] = None | ||||
|     ): | ||||
|         """ | ||||
|         :说明: | ||||
|  | ||||
|           使用此方法向指定群发送消息 | ||||
|  | ||||
|         :参数: | ||||
|  | ||||
|           * ``group: int``: 发送消息目标群的群号 | ||||
|           * ``message_chain: MessageChain``: 消息链,是一个消息对象构成的数组 | ||||
|           * ``quote: Optional[int]``: 引用一条消息的 message_id 进行回复 | ||||
|         """ | ||||
|         return await self.api.post( | ||||
|             "sendGroupMessage", | ||||
|             params={ | ||||
|                 "group": group, | ||||
|                 "messageChain": message_chain.export(), | ||||
|                 "quote": quote, | ||||
|             }, | ||||
|         ) | ||||
|  | ||||
|     @argument_validation | ||||
|     async def recall(self, target: int): | ||||
|         """ | ||||
|         :说明: | ||||
|  | ||||
|           使用此方法撤回指定消息。对于bot发送的消息,有2分钟时间限制。对于撤回群聊中群员的消息,需要有相应权限 | ||||
|  | ||||
|         :参数: | ||||
|  | ||||
|           * ``target: int``: 需要撤回的消息的message_id | ||||
|         """ | ||||
|         return await self.api.post("recall", params={"target": target}) | ||||
|  | ||||
|     @argument_validation | ||||
|     async def send_image_message( | ||||
|         self, target: int, qq: int, group: int, urls: List[str] | ||||
|     ) -> List[str]: | ||||
|         """ | ||||
|         :说明: | ||||
|  | ||||
|           使用此方法向指定对象(群或好友)发送图片消息 | ||||
|           除非需要通过此手段获取image_id,否则不推荐使用该接口 | ||||
|  | ||||
|           > 当qq和group同时存在时,表示发送临时会话图片,qq为临时会话对象QQ号,group为临时会话发起的群号 | ||||
|  | ||||
|         :参数: | ||||
|  | ||||
|           * ``target: int``: 发送对象的QQ号或群号,可能存在歧义 | ||||
|           * ``qq: int``: 发送对象的QQ号 | ||||
|           * ``group: int``: 发送对象的群号 | ||||
|           * ``urls: List[str]``: 是一个url字符串构成的数组 | ||||
|  | ||||
|         :返回: | ||||
|  | ||||
|           - ``List[str]``: 一个包含图片imageId的数组 | ||||
|         """ | ||||
|         return await self.api.post( | ||||
|             "sendImageMessage", | ||||
|             params={"target": target, "qq": qq, "group": group, "urls": urls}, | ||||
|         ) | ||||
|  | ||||
|     @argument_validation | ||||
|     async def upload_image(self, type: str, img: BytesIO): | ||||
|         """ | ||||
|         :说明: | ||||
|  | ||||
|            使用此方法上传图片文件至服务器并返回Image_id | ||||
|  | ||||
|         :参数: | ||||
|  | ||||
|           * ``type: str``: "friend" 或 "group" 或 "temp" | ||||
|           * ``img: BytesIO``: 图片的BytesIO对象 | ||||
|         """ | ||||
|         return await self.api.upload("uploadImage", params={"type": type, "img": img}) | ||||
|  | ||||
|     @argument_validation | ||||
|     async def upload_voice(self, type: str, voice: BytesIO): | ||||
|         """ | ||||
|         :说明: | ||||
|  | ||||
|           使用此方法上传语音文件至服务器并返回voice_id | ||||
|  | ||||
|         :参数: | ||||
|  | ||||
|           * ``type: str``: 当前仅支持 "group" | ||||
|           * ``voice: BytesIO``: 语音的BytesIO对象 | ||||
|         """ | ||||
|         return await self.api.upload( | ||||
|             "uploadVoice", params={"type": type, "voice": voice} | ||||
|         ) | ||||
|  | ||||
|     @argument_validation | ||||
|     async def fetch_message(self, count: int = 10): | ||||
|         """ | ||||
|         :说明: | ||||
|  | ||||
|           使用此方法获取bot接收到的最老消息和最老各类事件 | ||||
|           (会从MiraiApiHttp消息记录中删除) | ||||
|  | ||||
|         :参数: | ||||
|  | ||||
|           * ``count: int``: 获取消息和事件的数量 | ||||
|         """ | ||||
|         return await self.api.request("fetchMessage", params={"count": count}) | ||||
|  | ||||
|     @argument_validation | ||||
|     async def fetch_latest_message(self, count: int = 10): | ||||
|         """ | ||||
|         :说明: | ||||
|  | ||||
|           使用此方法获取bot接收到的最新消息和最新各类事件 | ||||
|           (会从MiraiApiHttp消息记录中删除) | ||||
|  | ||||
|         :参数: | ||||
|  | ||||
|           * ``count: int``: 获取消息和事件的数量 | ||||
|         """ | ||||
|         return await self.api.request("fetchLatestMessage", params={"count": count}) | ||||
|  | ||||
|     @argument_validation | ||||
|     async def peek_message(self, count: int = 10): | ||||
|         """ | ||||
|         :说明: | ||||
|  | ||||
|           使用此方法获取bot接收到的最老消息和最老各类事件 | ||||
|           (不会从MiraiApiHttp消息记录中删除) | ||||
|  | ||||
|         :参数: | ||||
|  | ||||
|           * ``count: int``: 获取消息和事件的数量 | ||||
|         """ | ||||
|         return await self.api.request("peekMessage", params={"count": count}) | ||||
|  | ||||
|     @argument_validation | ||||
|     async def peek_latest_message(self, count: int = 10): | ||||
|         """ | ||||
|         :说明: | ||||
|  | ||||
|           使用此方法获取bot接收到的最新消息和最新各类事件 | ||||
|           (不会从MiraiApiHttp消息记录中删除) | ||||
|  | ||||
|         :参数: | ||||
|  | ||||
|           * ``count: int``: 获取消息和事件的数量 | ||||
|         """ | ||||
|         return await self.api.request("peekLatestMessage", params={"count": count}) | ||||
|  | ||||
|     @argument_validation | ||||
|     async def messsage_from_id(self, id: int): | ||||
|         """ | ||||
|         :说明: | ||||
|  | ||||
|           通过messageId获取一条被缓存的消息 | ||||
|           使用此方法获取bot接收到的消息和各类事件 | ||||
|  | ||||
|         :参数: | ||||
|  | ||||
|           * ``id: int``: 获取消息的message_id | ||||
|         """ | ||||
|         return await self.api.request("messageFromId", params={"id": id}) | ||||
|  | ||||
|     @argument_validation | ||||
|     async def count_message(self): | ||||
|         """ | ||||
|         :说明: | ||||
|  | ||||
|           使用此方法获取bot接收并缓存的消息总数,注意不包含被删除的 | ||||
|         """ | ||||
|         return await self.api.request("countMessage") | ||||
|  | ||||
|     @argument_validation | ||||
|     async def friend_list(self) -> List[Dict[str, Any]]: | ||||
|         """ | ||||
|         :说明: | ||||
|  | ||||
|           使用此方法获取bot的好友列表 | ||||
|  | ||||
|         :返回: | ||||
|  | ||||
|           - ``List[Dict[str, Any]]``: 返回的好友列表数据 | ||||
|         """ | ||||
|         return await self.api.request("friendList") | ||||
|  | ||||
|     @argument_validation | ||||
|     async def group_list(self) -> List[Dict[str, Any]]: | ||||
|         """ | ||||
|         :说明: | ||||
|  | ||||
|           使用此方法获取bot的群列表 | ||||
|  | ||||
|         :返回: | ||||
|  | ||||
|           - ``List[Dict[str, Any]]``: 返回的群列表数据 | ||||
|         """ | ||||
|         return await self.api.request("groupList") | ||||
|  | ||||
|     @argument_validation | ||||
|     async def member_list(self, target: int) -> List[Dict[str, Any]]: | ||||
|         """ | ||||
|         :说明: | ||||
|  | ||||
|           使用此方法获取bot指定群种的成员列表 | ||||
|  | ||||
|         :参数: | ||||
|  | ||||
|           * ``target: int``: 指定群的群号 | ||||
|  | ||||
|         :返回: | ||||
|  | ||||
|           - ``List[Dict[str, Any]]``: 返回的群成员列表数据 | ||||
|         """ | ||||
|         return await self.api.request("memberList", params={"target": target}) | ||||
|  | ||||
|     @argument_validation | ||||
|     async def mute(self, target: int, member_id: int, time: int): | ||||
|         """ | ||||
|         :说明: | ||||
|  | ||||
|           使用此方法指定群禁言指定群员(需要有相关权限) | ||||
|  | ||||
|         :参数: | ||||
|  | ||||
|           * ``target: int``: 指定群的群号 | ||||
|           * ``member_id: int``: 指定群员QQ号 | ||||
|           * ``time: int``: 禁言时长,单位为秒,最多30天 | ||||
|         """ | ||||
|         return await self.api.post( | ||||
|             "mute", params={"target": target, "memberId": member_id, "time": time} | ||||
|         ) | ||||
|  | ||||
|     @argument_validation | ||||
|     async def unmute(self, target: int, member_id: int): | ||||
|         """ | ||||
|         :说明: | ||||
|  | ||||
|           使用此方法指定群解除群成员禁言(需要有相关权限) | ||||
|  | ||||
|         :参数: | ||||
|  | ||||
|           * ``target: int``: 指定群的群号 | ||||
|           * ``member_id: int``: 指定群员QQ号 | ||||
|         """ | ||||
|         return await self.api.post( | ||||
|             "unmute", params={"target": target, "memberId": member_id} | ||||
|         ) | ||||
|  | ||||
|     @argument_validation | ||||
|     async def kick(self, target: int, member_id: int, msg: str): | ||||
|         """ | ||||
|         :说明: | ||||
|  | ||||
|           使用此方法移除指定群成员(需要有相关权限) | ||||
|  | ||||
|         :参数: | ||||
|  | ||||
|           * ``target: int``: 指定群的群号 | ||||
|           * ``member_id: int``: 指定群员QQ号 | ||||
|           * ``msg: str``: 信息 | ||||
|         """ | ||||
|         return await self.api.post( | ||||
|             "kick", params={"target": target, "memberId": member_id, "msg": msg} | ||||
|         ) | ||||
|  | ||||
|     @argument_validation | ||||
|     async def quit(self, target: int): | ||||
|         """ | ||||
|         :说明: | ||||
|  | ||||
|           使用此方法使Bot退出群聊 | ||||
|  | ||||
|         :参数: | ||||
|  | ||||
|           * ``target: int``: 退出的群号 | ||||
|         """ | ||||
|         return await self.api.post("quit", params={"target": target}) | ||||
|  | ||||
|     @argument_validation | ||||
|     async def mute_all(self, target: int): | ||||
|         """ | ||||
|         :说明: | ||||
|  | ||||
|           使用此方法令指定群进行全体禁言(需要有相关权限) | ||||
|  | ||||
|         :参数: | ||||
|  | ||||
|           * ``target: int``: 指定群的群号 | ||||
|         """ | ||||
|         return await self.api.post("muteAll", params={"target": target}) | ||||
|  | ||||
|     @argument_validation | ||||
|     async def unmute_all(self, target: int): | ||||
|         """ | ||||
|         :说明: | ||||
|  | ||||
|           使用此方法令指定群解除全体禁言(需要有相关权限) | ||||
|  | ||||
|         :参数: | ||||
|  | ||||
|           * ``target: int``: 指定群的群号 | ||||
|         """ | ||||
|         return await self.api.post("unmuteAll", params={"target": target}) | ||||
|  | ||||
|     @argument_validation | ||||
|     async def group_config(self, target: int): | ||||
|         """ | ||||
|         :说明: | ||||
|  | ||||
|           使用此方法获取群设置 | ||||
|  | ||||
|         :参数: | ||||
|  | ||||
|           * ``target: int``: 指定群的群号 | ||||
|  | ||||
|         :返回: | ||||
|  | ||||
|         .. code-block:: json | ||||
|  | ||||
|             { | ||||
|                 "name": "群名称", | ||||
|                 "announcement": "群公告", | ||||
|                 "confessTalk": true, | ||||
|                 "allowMemberInvite": true, | ||||
|                 "autoApprove": true, | ||||
|                 "anonymousChat": true | ||||
|             } | ||||
|         """ | ||||
|         return await self.api.request("groupConfig", params={"target": target}) | ||||
|  | ||||
|     @argument_validation | ||||
|     async def modify_group_config(self, target: int, config: Dict[str, Any]): | ||||
|         """ | ||||
|         :说明: | ||||
|  | ||||
|           使用此方法修改群设置(需要有相关权限) | ||||
|  | ||||
|         :参数: | ||||
|  | ||||
|           * ``target: int``: 指定群的群号 | ||||
|           * ``config: Dict[str, Any]``: 群设置, 格式见 ``group_config`` 的返回值 | ||||
|         """ | ||||
|         return await self.api.post( | ||||
|             "groupConfig", params={"target": target, "config": config} | ||||
|         ) | ||||
|  | ||||
|     @argument_validation | ||||
|     async def member_info(self, target: int, member_id: int): | ||||
|         """ | ||||
|         :说明: | ||||
|  | ||||
|           使用此方法获取群员资料 | ||||
|  | ||||
|         :参数: | ||||
|  | ||||
|           * ``target: int``: 指定群的群号 | ||||
|           * ``member_id: int``: 群员QQ号 | ||||
|  | ||||
|         :返回: | ||||
|  | ||||
|         .. code-block:: json | ||||
|  | ||||
|             { | ||||
|                 "name": "群名片", | ||||
|                 "specialTitle": "群头衔" | ||||
|             } | ||||
|         """ | ||||
|         return await self.api.request( | ||||
|             "memberInfo", params={"target": target, "memberId": member_id} | ||||
|         ) | ||||
|  | ||||
|     @argument_validation | ||||
|     async def modify_member_info( | ||||
|         self, target: int, member_id: int, info: Dict[str, Any] | ||||
|     ): | ||||
|         """ | ||||
|         :说明: | ||||
|  | ||||
|           使用此方法修改群员资料(需要有相关权限) | ||||
|  | ||||
|         :参数: | ||||
|  | ||||
|           * ``target: int``: 指定群的群号 | ||||
|           * ``member_id: int``: 群员QQ号 | ||||
|           * ``info: Dict[str, Any]``: 群员资料, 格式见 ``member_info`` 的返回值 | ||||
|         """ | ||||
|         return await self.api.post( | ||||
|             "memberInfo", params={"target": target, "memberId": member_id, "info": info} | ||||
|         ) | ||||
| @@ -1,24 +0,0 @@ | ||||
| from typing import Optional | ||||
| from ipaddress import IPv4Address | ||||
|  | ||||
| from pydantic import Extra, Field, BaseModel | ||||
|  | ||||
|  | ||||
| class Config(BaseModel): | ||||
|     """ | ||||
|     Mirai 配置类 | ||||
|  | ||||
|     :必填: | ||||
|  | ||||
|       - ``auth_key`` / ``mirai_auth_key``: mirai-api-http 的 auth_key | ||||
|       - ``mirai_host``: mirai-api-http 的地址 | ||||
|       - ``mirai_port``: mirai-api-http 的端口 | ||||
|     """ | ||||
|  | ||||
|     auth_key: Optional[str] = Field(None, alias="mirai_auth_key") | ||||
|     host: Optional[IPv4Address] = Field(None, alias="mirai_host") | ||||
|     port: Optional[int] = Field(None, alias="mirai_port") | ||||
|  | ||||
|     class Config: | ||||
|         extra = Extra.ignore | ||||
|         allow_population_by_field_name = True | ||||
| @@ -1,60 +0,0 @@ | ||||
| r""" | ||||
| \:\:\: warning | ||||
| 事件中为了使代码更加整洁, 我们采用了与PEP8相符的命名规则取代Mirai原有的驼峰命名 | ||||
|  | ||||
| 部分字段可能与文档在符号上不一致 | ||||
| \:\:\: | ||||
| """ | ||||
| from .notice import * | ||||
| from .message import * | ||||
| from .request import * | ||||
| from .base import ( | ||||
|     Event, | ||||
|     GroupInfo, | ||||
|     GroupChatInfo, | ||||
|     UserPermission, | ||||
|     PrivateChatInfo, | ||||
| ) | ||||
|  | ||||
| __all__ = [ | ||||
|     "Event", | ||||
|     "GroupChatInfo", | ||||
|     "GroupInfo", | ||||
|     "PrivateChatInfo", | ||||
|     "UserPermission", | ||||
|     "MessageSource", | ||||
|     "MessageEvent", | ||||
|     "GroupMessage", | ||||
|     "FriendMessage", | ||||
|     "TempMessage", | ||||
|     "NoticeEvent", | ||||
|     "MuteEvent", | ||||
|     "BotMuteEvent", | ||||
|     "BotUnmuteEvent", | ||||
|     "MemberMuteEvent", | ||||
|     "MemberUnmuteEvent", | ||||
|     "BotJoinGroupEvent", | ||||
|     "BotLeaveEventActive", | ||||
|     "BotLeaveEventKick", | ||||
|     "MemberJoinEvent", | ||||
|     "MemberLeaveEventKick", | ||||
|     "MemberLeaveEventQuit", | ||||
|     "FriendRecallEvent", | ||||
|     "GroupRecallEvent", | ||||
|     "GroupStateChangeEvent", | ||||
|     "GroupNameChangeEvent", | ||||
|     "GroupEntranceAnnouncementChangeEvent", | ||||
|     "GroupMuteAllEvent", | ||||
|     "GroupAllowAnonymousChatEvent", | ||||
|     "GroupAllowConfessTalkEvent", | ||||
|     "GroupAllowMemberInviteEvent", | ||||
|     "MemberStateChangeEvent", | ||||
|     "MemberCardChangeEvent", | ||||
|     "MemberSpecialTitleChangeEvent", | ||||
|     "BotGroupPermissionChangeEvent", | ||||
|     "MemberPermissionChangeEvent", | ||||
|     "RequestEvent", | ||||
|     "NewFriendRequestEvent", | ||||
|     "MemberJoinRequestEvent", | ||||
|     "BotInvitedJoinGroupRequestEvent", | ||||
| ] | ||||
| @@ -1,158 +0,0 @@ | ||||
| import json | ||||
| from enum import Enum | ||||
| from typing_extensions import Literal | ||||
| from typing import Any, Dict, Type, Optional | ||||
|  | ||||
| from pydantic import Field, BaseModel, ValidationError | ||||
|  | ||||
| from nonebot.log import logger | ||||
| from nonebot.typing import overrides | ||||
| from nonebot.utils import escape_tag | ||||
| from nonebot.adapters import Event as BaseEvent | ||||
| from nonebot.adapters import Message as BaseMessage | ||||
|  | ||||
|  | ||||
| class UserPermission(str, Enum): | ||||
|     """ | ||||
|     :说明: | ||||
|  | ||||
|       用户权限枚举类 | ||||
|  | ||||
|       * ``OWNER``: 群主 | ||||
|       * ``ADMINISTRATOR``: 群管理 | ||||
|       * ``MEMBER``: 普通群成员 | ||||
|     """ | ||||
|  | ||||
|     OWNER = "OWNER" | ||||
|     ADMINISTRATOR = "ADMINISTRATOR" | ||||
|     MEMBER = "MEMBER" | ||||
|  | ||||
|  | ||||
| class NudgeSubjectKind(str, Enum): | ||||
|     """ | ||||
|     :说明: | ||||
|  | ||||
|       戳一戳类型枚举类 | ||||
|  | ||||
|       * ``Group``: 群 | ||||
|       * ``Friend``: 好友 | ||||
|     """ | ||||
|  | ||||
|     Group = "Group" | ||||
|     Friend = "Friend" | ||||
|  | ||||
|  | ||||
| class GroupInfo(BaseModel): | ||||
|     id: int | ||||
|     name: str | ||||
|     permission: UserPermission | ||||
|  | ||||
|  | ||||
| class GroupChatInfo(BaseModel): | ||||
|     id: int | ||||
|     name: str = Field(alias="memberName") | ||||
|     permission: UserPermission | ||||
|     group: GroupInfo | ||||
|  | ||||
|  | ||||
| class PrivateChatInfo(BaseModel): | ||||
|     id: int | ||||
|     nickname: str | ||||
|     remark: str | ||||
|  | ||||
|  | ||||
| class NudgeSubject(BaseModel): | ||||
|     id: int | ||||
|     kind: NudgeSubjectKind | ||||
|  | ||||
|  | ||||
| class Event(BaseEvent): | ||||
|     """ | ||||
|     mirai-api-http 协议事件,字段与 mirai-api-http 一致。各事件字段参考 `mirai-api-http 事件类型`_ | ||||
|  | ||||
|     .. _mirai-api-http 事件类型: | ||||
|         https://github.com/project-mirai/mirai-api-http/blob/master/docs/EventType.md | ||||
|     """ | ||||
|  | ||||
|     self_id: int | ||||
|     type: str | ||||
|  | ||||
|     @classmethod | ||||
|     def new(cls, data: Dict[str, Any]) -> "Event": | ||||
|         """ | ||||
|         此事件类的工厂函数, 能够通过事件数据选择合适的子类进行序列化 | ||||
|         """ | ||||
|         type = data["type"] | ||||
|  | ||||
|         def all_subclasses(cls: Type[Event]): | ||||
|             return set(cls.__subclasses__()).union( | ||||
|                 [s for c in cls.__subclasses__() for s in all_subclasses(c)] | ||||
|             ) | ||||
|  | ||||
|         event_class: Optional[Type[Event]] = None | ||||
|         for subclass in all_subclasses(cls): | ||||
|             if subclass.__name__ != type: | ||||
|                 continue | ||||
|             event_class = subclass | ||||
|  | ||||
|         if event_class is None: | ||||
|             return Event.parse_obj(data) | ||||
|  | ||||
|         while event_class and issubclass(event_class, Event): | ||||
|             try: | ||||
|                 return event_class.parse_obj(data) | ||||
|             except ValidationError as e: | ||||
|                 logger.info( | ||||
|                     f"Failed to parse {data} to class {event_class.__name__}: " | ||||
|                     f"{e.errors()!r}. Fallback to parent class." | ||||
|                 ) | ||||
|                 event_class = event_class.__base__  # type: ignore | ||||
|  | ||||
|         raise ValueError(f"Failed to serialize {data}.") | ||||
|  | ||||
|     @overrides(BaseEvent) | ||||
|     def get_type(self) -> Literal["message", "notice", "request", "meta_event"]: | ||||
|         from . import meta, notice, message, request | ||||
|  | ||||
|         if isinstance(self, message.MessageEvent): | ||||
|             return "message" | ||||
|         elif isinstance(self, notice.NoticeEvent): | ||||
|             return "notice" | ||||
|         elif isinstance(self, request.RequestEvent): | ||||
|             return "request" | ||||
|         else: | ||||
|             return "meta_event" | ||||
|  | ||||
|     @overrides(BaseEvent) | ||||
|     def get_event_name(self) -> str: | ||||
|         return self.type | ||||
|  | ||||
|     @overrides(BaseEvent) | ||||
|     def get_event_description(self) -> str: | ||||
|         return escape_tag(str(self.normalize_dict())) | ||||
|  | ||||
|     @overrides(BaseEvent) | ||||
|     def get_message(self) -> BaseMessage: | ||||
|         raise ValueError("Event has no message!") | ||||
|  | ||||
|     @overrides(BaseEvent) | ||||
|     def get_plaintext(self) -> str: | ||||
|         raise ValueError("Event has no message!") | ||||
|  | ||||
|     @overrides(BaseEvent) | ||||
|     def get_user_id(self) -> str: | ||||
|         raise ValueError("Event has no message!") | ||||
|  | ||||
|     @overrides(BaseEvent) | ||||
|     def get_session_id(self) -> str: | ||||
|         raise ValueError("Event has no message!") | ||||
|  | ||||
|     @overrides(BaseEvent) | ||||
|     def is_tome(self) -> bool: | ||||
|         return False | ||||
|  | ||||
|     def normalize_dict(self, **kwargs) -> Dict[str, Any]: | ||||
|         """ | ||||
|         返回可以被json正常反序列化的结构体 | ||||
|         """ | ||||
|         return json.loads(self.json(**kwargs)) | ||||
| @@ -1,89 +0,0 @@ | ||||
| from datetime import datetime | ||||
| from typing import Any, Optional | ||||
|  | ||||
| from pydantic import Field, BaseModel | ||||
|  | ||||
| from nonebot.typing import overrides | ||||
|  | ||||
| from ..message import MessageChain | ||||
| from .base import Event, GroupChatInfo, PrivateChatInfo | ||||
|  | ||||
|  | ||||
| class MessageSource(BaseModel): | ||||
|     id: int | ||||
|     time: datetime | ||||
|  | ||||
|  | ||||
| class MessageEvent(Event): | ||||
|     """消息事件基类""" | ||||
|  | ||||
|     message_chain: MessageChain = Field(alias="messageChain") | ||||
|     source: Optional[MessageSource] = None | ||||
|     sender: Any | ||||
|  | ||||
|     @overrides(Event) | ||||
|     def get_message(self) -> MessageChain: | ||||
|         return self.message_chain | ||||
|  | ||||
|     @overrides(Event) | ||||
|     def get_plaintext(self) -> str: | ||||
|         return self.message_chain.extract_plain_text() | ||||
|  | ||||
|     @overrides(Event) | ||||
|     def get_user_id(self) -> str: | ||||
|         raise NotImplementedError | ||||
|  | ||||
|     @overrides(Event) | ||||
|     def get_session_id(self) -> str: | ||||
|         raise NotImplementedError | ||||
|  | ||||
|  | ||||
| class GroupMessage(MessageEvent): | ||||
|     """群消息事件""" | ||||
|  | ||||
|     sender: GroupChatInfo | ||||
|     to_me: bool = False | ||||
|  | ||||
|     @overrides(MessageEvent) | ||||
|     def get_session_id(self) -> str: | ||||
|         return f"group_{self.sender.group.id}_" + self.get_user_id() | ||||
|  | ||||
|     @overrides(MessageEvent) | ||||
|     def get_user_id(self) -> str: | ||||
|         return str(self.sender.id) | ||||
|  | ||||
|     @overrides(MessageEvent) | ||||
|     def is_tome(self) -> bool: | ||||
|         return self.to_me | ||||
|  | ||||
|  | ||||
| class FriendMessage(MessageEvent): | ||||
|     """好友消息事件""" | ||||
|  | ||||
|     sender: PrivateChatInfo | ||||
|  | ||||
|     @overrides(MessageEvent) | ||||
|     def get_user_id(self) -> str: | ||||
|         return str(self.sender.id) | ||||
|  | ||||
|     @overrides(MessageEvent) | ||||
|     def get_session_id(self) -> str: | ||||
|         return "friend_" + self.get_user_id() | ||||
|  | ||||
|     @overrides(MessageEvent) | ||||
|     def is_tome(self) -> bool: | ||||
|         return True | ||||
|  | ||||
|  | ||||
| class TempMessage(MessageEvent): | ||||
|     """临时会话消息事件""" | ||||
|  | ||||
|     sender: GroupChatInfo | ||||
|  | ||||
|     @overrides(MessageEvent) | ||||
|     def get_session_id(self) -> str: | ||||
|         return f"temp_{self.sender.group.id}_" + self.get_user_id() | ||||
|  | ||||
|     @overrides(MessageEvent) | ||||
|     def is_tome(self) -> bool: | ||||
|         return True | ||||
| @@ -1,37 +0,0 @@ | ||||
| from .base import Event | ||||
|  | ||||
|  | ||||
| class MetaEvent(Event): | ||||
|     """元事件基类""" | ||||
|  | ||||
|     qq: int | ||||
|  | ||||
|  | ||||
| class BotOnlineEvent(MetaEvent): | ||||
|     """Bot登录成功""" | ||||
|  | ||||
|     pass | ||||
|  | ||||
|  | ||||
| class BotOfflineEventActive(MetaEvent): | ||||
|     """Bot主动离线""" | ||||
|  | ||||
|     pass | ||||
|  | ||||
|  | ||||
| class BotOfflineEventForce(MetaEvent): | ||||
|     """Bot被挤下线""" | ||||
|  | ||||
|     pass | ||||
|  | ||||
|  | ||||
| class BotOfflineEventDropped(MetaEvent): | ||||
|     """Bot被服务器断开或因网络问题而掉线""" | ||||
|  | ||||
|     pass | ||||
|  | ||||
|  | ||||
| class BotReloginEvent(MetaEvent): | ||||
|     """Bot主动重新登录""" | ||||
|  | ||||
|     pass | ||||
| @@ -1,192 +0,0 @@ | ||||
| from typing import Any, Optional | ||||
|  | ||||
| from pydantic import Field | ||||
|  | ||||
| from .base import Event, GroupInfo, NudgeSubject, GroupChatInfo, UserPermission | ||||
|  | ||||
|  | ||||
| class NoticeEvent(Event): | ||||
|     """通知事件基类""" | ||||
|  | ||||
|     pass | ||||
|  | ||||
|  | ||||
| class MuteEvent(NoticeEvent): | ||||
|     """禁言类事件基类""" | ||||
|  | ||||
|     operator: GroupChatInfo | ||||
|  | ||||
|  | ||||
| class BotMuteEvent(MuteEvent): | ||||
|     """Bot被禁言""" | ||||
|  | ||||
|     pass | ||||
|  | ||||
|  | ||||
| class BotUnmuteEvent(MuteEvent): | ||||
|     """Bot被取消禁言""" | ||||
|  | ||||
|     pass | ||||
|  | ||||
|  | ||||
| class MemberMuteEvent(MuteEvent): | ||||
|     """群成员被禁言事件(该成员不是Bot)""" | ||||
|  | ||||
|     duration_seconds: int = Field(alias="durationSeconds") | ||||
|     member: GroupChatInfo | ||||
|     operator: Optional[GroupChatInfo] = None | ||||
|  | ||||
|  | ||||
| class MemberUnmuteEvent(MuteEvent): | ||||
|     """群成员被取消禁言事件(该成员不是Bot)""" | ||||
|  | ||||
|     member: GroupChatInfo | ||||
|     operator: Optional[GroupChatInfo] = None | ||||
|  | ||||
|  | ||||
| class BotJoinGroupEvent(NoticeEvent): | ||||
|     """Bot加入了一个新群""" | ||||
|  | ||||
|     group: GroupInfo | ||||
|  | ||||
|  | ||||
| class BotLeaveEventActive(BotJoinGroupEvent): | ||||
|     """Bot主动退出一个群""" | ||||
|  | ||||
|     pass | ||||
|  | ||||
|  | ||||
| class BotLeaveEventKick(BotJoinGroupEvent): | ||||
|     """Bot被踢出一个群""" | ||||
|  | ||||
|     pass | ||||
|  | ||||
|  | ||||
| class MemberJoinEvent(NoticeEvent): | ||||
|     """新人入群的事件""" | ||||
|  | ||||
|     member: GroupChatInfo | ||||
|  | ||||
|  | ||||
| class MemberLeaveEventKick(MemberJoinEvent): | ||||
|     """成员被踢出群(该成员不是Bot)""" | ||||
|  | ||||
|     operator: Optional[GroupChatInfo] = None | ||||
|  | ||||
|  | ||||
| class MemberLeaveEventQuit(MemberJoinEvent): | ||||
|     """成员主动离群(该成员不是Bot)""" | ||||
|  | ||||
|     pass | ||||
|  | ||||
|  | ||||
| class FriendRecallEvent(NoticeEvent): | ||||
|     """好友消息撤回""" | ||||
|  | ||||
|     author_id: int = Field(alias="authorId") | ||||
|     message_id: int = Field(alias="messageId") | ||||
|     time: int | ||||
|     operator: int | ||||
|  | ||||
|  | ||||
| class GroupRecallEvent(FriendRecallEvent): | ||||
|     """群消息撤回""" | ||||
|  | ||||
|     group: GroupInfo | ||||
|     operator: Optional[GroupChatInfo] = None | ||||
|  | ||||
|  | ||||
| class GroupStateChangeEvent(NoticeEvent): | ||||
|     """群变化事件基类""" | ||||
|  | ||||
|     origin: Any | ||||
|     current: Any | ||||
|     group: GroupInfo | ||||
|     operator: Optional[GroupChatInfo] = None | ||||
|  | ||||
|  | ||||
| class GroupNameChangeEvent(GroupStateChangeEvent): | ||||
|     """某个群名改变""" | ||||
|  | ||||
|     origin: str | ||||
|     current: str | ||||
|  | ||||
|  | ||||
| class GroupEntranceAnnouncementChangeEvent(GroupStateChangeEvent): | ||||
|     """某群入群公告改变""" | ||||
|  | ||||
|     origin: str | ||||
|     current: str | ||||
|  | ||||
|  | ||||
| class GroupMuteAllEvent(GroupStateChangeEvent): | ||||
|     """全员禁言""" | ||||
|  | ||||
|     origin: bool | ||||
|     current: bool | ||||
|  | ||||
|  | ||||
| class GroupAllowAnonymousChatEvent(GroupStateChangeEvent): | ||||
|     """匿名聊天""" | ||||
|  | ||||
|     origin: bool | ||||
|     current: bool | ||||
|  | ||||
|  | ||||
| class GroupAllowConfessTalkEvent(GroupStateChangeEvent): | ||||
|     """坦白说""" | ||||
|  | ||||
|     origin: bool | ||||
|     current: bool | ||||
|  | ||||
|  | ||||
| class GroupAllowMemberInviteEvent(GroupStateChangeEvent): | ||||
|     """允许群员邀请好友加群""" | ||||
|  | ||||
|     origin: bool | ||||
|     current: bool | ||||
|  | ||||
|  | ||||
| class MemberStateChangeEvent(NoticeEvent): | ||||
|     """群成员变化事件基类""" | ||||
|  | ||||
|     member: GroupChatInfo | ||||
|     operator: Optional[GroupChatInfo] = None | ||||
|  | ||||
|  | ||||
| class MemberCardChangeEvent(MemberStateChangeEvent): | ||||
|     """群名片改动""" | ||||
|  | ||||
|     origin: str | ||||
|     current: str | ||||
|  | ||||
|  | ||||
| class MemberSpecialTitleChangeEvent(MemberStateChangeEvent): | ||||
|     """群头衔改动(只有群主有操作限权)""" | ||||
|  | ||||
|     origin: str | ||||
|     current: str | ||||
|  | ||||
|  | ||||
| class BotGroupPermissionChangeEvent(MemberStateChangeEvent): | ||||
|     """Bot在群里的权限被改变""" | ||||
|  | ||||
|     origin: UserPermission | ||||
|     current: UserPermission | ||||
|  | ||||
|  | ||||
| class MemberPermissionChangeEvent(MemberStateChangeEvent): | ||||
|     """成员权限改变的事件(该成员不是Bot)""" | ||||
|  | ||||
|     origin: UserPermission | ||||
|     current: UserPermission | ||||
|  | ||||
|  | ||||
| class NudgeEvent(NoticeEvent): | ||||
|     """戳一戳触发事件""" | ||||
|  | ||||
|     from_id: int = Field(alias="fromId") | ||||
|     target: int | ||||
|     subject: NudgeSubject | ||||
|     action: str | ||||
|     suffix: str | ||||
| @@ -1,185 +0,0 @@ | ||||
| from typing import TYPE_CHECKING | ||||
| from typing_extensions import Literal | ||||
|  | ||||
| from pydantic import Field | ||||
|  | ||||
| from .base import Event | ||||
|  | ||||
| if TYPE_CHECKING: | ||||
|     from ..bot import Bot | ||||
|  | ||||
|  | ||||
| class RequestEvent(Event): | ||||
|     """请求事件基类""" | ||||
|  | ||||
|     event_id: int = Field(alias="eventId") | ||||
|     message: str | ||||
|     nick: str | ||||
|  | ||||
|  | ||||
| class NewFriendRequestEvent(RequestEvent): | ||||
|     """添加好友申请""" | ||||
|  | ||||
|     from_id: int = Field(alias="fromId") | ||||
|     group_id: int = Field(0, alias="groupId") | ||||
|  | ||||
|     async def approve(self, bot: "Bot"): | ||||
|         """ | ||||
|         :说明: | ||||
|  | ||||
|           通过此人的好友申请 | ||||
|  | ||||
|         :参数: | ||||
|  | ||||
|           * ``bot: Bot``: 当前的 ``Bot`` 对象 | ||||
|         """ | ||||
|         return await bot.api.post( | ||||
|             "/resp/newFriendRequestEvent", | ||||
|             params={ | ||||
|                 "eventId": self.event_id, | ||||
|                 "groupId": self.group_id, | ||||
|                 "fromId": self.from_id, | ||||
|                 "operate": 0, | ||||
|                 "message": "", | ||||
|             }, | ||||
|         ) | ||||
|  | ||||
|     async def reject(self, bot: "Bot", operate: Literal[1, 2] = 1, message: str = ""): | ||||
|         """ | ||||
|         :说明: | ||||
|  | ||||
|           拒绝此人的好友申请 | ||||
|  | ||||
|         :参数: | ||||
|  | ||||
|           * ``bot: Bot``: 当前的 ``Bot`` 对象 | ||||
|           * ``operate: Literal[1, 2]``: 响应的操作类型 | ||||
|  | ||||
|             * ``1``: 拒绝添加好友 | ||||
|             * ``2``: 拒绝添加好友并添加黑名单,不再接收该用户的好友申请 | ||||
|  | ||||
|           * ``message: str``: 回复的信息 | ||||
|         """ | ||||
|         assert operate > 0 | ||||
|         return await bot.api.post( | ||||
|             "/resp/newFriendRequestEvent", | ||||
|             params={ | ||||
|                 "eventId": self.event_id, | ||||
|                 "groupId": self.group_id, | ||||
|                 "fromId": self.from_id, | ||||
|                 "operate": operate, | ||||
|                 "message": message, | ||||
|             }, | ||||
|         ) | ||||
|  | ||||
|  | ||||
| class MemberJoinRequestEvent(RequestEvent): | ||||
|     """用户入群申请(Bot需要有管理员权限)""" | ||||
|  | ||||
|     from_id: int = Field(alias="fromId") | ||||
|     group_id: int = Field(alias="groupId") | ||||
|     group_name: str = Field(alias="groupName") | ||||
|  | ||||
|     async def approve(self, bot: "Bot"): | ||||
|         """ | ||||
|         :说明: | ||||
|  | ||||
|           通过此人的加群申请 | ||||
|  | ||||
|         :参数: | ||||
|  | ||||
|           * ``bot: Bot``: 当前的 ``Bot`` 对象 | ||||
|         """ | ||||
|         return await bot.api.post( | ||||
|             "/resp/memberJoinRequestEvent", | ||||
|             params={ | ||||
|                 "eventId": self.event_id, | ||||
|                 "groupId": self.group_id, | ||||
|                 "fromId": self.from_id, | ||||
|                 "operate": 0, | ||||
|                 "message": "", | ||||
|             }, | ||||
|         ) | ||||
|  | ||||
|     async def reject( | ||||
|         self, bot: "Bot", operate: Literal[1, 2, 3, 4] = 1, message: str = "" | ||||
|     ): | ||||
|         """ | ||||
|         :说明: | ||||
|  | ||||
|           拒绝(忽略)此人的加群申请 | ||||
|  | ||||
|         :参数: | ||||
|  | ||||
|           * ``bot: Bot``: 当前的 ``Bot`` 对象 | ||||
|           * ``operate: Literal[1, 2, 3, 4]``: 响应的操作类型 | ||||
|  | ||||
|             * ``1``: 拒绝入群 | ||||
|             * ``2``: 忽略请求 | ||||
|             * ``3``: 拒绝入群并添加黑名单,不再接收该用户的入群申请 | ||||
|             * ``4``: 忽略入群并添加黑名单,不再接收该用户的入群申请 | ||||
|  | ||||
|           * ``message: str``: 回复的信息 | ||||
|         """ | ||||
|         assert operate > 0 | ||||
|         return await bot.api.post( | ||||
|             "/resp/memberJoinRequestEvent", | ||||
|             params={ | ||||
|                 "eventId": self.event_id, | ||||
|                 "groupId": self.group_id, | ||||
|                 "fromId": self.from_id, | ||||
|                 "operate": operate, | ||||
|                 "message": message, | ||||
|             }, | ||||
|         ) | ||||
|  | ||||
|  | ||||
| class BotInvitedJoinGroupRequestEvent(RequestEvent): | ||||
|     """Bot被邀请入群申请""" | ||||
|  | ||||
|     from_id: int = Field(alias="fromId") | ||||
|     group_id: int = Field(alias="groupId") | ||||
|     group_name: str = Field(alias="groupName") | ||||
|  | ||||
|     async def approve(self, bot: "Bot"): | ||||
|         """ | ||||
|         :说明: | ||||
|  | ||||
|           通过这份被邀请入群申请 | ||||
|  | ||||
|         :参数: | ||||
|  | ||||
|           * ``bot: Bot``: 当前的 ``Bot`` 对象 | ||||
|         """ | ||||
|         return await bot.api.post( | ||||
|             "/resp/botInvitedJoinGroupRequestEvent", | ||||
|             params={ | ||||
|                 "eventId": self.event_id, | ||||
|                 "groupId": self.group_id, | ||||
|                 "fromId": self.from_id, | ||||
|                 "operate": 0, | ||||
|                 "message": "", | ||||
|             }, | ||||
|         ) | ||||
|  | ||||
|     async def reject(self, bot: "Bot", message: str = ""): | ||||
|         """ | ||||
|         :说明: | ||||
|  | ||||
|           拒绝这份被邀请入群申请 | ||||
|  | ||||
|         :参数: | ||||
|  | ||||
|           * ``bot: Bot``: 当前的 ``Bot`` 对象 | ||||
|           * ``message: str``: 邀请消息 | ||||
|         """ | ||||
|         return await bot.api.post( | ||||
|             "/resp/botInvitedJoinGroupRequestEvent", | ||||
|             params={ | ||||
|                 "eventId": self.event_id, | ||||
|                 "groupId": self.group_id, | ||||
|                 "fromId": self.from_id, | ||||
|                 "operate": 1, | ||||
|                 "message": message, | ||||
|             }, | ||||
|         ) | ||||
| @@ -1,324 +0,0 @@ | ||||
| from enum import Enum | ||||
| from typing import Any, Dict, List, Type, Union, Iterable, Optional | ||||
|  | ||||
| from pydantic import validate_arguments | ||||
|  | ||||
| from nonebot.typing import overrides | ||||
| from nonebot.adapters import Message as BaseMessage | ||||
| from nonebot.adapters import MessageSegment as BaseMessageSegment | ||||
|  | ||||
|  | ||||
| class MessageType(str, Enum): | ||||
|     """消息类型枚举类""" | ||||
|  | ||||
|     SOURCE = "Source" | ||||
|     QUOTE = "Quote" | ||||
|     AT = "At" | ||||
|     AT_ALL = "AtAll" | ||||
|     FACE = "Face" | ||||
|     PLAIN = "Plain" | ||||
|     IMAGE = "Image" | ||||
|     FLASH_IMAGE = "FlashImage" | ||||
|     VOICE = "Voice" | ||||
|     XML = "Xml" | ||||
|     JSON = "Json" | ||||
|     APP = "App" | ||||
|     POKE = "Poke" | ||||
|  | ||||
|  | ||||
| class MessageSegment(BaseMessageSegment["MessageChain"]): | ||||
|     """ | ||||
|     Mirai-API-HTTP 协议 MessageSegment 适配。具体方法参考 `mirai-api-http 消息类型`_ | ||||
|  | ||||
|     .. _mirai-api-http 消息类型: | ||||
|         https://github.com/project-mirai/mirai-api-http/blob/master/docs/MessageType.md | ||||
|     """ | ||||
|  | ||||
|     type: MessageType | ||||
|     data: Dict[str, Any] | ||||
|  | ||||
|     @classmethod | ||||
|     def get_message_class(cls) -> Type["MessageChain"]: | ||||
|         return MessageChain | ||||
|  | ||||
|     @validate_arguments | ||||
|     @overrides(BaseMessageSegment) | ||||
|     def __init__(self, type: MessageType, **data: Any): | ||||
|         super().__init__( | ||||
|             type=type, data={k: v for k, v in data.items() if v is not None} | ||||
|         ) | ||||
|  | ||||
|     @overrides(BaseMessageSegment) | ||||
|     def __str__(self) -> str: | ||||
|         return self.data["text"] if self.is_text() else repr(self) | ||||
|  | ||||
|     def __repr__(self) -> str: | ||||
|         return "[mirai:%s]" % ",".join( | ||||
|             [ | ||||
|                 self.type.value, | ||||
|                 *map( | ||||
|                     lambda s: "%s=%r" % s, | ||||
|                     self.data.items(), | ||||
|                 ), | ||||
|             ] | ||||
|         ) | ||||
|  | ||||
|     @overrides(BaseMessageSegment) | ||||
|     def is_text(self) -> bool: | ||||
|         return self.type == MessageType.PLAIN | ||||
|  | ||||
|     def as_dict(self) -> Dict[str, Any]: | ||||
|         """导出可以被正常json序列化的结构体""" | ||||
|         return {"type": self.type.value, **self.data} | ||||
|  | ||||
|     @classmethod | ||||
|     def source(cls, id: int, time: int): | ||||
|         return cls(type=MessageType.SOURCE, id=id, time=time) | ||||
|  | ||||
|     @classmethod | ||||
|     def quote( | ||||
|         cls, | ||||
|         id: int, | ||||
|         group_id: int, | ||||
|         sender_id: int, | ||||
|         target_id: int, | ||||
|         origin: "MessageChain", | ||||
|     ): | ||||
|         """ | ||||
|         :说明: | ||||
|  | ||||
|           生成回复引用消息段 | ||||
|  | ||||
|         :参数: | ||||
|  | ||||
|           * ``id: int``: 被引用回复的原消息的message_id | ||||
|           * ``group_id: int``: 被引用回复的原消息所接收的群号,当为好友消息时为0 | ||||
|           * ``sender_id: int``: 被引用回复的原消息的发送者的QQ号 | ||||
|           * ``target_id: int``: 被引用回复的原消息的接收者者的QQ号(或群号) | ||||
|           * ``origin: MessageChain``: 被引用回复的原消息的消息链对象 | ||||
|         """ | ||||
|         return cls( | ||||
|             type=MessageType.QUOTE, | ||||
|             id=id, | ||||
|             groupId=group_id, | ||||
|             senderId=sender_id, | ||||
|             targetId=target_id, | ||||
|             origin=origin.export(), | ||||
|         ) | ||||
|  | ||||
|     @classmethod | ||||
|     def at(cls, target: int): | ||||
|         """ | ||||
|         :说明: | ||||
|  | ||||
|           @某个人 | ||||
|  | ||||
|         :参数: | ||||
|  | ||||
|           * ``target: int``: 群员QQ号 | ||||
|         """ | ||||
|         return cls(type=MessageType.AT, target=target) | ||||
|  | ||||
|     @classmethod | ||||
|     def at_all(cls): | ||||
|         """ | ||||
|         :说明: | ||||
|  | ||||
|           @全体成员 | ||||
|         """ | ||||
|         return cls(type=MessageType.AT_ALL) | ||||
|  | ||||
|     @classmethod | ||||
|     def face(cls, face_id: Optional[int] = None, name: Optional[str] = None): | ||||
|         """ | ||||
|         :说明: | ||||
|  | ||||
|           发送QQ表情 | ||||
|  | ||||
|         :参数: | ||||
|  | ||||
|           * ``face_id: Optional[int]``: QQ表情编号,可选,优先高于name | ||||
|           * ``name: Optional[str]``: QQ表情拼音,可选 | ||||
|         """ | ||||
|         return cls(type=MessageType.FACE, faceId=face_id, name=name) | ||||
|  | ||||
|     @classmethod | ||||
|     def plain(cls, text: str): | ||||
|         """ | ||||
|         :说明: | ||||
|  | ||||
|           纯文本消息 | ||||
|  | ||||
|         :参数: | ||||
|  | ||||
|           * ``text: str``: 文字消息 | ||||
|         """ | ||||
|         return cls(type=MessageType.PLAIN, text=text) | ||||
|  | ||||
|     @classmethod | ||||
|     def image( | ||||
|         cls, | ||||
|         image_id: Optional[str] = None, | ||||
|         url: Optional[str] = None, | ||||
|         path: Optional[str] = None, | ||||
|     ): | ||||
|         """ | ||||
|         :说明: | ||||
|  | ||||
|           图片消息 | ||||
|  | ||||
|         :参数: | ||||
|  | ||||
|           * ``image_id: Optional[str]``: 图片的image_id,群图片与好友图片格式不同。不为空时将忽略url属性 | ||||
|           * ``url: Optional[str]``: 图片的URL,发送时可作网络图片的链接 | ||||
|           * ``path: Optional[str]``: 图片的路径,发送本地图片 | ||||
|         """ | ||||
|         return cls(type=MessageType.IMAGE, imageId=image_id, url=url, path=path) | ||||
|  | ||||
|     @classmethod | ||||
|     def flash_image( | ||||
|         cls, | ||||
|         image_id: Optional[str] = None, | ||||
|         url: Optional[str] = None, | ||||
|         path: Optional[str] = None, | ||||
|     ): | ||||
|         """ | ||||
|         :说明: | ||||
|  | ||||
|           闪照消息 | ||||
|  | ||||
|         :参数: | ||||
|  | ||||
|           同 ``image`` | ||||
|         """ | ||||
|         return cls(type=MessageType.FLASH_IMAGE, imageId=image_id, url=url, path=path) | ||||
|  | ||||
|     @classmethod | ||||
|     def voice( | ||||
|         cls, | ||||
|         voice_id: Optional[str] = None, | ||||
|         url: Optional[str] = None, | ||||
|         path: Optional[str] = None, | ||||
|     ): | ||||
|         """ | ||||
|         :说明: | ||||
|  | ||||
|           语音消息 | ||||
|  | ||||
|         :参数: | ||||
|  | ||||
|           * ``voice_id: Optional[str]``: 语音的voice_id,不为空时将忽略url属性 | ||||
|           * ``url: Optional[str]``: 语音的URL,发送时可作网络语音的链接 | ||||
|           * ``path: Optional[str]``: 语音的路径,发送本地语音 | ||||
|         """ | ||||
|         return cls(type=MessageType.FLASH_IMAGE, imageId=voice_id, url=url, path=path) | ||||
|  | ||||
|     @classmethod | ||||
|     def xml(cls, xml: str): | ||||
|         """ | ||||
|         :说明: | ||||
|  | ||||
|           XML消息 | ||||
|  | ||||
|         :参数: | ||||
|  | ||||
|           * ``xml: str``: XML文本 | ||||
|         """ | ||||
|         return cls(type=MessageType.XML, xml=xml) | ||||
|  | ||||
|     @classmethod | ||||
|     def json(cls, json: str): | ||||
|         """ | ||||
|         :说明: | ||||
|  | ||||
|           Json消息 | ||||
|  | ||||
|         :参数: | ||||
|  | ||||
|           * ``json: str``: Json文本 | ||||
|         """ | ||||
|         return cls(type=MessageType.JSON, json=json) | ||||
|  | ||||
|     @classmethod | ||||
|     def app(cls, content: str): | ||||
|         """ | ||||
|         :说明: | ||||
|  | ||||
|           应用程序消息 | ||||
|  | ||||
|         :参数: | ||||
|  | ||||
|           * ``content: str``: 内容 | ||||
|         """ | ||||
|         return cls(type=MessageType.APP, content=content) | ||||
|  | ||||
|     @classmethod | ||||
|     def poke(cls, name: str): | ||||
|         """ | ||||
|         :说明: | ||||
|  | ||||
|           戳一戳消息 | ||||
|  | ||||
|         :参数: | ||||
|  | ||||
|           * ``name: str``: 戳一戳的类型 | ||||
|  | ||||
|             * ``Poke``: 戳一戳 | ||||
|             * ``ShowLove``: 比心 | ||||
|             * ``Like``: 点赞 | ||||
|             * ``Heartbroken``: 心碎 | ||||
|             * ``SixSixSix``: 666 | ||||
|             * ``FangDaZhao``: 放大招 | ||||
|  | ||||
|         """ | ||||
|         return cls(type=MessageType.POKE, name=name) | ||||
|  | ||||
|  | ||||
| class MessageChain(BaseMessage[MessageSegment]): | ||||
|     """ | ||||
|     Mirai 协议 Message 适配 | ||||
|  | ||||
|     由于Mirai协议的Message实现较为特殊, 故使用MessageChain命名 | ||||
|     """ | ||||
|  | ||||
|     @classmethod | ||||
|     @overrides(BaseMessage) | ||||
|     def get_segment_class(cls) -> Type[MessageSegment]: | ||||
|         return MessageSegment | ||||
|  | ||||
|     @overrides(BaseMessage) | ||||
|     def _construct( | ||||
|         self, message: Union[List[Dict[str, Any]], Iterable[MessageSegment]] | ||||
|     ) -> List[MessageSegment]: | ||||
|         if isinstance(message, str): | ||||
|             return [MessageSegment.plain(text=message)] | ||||
|         return [ | ||||
|             *map( | ||||
|                 lambda x: x if isinstance(x, MessageSegment) else MessageSegment(**x), | ||||
|                 message, | ||||
|             ) | ||||
|         ] | ||||
|  | ||||
|     def export(self) -> List[Dict[str, Any]]: | ||||
|         """导出为可以被正常json序列化的数组""" | ||||
|         return [*map(lambda segment: segment.as_dict(), self.copy())]  # type: ignore | ||||
|  | ||||
|     def extract_first(self, *type: MessageType) -> Optional[MessageSegment]: | ||||
|         """ | ||||
|         :说明: | ||||
|  | ||||
|           弹出该消息链的第一个消息 | ||||
|  | ||||
|         :参数: | ||||
|  | ||||
|           * `*type: MessageType`: 指定的消息类型, 当指定后如类型不匹配不弹出 | ||||
|         """ | ||||
|         if not len(self): | ||||
|             return None | ||||
|         first: MessageSegment = self[0] | ||||
|         if (not type) or (first.type in type): | ||||
|             return self.pop(0) | ||||
|         return None | ||||
|  | ||||
|     def __repr__(self) -> str: | ||||
|         return f"<{self.__class__.__name__} {[*self.copy()]}>" | ||||
| @@ -1,179 +0,0 @@ | ||||
| import re | ||||
| from functools import wraps | ||||
| from typing import TYPE_CHECKING, Any, TypeVar, Callable, Optional, Coroutine | ||||
|  | ||||
| import httpx | ||||
| from pydantic import Extra, ValidationError, validate_arguments | ||||
|  | ||||
| from nonebot.log import logger | ||||
| import nonebot.exception as exception | ||||
| from nonebot.message import handle_event | ||||
| from nonebot.utils import escape_tag, logger_wrapper | ||||
|  | ||||
| from .message import MessageType, MessageSegment | ||||
| from .event import Event, GroupMessage, MessageEvent, MessageSource | ||||
|  | ||||
| if TYPE_CHECKING: | ||||
|     from .bot import Bot | ||||
|  | ||||
| _AsyncCallable = TypeVar("_AsyncCallable", bound=Callable[..., Coroutine]) | ||||
| _AnyCallable = TypeVar("_AnyCallable", bound=Callable) | ||||
|  | ||||
|  | ||||
| class Log: | ||||
|     @staticmethod | ||||
|     def log(level: str, message: str, exception: Optional[Exception] = None): | ||||
|         logger = logger_wrapper("MIRAI") | ||||
|         message = "<e>" + escape_tag(message) + "</e>" | ||||
|         logger(level=level.upper(), message=message, exception=exception) | ||||
|  | ||||
|     @classmethod | ||||
|     def info(cls, message: Any): | ||||
|         cls.log("INFO", str(message)) | ||||
|  | ||||
|     @classmethod | ||||
|     def debug(cls, message: Any): | ||||
|         cls.log("DEBUG", str(message)) | ||||
|  | ||||
|     @classmethod | ||||
|     def warn(cls, message: Any): | ||||
|         cls.log("WARNING", str(message)) | ||||
|  | ||||
|     @classmethod | ||||
|     def error(cls, message: Any, exception: Optional[Exception] = None): | ||||
|         cls.log("ERROR", str(message), exception=exception) | ||||
|  | ||||
|  | ||||
| class ActionFailed(exception.ActionFailed): | ||||
|     """ | ||||
|     :说明: | ||||
|  | ||||
|       API 请求成功返回数据,但 API 操作失败。 | ||||
|     """ | ||||
|  | ||||
|     def __init__(self, **kwargs): | ||||
|         super().__init__("mirai") | ||||
|         self.data = kwargs.copy() | ||||
|  | ||||
|     def __repr__(self): | ||||
|         return self.__class__.__name__ + "(%s)" % ", ".join( | ||||
|             map(lambda m: "%s=%r" % m, self.data.items()) | ||||
|         ) | ||||
|  | ||||
|  | ||||
| class InvalidArgument(exception.AdapterException): | ||||
|     """ | ||||
|     :说明: | ||||
|  | ||||
|       调用API的参数出错 | ||||
|     """ | ||||
|  | ||||
|     def __init__(self, **kwargs): | ||||
|         super().__init__("mirai") | ||||
|  | ||||
|  | ||||
| def catch_network_error(function: _AsyncCallable) -> _AsyncCallable: | ||||
|     r""" | ||||
|     :说明: | ||||
|  | ||||
|       捕捉函数抛出的httpx网络异常并释放 ``NetworkError`` 异常 | ||||
|  | ||||
|       处理返回数据, 在code不为0时释放 ``ActionFailed`` 异常 | ||||
|  | ||||
|     \:\:\: warning | ||||
|     此装饰器只支持使用了httpx的异步函数 | ||||
|     \:\:\: | ||||
|     """ | ||||
|  | ||||
|     @wraps(function) | ||||
|     async def wrapper(*args, **kwargs): | ||||
|         try: | ||||
|             data = await function(*args, **kwargs) | ||||
|         except httpx.HTTPError: | ||||
|             raise exception.NetworkError("mirai") | ||||
|         logger.opt(colors=True).debug( | ||||
|             "<b>Mirai API returned data:</b> " f"<y>{escape_tag(str(data))}</y>" | ||||
|         ) | ||||
|         if isinstance(data, dict): | ||||
|             if data.get("code", 0) != 0: | ||||
|                 raise ActionFailed(**data) | ||||
|         return data | ||||
|  | ||||
|     return wrapper  # type: ignore | ||||
|  | ||||
|  | ||||
| def argument_validation(function: _AnyCallable) -> _AnyCallable: | ||||
|     """ | ||||
|     :说明: | ||||
|  | ||||
|       通过函数签名中的类型注解来对传入参数进行运行时校验 | ||||
|  | ||||
|       会在参数出错时释放 ``InvalidArgument`` 异常 | ||||
|     """ | ||||
|     function = validate_arguments( | ||||
|         config={"arbitrary_types_allowed": True, "extra": Extra.forbid} | ||||
|     )(function) | ||||
|  | ||||
|     @wraps(function) | ||||
|     def wrapper(*args, **kwargs): | ||||
|         try: | ||||
|             return function(*args, **kwargs) | ||||
|         except ValidationError: | ||||
|             raise InvalidArgument | ||||
|  | ||||
|     return wrapper  # type: ignore | ||||
|  | ||||
|  | ||||
| def process_source(bot: "Bot", event: MessageEvent) -> MessageEvent: | ||||
|     source = event.message_chain.extract_first(MessageType.SOURCE) | ||||
|     if source is not None: | ||||
|         event.source = MessageSource.parse_obj(source.data) | ||||
|     return event | ||||
|  | ||||
|  | ||||
| def process_at(bot: "Bot", event: GroupMessage) -> GroupMessage: | ||||
|     at = event.message_chain.extract_first(MessageType.AT) | ||||
|     if at is not None: | ||||
|         if at.data["target"] == event.self_id: | ||||
|             event.to_me = True | ||||
|         else: | ||||
|             event.message_chain.insert(0, at) | ||||
|     if not event.message_chain: | ||||
|         event.message_chain.append(MessageSegment.plain("")) | ||||
|     return event | ||||
|  | ||||
|  | ||||
| def process_nick(bot: "Bot", event: GroupMessage) -> GroupMessage: | ||||
|     plain = event.message_chain.extract_first(MessageType.PLAIN) | ||||
|     if plain is not None: | ||||
|         text = str(plain) | ||||
|         nick_regex = "|".join(filter(lambda x: x, bot.config.nickname)) | ||||
|         matched = re.search(rf"^({nick_regex})([\s,,]*|$)", text, re.IGNORECASE) | ||||
|         if matched is not None: | ||||
|             event.to_me = True | ||||
|             nickname = matched.group(1) | ||||
|             Log.info(f"User is calling me {nickname}") | ||||
|             plain.data["text"] = text[matched.end() :] | ||||
|         event.message_chain.insert(0, plain) | ||||
|     return event | ||||
|  | ||||
|  | ||||
| def process_reply(bot: "Bot", event: GroupMessage) -> GroupMessage: | ||||
|     reply = event.message_chain.extract_first(MessageType.QUOTE) | ||||
|     if reply is not None: | ||||
|         if reply.data["senderId"] == event.self_id: | ||||
|             event.to_me = True | ||||
|         else: | ||||
|             event.message_chain.insert(0, reply) | ||||
|     return event | ||||
|  | ||||
|  | ||||
| async def process_event(bot: "Bot", event: Event) -> None: | ||||
|     if isinstance(event, MessageEvent): | ||||
|         Log.debug(event.message_chain) | ||||
|         event = process_source(bot, event) | ||||
|         if isinstance(event, GroupMessage): | ||||
|             event = process_nick(bot, event) | ||||
|             event = process_at(bot, event) | ||||
|             event = process_reply(bot, event) | ||||
|     await handle_event(bot, event) | ||||
							
								
								
									
										649
									
								
								packages/nonebot-adapter-mirai/poetry.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										649
									
								
								packages/nonebot-adapter-mirai/poetry.lock
									
									
									
										generated
									
									
									
								
							| @@ -1,649 +0,0 @@ | ||||
| [[package]] | ||||
| name = "anyio" | ||||
| version = "3.3.4" | ||||
| description = "High level compatibility layer for multiple asynchronous event loop implementations" | ||||
| category = "main" | ||||
| optional = false | ||||
| python-versions = ">=3.6.2" | ||||
|  | ||||
| [package.dependencies] | ||||
| idna = ">=2.8" | ||||
| sniffio = ">=1.1" | ||||
| typing-extensions = {version = "*", markers = "python_version < \"3.8\""} | ||||
|  | ||||
| [package.extras] | ||||
| doc = ["sphinx-rtd-theme", "sphinx-autodoc-typehints (>=1.2.0)"] | ||||
| test = ["coverage[toml] (>=4.5)", "hypothesis (>=4.0)", "pytest (>=6.0)", "pytest-mock (>=3.6.1)", "trustme", "uvloop (<0.15)", "mock (>=4)", "uvloop (>=0.15)"] | ||||
| trio = ["trio (>=0.16)"] | ||||
|  | ||||
| [[package]] | ||||
| name = "asgiref" | ||||
| version = "3.4.1" | ||||
| description = "ASGI specs, helper code, and adapters" | ||||
| category = "main" | ||||
| optional = false | ||||
| python-versions = ">=3.6" | ||||
|  | ||||
| [package.dependencies] | ||||
| typing-extensions = {version = "*", markers = "python_version < \"3.8\""} | ||||
|  | ||||
| [package.extras] | ||||
| tests = ["pytest", "pytest-asyncio", "mypy (>=0.800)"] | ||||
|  | ||||
| [[package]] | ||||
| name = "certifi" | ||||
| version = "2021.10.8" | ||||
| description = "Python package for providing Mozilla's CA Bundle." | ||||
| category = "main" | ||||
| optional = false | ||||
| python-versions = "*" | ||||
|  | ||||
| [[package]] | ||||
| name = "charset-normalizer" | ||||
| version = "2.0.7" | ||||
| description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." | ||||
| category = "main" | ||||
| optional = false | ||||
| python-versions = ">=3.5.0" | ||||
|  | ||||
| [package.extras] | ||||
| unicode_backport = ["unicodedata2"] | ||||
|  | ||||
| [[package]] | ||||
| name = "click" | ||||
| version = "8.0.3" | ||||
| description = "Composable command line interface toolkit" | ||||
| category = "main" | ||||
| optional = false | ||||
| python-versions = ">=3.6" | ||||
|  | ||||
| [package.dependencies] | ||||
| colorama = {version = "*", markers = "platform_system == \"Windows\""} | ||||
| importlib-metadata = {version = "*", markers = "python_version < \"3.8\""} | ||||
|  | ||||
| [[package]] | ||||
| name = "colorama" | ||||
| version = "0.4.4" | ||||
| description = "Cross-platform colored terminal text." | ||||
| category = "main" | ||||
| optional = false | ||||
| python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" | ||||
|  | ||||
| [[package]] | ||||
| name = "fastapi" | ||||
| version = "0.70.0" | ||||
| description = "FastAPI framework, high performance, easy to learn, fast to code, ready for production" | ||||
| category = "main" | ||||
| optional = false | ||||
| python-versions = ">=3.6.1" | ||||
|  | ||||
| [package.dependencies] | ||||
| pydantic = ">=1.6.2,<1.7 || >1.7,<1.7.1 || >1.7.1,<1.7.2 || >1.7.2,<1.7.3 || >1.7.3,<1.8 || >1.8,<1.8.1 || >1.8.1,<2.0.0" | ||||
| starlette = "0.16.0" | ||||
|  | ||||
| [package.extras] | ||||
| all = ["requests (>=2.24.0,<3.0.0)", "jinja2 (>=2.11.2,<4.0.0)", "python-multipart (>=0.0.5,<0.0.6)", "itsdangerous (>=1.1.0,<3.0.0)", "pyyaml (>=5.3.1,<6.0.0)", "ujson (>=4.0.1,<5.0.0)", "orjson (>=3.2.1,<4.0.0)", "email_validator (>=1.1.1,<2.0.0)", "uvicorn[standard] (>=0.12.0,<0.16.0)"] | ||||
| dev = ["python-jose[cryptography] (>=3.3.0,<4.0.0)", "passlib[bcrypt] (>=1.7.2,<2.0.0)", "autoflake (>=1.4.0,<2.0.0)", "flake8 (>=3.8.3,<4.0.0)", "uvicorn[standard] (>=0.12.0,<0.16.0)"] | ||||
| doc = ["mkdocs (>=1.1.2,<2.0.0)", "mkdocs-material (>=7.1.9,<8.0.0)", "mdx-include (>=1.4.1,<2.0.0)", "mkdocs-markdownextradata-plugin (>=0.1.7,<0.3.0)", "typer-cli (>=0.0.12,<0.0.13)", "pyyaml (>=5.3.1,<6.0.0)"] | ||||
| test = ["pytest (>=6.2.4,<7.0.0)", "pytest-cov (>=2.12.0,<4.0.0)", "mypy (==0.910)", "flake8 (>=3.8.3,<4.0.0)", "black (==21.9b0)", "isort (>=5.0.6,<6.0.0)", "requests (>=2.24.0,<3.0.0)", "httpx (>=0.14.0,<0.19.0)", "email_validator (>=1.1.1,<2.0.0)", "sqlalchemy (>=1.3.18,<1.5.0)", "peewee (>=3.13.3,<4.0.0)", "databases[sqlite] (>=0.3.2,<0.6.0)", "orjson (>=3.2.1,<4.0.0)", "ujson (>=4.0.1,<5.0.0)", "python-multipart (>=0.0.5,<0.0.6)", "flask (>=1.1.2,<3.0.0)", "anyio[trio] (>=3.2.1,<4.0.0)", "types-ujson (==0.1.1)", "types-orjson (==3.6.0)", "types-dataclasses (==0.1.7)"] | ||||
|  | ||||
| [[package]] | ||||
| name = "h11" | ||||
| version = "0.12.0" | ||||
| description = "A pure-Python, bring-your-own-I/O implementation of HTTP/1.1" | ||||
| category = "main" | ||||
| optional = false | ||||
| python-versions = ">=3.6" | ||||
|  | ||||
| [[package]] | ||||
| name = "h2" | ||||
| version = "4.1.0" | ||||
| description = "HTTP/2 State-Machine based protocol implementation" | ||||
| category = "main" | ||||
| optional = false | ||||
| python-versions = ">=3.6.1" | ||||
|  | ||||
| [package.dependencies] | ||||
| hpack = ">=4.0,<5" | ||||
| hyperframe = ">=6.0,<7" | ||||
|  | ||||
| [[package]] | ||||
| name = "hpack" | ||||
| version = "4.0.0" | ||||
| description = "Pure-Python HPACK header compression" | ||||
| category = "main" | ||||
| optional = false | ||||
| python-versions = ">=3.6.1" | ||||
|  | ||||
| [[package]] | ||||
| name = "httpcore" | ||||
| version = "0.13.7" | ||||
| description = "A minimal low-level HTTP client." | ||||
| category = "main" | ||||
| optional = false | ||||
| python-versions = ">=3.6" | ||||
|  | ||||
| [package.dependencies] | ||||
| anyio = ">=3.0.0,<4.0.0" | ||||
| h11 = ">=0.11,<0.13" | ||||
| sniffio = ">=1.0.0,<2.0.0" | ||||
|  | ||||
| [package.extras] | ||||
| http2 = ["h2 (>=3,<5)"] | ||||
|  | ||||
| [[package]] | ||||
| name = "httptools" | ||||
| version = "0.2.0" | ||||
| description = "A collection of framework independent HTTP protocol utils." | ||||
| category = "main" | ||||
| optional = false | ||||
| python-versions = "*" | ||||
|  | ||||
| [package.extras] | ||||
| test = ["Cython (==0.29.22)"] | ||||
|  | ||||
| [[package]] | ||||
| name = "httpx" | ||||
| version = "0.20.0" | ||||
| description = "The next generation HTTP client." | ||||
| category = "main" | ||||
| optional = false | ||||
| python-versions = ">=3.6" | ||||
|  | ||||
| [package.dependencies] | ||||
| certifi = "*" | ||||
| charset-normalizer = "*" | ||||
| h2 = {version = ">=3,<5", optional = true, markers = "extra == \"http2\""} | ||||
| httpcore = ">=0.13.3,<0.14.0" | ||||
| rfc3986 = {version = ">=1.3,<2", extras = ["idna2008"]} | ||||
| sniffio = "*" | ||||
|  | ||||
| [package.extras] | ||||
| brotli = ["brotlicffi", "brotli"] | ||||
| cli = ["click (>=8.0.0,<9.0.0)", "rich (>=10.0.0,<11.0.0)", "pygments (>=2.0.0,<3.0.0)"] | ||||
| http2 = ["h2 (>=3,<5)"] | ||||
|  | ||||
| [[package]] | ||||
| name = "hyperframe" | ||||
| version = "6.0.1" | ||||
| description = "HTTP/2 framing layer for Python" | ||||
| category = "main" | ||||
| optional = false | ||||
| python-versions = ">=3.6.1" | ||||
|  | ||||
| [[package]] | ||||
| name = "idna" | ||||
| version = "3.3" | ||||
| description = "Internationalized Domain Names in Applications (IDNA)" | ||||
| category = "main" | ||||
| optional = false | ||||
| python-versions = ">=3.5" | ||||
|  | ||||
| [[package]] | ||||
| name = "importlib-metadata" | ||||
| version = "4.8.1" | ||||
| description = "Read metadata from Python packages" | ||||
| category = "main" | ||||
| optional = false | ||||
| python-versions = ">=3.6" | ||||
|  | ||||
| [package.dependencies] | ||||
| typing-extensions = {version = ">=3.6.4", markers = "python_version < \"3.8\""} | ||||
| zipp = ">=0.5" | ||||
|  | ||||
| [package.extras] | ||||
| docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"] | ||||
| perf = ["ipython"] | ||||
| testing = ["pytest (>=4.6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "packaging", "pep517", "pyfakefs", "flufl.flake8", "pytest-perf (>=0.9.2)", "pytest-black (>=0.3.7)", "pytest-mypy", "importlib-resources (>=1.3)"] | ||||
|  | ||||
| [[package]] | ||||
| name = "loguru" | ||||
| version = "0.5.3" | ||||
| description = "Python logging made (stupidly) simple" | ||||
| category = "main" | ||||
| optional = false | ||||
| python-versions = ">=3.5" | ||||
|  | ||||
| [package.dependencies] | ||||
| colorama = {version = ">=0.3.4", markers = "sys_platform == \"win32\""} | ||||
| win32-setctime = {version = ">=1.0.0", markers = "sys_platform == \"win32\""} | ||||
|  | ||||
| [package.extras] | ||||
| dev = ["codecov (>=2.0.15)", "colorama (>=0.3.4)", "flake8 (>=3.7.7)", "tox (>=3.9.0)", "tox-travis (>=0.12)", "pytest (>=4.6.2)", "pytest-cov (>=2.7.1)", "Sphinx (>=2.2.1)", "sphinx-autobuild (>=0.7.1)", "sphinx-rtd-theme (>=0.4.3)", "black (>=19.10b0)", "isort (>=5.1.1)"] | ||||
|  | ||||
| [[package]] | ||||
| name = "nonebot2" | ||||
| version = "2.0.0-alpha.16" | ||||
| description = "An asynchronous python bot framework." | ||||
| category = "main" | ||||
| optional = false | ||||
| python-versions = "^3.7.3" | ||||
| develop = true | ||||
|  | ||||
| [package.dependencies] | ||||
| fastapi = "^0.70.0" | ||||
| httpx = {version = ">=0.20.0, <1.0.0", extras = ["http2"]} | ||||
| loguru = "^0.5.1" | ||||
| pydantic = {version = "~1.8.0", extras = ["dotenv"]} | ||||
| pygtrie = "^2.4.1" | ||||
| tomlkit = "^0.7.0" | ||||
| uvicorn = {version = "^0.15.0", extras = ["standard"]} | ||||
| websockets = ">=9.1" | ||||
|  | ||||
| [package.extras] | ||||
| quart = ["Quart (>=0.15.0,<0.16.0)"] | ||||
| aiohttp = ["aiohttp[speedups] (>=3.7.4,<4.0.0)"] | ||||
| all = ["Quart (>=0.15.0,<0.16.0)", "aiohttp[speedups] (>=3.7.4,<4.0.0)"] | ||||
|  | ||||
| [package.source] | ||||
| type = "directory" | ||||
| url = "../.." | ||||
|  | ||||
| [[package]] | ||||
| name = "pydantic" | ||||
| version = "1.8.2" | ||||
| description = "Data validation and settings management using python 3.6 type hinting" | ||||
| category = "main" | ||||
| optional = false | ||||
| python-versions = ">=3.6.1" | ||||
|  | ||||
| [package.dependencies] | ||||
| python-dotenv = {version = ">=0.10.4", optional = true, markers = "extra == \"dotenv\""} | ||||
| typing-extensions = ">=3.7.4.3" | ||||
|  | ||||
| [package.extras] | ||||
| dotenv = ["python-dotenv (>=0.10.4)"] | ||||
| email = ["email-validator (>=1.0.3)"] | ||||
|  | ||||
| [[package]] | ||||
| name = "pygtrie" | ||||
| version = "2.4.2" | ||||
| description = "A pure Python trie data structure implementation." | ||||
| category = "main" | ||||
| optional = false | ||||
| python-versions = "*" | ||||
|  | ||||
| [[package]] | ||||
| name = "python-dotenv" | ||||
| version = "0.19.1" | ||||
| description = "Read key-value pairs from a .env file and set them as environment variables" | ||||
| category = "main" | ||||
| optional = false | ||||
| python-versions = ">=3.5" | ||||
|  | ||||
| [package.extras] | ||||
| cli = ["click (>=5.0)"] | ||||
|  | ||||
| [[package]] | ||||
| name = "pyyaml" | ||||
| version = "6.0" | ||||
| description = "YAML parser and emitter for Python" | ||||
| category = "main" | ||||
| optional = false | ||||
| python-versions = ">=3.6" | ||||
|  | ||||
| [[package]] | ||||
| name = "rfc3986" | ||||
| version = "1.5.0" | ||||
| description = "Validating URI References per RFC 3986" | ||||
| category = "main" | ||||
| optional = false | ||||
| python-versions = "*" | ||||
|  | ||||
| [package.dependencies] | ||||
| idna = {version = "*", optional = true, markers = "extra == \"idna2008\""} | ||||
|  | ||||
| [package.extras] | ||||
| idna2008 = ["idna"] | ||||
|  | ||||
| [[package]] | ||||
| name = "sniffio" | ||||
| version = "1.2.0" | ||||
| description = "Sniff out which async library your code is running under" | ||||
| category = "main" | ||||
| optional = false | ||||
| python-versions = ">=3.5" | ||||
|  | ||||
| [[package]] | ||||
| name = "starlette" | ||||
| version = "0.16.0" | ||||
| description = "The little ASGI library that shines." | ||||
| category = "main" | ||||
| optional = false | ||||
| python-versions = ">=3.6" | ||||
|  | ||||
| [package.dependencies] | ||||
| anyio = ">=3.0.0,<4" | ||||
| typing-extensions = {version = "*", markers = "python_version < \"3.8\""} | ||||
|  | ||||
| [package.extras] | ||||
| full = ["itsdangerous", "jinja2", "python-multipart", "pyyaml", "requests", "graphene"] | ||||
|  | ||||
| [[package]] | ||||
| name = "tomlkit" | ||||
| version = "0.7.2" | ||||
| description = "Style preserving TOML library" | ||||
| category = "main" | ||||
| optional = false | ||||
| python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" | ||||
|  | ||||
| [[package]] | ||||
| name = "typing-extensions" | ||||
| version = "3.10.0.2" | ||||
| description = "Backported and Experimental Type Hints for Python 3.5+" | ||||
| category = "main" | ||||
| optional = false | ||||
| python-versions = "*" | ||||
|  | ||||
| [[package]] | ||||
| name = "uvicorn" | ||||
| version = "0.15.0" | ||||
| description = "The lightning-fast ASGI server." | ||||
| category = "main" | ||||
| optional = false | ||||
| python-versions = "*" | ||||
|  | ||||
| [package.dependencies] | ||||
| asgiref = ">=3.4.0" | ||||
| click = ">=7.0" | ||||
| colorama = {version = ">=0.4", optional = true, markers = "sys_platform == \"win32\" and extra == \"standard\""} | ||||
| h11 = ">=0.8" | ||||
| httptools = {version = ">=0.2.0,<0.3.0", optional = true, markers = "extra == \"standard\""} | ||||
| python-dotenv = {version = ">=0.13", optional = true, markers = "extra == \"standard\""} | ||||
| PyYAML = {version = ">=5.1", optional = true, markers = "extra == \"standard\""} | ||||
| typing-extensions = {version = "*", markers = "python_version < \"3.8\""} | ||||
| 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\""} | ||||
| watchgod = {version = ">=0.6", optional = true, markers = "extra == \"standard\""} | ||||
| websockets = {version = ">=9.1", optional = true, markers = "extra == \"standard\""} | ||||
|  | ||||
| [package.extras] | ||||
| standard = ["websockets (>=9.1)", "httptools (>=0.2.0,<0.3.0)", "watchgod (>=0.6)", "python-dotenv (>=0.13)", "PyYAML (>=5.1)", "uvloop (>=0.14.0,!=0.15.0,!=0.15.1)", "colorama (>=0.4)"] | ||||
|  | ||||
| [[package]] | ||||
| name = "uvloop" | ||||
| version = "0.16.0" | ||||
| description = "Fast implementation of asyncio event loop on top of libuv" | ||||
| category = "main" | ||||
| optional = false | ||||
| python-versions = ">=3.7" | ||||
|  | ||||
| [package.extras] | ||||
| dev = ["Cython (>=0.29.24,<0.30.0)", "pytest (>=3.6.0)", "Sphinx (>=4.1.2,<4.2.0)", "sphinxcontrib-asyncio (>=0.3.0,<0.4.0)", "sphinx-rtd-theme (>=0.5.2,<0.6.0)", "aiohttp", "flake8 (>=3.9.2,<3.10.0)", "psutil", "pycodestyle (>=2.7.0,<2.8.0)", "pyOpenSSL (>=19.0.0,<19.1.0)", "mypy (>=0.800)"] | ||||
| docs = ["Sphinx (>=4.1.2,<4.2.0)", "sphinxcontrib-asyncio (>=0.3.0,<0.4.0)", "sphinx-rtd-theme (>=0.5.2,<0.6.0)"] | ||||
| test = ["aiohttp", "flake8 (>=3.9.2,<3.10.0)", "psutil", "pycodestyle (>=2.7.0,<2.8.0)", "pyOpenSSL (>=19.0.0,<19.1.0)", "mypy (>=0.800)"] | ||||
|  | ||||
| [[package]] | ||||
| name = "watchgod" | ||||
| version = "0.7" | ||||
| description = "Simple, modern file watching and code reload in python." | ||||
| category = "main" | ||||
| optional = false | ||||
| python-versions = ">=3.5" | ||||
|  | ||||
| [[package]] | ||||
| name = "websockets" | ||||
| version = "10.0" | ||||
| description = "An implementation of the WebSocket Protocol (RFC 6455 & 7692)" | ||||
| category = "main" | ||||
| optional = false | ||||
| python-versions = ">=3.7" | ||||
|  | ||||
| [[package]] | ||||
| name = "win32-setctime" | ||||
| version = "1.0.3" | ||||
| description = "A small Python utility to set file creation time on Windows" | ||||
| category = "main" | ||||
| optional = false | ||||
| python-versions = ">=3.5" | ||||
|  | ||||
| [package.extras] | ||||
| dev = ["pytest (>=4.6.2)", "black (>=19.3b0)"] | ||||
|  | ||||
| [[package]] | ||||
| name = "zipp" | ||||
| version = "3.6.0" | ||||
| description = "Backport of pathlib-compatible object wrapper for zip files" | ||||
| category = "main" | ||||
| optional = false | ||||
| python-versions = ">=3.6" | ||||
|  | ||||
| [package.extras] | ||||
| docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"] | ||||
| testing = ["pytest (>=4.6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "jaraco.itertools", "func-timeout", "pytest-black (>=0.3.7)", "pytest-mypy"] | ||||
|  | ||||
| [metadata] | ||||
| lock-version = "1.1" | ||||
| python-versions = "^3.7.3" | ||||
| content-hash = "0cc9df471eb39cfb9b3225370913296535c45171158adc19753cebb7fe791ae3" | ||||
|  | ||||
| [metadata.files] | ||||
| anyio = [ | ||||
|     {file = "anyio-3.3.4-py3-none-any.whl", hash = "sha256:4fd09a25ab7fa01d34512b7249e366cd10358cdafc95022c7ff8c8f8a5026d66"}, | ||||
|     {file = "anyio-3.3.4.tar.gz", hash = "sha256:67da67b5b21f96b9d3d65daa6ea99f5d5282cb09f50eb4456f8fb51dffefc3ff"}, | ||||
| ] | ||||
| asgiref = [ | ||||
|     {file = "asgiref-3.4.1-py3-none-any.whl", hash = "sha256:ffc141aa908e6f175673e7b1b3b7af4fdb0ecb738fc5c8b88f69f055c2415214"}, | ||||
|     {file = "asgiref-3.4.1.tar.gz", hash = "sha256:4ef1ab46b484e3c706329cedeff284a5d40824200638503f5768edb6de7d58e9"}, | ||||
| ] | ||||
| certifi = [ | ||||
|     {file = "certifi-2021.10.8-py2.py3-none-any.whl", hash = "sha256:d62a0163eb4c2344ac042ab2bdf75399a71a2d8c7d47eac2e2ee91b9d6339569"}, | ||||
|     {file = "certifi-2021.10.8.tar.gz", hash = "sha256:78884e7c1d4b00ce3cea67b44566851c4343c120abd683433ce934a68ea58872"}, | ||||
| ] | ||||
| charset-normalizer = [ | ||||
|     {file = "charset-normalizer-2.0.7.tar.gz", hash = "sha256:e019de665e2bcf9c2b64e2e5aa025fa991da8720daa3c1138cadd2fd1856aed0"}, | ||||
|     {file = "charset_normalizer-2.0.7-py3-none-any.whl", hash = "sha256:f7af805c321bfa1ce6714c51f254e0d5bb5e5834039bc17db7ebe3a4cec9492b"}, | ||||
| ] | ||||
| click = [ | ||||
|     {file = "click-8.0.3-py3-none-any.whl", hash = "sha256:353f466495adaeb40b6b5f592f9f91cb22372351c84caeb068132442a4518ef3"}, | ||||
|     {file = "click-8.0.3.tar.gz", hash = "sha256:410e932b050f5eed773c4cda94de75971c89cdb3155a72a0831139a79e5ecb5b"}, | ||||
| ] | ||||
| colorama = [ | ||||
|     {file = "colorama-0.4.4-py2.py3-none-any.whl", hash = "sha256:9f47eda37229f68eee03b24b9748937c7dc3868f906e8ba69fbcbdd3bc5dc3e2"}, | ||||
|     {file = "colorama-0.4.4.tar.gz", hash = "sha256:5941b2b48a20143d2267e95b1c2a7603ce057ee39fd88e7329b0c292aa16869b"}, | ||||
| ] | ||||
| fastapi = [ | ||||
|     {file = "fastapi-0.70.0-py3-none-any.whl", hash = "sha256:a36d5f2fad931aa3575c07a3472c784e81f3e664e3bb5c8b9c88d0ec1104f59c"}, | ||||
|     {file = "fastapi-0.70.0.tar.gz", hash = "sha256:66da43cfe5185ea1df99552acffd201f1832c6b364e0f4136c0a99f933466ced"}, | ||||
| ] | ||||
| h11 = [ | ||||
|     {file = "h11-0.12.0-py3-none-any.whl", hash = "sha256:36a3cb8c0a032f56e2da7084577878a035d3b61d104230d4bd49c0c6b555a9c6"}, | ||||
|     {file = "h11-0.12.0.tar.gz", hash = "sha256:47222cb6067e4a307d535814917cd98fd0a57b6788ce715755fa2b6c28b56042"}, | ||||
| ] | ||||
| h2 = [ | ||||
|     {file = "h2-4.1.0-py3-none-any.whl", hash = "sha256:03a46bcf682256c95b5fd9e9a99c1323584c3eec6440d379b9903d709476bc6d"}, | ||||
|     {file = "h2-4.1.0.tar.gz", hash = "sha256:a83aca08fbe7aacb79fec788c9c0bac936343560ed9ec18b82a13a12c28d2abb"}, | ||||
| ] | ||||
| hpack = [ | ||||
|     {file = "hpack-4.0.0-py3-none-any.whl", hash = "sha256:84a076fad3dc9a9f8063ccb8041ef100867b1878b25ef0ee63847a5d53818a6c"}, | ||||
|     {file = "hpack-4.0.0.tar.gz", hash = "sha256:fc41de0c63e687ebffde81187a948221294896f6bdc0ae2312708df339430095"}, | ||||
| ] | ||||
| httpcore = [ | ||||
|     {file = "httpcore-0.13.7-py3-none-any.whl", hash = "sha256:369aa481b014cf046f7067fddd67d00560f2f00426e79569d99cb11245134af0"}, | ||||
|     {file = "httpcore-0.13.7.tar.gz", hash = "sha256:036f960468759e633574d7c121afba48af6419615d36ab8ede979f1ad6276fa3"}, | ||||
| ] | ||||
| httptools = [ | ||||
|     {file = "httptools-0.2.0-cp35-cp35m-macosx_10_14_x86_64.whl", hash = "sha256:79dbc21f3612a78b28384e989b21872e2e3cf3968532601544696e4ed0007ce5"}, | ||||
|     {file = "httptools-0.2.0-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:78d03dd39b09c99ec917d50189e6743adbfd18c15d5944392d2eabda688bf149"}, | ||||
|     {file = "httptools-0.2.0-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:a23166e5ae2775709cf4f7ad4c2048755ebfb272767d244e1a96d55ac775cca7"}, | ||||
|     {file = "httptools-0.2.0-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:3ab1f390d8867f74b3b5ee2a7ecc9b8d7f53750bd45714bf1cb72a953d7dfa77"}, | ||||
|     {file = "httptools-0.2.0-cp36-cp36m-win_amd64.whl", hash = "sha256:a7594f9a010cdf1e16a58b3bf26c9da39bbf663e3b8d46d39176999d71816658"}, | ||||
|     {file = "httptools-0.2.0-cp37-cp37m-macosx_10_14_x86_64.whl", hash = "sha256:01b392a166adcc8bc2f526a939a8aabf89fe079243e1543fd0e7dc1b58d737cb"}, | ||||
|     {file = "httptools-0.2.0-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:80ffa04fe8c8dfacf6e4cef8277347d35b0442c581f5814f3b0cf41b65c43c6e"}, | ||||
|     {file = "httptools-0.2.0-cp37-cp37m-win_amd64.whl", hash = "sha256:d5682eeb10cca0606c4a8286a3391d4c3c5a36f0c448e71b8bd05be4e1694bfb"}, | ||||
|     {file = "httptools-0.2.0-cp38-cp38-macosx_10_14_x86_64.whl", hash = "sha256:a289c27ccae399a70eacf32df9a44059ca2ba4ac444604b00a19a6c1f0809943"}, | ||||
|     {file = "httptools-0.2.0-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:813871f961edea6cb2fe312f2d9b27d12a51ba92545380126f80d0de1917ea15"}, | ||||
|     {file = "httptools-0.2.0-cp38-cp38-win_amd64.whl", hash = "sha256:cc9be041e428c10f8b6ab358c6b393648f9457094e1dcc11b4906026d43cd380"}, | ||||
|     {file = "httptools-0.2.0-cp39-cp39-macosx_10_14_x86_64.whl", hash = "sha256:b08d00d889a118f68f37f3c43e359aab24ee29eb2e3fe96d64c6a2ba8b9d6557"}, | ||||
|     {file = "httptools-0.2.0-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:fd3b8905e21431ad306eeaf56644a68fdd621bf8f3097eff54d0f6bdf7262065"}, | ||||
|     {file = "httptools-0.2.0-cp39-cp39-win_amd64.whl", hash = "sha256:200fc1cdf733a9ff554c0bb97a4047785cfaad9875307d6087001db3eb2b417f"}, | ||||
|     {file = "httptools-0.2.0.tar.gz", hash = "sha256:94505026be56652d7a530ab03d89474dc6021019d6b8682281977163b3471ea0"}, | ||||
| ] | ||||
| httpx = [ | ||||
|     {file = "httpx-0.20.0-py3-none-any.whl", hash = "sha256:33af5aad9bdc82ef1fc89219c1e36f5693bf9cd0ebe330884df563445682c0f8"}, | ||||
|     {file = "httpx-0.20.0.tar.gz", hash = "sha256:09606d630f070d07f9ff28104fbcea429ea0014c1e89ac90b4d8de8286c40e7b"}, | ||||
| ] | ||||
| hyperframe = [ | ||||
|     {file = "hyperframe-6.0.1-py3-none-any.whl", hash = "sha256:0ec6bafd80d8ad2195c4f03aacba3a8265e57bc4cff261e802bf39970ed02a15"}, | ||||
|     {file = "hyperframe-6.0.1.tar.gz", hash = "sha256:ae510046231dc8e9ecb1a6586f63d2347bf4c8905914aa84ba585ae85f28a914"}, | ||||
| ] | ||||
| idna = [ | ||||
|     {file = "idna-3.3-py3-none-any.whl", hash = "sha256:84d9dd047ffa80596e0f246e2eab0b391788b0503584e8945f2368256d2735ff"}, | ||||
|     {file = "idna-3.3.tar.gz", hash = "sha256:9d643ff0a55b762d5cdb124b8eaa99c66322e2157b69160bc32796e824360e6d"}, | ||||
| ] | ||||
| importlib-metadata = [ | ||||
|     {file = "importlib_metadata-4.8.1-py3-none-any.whl", hash = "sha256:b618b6d2d5ffa2f16add5697cf57a46c76a56229b0ed1c438322e4e95645bd15"}, | ||||
|     {file = "importlib_metadata-4.8.1.tar.gz", hash = "sha256:f284b3e11256ad1e5d03ab86bb2ccd6f5339688ff17a4d797a0fe7df326f23b1"}, | ||||
| ] | ||||
| loguru = [ | ||||
|     {file = "loguru-0.5.3-py3-none-any.whl", hash = "sha256:f8087ac396b5ee5f67c963b495d615ebbceac2796379599820e324419d53667c"}, | ||||
|     {file = "loguru-0.5.3.tar.gz", hash = "sha256:b28e72ac7a98be3d28ad28570299a393dfcd32e5e3f6a353dec94675767b6319"}, | ||||
| ] | ||||
| nonebot2 = [] | ||||
| pydantic = [ | ||||
|     {file = "pydantic-1.8.2-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:05ddfd37c1720c392f4e0d43c484217b7521558302e7069ce8d318438d297739"}, | ||||
|     {file = "pydantic-1.8.2-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:a7c6002203fe2c5a1b5cbb141bb85060cbff88c2d78eccbc72d97eb7022c43e4"}, | ||||
|     {file = "pydantic-1.8.2-cp36-cp36m-manylinux2014_i686.whl", hash = "sha256:589eb6cd6361e8ac341db97602eb7f354551482368a37f4fd086c0733548308e"}, | ||||
|     {file = "pydantic-1.8.2-cp36-cp36m-manylinux2014_x86_64.whl", hash = "sha256:10e5622224245941efc193ad1d159887872776df7a8fd592ed746aa25d071840"}, | ||||
|     {file = "pydantic-1.8.2-cp36-cp36m-win_amd64.whl", hash = "sha256:99a9fc39470010c45c161a1dc584997f1feb13f689ecf645f59bb4ba623e586b"}, | ||||
|     {file = "pydantic-1.8.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:a83db7205f60c6a86f2c44a61791d993dff4b73135df1973ecd9eed5ea0bda20"}, | ||||
|     {file = "pydantic-1.8.2-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:41b542c0b3c42dc17da70554bc6f38cbc30d7066d2c2815a94499b5684582ecb"}, | ||||
|     {file = "pydantic-1.8.2-cp37-cp37m-manylinux2014_i686.whl", hash = "sha256:ea5cb40a3b23b3265f6325727ddfc45141b08ed665458be8c6285e7b85bd73a1"}, | ||||
|     {file = "pydantic-1.8.2-cp37-cp37m-manylinux2014_x86_64.whl", hash = "sha256:18b5ea242dd3e62dbf89b2b0ec9ba6c7b5abaf6af85b95a97b00279f65845a23"}, | ||||
|     {file = "pydantic-1.8.2-cp37-cp37m-win_amd64.whl", hash = "sha256:234a6c19f1c14e25e362cb05c68afb7f183eb931dd3cd4605eafff055ebbf287"}, | ||||
|     {file = "pydantic-1.8.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:021ea0e4133e8c824775a0cfe098677acf6fa5a3cbf9206a376eed3fc09302cd"}, | ||||
|     {file = "pydantic-1.8.2-cp38-cp38-manylinux1_i686.whl", hash = "sha256:e710876437bc07bd414ff453ac8ec63d219e7690128d925c6e82889d674bb505"}, | ||||
|     {file = "pydantic-1.8.2-cp38-cp38-manylinux2014_i686.whl", hash = "sha256:ac8eed4ca3bd3aadc58a13c2aa93cd8a884bcf21cb019f8cfecaae3b6ce3746e"}, | ||||
|     {file = "pydantic-1.8.2-cp38-cp38-manylinux2014_x86_64.whl", hash = "sha256:4a03cbbe743e9c7247ceae6f0d8898f7a64bb65800a45cbdc52d65e370570820"}, | ||||
|     {file = "pydantic-1.8.2-cp38-cp38-win_amd64.whl", hash = "sha256:8621559dcf5afacf0069ed194278f35c255dc1a1385c28b32dd6c110fd6531b3"}, | ||||
|     {file = "pydantic-1.8.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:8b223557f9510cf0bfd8b01316bf6dd281cf41826607eada99662f5e4963f316"}, | ||||
|     {file = "pydantic-1.8.2-cp39-cp39-manylinux1_i686.whl", hash = "sha256:244ad78eeb388a43b0c927e74d3af78008e944074b7d0f4f696ddd5b2af43c62"}, | ||||
|     {file = "pydantic-1.8.2-cp39-cp39-manylinux2014_i686.whl", hash = "sha256:05ef5246a7ffd2ce12a619cbb29f3307b7c4509307b1b49f456657b43529dc6f"}, | ||||
|     {file = "pydantic-1.8.2-cp39-cp39-manylinux2014_x86_64.whl", hash = "sha256:54cd5121383f4a461ff7644c7ca20c0419d58052db70d8791eacbbe31528916b"}, | ||||
|     {file = "pydantic-1.8.2-cp39-cp39-win_amd64.whl", hash = "sha256:4be75bebf676a5f0f87937c6ddb061fa39cbea067240d98e298508c1bda6f3f3"}, | ||||
|     {file = "pydantic-1.8.2-py3-none-any.whl", hash = "sha256:fec866a0b59f372b7e776f2d7308511784dace622e0992a0b59ea3ccee0ae833"}, | ||||
|     {file = "pydantic-1.8.2.tar.gz", hash = "sha256:26464e57ccaafe72b7ad156fdaa4e9b9ef051f69e175dbbb463283000c05ab7b"}, | ||||
| ] | ||||
| pygtrie = [ | ||||
|     {file = "pygtrie-2.4.2.tar.gz", hash = "sha256:43205559d28863358dbbf25045029f58e2ab357317a59b11f11ade278ac64692"}, | ||||
| ] | ||||
| python-dotenv = [ | ||||
|     {file = "python-dotenv-0.19.1.tar.gz", hash = "sha256:14f8185cc8d494662683e6914addcb7e95374771e707601dfc70166946b4c4b8"}, | ||||
|     {file = "python_dotenv-0.19.1-py2.py3-none-any.whl", hash = "sha256:bbd3da593fc49c249397cbfbcc449cf36cb02e75afc8157fcc6a81df6fb7750a"}, | ||||
| ] | ||||
| pyyaml = [ | ||||
|     {file = "PyYAML-6.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d4db7c7aef085872ef65a8fd7d6d09a14ae91f691dec3e87ee5ee0539d516f53"}, | ||||
|     {file = "PyYAML-6.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9df7ed3b3d2e0ecfe09e14741b857df43adb5a3ddadc919a2d94fbdf78fea53c"}, | ||||
|     {file = "PyYAML-6.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:77f396e6ef4c73fdc33a9157446466f1cff553d979bd00ecb64385760c6babdc"}, | ||||
|     {file = "PyYAML-6.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a80a78046a72361de73f8f395f1f1e49f956c6be882eed58505a15f3e430962b"}, | ||||
|     {file = "PyYAML-6.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f84fbc98b019fef2ee9a1cb3ce93e3187a6df0b2538a651bfb890254ba9f90b5"}, | ||||
|     {file = "PyYAML-6.0-cp310-cp310-win32.whl", hash = "sha256:2cd5df3de48857ed0544b34e2d40e9fac445930039f3cfe4bcc592a1f836d513"}, | ||||
|     {file = "PyYAML-6.0-cp310-cp310-win_amd64.whl", hash = "sha256:daf496c58a8c52083df09b80c860005194014c3698698d1a57cbcfa182142a3a"}, | ||||
|     {file = "PyYAML-6.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:897b80890765f037df3403d22bab41627ca8811ae55e9a722fd0392850ec4d86"}, | ||||
|     {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:50602afada6d6cbfad699b0c7bb50d5ccffa7e46a3d738092afddc1f9758427f"}, | ||||
|     {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:48c346915c114f5fdb3ead70312bd042a953a8ce5c7106d5bfb1a5254e47da92"}, | ||||
|     {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:98c4d36e99714e55cfbaaee6dd5badbc9a1ec339ebfc3b1f52e293aee6bb71a4"}, | ||||
|     {file = "PyYAML-6.0-cp36-cp36m-win32.whl", hash = "sha256:0283c35a6a9fbf047493e3a0ce8d79ef5030852c51e9d911a27badfde0605293"}, | ||||
|     {file = "PyYAML-6.0-cp36-cp36m-win_amd64.whl", hash = "sha256:07751360502caac1c067a8132d150cf3d61339af5691fe9e87803040dbc5db57"}, | ||||
|     {file = "PyYAML-6.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:819b3830a1543db06c4d4b865e70ded25be52a2e0631ccd2f6a47a2822f2fd7c"}, | ||||
|     {file = "PyYAML-6.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:473f9edb243cb1935ab5a084eb238d842fb8f404ed2193a915d1784b5a6b5fc0"}, | ||||
|     {file = "PyYAML-6.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0ce82d761c532fe4ec3f87fc45688bdd3a4c1dc5e0b4a19814b9009a29baefd4"}, | ||||
|     {file = "PyYAML-6.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:231710d57adfd809ef5d34183b8ed1eeae3f76459c18fb4a0b373ad56bedcdd9"}, | ||||
|     {file = "PyYAML-6.0-cp37-cp37m-win32.whl", hash = "sha256:c5687b8d43cf58545ade1fe3e055f70eac7a5a1a0bf42824308d868289a95737"}, | ||||
|     {file = "PyYAML-6.0-cp37-cp37m-win_amd64.whl", hash = "sha256:d15a181d1ecd0d4270dc32edb46f7cb7733c7c508857278d3d378d14d606db2d"}, | ||||
|     {file = "PyYAML-6.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0b4624f379dab24d3725ffde76559cff63d9ec94e1736b556dacdfebe5ab6d4b"}, | ||||
|     {file = "PyYAML-6.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:213c60cd50106436cc818accf5baa1aba61c0189ff610f64f4a3e8c6726218ba"}, | ||||
|     {file = "PyYAML-6.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9fa600030013c4de8165339db93d182b9431076eb98eb40ee068700c9c813e34"}, | ||||
|     {file = "PyYAML-6.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:277a0ef2981ca40581a47093e9e2d13b3f1fbbeffae064c1d21bfceba2030287"}, | ||||
|     {file = "PyYAML-6.0-cp38-cp38-win32.whl", hash = "sha256:d4eccecf9adf6fbcc6861a38015c2a64f38b9d94838ac1810a9023a0609e1b78"}, | ||||
|     {file = "PyYAML-6.0-cp38-cp38-win_amd64.whl", hash = "sha256:1e4747bc279b4f613a09eb64bba2ba602d8a6664c6ce6396a4d0cd413a50ce07"}, | ||||
|     {file = "PyYAML-6.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:055d937d65826939cb044fc8c9b08889e8c743fdc6a32b33e2390f66013e449b"}, | ||||
|     {file = "PyYAML-6.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e61ceaab6f49fb8bdfaa0f92c4b57bcfbea54c09277b1b4f7ac376bfb7a7c174"}, | ||||
|     {file = "PyYAML-6.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d67d839ede4ed1b28a4e8909735fc992a923cdb84e618544973d7dfc71540803"}, | ||||
|     {file = "PyYAML-6.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cba8c411ef271aa037d7357a2bc8f9ee8b58b9965831d9e51baf703280dc73d3"}, | ||||
|     {file = "PyYAML-6.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:40527857252b61eacd1d9af500c3337ba8deb8fc298940291486c465c8b46ec0"}, | ||||
|     {file = "PyYAML-6.0-cp39-cp39-win32.whl", hash = "sha256:b5b9eccad747aabaaffbc6064800670f0c297e52c12754eb1d976c57e4f74dcb"}, | ||||
|     {file = "PyYAML-6.0-cp39-cp39-win_amd64.whl", hash = "sha256:b3d267842bf12586ba6c734f89d1f5b871df0273157918b0ccefa29deb05c21c"}, | ||||
|     {file = "PyYAML-6.0.tar.gz", hash = "sha256:68fb519c14306fec9720a2a5b45bc9f0c8d1b9c72adf45c37baedfcd949c35a2"}, | ||||
| ] | ||||
| rfc3986 = [ | ||||
|     {file = "rfc3986-1.5.0-py2.py3-none-any.whl", hash = "sha256:a86d6e1f5b1dc238b218b012df0aa79409667bb209e58da56d0b94704e712a97"}, | ||||
|     {file = "rfc3986-1.5.0.tar.gz", hash = "sha256:270aaf10d87d0d4e095063c65bf3ddbc6ee3d0b226328ce21e036f946e421835"}, | ||||
| ] | ||||
| sniffio = [ | ||||
|     {file = "sniffio-1.2.0-py3-none-any.whl", hash = "sha256:471b71698eac1c2112a40ce2752bb2f4a4814c22a54a3eed3676bc0f5ca9f663"}, | ||||
|     {file = "sniffio-1.2.0.tar.gz", hash = "sha256:c4666eecec1d3f50960c6bdf61ab7bc350648da6c126e3cf6898d8cd4ddcd3de"}, | ||||
| ] | ||||
| starlette = [ | ||||
|     {file = "starlette-0.16.0-py3-none-any.whl", hash = "sha256:38eb24bf705a2c317e15868e384c1b8a12ca396e5a3c3a003db7e667c43f939f"}, | ||||
|     {file = "starlette-0.16.0.tar.gz", hash = "sha256:e1904b5d0007aee24bdd3c43994be9b3b729f4f58e740200de1d623f8c3a8870"}, | ||||
| ] | ||||
| tomlkit = [ | ||||
|     {file = "tomlkit-0.7.2-py2.py3-none-any.whl", hash = "sha256:173ad840fa5d2aac140528ca1933c29791b79a374a0861a80347f42ec9328117"}, | ||||
|     {file = "tomlkit-0.7.2.tar.gz", hash = "sha256:d7a454f319a7e9bd2e249f239168729327e4dd2d27b17dc68be264ad1ce36754"}, | ||||
| ] | ||||
| typing-extensions = [ | ||||
|     {file = "typing_extensions-3.10.0.2-py2-none-any.whl", hash = "sha256:d8226d10bc02a29bcc81df19a26e56a9647f8b0a6d4a83924139f4a8b01f17b7"}, | ||||
|     {file = "typing_extensions-3.10.0.2-py3-none-any.whl", hash = "sha256:f1d25edafde516b146ecd0613dabcc61409817af4766fbbcfb8d1ad4ec441a34"}, | ||||
|     {file = "typing_extensions-3.10.0.2.tar.gz", hash = "sha256:49f75d16ff11f1cd258e1b988ccff82a3ca5570217d7ad8c5f48205dd99a677e"}, | ||||
| ] | ||||
| uvicorn = [ | ||||
|     {file = "uvicorn-0.15.0-py3-none-any.whl", hash = "sha256:17f898c64c71a2640514d4089da2689e5db1ce5d4086c2d53699bf99513421c1"}, | ||||
|     {file = "uvicorn-0.15.0.tar.gz", hash = "sha256:d9a3c0dd1ca86728d3e235182683b4cf94cd53a867c288eaeca80ee781b2caff"}, | ||||
| ] | ||||
| uvloop = [ | ||||
|     {file = "uvloop-0.16.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:6224f1401025b748ffecb7a6e2652b17768f30b1a6a3f7b44660e5b5b690b12d"}, | ||||
|     {file = "uvloop-0.16.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:30ba9dcbd0965f5c812b7c2112a1ddf60cf904c1c160f398e7eed3a6b82dcd9c"}, | ||||
|     {file = "uvloop-0.16.0-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:bd53f7f5db562f37cd64a3af5012df8cac2c464c97e732ed556800129505bd64"}, | ||||
|     {file = "uvloop-0.16.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:772206116b9b57cd625c8a88f2413df2fcfd0b496eb188b82a43bed7af2c2ec9"}, | ||||
|     {file = "uvloop-0.16.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b572256409f194521a9895aef274cea88731d14732343da3ecdb175228881638"}, | ||||
|     {file = "uvloop-0.16.0-cp37-cp37m-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:04ff57aa137230d8cc968f03481176041ae789308b4d5079118331ab01112450"}, | ||||
|     {file = "uvloop-0.16.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3a19828c4f15687675ea912cc28bbcb48e9bb907c801873bd1519b96b04fb805"}, | ||||
|     {file = "uvloop-0.16.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:e814ac2c6f9daf4c36eb8e85266859f42174a4ff0d71b99405ed559257750382"}, | ||||
|     {file = "uvloop-0.16.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:bd8f42ea1ea8f4e84d265769089964ddda95eb2bb38b5cbe26712b0616c3edee"}, | ||||
|     {file = "uvloop-0.16.0-cp38-cp38-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:647e481940379eebd314c00440314c81ea547aa636056f554d491e40503c8464"}, | ||||
|     {file = "uvloop-0.16.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8e0d26fa5875d43ddbb0d9d79a447d2ace4180d9e3239788208527c4784f7cab"}, | ||||
|     {file = "uvloop-0.16.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:6ccd57ae8db17d677e9e06192e9c9ec4bd2066b77790f9aa7dede2cc4008ee8f"}, | ||||
|     {file = "uvloop-0.16.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:089b4834fd299d82d83a25e3335372f12117a7d38525217c2258e9b9f4578897"}, | ||||
|     {file = "uvloop-0.16.0-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:98d117332cc9e5ea8dfdc2b28b0a23f60370d02e1395f88f40d1effd2cb86c4f"}, | ||||
|     {file = "uvloop-0.16.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1e5f2e2ff51aefe6c19ee98af12b4ae61f5be456cd24396953244a30880ad861"}, | ||||
|     {file = "uvloop-0.16.0.tar.gz", hash = "sha256:f74bc20c7b67d1c27c72601c78cf95be99d5c2cdd4514502b4f3eb0933ff1228"}, | ||||
| ] | ||||
| watchgod = [ | ||||
|     {file = "watchgod-0.7-py3-none-any.whl", hash = "sha256:d6c1ea21df37847ac0537ca0d6c2f4cdf513562e95f77bb93abbcf05573407b7"}, | ||||
|     {file = "watchgod-0.7.tar.gz", hash = "sha256:48140d62b0ebe9dd9cf8381337f06351e1f2e70b2203fa9c6eff4e572ca84f29"}, | ||||
| ] | ||||
| websockets = [ | ||||
|     {file = "websockets-10.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:cd8c6f2ec24aedace251017bc7a414525171d4e6578f914acab9349362def4da"}, | ||||
|     {file = "websockets-10.0-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:1f6b814cff6aadc4288297cb3a248614829c6e4ff5556593c44a115e9dd49939"}, | ||||
|     {file = "websockets-10.0-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:01db0ecd1a0ca6702d02a5ed40413e18b7d22f94afb3bbe0d323bac86c42c1c8"}, | ||||
|     {file = "websockets-10.0-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:82b17524b1ce6ae7f7dd93e4d18e9b9474071e28b65dbf1dfe9b5767778db379"}, | ||||
|     {file = "websockets-10.0-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:8bbf8660c3f833ddc8b1afab90213f2e672a9ddac6eecb3cde968e6b2807c1c7"}, | ||||
|     {file = "websockets-10.0-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:b8176deb6be540a46695960a765a77c28ac8b2e3ef2ec95d50a4f5df901edb1c"}, | ||||
|     {file = "websockets-10.0-cp37-cp37m-win32.whl", hash = "sha256:706e200fc7f03bed99ad0574cd1ea8b0951477dd18cc978ccb190683c69dba76"}, | ||||
|     {file = "websockets-10.0-cp37-cp37m-win_amd64.whl", hash = "sha256:5b2600e01c7ca6f840c42c747ffbe0254f319594ed108db847eb3d75f4aacb80"}, | ||||
|     {file = "websockets-10.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:085bb8a6e780d30eaa1ba48ac7f3a6707f925edea787cfb761ce5a39e77ac09b"}, | ||||
|     {file = "websockets-10.0-cp38-cp38-manylinux1_i686.whl", hash = "sha256:9a4d889162bd48588e80950e07fa5e039eee9deb76a58092e8c3ece96d7ef537"}, | ||||
|     {file = "websockets-10.0-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:b4ade7569b6fd17912452f9c3757d96f8e4044016b6d22b3b8391e641ca50456"}, | ||||
|     {file = "websockets-10.0-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:2a43072e434c041a99f2e1eb9b692df0232a38c37c61d00e9f24db79474329e4"}, | ||||
|     {file = "websockets-10.0-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:7f79f02c7f9a8320aff7d3321cd1c7e3a7dbc15d922ac996cca827301ee75238"}, | ||||
|     {file = "websockets-10.0-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:1ac35426fe3e7d3d0fac3d63c8965c76ed67a8fd713937be072bf0ce22808539"}, | ||||
|     {file = "websockets-10.0-cp38-cp38-win32.whl", hash = "sha256:ff59c6bdb87b31f7e2d596f09353d5a38c8c8ff571b0e2238e8ee2d55ad68465"}, | ||||
|     {file = "websockets-10.0-cp38-cp38-win_amd64.whl", hash = "sha256:d67646ddd17a86117ae21c27005d83c1895c0cef5d7be548b7549646372f868a"}, | ||||
|     {file = "websockets-10.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:82bd921885231f4a30d9bc550552495b3fc36b1235add6d374e7c65c3babd805"}, | ||||
|     {file = "websockets-10.0-cp39-cp39-manylinux1_i686.whl", hash = "sha256:7d2e12e4f901f1bc062dfdf91831712c4106ed18a9a4cdb65e2e5f502124ca37"}, | ||||
|     {file = "websockets-10.0-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:71358c7816e2762f3e4af3adf0040f268e219f5a38cb3487a9d0fc2e554fef6a"}, | ||||
|     {file = "websockets-10.0-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:fe83b3ec9ef34063d86dfe1029160a85f24a5a94271036e5714a57acfdd089a1"}, | ||||
|     {file = "websockets-10.0-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:eb282127e9c136f860c6068a4fba5756eb25e755baffb5940b6f1eae071928b2"}, | ||||
|     {file = "websockets-10.0-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:62160772314920397f9d219147f958b33fa27a12c662d4455c9ccbba9a07e474"}, | ||||
|     {file = "websockets-10.0-cp39-cp39-win32.whl", hash = "sha256:e42a1f1e03437b017af341e9bbfdc09252cd48ef32a8c3c3ead769eab3b17368"}, | ||||
|     {file = "websockets-10.0-cp39-cp39-win_amd64.whl", hash = "sha256:c5880442f5fc268f1ef6d37b2c152c114deccca73f48e3a8c48004d2f16f4567"}, | ||||
|     {file = "websockets-10.0.tar.gz", hash = "sha256:c4fc9a1d242317892590abe5b61a9127f1a61740477bfb121743f290b8054002"}, | ||||
| ] | ||||
| win32-setctime = [ | ||||
|     {file = "win32_setctime-1.0.3-py3-none-any.whl", hash = "sha256:dc925662de0a6eb987f0b01f599c01a8236cb8c62831c22d9cada09ad958243e"}, | ||||
|     {file = "win32_setctime-1.0.3.tar.gz", hash = "sha256:4e88556c32fdf47f64165a2180ba4552f8bb32c1103a2fafd05723a0bd42bd4b"}, | ||||
| ] | ||||
| zipp = [ | ||||
|     {file = "zipp-3.6.0-py3-none-any.whl", hash = "sha256:9fe5ea21568a0a70e50f273397638d39b03353731e6cbbb3fd8502a33fec40bc"}, | ||||
|     {file = "zipp-3.6.0.tar.gz", hash = "sha256:71c644c5369f4a6e07636f0aa966270449561fcea2e3d6747b8d23efaa9d7832"}, | ||||
| ] | ||||
| @@ -1,54 +0,0 @@ | ||||
| [tool.poetry] | ||||
| name = "nonebot-adapter-mirai" | ||||
| version = "2.0.0-alpha.16" | ||||
| description = "Mirai Api HTTP adapter for nonebot2" | ||||
| authors = ["Mix <admin@yami.im>", "yanyongyu <yyy@nonebot.dev>"] | ||||
| license = "AGPL-3.0-or-later" | ||||
| readme = "README.md" | ||||
| homepage = "https://v2.nonebot.dev/" | ||||
| repository = "https://github.com/nonebot/nonebot2" | ||||
| documentation = "https://v2.nonebot.dev/" | ||||
| keywords = ["bot", "qq", "qqbot", "mirai"] | ||||
| classifiers = [ | ||||
|   "Development Status :: 5 - Production/Stable", | ||||
|   "Framework :: Robot Framework", | ||||
|   "Framework :: Robot Framework :: Library", | ||||
|   "Operating System :: OS Independent", | ||||
|   "Programming Language :: Python :: 3" | ||||
| ] | ||||
| packages = [ | ||||
|   { include = "nonebot" } | ||||
| ] | ||||
| exclude = ["nonebot/__init__.py", "nonebot/adapters/__init__.py"] | ||||
|  | ||||
| [tool.poetry.dependencies] | ||||
| python = "^3.7.3" | ||||
| httpx = ">=0.20.0, <1.0.0" | ||||
| nonebot2 = "^2.0.0-alpha.14" | ||||
|  | ||||
| [tool.poetry.dev-dependencies] | ||||
| nonebot2 = { path = "../../", develop = true } | ||||
|  | ||||
| # [[tool.poetry.source]] | ||||
| # name = "aliyun" | ||||
| # url = "https://mirrors.aliyun.com/pypi/simple/" | ||||
| # default = true | ||||
|  | ||||
| [tool.black] | ||||
| line-length = 88 | ||||
| target-version = ["py37", "py38", "py39"] | ||||
| include = '\.pyi?$' | ||||
| extend-exclude = ''' | ||||
| ''' | ||||
|  | ||||
| [tool.isort] | ||||
| profile = "black" | ||||
| line_length = 80 | ||||
| length_sort = true | ||||
| skip_gitignore = true | ||||
| force_sort_within_sections = true | ||||
| extra_standard_library = ["typing_extensions"] | ||||
|  | ||||
| [build-system] | ||||
| requires = ["poetry-core>=1.0.0"] | ||||
| build-backend = "poetry.core.masonry.api" | ||||
							
								
								
									
										322
									
								
								poetry.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										322
									
								
								poetry.lock
									
									
									
										generated
									
									
									
								
							| @@ -1,17 +1,3 @@ | ||||
| [[package]] | ||||
| name = "aiocache" | ||||
| version = "0.11.1" | ||||
| description = "multi backend asyncio cache" | ||||
| category = "dev" | ||||
| optional = false | ||||
| python-versions = "*" | ||||
|  | ||||
| [package.extras] | ||||
| dev = ["asynctest (>=0.11.0)", "codecov", "coverage", "flake8", "ipdb", "marshmallow", "pystache", "pytest", "pytest-asyncio", "pytest-mock", "sphinx", "sphinx-autobuild", "sphinx-rtd-theme", "black"] | ||||
| memcached = ["aiomcache (>=0.5.2)"] | ||||
| msgpack = ["msgpack (>=0.5.5)"] | ||||
| redis = ["aioredis (>=0.3.3)", "aioredis (>=1.0.0)"] | ||||
|  | ||||
| [[package]] | ||||
| name = "aiodns" | ||||
| version = "3.0.0" | ||||
| @@ -25,10 +11,10 @@ pycares = ">=4.0.0" | ||||
|  | ||||
| [[package]] | ||||
| name = "aiofiles" | ||||
| version = "0.7.0" | ||||
| version = "0.8.0" | ||||
| description = "File support for asyncio." | ||||
| category = "main" | ||||
| optional = false | ||||
| optional = true | ||||
| python-versions = ">=3.6,<4.0" | ||||
|  | ||||
| [[package]] | ||||
| @@ -153,7 +139,7 @@ pytz = ">=2015.7" | ||||
|  | ||||
| [[package]] | ||||
| name = "black" | ||||
| version = "21.11b1" | ||||
| version = "21.12b0" | ||||
| description = "The uncompromising code formatter." | ||||
| category = "dev" | ||||
| optional = false | ||||
| @@ -164,7 +150,6 @@ click = ">=7.1.2" | ||||
| mypy-extensions = ">=0.4.3" | ||||
| pathspec = ">=0.9.0,<1" | ||||
| platformdirs = ">=2" | ||||
| regex = ">=2021.4.4" | ||||
| tomli = ">=0.2.6,<2.0.0" | ||||
| typed-ast = {version = ">=1.4.2", markers = "python_version < \"3.8\" and implementation_name == \"cpython\""} | ||||
| typing-extensions = [ | ||||
| @@ -224,7 +209,7 @@ pycparser = "*" | ||||
|  | ||||
| [[package]] | ||||
| name = "charset-normalizer" | ||||
| version = "2.0.7" | ||||
| version = "2.0.9" | ||||
| description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." | ||||
| category = "main" | ||||
| optional = false | ||||
| @@ -509,72 +494,6 @@ category = "dev" | ||||
| optional = false | ||||
| python-versions = "*" | ||||
|  | ||||
| [[package]] | ||||
| name = "nonebot-adapter-ding" | ||||
| version = "2.0.0-alpha.16" | ||||
| description = "Ding adapter for nonebot2" | ||||
| category = "dev" | ||||
| optional = false | ||||
| python-versions = "^3.7.3" | ||||
| develop = true | ||||
|  | ||||
| [package.dependencies] | ||||
| httpx = ">=0.20.0, <1.0.0" | ||||
| nonebot2 = "^2.0.0-alpha.14" | ||||
|  | ||||
| [package.source] | ||||
| type = "directory" | ||||
| url = "packages/nonebot-adapter-ding" | ||||
|  | ||||
| [[package]] | ||||
| name = "nonebot-adapter-feishu" | ||||
| version = "2.0.0-alpha.16" | ||||
| description = "feishu(larksuite) adapter for nonebot2" | ||||
| category = "dev" | ||||
| optional = false | ||||
| python-versions = "^3.7.3" | ||||
| develop = true | ||||
|  | ||||
| [package.dependencies] | ||||
| aiocache = "^0.11.1" | ||||
| httpx = ">=0.20.0, <1.0.0" | ||||
| nonebot2 = "^2.0.0-alpha.14" | ||||
| pycryptodome = "^3.10.1" | ||||
|  | ||||
| [package.source] | ||||
| type = "directory" | ||||
| url = "packages/nonebot-adapter-feishu" | ||||
|  | ||||
| [[package]] | ||||
| name = "nonebot-adapter-mirai" | ||||
| version = "2.0.0-alpha.16" | ||||
| description = "Mirai Api HTTP adapter for nonebot2" | ||||
| category = "dev" | ||||
| optional = false | ||||
| python-versions = "^3.7.3" | ||||
| develop = true | ||||
|  | ||||
| [package.dependencies] | ||||
| httpx = ">=0.20.0, <1.0.0" | ||||
| nonebot2 = "^2.0.0-alpha.14" | ||||
|  | ||||
| [package.source] | ||||
| type = "directory" | ||||
| url = "packages/nonebot-adapter-mirai" | ||||
|  | ||||
| [[package]] | ||||
| name = "nonebot-plugin-test" | ||||
| version = "0.3.0" | ||||
| description = "Test frontend for nonebot v2+" | ||||
| category = "dev" | ||||
| optional = false | ||||
| python-versions = ">=3.7.3,<4.0.0" | ||||
|  | ||||
| [package.dependencies] | ||||
| aiofiles = ">=0.7.0,<0.8.0" | ||||
| nonebot2 = ">=2.0.0-alpha.14,<3.0.0" | ||||
| python-socketio = ">=4.6.1,<5.0.0" | ||||
|  | ||||
| [[package]] | ||||
| name = "packaging" | ||||
| version = "21.3" | ||||
| @@ -636,14 +555,6 @@ category = "main" | ||||
| optional = true | ||||
| python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" | ||||
|  | ||||
| [[package]] | ||||
| name = "pycryptodome" | ||||
| version = "3.11.0" | ||||
| description = "Cryptographic library for Python" | ||||
| category = "dev" | ||||
| optional = false | ||||
| python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" | ||||
|  | ||||
| [[package]] | ||||
| name = "pydantic" | ||||
| version = "1.8.2" | ||||
| @@ -709,37 +620,6 @@ python-versions = ">=3.5" | ||||
| [package.extras] | ||||
| cli = ["click (>=5.0)"] | ||||
|  | ||||
| [[package]] | ||||
| name = "python-engineio" | ||||
| version = "3.14.2" | ||||
| description = "Engine.IO server" | ||||
| category = "dev" | ||||
| optional = false | ||||
| python-versions = "*" | ||||
|  | ||||
| [package.dependencies] | ||||
| six = ">=1.9.0" | ||||
|  | ||||
| [package.extras] | ||||
| asyncio_client = ["aiohttp (>=3.4)"] | ||||
| client = ["requests (>=2.21.0)", "websocket-client (>=0.54.0)"] | ||||
|  | ||||
| [[package]] | ||||
| name = "python-socketio" | ||||
| version = "4.6.1" | ||||
| description = "Socket.IO server" | ||||
| category = "dev" | ||||
| optional = false | ||||
| python-versions = "*" | ||||
|  | ||||
| [package.dependencies] | ||||
| python-engineio = ">=3.13.0,<4" | ||||
| six = ">=1.9.0" | ||||
|  | ||||
| [package.extras] | ||||
| asyncio_client = ["aiohttp (>=3.4)", "websockets (>=7.0)"] | ||||
| client = ["requests (>=2.21.0)", "websocket-client (>=0.54.0)"] | ||||
|  | ||||
| [[package]] | ||||
| name = "pytz" | ||||
| version = "2021.3" | ||||
| @@ -778,14 +658,6 @@ werkzeug = ">=2.0.0" | ||||
| [package.extras] | ||||
| dotenv = ["python-dotenv"] | ||||
|  | ||||
| [[package]] | ||||
| name = "regex" | ||||
| version = "2021.11.10" | ||||
| description = "Alternative regular expression module, to replace re." | ||||
| category = "dev" | ||||
| optional = false | ||||
| python-versions = "*" | ||||
|  | ||||
| [[package]] | ||||
| name = "requests" | ||||
| version = "2.26.0" | ||||
| @@ -818,14 +690,6 @@ idna = {version = "*", optional = true, markers = "extra == \"idna2008\""} | ||||
| [package.extras] | ||||
| idna2008 = ["idna"] | ||||
|  | ||||
| [[package]] | ||||
| 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.*" | ||||
|  | ||||
| [[package]] | ||||
| name = "sniffio" | ||||
| version = "1.2.0" | ||||
| @@ -844,7 +708,7 @@ python-versions = "*" | ||||
|  | ||||
| [[package]] | ||||
| name = "sphinx" | ||||
| version = "4.3.0" | ||||
| version = "4.3.1" | ||||
| description = "Python documentation generator" | ||||
| category = "dev" | ||||
| optional = false | ||||
| @@ -1007,7 +871,7 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" | ||||
|  | ||||
| [[package]] | ||||
| name = "typed-ast" | ||||
| version = "1.5.0" | ||||
| version = "1.5.1" | ||||
| description = "a fork of Python 2 and 3 ast modules with type comment support" | ||||
| category = "dev" | ||||
| optional = false | ||||
| @@ -1015,7 +879,7 @@ python-versions = ">=3.6" | ||||
|  | ||||
| [[package]] | ||||
| name = "typing-extensions" | ||||
| version = "4.0.0" | ||||
| version = "4.0.1" | ||||
| description = "Backported and Experimental Type Hints for Python 3.6+" | ||||
| category = "main" | ||||
| optional = false | ||||
| @@ -1119,7 +983,7 @@ watchdog = ["watchdog"] | ||||
|  | ||||
| [[package]] | ||||
| name = "win32-setctime" | ||||
| version = "1.0.3" | ||||
| version = "1.0.4" | ||||
| description = "A small Python utility to set file creation time on Windows" | ||||
| category = "main" | ||||
| optional = false | ||||
| @@ -1180,20 +1044,16 @@ quart = ["Quart"] | ||||
| [metadata] | ||||
| lock-version = "1.1" | ||||
| python-versions = "^3.7.3" | ||||
| content-hash = "9c7bf3b0936f4084baf0184046f4443a37c60dadb289c2baaa4360c8d85e3ae8" | ||||
| content-hash = "d7cede1e6f5d427a8122a895459faf0181ccee6e670fc275e8890219fc11d545" | ||||
|  | ||||
| [metadata.files] | ||||
| aiocache = [ | ||||
|     {file = "aiocache-0.11.1-py2.py3-none-any.whl", hash = "sha256:e55c7caaa5753794fd301c3a2e592737fa1d036db9f8d04ae154facdfb48a157"}, | ||||
|     {file = "aiocache-0.11.1.tar.gz", hash = "sha256:f2ebe0b05cec45782e7b5ea0bb74640f157dd4bb1028b4565364dda9fe33be7f"}, | ||||
| ] | ||||
| aiodns = [ | ||||
|     {file = "aiodns-3.0.0-py3-none-any.whl", hash = "sha256:2b19bc5f97e5c936638d28e665923c093d8af2bf3aa88d35c43417fa25d136a2"}, | ||||
|     {file = "aiodns-3.0.0.tar.gz", hash = "sha256:946bdfabe743fceeeb093c8a010f5d1645f708a241be849e17edfb0e49e08cd6"}, | ||||
| ] | ||||
| aiofiles = [ | ||||
|     {file = "aiofiles-0.7.0-py3-none-any.whl", hash = "sha256:c67a6823b5f23fcab0a2595a289cec7d8c863ffcb4322fb8cd6b90400aedfdbc"}, | ||||
|     {file = "aiofiles-0.7.0.tar.gz", hash = "sha256:a1c4fc9b2ff81568c83e21392a82f344ea9d23da906e4f6a52662764545e19d4"}, | ||||
|     {file = "aiofiles-0.8.0-py3-none-any.whl", hash = "sha256:7a973fc22b29e9962d0897805ace5856e6a566ab1f0c8e5c91ff6c866519c937"}, | ||||
|     {file = "aiofiles-0.8.0.tar.gz", hash = "sha256:8334f23235248a3b2e83b2c3a78a22674f39969b96397126cc93664d9a901e59"}, | ||||
| ] | ||||
| aiohttp = [ | ||||
|     {file = "aiohttp-3.8.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:1ed0b6477896559f17b9eaeb6d38e07f7f9ffe40b9f0f9627ae8b9926ae260a8"}, | ||||
| @@ -1302,8 +1162,8 @@ babel = [ | ||||
|     {file = "Babel-2.9.1.tar.gz", hash = "sha256:bc0c176f9f6a994582230df350aa6e05ba2ebe4b3ac317eab29d9be5d2768da0"}, | ||||
| ] | ||||
| black = [ | ||||
|     {file = "black-21.11b1-py3-none-any.whl", hash = "sha256:802c6c30b637b28645b7fde282ed2569c0cd777dbe493a41b6a03c1d903f99ac"}, | ||||
|     {file = "black-21.11b1.tar.gz", hash = "sha256:a042adbb18b3262faad5aff4e834ff186bb893f95ba3a8013f09de1e5569def2"}, | ||||
|     {file = "black-21.12b0-py3-none-any.whl", hash = "sha256:a615e69ae185e08fdd73e4715e260e2479c861b5740057fde6e8b4e3b7dd589f"}, | ||||
|     {file = "black-21.12b0.tar.gz", hash = "sha256:77b80f693a569e2e527958459634f18df9b0ba2625ba4e0c2d5da5be42e6f2b3"}, | ||||
| ] | ||||
| blinker = [ | ||||
|     {file = "blinker-1.4.tar.gz", hash = "sha256:471aee25f3992bd325afa3772f1063dbdbbca947a041b8b89466dc00d606f8b6"}, | ||||
| @@ -1445,8 +1305,8 @@ cffi = [ | ||||
|     {file = "cffi-1.15.0.tar.gz", hash = "sha256:920f0d66a896c2d99f0adbb391f990a84091179542c205fa53ce5787aff87954"}, | ||||
| ] | ||||
| charset-normalizer = [ | ||||
|     {file = "charset-normalizer-2.0.7.tar.gz", hash = "sha256:e019de665e2bcf9c2b64e2e5aa025fa991da8720daa3c1138cadd2fd1856aed0"}, | ||||
|     {file = "charset_normalizer-2.0.7-py3-none-any.whl", hash = "sha256:f7af805c321bfa1ce6714c51f254e0d5bb5e5834039bc17db7ebe3a4cec9492b"}, | ||||
|     {file = "charset-normalizer-2.0.9.tar.gz", hash = "sha256:b0b883e8e874edfdece9c28f314e3dd5badf067342e42fb162203335ae61aa2c"}, | ||||
|     {file = "charset_normalizer-2.0.9-py3-none-any.whl", hash = "sha256:1eecaa09422db5be9e29d7fc65664e6c33bd06f9ced7838578ba40d58bdf3721"}, | ||||
| ] | ||||
| click = [ | ||||
|     {file = "click-8.0.3-py3-none-any.whl", hash = "sha256:353f466495adaeb40b6b5f592f9f91cb22372351c84caeb068132442a4518ef3"}, | ||||
| @@ -1764,13 +1624,6 @@ mypy-extensions = [ | ||||
|     {file = "mypy_extensions-0.4.3-py2.py3-none-any.whl", hash = "sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d"}, | ||||
|     {file = "mypy_extensions-0.4.3.tar.gz", hash = "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8"}, | ||||
| ] | ||||
| nonebot-adapter-ding = [] | ||||
| nonebot-adapter-feishu = [] | ||||
| nonebot-adapter-mirai = [] | ||||
| nonebot-plugin-test = [ | ||||
|     {file = "nonebot-plugin-test-0.3.0.tar.gz", hash = "sha256:6cea9342f4df69a73b9aa27a3eaa22a08c6e54b675e2e6638b4b3fc8568cd6fe"}, | ||||
|     {file = "nonebot_plugin_test-0.3.0-py3-none-any.whl", hash = "sha256:edb880340436323ccd0a13b31d48975136b6bdc71daa178601c4b05b068cc73e"}, | ||||
| ] | ||||
| packaging = [ | ||||
|     {file = "packaging-21.3-py3-none-any.whl", hash = "sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522"}, | ||||
|     {file = "packaging-21.3.tar.gz", hash = "sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb"}, | ||||
| @@ -1824,38 +1677,6 @@ pycparser = [ | ||||
|     {file = "pycparser-2.21-py2.py3-none-any.whl", hash = "sha256:8ee45429555515e1f6b185e78100aea234072576aa43ab53aefcae078162fca9"}, | ||||
|     {file = "pycparser-2.21.tar.gz", hash = "sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206"}, | ||||
| ] | ||||
| pycryptodome = [ | ||||
|     {file = "pycryptodome-3.11.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:ffd0cac13ff41f2d15ed39dc6ba1d2ad88dd2905d656c33d8235852f5d6151fd"}, | ||||
|     {file = "pycryptodome-3.11.0-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:ead516e03dfe062aefeafe4a29445a6449b0fc43bc8cb30194b2754917a63798"}, | ||||
|     {file = "pycryptodome-3.11.0-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:4ce6b09547bf2c7cede3a017f79502eaed3e819c13cdb3cb357aea1b004e4cc6"}, | ||||
|     {file = "pycryptodome-3.11.0-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:014c758af7fa38cab85b357a496b76f4fc9dda1f731eb28358d66fef7ad4a3e1"}, | ||||
|     {file = "pycryptodome-3.11.0-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:a843350d08c3d22f6c09c2f17f020d8dcfa59496165d7425a3fba0045543dda7"}, | ||||
|     {file = "pycryptodome-3.11.0-cp27-cp27m-manylinux2014_aarch64.whl", hash = "sha256:53989477044be41fa4a63da09d5038c2a34b2f4554cfea2e3933b17186ee9e19"}, | ||||
|     {file = "pycryptodome-3.11.0-cp27-cp27m-win32.whl", hash = "sha256:f9bad2220b80b4ed74f089db012ab5ab5419143a33fad6c8aedcc2a9341eac70"}, | ||||
|     {file = "pycryptodome-3.11.0-cp27-cp27m-win_amd64.whl", hash = "sha256:3c7ed5b07274535979c730daf5817db5e983ea80b04c22579eee8da4ca3ae4f8"}, | ||||
|     {file = "pycryptodome-3.11.0-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:8f3a60926be78422e662b0d0b18351b426ce27657101c8a50bad80300de6a701"}, | ||||
|     {file = "pycryptodome-3.11.0-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:fce7e22d96030b35345637c563246c24d4513bd3b413e1c40293114837ab8912"}, | ||||
|     {file = "pycryptodome-3.11.0-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:bc3c61ff92efdcc14af4a7b81da71d849c9acee51d8fd8ac9841a7620140d6c6"}, | ||||
|     {file = "pycryptodome-3.11.0-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:b33c9b3d1327d821e28e9cc3a6512c14f8b17570ddb4cfb9a52247ed0fcc5d8b"}, | ||||
|     {file = "pycryptodome-3.11.0-cp27-cp27mu-manylinux2014_aarch64.whl", hash = "sha256:75e78360d1dd6d02eb288fd8275bb4d147d6e3f5337935c096d11dba1fa84748"}, | ||||
|     {file = "pycryptodome-3.11.0-cp35-abi3-macosx_10_9_x86_64.whl", hash = "sha256:621a90147a5e255fdc2a0fec2d56626b76b5d72ea9e60164c9a5a8976d45b0c9"}, | ||||
|     {file = "pycryptodome-3.11.0-cp35-abi3-manylinux1_i686.whl", hash = "sha256:0ca7a6b4fc1f9fafe990b95c8cda89099797e2cfbf40e55607f2f2f5a3355dcb"}, | ||||
|     {file = "pycryptodome-3.11.0-cp35-abi3-manylinux1_x86_64.whl", hash = "sha256:b59bf823cfafde8ef1105d8984f26d1694dff165adb7198b12e3e068d7999b15"}, | ||||
|     {file = "pycryptodome-3.11.0-cp35-abi3-manylinux2010_i686.whl", hash = "sha256:ce81b9c6aaa0f920e2ab05eb2b9f4ccd102e3016b2f37125593b16a83a4b0cc2"}, | ||||
|     {file = "pycryptodome-3.11.0-cp35-abi3-manylinux2010_x86_64.whl", hash = "sha256:ae29fcd56152f417bfba50a36a56a7a5f9fb74ff80bab98704cac704de6568ab"}, | ||||
|     {file = "pycryptodome-3.11.0-cp35-abi3-manylinux2014_aarch64.whl", hash = "sha256:ae31cb874f6f0cedbed457c6374e7e54d7ed45c1a4e11a65a9c80968da90a650"}, | ||||
|     {file = "pycryptodome-3.11.0-cp35-abi3-win32.whl", hash = "sha256:6db1f9fa1f52226621905f004278ce7bd90c8f5363ffd5d7ab3755363d98549a"}, | ||||
|     {file = "pycryptodome-3.11.0-cp35-abi3-win_amd64.whl", hash = "sha256:d7e5f6f692421e5219aa3b545eb0cffd832cd589a4b9dcd4a5eb4260e2c0d68a"}, | ||||
|     {file = "pycryptodome-3.11.0-pp27-pypy_73-macosx_10_9_x86_64.whl", hash = "sha256:da796e9221dda61a0019d01742337eb8a322de8598b678a4344ca0a436380315"}, | ||||
|     {file = "pycryptodome-3.11.0-pp27-pypy_73-manylinux1_x86_64.whl", hash = "sha256:ed45ef92d21db33685b789de2c015e9d9a18a74760a8df1fc152faee88cdf741"}, | ||||
|     {file = "pycryptodome-3.11.0-pp27-pypy_73-manylinux2010_x86_64.whl", hash = "sha256:4169ed515742425ff21e4bd3fabbb6994ffb64434472fb72230019bdfa36b939"}, | ||||
|     {file = "pycryptodome-3.11.0-pp27-pypy_73-win32.whl", hash = "sha256:f19edd42368e9057c39492947bb99570dc927123e210008f2af7cf9b505c6892"}, | ||||
|     {file = "pycryptodome-3.11.0-pp36-pypy36_pp73-macosx_10_9_x86_64.whl", hash = "sha256:06162fcfed2f9deee8383fd59eaeabc7b7ffc3af50d3fad4000032deb8f700b0"}, | ||||
|     {file = "pycryptodome-3.11.0-pp36-pypy36_pp73-manylinux1_x86_64.whl", hash = "sha256:6eda8a3157c91ba60b26a07bedd6c44ab8bda6cd79b6b5ea9744ba62c39b7b1e"}, | ||||
|     {file = "pycryptodome-3.11.0-pp36-pypy36_pp73-manylinux2010_x86_64.whl", hash = "sha256:7ff701fc283412e651eaab4319b3cd4eaa0827e94569cd37ee9075d5c05fe655"}, | ||||
|     {file = "pycryptodome-3.11.0-pp36-pypy36_pp73-win32.whl", hash = "sha256:2a4bcc8a9977fee0979079cd33a9e9f0d3ddba5660d35ffe874cf84f1dd399d2"}, | ||||
|     {file = "pycryptodome-3.11.0.tar.gz", hash = "sha256:428096bbf7a77e207f418dfd4d7c284df8ade81d2dc80f010e92753a3e406ad0"}, | ||||
| ] | ||||
| pydantic = [ | ||||
|     {file = "pydantic-1.8.2-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:05ddfd37c1720c392f4e0d43c484217b7521558302e7069ce8d318438d297739"}, | ||||
|     {file = "pydantic-1.8.2-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:a7c6002203fe2c5a1b5cbb141bb85060cbff88c2d78eccbc72d97eb7022c43e4"}, | ||||
| @@ -1899,14 +1720,6 @@ python-dotenv = [ | ||||
|     {file = "python-dotenv-0.19.2.tar.gz", hash = "sha256:a5de49a31e953b45ff2d2fd434bbc2670e8db5273606c1e737cc6b93eff3655f"}, | ||||
|     {file = "python_dotenv-0.19.2-py2.py3-none-any.whl", hash = "sha256:32b2bdc1873fd3a3c346da1c6db83d0053c3c62f28f1f38516070c4c8971b1d3"}, | ||||
| ] | ||||
| python-engineio = [ | ||||
|     {file = "python-engineio-3.14.2.tar.gz", hash = "sha256:eab4553f2804c1ce97054c8b22cf0d5a9ab23128075248b97e1a5b2f29553085"}, | ||||
|     {file = "python_engineio-3.14.2-py2.py3-none-any.whl", hash = "sha256:5a9e6086d192463b04a1428ff1f85b6ba631bbb19d453b144ffc04f530542b84"}, | ||||
| ] | ||||
| python-socketio = [ | ||||
|     {file = "python-socketio-4.6.1.tar.gz", hash = "sha256:cd1f5aa492c1eb2be77838e837a495f117e17f686029ebc03d62c09e33f4fa10"}, | ||||
|     {file = "python_socketio-4.6.1-py2.py3-none-any.whl", hash = "sha256:5a21da53fdbdc6bb6c8071f40e13d100e0b279ad997681c2492478e06f370523"}, | ||||
| ] | ||||
| pytz = [ | ||||
|     {file = "pytz-2021.3-py2.py3-none-any.whl", hash = "sha256:3672058bc3453457b622aab7a1c3bfd5ab0bdae451512f6cf25f64ed37f5b87c"}, | ||||
|     {file = "pytz-2021.3.tar.gz", hash = "sha256:acad2d8b20a1af07d4e4c9d2e9285c5ed9104354062f275f3fcd88dcef4f1326"}, | ||||
| @@ -1950,57 +1763,6 @@ quart = [ | ||||
|     {file = "Quart-0.15.1-py3-none-any.whl", hash = "sha256:f35134fb1d81af61624e6d89bca33cd611dcedce2dc4e291f527ab04395f4e1a"}, | ||||
|     {file = "Quart-0.15.1.tar.gz", hash = "sha256:f80c91d1e0588662483e22dd9c368a5778886b62e128c5399d2cc1b1898482cf"}, | ||||
| ] | ||||
| regex = [ | ||||
|     {file = "regex-2021.11.10-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9345b6f7ee578bad8e475129ed40123d265464c4cfead6c261fd60fc9de00bcf"}, | ||||
|     {file = "regex-2021.11.10-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:416c5f1a188c91e3eb41e9c8787288e707f7d2ebe66e0a6563af280d9b68478f"}, | ||||
|     {file = "regex-2021.11.10-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e0538c43565ee6e703d3a7c3bdfe4037a5209250e8502c98f20fea6f5fdf2965"}, | ||||
|     {file = "regex-2021.11.10-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7ee1227cf08b6716c85504aebc49ac827eb88fcc6e51564f010f11a406c0a667"}, | ||||
|     {file = "regex-2021.11.10-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6650f16365f1924d6014d2ea770bde8555b4a39dc9576abb95e3cd1ff0263b36"}, | ||||
|     {file = "regex-2021.11.10-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:30ab804ea73972049b7a2a5c62d97687d69b5a60a67adca07eb73a0ddbc9e29f"}, | ||||
|     {file = "regex-2021.11.10-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:68a067c11463de2a37157930d8b153005085e42bcb7ad9ca562d77ba7d1404e0"}, | ||||
|     {file = "regex-2021.11.10-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:162abfd74e88001d20cb73ceaffbfe601469923e875caf9118333b1a4aaafdc4"}, | ||||
|     {file = "regex-2021.11.10-cp310-cp310-win32.whl", hash = "sha256:98ba568e8ae26beb726aeea2273053c717641933836568c2a0278a84987b2a1a"}, | ||||
|     {file = "regex-2021.11.10-cp310-cp310-win_amd64.whl", hash = "sha256:780b48456a0f0ba4d390e8b5f7c661fdd218934388cde1a974010a965e200e12"}, | ||||
|     {file = "regex-2021.11.10-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:dba70f30fd81f8ce6d32ddeef37d91c8948e5d5a4c63242d16a2b2df8143aafc"}, | ||||
|     {file = "regex-2021.11.10-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e1f54b9b4b6c53369f40028d2dd07a8c374583417ee6ec0ea304e710a20f80a0"}, | ||||
|     {file = "regex-2021.11.10-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fbb9dc00e39f3e6c0ef48edee202f9520dafb233e8b51b06b8428cfcb92abd30"}, | ||||
|     {file = "regex-2021.11.10-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:666abff54e474d28ff42756d94544cdfd42e2ee97065857413b72e8a2d6a6345"}, | ||||
|     {file = "regex-2021.11.10-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5537f71b6d646f7f5f340562ec4c77b6e1c915f8baae822ea0b7e46c1f09b733"}, | ||||
|     {file = "regex-2021.11.10-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ed2e07c6a26ed4bea91b897ee2b0835c21716d9a469a96c3e878dc5f8c55bb23"}, | ||||
|     {file = "regex-2021.11.10-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:ca5f18a75e1256ce07494e245cdb146f5a9267d3c702ebf9b65c7f8bd843431e"}, | ||||
|     {file = "regex-2021.11.10-cp36-cp36m-win32.whl", hash = "sha256:93a5051fcf5fad72de73b96f07d30bc29665697fb8ecdfbc474f3452c78adcf4"}, | ||||
|     {file = "regex-2021.11.10-cp36-cp36m-win_amd64.whl", hash = "sha256:b483c9d00a565633c87abd0aaf27eb5016de23fed952e054ecc19ce32f6a9e7e"}, | ||||
|     {file = "regex-2021.11.10-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:fff55f3ce50a3ff63ec8e2a8d3dd924f1941b250b0aac3d3d42b687eeff07a8e"}, | ||||
|     {file = "regex-2021.11.10-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e32d2a2b02ccbef10145df9135751abea1f9f076e67a4e261b05f24b94219e36"}, | ||||
|     {file = "regex-2021.11.10-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:53db2c6be8a2710b359bfd3d3aa17ba38f8aa72a82309a12ae99d3c0c3dcd74d"}, | ||||
|     {file = "regex-2021.11.10-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2207ae4f64ad3af399e2d30dde66f0b36ae5c3129b52885f1bffc2f05ec505c8"}, | ||||
|     {file = "regex-2021.11.10-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d5ca078bb666c4a9d1287a379fe617a6dccd18c3e8a7e6c7e1eb8974330c626a"}, | ||||
|     {file = "regex-2021.11.10-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dd33eb9bdcfbabab3459c9ee651d94c842bc8a05fabc95edf4ee0c15a072495e"}, | ||||
|     {file = "regex-2021.11.10-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:05b7d6d7e64efe309972adab77fc2af8907bb93217ec60aa9fe12a0dad35874f"}, | ||||
|     {file = "regex-2021.11.10-cp37-cp37m-win32.whl", hash = "sha256:e71255ba42567d34a13c03968736c5d39bb4a97ce98188fafb27ce981115beec"}, | ||||
|     {file = "regex-2021.11.10-cp37-cp37m-win_amd64.whl", hash = "sha256:07856afef5ffcc052e7eccf3213317fbb94e4a5cd8177a2caa69c980657b3cb4"}, | ||||
|     {file = "regex-2021.11.10-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:ba05430e819e58544e840a68b03b28b6d328aff2e41579037e8bab7653b37d83"}, | ||||
|     {file = "regex-2021.11.10-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:7f301b11b9d214f83ddaf689181051e7f48905568b0c7017c04c06dfd065e244"}, | ||||
|     {file = "regex-2021.11.10-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4aaa4e0705ef2b73dd8e36eeb4c868f80f8393f5f4d855e94025ce7ad8525f50"}, | ||||
|     {file = "regex-2021.11.10-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:788aef3549f1924d5c38263104dae7395bf020a42776d5ec5ea2b0d3d85d6646"}, | ||||
|     {file = "regex-2021.11.10-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f8af619e3be812a2059b212064ea7a640aff0568d972cd1b9e920837469eb3cb"}, | ||||
|     {file = "regex-2021.11.10-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:85bfa6a5413be0ee6c5c4a663668a2cad2cbecdee367630d097d7823041bdeec"}, | ||||
|     {file = "regex-2021.11.10-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f23222527b307970e383433daec128d769ff778d9b29343fb3496472dc20dabe"}, | ||||
|     {file = "regex-2021.11.10-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:da1a90c1ddb7531b1d5ff1e171b4ee61f6345119be7351104b67ff413843fe94"}, | ||||
|     {file = "regex-2021.11.10-cp38-cp38-win32.whl", hash = "sha256:0617383e2fe465732af4509e61648b77cbe3aee68b6ac8c0b6fe934db90be5cc"}, | ||||
|     {file = "regex-2021.11.10-cp38-cp38-win_amd64.whl", hash = "sha256:a3feefd5e95871872673b08636f96b61ebef62971eab044f5124fb4dea39919d"}, | ||||
|     {file = "regex-2021.11.10-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f7f325be2804246a75a4f45c72d4ce80d2443ab815063cdf70ee8fb2ca59ee1b"}, | ||||
|     {file = "regex-2021.11.10-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:537ca6a3586931b16a85ac38c08cc48f10fc870a5b25e51794c74df843e9966d"}, | ||||
|     {file = "regex-2021.11.10-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eef2afb0fd1747f33f1ee3e209bce1ed582d1896b240ccc5e2697e3275f037c7"}, | ||||
|     {file = "regex-2021.11.10-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:432bd15d40ed835a51617521d60d0125867f7b88acf653e4ed994a1f8e4995dc"}, | ||||
|     {file = "regex-2021.11.10-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b43c2b8a330a490daaef5a47ab114935002b13b3f9dc5da56d5322ff218eeadb"}, | ||||
|     {file = "regex-2021.11.10-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:962b9a917dd7ceacbe5cd424556914cb0d636001e393b43dc886ba31d2a1e449"}, | ||||
|     {file = "regex-2021.11.10-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fa8c626d6441e2d04b6ee703ef2d1e17608ad44c7cb75258c09dd42bacdfc64b"}, | ||||
|     {file = "regex-2021.11.10-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:3c5fb32cc6077abad3bbf0323067636d93307c9fa93e072771cf9a64d1c0f3ef"}, | ||||
|     {file = "regex-2021.11.10-cp39-cp39-win32.whl", hash = "sha256:3b5df18db1fccd66de15aa59c41e4f853b5df7550723d26aa6cb7f40e5d9da5a"}, | ||||
|     {file = "regex-2021.11.10-cp39-cp39-win_amd64.whl", hash = "sha256:83ee89483672b11f8952b158640d0c0ff02dc43d9cb1b70c1564b49abe92ce29"}, | ||||
|     {file = "regex-2021.11.10.tar.gz", hash = "sha256:f341ee2df0999bfdf7a95e448075effe0db212a59387de1a70690e4acb03d4c6"}, | ||||
| ] | ||||
| requests = [ | ||||
|     {file = "requests-2.26.0-py2.py3-none-any.whl", hash = "sha256:6c1246513ecd5ecd4528a0906f910e8f0f9c6b8ec72030dc9fd154dc1a6efd24"}, | ||||
|     {file = "requests-2.26.0.tar.gz", hash = "sha256:b8aa58f8cf793ffd8782d3d8cb19e66ef36f7aba4353eec859e74678b01b07a7"}, | ||||
| @@ -2009,10 +1771,6 @@ rfc3986 = [ | ||||
|     {file = "rfc3986-1.5.0-py2.py3-none-any.whl", hash = "sha256:a86d6e1f5b1dc238b218b012df0aa79409667bb209e58da56d0b94704e712a97"}, | ||||
|     {file = "rfc3986-1.5.0.tar.gz", hash = "sha256:270aaf10d87d0d4e095063c65bf3ddbc6ee3d0b226328ce21e036f946e421835"}, | ||||
| ] | ||||
| six = [ | ||||
|     {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, | ||||
|     {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, | ||||
| ] | ||||
| sniffio = [ | ||||
|     {file = "sniffio-1.2.0-py3-none-any.whl", hash = "sha256:471b71698eac1c2112a40ce2752bb2f4a4814c22a54a3eed3676bc0f5ca9f663"}, | ||||
|     {file = "sniffio-1.2.0.tar.gz", hash = "sha256:c4666eecec1d3f50960c6bdf61ab7bc350648da6c126e3cf6898d8cd4ddcd3de"}, | ||||
| @@ -2022,8 +1780,8 @@ snowballstemmer = [ | ||||
|     {file = "snowballstemmer-2.2.0.tar.gz", hash = "sha256:09b16deb8547d3412ad7b590689584cd0fe25ec8db3be37788be3810cbf19cb1"}, | ||||
| ] | ||||
| sphinx = [ | ||||
|     {file = "Sphinx-4.3.0-py3-none-any.whl", hash = "sha256:7e2b30da5f39170efcd95c6270f07669d623c276521fee27ad6c380f49d2bf5b"}, | ||||
|     {file = "Sphinx-4.3.0.tar.gz", hash = "sha256:6d051ab6e0d06cba786c4656b0fe67ba259fe058410f49e95bee6e49c4052cbf"}, | ||||
|     {file = "Sphinx-4.3.1-py3-none-any.whl", hash = "sha256:048dac56039a5713f47a554589dc98a442b39226a2b9ed7f82797fcb2fe9253f"}, | ||||
|     {file = "Sphinx-4.3.1.tar.gz", hash = "sha256:32a5b3e9a1b176cc25ed048557d4d3d01af635e6b76c5bc7a43b0a34447fbd45"}, | ||||
| ] | ||||
| sphinx-markdown-builder = [] | ||||
| sphinxcontrib-applehelp = [ | ||||
| @@ -2067,29 +1825,29 @@ tomlkit = [ | ||||
|     {file = "tomlkit-0.7.2.tar.gz", hash = "sha256:d7a454f319a7e9bd2e249f239168729327e4dd2d27b17dc68be264ad1ce36754"}, | ||||
| ] | ||||
| typed-ast = [ | ||||
|     {file = "typed_ast-1.5.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:7b310a207ee9fde3f46ba327989e6cba4195bc0c8c70a158456e7b10233e6bed"}, | ||||
|     {file = "typed_ast-1.5.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:52ca2b2b524d770bed7a393371a38e91943f9160a190141e0df911586066ecda"}, | ||||
|     {file = "typed_ast-1.5.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:14fed8820114a389a2b7e91624db5f85f3f6682fda09fe0268a59aabd28fe5f5"}, | ||||
|     {file = "typed_ast-1.5.0-cp310-cp310-win_amd64.whl", hash = "sha256:65c81abbabda7d760df7304d843cc9dbe7ef5d485504ca59a46ae2d1731d2428"}, | ||||
|     {file = "typed_ast-1.5.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:37ba2ab65a0028b1a4f2b61a8fe77f12d242731977d274a03d68ebb751271508"}, | ||||
|     {file = "typed_ast-1.5.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:49af5b8f6f03ed1eb89ee06c1d7c2e7c8e743d720c3746a5857609a1abc94c94"}, | ||||
|     {file = "typed_ast-1.5.0-cp36-cp36m-win_amd64.whl", hash = "sha256:e4374a76e61399a173137e7984a1d7e356038cf844f24fd8aea46c8029a2f712"}, | ||||
|     {file = "typed_ast-1.5.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:ea517c2bb11c5e4ba7a83a91482a2837041181d57d3ed0749a6c382a2b6b7086"}, | ||||
|     {file = "typed_ast-1.5.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:51040bf45aacefa44fa67fb9ebcd1f2bec73182b99a532c2394eea7dabd18e24"}, | ||||
|     {file = "typed_ast-1.5.0-cp37-cp37m-win_amd64.whl", hash = "sha256:806e0c7346b9b4af8c62d9a29053f484599921a4448c37fbbcbbf15c25138570"}, | ||||
|     {file = "typed_ast-1.5.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:a67fd5914603e2165e075f1b12f5a8356bfb9557e8bfb74511108cfbab0f51ed"}, | ||||
|     {file = "typed_ast-1.5.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:224afecb8b39739f5c9562794a7c98325cb9d972712e1a98b6989a4720219541"}, | ||||
|     {file = "typed_ast-1.5.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:155b74b078be842d2eb630dd30a280025eca0a5383c7d45853c27afee65f278f"}, | ||||
|     {file = "typed_ast-1.5.0-cp38-cp38-win_amd64.whl", hash = "sha256:361b9e5d27bd8e3ccb6ea6ad6c4f3c0be322a1a0f8177db6d56264fa0ae40410"}, | ||||
|     {file = "typed_ast-1.5.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:618912cbc7e17b4aeba86ffe071698c6e2d292acbd6d1d5ec1ee724b8c4ae450"}, | ||||
|     {file = "typed_ast-1.5.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:7e6731044f748340ef68dcadb5172a4b1f40847a2983fe3983b2a66445fbc8e6"}, | ||||
|     {file = "typed_ast-1.5.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:e8a9b9c87801cecaad3b4c2b8876387115d1a14caa602c1618cedbb0cb2a14e6"}, | ||||
|     {file = "typed_ast-1.5.0-cp39-cp39-win_amd64.whl", hash = "sha256:ec184dfb5d3d11e82841dbb973e7092b75f306b625fad7b2e665b64c5d60ab3f"}, | ||||
|     {file = "typed_ast-1.5.0.tar.gz", hash = "sha256:ff4ad88271aa7a55f19b6a161ed44e088c393846d954729549e3cde8257747bb"}, | ||||
|     {file = "typed_ast-1.5.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5d8314c92414ce7481eee7ad42b353943679cf6f30237b5ecbf7d835519e1212"}, | ||||
|     {file = "typed_ast-1.5.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:b53ae5de5500529c76225d18eeb060efbcec90ad5e030713fe8dab0fb4531631"}, | ||||
|     {file = "typed_ast-1.5.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:24058827d8f5d633f97223f5148a7d22628099a3d2efe06654ce872f46f07cdb"}, | ||||
|     {file = "typed_ast-1.5.1-cp310-cp310-win_amd64.whl", hash = "sha256:a6d495c1ef572519a7bac9534dbf6d94c40e5b6a608ef41136133377bba4aa08"}, | ||||
|     {file = "typed_ast-1.5.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:de4ecae89c7d8b56169473e08f6bfd2df7f95015591f43126e4ea7865928677e"}, | ||||
|     {file = "typed_ast-1.5.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:256115a5bc7ea9e665c6314ed6671ee2c08ca380f9d5f130bd4d2c1f5848d695"}, | ||||
|     {file = "typed_ast-1.5.1-cp36-cp36m-win_amd64.whl", hash = "sha256:7c42707ab981b6cf4b73490c16e9d17fcd5227039720ca14abe415d39a173a30"}, | ||||
|     {file = "typed_ast-1.5.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:71dcda943a471d826ea930dd449ac7e76db7be778fcd722deb63642bab32ea3f"}, | ||||
|     {file = "typed_ast-1.5.1-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:4f30a2bcd8e68adbb791ce1567fdb897357506f7ea6716f6bbdd3053ac4d9471"}, | ||||
|     {file = "typed_ast-1.5.1-cp37-cp37m-win_amd64.whl", hash = "sha256:ca9e8300d8ba0b66d140820cf463438c8e7b4cdc6fd710c059bfcfb1531d03fb"}, | ||||
|     {file = "typed_ast-1.5.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:9caaf2b440efb39ecbc45e2fabde809cbe56272719131a6318fd9bf08b58e2cb"}, | ||||
|     {file = "typed_ast-1.5.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:c9bcad65d66d594bffab8575f39420fe0ee96f66e23c4d927ebb4e24354ec1af"}, | ||||
|     {file = "typed_ast-1.5.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:591bc04e507595887160ed7aa8d6785867fb86c5793911be79ccede61ae96f4d"}, | ||||
|     {file = "typed_ast-1.5.1-cp38-cp38-win_amd64.whl", hash = "sha256:a80d84f535642420dd17e16ae25bb46c7f4c16ee231105e7f3eb43976a89670a"}, | ||||
|     {file = "typed_ast-1.5.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:38cf5c642fa808300bae1281460d4f9b7617cf864d4e383054a5ef336e344d32"}, | ||||
|     {file = "typed_ast-1.5.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:5b6ab14c56bc9c7e3c30228a0a0b54b915b1579613f6e463ba6f4eb1382e7fd4"}, | ||||
|     {file = "typed_ast-1.5.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:a2b8d7007f6280e36fa42652df47087ac7b0a7d7f09f9468f07792ba646aac2d"}, | ||||
|     {file = "typed_ast-1.5.1-cp39-cp39-win_amd64.whl", hash = "sha256:b6d17f37f6edd879141e64a5db17b67488cfeffeedad8c5cec0392305e9bc775"}, | ||||
|     {file = "typed_ast-1.5.1.tar.gz", hash = "sha256:484137cab8ecf47e137260daa20bafbba5f4e3ec7fda1c1e69ab299b75fa81c5"}, | ||||
| ] | ||||
| typing-extensions = [ | ||||
|     {file = "typing_extensions-4.0.0-py3-none-any.whl", hash = "sha256:829704698b22e13ec9eaf959122315eabb370b0884400e9818334d8b677023d9"}, | ||||
|     {file = "typing_extensions-4.0.0.tar.gz", hash = "sha256:2cdf80e4e04866a9b3689a51869016d36db0814d84b8d8a568d22781d45d27ed"}, | ||||
|     {file = "typing_extensions-4.0.1-py3-none-any.whl", hash = "sha256:7f001e5ac290a0c0401508864c7ec868be4e701886d5b573a9528ed3973d9d3b"}, | ||||
|     {file = "typing_extensions-4.0.1.tar.gz", hash = "sha256:4ca091dea149f945ec56afb48dae714f21e8692ef22a395223bcd328961b6a0e"}, | ||||
| ] | ||||
| unify = [ | ||||
|     {file = "unify-0.5.tar.gz", hash = "sha256:8ddce812b2457212b7598fe574c9e6eb3ad69710f445391338270c7f8a71723c"}, | ||||
| @@ -2182,8 +1940,8 @@ werkzeug = [ | ||||
|     {file = "Werkzeug-2.0.2.tar.gz", hash = "sha256:aa2bb6fc8dee8d6c504c0ac1e7f5f7dc5810a9903e793b6f715a9f015bdadb9a"}, | ||||
| ] | ||||
| win32-setctime = [ | ||||
|     {file = "win32_setctime-1.0.3-py3-none-any.whl", hash = "sha256:dc925662de0a6eb987f0b01f599c01a8236cb8c62831c22d9cada09ad958243e"}, | ||||
|     {file = "win32_setctime-1.0.3.tar.gz", hash = "sha256:4e88556c32fdf47f64165a2180ba4552f8bb32c1103a2fafd05723a0bd42bd4b"}, | ||||
|     {file = "win32_setctime-1.0.4-py3-none-any.whl", hash = "sha256:7964234073ad9bc7a689ef2ebe6ce931976b644fe73fd50cf7729c996b7d8385"}, | ||||
|     {file = "win32_setctime-1.0.4.tar.gz", hash = "sha256:2b72b798fdc1d909fb3cc0d25e0be52a42f4848857e3588dd3947c6a18b42609"}, | ||||
| ] | ||||
| wsproto = [ | ||||
|     {file = "wsproto-1.0.0-py3-none-any.whl", hash = "sha256:d8345d1808dd599b5ffb352c25a367adb6157e664e140dbecba3f9bc007edb9f"}, | ||||
|   | ||||
| @@ -39,10 +39,6 @@ aiohttp = { version = "^3.7.4", extras = ["speedups"], optional = true } | ||||
| sphinx = "^4.1.1" | ||||
| isort = "^5.10.1" | ||||
| black = "^21.11b1" | ||||
| nonebot-plugin-test = "^0.3.0" | ||||
| nonebot-adapter-ding = { path = "./packages/nonebot-adapter-ding", develop = true } | ||||
| nonebot-adapter-mirai = { path = "./packages/nonebot-adapter-mirai", develop = true } | ||||
| nonebot-adapter-feishu = { path = "./packages/nonebot-adapter-feishu", develop = true } | ||||
| sphinx-markdown-builder = { git = "https://github.com/nonebot/sphinx-markdown-builder.git" } | ||||
|  | ||||
| [tool.poetry.extras] | ||||
|   | ||||
| @@ -1,4 +0,0 @@ | ||||
| ENVIRONMENT=dev | ||||
| LOG_LEVEL=25 | ||||
| CUSTOM_CONFIG=common | ||||
| # FASTAPI_RELOAD_DIRS=["test_plugins"] | ||||
| @@ -1,24 +0,0 @@ | ||||
| DRIVER=nonebot.drivers.fastapi:FullDriver | ||||
| HOST=0.0.0.0 | ||||
| PORT=2333 | ||||
| DEBUG=true | ||||
| LOG_LEVEL=DEBUG | ||||
|  | ||||
| SUPERUSERS=["123123123"] | ||||
| NICKNAME=["bot"] | ||||
|  | ||||
| COMMAND_START=["", "/", "#"] | ||||
| COMMAND_SEP=["/", "."] | ||||
|  | ||||
| CUSTOM_CONFIG1=config in env | ||||
| CUSTOM_CONFIG3= | ||||
|  | ||||
| # CQHTTP_WS_URLS={"123123123": "ws://127.0.0.1:6700/"} | ||||
|  | ||||
| MIRAI_AUTH_KEY=12345678 | ||||
| MIRAI_HOST=127.0.0.1 | ||||
| MIRAI_PORT=8080 | ||||
|  | ||||
| APP_ID=111111111111 | ||||
| APP_SECRET=222222222222222222 | ||||
| VERIFICATION_TOKEN=3333333333333333333333333333 | ||||
							
								
								
									
										37
									
								
								tests/bot.py
									
									
									
									
									
								
							
							
						
						
									
										37
									
								
								tests/bot.py
									
									
									
									
									
								
							| @@ -1,37 +0,0 @@ | ||||
| import os | ||||
| import sys | ||||
|  | ||||
| sys.path.insert(0, os.path.abspath("..")) | ||||
|  | ||||
| import nonebot | ||||
| from nonebot.log import logger, default_format | ||||
| from nonebot.adapters.ding import Bot as DingBot | ||||
| from nonebot.adapters.mirai import Bot as MiraiBot | ||||
| from nonebot.adapters.feishu import Bot as FeishuBot | ||||
|  | ||||
| # test custom log | ||||
| logger.add( | ||||
|     "error.log", rotation="00:00", diagnose=False, level="ERROR", format=default_format | ||||
| ) | ||||
|  | ||||
| nonebot.init(custom_config2="config on init") | ||||
| app = nonebot.get_asgi() | ||||
| driver = nonebot.get_driver() | ||||
| driver.register_adapter("ding", DingBot) | ||||
| driver.register_adapter("mirai", MiraiBot) | ||||
| driver.register_adapter("feishu", FeishuBot) | ||||
|  | ||||
| # load builtin plugin | ||||
| nonebot.load_builtin_plugins() | ||||
|  | ||||
| # load all plugins | ||||
| nonebot.load_from_toml("plugins.toml") | ||||
|  | ||||
| # modify some config / config depends on loaded configs | ||||
| config = driver.config | ||||
| config.custom_config3 = config.custom_config1 | ||||
| config.custom_config4 = "New custom config" | ||||
|  | ||||
| if __name__ == "__main__": | ||||
|     nonebot.run(app="__mp_main__:app") | ||||
|     # nonebot.run() | ||||
| @@ -1,3 +0,0 @@ | ||||
| [tool.nonebot] | ||||
| plugins = ["nonebot_plugin_test"] | ||||
| plugin_dirs = ["test_plugins"] | ||||
| @@ -1,6 +0,0 @@ | ||||
| from nonebot.adapters import Bot | ||||
|  | ||||
|  | ||||
| @Bot.on_calling_api | ||||
| async def call(bot: Bot, api: str, data: dict): | ||||
|     print(type(bot), api, data) | ||||
| @@ -1,32 +0,0 @@ | ||||
| import asyncio | ||||
|  | ||||
| from nonebot import on_message | ||||
| from nonebot.typing import T_State | ||||
| from nonebot.permission import USER | ||||
| from nonebot.adapters import Bot, Event | ||||
|  | ||||
| a = on_message(priority=0, permission=USER("123123123"), temp=True) | ||||
|  | ||||
|  | ||||
| @a.handle() | ||||
| async def test_a(bot: Bot, event: Event, state: T_State): | ||||
|     print("======== A Received ========") | ||||
|     print("======== A Running Completed ========") | ||||
|  | ||||
|  | ||||
| b = on_message(priority=0, permission=USER("123456789"), temp=True) | ||||
|  | ||||
|  | ||||
| @b.handle() | ||||
| async def test_b(bot: Bot, event: Event, state: T_State): | ||||
|     print("======== B Received ========") | ||||
|     await asyncio.sleep(10) | ||||
|     print("======== B Running Completed ========") | ||||
|  | ||||
|  | ||||
| c = on_message(priority=0, permission=USER("1111111111")) | ||||
|  | ||||
|  | ||||
| @c.handle() | ||||
| async def test_c(bot: Bot, event: Event, state: T_State): | ||||
|     print("======== C Received ========") | ||||
| @@ -1,28 +0,0 @@ | ||||
| from nonebot.log import logger | ||||
| from nonebot.dependencies import Depends | ||||
| from nonebot import on_command, on_message | ||||
|  | ||||
| test = on_command("123") | ||||
|  | ||||
|  | ||||
| def depend(state: dict): | ||||
|     print("==== depends running =====") | ||||
|     return state | ||||
|  | ||||
|  | ||||
| @test.got("a", prompt="a") | ||||
| @test.got("b", prompt="b") | ||||
| @test.receive() | ||||
| @test.got("c", prompt="c") | ||||
| async def _(x: dict = Depends(depend)): | ||||
|     logger.info(f"=======, {x}") | ||||
|  | ||||
|  | ||||
| test_cache1 = on_message() | ||||
| test_cache2 = on_message() | ||||
|  | ||||
|  | ||||
| @test_cache1.handle() | ||||
| @test_cache2.handle() | ||||
| async def _(x: dict = Depends(depend)): | ||||
|     logger.info(f"======= test, {x}") | ||||
| @@ -1,233 +0,0 @@ | ||||
| from nonebot.rule import to_me | ||||
| from nonebot.plugin import on_command | ||||
| from nonebot.adapters.ding import Bot as DingBot | ||||
| from nonebot.adapters.ding import MessageEvent, MessageSegment | ||||
| from nonebot.adapters.ding.event import GroupMessageEvent, PrivateMessageEvent | ||||
|  | ||||
| helper = on_command("ding_helper", to_me()) | ||||
|  | ||||
|  | ||||
| @helper.handle() | ||||
| async def ding_helper(bot: DingBot, event: MessageEvent): | ||||
|     message = MessageSegment.markdown( | ||||
|         "Hello, This is NoneBot", | ||||
|         """帮助信息如下:\n | ||||
| [ding_helper](dtmd://dingtalkclient/sendMessage?content=ding_helper) 查看帮助\n | ||||
| [markdown](dtmd://dingtalkclient/sendMessage?content=markdown) 发送 markdown\n | ||||
| [actionCardSingleBtn](dtmd://dingtalkclient/sendMessage?content=actionCardSingleBtn)\n | ||||
| [actionCard](dtmd://dingtalkclient/sendMessage?content=actionCard)\n | ||||
| [feedCard](dtmd://dingtalkclient/sendMessage?content=feedCard)\n | ||||
| [atme](dtmd://dingtalkclient/sendMessage?content=atme)\n | ||||
| [image](dtmd://dingtalkclient/sendMessage?content=image)\n | ||||
| [t](dtmd://dingtalkclient/sendMessage?content=t)\n | ||||
| [code](dtmd://dingtalkclient/sendMessage?content=code) 发送代码\n | ||||
| [test_message](dtmd://dingtalkclient/sendMessage?content=test_message)\n | ||||
| [hello](dtmd://dingtalkclient/sendMessage?content=hello)\n | ||||
| [webhook](dtmd://dingtalkclient/sendMessage?content=webhook)""", | ||||
|     ) | ||||
|     await markdown.finish(message) | ||||
|  | ||||
|  | ||||
| markdown = on_command("markdown", to_me()) | ||||
|  | ||||
|  | ||||
| @markdown.handle() | ||||
| async def markdown_handler(bot: DingBot): | ||||
|     message = MessageSegment.markdown( | ||||
|         "Hello, This is NoneBot", | ||||
|         "#### NoneBot  \n> Nonebot 是一款高性能的 Python 机器人框架\n> \n> [GitHub 仓库地址](https://github.com/nonebot/nonebot2) \n", | ||||
|     ) | ||||
|     await markdown.finish(message) | ||||
|  | ||||
|  | ||||
| actionCardSingleBtn = on_command("actionCardSingleBtn", to_me()) | ||||
|  | ||||
|  | ||||
| @actionCardSingleBtn.handle() | ||||
| async def actionCardSingleBtn_handler(bot: DingBot): | ||||
|     message = MessageSegment.actionCardSingleBtn( | ||||
|         title="打造一间咖啡厅", | ||||
|         text=" \n #### 乔布斯 20 年前想打造的苹果咖啡厅 \n\n Apple Store 的设计正从原来满满的科技感走向生活化,而其生活化的走向其实可以追溯到 20 年前苹果一个建立咖啡馆的计划", | ||||
|         singleTitle="阅读全文", | ||||
|         singleURL="https://www.dingtalk.com/", | ||||
|     ) | ||||
|     await actionCardSingleBtn.finish(message) | ||||
|  | ||||
|  | ||||
| actionCard = on_command("actionCard", to_me()) | ||||
|  | ||||
|  | ||||
| @actionCard.handle() | ||||
| async def actionCard_handler(bot: DingBot): | ||||
|     message = MessageSegment.raw( | ||||
|         { | ||||
|             "msgtype": "actionCard", | ||||
|             "actionCard": { | ||||
|                 "title": "乔布斯 20 年前想打造一间苹果咖啡厅,而它正是 Apple Store 的前身", | ||||
|                 "text": " \n\n #### 乔布斯 20 年前想打造的苹果咖啡厅 \n\n Apple Store 的设计正从原来满满的科技感走向生活化,而其生活化的走向其实可以追溯到 20 年前苹果一个建立咖啡馆的计划", | ||||
|                 "hideAvatar": "0", | ||||
|                 "btnOrientation": "0", | ||||
|                 "btns": [ | ||||
|                     {"title": "内容不错", "actionURL": "https://www.dingtalk.com/"}, | ||||
|                     {"title": "不感兴趣", "actionURL": "https://www.dingtalk.com/"}, | ||||
|                 ], | ||||
|             }, | ||||
|         } | ||||
|     ) | ||||
|     await actionCard.finish(message, at_sender=True) | ||||
|  | ||||
|  | ||||
| feedCard = on_command("feedCard", to_me()) | ||||
|  | ||||
|  | ||||
| @feedCard.handle() | ||||
| async def feedCard_handler(bot: DingBot): | ||||
|     message = MessageSegment.raw( | ||||
|         { | ||||
|             "msgtype": "feedCard", | ||||
|             "feedCard": { | ||||
|                 "links": [ | ||||
|                     { | ||||
|                         "title": "时代的火车向前开1", | ||||
|                         "messageURL": "https://www.dingtalk.com/", | ||||
|                         "picURL": "https://img.alicdn.com/tfs/TB1NwmBEL9TBuNjy1zbXXXpepXa-2400-1218.png", | ||||
|                     }, | ||||
|                     { | ||||
|                         "title": "时代的火车向前开2", | ||||
|                         "messageURL": "https://www.dingtalk.com/", | ||||
|                         "picURL": "https://img.alicdn.com/tfs/TB1NwmBEL9TBuNjy1zbXXXpepXa-2400-1218.png", | ||||
|                     }, | ||||
|                 ] | ||||
|             }, | ||||
|         } | ||||
|     ) | ||||
|     await feedCard.finish(message) | ||||
|  | ||||
|  | ||||
| atme = on_command("atme", to_me()) | ||||
|  | ||||
|  | ||||
| @atme.handle() | ||||
| async def atme_handler(bot: DingBot, event: MessageEvent): | ||||
|     message = f"@{event.senderId} manually at you" + MessageSegment.atDingtalkIds( | ||||
|         event.senderId | ||||
|     ) | ||||
|     await atme.send("matcher send auto at you", at_sender=True) | ||||
|     await bot.send(event, "bot send auto at you", at_sender=True) | ||||
|     await atme.finish(message) | ||||
|  | ||||
|  | ||||
| image = on_command("image", to_me()) | ||||
|  | ||||
|  | ||||
| @image.handle() | ||||
| async def image_handler(bot: DingBot, event: MessageEvent): | ||||
|     message = MessageSegment.image( | ||||
|         "https://static-aliyun-doc.oss-accelerate.aliyuncs.com/assets/img/zh-CN/0634199951/p158167.png" | ||||
|     ) | ||||
|     await image.finish(message) | ||||
|  | ||||
|  | ||||
| textAdd = on_command("t", to_me()) | ||||
|  | ||||
|  | ||||
| @textAdd.handle() | ||||
| async def textAdd_handler(bot: DingBot, event: MessageEvent): | ||||
|     message = "第一段消息\n" + MessageSegment.text("asdawefaefa\n") | ||||
|     await textAdd.send(message) | ||||
|  | ||||
|     message = message + MessageSegment.text("第二段消息\n") | ||||
|     await textAdd.send(message) | ||||
|  | ||||
|     message = ( | ||||
|         message + MessageSegment.text("\n第三段消息\n") + "adfkasfkhsdkfahskdjasdashdkjasdf" | ||||
|     ) | ||||
|     message = message + MessageSegment.extension( | ||||
|         {"text_type": "code_snippet", "code_language": "C#"} | ||||
|     ) | ||||
|     await textAdd.send(message) | ||||
|  | ||||
|  | ||||
| code = on_command("code", to_me()) | ||||
|  | ||||
|  | ||||
| @code.handle() | ||||
| async def code_handler(bot: DingBot, event: MessageEvent): | ||||
|     raw = MessageSegment.code("Python", 'print("hello world")') | ||||
|     await code.send(raw) | ||||
|     message = MessageSegment.text( | ||||
|         """using System; | ||||
|  | ||||
| namespace HelloWorld | ||||
| { | ||||
|   class Program | ||||
|   { | ||||
|     static void Main(string[] args) | ||||
|     { | ||||
|       Console.WriteLine("Hello World!"); | ||||
|     } | ||||
|   } | ||||
| }""" | ||||
|     ) | ||||
|     message += MessageSegment.extension( | ||||
|         {"text_type": "code_snippet", "code_language": "C#"} | ||||
|     ) | ||||
|     await code.finish(message) | ||||
|  | ||||
|  | ||||
| test_message = on_command("test_message", to_me()) | ||||
|  | ||||
|  | ||||
| @test_message.handle() | ||||
| async def test_message_handler1(bot: DingBot, event: PrivateMessageEvent): | ||||
|     await test_message.finish("PrivateMessageEvent") | ||||
|  | ||||
|  | ||||
| @test_message.handle() | ||||
| async def test_message_handler2(bot: DingBot, event: GroupMessageEvent): | ||||
|     await test_message.finish("GroupMessageEvent") | ||||
|  | ||||
|  | ||||
| hello = on_command("hello", to_me()) | ||||
|  | ||||
|  | ||||
| @hello.handle() | ||||
| async def hello_handler(bot: DingBot, event: MessageEvent): | ||||
|     message = MessageSegment.raw( | ||||
|         { | ||||
|             "msgtype": "text", | ||||
|             "text": {"content": "hello "}, | ||||
|         } | ||||
|     ) | ||||
|     message += MessageSegment.atDingtalkIds(event.senderId) | ||||
|     await hello.send(message) | ||||
|  | ||||
|     message = MessageSegment.text(f"@{event.senderId},你好") | ||||
|     message += MessageSegment.atDingtalkIds(event.senderId) | ||||
|     await hello.finish(message) | ||||
|  | ||||
|  | ||||
| hello = on_command("webhook", to_me()) | ||||
|  | ||||
|  | ||||
| @hello.handle() | ||||
| async def webhook_handler(bot: DingBot, event: MessageEvent): | ||||
|     print(event) | ||||
|     message = MessageSegment.raw( | ||||
|         { | ||||
|             "msgtype": "text", | ||||
|             "text": {"content": "hello from webhook,一定要注意安全方式的鉴权哦,否则可能发送失败的"}, | ||||
|         } | ||||
|     ) | ||||
|     message += MessageSegment.atDingtalkIds(event.senderId) | ||||
|     await hello.send( | ||||
|         message, | ||||
|         webhook="https://oapi.dingtalk.com/robot/send?access_token=XXXXXXXXXXXXXX", | ||||
|         secret="SECXXXXXXXXXXXXXXXXXXXXXXXXX", | ||||
|     ) | ||||
|  | ||||
|     message = MessageSegment.text("TEST 123123  S") | ||||
|     await hello.send( | ||||
|         message, | ||||
|         webhook="https://oapi.dingtalk.com/robot/send?access_token=XXXXXXXXXXXXXX", | ||||
|     ) | ||||
| @@ -1,15 +0,0 @@ | ||||
| import nonebot | ||||
|  | ||||
| export = nonebot.export() | ||||
| export.foo = "bar" | ||||
| export["bar"] = "foo" | ||||
|  | ||||
|  | ||||
| @export | ||||
| def a(): | ||||
|     pass | ||||
|  | ||||
|  | ||||
| @export.sub | ||||
| def b(): | ||||
|     pass | ||||
| @@ -1,12 +0,0 @@ | ||||
| from nonebot.typing import T_State | ||||
| from nonebot.plugin import on_command | ||||
| from nonebot.adapters.feishu import MessageEvent | ||||
| from nonebot.adapters.feishu import Bot as FeishuBot | ||||
|  | ||||
| helper = on_command("say") | ||||
|  | ||||
|  | ||||
| @helper.handle() | ||||
| async def feishu_helper(bot: FeishuBot, event: MessageEvent, state: T_State): | ||||
|     message = event.get_message() | ||||
|     await helper.finish(message, at_sender=True) | ||||
| @@ -1,4 +0,0 @@ | ||||
| import nonebot | ||||
| from .test_export import export | ||||
|  | ||||
| print(export, nonebot.require("test_export")) | ||||
| @@ -1,7 +0,0 @@ | ||||
| from nonebot.rule import to_me | ||||
| from nonebot import CommandGroup, MatcherGroup | ||||
|  | ||||
| cmd = CommandGroup("test", rule=to_me()) | ||||
| match = MatcherGroup(priority=2) | ||||
|  | ||||
| from . import commands | ||||
| @@ -1,9 +0,0 @@ | ||||
| from . import cmd | ||||
| from nonebot.adapters import Bot, Event | ||||
|  | ||||
| test_1 = cmd.command("1", aliases={"test"}) | ||||
|  | ||||
|  | ||||
| @test_1.handle() | ||||
| async def test1(bot: Bot, event: Event): | ||||
|     await test_1.finish(event.get_message()) | ||||
| @@ -1,20 +0,0 @@ | ||||
| from nonebot.rule import to_me | ||||
| from nonebot.plugin import on_command, on_keyword | ||||
| from nonebot.adapters.mirai import Bot, MessageEvent | ||||
|  | ||||
| message_test = on_keyword({"reply"}, rule=to_me()) | ||||
|  | ||||
|  | ||||
| @message_test.handle() | ||||
| async def _message(bot: Bot, event: MessageEvent): | ||||
|     text = event.get_plaintext() | ||||
|     await bot.send(event, text, at_sender=True) | ||||
|  | ||||
|  | ||||
| command_test = on_command("miecho") | ||||
|  | ||||
|  | ||||
| @command_test.handle() | ||||
| async def _echo(bot: Bot, event: MessageEvent): | ||||
|     text = event.get_plaintext() | ||||
|     await bot.send(event, text, at_sender=True) | ||||
| @@ -1 +0,0 @@ | ||||
| from . import test_command | ||||
| @@ -1,24 +0,0 @@ | ||||
| from nonebot.rule import to_me | ||||
| from nonebot.typing import T_State | ||||
| from nonebot.plugin import on_command | ||||
| from nonebot.adapters import Bot, Event | ||||
|  | ||||
| test_command = on_command("帮助", to_me()) | ||||
|  | ||||
|  | ||||
| @test_command.handle() | ||||
| async def test_handler1(bot: Bot, event: Event, state: T_State): | ||||
|     args = str(event.get_message()).strip() | ||||
|     print("[!] Command:", state["_prefix"], "Args:", args) | ||||
|     if args: | ||||
|         state["help"] = args | ||||
|     else: | ||||
|         await bot.send(message="命令:\n1. test1\n2. test2", event=event) | ||||
|  | ||||
|  | ||||
| @test_command.got("help", prompt="你要帮助的命令是?") | ||||
| async def test_handler2(bot: Bot, event: Event, state: T_State): | ||||
|     print("[!] Command 帮助:", state["help"]) | ||||
|     if state["help"] not in ["test1", "test2"]: | ||||
|         await test_command.reject(f"{state['help']} 不支持,请重新输入!") | ||||
|     await bot.send(message=f"{state['help']} 帮助:\n...", event=event) | ||||
| @@ -1,15 +0,0 @@ | ||||
| from nonebot.adapters import Event | ||||
| from nonebot.typing import T_State | ||||
| from nonebot.matcher import Matcher | ||||
| from nonebot.message import run_preprocessor, event_preprocessor | ||||
|  | ||||
|  | ||||
| @event_preprocessor | ||||
| async def handle(event: Event, state: T_State): | ||||
|     state["preprocessed"] = True | ||||
|     print(type(event), event) | ||||
|  | ||||
|  | ||||
| @run_preprocessor | ||||
| async def run(matcher: Matcher): | ||||
|     print(matcher) | ||||
| @@ -1,15 +0,0 @@ | ||||
| from nonebot.adapters import Bot | ||||
| from nonebot.typing import T_State | ||||
| from nonebot import on_shell_command | ||||
| from nonebot.rule import ArgumentParser, to_me | ||||
|  | ||||
| parser = ArgumentParser() | ||||
| parser.add_argument("-a", action="store_true") | ||||
|  | ||||
| shell = on_shell_command("ls", to_me(), parser=parser) | ||||
|  | ||||
|  | ||||
| @shell.handle() | ||||
| async def _(bot: Bot, state: T_State): | ||||
|     print(state["argv"]) | ||||
|     print(state["args"]) | ||||
| @@ -1,25 +0,0 @@ | ||||
| from nonebot import on_command | ||||
| from nonebot.rule import to_me | ||||
| from nonebot.typing import T_State | ||||
| from nonebot.adapters import Bot, Event | ||||
|  | ||||
| weather = on_command("天气", rule=to_me(), priority=1) | ||||
|  | ||||
|  | ||||
| @weather.handle() | ||||
| async def handle_first_receive(bot: Bot, event: Event, state: T_State): | ||||
|     args = str(event.get_message()).strip()  # 首次发送命令时跟随的参数,例:/天气 上海,则args为上海 | ||||
|     print(f"==={args}===") | ||||
|     if args: | ||||
|         state["city"] = args  # 如果用户发送了参数则直接赋值 | ||||
|  | ||||
|  | ||||
| @weather.got("city", prompt="你想查询哪个城市的天气呢?") | ||||
| async def handle_city(bot: Bot, state: T_State): | ||||
|     city = state["city"] | ||||
|     if city not in ["上海", "北京"]: | ||||
|         await weather.reject("你想查询的城市暂不支持,请重新输入!") | ||||
|     # weather = await get_weather_from_xxx(city) | ||||
|     city_weather = "晴天" | ||||
|     # await bot.send(city_weather) | ||||
|     await weather.finish(city_weather) | ||||
| @@ -1,14 +0,0 @@ | ||||
| import nonebot | ||||
| from nonebot.adapters import Bot | ||||
|  | ||||
| driver = nonebot.get_driver() | ||||
|  | ||||
|  | ||||
| @driver.on_bot_connect | ||||
| async def connect(bot: Bot) -> None: | ||||
|     print("Connect", bot) | ||||
|  | ||||
|  | ||||
| @driver.on_bot_disconnect | ||||
| async def disconnect(bot: Bot) -> None: | ||||
|     print("Disconnect", bot) | ||||
		Reference in New Issue
	
	Block a user