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

1""" 

2Typing stuff 

3""" 

4 

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) 

23 

24from slixmpp import Message, Presence 

25from slixmpp.types import PresenceShows, PresenceTypes, ResourceDict 

26 

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 

32 

33 AnyBaseSession = BaseSession[Any, Any] 

34else: 

35 AnyBaseSession = None 

36 

37 

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) 

46 

47LegacyContactType = TypeVar("LegacyContactType", bound="LegacyContact[Any]") 

48LegacyMUCType = TypeVar("LegacyMUCType", bound="LegacyMUC[Any, Any, Any, Any]") 

49LegacyParticipantType = TypeVar("LegacyParticipantType", bound="LegacyParticipant") 

50 

51Recipient = Union["LegacyMUC[Any, Any, Any, Any]", "LegacyContact[Any]"] 

52RecipientType = TypeVar("RecipientType", bound=Recipient) 

53Sender = Union["LegacyContact[Any]", "LegacyParticipant"] 

54LegacyFileIdType = Union[int, str] 

55 

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] 

75 

76 

77@dataclass 

78class MessageReference(Generic[LegacyMessageType]): 

79 """ 

80 A "message reply", ie a "quoted message" (:xep:`0461`) 

81 

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 """ 

89 

90 legacy_id: LegacyMessageType 

91 author: Optional[Union[Literal["user"], "LegacyParticipant", "LegacyContact"]] = ( 

92 None 

93 ) 

94 body: Optional[str] = None 

95 

96 

97@dataclass 

98class LegacyAttachment: 

99 """ 

100 A file attachment to a message 

101 

102 At the minimum, one of the ``path``, ``steam``, ``data`` or ``url`` attribute 

103 has to be set 

104 

105 To be used with :meth:`.LegacyContact.send_files` or 

106 :meth:`.LegacyParticipant.send_files` 

107 """ 

108 

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 """ 

122 

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) 

131 

132 

133class MucType(IntEnum): 

134 """ 

135 The type of group, private, public, anonymous or not. 

136 """ 

137 

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 """ 

150 

151 

152PseudoPresenceShow = Union[PresenceShows, Literal[""]] 

153 

154 

155MessageOrPresenceTypeVar = TypeVar( 

156 "MessageOrPresenceTypeVar", bound=Union[Message, Presence] 

157) 

158 

159 

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] 

168 

169 

170class Mention(NamedTuple): 

171 contact: "LegacyContact[Any]" 

172 start: int 

173 end: int 

174 

175 

176class Hat(NamedTuple): 

177 uri: str 

178 title: str 

179 

180 

181class UserPreferences(TypedDict): 

182 sync_avatar: bool 

183 sync_presence: bool 

184 

185 

186class MamMetadata(NamedTuple): 

187 id: str 

188 sent_on: datetime 

189 

190 

191class HoleBound(NamedTuple): 

192 id: int | str 

193 timestamp: datetime 

194 

195 

196class CachedPresence(NamedTuple): 

197 last_seen: Optional[datetime] = None 

198 ptype: Optional[PresenceTypes] = None 

199 pstatus: Optional[str] = None 

200 pshow: Optional[PresenceShows] = None 

201 

202 

203class Sticker(NamedTuple): 

204 path: Path 

205 content_type: Optional[str] 

206 hashes: dict[str, str] 

207 

208 

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