satori-python 1.3.5__py3-none-any.whl → 1.3.7__py3-none-any.whl
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/__init__.py +1 -1
- satori/client/__init__.py +1 -4
- satori/client/config.py +3 -3
- satori/element.py +25 -11
- satori/server/__init__.py +20 -14
- satori/server/adapter.py +4 -2
- {satori_python-1.3.5.dist-info → satori_python-1.3.7.dist-info}/METADATA +1 -1
- {satori_python-1.3.5.dist-info → satori_python-1.3.7.dist-info}/RECORD +10 -10
- {satori_python-1.3.5.dist-info → satori_python-1.3.7.dist-info}/WHEEL +0 -0
- {satori_python-1.3.5.dist-info → satori_python-1.3.7.dist-info}/licenses/LICENSE +0 -0
satori/__init__.py
CHANGED
satori/client/__init__.py
CHANGED
|
@@ -31,10 +31,7 @@ from .protocol import ApiProtocol as ApiProtocol
|
|
|
31
31
|
TConfig = TypeVar("TConfig", bound=Config)
|
|
32
32
|
TE = TypeVar("TE", bound=Event, contravariant=True)
|
|
33
33
|
|
|
34
|
-
MAPPING: dict[type[Config], type[BaseNetwork]] = {
|
|
35
|
-
WebhookInfo: WebhookNetwork,
|
|
36
|
-
WebsocketsInfo: WsNetwork,
|
|
37
|
-
}
|
|
34
|
+
MAPPING: dict[type[Config], type[BaseNetwork]] = {WebhookInfo: WebhookNetwork, WebsocketsInfo: WsNetwork} # noqa
|
|
38
35
|
|
|
39
36
|
_app: App | None = None
|
|
40
37
|
|
satori/client/config.py
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
from dataclasses import dataclass
|
|
1
|
+
from dataclasses import dataclass, field
|
|
2
2
|
|
|
3
3
|
from yarl import URL
|
|
4
4
|
|
|
@@ -25,8 +25,8 @@ class WebsocketsInfo(Config):
|
|
|
25
25
|
token: str | None = None
|
|
26
26
|
secure: bool = False
|
|
27
27
|
timeout: float | None = None
|
|
28
|
-
identity: str = None # type: ignore
|
|
29
|
-
api_base: URL = None # type: ignore
|
|
28
|
+
identity: str = field(init=False, default=None) # type: ignore
|
|
29
|
+
api_base: URL = field(init=False, default=None) # type: ignore
|
|
30
30
|
|
|
31
31
|
def __post_init__(self):
|
|
32
32
|
if self.path and not self.path.startswith("/"):
|
satori/element.py
CHANGED
|
@@ -129,7 +129,7 @@ class Element:
|
|
|
129
129
|
args = {**self._attrs}
|
|
130
130
|
elem = f"{self.__class__.__name__}(" + ", ".join(f"{k}={v!r}" for k, v in args.items())
|
|
131
131
|
if self._children:
|
|
132
|
-
elem += ",
|
|
132
|
+
elem += ", [" + ", ".join(repr(i) for i in self._children) + "]"
|
|
133
133
|
return elem + ")"
|
|
134
134
|
|
|
135
135
|
def __call__(self, *content: "str | Element"):
|
|
@@ -257,7 +257,6 @@ class Link(Element):
|
|
|
257
257
|
class Resource(Element):
|
|
258
258
|
src: str
|
|
259
259
|
title: str | None = None
|
|
260
|
-
extra: InitVar[dict[str, Any] | None] = None
|
|
261
260
|
cache: bool | None = None
|
|
262
261
|
timeout: int | None = None
|
|
263
262
|
|
|
@@ -271,14 +270,15 @@ class Resource(Element):
|
|
|
271
270
|
raw: bytes | BytesIO | None = None,
|
|
272
271
|
mime: str | None = None,
|
|
273
272
|
name: str | None = None,
|
|
273
|
+
width: int | None = None,
|
|
274
|
+
height: int | None = None,
|
|
274
275
|
duration: float | None = None,
|
|
275
276
|
poster: str | None = None,
|
|
276
|
-
extra: dict[str, Any] | None = None,
|
|
277
277
|
cache: bool | None = None,
|
|
278
278
|
timeout: int | None = None,
|
|
279
279
|
**kwargs,
|
|
280
280
|
) -> Self:
|
|
281
|
-
data: dict[str, Any] = {
|
|
281
|
+
data: dict[str, Any] = {**kwargs}
|
|
282
282
|
if url is not None:
|
|
283
283
|
data |= {"src": url}
|
|
284
284
|
elif path:
|
|
@@ -296,6 +296,10 @@ class Resource(Element):
|
|
|
296
296
|
raise ValueError(f"{cls} need at least one of url, path and raw")
|
|
297
297
|
if name is not None:
|
|
298
298
|
data["title"] = name
|
|
299
|
+
if width is not None and cls in (Image, Video):
|
|
300
|
+
data["width"] = width
|
|
301
|
+
if height is not None and cls in (Image, Video):
|
|
302
|
+
data["height"] = height
|
|
299
303
|
if duration is not None and cls is Audio:
|
|
300
304
|
data["duration"] = duration
|
|
301
305
|
if poster is not None and cls in (Video, Audio, File):
|
|
@@ -304,11 +308,7 @@ class Resource(Element):
|
|
|
304
308
|
data["cache"] = cache
|
|
305
309
|
if timeout is not None:
|
|
306
310
|
data["timeout"] = timeout
|
|
307
|
-
return cls(
|
|
308
|
-
|
|
309
|
-
def __post_init__(self, extra: dict[str, Any] | None = None):
|
|
310
|
-
if extra:
|
|
311
|
-
self._attrs.update(extra)
|
|
311
|
+
return cls.unpack(data)
|
|
312
312
|
|
|
313
313
|
|
|
314
314
|
@dataclass(repr=False)
|
|
@@ -582,7 +582,7 @@ class Custom(Element):
|
|
|
582
582
|
attrs: dict[str, Any] | None = None,
|
|
583
583
|
children: Sequence[str | Element] | None = None,
|
|
584
584
|
):
|
|
585
|
-
self.
|
|
585
|
+
self._type = type
|
|
586
586
|
if not hasattr(self, "_attrs"):
|
|
587
587
|
self._attrs = attrs or {}
|
|
588
588
|
else:
|
|
@@ -595,7 +595,21 @@ class Custom(Element):
|
|
|
595
595
|
@property
|
|
596
596
|
@override
|
|
597
597
|
def tag(self) -> str:
|
|
598
|
-
return self.
|
|
598
|
+
return self._type
|
|
599
|
+
|
|
600
|
+
def __repr__(self) -> str:
|
|
601
|
+
if not self._attrs:
|
|
602
|
+
self._attrs = {k: v for k, v in self.__dict__.items() if not k.startswith("_")}
|
|
603
|
+
args = {**self._attrs}
|
|
604
|
+
elem = (
|
|
605
|
+
f"{self.__class__.__name__}({self._type!r}"
|
|
606
|
+
+ ", {"
|
|
607
|
+
+ ", ".join(f"{k!r}: {v!r}" for k, v in args.items())
|
|
608
|
+
+ "}"
|
|
609
|
+
)
|
|
610
|
+
if self._children:
|
|
611
|
+
elem += ", [" + ", ".join(repr(i) for i in self._children) + "]"
|
|
612
|
+
return elem + ")"
|
|
599
613
|
|
|
600
614
|
|
|
601
615
|
@dataclass(repr=False)
|
satori/server/__init__.py
CHANGED
|
@@ -7,13 +7,13 @@ import re
|
|
|
7
7
|
import secrets
|
|
8
8
|
import signal
|
|
9
9
|
import threading
|
|
10
|
+
import traceback
|
|
10
11
|
import urllib.parse
|
|
11
12
|
from collections.abc import Awaitable, Callable, Iterable
|
|
12
13
|
from contextlib import suppress
|
|
13
14
|
from itertools import chain
|
|
14
15
|
from pathlib import Path
|
|
15
16
|
from tempfile import TemporaryDirectory
|
|
16
|
-
from traceback import print_exc
|
|
17
17
|
from typing import Any, TypeVar
|
|
18
18
|
|
|
19
19
|
import aiohttp
|
|
@@ -103,10 +103,10 @@ async def _request_handler(action: str, request: StarletteRequest, func: RouteCa
|
|
|
103
103
|
return Response(status_code=504, content="Request timeout")
|
|
104
104
|
except ActionFailed as ae:
|
|
105
105
|
logger.warning(ae)
|
|
106
|
-
return Response(status_code=ae.CODE, content=
|
|
106
|
+
return Response(status_code=ae.CODE, content=repr(ae))
|
|
107
107
|
except Exception as e:
|
|
108
108
|
logger.error(e)
|
|
109
|
-
return Response(status_code=500, content=
|
|
109
|
+
return Response(status_code=500, content=repr(e))
|
|
110
110
|
if isinstance(res, ModelBase):
|
|
111
111
|
return JSONResponse(content=res.dump())
|
|
112
112
|
if res and isinstance(res, list) and isinstance(res[0], ModelBase):
|
|
@@ -239,16 +239,22 @@ class Server(Service, RouterMixin):
|
|
|
239
239
|
event.sn = self._sequence
|
|
240
240
|
self._event_cache.append(event)
|
|
241
241
|
self._sequence += 1
|
|
242
|
-
for
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
242
|
+
connections = [conn for conn in self.connections if conn.alive]
|
|
243
|
+
payload = {"op": Opcode.EVENT, "body": event.dump()}
|
|
244
|
+
ws_tasks = [conn.send(payload) for conn in connections]
|
|
245
|
+
if ws_tasks:
|
|
246
|
+
results = await asyncio.gather(*ws_tasks, return_exceptions=True)
|
|
247
|
+
for conn, result in zip(connections, results):
|
|
248
|
+
if not result:
|
|
249
|
+
continue
|
|
250
|
+
if isinstance(result, (WebSocketDisconnect, RuntimeError)):
|
|
251
|
+
logger.warning(f"Connection {id(conn):x} closed: {result}")
|
|
252
|
+
else:
|
|
253
|
+
traceback.print_exception(type(result), result, result.__traceback__)
|
|
254
|
+
logger.error(result)
|
|
255
|
+
await conn.connection_closed()
|
|
256
|
+
if conn in self.connections:
|
|
257
|
+
self.connections.remove(conn)
|
|
252
258
|
for hook in self.webhooks:
|
|
253
259
|
try:
|
|
254
260
|
async with self.session.post(
|
|
@@ -263,7 +269,7 @@ class Server(Service, RouterMixin):
|
|
|
263
269
|
) as resp:
|
|
264
270
|
resp.raise_for_status()
|
|
265
271
|
except Exception as e:
|
|
266
|
-
|
|
272
|
+
traceback.print_exception(type(e), e, e.__traceback__)
|
|
267
273
|
logger.error(e)
|
|
268
274
|
|
|
269
275
|
async def websocket_server_handler(self, ws: WebSocket):
|
satori/server/adapter.py
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
from abc import abstractmethod
|
|
2
|
-
from typing import TYPE_CHECKING, Union
|
|
2
|
+
from typing import TYPE_CHECKING, Generic, TypeVar, Union
|
|
3
3
|
|
|
4
4
|
from launart import Service
|
|
5
5
|
from starlette.responses import Response
|
|
@@ -16,10 +16,12 @@ if TYPE_CHECKING:
|
|
|
16
16
|
|
|
17
17
|
|
|
18
18
|
LoginType = Union[Login, LoginPartial] # noqa: UP007
|
|
19
|
+
T = TypeVar("T")
|
|
19
20
|
|
|
20
21
|
|
|
21
|
-
class Adapter(Service, RouterMixin):
|
|
22
|
+
class Adapter(Service, RouterMixin, Generic[T]):
|
|
22
23
|
server: "Server"
|
|
24
|
+
config: T
|
|
23
25
|
|
|
24
26
|
@abstractmethod
|
|
25
27
|
def get_platform(self) -> str:
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
satori/__init__.py,sha256=
|
|
1
|
+
satori/__init__.py,sha256=9-XGaPuZ5S-JE-Ew5MKGzQLQ2TzrPSLog__4k7td8CY,1888
|
|
2
2
|
satori/_vendor/fleep.py,sha256=_zKP7iY3mMQr0rC5KbgkbkMorT3KVLeIsWPLIUa0Y34,16347
|
|
3
|
-
satori/client/__init__.py,sha256=
|
|
3
|
+
satori/client/__init__.py,sha256=KZB5Ta5KzxdfCO8Ey5AuG7l4dzI0KnkqlaBVuyrfEMA,14481
|
|
4
4
|
satori/client/account.py,sha256=HP7BJWkN69SB9ldNIjHxWlXcrmB-IPnTnYqm3lBMvl8,2742
|
|
5
5
|
satori/client/account.pyi,sha256=ha632NYjlQDU65cjmYiP3eoPJnb82tMXuApLlUBwUKE,18744
|
|
6
|
-
satori/client/config.py,sha256=
|
|
6
|
+
satori/client/config.py,sha256=50y9RXHHUJ2noNEiREsri_MOM_6Waozvx6x2JOcOFd8,1919
|
|
7
7
|
satori/client/network/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
8
8
|
satori/client/network/base.py,sha256=0ajEhclVpVch-HMWLknoicexNe_keWW0dbLtboAtdtE,817
|
|
9
9
|
satori/client/network/util.py,sha256=WfVTjmYxj4EjrbR8r3zm7RJZjxmGQwC7yjZtXQT6SWE,1246
|
|
@@ -11,21 +11,21 @@ satori/client/network/webhook.py,sha256=N1zcJGx-Ijwtc0dIsPWzdnJSLi0ydQTengHBxtbb
|
|
|
11
11
|
satori/client/network/websocket.py,sha256=oZtiFLywP_Rw-_I-hl32nShCTTQ1XKlv0BhWJj53x9Y,8476
|
|
12
12
|
satori/client/protocol.py,sha256=hXrtgh-ypiF1W-dTl5I4LBWg8P2VTNKYQWFq8aRCeeo,28577
|
|
13
13
|
satori/const.py,sha256=6TQAIlgNq7fHLiadxGUU-mzkffOcpRrEvq5yrWYMuGc,2738
|
|
14
|
-
satori/element.py,sha256=
|
|
14
|
+
satori/element.py,sha256=7a1azqihsYBNe7BHGvN-MQH4jOsTj47Ei9h5qwDVu9M,21355
|
|
15
15
|
satori/event.py,sha256=yC6rKaa7JbeOZ4Un1rX-Isvm3EcR7e782nxYf1j6JdM,1060
|
|
16
16
|
satori/exception.py,sha256=edKeuLRZAQxyCdw1_XCgOtv5tIHkfHw0Die9B818_HM,545
|
|
17
17
|
satori/model.py,sha256=L8Wlk4zGlnR5kM4rAsaXvPufxdwmUsshkFY9PLGj8tY,17614
|
|
18
18
|
satori/parser.py,sha256=EyKitj39OewGhZuNIvrd8nWJiL5EJAVy7mtcv8Zk6v0,14658
|
|
19
19
|
satori/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
20
|
-
satori/server/__init__.py,sha256=
|
|
21
|
-
satori/server/adapter.py,sha256
|
|
20
|
+
satori/server/__init__.py,sha256=SumWaENrpRiZL7hLZpk8zcOJ-wvphHPMJjKwyhVzhDQ,24338
|
|
21
|
+
satori/server/adapter.py,sha256=sxP6XPcRmRSxxkXhnczXghLASYpMKgDYAebsGft_ud4,1661
|
|
22
22
|
satori/server/connection.py,sha256=28sDNT9QmTJknCRQAMB1jzxcRiG3Tw_TO0AFlCMNr5g,1439
|
|
23
23
|
satori/server/formdata.py,sha256=lHLTatf6117eC4U7FX77PjGvchEPiZGmVWnpe9tceh4,437
|
|
24
24
|
satori/server/model.py,sha256=zzjNa3iBFkd8crZIVTrEisPaB0g8JsxV4fA2rRU0maw,1105
|
|
25
25
|
satori/server/route.py,sha256=kpelAX0kYQbJncp5biWi8pWRcEIez9m9sJN8NF3sjn4,10654
|
|
26
26
|
satori/server/utils.py,sha256=hMNqLzbzcwyLJO-sGncO5kuviiW5Y6k34fj4AS2iVWQ,910
|
|
27
27
|
satori/utils.py,sha256=N8HEw-DOXxOBwFHmmXgqPdMh6AXjiGR0ZGa1zBPH6EI,822
|
|
28
|
-
satori_python-1.3.
|
|
29
|
-
satori_python-1.3.
|
|
30
|
-
satori_python-1.3.
|
|
31
|
-
satori_python-1.3.
|
|
28
|
+
satori_python-1.3.7.dist-info/METADATA,sha256=DraUqSrYvoBkX-l8wAmLmr04Nh1Oz6CSVcK-ngCnzE4,5511
|
|
29
|
+
satori_python-1.3.7.dist-info/WHEEL,sha256=rSwsxJWe3vzyR5HCwjWXQruDgschpei4h_giTm0dJVE,90
|
|
30
|
+
satori_python-1.3.7.dist-info/licenses/LICENSE,sha256=2EDswKd1M1648judap8BEEwp3Jz6IpfFP2wYVdU0Y2o,1069
|
|
31
|
+
satori_python-1.3.7.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|