Coverage for slidge/util/types.py: 99%
96 statements
« prev ^ index » next coverage.py v7.8.0, created at 2025-05-04 08:17 +0000
« prev ^ index » next coverage.py v7.8.0, created at 2025-05-04 08:17 +0000
1"""
2Typing stuff
3"""
5from dataclasses import dataclass
6from datetime import datetime
7from enum import IntEnum
8from pathlib import Path
9from typing import (
10 IO,
11 TYPE_CHECKING,
12 Any,
13 AsyncIterator,
14 Generic,
15 Hashable,
16 Literal,
17 NamedTuple,
18 Optional,
19 TypedDict,
20 TypeVar,
21 Union,
22)
24from slixmpp import Message, Presence
25from slixmpp.types import PresenceShows, PresenceTypes, ResourceDict
27if TYPE_CHECKING:
28 from ..contact import LegacyContact
29 from ..core.session import BaseSession
30 from ..group import LegacyMUC
31 from ..group.participant import LegacyParticipant
33 AnyBaseSession = BaseSession[Any, Any]
34else:
35 AnyBaseSession = None
38LegacyGroupIdType = TypeVar("LegacyGroupIdType", bound=Hashable)
39"""
40Type of the unique identifier for groups, usually a str or an int,
41but anything hashable should work.
42"""
43LegacyMessageType = TypeVar("LegacyMessageType", bound=Hashable)
44LegacyThreadType = TypeVar("LegacyThreadType", bound=Hashable)
45LegacyUserIdType = TypeVar("LegacyUserIdType", bound=Hashable)
47LegacyContactType = TypeVar("LegacyContactType", bound="LegacyContact[Any]")
48LegacyMUCType = TypeVar("LegacyMUCType", bound="LegacyMUC[Any, Any, Any, Any]")
49LegacyParticipantType = TypeVar("LegacyParticipantType", bound="LegacyParticipant")
51Recipient = Union["LegacyMUC[Any, Any, Any, Any]", "LegacyContact[Any]"]
52RecipientType = TypeVar("RecipientType", bound=Recipient)
53Sender = Union["LegacyContact[Any]", "LegacyParticipant"]
54LegacyFileIdType = Union[int, str]
56ChatState = Literal["active", "composing", "gone", "inactive", "paused"]
57ProcessingHint = Literal["no-store", "markable", "store"]
58Marker = Literal["acknowledged", "received", "displayed"]
59FieldType = Literal[
60 "boolean",
61 "fixed",
62 "text-single",
63 "jid-single",
64 "jid-multi",
65 "list-single",
66 "list-multi",
67 "text-private",
68]
69MucAffiliation = Literal["owner", "admin", "member", "outcast", "none"]
70MucRole = Literal["visitor", "participant", "moderator", "none"]
71# https://xmpp.org/registrar/disco-categories.html#client
72ClientType = Literal[
73 "bot", "console", "game", "handheld", "pc", "phone", "sms", "tablet", "web"
74]
77@dataclass
78class MessageReference(Generic[LegacyMessageType]):
79 """
80 A "message reply", ie a "quoted message" (:xep:`0461`)
82 At the very minimum, the legacy message ID attribute must be set, but to
83 ensure that the quote is displayed in all XMPP clients, the author must also
84 be set (use the string "user" if the slidge user is the author of the referenced
85 message).
86 The body is used as a fallback for XMPP clients that do not support :xep:`0461`
87 of that failed to find the referenced message.
88 """
90 legacy_id: LegacyMessageType
91 author: Optional[Union[Literal["user"], "LegacyParticipant", "LegacyContact"]] = (
92 None
93 )
94 body: Optional[str] = None
97@dataclass
98class LegacyAttachment:
99 """
100 A file attachment to a message
102 At the minimum, one of the ``path``, ``steam``, ``data`` or ``url`` attribute
103 has to be set
105 To be used with :meth:`.LegacyContact.send_files` or
106 :meth:`.LegacyParticipant.send_files`
107 """
109 path: Optional[Union[Path, str]] = None
110 name: Optional[Union[str]] = None
111 stream: Optional[IO[bytes]] = None
112 aio_stream: Optional[AsyncIterator[bytes]] = None
113 data: Optional[bytes] = None
114 content_type: Optional[str] = None
115 legacy_file_id: Optional[Union[str, int]] = None
116 url: Optional[str] = None
117 caption: Optional[str] = None
118 """
119 A caption for this specific image. For a global caption for a list of attachments,
120 use the ``body`` parameter of :meth:`.AttachmentMixin.send_files`
121 """
123 def __post_init__(self) -> None:
124 if all(
125 x is None
126 for x in (self.path, self.stream, self.data, self.url, self.aio_stream)
127 ):
128 raise TypeError("There is not data in this attachment", self)
129 if isinstance(self.path, str):
130 self.path = Path(self.path)
133class MucType(IntEnum):
134 """
135 The type of group, private, public, anonymous or not.
136 """
138 GROUP = 0
139 """
140 A private group, members-only and non-anonymous, eg a family group.
141 """
142 CHANNEL = 1
143 """
144 A public group, aka an anonymous channel.
145 """
146 CHANNEL_NON_ANONYMOUS = 2
147 """
148 A public group where participants' legacy IDs are visible to everybody.
149 """
152PseudoPresenceShow = Union[PresenceShows, Literal[""]]
155MessageOrPresenceTypeVar = TypeVar(
156 "MessageOrPresenceTypeVar", bound=Union[Message, Presence]
157)
160class LinkPreview(NamedTuple):
161 about: str
162 title: Optional[str]
163 description: Optional[str]
164 url: Optional[str]
165 image: Optional[str]
166 type: Optional[str]
167 site_name: Optional[str]
170class Mention(NamedTuple):
171 contact: "LegacyContact[Any]"
172 start: int
173 end: int
176class Hat(NamedTuple):
177 uri: str
178 title: str
181class UserPreferences(TypedDict):
182 sync_avatar: bool
183 sync_presence: bool
186class MamMetadata(NamedTuple):
187 id: str
188 sent_on: datetime
191class HoleBound(NamedTuple):
192 id: int | str
193 timestamp: datetime
196class CachedPresence(NamedTuple):
197 last_seen: Optional[datetime] = None
198 ptype: Optional[PresenceTypes] = None
199 pstatus: Optional[str] = None
200 pshow: Optional[PresenceShows] = None
203class Sticker(NamedTuple):
204 path: Path
205 content_type: Optional[str]
206 hashes: dict[str, str]
209class Avatar(NamedTuple):
210 path: Optional[Path] = None
211 unique_id: Optional[str | int] = None
212 url: Optional[str] = None
213 data: Optional[bytes] = None