summaryrefslogtreecommitdiff
path: root/sleekxmpp/xmlstream/stanzabase.py
diff options
context:
space:
mode:
Diffstat (limited to 'sleekxmpp/xmlstream/stanzabase.py')
-rw-r--r--sleekxmpp/xmlstream/stanzabase.py114
1 files changed, 64 insertions, 50 deletions
diff --git a/sleekxmpp/xmlstream/stanzabase.py b/sleekxmpp/xmlstream/stanzabase.py
index 4af441cc..11c8dd67 100644
--- a/sleekxmpp/xmlstream/stanzabase.py
+++ b/sleekxmpp/xmlstream/stanzabase.py
@@ -3,7 +3,7 @@
sleekxmpp.xmlstream.stanzabase
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- This module implements a wrapper layer for XML objects
+ module implements a wrapper layer for XML objects
that allows them to be treated like dictionaries.
Part of SleekXMPP: The Sleek XMPP Library
@@ -19,6 +19,7 @@ import logging
import weakref
from xml.etree import cElementTree as ET
+from sleekxmpp.util import safedict
from sleekxmpp.xmlstream import JID
from sleekxmpp.xmlstream.tostring import tostring
from sleekxmpp.thirdparty import OrderedDict
@@ -141,7 +142,7 @@ def multifactory(stanza, plugin_attrib):
parent.loaded_plugins.remove(plugin_attrib)
try:
parent.xml.remove(self.xml)
- except:
+ except ValueError:
pass
else:
for stanza in list(res):
@@ -192,7 +193,7 @@ def fix_ns(xpath, split=False, propagate_ns=True, default_ns=''):
for element in elements:
if element:
# Skip empty entry artifacts from splitting.
- if propagate_ns:
+ if propagate_ns and element[0] != '*':
tag = '{%s}%s' % (namespace, element)
else:
tag = element
@@ -488,7 +489,7 @@ class ElementBase(object):
"""
return self.init_plugin(attrib, lang)
- def _get_plugin(self, name, lang=None):
+ def _get_plugin(self, name, lang=None, check=False):
if lang is None:
lang = self.get_lang()
@@ -501,12 +502,12 @@ class ElementBase(object):
if (name, None) in self.plugins:
return self.plugins[(name, None)]
else:
- return self.init_plugin(name, lang)
+ return None if check else self.init_plugin(name, lang)
else:
if (name, lang) in self.plugins:
return self.plugins[(name, lang)]
else:
- return self.init_plugin(name, lang)
+ return None if check else self.init_plugin(name, lang)
def init_plugin(self, attrib, lang=None, existing_xml=None, reuse=True):
"""Enable and initialize a stanza plugin.
@@ -514,8 +515,9 @@ class ElementBase(object):
:param string attrib: The :attr:`plugin_attrib` value of the
plugin to enable.
"""
- if lang is None:
- lang = self.get_lang()
+ default_lang = self.get_lang()
+ if not lang:
+ lang = default_lang
plugin_class = self.plugin_attrib_map[attrib]
@@ -524,19 +526,13 @@ class ElementBase(object):
if reuse and (attrib, lang) in self.plugins:
return self.plugins[(attrib, lang)]
- if existing_xml is None:
- existing_xml = self.xml.find(plugin_class.tag_name())
-
- if existing_xml is not None:
- if existing_xml.attrib.get('{%s}lang' % XML_NS, '') != lang:
- existing_xml = None
-
plugin = plugin_class(parent=self, xml=existing_xml)
if plugin.is_extension:
self.plugins[(attrib, None)] = plugin
else:
- plugin['lang'] = lang
+ if lang != default_lang:
+ plugin['lang'] = lang
self.plugins[(attrib, lang)] = plugin
if plugin_class in self.plugin_iterables:
@@ -570,13 +566,16 @@ class ElementBase(object):
values = {}
values['lang'] = self['lang']
for interface in self.interfaces:
- values[interface] = self[interface]
+ if isinstance(self[interface], JID):
+ values[interface] = self[interface].jid
+ else:
+ values[interface] = self[interface]
if interface in self.lang_interfaces:
values['%s|*' % interface] = self['%s|*' % interface]
for plugin, stanza in self.plugins.items():
lang = stanza['lang']
if lang:
- values['%s|%s' % (plugin, lang)] = stanza.values
+ values['%s|%s' % (plugin[0], lang)] = stanza.values
else:
values[plugin[0]] = stanza.values
if self.iterables:
@@ -601,31 +600,39 @@ class ElementBase(object):
iterable_interfaces = [p.plugin_attrib for \
p in self.plugin_iterables]
+ if 'lang' in values:
+ self['lang'] = values['lang']
+
+ if 'substanzas' in values:
+ # Remove existing substanzas
+ for stanza in self.iterables:
+ try:
+ self.xml.remove(stanza.xml)
+ except ValueError:
+ pass
+ self.iterables = []
+
+ # Add new substanzas
+ for subdict in values['substanzas']:
+ if '__childtag__' in subdict:
+ for subclass in self.plugin_iterables:
+ child_tag = "{%s}%s" % (subclass.namespace,
+ subclass.name)
+ if subdict['__childtag__'] == child_tag:
+ sub = subclass(parent=self)
+ sub.values = subdict
+ self.iterables.append(sub)
+
for interface, value in values.items():
full_interface = interface
interface_lang = ('%s|' % interface).split('|')
interface = interface_lang[0]
lang = interface_lang[1] or self.get_lang()
- if interface == 'substanzas':
- # Remove existing substanzas
- for stanza in self.iterables:
- self.xml.remove(stanza.xml)
- self.iterables = []
-
- # Add new substanzas
- for subdict in value:
- if '__childtag__' in subdict:
- for subclass in self.plugin_iterables:
- child_tag = "{%s}%s" % (subclass.namespace,
- subclass.name)
- if subdict['__childtag__'] == child_tag:
- sub = subclass(parent=self)
- sub.values = subdict
- self.iterables.append(sub)
- break
- elif interface == 'lang':
- self[interface] = value
+ if interface == 'lang':
+ continue
+ elif interface == 'substanzas':
+ continue
elif interface in self.interfaces:
self[full_interface] = value
elif interface in self.plugin_attrib_map:
@@ -667,12 +674,14 @@ class ElementBase(object):
full_attrib = attrib
attrib_lang = ('%s|' % attrib).split('|')
attrib = attrib_lang[0]
- lang = attrib_lang[1] or ''
+ lang = attrib_lang[1] or None
kwargs = {}
if lang and attrib in self.lang_interfaces:
kwargs['lang'] = lang
+ kwargs = safedict(kwargs)
+
if attrib == 'substanzas':
return self.iterables
elif attrib in self.interfaces or attrib == 'lang':
@@ -743,12 +752,14 @@ class ElementBase(object):
full_attrib = attrib
attrib_lang = ('%s|' % attrib).split('|')
attrib = attrib_lang[0]
- lang = attrib_lang[1] or ''
+ lang = attrib_lang[1] or None
kwargs = {}
if lang and attrib in self.lang_interfaces:
kwargs['lang'] = lang
+ kwargs = safedict(kwargs)
+
if attrib in self.interfaces or attrib == 'lang':
if value is not None:
set_method = "set_%s" % attrib.lower()
@@ -829,12 +840,14 @@ class ElementBase(object):
full_attrib = attrib
attrib_lang = ('%s|' % attrib).split('|')
attrib = attrib_lang[0]
- lang = attrib_lang[1] or ''
+ lang = attrib_lang[1] or None
kwargs = {}
if lang and attrib in self.lang_interfaces:
kwargs['lang'] = lang
+ kwargs = safedict(kwargs)
+
if attrib in self.interfaces or attrib == 'lang':
del_method = "del_%s" % attrib.lower()
del_method2 = "del%s" % attrib.title()
@@ -860,18 +873,18 @@ class ElementBase(object):
else:
self._del_attr(attrib)
elif attrib in self.plugin_attrib_map:
- plugin = self._get_plugin(attrib, lang)
+ plugin = self._get_plugin(attrib, lang, check=True)
if not plugin:
return self
if plugin.is_extension:
del plugin[full_attrib]
del self.plugins[(attrib, None)]
else:
- del self.plugins[(attrib, lang)]
+ del self.plugins[(attrib, plugin['lang'])]
self.loaded_plugins.remove(attrib)
try:
self.xml.remove(plugin.xml)
- except:
+ except ValueError:
pass
return self
@@ -1222,6 +1235,10 @@ class ElementBase(object):
if item.__class__ in self.plugin_iterables:
if item.__class__.plugin_multi_attrib:
self.init_plugin(item.__class__.plugin_multi_attrib)
+ elif item.__class__ == self.plugin_tag_map.get(item.tag_name(), None):
+ self.init_plugin(item.plugin_attrib,
+ existing_xml=item.xml,
+ reuse=False)
return self
def appendxml(self, xml):
@@ -1398,10 +1415,8 @@ class ElementBase(object):
:param bool top_level_ns: Display the top-most namespace.
Defaults to True.
"""
- stanza_ns = '' if top_level_ns else self.namespace
return tostring(self.xml, xmlns='',
- stanza_ns=stanza_ns,
- top_level=not top_level_ns)
+ top_level=True)
def __repr__(self):
"""Use the stanza's serialized XML as its representation."""
@@ -1590,11 +1605,10 @@ class StanzaBase(ElementBase):
:param bool top_level_ns: Display the top-most namespace.
Defaults to ``False``.
"""
- stanza_ns = '' if top_level_ns else self.namespace
- return tostring(self.xml, xmlns='',
- stanza_ns=stanza_ns,
+ xmlns = self.stream.default_ns if self.stream else ''
+ return tostring(self.xml, xmlns=xmlns,
stream=self.stream,
- top_level=not top_level_ns)
+ top_level=(self.stream is None))
#: A JSON/dictionary version of the XML content exposed through