Philipp Hörist pushed to branch master at gajim / python-nbxmpp
Commits: 30f65e21 by Philipp Hörist at 2019-08-05T08:09:30Z Add Node.getXmlLang()
Get the xml:lang attr, if not found traverse all parents
- - - - - d1e511bf by Philipp Hörist at 2019-08-05T08:58:16Z Refactor CommonError
- Parse application errors - Parse text elements in all languages
- - - - - d33c50ad by Philipp Hörist at 2019-08-05T09:01:43Z Add test for parsing errors
- - - - -
5 changed files:
- nbxmpp/protocol.py - nbxmpp/simplexml.py - nbxmpp/structs.py - nbxmpp/util.py - + test/unit/test_error_parsing.py
Changes:
===================================== nbxmpp/protocol.py ===================================== @@ -1084,11 +1084,27 @@ class Protocol(Node): of the error (otherwise) """ errtag = self.getTag('error') - if errtag: - for tag in errtag.getChildren(): - if tag.getName() != 'text': - return tag.getName() - return errtag.getData() + if errtag is None: + return + for tag in errtag.getChildren(): + if tag.getName() != 'text' and tag.getNamespace() == NS_STANZAS: + return tag.getName() + + def getAppError(self): + errtag = self.getTag('error') + if errtag is None: + return + for tag in errtag.getChildren(): + if tag.getName() != 'text' and tag.getNamespace() != NS_STANZAS: + return tag.getName() + + def getAppErrorNamespace(self): + errtag = self.getTag('error') + if errtag is None: + return + for tag in errtag.getChildren(): + if tag.getName() != 'text' and tag.getNamespace() != NS_STANZAS: + return tag.getNamespace()
def getErrorMsg(self): """
===================================== nbxmpp/simplexml.py ===================================== @@ -431,6 +431,14 @@ class Node: except Exception: self.addChild(tag, attrs, payload = [str(val)])
+ def getXmlLang(self): + lang = self.attrs.get('xml:lang') + if lang is not None: + return lang + + if self.parent is not None: + return self.parent.getXmlLang() + def has_attr(self, key): """ Check if node have attribute "key"
===================================== nbxmpp/structs.py ===================================== @@ -309,11 +309,52 @@ class OMEMOBundle(namedtuple('OMEMOBundle', 'spk spk_signature ik otpks')): return random.SystemRandom().choice(self.otpks)
-class CommonError(namedtuple('CommonError', 'type message jid')): +class CommonError: + def __init__(self, stanza): + self._error_node = stanza.getTag('error') + self.condition = stanza.getError() + self.app_condition = stanza.getAppError() + self.type = stanza.getErrorType() + self.jid = stanza.getFrom() + self.id = stanza.getID() + self._text = {} + + error = stanza.getTag('error') + if error is not None: + text_elements = error.getTags('text', namespace=NS_STANZAS) + for element in text_elements: + lang = element.getXmlLang() + text = element.getData() + self._text[lang] = text + + def get_text(self, pref_lang=None): + if pref_lang is not None: + text = self._text.get(pref_lang) + if text is not None: + return text + + if self._text: + text = self._text.get('en') + if text is not None: + return text + + text = self._text.get(None) + if text is not None: + return text + return self._text.popitem()[1] + return '' + + def set_text(self, lang, text): + self._text[lang] = text + def __str__(self): - if self.message is not None: - return 'Error from %s %s: %s' % (self.jid, self.type, self.message) - return 'Error from %s: %s' % (self.jid, self.type) + condition = self.condition + if self.app_condition is not None: + condition = '%s (%s)' % (self.condition, self.app_condition) + text = self.get_text('en') or '' + if text: + text = ' - %s' % text + return 'Error from %s: %s%s' % (self.jid, condition, text)
class TuneData(namedtuple('TuneData', 'artist length rating source title track uri')):
===================================== nbxmpp/util.py ===================================== @@ -138,14 +138,19 @@ def to_xs_boolean(value): 'Cant convert %s to xs:boolean' % value)
-def raise_error(log_method, stanza, type_=None, message=None): - if message is not None: - message = str(message) - if type_ is None: - type_ = stanza.getError() - message = stanza.getErrorMsg() - jid = stanza.getFrom() - error = CommonError(type_, message, jid) +error_classes = {} + +def error_factory(stanza): + app_namespace = stanza.getAppErrorNamespace() + return error_classes.get(app_namespace, CommonError)(stanza) + + +def raise_error(log_method, stanza, condition=None, text=None): + error = error_factory(stanza) + if text is not None: + error.set_text('en', str(text)) + if condition is not None: + error.condition = str(condition) log_method(error) if log_method.__name__ in ('warning', 'error'): log_method(stanza)
===================================== test/unit/test_error_parsing.py ===================================== @@ -0,0 +1,32 @@ +import unittest + +from nbxmpp.protocol import Iq +from nbxmpp.util import error_factory + + +class TestErrorParsing(unittest.TestCase): + + def test_error_parsing(self): + stanza = ''' + <iq from='upload.montague.tld' + id='step_03' + to='romeo@montague.tld/garden' + type='error'> + <error type='modify'> + <not-acceptable xmlns='urn:ietf:params:xml:ns:xmpp-stanzas' /> + <text xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'>File too large. The maximum file size is 20000 bytes</text> + <text xml:lang='de' xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'>File zu groß. Erlaubt sind 20000 bytes</text> + <file-too-large xmlns='urn:xmpp:http:upload:0'> + <max-file-size>20000</max-file-size> + </file-too-large> + </error> + </iq>''' + + error = error_factory(Iq(node=stanza)) + self.assertEqual(error.condition, 'not-acceptable') + self.assertEqual(error.app_condition, 'file-too-large') + self.assertEqual(error.get_text(), 'File too large. The maximum file size is 20000 bytes') + self.assertEqual(error.get_text('de'), 'File zu groß. Erlaubt sind 20000 bytes') + self.assertEqual(error.type, 'modify') + self.assertEqual(error.id, 'step_03') + self.assertEqual(error.jid, 'upload.montague.tld')
View it on GitLab: https://dev.gajim.org/gajim/python-nbxmpp/compare/b1f664db25f4729b36899bdafd...