Make extending stanza objects nicer.
A stanza object may add is_extension = True to its class definition
to provide a single new interface to a parent stanza.
For example:
import sleekxmpp
from sleekxmpp import Iq
from sleekxmpp.xmlstream import ElementBase, register_stanza_plugin, ET
class Foo(ElementBase):
"""
Test adding just an attribute to a parent stanza.
Adding subelements works as expected.
"""
is_extension = True
interfaces = set(('foo',))
plugin_attrib = 'foo'
def setup(self, xml):
# Don't include an XML element in the parent stanza
# since we're adding just an attribute.
# If adding a regular subelement, no need to do this.
self.xml = ET.Element('')
def set_foo(self, val):
self.parent()._set_attr('foo', val)
def get_foo(self):
return self.parent()._get_attr('foo')
def del_foo(self):
self.parent()._del_attr('foo')
register_stanza_plugin(Iq, Foo)
i1 = Iq()
i2 = Iq(xml=ET.fromstring("<iq xmlns='jabber:client' foo='bar' />"))
>>> i1['foo'] = '3'
>>> i1
'3'
>>> i1
'<iq id="0" foo="3" />'
>>> i2
'<iq id="0" foo="bar" />'
>>> i2['foo']
'bar'
>>> del i2['foo']
>>> i2
'<iq id="0" />'
This commit is contained in:
@@ -95,10 +95,22 @@ class ElementBase(object):
|
|||||||
>>> message['custom']['useful_thing'] = 'foo'
|
>>> message['custom']['useful_thing'] = 'foo'
|
||||||
|
|
||||||
If a plugin provides an interface that is the same as the plugin's
|
If a plugin provides an interface that is the same as the plugin's
|
||||||
plugin_attrib value, then the plugin's interface may be accessed
|
plugin_attrib value, then the plugin's interface may be assigned
|
||||||
directly from the parent stanza, as so:
|
directly from the parent stanza, as shown below, but retrieving
|
||||||
|
information will require all interfaces to be used, as so:
|
||||||
|
|
||||||
>>> message['custom'] = 'bar' # Same as using message['custom']['custom']
|
>>> message['custom'] = 'bar' # Same as using message['custom']['custom']
|
||||||
|
>>> message['custom']['custom'] # Must use all interfaces
|
||||||
|
'bar'
|
||||||
|
|
||||||
|
If the plugin sets the value is_extension = True, then both setting
|
||||||
|
and getting an interface value that is the same as the plugin's
|
||||||
|
plugin_attrib value will work, as so:
|
||||||
|
|
||||||
|
>>> message['custom'] = 'bar' # Using is_extension=True
|
||||||
|
>>> message['custom']
|
||||||
|
'bar'
|
||||||
|
|
||||||
|
|
||||||
Class Attributes:
|
Class Attributes:
|
||||||
name -- The name of the stanza's main element.
|
name -- The name of the stanza's main element.
|
||||||
@@ -116,6 +128,10 @@ class ElementBase(object):
|
|||||||
associated plugin stanza classes.
|
associated plugin stanza classes.
|
||||||
plugin_tag_map -- A mapping of plugin stanza tag names with
|
plugin_tag_map -- A mapping of plugin stanza tag names with
|
||||||
the associated plugin stanza classes.
|
the associated plugin stanza classes.
|
||||||
|
is_extension -- When True, allows the stanza to provide one
|
||||||
|
additional interface to the parent stanza,
|
||||||
|
extending the interfaces supported by the
|
||||||
|
parent. Defaults to False.
|
||||||
xml_ns -- The XML namespace,
|
xml_ns -- The XML namespace,
|
||||||
http://www.w3.org/XML/1998/namespace,
|
http://www.w3.org/XML/1998/namespace,
|
||||||
for use with xml:lang values.
|
for use with xml:lang values.
|
||||||
@@ -173,6 +189,7 @@ class ElementBase(object):
|
|||||||
plugin_attrib_map = {}
|
plugin_attrib_map = {}
|
||||||
plugin_tag_map = {}
|
plugin_tag_map = {}
|
||||||
subitem = None
|
subitem = None
|
||||||
|
is_extension = False
|
||||||
xml_ns = 'http://www.w3.org/XML/1998/namespace'
|
xml_ns = 'http://www.w3.org/XML/1998/namespace'
|
||||||
|
|
||||||
def __init__(self, xml=None, parent=None):
|
def __init__(self, xml=None, parent=None):
|
||||||
@@ -371,6 +388,8 @@ class ElementBase(object):
|
|||||||
elif attrib in self.plugin_attrib_map:
|
elif attrib in self.plugin_attrib_map:
|
||||||
if attrib not in self.plugins:
|
if attrib not in self.plugins:
|
||||||
self.init_plugin(attrib)
|
self.init_plugin(attrib)
|
||||||
|
if self.plugins[attrib].is_extension:
|
||||||
|
return self.plugins[attrib][attrib]
|
||||||
return self.plugins[attrib]
|
return self.plugins[attrib]
|
||||||
else:
|
else:
|
||||||
return ''
|
return ''
|
||||||
@@ -467,8 +486,13 @@ class ElementBase(object):
|
|||||||
elif attrib in self.plugin_attrib_map:
|
elif attrib in self.plugin_attrib_map:
|
||||||
if attrib in self.plugins:
|
if attrib in self.plugins:
|
||||||
xml = self.plugins[attrib].xml
|
xml = self.plugins[attrib].xml
|
||||||
|
if self.plugins[attrib].is_extension:
|
||||||
|
del self.plugins[attrib][attrib]
|
||||||
del self.plugins[attrib]
|
del self.plugins[attrib]
|
||||||
self.xml.remove(xml)
|
try:
|
||||||
|
self.xml.remove(xml)
|
||||||
|
except:
|
||||||
|
pass
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def _set_attr(self, name, value):
|
def _set_attr(self, name, value):
|
||||||
|
|||||||
Reference in New Issue
Block a user