nonebot2/nonebot/adapters/__init__.py

171 lines
4.9 KiB
Python
Raw Normal View History

2020-07-05 20:39:34 +08:00
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
2020-07-18 18:18:43 +08:00
import abc
from functools import reduce
2020-08-10 13:06:02 +08:00
from dataclasses import dataclass, field
2020-07-11 17:32:03 +08:00
from nonebot.config import Config
2020-08-10 13:06:02 +08:00
from nonebot.typing import Dict, Union, Iterable, WebSocket
2020-07-11 17:32:03 +08:00
2020-07-05 20:39:34 +08:00
2020-07-18 18:18:43 +08:00
class BaseBot(abc.ABC):
2020-07-05 20:39:34 +08:00
2020-07-18 18:18:43 +08:00
@abc.abstractmethod
2020-08-01 22:03:40 +08:00
def __init__(self,
2020-08-07 17:51:57 +08:00
connection_type: str,
2020-08-01 22:03:40 +08:00
config: Config,
self_id: int,
*,
2020-08-10 13:06:02 +08:00
websocket: WebSocket = None):
2020-08-07 17:51:57 +08:00
self.connection_type = connection_type
self.config = config
self.self_id = self_id
self.websocket = websocket
@property
@abc.abstractmethod
def type(self) -> str:
2020-07-11 17:32:03 +08:00
raise NotImplementedError
2020-07-18 18:18:43 +08:00
@abc.abstractmethod
2020-07-11 17:32:03 +08:00
async def handle_message(self, message: dict):
raise NotImplementedError
2020-07-18 18:18:43 +08:00
@abc.abstractmethod
2020-07-11 17:32:03 +08:00
async def call_api(self, api: str, data: dict):
raise NotImplementedError
2020-08-08 23:08:01 +08:00
@dataclass
class BaseMessageSegment(abc.ABC):
type: str
2020-08-10 13:06:02 +08:00
data: Dict[str, str] = field(default_factory=lambda: {})
2020-07-11 17:32:03 +08:00
2020-08-08 23:08:01 +08:00
@abc.abstractmethod
2020-07-11 17:32:03 +08:00
def __str__(self):
raise NotImplementedError
2020-08-08 23:08:01 +08:00
@abc.abstractmethod
def __add__(self, other):
raise NotImplementedError
2020-08-08 23:08:01 +08:00
# class BaseMessageSegment(dict):
2020-08-08 23:08:01 +08:00
# def __init__(self,
# type_: Optional[str] = None,
# data: Optional[Dict[str, str]] = None):
# super().__init__()
# if type_:
# self.type = type_
# self.data = data
# else:
# raise ValueError('The "type" field cannot be empty')
2020-08-08 23:08:01 +08:00
# def __str__(self):
# raise NotImplementedError
2020-08-08 23:08:01 +08:00
# def __getitem__(self, item):
# if item not in ("type", "data"):
# raise KeyError(f'Key "{item}" is not allowed')
# return super().__getitem__(item)
# def __setitem__(self, key, value):
# if key not in ("type", "data"):
# raise KeyError(f'Key "{key}" is not allowed')
# return super().__setitem__(key, value)
# # TODO: __eq__ __add__
# @property
# def type(self) -> str:
# return self["type"]
2020-08-08 23:08:01 +08:00
# @type.setter
# def type(self, value: str):
# self["type"] = value
2020-08-08 23:08:01 +08:00
# @property
# def data(self) -> Dict[str, str]:
# return self["data"]
2020-07-11 17:32:03 +08:00
2020-08-08 23:08:01 +08:00
# @data.setter
# def data(self, data: Optional[Dict[str, str]]):
# self["data"] = data or {}
class BaseMessage(list, abc.ABC):
2020-07-11 17:32:03 +08:00
2020-07-18 18:18:43 +08:00
def __init__(self,
message: Union[str, BaseMessageSegment, "BaseMessage"] = None,
*args,
**kwargs):
super().__init__(*args, **kwargs)
if isinstance(message, str):
self.extend(self._construct(message))
elif isinstance(message, BaseMessage):
self.extend(message)
elif isinstance(message, BaseMessageSegment):
self.append(message)
2020-07-11 17:32:03 +08:00
def __str__(self):
return ''.join((str(seg) for seg in self))
2020-07-18 18:18:43 +08:00
@staticmethod
2020-08-08 23:08:01 +08:00
@abc.abstractmethod
2020-07-18 18:18:43 +08:00
def _construct(msg: str) -> Iterable[BaseMessageSegment]:
raise NotImplementedError
def __add__(
self, other: Union[str, BaseMessageSegment,
"BaseMessage"]) -> "BaseMessage":
result = self.__class__(self)
if isinstance(other, str):
result.extend(self._construct(other))
elif isinstance(other, BaseMessageSegment):
result.append(other)
elif isinstance(other, BaseMessage):
result.extend(other)
return result
def __radd__(self, other: Union[str, BaseMessageSegment, "BaseMessage"]):
result = self.__class__(other)
return result.__add__(self)
def append(self, obj: Union[str, BaseMessageSegment]) -> "BaseMessage":
if isinstance(obj, BaseMessageSegment):
if obj.type == "text" and self and self[-1].type == "text":
self[-1].data["text"] += obj.data["text"]
else:
super().append(obj)
elif isinstance(obj, str):
self.extend(self._construct(obj))
else:
raise ValueError(f"Unexpected type: {type(obj)} {obj}")
return self
def extend(
self, obj: Union["BaseMessage",
Iterable[BaseMessageSegment]]) -> "BaseMessage":
for segment in obj:
self.append(segment)
return self
def reduce(self) -> None:
index = 0
while index < len(self):
if index > 0 and self[
index - 1].type == "text" and self[index].type == "text":
self[index - 1].data["text"] += self[index].data["text"]
del self[index]
else:
index += 1
def extract_plain_text(self) -> str:
def _concat(x: str, y: BaseMessageSegment) -> str:
return f"{x} {y.data['text']}" if y.type == "text" else x
return reduce(_concat, self, "")