Stream features now use stanza objects!
Features are given a ranking that expresses the dependency
relationships (since only one feature is negotiated at a time, the
dependency graph can be replaced by a line).
>>> xmpp.register_feature('my_feature', _my_handler,
>>> restart=True, # Requires stream restart
>>> order=600) # Ranking (out of ~ 10,000,
>>> # lower #'s executed first)
SASL mechanisms may now be added or disabled as needed. Each mechanism
is given a priority value indicating the order in which the client
wishes for mechanisms to be tried. Higher priority numbers are executed
first.
>>> xmpp.register_sasl_mechanism('SASL-MECH', _mech_handler,
>>> priority=0)
Disabling a SASL mechanism:
>>> xmpp.remove_sasl_mechanism('ANONYMOUS')
Will now always show top-level namespace, unless it is the same
as the stream's default namespace. Also added the XMPP stream
namespace to the namespace map as 'stream'.
Use stanza.values instead of _get/set_stanza_values where used.
ElementBase stanzas can now use .tag
May use class method tag_name() for stanza classes.
ElementBase now has .clear() method.
May now use register_stanza_plugin(Foo, Bar, iterable=True)
to add to the set of stanza classes used for iterable
substanzas. It is no longer necessary to manually specify
the contents of subitem if the new method is used.
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" />'
We now raise the unexpected exceptions instead of sending
them on the network.
- avoids flood (sending a traceback on a MUC, for example…) and
maybe some security issues.
- lets you handle the traceback (catch it to handle
it properly, or with except_hook, etc)
- an exception cannot be raised without you knowing
Daemonized threads exit once the main program has quit,
and the only threads left running are all daemon threads.
Should fix hanging clients while not trampling over anyone
else's signal handlers.