satori-python-core 0.13.2__tar.gz → 0.14.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {satori_python_core-0.13.2 → satori_python_core-0.14.0}/PKG-INFO +1 -1
- {satori_python_core-0.13.2 → satori_python_core-0.14.0}/pyproject.toml +3 -3
- {satori_python_core-0.13.2 → satori_python_core-0.14.0}/src/satori/__init__.py +1 -1
- {satori_python_core-0.13.2 → satori_python_core-0.14.0}/src/satori/element.py +20 -20
- {satori_python_core-0.13.2 → satori_python_core-0.14.0}/src/satori/model.py +11 -11
- {satori_python_core-0.13.2 → satori_python_core-0.14.0}/src/satori/parser.py +25 -21
- {satori_python_core-0.13.2 → satori_python_core-0.14.0}/.mina/core.toml +0 -0
- {satori_python_core-0.13.2 → satori_python_core-0.14.0}/LICENSE +0 -0
- {satori_python_core-0.13.2 → satori_python_core-0.14.0}/README.md +0 -0
- {satori_python_core-0.13.2 → satori_python_core-0.14.0}/src/satori/config.py +0 -0
- {satori_python_core-0.13.2 → satori_python_core-0.14.0}/src/satori/const.py +0 -0
- {satori_python_core-0.13.2 → satori_python_core-0.14.0}/src/satori/event.py +0 -0
- {satori_python_core-0.13.2 → satori_python_core-0.14.0}/src/satori/exception.py +0 -0
|
@@ -23,7 +23,7 @@ classifiers = [
|
|
|
23
23
|
"Programming Language :: Python :: 3.12",
|
|
24
24
|
"Operating System :: OS Independent",
|
|
25
25
|
]
|
|
26
|
-
version = "0.
|
|
26
|
+
version = "0.14.0"
|
|
27
27
|
|
|
28
28
|
[project.license]
|
|
29
29
|
text = "MIT"
|
|
@@ -85,7 +85,7 @@ extra_standard_library = [
|
|
|
85
85
|
|
|
86
86
|
[tool.ruff]
|
|
87
87
|
line-length = 110
|
|
88
|
-
target-version = "
|
|
88
|
+
target-version = "py39"
|
|
89
89
|
exclude = [
|
|
90
90
|
"exam.py",
|
|
91
91
|
]
|
|
@@ -110,7 +110,7 @@ ignore = [
|
|
|
110
110
|
|
|
111
111
|
[tool.pyright]
|
|
112
112
|
pythonPlatform = "All"
|
|
113
|
-
pythonVersion = "3.
|
|
113
|
+
pythonVersion = "3.9"
|
|
114
114
|
typeCheckingMode = "basic"
|
|
115
115
|
reportShadowedImports = false
|
|
116
116
|
disableBytesTypePromotions = true
|
|
@@ -2,7 +2,7 @@ from base64 import b64encode
|
|
|
2
2
|
from dataclasses import InitVar, dataclass, field, fields
|
|
3
3
|
from io import BytesIO
|
|
4
4
|
from pathlib import Path
|
|
5
|
-
from typing import Any, ClassVar,
|
|
5
|
+
from typing import Any, ClassVar, Optional, TypeVar, Union, get_args, overload
|
|
6
6
|
from typing_extensions import override
|
|
7
7
|
|
|
8
8
|
from .parser import Element as RawElement
|
|
@@ -14,13 +14,13 @@ TE = TypeVar("TE", bound="Element")
|
|
|
14
14
|
|
|
15
15
|
@dataclass(repr=False)
|
|
16
16
|
class Element:
|
|
17
|
-
_attrs:
|
|
18
|
-
_children:
|
|
17
|
+
_attrs: dict[str, Any] = field(init=False, default_factory=dict)
|
|
18
|
+
_children: list["Element"] = field(init=False, default_factory=list)
|
|
19
19
|
|
|
20
|
-
__names__: ClassVar[
|
|
20
|
+
__names__: ClassVar[tuple[str, ...]]
|
|
21
21
|
|
|
22
22
|
@property
|
|
23
|
-
def children(self) ->
|
|
23
|
+
def children(self) -> list["Element"]:
|
|
24
24
|
return self._children
|
|
25
25
|
|
|
26
26
|
@property
|
|
@@ -28,7 +28,7 @@ class Element:
|
|
|
28
28
|
return self.__class__.__name__.lower()
|
|
29
29
|
|
|
30
30
|
@classmethod
|
|
31
|
-
def unpack(cls, attrs:
|
|
31
|
+
def unpack(cls, attrs: dict[str, Any]):
|
|
32
32
|
obj = cls(**{k: v for k, v in attrs.items() if k in cls.__names__}) # type: ignore
|
|
33
33
|
obj._attrs.update({k: v for k, v in attrs.items() if k not in cls.__names__})
|
|
34
34
|
return obj
|
|
@@ -166,7 +166,7 @@ class Link(Element):
|
|
|
166
166
|
class Resource(Element):
|
|
167
167
|
src: str
|
|
168
168
|
title: Optional[str] = None
|
|
169
|
-
extra: InitVar[Optional[
|
|
169
|
+
extra: InitVar[Optional[dict[str, Any]]] = None
|
|
170
170
|
cache: Optional[bool] = None
|
|
171
171
|
timeout: Optional[int] = None
|
|
172
172
|
|
|
@@ -181,19 +181,19 @@ class Resource(Element):
|
|
|
181
181
|
mime: Optional[str] = None,
|
|
182
182
|
name: Optional[str] = None,
|
|
183
183
|
poster: Optional[str] = None,
|
|
184
|
-
extra: Optional[
|
|
184
|
+
extra: Optional[dict[str, Any]] = None,
|
|
185
185
|
cache: Optional[bool] = None,
|
|
186
186
|
timeout: Optional[int] = None,
|
|
187
187
|
**kwargs,
|
|
188
188
|
):
|
|
189
|
-
data:
|
|
189
|
+
data: dict[str, Any] = {"extra": extra or kwargs}
|
|
190
190
|
if url is not None:
|
|
191
|
-
data
|
|
191
|
+
data |= {"src": url}
|
|
192
192
|
elif path:
|
|
193
|
-
data
|
|
193
|
+
data |= {"src": Path(path).as_uri()}
|
|
194
194
|
elif raw and mime:
|
|
195
195
|
bd = raw.getvalue() if isinstance(raw, BytesIO) else raw
|
|
196
|
-
data
|
|
196
|
+
data |= {"src": f"data:{mime};base64,{b64encode(bd).decode('utf-8')}"}
|
|
197
197
|
else:
|
|
198
198
|
raise ValueError(f"{cls} need at least one of url, path and raw")
|
|
199
199
|
if name is not None:
|
|
@@ -206,7 +206,7 @@ class Resource(Element):
|
|
|
206
206
|
data["timeout"] = timeout
|
|
207
207
|
return cls(**data)
|
|
208
208
|
|
|
209
|
-
def __post_init__(self, extra: Optional[
|
|
209
|
+
def __post_init__(self, extra: Optional[dict[str, Any]] = None):
|
|
210
210
|
super().__post_init__()
|
|
211
211
|
if extra:
|
|
212
212
|
self._attrs.update(extra)
|
|
@@ -380,7 +380,7 @@ class Message(Element):
|
|
|
380
380
|
self,
|
|
381
381
|
id: Optional[str] = None,
|
|
382
382
|
forward: Optional[bool] = None,
|
|
383
|
-
content: Optional[
|
|
383
|
+
content: Optional[list[Union[str, Element]]] = None,
|
|
384
384
|
):
|
|
385
385
|
self.id = id
|
|
386
386
|
self.forward = forward
|
|
@@ -464,8 +464,8 @@ class Custom(Element):
|
|
|
464
464
|
def __init__(
|
|
465
465
|
self,
|
|
466
466
|
type: str,
|
|
467
|
-
attrs: Optional[
|
|
468
|
-
children: Optional[
|
|
467
|
+
attrs: Optional[dict[str, Any]] = None,
|
|
468
|
+
children: Optional[list[Union[str, Element]]] = None,
|
|
469
469
|
):
|
|
470
470
|
self.type = type
|
|
471
471
|
super().__init__()
|
|
@@ -536,7 +536,7 @@ STYLE_TYPE_MAP = {
|
|
|
536
536
|
}
|
|
537
537
|
|
|
538
538
|
|
|
539
|
-
def transform(elements:
|
|
539
|
+
def transform(elements: list[RawElement]) -> list[Element]:
|
|
540
540
|
msg = []
|
|
541
541
|
for elem in elements:
|
|
542
542
|
tag = elem.tag()
|
|
@@ -568,14 +568,14 @@ def transform(elements: List[RawElement]) -> List[Element]:
|
|
|
568
568
|
|
|
569
569
|
|
|
570
570
|
@overload
|
|
571
|
-
def select(elements: Union[Element,
|
|
571
|
+
def select(elements: Union[Element, list[Element]], query: type[TE]) -> list[TE]: ...
|
|
572
572
|
|
|
573
573
|
|
|
574
574
|
@overload
|
|
575
|
-
def select(elements: Union[Element,
|
|
575
|
+
def select(elements: Union[Element, list[Element]], query: str) -> list[Element]: ...
|
|
576
576
|
|
|
577
577
|
|
|
578
|
-
def select(elements: Union[Element,
|
|
578
|
+
def select(elements: Union[Element, list[Element]], query: Union[type[TE], str]):
|
|
579
579
|
if not elements:
|
|
580
580
|
return []
|
|
581
581
|
if isinstance(elements, Element):
|
|
@@ -4,7 +4,7 @@ from datetime import datetime
|
|
|
4
4
|
from enum import IntEnum
|
|
5
5
|
from os import PathLike
|
|
6
6
|
from pathlib import Path
|
|
7
|
-
from typing import IO, Any, Callable, ClassVar,
|
|
7
|
+
from typing import IO, Any, Callable, ClassVar, Generic, Literal, Optional, TypeVar, Union
|
|
8
8
|
from typing_extensions import TypeAlias
|
|
9
9
|
|
|
10
10
|
from .element import Element, transform
|
|
@@ -14,7 +14,7 @@ from .parser import parse
|
|
|
14
14
|
|
|
15
15
|
@dataclass
|
|
16
16
|
class ModelBase:
|
|
17
|
-
__converter__: ClassVar[
|
|
17
|
+
__converter__: ClassVar[dict[str, Callable[[Any], Any]]] = {}
|
|
18
18
|
|
|
19
19
|
@classmethod
|
|
20
20
|
def parse(cls, raw: dict):
|
|
@@ -81,7 +81,7 @@ class User(ModelBase):
|
|
|
81
81
|
is_bot: Optional[bool] = None
|
|
82
82
|
|
|
83
83
|
def dump(self):
|
|
84
|
-
res:
|
|
84
|
+
res: dict[str, Any] = {"id": self.id}
|
|
85
85
|
if self.name:
|
|
86
86
|
res["name"] = self.name
|
|
87
87
|
if self.nick:
|
|
@@ -141,13 +141,13 @@ class Login(ModelBase):
|
|
|
141
141
|
user: Optional[User] = None
|
|
142
142
|
self_id: Optional[str] = None
|
|
143
143
|
platform: Optional[str] = None
|
|
144
|
-
features:
|
|
145
|
-
proxy_urls:
|
|
144
|
+
features: list[str] = field(default_factory=list)
|
|
145
|
+
proxy_urls: list[str] = field(default_factory=list)
|
|
146
146
|
|
|
147
147
|
__converter__ = {"user": User.parse, "status": LoginStatus}
|
|
148
148
|
|
|
149
149
|
def dump(self):
|
|
150
|
-
res:
|
|
150
|
+
res: dict[str, Any] = {
|
|
151
151
|
"status": self.status.value,
|
|
152
152
|
"features": self.features,
|
|
153
153
|
"proxy_urls": self.proxy_urls,
|
|
@@ -195,7 +195,7 @@ class Identify(ModelBase):
|
|
|
195
195
|
|
|
196
196
|
@dataclass
|
|
197
197
|
class Ready(ModelBase):
|
|
198
|
-
logins:
|
|
198
|
+
logins: list[Login]
|
|
199
199
|
|
|
200
200
|
|
|
201
201
|
@dataclass
|
|
@@ -213,7 +213,7 @@ class MessageObject(ModelBase):
|
|
|
213
213
|
def from_elements(
|
|
214
214
|
cls,
|
|
215
215
|
id: str,
|
|
216
|
-
content:
|
|
216
|
+
content: list[Element],
|
|
217
217
|
channel: Optional[Channel] = None,
|
|
218
218
|
guild: Optional[Guild] = None,
|
|
219
219
|
member: Optional[Member] = None,
|
|
@@ -224,7 +224,7 @@ class MessageObject(ModelBase):
|
|
|
224
224
|
return cls(id, "".join(str(i) for i in content), channel, guild, member, user, created_at, updated_at)
|
|
225
225
|
|
|
226
226
|
@property
|
|
227
|
-
def message(self) ->
|
|
227
|
+
def message(self) -> list[Element]:
|
|
228
228
|
return transform(parse(self.content))
|
|
229
229
|
|
|
230
230
|
@classmethod
|
|
@@ -244,7 +244,7 @@ class MessageObject(ModelBase):
|
|
|
244
244
|
}
|
|
245
245
|
|
|
246
246
|
def dump(self):
|
|
247
|
-
res:
|
|
247
|
+
res: dict[str, Any] = {"id": self.id, "content": self.content}
|
|
248
248
|
if self.channel:
|
|
249
249
|
res["channel"] = self.channel.dump()
|
|
250
250
|
if self.guild:
|
|
@@ -335,7 +335,7 @@ T = TypeVar("T", bound=ModelBase)
|
|
|
335
335
|
|
|
336
336
|
@dataclass
|
|
337
337
|
class PageResult(ModelBase, Generic[T]):
|
|
338
|
-
data:
|
|
338
|
+
data: list[T]
|
|
339
339
|
next: Optional[str] = None
|
|
340
340
|
|
|
341
341
|
@classmethod
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import re
|
|
2
|
+
from collections.abc import Iterable
|
|
2
3
|
from dataclasses import dataclass, field
|
|
3
4
|
from enum import IntEnum
|
|
4
|
-
from typing import Any, Callable,
|
|
5
|
+
from typing import Any, Callable, Literal, Optional, TypedDict, TypeVar, Union, cast
|
|
5
6
|
from typing_extensions import TypeAlias
|
|
6
7
|
|
|
7
8
|
T = TypeVar("T")
|
|
@@ -39,13 +40,13 @@ def snake_case(source: str) -> str:
|
|
|
39
40
|
)
|
|
40
41
|
|
|
41
42
|
|
|
42
|
-
def ensure_list(value: Union[T,
|
|
43
|
+
def ensure_list(value: Union[T, list[T], None]) -> list[T]:
|
|
43
44
|
return value if isinstance(value, list) else [value] if value else []
|
|
44
45
|
|
|
45
46
|
|
|
46
47
|
S = TypeVar("S")
|
|
47
|
-
Fragment: TypeAlias = Union[str, "Element",
|
|
48
|
-
Render: TypeAlias = Callable[[dict,
|
|
48
|
+
Fragment: TypeAlias = Union[str, "Element", list[Union[str, "Element"]]]
|
|
49
|
+
Render: TypeAlias = Callable[[dict, list["Element"], S], T]
|
|
49
50
|
Visitor: TypeAlias = Callable[["Element", S], T]
|
|
50
51
|
|
|
51
52
|
|
|
@@ -60,7 +61,7 @@ def make_element(content: Union[str, bool, int, float, "Element"]) -> Optional["
|
|
|
60
61
|
raise ValueError(f"Invalid content: {content!r}")
|
|
61
62
|
|
|
62
63
|
|
|
63
|
-
def make_elements(content: Fragment) ->
|
|
64
|
+
def make_elements(content: Fragment) -> list["Element"]:
|
|
64
65
|
if isinstance(content, list):
|
|
65
66
|
res = [make_element(c) for c in content]
|
|
66
67
|
else:
|
|
@@ -70,14 +71,14 @@ def make_elements(content: Fragment) -> List["Element"]:
|
|
|
70
71
|
|
|
71
72
|
class Element:
|
|
72
73
|
type: str
|
|
73
|
-
attrs:
|
|
74
|
-
children:
|
|
74
|
+
attrs: dict[str, Any]
|
|
75
|
+
children: list["Element"]
|
|
75
76
|
source: Optional[str] = None
|
|
76
77
|
|
|
77
78
|
def __init__(
|
|
78
79
|
self,
|
|
79
80
|
type: Union[str, Render[Fragment, Any]],
|
|
80
|
-
attrs: Optional[
|
|
81
|
+
attrs: Optional[dict[str, Any]] = None,
|
|
81
82
|
*children: Fragment,
|
|
82
83
|
) -> None:
|
|
83
84
|
self.attrs = {}
|
|
@@ -97,8 +98,11 @@ class Element:
|
|
|
97
98
|
self.attrs["is"] = type
|
|
98
99
|
else:
|
|
99
100
|
self.type = type
|
|
100
|
-
if self.tag() == "text"
|
|
101
|
-
|
|
101
|
+
if self.tag() == "text":
|
|
102
|
+
if "content" in self.attrs:
|
|
103
|
+
self.attrs["text"] = self.attrs.pop("content")
|
|
104
|
+
elif not self.attrs:
|
|
105
|
+
self.attrs["text"] = ""
|
|
102
106
|
|
|
103
107
|
def tag(self):
|
|
104
108
|
if self.type == "component":
|
|
@@ -151,8 +155,8 @@ class Selector:
|
|
|
151
155
|
comb_pat = re.compile(" *([ >+~]) *")
|
|
152
156
|
|
|
153
157
|
|
|
154
|
-
def parse_selector(input: str) ->
|
|
155
|
-
def _quert(query: str) ->
|
|
158
|
+
def parse_selector(input: str) -> list[list[Selector]]:
|
|
159
|
+
def _quert(query: str) -> list[Selector]:
|
|
156
160
|
selectors = []
|
|
157
161
|
combinator = " "
|
|
158
162
|
while mat := comb_pat.search(query):
|
|
@@ -170,7 +174,7 @@ def parse_selector(input: str) -> List[List[Selector]]:
|
|
|
170
174
|
return [_quert(q) for q in input.split(",")]
|
|
171
175
|
|
|
172
176
|
|
|
173
|
-
def select(source: Union[str,
|
|
177
|
+
def select(source: Union[str, list[Element]], query: Union[str, list[list[Selector]]]) -> list[Element]:
|
|
174
178
|
if not source or not query:
|
|
175
179
|
return []
|
|
176
180
|
if isinstance(source, str):
|
|
@@ -179,10 +183,10 @@ def select(source: Union[str, List[Element]], query: Union[str, List[List[Select
|
|
|
179
183
|
query = parse_selector(query)
|
|
180
184
|
if not query:
|
|
181
185
|
return []
|
|
182
|
-
adjacent:
|
|
186
|
+
adjacent: list[list[Selector]] = []
|
|
183
187
|
results = []
|
|
184
188
|
for index, elem in enumerate(source):
|
|
185
|
-
inner:
|
|
189
|
+
inner: list[list[Selector]] = []
|
|
186
190
|
local = [*query, *adjacent]
|
|
187
191
|
adjacent = []
|
|
188
192
|
matched = False
|
|
@@ -252,7 +256,7 @@ class Token:
|
|
|
252
256
|
positon: Position
|
|
253
257
|
source: str
|
|
254
258
|
extra: str
|
|
255
|
-
children:
|
|
259
|
+
children: dict[str, list[Union[str, "Token"]]] = field(default_factory=dict)
|
|
256
260
|
|
|
257
261
|
|
|
258
262
|
class StackItem(TypedDict):
|
|
@@ -260,8 +264,8 @@ class StackItem(TypedDict):
|
|
|
260
264
|
slot: str
|
|
261
265
|
|
|
262
266
|
|
|
263
|
-
def fold_tokens(tokens:
|
|
264
|
-
stack:
|
|
267
|
+
def fold_tokens(tokens: list[Union[str, Token]]) -> list[Union[str, Token]]:
|
|
268
|
+
stack: list[StackItem] = [
|
|
265
269
|
{
|
|
266
270
|
"token": Token(
|
|
267
271
|
type="angle",
|
|
@@ -298,8 +302,8 @@ def fold_tokens(tokens: List[Union[str, Token]]) -> List[Union[str, Token]]:
|
|
|
298
302
|
return stack[-1]["token"].children["default"]
|
|
299
303
|
|
|
300
304
|
|
|
301
|
-
def parse_tokens(tokens:
|
|
302
|
-
result:
|
|
305
|
+
def parse_tokens(tokens: list[Union[str, Token]], context: Optional[dict] = None) -> list[Element]:
|
|
306
|
+
result: list[Element] = []
|
|
303
307
|
for token in tokens:
|
|
304
308
|
if isinstance(token, str):
|
|
305
309
|
result.append(Element(type="text", attrs={"text": token}))
|
|
@@ -345,7 +349,7 @@ def parse_tokens(tokens: List[Union[str, Token]], context: Optional[dict] = None
|
|
|
345
349
|
|
|
346
350
|
|
|
347
351
|
def parse(src: str, context: Optional[dict] = None):
|
|
348
|
-
tokens:
|
|
352
|
+
tokens: list[Union[str, Token]] = []
|
|
349
353
|
|
|
350
354
|
def push_text(text: str):
|
|
351
355
|
if text:
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|