Replaced the ToString class with a tostring function.
The sleekxmpp.xmlstream.tostring and sleekxmpp.xmlstream.tostring26 packages have been merged to sleekxmpp.xmlstream.tostring. The __init__.py file will import the appropriate tostring function depending on the Python version. The setup.py file has been updated with the package changes. ElementBase is now a direct descendent of object and does not subclass ToString. Stanza objects now return their XML contents for __repr__.
This commit is contained in:
parent
58f77d898f
commit
e077204a16
8 changed files with 298 additions and 343 deletions
8
setup.py
8
setup.py
|
@ -42,12 +42,8 @@ packages = [ 'sleekxmpp',
|
|||
'sleekxmpp/stanza',
|
||||
'sleekxmpp/xmlstream',
|
||||
'sleekxmpp/xmlstream/matcher',
|
||||
'sleekxmpp/xmlstream/handler' ]
|
||||
|
||||
if sys.version_info < (3, 0):
|
||||
packages.append('sleekxmpp/xmlstream/tostring26')
|
||||
else:
|
||||
packages.append('sleekxmpp/xmlstream/tostring')
|
||||
'sleekxmpp/xmlstream/handler',
|
||||
'sleekxmpp/xmlstream/tostring']
|
||||
|
||||
setup(
|
||||
name = "sleekxmpp",
|
||||
|
|
|
@ -25,6 +25,7 @@ from . stanza.roster import Roster
|
|||
from . stanza.nick import Nick
|
||||
from . stanza.htmlim import HTMLIM
|
||||
from . stanza.error import Error
|
||||
from sleekxmpp.xmlstream.tostring import tostring
|
||||
|
||||
import logging
|
||||
import threading
|
||||
|
@ -128,7 +129,7 @@ class basexmpp(object):
|
|||
return "%x".upper() % self.id
|
||||
|
||||
def sendXML(self, data, mask=None, timeout=10):
|
||||
return self.send(self.tostring(data), mask, timeout)
|
||||
return self.send(tostring(data), mask, timeout)
|
||||
|
||||
def send(self, data, mask=None, timeout=10):
|
||||
#logging.warning("Deprecated send used for \"%s\"" % (data,))
|
||||
|
|
|
@ -12,10 +12,7 @@ import weakref
|
|||
import copy
|
||||
from . jid import JID
|
||||
|
||||
if sys.version_info < (3,0):
|
||||
from . import tostring26 as tostring
|
||||
else:
|
||||
from . import tostring
|
||||
from sleekxmpp.xmlstream.tostring import tostring
|
||||
|
||||
xmltester = type(ET.Element('xml'))
|
||||
|
||||
|
@ -29,7 +26,7 @@ def registerStanzaPlugin(stanza, plugin):
|
|||
stanza.plugin_tag_map[tag] = plugin
|
||||
|
||||
|
||||
class ElementBase(tostring.ToString):
|
||||
class ElementBase(object):
|
||||
name = 'stanza'
|
||||
plugin_attrib = 'plugin'
|
||||
namespace = 'jabber:client'
|
||||
|
@ -306,6 +303,12 @@ class ElementBase(tostring.ToString):
|
|||
def __copy__(self):
|
||||
return self.__class__(xml=copy.deepcopy(self.xml), parent=self.parent)
|
||||
|
||||
def __str__(self):
|
||||
return tostring(self.xml, xmlns='', stanza_ns=self.namespace)
|
||||
|
||||
def __repr__(self):
|
||||
return self.__str__()
|
||||
|
||||
#def __del__(self): #prevents garbage collection of reference cycle
|
||||
# if self.parent is not None:
|
||||
# self.parent.xml.remove(self.xml)
|
||||
|
@ -391,3 +394,5 @@ class StanzaBase(ElementBase):
|
|||
def __copy__(self):
|
||||
return self.__class__(xml=copy.deepcopy(self.xml), stream=self.stream)
|
||||
|
||||
def __str__(self):
|
||||
return tostring(self.xml, xmlns='', stanza_ns=self.namespace, stream=self.stream)
|
||||
|
|
|
@ -1,14 +1,19 @@
|
|||
"""
|
||||
SleekXMPP: The Sleek XMPP Library
|
||||
Copyright (C) 2010 Nathanael C. Fritz
|
||||
This file is part of SleekXMPP.
|
||||
|
||||
See the file LICENSE for copying permission.
|
||||
"""
|
||||
|
||||
import sys
|
||||
|
||||
# Import the correct tostring and xml_escape functions based on the Python
|
||||
# version in order to properly handle Unicode.
|
||||
|
||||
# Import the correct ToString class based on the Python version.
|
||||
if sys.version_info < (3, 0):
|
||||
from sleekxmpp.xmlstream.tostring.tostring26 import ToString
|
||||
from sleekxmpp.xmlstream.tostring.tostring26 import tostring, xml_escape
|
||||
else:
|
||||
from sleekxmpp.xmlstream.tostring.tostring import ToString
|
||||
from sleekxmpp.xmlstream.tostring.tostring import tostring, xml_escape
|
||||
|
||||
__all__ = ['ToString']
|
||||
__all__ = ['tostring', 'xml_escape']
|
||||
|
|
|
@ -1,60 +1,91 @@
|
|||
"""
|
||||
SleekXMPP: The Sleek XMPP Library
|
||||
Copyright (C) 2010 Nathanael C. Fritz
|
||||
This file is part of SleekXMPP.
|
||||
|
||||
class ToString(object):
|
||||
def __str__(self, xml=None, xmlns='', stringbuffer=''):
|
||||
if xml is None:
|
||||
xml = self.xml
|
||||
newoutput = [stringbuffer]
|
||||
#TODO respect ET mapped namespaces
|
||||
itag = xml.tag.split('}', 1)[-1]
|
||||
See the file LICENSE for copying permission.
|
||||
"""
|
||||
|
||||
|
||||
def tostring(xml=None, xmlns='', stanza_ns='', stream=None, outbuffer=''):
|
||||
"""
|
||||
Serialize an XML object to a Unicode string.
|
||||
|
||||
Arguments:
|
||||
xml -- The XML object to serialize. If the value is None,
|
||||
then the XML object contained in this stanza
|
||||
object will be used.
|
||||
xmlns -- Optional namespace of an element wrapping the XML
|
||||
object.
|
||||
stanza_ns -- The namespace of the stanza object that contains
|
||||
the XML object.
|
||||
stream -- The XML stream that generated the XML object.
|
||||
outbuffer -- Optional buffer for storing serializations during
|
||||
recursive calls.
|
||||
"""
|
||||
# Add previous results to the start of the output.
|
||||
output = [outbuffer]
|
||||
|
||||
# Extract the element's tag name.
|
||||
tag_name = xml.tag.split('}', 1)[-1]
|
||||
|
||||
# Extract the element's namespace if it is defined.
|
||||
if '}' in xml.tag:
|
||||
ixmlns = xml.tag.split('}', 1)[0][1:]
|
||||
tag_xmlns = xml.tag.split('}', 1)[0][1:]
|
||||
else:
|
||||
ixmlns = ''
|
||||
nsbuffer = ''
|
||||
if xmlns != ixmlns and ixmlns != '' and ixmlns != self.namespace:
|
||||
if self.stream is not None and ixmlns in self.stream.namespace_map:
|
||||
if self.stream.namespace_map[ixmlns] != '':
|
||||
itag = "%s:%s" % (self.stream.namespace_map[ixmlns], itag)
|
||||
else:
|
||||
nsbuffer = """ xmlns="%s\"""" % ixmlns
|
||||
if ixmlns not in ('', xmlns, self.namespace):
|
||||
nsbuffer = """ xmlns="%s\"""" % ixmlns
|
||||
newoutput.append("<%s" % itag)
|
||||
newoutput.append(nsbuffer)
|
||||
for attrib in xml.attrib:
|
||||
tag_xmlns = ''
|
||||
|
||||
# Output the tag name and derived namespace of the element.
|
||||
namespace = ''
|
||||
if tag_xmlns not in ['', xmlns, stanza_ns]:
|
||||
namespace = ' xmlns="%s"' % tag_xmlns
|
||||
if stream and tag_xmlns in stream.namespace_map:
|
||||
mapped_namespace = stream.namespace_map[tag_xmlns]
|
||||
if mapped_namespace:
|
||||
tag = "%s:%s" % (mapped_namespace, tag_name)
|
||||
output.append("<%s" % tag_name)
|
||||
output.append(namespace)
|
||||
|
||||
# Output escaped attribute values.
|
||||
for attrib, value in xml.attrib.items():
|
||||
if '{' not in attrib:
|
||||
newoutput.append(""" %s="%s\"""" % (attrib, self.xmlesc(xml.attrib[attrib])))
|
||||
if len(xml) or xml.text or xml.tail:
|
||||
newoutput.append(">")
|
||||
value = xml_escape(value)
|
||||
output.append(' %s="%s"' % (attrib, value))
|
||||
|
||||
if len(xml) or xml.text:
|
||||
# If there are additional child elements to serialize.
|
||||
output.append(">")
|
||||
if xml.text:
|
||||
newoutput.append(self.xmlesc(xml.text))
|
||||
output.append(xml_escape(xml.text))
|
||||
if len(xml):
|
||||
for child in xml.getchildren():
|
||||
newoutput.append(self.__str__(child, ixmlns))
|
||||
newoutput.append("</%s>" % (itag, ))
|
||||
if xml.tail:
|
||||
newoutput.append(self.xmlesc(xml.tail))
|
||||
output.append(tostring(child, tag_xmlns, stanza_ns, stream))
|
||||
output.append("</%s>" % tag_name)
|
||||
elif xml.text:
|
||||
newoutput.append(">%s</%s>" % (self.xmlesc(xml.text), itag))
|
||||
# If we only have text content.
|
||||
output.append(">%s</%s>" % (xml_escape(xml.text), tag_name))
|
||||
else:
|
||||
newoutput.append(" />")
|
||||
return ''.join(newoutput)
|
||||
# Empty element.
|
||||
output.append(" />")
|
||||
if xml.tail:
|
||||
# If there is additional text after the element.
|
||||
output.append(xml_escape(xml.tail))
|
||||
return ''.join(output)
|
||||
|
||||
def xmlesc(self, text):
|
||||
|
||||
def xml_escape(text):
|
||||
"""
|
||||
Convert special characters in XML to escape sequences.
|
||||
|
||||
Arguments:
|
||||
text -- The XML text to convert.
|
||||
"""
|
||||
text = list(text)
|
||||
cc = 0
|
||||
matches = ('&', '<', '"', '>', "'")
|
||||
for c in text:
|
||||
if c in matches:
|
||||
if c == '&':
|
||||
text[cc] = '&'
|
||||
elif c == '<':
|
||||
text[cc] = '<'
|
||||
elif c == '>':
|
||||
text[cc] = '>'
|
||||
elif c == "'":
|
||||
text[cc] = '''
|
||||
else:
|
||||
text[cc] = '"'
|
||||
cc += 1
|
||||
escapes = {'&': '&',
|
||||
'<': '<',
|
||||
'>': '>',
|
||||
"'": ''',
|
||||
'"': '"'}
|
||||
for i, c in enumerate(text):
|
||||
text[i] = escapes.get(c, c)
|
||||
return ''.join(text)
|
||||
|
|
|
@ -1,65 +1,100 @@
|
|||
"""
|
||||
SleekXMPP: The Sleek XMPP Library
|
||||
Copyright (C) 2010 Nathanael C. Fritz
|
||||
This file is part of SleekXMPP.
|
||||
|
||||
See the file LICENSE for copying permission.
|
||||
"""
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import types
|
||||
|
||||
class ToString(object):
|
||||
def __str__(self, xml=None, xmlns='', stringbuffer=''):
|
||||
if xml is None:
|
||||
xml = self.xml
|
||||
newoutput = [stringbuffer]
|
||||
#TODO respect ET mapped namespaces
|
||||
itag = xml.tag.split('}', 1)[-1]
|
||||
|
||||
def tostring(xml=None, xmlns='', stanza_ns='', stream=None, outbuffer=''):
|
||||
"""
|
||||
Serialize an XML object to a Unicode string.
|
||||
|
||||
Arguments:
|
||||
xml -- The XML object to serialize. If the value is None,
|
||||
then the XML object contained in this stanza
|
||||
object will be used.
|
||||
xmlns -- Optional namespace of an element wrapping the XML
|
||||
object.
|
||||
stanza_ns -- The namespace of the stanza object that contains
|
||||
the XML object.
|
||||
stream -- The XML stream that generated the XML object.
|
||||
outbuffer -- Optional buffer for storing serializations during
|
||||
recursive calls.
|
||||
"""
|
||||
# Add previous results to the start of the output.
|
||||
output = [outbuffer]
|
||||
|
||||
# Extract the element's tag name.
|
||||
tag_name = xml.tag.split('}', 1)[-1]
|
||||
|
||||
# Extract the element's namespace if it is defined.
|
||||
if '}' in xml.tag:
|
||||
ixmlns = xml.tag.split('}', 1)[0][1:]
|
||||
tag_xmlns = xml.tag.split('}', 1)[0][1:]
|
||||
else:
|
||||
ixmlns = ''
|
||||
nsbuffer = ''
|
||||
if xmlns != ixmlns and ixmlns != u'' and ixmlns != self.namespace:
|
||||
if self.stream is not None and ixmlns in self.stream.namespace_map:
|
||||
if self.stream.namespace_map[ixmlns] != u'':
|
||||
itag = "%s:%s" % (self.stream.namespace_map[ixmlns], itag)
|
||||
else:
|
||||
nsbuffer = """ xmlns="%s\"""" % ixmlns
|
||||
if ixmlns not in ('', xmlns, self.namespace):
|
||||
nsbuffer = """ xmlns="%s\"""" % ixmlns
|
||||
newoutput.append("<%s" % itag)
|
||||
newoutput.append(nsbuffer)
|
||||
for attrib in xml.attrib:
|
||||
tag_xmlns = u''
|
||||
|
||||
# Output the tag name and derived namespace of the element.
|
||||
namespace = u''
|
||||
if tag_xmlns not in ['', xmlns, stanza_ns]:
|
||||
namespace = u' xmlns="%s"' % tag_xmlns
|
||||
if stream and tag_xmlns in stream.namespace_map:
|
||||
mapped_namespace = stream.namespace_map[tag_xmlns]
|
||||
if mapped_namespace:
|
||||
tag = u"%s:%s" % (mapped_namespace, tag_name)
|
||||
output.append(u"<%s" % tag_name)
|
||||
output.append(namespace)
|
||||
|
||||
# Output escaped attribute values.
|
||||
for attrib, value in xml.attrib.items():
|
||||
if '{' not in attrib:
|
||||
newoutput.append(""" %s="%s\"""" % (attrib, self.xmlesc(xml.attrib[attrib])))
|
||||
if len(xml) or xml.text or xml.tail:
|
||||
newoutput.append(u">")
|
||||
value = xml_escape(value)
|
||||
output.append(u' %s="%s"' % (attrib, value))
|
||||
|
||||
if len(xml) or xml.text:
|
||||
# If there are additional child elements to serialize.
|
||||
output.append(u">")
|
||||
if xml.text:
|
||||
newoutput.append(self.xmlesc(xml.text))
|
||||
output.append(xml_escape(xml.text))
|
||||
if len(xml):
|
||||
for child in xml.getchildren():
|
||||
newoutput.append(self.__str__(child, ixmlns))
|
||||
newoutput.append(u"</%s>" % (itag, ))
|
||||
output.append(tostring(child, tag_xmlns, stanza_ns, stream))
|
||||
output.append(u"</%s>" % tag_name)
|
||||
if xml.tail:
|
||||
newoutput.append(self.xmlesc(xml.tail))
|
||||
# If there is additional text after the element.
|
||||
output.append(xml_escape(xml.tail))
|
||||
elif xml.text:
|
||||
newoutput.append(">%s</%s>" % (self.xmlesc(xml.text), itag))
|
||||
# If we only have text content.
|
||||
output.append(u">%s</%s>" % (xml_escape(xml.text), tag_name))
|
||||
else:
|
||||
newoutput.append(" />")
|
||||
return u''.join(newoutput)
|
||||
# Empty element.
|
||||
output.append(u" />")
|
||||
if xml.tail:
|
||||
# If there is additional text after the element.
|
||||
output.append(xml_escape(xml.tail))
|
||||
return u''.join(output)
|
||||
|
||||
def xmlesc(self, text):
|
||||
|
||||
def xml_escape(text):
|
||||
"""
|
||||
Convert special characters in XML to escape sequences.
|
||||
|
||||
Arguments:
|
||||
text -- The XML text to convert.
|
||||
"""
|
||||
if type(text) != types.UnicodeType:
|
||||
text = list(unicode(text, 'utf-8', 'ignore'))
|
||||
else:
|
||||
text = list(text)
|
||||
|
||||
cc = 0
|
||||
matches = (u'&', u'<', u'"', u'>', u"'")
|
||||
for c in text:
|
||||
if c in matches:
|
||||
if c == u'&':
|
||||
text[cc] = u'&'
|
||||
elif c == u'<':
|
||||
text[cc] = u'<'
|
||||
elif c == u'>':
|
||||
text[cc] = u'>'
|
||||
elif c == u"'":
|
||||
text[cc] = u'''
|
||||
else:
|
||||
text[cc] = u'"'
|
||||
cc += 1
|
||||
return ''.join(text)
|
||||
escapes = {u'&': u'&',
|
||||
u'<': u'<',
|
||||
u'>': u'>',
|
||||
u"'": u''',
|
||||
u'"': u'"'}
|
||||
for i, c in enumerate(text):
|
||||
text[i] = escapes.get(c, c)
|
||||
return u''.join(text)
|
||||
|
|
|
@ -1,65 +0,0 @@
|
|||
import types
|
||||
|
||||
class ToString(object):
|
||||
def __str__(self, xml=None, xmlns='', stringbuffer=''):
|
||||
if xml is None:
|
||||
xml = self.xml
|
||||
newoutput = [stringbuffer]
|
||||
#TODO respect ET mapped namespaces
|
||||
itag = xml.tag.split('}', 1)[-1]
|
||||
if '}' in xml.tag:
|
||||
ixmlns = xml.tag.split('}', 1)[0][1:]
|
||||
else:
|
||||
ixmlns = ''
|
||||
nsbuffer = ''
|
||||
if xmlns != ixmlns and ixmlns != u'' and ixmlns != self.namespace:
|
||||
if self.stream is not None and ixmlns in self.stream.namespace_map:
|
||||
if self.stream.namespace_map[ixmlns] != u'':
|
||||
itag = "%s:%s" % (self.stream.namespace_map[ixmlns], itag)
|
||||
else:
|
||||
nsbuffer = """ xmlns="%s\"""" % ixmlns
|
||||
if ixmlns not in ('', xmlns, self.namespace):
|
||||
nsbuffer = """ xmlns="%s\"""" % ixmlns
|
||||
newoutput.append("<%s" % itag)
|
||||
newoutput.append(nsbuffer)
|
||||
for attrib in xml.attrib:
|
||||
if '{' not in attrib:
|
||||
newoutput.append(""" %s="%s\"""" % (attrib, self.xmlesc(xml.attrib[attrib])))
|
||||
if len(xml) or xml.text or xml.tail:
|
||||
newoutput.append(u">")
|
||||
if xml.text:
|
||||
newoutput.append(self.xmlesc(xml.text))
|
||||
if len(xml):
|
||||
for child in xml.getchildren():
|
||||
newoutput.append(self.__str__(child, ixmlns))
|
||||
newoutput.append(u"</%s>" % (itag, ))
|
||||
if xml.tail:
|
||||
newoutput.append(self.xmlesc(xml.tail))
|
||||
elif xml.text:
|
||||
newoutput.append(">%s</%s>" % (self.xmlesc(xml.text), itag))
|
||||
else:
|
||||
newoutput.append(" />")
|
||||
return u''.join(newoutput)
|
||||
|
||||
def xmlesc(self, text):
|
||||
if type(text) != types.UnicodeType:
|
||||
text = list(unicode(text, 'utf-8', 'ignore'))
|
||||
else:
|
||||
text = list(text)
|
||||
|
||||
cc = 0
|
||||
matches = (u'&', u'<', u'"', u'>', u"'")
|
||||
for c in text:
|
||||
if c in matches:
|
||||
if c == u'&':
|
||||
text[cc] = u'&'
|
||||
elif c == u'<':
|
||||
text[cc] = u'<'
|
||||
elif c == u'>':
|
||||
text[cc] = u'>'
|
||||
elif c == u"'":
|
||||
text[cc] = u'''
|
||||
else:
|
||||
text[cc] = u'"'
|
||||
cc += 1
|
||||
return ''.join(text)
|
|
@ -23,6 +23,7 @@ import types
|
|||
import copy
|
||||
import xml.sax.saxutils
|
||||
from . import scheduler
|
||||
from sleekxmpp.xmlstream.tostring import tostring
|
||||
|
||||
RESPONSE_TIMEOUT = 10
|
||||
HANDLER_THREADS = 1
|
||||
|
@ -303,7 +304,7 @@ class XMLStream(object):
|
|||
def __spawnEvent(self, xmlobj):
|
||||
"watching xmlOut and processes handlers"
|
||||
#convert XML into Stanza
|
||||
logging.debug("RECV: %s" % cElementTree.tostring(xmlobj))
|
||||
logging.debug("RECV: %s" % tostring(xmlobj))
|
||||
xmlobj = self.incoming_filter(xmlobj)
|
||||
stanza_type = StanzaBase
|
||||
for stanza_class in self.__root_stanza:
|
||||
|
@ -388,60 +389,6 @@ class XMLStream(object):
|
|||
def removeStanzaExtension(self, stanza_class, stanza_extension):
|
||||
stanza_extension[stanza_class].pop(stanza_extension)
|
||||
|
||||
def tostring(self, xml, xmlns='', stringbuffer=''):
|
||||
newoutput = [stringbuffer]
|
||||
#TODO respect ET mapped namespaces
|
||||
itag = xml.tag.split('}', 1)[-1]
|
||||
if '}' in xml.tag:
|
||||
ixmlns = xml.tag.split('}', 1)[0][1:]
|
||||
else:
|
||||
ixmlns = ''
|
||||
nsbuffer = ''
|
||||
if xmlns != ixmlns and ixmlns != '':
|
||||
if ixmlns in self.namespace_map:
|
||||
if self.namespace_map[ixmlns] != '':
|
||||
itag = "%s:%s" % (self.namespace_map[ixmlns], itag)
|
||||
else:
|
||||
nsbuffer = """ xmlns="%s\"""" % ixmlns
|
||||
newoutput.append("<%s" % itag)
|
||||
newoutput.append(nsbuffer)
|
||||
for attrib in xml.attrib:
|
||||
newoutput.append(""" %s="%s\"""" % (attrib, self.xmlesc(xml.attrib[attrib])))
|
||||
if len(xml) or xml.text or xml.tail:
|
||||
newoutput.append(">")
|
||||
if xml.text:
|
||||
newoutput.append(self.xmlesc(xml.text))
|
||||
if len(xml):
|
||||
for child in xml.getchildren():
|
||||
newoutput.append(self.tostring(child, ixmlns))
|
||||
newoutput.append("</%s>" % (itag, ))
|
||||
if xml.tail:
|
||||
newoutput.append(self.xmlesc(xml.tail))
|
||||
elif xml.text:
|
||||
newoutput.append(">%s</%s>" % (self.xmlesc(xml.text), itag))
|
||||
else:
|
||||
newoutput.append(" />")
|
||||
return ''.join(newoutput)
|
||||
|
||||
def xmlesc(self, text):
|
||||
text = list(text)
|
||||
cc = 0
|
||||
matches = ('&', '<', '"', '>', "'")
|
||||
for c in text:
|
||||
if c in matches:
|
||||
if c == '&':
|
||||
text[cc] = '&'
|
||||
elif c == '<':
|
||||
text[cc] = '<'
|
||||
elif c == '>':
|
||||
text[cc] = '>'
|
||||
elif c == "'":
|
||||
text[cc] = '''
|
||||
elif self.escape_quotes:
|
||||
text[cc] = '"'
|
||||
cc += 1
|
||||
return ''.join(text)
|
||||
|
||||
def start_stream_handler(self, xml):
|
||||
"""Meant to be overridden"""
|
||||
pass
|
||||
|
|
Loading…
Reference in a new issue