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
This commit is contained in:
Goffi 2019-08-13 19:08:41 +02:00
commit fbfe96c505

View file

@ -1,4 +1,4 @@
#!/usr/bin/env python2
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# SAT plugin for pubsub forums
@ -29,8 +29,8 @@ import shortuuid
import json
log = getLogger(__name__)
NS_FORUMS = u'org.salut-a-toi.forums:0'
NS_FORUMS_TOPICS = NS_FORUMS + u'#topics'
NS_FORUMS = 'org.salut-a-toi.forums:0'
NS_FORUMS_TOPICS = NS_FORUMS + '#topics'
PLUGIN_INFO = {
C.PI_NAME: _("forums management"),
@ -42,16 +42,16 @@ PLUGIN_INFO = {
C.PI_HANDLER: "no",
C.PI_DESCRIPTION: _("""forums management plugin""")
}
FORUM_ATTR = {u'title', u'name', u'main-language', u'uri'}
FORUM_SUB_ELTS = (u'short-desc', u'desc')
FORUM_TOPICS_NODE_TPL = u'{node}#topics_{uuid}'
FORUM_TOPIC_NODE_TPL = u'{node}_{uuid}'
FORUM_ATTR = {'title', 'name', 'main-language', 'uri'}
FORUM_SUB_ELTS = ('short-desc', 'desc')
FORUM_TOPICS_NODE_TPL = '{node}#topics_{uuid}'
FORUM_TOPIC_NODE_TPL = '{node}_{uuid}'
class forums(object):
def __init__(self, host):
log.info(_(u"forums plugin initialization"))
log.info(_("forums plugin initialization"))
self.host = host
self._m = self.host.plugins['XEP-0277']
self._p = self.host.plugins['XEP-0060']
@ -67,19 +67,19 @@ class forums(object):
host.bridge.addMethod("forumsGet", ".plugin",
in_sign='ssss', out_sign='s',
method=self._get,
async=True)
async_=True)
host.bridge.addMethod("forumsSet", ".plugin",
in_sign='sssss', out_sign='',
method=self._set,
async=True)
async_=True)
host.bridge.addMethod("forumTopicsGet", ".plugin",
in_sign='ssa{ss}s', out_sign='(aa{ss}a{ss})',
method=self._getTopics,
async=True)
async_=True)
host.bridge.addMethod("forumTopicCreate", ".plugin",
in_sign='ssa{ss}s', out_sign='',
method=self._createTopic,
async=True)
async_=True)
@defer.inlineCallbacks
def _createForums(self, client, forums, service, node, forums_elt=None, names=None):
@ -94,48 +94,48 @@ class forums(object):
@return (domish.Element): created forums
"""
if not isinstance(forums, list):
raise ValueError(_(u"forums arguments must be a list of forums"))
raise ValueError(_("forums arguments must be a list of forums"))
if forums_elt is None:
forums_elt = domish.Element((NS_FORUMS, u'forums'))
forums_elt = domish.Element((NS_FORUMS, 'forums'))
assert names is None
names = set()
else:
if names is None or forums_elt.name != u'forums':
raise exceptions.InternalError(u'invalid forums or names')
if names is None or forums_elt.name != 'forums':
raise exceptions.InternalError('invalid forums or names')
assert names is not None
for forum in forums:
if not isinstance(forum, dict):
raise ValueError(_(u"A forum item must be a dictionary"))
raise ValueError(_("A forum item must be a dictionary"))
forum_elt = forums_elt.addElement('forum')
for key, value in forum.iteritems():
if key == u'name' and key in names:
raise exceptions.ConflictError(_(u"following forum name is not unique: {name}").format(name=key))
if key == u'uri' and not value.strip():
log.info(_(u"creating missing forum node"))
for key, value in forum.items():
if key == 'name' and key in names:
raise exceptions.ConflictError(_("following forum name is not unique: {name}").format(name=key))
if key == 'uri' and not value.strip():
log.info(_("creating missing forum node"))
forum_node = FORUM_TOPICS_NODE_TPL.format(node=node, uuid=shortuuid.uuid())
yield self._p.createNode(client, service, forum_node, self._node_options)
value = uri.buildXMPPUri(u'pubsub',
value = uri.buildXMPPUri('pubsub',
path=service.full(),
node=forum_node)
if key in FORUM_ATTR:
forum_elt[key] = value.strip()
elif key in FORUM_SUB_ELTS:
forum_elt.addElement(key, content=value)
elif key == u'sub-forums':
sub_forums_elt = forum_elt.addElement(u'forums')
elif key == 'sub-forums':
sub_forums_elt = forum_elt.addElement('forums')
yield self._createForums(client, value, service, node, sub_forums_elt, names=names)
else:
log.warning(_(u"Unknown forum attribute: {key}").format(key=key))
if not forum_elt.getAttribute(u'title'):
name = forum_elt.getAttribute(u'name')
log.warning(_("Unknown forum attribute: {key}").format(key=key))
if not forum_elt.getAttribute('title'):
name = forum_elt.getAttribute('name')
if name:
forum_elt[u'title'] = name
forum_elt['title'] = name
else:
raise ValueError(_(u"forum need a title or a name"))
if not forum_elt.getAttribute(u'uri') and not forum_elt.children:
raise ValueError(_(u"forum need uri or sub-forums"))
raise ValueError(_("forum need a title or a name"))
if not forum_elt.getAttribute('uri') and not forum_elt.children:
raise ValueError(_("forum need uri or sub-forums"))
defer.returnValue(forums_elt)
def _parseForums(self, parent_elt=None, forums=None):
@ -146,18 +146,18 @@ class forums(object):
@return (list): parsed data
@raise ValueError: item is invalid
"""
if parent_elt.name == u'item':
if parent_elt.name == 'item':
forums = []
try:
forums_elt = next(parent_elt.elements(NS_FORUMS, u'forums'))
forums_elt = next(parent_elt.elements(NS_FORUMS, 'forums'))
except StopIteration:
raise ValueError(_(u"missing <forums> element"))
raise ValueError(_("missing <forums> element"))
else:
forums_elt = parent_elt
if forums is None:
raise exceptions.InternalError(u'expected forums')
raise exceptions.InternalError('expected forums')
if forums_elt.name != 'forums':
raise ValueError(_(u'Unexpected element: {xml}').format(xml=forums_elt.toXml()))
raise ValueError(_('Unexpected element: {xml}').format(xml=forums_elt.toXml()))
for forum_elt in forums_elt.elements():
if forum_elt.name == 'forum':
data = {}
@ -165,19 +165,19 @@ class forums(object):
data[attrib] = forum_elt[attrib]
unknown = set(forum_elt.attributes).difference(FORUM_ATTR)
if unknown:
log.warning(_(u"Following attributes are unknown: {unknown}").format(unknown=unknown))
log.warning(_("Following attributes are unknown: {unknown}").format(unknown=unknown))
for elt in forum_elt.elements():
if elt.name in FORUM_SUB_ELTS:
data[elt.name] = unicode(elt)
elif elt.name == u'forums':
sub_forums = data[u'sub-forums'] = []
data[elt.name] = str(elt)
elif elt.name == 'forums':
sub_forums = data['sub-forums'] = []
self._parseForums(elt, sub_forums)
if not u'title' in data or not {u'uri', u'sub-forums'}.intersection(data):
log.warning(_(u"invalid forum, ignoring: {xml}").format(xml=forum_elt.toXml()))
if not 'title' in data or not {'uri', 'sub-forums'}.intersection(data):
log.warning(_("invalid forum, ignoring: {xml}").format(xml=forum_elt.toXml()))
else:
forums.append(data)
else:
log.warning(_(u"unkown forums sub element: {xml}").format(xml=forum_elt))
log.warning(_("unkown forums sub element: {xml}").format(xml=forum_elt))
return forums
@ -200,7 +200,7 @@ class forums(object):
if node is None:
node = NS_FORUMS
if forums_key is None:
forums_key = u'default'
forums_key = 'default'
items_data = yield self._p.getItems(client, service, node, item_ids=[forums_key])
item = items_data[0][0]
# we have the item and need to convert it to json
@ -241,7 +241,7 @@ class forums(object):
if node is None:
node = NS_FORUMS
if forums_key is None:
forums_key = u'default'
forums_key = 'default'
forums_elt = yield self._createForums(client, forums, service, node)
yield self._p.sendItem(client, service, node, forums_elt, item_id=forums_key)
@ -249,7 +249,7 @@ class forums(object):
client = self.host.getClient(profile_key)
extra = self._p.parseExtra(extra)
d = self.getTopics(client, jid.JID(service), node, rsm_request=extra.rsm_request, extra=extra.extra)
d.addCallback(lambda(topics, metadata): (topics, {k: unicode(v) for k,v in metadata.iteritems()}))
d.addCallback(lambda topics_metadata: (topics_metadata[0], {k: str(v) for k,v in topics_metadata[1].items()}))
return d
@defer.inlineCallbacks
@ -262,11 +262,11 @@ class forums(object):
topics = []
item_elts, metadata = topics_data
for item_elt in item_elts:
topic_elt = next(item_elt.elements(NS_FORUMS, u'topic'))
title_elt = next(topic_elt.elements(NS_FORUMS, u'title'))
topic = {u'uri': topic_elt[u'uri'],
u'author': topic_elt[u'author'],
u'title': unicode(title_elt)}
topic_elt = next(item_elt.elements(NS_FORUMS, 'topic'))
title_elt = next(topic_elt.elements(NS_FORUMS, 'title'))
topic = {'uri': topic_elt['uri'],
'author': topic_elt['author'],
'title': str(title_elt)}
topics.append(topic)
defer.returnValue((topics, metadata))
@ -277,21 +277,21 @@ class forums(object):
@defer.inlineCallbacks
def createTopic(self, client, service, node, mb_data):
try:
title = mb_data[u'title']
if not u'content' in mb_data:
raise KeyError(u'content')
title = mb_data['title']
if not 'content' in mb_data:
raise KeyError('content')
except KeyError as e:
raise exceptions.DataError(u"missing mandatory data: {key}".format(key=e.args[0]))
raise exceptions.DataError("missing mandatory data: {key}".format(key=e.args[0]))
topic_node = FORUM_TOPIC_NODE_TPL.format(node=node, uuid=shortuuid.uuid())
yield self._p.createNode(client, service, topic_node, self._node_options)
self._m.send(client, mb_data, service, topic_node)
topic_uri = uri.buildXMPPUri(u'pubsub',
subtype=u'microblog',
topic_uri = uri.buildXMPPUri('pubsub',
subtype='microblog',
path=service.full(),
node=topic_node)
topic_elt = domish.Element((NS_FORUMS, 'topic'))
topic_elt[u'uri'] = topic_uri
topic_elt[u'author'] = client.jid.userhost()
topic_elt.addElement(u'title', content = title)
topic_elt['uri'] = topic_uri
topic_elt['author'] = client.jid.userhost()
topic_elt.addElement('title', content = title)
yield self._p.sendItem(client, service, node, topic_elt)