Mercurial > libervia-backend
comparison sat/plugins/plugin_misc_text_syntaxes.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 | a02ad4bc0a6d |
children | fee60f17ebac |
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 plugin for managing various text syntaxes | 4 # SAT plugin for managing various text syntaxes |
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 |
33 from lxml import html | 33 from lxml import html |
34 from lxml.html import clean | 34 from lxml.html import clean |
35 from lxml import etree | 35 from lxml import etree |
36 except ImportError: | 36 except ImportError: |
37 raise exceptions.MissingModule( | 37 raise exceptions.MissingModule( |
38 u"Missing module lxml, please download/install it from http://lxml.de/" | 38 "Missing module lxml, please download/install it from http://lxml.de/" |
39 ) | 39 ) |
40 | 40 |
41 log = getLogger(__name__) | 41 log = getLogger(__name__) |
42 | 42 |
43 CATEGORY = D_("Composition") | 43 CATEGORY = D_("Composition") |
216 self.addSyntax( | 216 self.addSyntax( |
217 self.SYNTAX_MARKDOWN, | 217 self.SYNTAX_MARKDOWN, |
218 partial(markdown.markdown, | 218 partial(markdown.markdown, |
219 extensions=[ | 219 extensions=[ |
220 EscapeHTML(), | 220 EscapeHTML(), |
221 u'nl2br', | 221 'nl2br', |
222 u'codehilite', | 222 'codehilite', |
223 u'fenced_code', | 223 'fenced_code', |
224 u'sane_lists', | 224 'sane_lists', |
225 u'tables', | 225 'tables', |
226 ], | 226 ], |
227 extension_configs = { | 227 extension_configs = { |
228 u"codehilite": { | 228 "codehilite": { |
229 u"css_class": "highlight", | 229 "css_class": "highlight", |
230 } | 230 } |
231 }), | 231 }), |
232 _html2text, | 232 _html2text, |
233 [TextSyntaxes.OPT_DEFAULT], | 233 [TextSyntaxes.OPT_DEFAULT], |
234 ) | 234 ) |
235 except ImportError: | 235 except ImportError: |
236 log.warning(u"markdown or html2text not found, can't use Markdown syntax") | 236 log.warning("markdown or html2text not found, can't use Markdown syntax") |
237 log.info( | 237 log.info( |
238 u"You can download/install them from https://pythonhosted.org/Markdown/ and https://github.com/Alir3z4/html2text/" | 238 "You can download/install them from https://pythonhosted.org/Markdown/ and https://github.com/Alir3z4/html2text/" |
239 ) | 239 ) |
240 host.bridge.addMethod( | 240 host.bridge.addMethod( |
241 "syntaxConvert", | 241 "syntaxConvert", |
242 ".plugin", | 242 ".plugin", |
243 in_sign="sssbs", | 243 in_sign="sssbs", |
244 out_sign="s", | 244 out_sign="s", |
245 async=True, | 245 async_=True, |
246 method=self.convert, | 246 method=self.convert, |
247 ) | 247 ) |
248 host.bridge.addMethod( | 248 host.bridge.addMethod( |
249 "syntaxGet", ".plugin", in_sign="s", out_sign="s", method=self.getSyntax | 249 "syntaxGet", ".plugin", in_sign="s", out_sign="s", method=self.getSyntax |
250 ) | 250 ) |
251 if xml_tools.cleanXHTML is None: | 251 if xml_tools.cleanXHTML is None: |
252 log.debug(u"Installing cleaning method") | 252 log.debug("Installing cleaning method") |
253 xml_tools.cleanXHTML = self.cleanXHTML | 253 xml_tools.cleanXHTML = self.cleanXHTML |
254 | 254 |
255 def _updateParamOptions(self): | 255 def _updateParamOptions(self): |
256 data_synt = TextSyntaxes.syntaxes | 256 data_synt = TextSyntaxes.syntaxes |
257 default_synt = TextSyntaxes.default_syntax | 257 default_synt = TextSyntaxes.default_syntax |
258 syntaxes = [] | 258 syntaxes = [] |
259 | 259 |
260 for syntax in data_synt.keys(): | 260 for syntax in list(data_synt.keys()): |
261 flags = data_synt[syntax]["flags"] | 261 flags = data_synt[syntax]["flags"] |
262 if TextSyntaxes.OPT_HIDDEN not in flags: | 262 if TextSyntaxes.OPT_HIDDEN not in flags: |
263 syntaxes.append(syntax) | 263 syntaxes.append(syntax) |
264 | 264 |
265 syntaxes.sort(key=lambda synt: synt.lower()) | 265 syntaxes.sort(key=lambda synt: synt.lower()) |
266 options = [] | 266 options = [] |
267 | 267 |
268 for syntax in syntaxes: | 268 for syntax in syntaxes: |
269 selected = 'selected="true"' if syntax == default_synt else "" | 269 selected = 'selected="true"' if syntax == default_synt else "" |
270 options.append(u'<option value="%s" %s/>' % (syntax, selected)) | 270 options.append('<option value="%s" %s/>' % (syntax, selected)) |
271 | 271 |
272 TextSyntaxes.params_data["options"] = u"\n".join(options) | 272 TextSyntaxes.params_data["options"] = "\n".join(options) |
273 self.host.memory.updateParams(TextSyntaxes.params % TextSyntaxes.params_data) | 273 self.host.memory.updateParams(TextSyntaxes.params % TextSyntaxes.params_data) |
274 | 274 |
275 def getCurrentSyntax(self, profile): | 275 def getCurrentSyntax(self, profile): |
276 """ Return the selected syntax for the given profile | 276 """ Return the selected syntax for the given profile |
277 | 277 |
278 @param profile: %(doc_profile)s | 278 @param profile: %(doc_profile)s |
279 @return: profile selected syntax | 279 @return: profile selected syntax |
280 """ | 280 """ |
281 return self.host.memory.getParamA(NAME, CATEGORY, profile_key=profile) | 281 return self.host.memory.getParamA(NAME, CATEGORY, profile_key=profile) |
282 | 282 |
283 def _logError(self, failure, action=u"converting syntax"): | 283 def _logError(self, failure, action="converting syntax"): |
284 log.error( | 284 log.error( |
285 u"Error while {action}: {failure}".format(action=action, failure=failure) | 285 "Error while {action}: {failure}".format(action=action, failure=failure) |
286 ) | 286 ) |
287 return failure | 287 return failure |
288 | 288 |
289 def cleanStyle(self, styles): | 289 def cleanStyle(self, styles): |
290 """"Clean unsafe CSS styles | 290 """"Clean unsafe CSS styles |
318 | 318 |
319 @param xhtml(unicode, lxml.etree._Element): raw HTML/XHTML text to clean | 319 @param xhtml(unicode, lxml.etree._Element): raw HTML/XHTML text to clean |
320 @return (unicode): cleaned XHTML | 320 @return (unicode): cleaned XHTML |
321 """ | 321 """ |
322 | 322 |
323 if isinstance(xhtml, basestring): | 323 if isinstance(xhtml, str): |
324 try: | 324 try: |
325 xhtml_elt = html.fromstring(xhtml) | 325 xhtml_elt = html.fromstring(xhtml) |
326 except etree.ParserError as e: | 326 except etree.ParserError as e: |
327 if not xhtml.strip(): | 327 if not xhtml.strip(): |
328 return u"" | 328 return "" |
329 log.error(u"Can't clean XHTML: {xhtml}".format(xhtml=xhtml)) | 329 log.error("Can't clean XHTML: {xhtml}".format(xhtml=xhtml)) |
330 raise e | 330 raise e |
331 elif isinstance(xhtml, html.HtmlElement): | 331 elif isinstance(xhtml, html.HtmlElement): |
332 xhtml_elt = xhtml | 332 xhtml_elt = xhtml |
333 else: | 333 else: |
334 log.error("Only strings and HtmlElements can be cleaned") | 334 log.error("Only strings and HtmlElements can be cleaned") |
343 for element in xhtml_elt.iter(tag=etree.Element): | 343 for element in xhtml_elt.iter(tag=etree.Element): |
344 if not element.text: | 344 if not element.text: |
345 if element.tag in VOID_ELEMENTS: | 345 if element.tag in VOID_ELEMENTS: |
346 element.text = None | 346 element.text = None |
347 else: | 347 else: |
348 element.text = u'' | 348 element.text = '' |
349 return html.tostring(xhtml_elt, encoding=unicode, method="xml") | 349 return html.tostring(xhtml_elt, encoding=str, method="xml") |
350 | 350 |
351 def convert( | 351 def convert( |
352 self, text, syntax_from, syntax_to=_SYNTAX_XHTML, safe=True, profile=None | 352 self, text, syntax_from, syntax_to=_SYNTAX_XHTML, safe=True, profile=None |
353 ): | 353 ): |
354 """Convert a text between two syntaxes | 354 """Convert a text between two syntaxes |
411 TextSyntaxes.OPT_NO_THREAD: do not defer to thread when converting (the callback may then return a deferred) | 411 TextSyntaxes.OPT_NO_THREAD: do not defer to thread when converting (the callback may then return a deferred) |
412 """ | 412 """ |
413 flags = flags if flags is not None else [] | 413 flags = flags if flags is not None else [] |
414 if TextSyntaxes.OPT_HIDDEN in flags and TextSyntaxes.OPT_DEFAULT in flags: | 414 if TextSyntaxes.OPT_HIDDEN in flags and TextSyntaxes.OPT_DEFAULT in flags: |
415 raise ValueError( | 415 raise ValueError( |
416 u"{} and {} are mutually exclusive".format( | 416 "{} and {} are mutually exclusive".format( |
417 TextSyntaxes.OPT_HIDDEN, TextSyntaxes.OPT_DEFAULT | 417 TextSyntaxes.OPT_HIDDEN, TextSyntaxes.OPT_DEFAULT |
418 ) | 418 ) |
419 ) | 419 ) |
420 | 420 |
421 syntaxes = TextSyntaxes.syntaxes | 421 syntaxes = TextSyntaxes.syntaxes |
422 key = name.lower().strip() | 422 key = name.lower().strip() |
423 if key in syntaxes: | 423 if key in syntaxes: |
424 raise exceptions.ConflictError( | 424 raise exceptions.ConflictError( |
425 u"This syntax key already exists: {}".format(key) | 425 "This syntax key already exists: {}".format(key) |
426 ) | 426 ) |
427 syntaxes[key] = { | 427 syntaxes[key] = { |
428 "name": name, | 428 "name": name, |
429 "to": to_xhtml_cb, | 429 "to": to_xhtml_cb, |
430 "from": from_xhtml_cb, | 430 "from": from_xhtml_cb, |
451 @param xhtml: the XHTML string to be cleaned | 451 @param xhtml: the XHTML string to be cleaned |
452 @return: the cleaned string | 452 @return: the cleaned string |
453 """ | 453 """ |
454 cleaner = clean.Cleaner(kill_tags=["style"]) | 454 cleaner = clean.Cleaner(kill_tags=["style"]) |
455 cleaned = cleaner.clean_html(html.fromstring(xhtml)) | 455 cleaned = cleaner.clean_html(html.fromstring(xhtml)) |
456 return html.tostring(cleaned, encoding=unicode, method="text") | 456 return html.tostring(cleaned, encoding=str, method="text") |