Skip to content

Commit

Permalink
fix lint check error
Browse files Browse the repository at this point in the history
  • Loading branch information
Ovizro committed Dec 18, 2023
1 parent e0b9289 commit ca7ef23
Show file tree
Hide file tree
Showing 5 changed files with 92 additions and 39 deletions.
3 changes: 3 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ refresh: clean develop test lint
run:
python -m ${MODULE}

build:
python setup.py build

build_dist:
python setup.py sdist bdist_wheel

Expand Down
19 changes: 12 additions & 7 deletions karuha/bot.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@
import sys
from asyncio.queues import Queue, QueueEmpty
from collections import defaultdict
from contextlib import asynccontextmanager
from contextlib import asynccontextmanager, contextmanager
from enum import IntEnum
from typing import (Any, AsyncGenerator, Callable, Coroutine, Dict, List, Literal, Optional,
from typing import (Any, AsyncGenerator, Callable, Coroutine, Dict, Generator, List, Literal, Optional,
Union, overload)
from typing_extensions import Self, deprecated
from weakref import WeakSet, ref
Expand Down Expand Up @@ -250,9 +250,13 @@ async def send_message(self, wait_tid: Optional[str] = None, /, **kwds: Message)
:rtype: Optional[Message]
"""
client_msg = pb.ClientMsg(**kwds) # type: ignore
await self.queue.put(client_msg)
if wait_tid is not None:
return await self._wait_reply(wait_tid)
if wait_tid is None:
await self.queue.put(client_msg)
return

with self._wait_reply(wait_tid) as future:
await self.queue.put(client_msg)
return await future

async def async_run(self) -> None:
server = self.server
Expand Down Expand Up @@ -351,12 +355,13 @@ def _get_tid(self) -> str:
self._tid_counter += 1
return tid

async def _wait_reply(self, tid: Optional[str] = None) -> Any:
@contextmanager
def _wait_reply(self, tid: Optional[str] = None) -> Generator[asyncio.Future, None, None]:
tid = tid or self._get_tid()
future = asyncio.get_running_loop().create_future()
self._wait_list[tid] = future
try:
return await future
yield future
finally:
assert self._wait_list.pop(tid, None) is future

Expand Down
2 changes: 1 addition & 1 deletion karuha/event/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

class Event(object):
"""base class for all events"""

__slots__ = []

__handlers__: ClassVar[List[Callable[[Self], Coroutine]]] = []
Expand Down
101 changes: 73 additions & 28 deletions karuha/event/bot.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ def call_handler(self, handler: Callable[[Self], Coroutine]) -> Awaitable:
# Server Event Part
# =========================


class ServerEvent(BotEvent):
"""base class for all events from server"""

Expand All @@ -31,11 +31,11 @@ class ServerEvent(BotEvent):
def __init__(self, bot: "bot.Bot", message: Message) -> None:
super().__init__(bot)
self.server_message = message

def __init_subclass__(cls, on_field: str, **kwds: Any) -> None:
super().__init_subclass__(**kwds)
bot.Bot.server_event_map[on_field].append(cls.new)


class DataEvent(ServerEvent, on_field="data"):
"""
Expand All @@ -58,12 +58,17 @@ class DataEvent(ServerEvent, on_field="data"):
}
```
Data messages have a `seq` field which holds a sequential numeric ID generated by the server. The IDs are guaranteed to be unique within a topic. IDs start from 1 and sequentially increment with every successful [`{pub}`](#pub) message received by the topic.
See [Format of Content](https://github.com/tinode/chat/blob/master/docs/API.md#format-of-content) for `content` format considerations.
Data messages have a `seq` field which holds a sequential numeric ID generated by the server.
The IDs are guaranteed to be unique within a topic. IDs start from 1 and sequentially increment
with every successful [{pub}](https://github.com/tinode/chat/blob/master/docs/API.md#pub) message received by the topic.
See [Format of Content](https://github.com/tinode/chat/blob/master/docs/API.md#format-of-content)
for `content` format considerations.
See [{pub}](https://github.com/tinode/chat/blob/master/docs/API.md#pub) message for the possible values of the `head` field.
See [{pub}](https://github.com/tinode/chat/blob/master/docs/API.md#pub) message
for the possible values of the `head` field.
"""

__slots__ = []

server_message: pb.ServerData
Expand All @@ -87,14 +92,16 @@ class CtrlEvent(ServerEvent, on_field="ctrl"):
}
```
"""

__slots__ = []

server_message: pb.ServerCtrl


class MetaEvent(ServerEvent, on_field="meta"):
"""
Information about topic metadata or subscribers, sent in response to `{get}`, `{set}` or `{sub}` message to the originating session.
Information about topic metadata or subscribers, sent in response to `{get}`,
`{set}` or `{sub}` message to the originating session.
```js
meta: {
Expand Down Expand Up @@ -198,14 +205,16 @@ class MetaEvent(ServerEvent, on_field="meta"):
}
```
"""

__slots__ = []

server_message: pb.ServerMeta


class PresEvent(ServerEvent, on_field="pres"):
"""
Tinode uses `{pres}` message to inform clients of important events. A separate [document](https://docs.google.com/spreadsheets/d/e/2PACX-1vStUDHb7DPrD8tF5eANLu4YIjRkqta8KOhLvcj2precsjqR40eDHvJnnuuS3bw-NcWsP1QKc7GSTYuX/pubhtml?gid=1959642482&single=true) explains all possible use cases.
Tinode uses `{pres}` message to inform clients of important events.
A separate [document](https://docs.google.com/spreadsheets/d/e/2PACX-1vStUDHb7DPrD8tF5eANLu4YIjRkqta8KOhLvcj2precsjqR40eDHvJnnuuS3bw-NcWsP1QKc7GSTYuX/pubhtml?gid=1959642482&single=true) explains all possible use cases.
```js
pres: {
Expand Down Expand Up @@ -242,18 +251,23 @@ class PresEvent(ServerEvent, on_field="pres"):
* del: messages were deleted
The `{pres}` messages are purely transient: they are not stored and no attempt is made to deliver them later if the destination is temporarily unavailable.
The `{pres}` messages are purely transient: they are not stored and no attempt is made
to deliver them later if the destination is temporarily unavailable.
Timestamp is not present in `{pres}` messages.
"""
""" # noqa

__slots__ = []

server_message: pb.ServerPres


class InfoEvent(ServerEvent, on_field="info"):
"""
Forwarded client-generated notification `{note}`. Server guarantees that the message complies with this specification and that content of `topic` and `from` fields is correct. The other content is copied from the `{note}` message verbatim and may potentially be incorrect or misleading if the originator so desires.
Forwarded client-generated notification `{note}`. Server guarantees that the message complies
with this specification and that content of `topic` and `from` fields is correct.
The other content is copied from the `{note}` message verbatim and
may potentially be incorrect or misleading if the originator so desires.
```js
info: {
Expand All @@ -268,6 +282,7 @@ class InfoEvent(ServerEvent, on_field="info"):
}
```
"""

__slots__ = []

server_message: pb.ServerInfo
Expand Down Expand Up @@ -297,21 +312,33 @@ class PublishEvent(ClientEvent):
}
```
Topic subscribers receive the `content` in the [`{data}`](#data) message. By default the originating session gets a copy of `{data}` like any other session currently attached to the topic. If for some reason the originating session does not want to receive the copy of the data it just published, set `noecho` to `true`.
Topic subscribers receive the `content` in the [`{data}`](#data) message.
By default the originating session gets a copy of `{data}`
like any other session currently attached to the topic.
If for some reason the originating session does not want to receive
the copy of the data it just published, set `noecho` to `true`.
See [Format of Content](https://github.com/tinode/chat/blob/master/docs/API.md#format-of-content) for `content` format considerations.
See [Format of Content](https://github.com/tinode/chat/blob/master/docs/API.md#format-of-content)
for `content` format considerations.
The following values are currently defined for the `head` field:
* `attachments`: an array of paths indicating media attached to this message `["/v0/file/s/sJOD_tZDPz0.jpg"]`.
* `auto`: `true` when the message was sent automatically, i.e. by a chatbot or an auto-responder.
* `forwarded`: an indicator that the message is a forwarded message, a unique ID of the original message, `"grp1XUtEhjv6HND:123"`.
* `forwarded`: an indicator that the message is a forwarded message,
a unique ID of the original message, `"grp1XUtEhjv6HND:123"`.
* `mentions`: an array of user IDs mentioned (`@alice`) in the message: `["usr1XUtEhjv6HND", "usr2il9suCbuko"]`.
* `mime`: MIME-type of the message content, `"text/x-drafty"`; a `null` or a missing value is interpreted as `"text/plain"`.
* `replace`: an indicator that the message is a correction/replacement for another message, a topic-unique ID of the message being updated/replaced, `":123"`
* `reply`: an indicator that the message is a reply to another message, a unique ID of the original message, `"grp1XUtEhjv6HND:123"`.
* `sender`: a user ID of the sender added by the server when the message is sent on behalf of another user, `"usr1XUtEhjv6HND"`.
* `thread`: an indicator that the message is a part of a conversation thread, a topic-unique ID of the first message in the thread, `":123"`; `thread` is intended for tagging a flat list of messages as opposite to creating a tree.
* `mime`: MIME-type of the message content, `"text/x-drafty"`;
a `null` or a missing value is interpreted as `"text/plain"`.
* `replace`: an indicator that the message is a correction/replacement for another message,
a topic-unique ID of the message being updated/replaced, `":123"`
* `reply`: an indicator that the message is a reply to another message,
a unique ID of the original message, `"grp1XUtEhjv6HND:123"`.
* `sender`: a user ID of the sender added by the server when the message is sent
on behalf of another user, `"usr1XUtEhjv6HND"`.
* `thread`: an indicator that the message is a part of a conversation thread,
a topic-unique ID of the first message in the thread, `":123"`;
`thread` is intended for tagging a flat list of messages as opposite to creating a tree.
* `webrtc`: a string representing the state of the video call the message represents. Possible values:
* `"started"`: call has been initiated and being established
* `"accepted"`: call has been accepted and established
Expand All @@ -322,10 +349,13 @@ class PublishEvent(ClientEvent):
* `"disconnected"`: call was terminated by the server for other reasons (e.g. due to an error)
* `webrtc-duration`: a number representing a video call duration (in milliseconds).
Application-specific fields should start with an `x-<application-name>-`. Although the server does not enforce this rule yet, it may start doing so in the future.
Application-specific fields should start with an `x-<application-name>-`.
Although the server does not enforce this rule yet, it may start doing so in the future.
The unique message ID should be formed as `<topic_name>:<seqId>` whenever possible, such as `"grp1XUtEhjv6HND:123"`. If the topic is omitted, i.e. `":123"`, it's assumed to be the current topic.
The unique message ID should be formed as `<topic_name>:<seqId>` whenever possible, such as `"grp1XUtEhjv6HND:123"`.
If the topic is omitted, i.e. `":123"`, it's assumed to be the current topic.
"""

__slots__ = ["text", "topic"]

def __init__(self, bot: "bot.Bot", topic: str, text: Union[str, Drafty, BaseText]) -> None:
Expand All @@ -342,20 +372,31 @@ class SubscribeEvent(ClientEvent):
* attaching session to a previously subscribed topic
* fetching topic data
User creates a new group topic by sending `{sub}` packet with the `topic` field set to `new12321` (regular topic) or `nch12321` (channel) where `12321` denotes any string including an empty string. Server will create a topic and respond back to the session with the name of the newly created topic.
User creates a new group topic by sending `{sub}` packet with the `topic` field set
to `new12321` (regular topic) or `nch12321` (channel) where `12321` denotes any string including an empty string.
Server will create a topic and respond back to the session with the name of the newly created topic.
User creates a new peer to peer topic by sending `{sub}` packet with `topic` set to peer's user ID.
The user is always subscribed to and the session is attached to the newly created topic.
If the user had no relationship with the topic, sending `{sub}` packet creates it. Subscribing means to establish a relationship between session's user and the topic where no relationship existed in the past.
If the user had no relationship with the topic, sending `{sub}` packet creates it.
Subscribing means to establish a relationship between session's user and
the topic where no relationship existed in the past.
Joining (attaching to) a topic means for the session to start consuming content from the topic. Server automatically differentiates between subscribing and joining/attaching based on context: if the user had no prior relationship with the topic, the server subscribes the user then attaches the current session to the topic. If relationship existed, the server only attaches the session to the topic. When subscribing, the server checks user's access permissions against topic's access control list. It may grant immediate access, deny access, may generate a request for approval from topic managers.
Joining (attaching to) a topic means for the session to start consuming content from the topic.
Server automatically differentiates between subscribing and joining/attaching based on context:
if the user had no prior relationship with the topic, the server subscribes the user
then attaches the current session to the topic.
If relationship existed, the server only attaches the session to the topic.
When subscribing, the server checks user's access permissions against topic's access control list.
It may grant immediate access, deny access, may generate a request for approval from topic managers.
Server replies to the `{sub}` with a `{ctrl}`.
The `{sub}` message may include a `get` and `set` fields which mirror `{get}` and `{set}` messages. If included, server will treat them as a subsequent `{set}` and `{get}` messages on the same topic. If the `get` is set, the reply may include `{meta}` and `{data}` messages.
The `{sub}` message may include a `get` and `set` fields which mirror `{get}` and `{set}` messages.
If included, server will treat them as a subsequent `{set}` and `{get}` messages on the same topic. If the `get` is set,
the reply may include `{meta}` and `{data}` messages.
```js
sub: {
Expand Down Expand Up @@ -434,6 +475,7 @@ class SubscribeEvent(ClientEvent):
}
```
"""

__slots__ = ["topic", "since"]

def __init__(self, bot: "bot.Bot", topic: str, *, since: Optional[int] = None) -> None:
Expand All @@ -448,7 +490,9 @@ class LeaveEvent(ClientEvent):
* leaving the topic without unsubscribing (`unsub=false`)
* unsubscribing (`unsub=true`)
Server responds to `{leave}` with a `{ctrl}` packet. Leaving without unsubscribing affects just the current session. Leaving with unsubscribing will affect all user's sessions.
Server responds to `{leave}` with a `{ctrl}` packet.
Leaving without unsubscribing affects just the current session.
Leaving with unsubscribing will affect all user's sessions.
```js
leave: {
Expand All @@ -459,6 +503,7 @@ class LeaveEvent(ClientEvent):
}
```
"""

__slots__ = ["topic"]

def __init__(self, bot: "bot.Bot", topic: str) -> None:
Expand Down
6 changes: 3 additions & 3 deletions karuha/event/dispatcher.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ def deactivate(self) -> None:
self.dispatchers.remove(self)

@classmethod
def dispatch(cls, message: T) -> None:
def dispatch(cls, message: T, /) -> None:
if not cls.dispatchers:
return
selected = max(
Expand All @@ -44,9 +44,9 @@ def activated(self) -> bool:
class FutureDispatcher(AbstractDispatcher[T]):
__slots__ = ["future"]

def __init__(self, future: asyncio.Future) -> None:
def __init__(self, /, future: asyncio.Future) -> None:
super().__init__()
self.future = future

def run(self, message: T) -> None:
def run(self, message: T, /) -> None:
self.future.set_result(message)

0 comments on commit ca7ef23

Please sign in to comment.