Mercurial > libervia-backend
comparison sat/tools/common/data_objects.py @ 3028:ab2696e34d29
Python 3 port:
/!\ this is a huge commit
/!\ starting from this commit, SàT is needs Python 3.6+
/!\ SàT maybe be instable or some feature may not work anymore, this will improve with time
This patch port backend, bridge and frontends to Python 3.
Roughly this has been done this way:
- 2to3 tools has been applied (with python 3.7)
- all references to python2 have been replaced with python3 (notably shebangs)
- fixed files not handled by 2to3 (notably the shell script)
- several manual fixes
- fixed issues reported by Python 3 that where not handled in Python 2
- replaced "async" with "async_" when needed (it's a reserved word from Python 3.7)
- replaced zope's "implements" with @implementer decorator
- temporary hack to handle data pickled in database, as str or bytes may be returned,
to be checked later
- fixed hash comparison for password
- removed some code which is not needed anymore with Python 3
- deactivated some code which needs to be checked (notably certificate validation)
- tested with jp, fixed reported issues until some basic commands worked
- ported Primitivus (after porting dependencies like urwid satext)
- more manual fixes
author | Goffi <goffi@goffi.org> |
---|---|
date | Tue, 13 Aug 2019 19:08:41 +0200 |
parents | 8dbef2d190eb |
children | 9d0df638c8b4 |
comparison
equal
deleted
inserted
replaced
3027:ff5bcb12ae60 | 3028:ab2696e34d29 |
---|---|
1 #!/usr/bin/env python2 | 1 #!/usr/bin/env python3 |
2 # -*- coding: utf-8 -*- | 2 # -*- coding: utf-8 -*- |
3 | 3 |
4 # SAT: a jabber client | 4 # SAT: a jabber client |
5 # Copyright (C) 2009-2019 Jérôme Poisson (goffi@goffi.org) | 5 # Copyright (C) 2009-2019 Jérôme Poisson (goffi@goffi.org) |
6 | 6 |
23 from sat.tools.common import data_format | 23 from sat.tools.common import data_format |
24 | 24 |
25 try: | 25 try: |
26 from jinja2 import Markup as safe | 26 from jinja2 import Markup as safe |
27 except ImportError: | 27 except ImportError: |
28 safe = unicode | 28 safe = str |
29 | 29 |
30 from sat.tools.common import uri as xmpp_uri | 30 from sat.tools.common import uri as xmpp_uri |
31 import urllib | 31 import urllib.request, urllib.parse, urllib.error |
32 | 32 |
33 q = lambda value: urllib.quote(value.encode("utf-8"), safe="@") | 33 q = lambda value: urllib.parse.quote(value.encode("utf-8"), safe="@") |
34 | 34 |
35 | 35 |
36 def parsePubSubMetadata(metadata, items): | 36 def parsePubSubMetadata(metadata, items): |
37 """Helper method to have nicer metadata while doing a PubSub request | 37 """Helper method to have nicer metadata while doing a PubSub request |
38 | 38 |
47 @return (dict): parsed metadata | 47 @return (dict): parsed metadata |
48 """ | 48 """ |
49 data = {} | 49 data = {} |
50 assert "complete" not in metadata | 50 assert "complete" not in metadata |
51 | 51 |
52 for key, value in metadata.iteritems(): | 52 for key, value in metadata.items(): |
53 if key in (u"rsm_index", u"rsm_count"): | 53 if key in ("rsm_index", "rsm_count"): |
54 value = int(value) | 54 value = int(value) |
55 elif key == u"mam_stable": | 55 elif key == "mam_stable": |
56 value = C.bool(value) | 56 value = C.bool(value) |
57 elif key == u"mam_complete": | 57 elif key == "mam_complete": |
58 key = u"complete" | 58 key = "complete" |
59 value = C.bool(value) | 59 value = C.bool(value) |
60 data[key] = value | 60 data[key] = value |
61 if u"complete" not in data: | 61 if "complete" not in data: |
62 index = data.get(u"rsm_index") | 62 index = data.get("rsm_index") |
63 count = data.get(u"rsm_count") | 63 count = data.get("rsm_count") |
64 if index is None or count is None: | 64 if index is None or count is None: |
65 # we don't have enough information to know if the data is complete or not | 65 # we don't have enough information to know if the data is complete or not |
66 data[u"complete"] = None | 66 data["complete"] = None |
67 else: | 67 else: |
68 # normally we have a strict equality here but XEP-0059 states | 68 # normally we have a strict equality here but XEP-0059 states |
69 # that index MAY be approximative, so just in case… | 69 # that index MAY be approximative, so just in case… |
70 data[u"complete"] = index + len(items) >= count | 70 data["complete"] = index + len(items) >= count |
71 return data | 71 return data |
72 | 72 |
73 | 73 |
74 class BlogItem(object): | 74 class BlogItem(object): |
75 def __init__(self, mb_data, parent, deserialise=True): | 75 def __init__(self, mb_data, parent, deserialise=True): |
86 self._comments = None | 86 self._comments = None |
87 self._comments_items_list = None | 87 self._comments_items_list = None |
88 | 88 |
89 @property | 89 @property |
90 def id(self): | 90 def id(self): |
91 return self.mb_data.get(u"id") | 91 return self.mb_data.get("id") |
92 | 92 |
93 @property | 93 @property |
94 def atom_id(self): | 94 def atom_id(self): |
95 return self.mb_data.get(u"atom_id") | 95 return self.mb_data.get("atom_id") |
96 | 96 |
97 @property | 97 @property |
98 def uri(self): | 98 def uri(self): |
99 node = self.parent.node | 99 node = self.parent.node |
100 service = self.parent.service | 100 service = self.parent.service |
101 return xmpp_uri.buildXMPPUri( | 101 return xmpp_uri.buildXMPPUri( |
102 u"pubsub", subtype=u"microblog", path=service, node=node, item=self.id | 102 "pubsub", subtype="microblog", path=service, node=node, item=self.id |
103 ) | 103 ) |
104 | 104 |
105 @property | 105 @property |
106 def published(self): | 106 def published(self): |
107 return self.mb_data.get(u"published") | 107 return self.mb_data.get("published") |
108 | 108 |
109 @property | 109 @property |
110 def updated(self): | 110 def updated(self): |
111 return self.mb_data.get(u"updated") | 111 return self.mb_data.get("updated") |
112 | 112 |
113 @property | 113 @property |
114 def language(self): | 114 def language(self): |
115 return self.mb_data.get(u"language") | 115 return self.mb_data.get("language") |
116 | 116 |
117 @property | 117 @property |
118 def author(self): | 118 def author(self): |
119 return self.mb_data.get(u"author") | 119 return self.mb_data.get("author") |
120 | 120 |
121 @property | 121 @property |
122 def author_jid(self): | 122 def author_jid(self): |
123 return self.mb_data.get(u"author_jid") | 123 return self.mb_data.get("author_jid") |
124 | 124 |
125 @property | 125 @property |
126 def author_jid_verified(self): | 126 def author_jid_verified(self): |
127 return self.mb_data.get(u"author_jid_verified") | 127 return self.mb_data.get("author_jid_verified") |
128 | 128 |
129 @property | 129 @property |
130 def author_email(self): | 130 def author_email(self): |
131 return self.mb_data.get(u"author_email") | 131 return self.mb_data.get("author_email") |
132 | 132 |
133 @property | 133 @property |
134 def tags(self): | 134 def tags(self): |
135 return self.mb_data.get(u'tags', []) | 135 return self.mb_data.get('tags', []) |
136 | 136 |
137 @property | 137 @property |
138 def groups(self): | 138 def groups(self): |
139 return self.mb_data.get(u'groups', []) | 139 return self.mb_data.get('groups', []) |
140 | 140 |
141 @property | 141 @property |
142 def title(self): | 142 def title(self): |
143 return self.mb_data.get(u"title") | 143 return self.mb_data.get("title") |
144 | 144 |
145 @property | 145 @property |
146 def title_xhtml(self): | 146 def title_xhtml(self): |
147 try: | 147 try: |
148 return safe(self.mb_data[u"title_xhtml"]) | 148 return safe(self.mb_data["title_xhtml"]) |
149 except KeyError: | 149 except KeyError: |
150 return None | 150 return None |
151 | 151 |
152 @property | 152 @property |
153 def content(self): | 153 def content(self): |
154 return self.mb_data.get(u"content") | 154 return self.mb_data.get("content") |
155 | 155 |
156 @property | 156 @property |
157 def content_xhtml(self): | 157 def content_xhtml(self): |
158 try: | 158 try: |
159 return safe(self.mb_data[u"content_xhtml"]) | 159 return safe(self.mb_data["content_xhtml"]) |
160 except KeyError: | 160 except KeyError: |
161 return None | 161 return None |
162 | 162 |
163 @property | 163 @property |
164 def comments(self): | 164 def comments(self): |
165 if self._comments is None: | 165 if self._comments is None: |
166 self._comments = data_format.dict2iterdict( | 166 self._comments = data_format.dict2iterdict( |
167 u"comments", self.mb_data, (u"node", u"service") | 167 "comments", self.mb_data, ("node", "service") |
168 ) | 168 ) |
169 return self._comments | 169 return self._comments |
170 | 170 |
171 @property | 171 @property |
172 def comments_service(self): | 172 def comments_service(self): |
173 return self.mb_data.get(u"comments_service") | 173 return self.mb_data.get("comments_service") |
174 | 174 |
175 @property | 175 @property |
176 def comments_node(self): | 176 def comments_node(self): |
177 return self.mb_data.get(u"comments_node") | 177 return self.mb_data.get("comments_node") |
178 | 178 |
179 @property | 179 @property |
180 def comments_items_list(self): | 180 def comments_items_list(self): |
181 return [] if self._comments_items_list is None else self._comments_items_list | 181 return [] if self._comments_items_list is None else self._comments_items_list |
182 | 182 |
197 self.items = [BlogItem(i, self, deserialise=deserialise) for i in mb_data[0]] | 197 self.items = [BlogItem(i, self, deserialise=deserialise) for i in mb_data[0]] |
198 self.metadata = parsePubSubMetadata(mb_data[1], self.items) | 198 self.metadata = parsePubSubMetadata(mb_data[1], self.items) |
199 | 199 |
200 @property | 200 @property |
201 def service(self): | 201 def service(self): |
202 return self.metadata[u"service"] | 202 return self.metadata["service"] |
203 | 203 |
204 @property | 204 @property |
205 def node(self): | 205 def node(self): |
206 return self.metadata[u"node"] | 206 return self.metadata["node"] |
207 | 207 |
208 @property | 208 @property |
209 def uri(self): | 209 def uri(self): |
210 return self.metadata[u"uri"] | 210 return self.metadata["uri"] |
211 | 211 |
212 @property | 212 @property |
213 def with_rsm(self): | 213 def with_rsm(self): |
214 """Return True if RSM is activated on this request""" | 214 """Return True if RSM is activated on this request""" |
215 return u"rsm_first" in self.metadata | 215 return "rsm_first" in self.metadata |
216 | 216 |
217 @property | 217 @property |
218 def rsm_first(self): | 218 def rsm_first(self): |
219 return self.metadata[u"rsm_first"] | 219 return self.metadata["rsm_first"] |
220 | 220 |
221 @property | 221 @property |
222 def rsm_last(self): | 222 def rsm_last(self): |
223 return self.metadata[u"rsm_last"] | 223 return self.metadata["rsm_last"] |
224 | 224 |
225 @property | 225 @property |
226 def rsm_index(self): | 226 def rsm_index(self): |
227 return self.metadata[u"rsm_index"] | 227 return self.metadata["rsm_index"] |
228 | 228 |
229 @property | 229 @property |
230 def rsm_count(self): | 230 def rsm_count(self): |
231 return self.metadata[u"rsm_count"] | 231 return self.metadata["rsm_count"] |
232 | 232 |
233 @property | 233 @property |
234 def complete(self): | 234 def complete(self): |
235 return self.metadata[u"complete"] | 235 return self.metadata["complete"] |
236 | 236 |
237 def __len__(self): | 237 def __len__(self): |
238 return self.items.__len__() | 238 return self.items.__len__() |
239 | 239 |
240 def __missing__(self, key): | 240 def __missing__(self, key): |
280 @property | 280 @property |
281 def text(self): | 281 def text(self): |
282 try: | 282 try: |
283 return self._message_data[""] | 283 return self._message_data[""] |
284 except KeyError: | 284 except KeyError: |
285 return next(self._message_data.itervalues()) | 285 return next(iter(self._message_data.values())) |
286 | 286 |
287 @property | 287 @property |
288 def subject(self): | 288 def subject(self): |
289 try: | 289 try: |
290 return self._subject_data[""] | 290 return self._subject_data[""] |
291 except KeyError: | 291 except KeyError: |
292 return next(self._subject_data.itervalues()) | 292 return next(iter(self._subject_data.values())) |
293 | 293 |
294 @property | 294 @property |
295 def type(self): | 295 def type(self): |
296 return self._type | 296 return self._type |
297 | 297 |
320 if not self._html: | 320 if not self._html: |
321 return None | 321 return None |
322 try: | 322 try: |
323 return safe(self._html[""]) | 323 return safe(self._html[""]) |
324 except KeyError: | 324 except KeyError: |
325 return safe(next(self._html.itervalues())) | 325 return safe(next(iter(self._html.values()))) |
326 | 326 |
327 | 327 |
328 class Messages(object): | 328 class Messages(object): |
329 def __init__(self, msgs_data): | 329 def __init__(self, msgs_data): |
330 self.messages = [Message(m) for m in msgs_data] | 330 self.messages = [Message(m) for m in msgs_data] |
417 """format URL using Python formatting | 417 """format URL using Python formatting |
418 | 418 |
419 values will be quoted before being used | 419 values will be quoted before being used |
420 """ | 420 """ |
421 return self.url.format( | 421 return self.url.format( |
422 *[q(a) for a in args], **{k: ObjectQuoter(v) for k, v in kwargs.iteritems()} | 422 *[q(a) for a in args], **{k: ObjectQuoter(v) for k, v in kwargs.items()} |
423 ) | 423 ) |