Compare commits
	
		
			12 Commits
		
	
	
		
			1.1.7
			...
			sleek-1.1.
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					a26a8bd79c | ||
| 
						 | 
					9307a6915f | ||
| 
						 | 
					85ef2d8d0b | ||
| 
						 | 
					c2c7cc032b | ||
| 
						 | 
					e4911e9391 | ||
| 
						 | 
					b11e1ee92d | ||
| 
						 | 
					5027d00c10 | ||
| 
						 | 
					69ddeceb49 | ||
| 
						 | 
					82698672bb | ||
| 
						 | 
					9cec284947 | ||
| 
						 | 
					dc501d1902 | ||
| 
						 | 
					100e504b7f | 
@@ -45,7 +45,7 @@ The latest source code for SleekXMPP may be found on `Github
 | 
			
		||||
``develop`` branch.
 | 
			
		||||
 | 
			
		||||
**Latest Release**
 | 
			
		||||
    - `1.1.7 <http://github.com/fritzy/SleekXMPP/zipball/1.1.7>`_
 | 
			
		||||
    - `1.1.8 <http://github.com/fritzy/SleekXMPP/zipball/1.1.8>`_
 | 
			
		||||
 | 
			
		||||
**Develop Releases**
 | 
			
		||||
    - `Latest Develop Version <http://github.com/fritzy/SleekXMPP/zipball/develop>`_
 | 
			
		||||
 
 | 
			
		||||
@@ -122,6 +122,19 @@ if __name__ == '__main__':
 | 
			
		||||
    xmpp.register_plugin('xep_0060') # PubSub
 | 
			
		||||
    xmpp.register_plugin('xep_0199') # XMPP Ping
 | 
			
		||||
 | 
			
		||||
    # If you are connecting to Facebook and wish to use the
 | 
			
		||||
    # X-FACEBOOK-PLATFORM authentication mechanism, you will need
 | 
			
		||||
    # your API key and an access token. Then you'll set:
 | 
			
		||||
    # xmpp.credentials['api_key'] = 'THE_API_KEY'
 | 
			
		||||
    # xmpp.credentials['access_token'] = 'THE_ACCESS_TOKEN'
 | 
			
		||||
 | 
			
		||||
    # If you are connecting to MSN, then you will need an
 | 
			
		||||
    # access token, and it does not matter what JID you
 | 
			
		||||
    # specify other than that the domain is 'messenger.live.com',
 | 
			
		||||
    # so '_@messenger.live.com' will work. You can specify
 | 
			
		||||
    # the access token as so:
 | 
			
		||||
    # xmpp.credentials['access_token'] = 'THE_ACCESS_TOKEN'
 | 
			
		||||
 | 
			
		||||
    # If you are working with an OpenFire server, you may need
 | 
			
		||||
    # to adjust the SSL version used:
 | 
			
		||||
    # xmpp.ssl_version = ssl.PROTOCOL_SSLv3
 | 
			
		||||
 
 | 
			
		||||
@@ -134,6 +134,7 @@ class BaseXMPP(XMLStream):
 | 
			
		||||
            Callback('Presence',
 | 
			
		||||
                     MatchXPath("{%s}presence" % self.default_ns),
 | 
			
		||||
                     self._handle_presence))
 | 
			
		||||
 | 
			
		||||
        self.register_handler(
 | 
			
		||||
            Callback('Stream Error',
 | 
			
		||||
                     MatchXPath("{%s}error" % self.stream_ns),
 | 
			
		||||
@@ -658,6 +659,27 @@ class BaseXMPP(XMLStream):
 | 
			
		||||
    def _handle_stream_error(self, error):
 | 
			
		||||
        self.event('stream_error', error)
 | 
			
		||||
 | 
			
		||||
        if error['condition'] == 'see-other-host':
 | 
			
		||||
            other_host = error['see_other_host']
 | 
			
		||||
 | 
			
		||||
            host = other_host
 | 
			
		||||
            port = 5222
 | 
			
		||||
 | 
			
		||||
            if '[' in other_host and ']' in other_host:
 | 
			
		||||
                host = other_host.split(']')[0][1:]
 | 
			
		||||
            elif ':' in other_host:
 | 
			
		||||
                host = other_host.split(':')[0]
 | 
			
		||||
 | 
			
		||||
            port_sec = other_host.split(']')[-1]
 | 
			
		||||
            if ':' in port_sec:
 | 
			
		||||
                port = int(port_sec.split(':')[1])
 | 
			
		||||
 | 
			
		||||
            self.address = (host, port)
 | 
			
		||||
            self.default_domain = host
 | 
			
		||||
            self.dns_records = None
 | 
			
		||||
            self.reconnect_delay = None
 | 
			
		||||
            self.reconnect()
 | 
			
		||||
 | 
			
		||||
    def _handle_message(self, msg):
 | 
			
		||||
        """Process incoming message stanzas."""
 | 
			
		||||
        if not self.is_component and not msg['to'].bare:
 | 
			
		||||
 
 | 
			
		||||
@@ -56,5 +56,8 @@ __all__ = [
 | 
			
		||||
    'xep_0224',  # Attention
 | 
			
		||||
    'xep_0231',  # Bits of Binary
 | 
			
		||||
    'xep_0249',  # Direct MUC Invitations
 | 
			
		||||
    'xep_0256',  # Last Activity in Presence
 | 
			
		||||
    'xep_0258',  # Security Labels in XMPP
 | 
			
		||||
    'xep_0270',  # XMPP Compliance Suites 2010
 | 
			
		||||
    'xep_0302',  # XMPP Compliance Suites 2012
 | 
			
		||||
]
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										67
									
								
								sleekxmpp/plugins/xep_0256.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										67
									
								
								sleekxmpp/plugins/xep_0256.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,67 @@
 | 
			
		||||
"""
 | 
			
		||||
    SleekXMPP: The Sleek XMPP Library
 | 
			
		||||
    Copyright (C) 2012 Nathanael C. Fritz, Lance J.T. Stout
 | 
			
		||||
    This file is part of SleekXMPP.
 | 
			
		||||
 | 
			
		||||
    See the file LICENSE for copying permission.
 | 
			
		||||
"""
 | 
			
		||||
 | 
			
		||||
import logging
 | 
			
		||||
 | 
			
		||||
from sleekxmpp import Presence
 | 
			
		||||
from sleekxmpp.plugins import BasePlugin, register_plugin
 | 
			
		||||
from sleekxmpp.xmlstream import register_stanza_plugin
 | 
			
		||||
 | 
			
		||||
from sleekxmpp.plugins.xep_0012 import stanza, LastActivity
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
log = logging.getLogger(__name__)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class XEP_0256(BasePlugin):
 | 
			
		||||
 | 
			
		||||
    name = 'xep_0256'
 | 
			
		||||
    description = 'XEP-0256: Last Activity in Presence'
 | 
			
		||||
    dependencies = set(['xep_0012'])
 | 
			
		||||
    stanza = stanza
 | 
			
		||||
 | 
			
		||||
    def plugin_init(self):
 | 
			
		||||
        self.auto_last_activity = self.config.get('auto_last_activity', False)
 | 
			
		||||
 | 
			
		||||
        register_stanza_plugin(Presence, LastActivity)
 | 
			
		||||
 | 
			
		||||
        self.xmpp.add_filter('out', self._initial_presence_activity)
 | 
			
		||||
        self.xmpp.add_event_handler('connected', self._reset_presence_activity)
 | 
			
		||||
 | 
			
		||||
        self._initial_presence = set()
 | 
			
		||||
 | 
			
		||||
    def _reset_presence_activity(self, e):
 | 
			
		||||
        self._initial_presence = set()
 | 
			
		||||
 | 
			
		||||
    def _initial_presence_activity(self, stanza):
 | 
			
		||||
        if isinstance(stanza, Presence):
 | 
			
		||||
            use_last_activity = False
 | 
			
		||||
 | 
			
		||||
            if self.auto_last_activity and  stanza['show'] in ('xa', 'away'):
 | 
			
		||||
                use_last_activity = True
 | 
			
		||||
 | 
			
		||||
            if stanza['from'] not in self._initial_presence:
 | 
			
		||||
                self._initial_presence.add(stanza['from'])
 | 
			
		||||
                use_last_activity = True
 | 
			
		||||
 | 
			
		||||
            if use_last_activity:
 | 
			
		||||
                plugin = self.xmpp['xep_0012']
 | 
			
		||||
                try:
 | 
			
		||||
                    result = plugin.api['get_last_activity'](stanza['from'],
 | 
			
		||||
                                                             None,
 | 
			
		||||
                                                             stanza['to'])
 | 
			
		||||
                    seconds = result['last_activity']['seconds']
 | 
			
		||||
                except XMPPError:
 | 
			
		||||
                    seconds = None
 | 
			
		||||
 | 
			
		||||
                if seconds is not None:
 | 
			
		||||
                    stanza['last_activity']['seconds'] = seconds
 | 
			
		||||
        return stanza
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
register_plugin(XEP_0256)
 | 
			
		||||
							
								
								
									
										20
									
								
								sleekxmpp/plugins/xep_0270.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								sleekxmpp/plugins/xep_0270.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,20 @@
 | 
			
		||||
"""
 | 
			
		||||
    SleekXMPP: The Sleek XMPP Library
 | 
			
		||||
    Copyright (C) 2012 Nathanael C. Fritz, Lance J.T. Stout
 | 
			
		||||
    This file is part of SleekXMPP.
 | 
			
		||||
 | 
			
		||||
    See the file LICENSE for copying permission.
 | 
			
		||||
"""
 | 
			
		||||
 | 
			
		||||
from sleekxmpp.plugins import BasePlugin, register_plugin
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class XEP_0270(BasePlugin):
 | 
			
		||||
 | 
			
		||||
    name = 'xep_0270'
 | 
			
		||||
    description = 'XEP-0270: XMPP Compliance Suites 2010'
 | 
			
		||||
    dependencies = set(['xep_0030', 'xep_0115', 'xep_0054',
 | 
			
		||||
                        'xep_0163', 'xep_0045', 'xep_0085'])
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
register_plugin(XEP_0270)
 | 
			
		||||
							
								
								
									
										21
									
								
								sleekxmpp/plugins/xep_0302.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								sleekxmpp/plugins/xep_0302.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,21 @@
 | 
			
		||||
"""
 | 
			
		||||
    SleekXMPP: The Sleek XMPP Library
 | 
			
		||||
    Copyright (C) 2012 Nathanael C. Fritz, Lance J.T. Stout
 | 
			
		||||
    This file is part of SleekXMPP.
 | 
			
		||||
 | 
			
		||||
    See the file LICENSE for copying permission.
 | 
			
		||||
"""
 | 
			
		||||
 | 
			
		||||
from sleekxmpp.plugins import BasePlugin, register_plugin
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class XEP_0302(BasePlugin):
 | 
			
		||||
 | 
			
		||||
    name = 'xep_0302'
 | 
			
		||||
    description = 'XEP-0302: XMPP Compliance Suites 2012'
 | 
			
		||||
    dependencies = set(['xep_0030', 'xep_0115', 'xep_0054',
 | 
			
		||||
                        'xep_0163', 'xep_0045', 'xep_0085',
 | 
			
		||||
                        'xep_0184', 'xep_0198'])
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
register_plugin(XEP_0302)
 | 
			
		||||
@@ -7,7 +7,7 @@
 | 
			
		||||
"""
 | 
			
		||||
 | 
			
		||||
from sleekxmpp.stanza.rootstanza import RootStanza
 | 
			
		||||
from sleekxmpp.xmlstream import StanzaBase
 | 
			
		||||
from sleekxmpp.xmlstream import StanzaBase, ET
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Message(RootStanza):
 | 
			
		||||
@@ -54,13 +54,14 @@ class Message(RootStanza):
 | 
			
		||||
        del_mucnick -- Dummy method to prevent deletion.
 | 
			
		||||
    """
 | 
			
		||||
 | 
			
		||||
    namespace = 'jabber:client'
 | 
			
		||||
    name = 'message'
 | 
			
		||||
    interfaces = set(('type', 'to', 'from', 'id', 'body', 'subject',
 | 
			
		||||
                      'mucroom', 'mucnick'))
 | 
			
		||||
    sub_interfaces = set(('body', 'subject'))
 | 
			
		||||
    namespace = 'jabber:client'
 | 
			
		||||
    plugin_attrib = name
 | 
			
		||||
    types = set((None, 'normal', 'chat', 'headline', 'error', 'groupchat'))
 | 
			
		||||
    interfaces = set(['type', 'to', 'from', 'id', 'body', 'subject',
 | 
			
		||||
                      'thread', 'parent_thread', 'mucroom', 'mucnick'])
 | 
			
		||||
    sub_interfaces = set(['body', 'subject', 'thread'])
 | 
			
		||||
    lang_interfaces = sub_interfaces
 | 
			
		||||
    types = set(['normal', 'chat', 'headline', 'error', 'groupchat'])
 | 
			
		||||
 | 
			
		||||
    def get_type(self):
 | 
			
		||||
        """
 | 
			
		||||
@@ -72,6 +73,31 @@ class Message(RootStanza):
 | 
			
		||||
        """
 | 
			
		||||
        return self._get_attr('type', 'normal')
 | 
			
		||||
 | 
			
		||||
    def get_parent_thread(self):
 | 
			
		||||
        """Return the message thread's parent thread."""
 | 
			
		||||
        thread = self.xml.find('{%s}thread' % self.namespace)
 | 
			
		||||
        if thread is not None:
 | 
			
		||||
            return thread.attrib.get('parent', '')
 | 
			
		||||
        return ''
 | 
			
		||||
 | 
			
		||||
    def set_parent_thread(self, value):
 | 
			
		||||
        """Add or change the message thread's parent thread."""
 | 
			
		||||
        thread = self.xml.find('{%s}thread' % self.namespace)
 | 
			
		||||
        if value:
 | 
			
		||||
            if thread is None:
 | 
			
		||||
                thread = ET.Element('{%s}thread' % self.namespace)
 | 
			
		||||
                self.xml.append(thread)
 | 
			
		||||
            thread.attrib['parent'] = value
 | 
			
		||||
        else:
 | 
			
		||||
            if thread is not None and 'parent' in thread.attrib:
 | 
			
		||||
                del thread.attrib['parent']
 | 
			
		||||
 | 
			
		||||
    def del_parent_thread(self):
 | 
			
		||||
        """Delete the message thread's parent reference."""
 | 
			
		||||
        thread = self.xml.find('{%s}thread' % self.namespace)
 | 
			
		||||
        if thread is not None and 'parent' in thread.attrib:
 | 
			
		||||
            del thread.attrib['parent']
 | 
			
		||||
 | 
			
		||||
    def chat(self):
 | 
			
		||||
        """Set the message type to 'chat'."""
 | 
			
		||||
        self['type'] = 'chat'
 | 
			
		||||
@@ -96,10 +122,16 @@ class Message(RootStanza):
 | 
			
		||||
            clear -- Indicates if existing content should be removed
 | 
			
		||||
                     before replying. Defaults to True.
 | 
			
		||||
        """
 | 
			
		||||
        thread = self['thread']
 | 
			
		||||
        parent = self['parent_thread']
 | 
			
		||||
 | 
			
		||||
        StanzaBase.reply(self, clear)
 | 
			
		||||
        if self['type'] == 'groupchat':
 | 
			
		||||
            self['to'] = self['to'].bare
 | 
			
		||||
 | 
			
		||||
        self['thread'] = thread
 | 
			
		||||
        self['parent_thread'] = parent
 | 
			
		||||
 | 
			
		||||
        del self['id']
 | 
			
		||||
 | 
			
		||||
        if body is not None:
 | 
			
		||||
 
 | 
			
		||||
@@ -60,16 +60,17 @@ class Presence(RootStanza):
 | 
			
		||||
        set_priority -- Set the value of the <priority> element.
 | 
			
		||||
    """
 | 
			
		||||
 | 
			
		||||
    namespace = 'jabber:client'
 | 
			
		||||
    name = 'presence'
 | 
			
		||||
    interfaces = set(('type', 'to', 'from', 'id', 'show',
 | 
			
		||||
                      'status', 'priority'))
 | 
			
		||||
    sub_interfaces = set(('show', 'status', 'priority'))
 | 
			
		||||
    namespace = 'jabber:client'
 | 
			
		||||
    plugin_attrib = name
 | 
			
		||||
    interfaces = set(['type', 'to', 'from', 'id', 'show',
 | 
			
		||||
                      'status', 'priority'])
 | 
			
		||||
    sub_interfaces = set(['show', 'status', 'priority'])
 | 
			
		||||
    lang_interfaces = set(['status'])
 | 
			
		||||
 | 
			
		||||
    types = set(('available', 'unavailable', 'error', 'probe', 'subscribe',
 | 
			
		||||
                 'subscribed', 'unsubscribe', 'unsubscribed'))
 | 
			
		||||
    showtypes = set(('dnd', 'chat', 'xa', 'away'))
 | 
			
		||||
    types = set(['available', 'unavailable', 'error', 'probe', 'subscribe',
 | 
			
		||||
                 'subscribed', 'unsubscribe', 'unsubscribed'])
 | 
			
		||||
    showtypes = set(['dnd', 'chat', 'xa', 'away'])
 | 
			
		||||
 | 
			
		||||
    def exception(self, e):
 | 
			
		||||
        """
 | 
			
		||||
 
 | 
			
		||||
@@ -9,5 +9,5 @@
 | 
			
		||||
# We don't want to have to import the entire library
 | 
			
		||||
# just to get the version info for setup.py
 | 
			
		||||
 | 
			
		||||
__version__ = '1.1.7'
 | 
			
		||||
__version_info__ = (1, 1, 7, '', 0)
 | 
			
		||||
__version__ = '1.1.8'
 | 
			
		||||
__version_info__ = (1, 1, 8, '', 0)
 | 
			
		||||
 
 | 
			
		||||
@@ -421,12 +421,6 @@ class ElementBase(object):
 | 
			
		||||
        #: ``'{namespace}elementname'``.
 | 
			
		||||
        self.tag = self.tag_name()
 | 
			
		||||
 | 
			
		||||
        if 'lang' not in self.interfaces:
 | 
			
		||||
            if isinstance(self.interfaces, tuple):
 | 
			
		||||
                self.interfaces += ('lang',)
 | 
			
		||||
            else:
 | 
			
		||||
                self.interfaces.add('lang')
 | 
			
		||||
 | 
			
		||||
        #: A :class:`weakref.weakref` to the parent stanza, if there is one.
 | 
			
		||||
        #: If not, then :attr:`parent` is ``None``.
 | 
			
		||||
        self.parent = None
 | 
			
		||||
@@ -574,6 +568,7 @@ class ElementBase(object):
 | 
			
		||||
        .. versionadded:: 1.0-Beta1
 | 
			
		||||
        """
 | 
			
		||||
        values = {}
 | 
			
		||||
        values['lang'] = self['lang']
 | 
			
		||||
        for interface in self.interfaces:
 | 
			
		||||
            values[interface] = self[interface]
 | 
			
		||||
            if interface in self.lang_interfaces:
 | 
			
		||||
@@ -629,6 +624,8 @@ class ElementBase(object):
 | 
			
		||||
                                sub.values = subdict
 | 
			
		||||
                                self.iterables.append(sub)
 | 
			
		||||
                                break
 | 
			
		||||
            elif interface == 'lang':
 | 
			
		||||
                self[interface] = value
 | 
			
		||||
            elif interface in self.interfaces:
 | 
			
		||||
                self[full_interface] = value
 | 
			
		||||
            elif interface in self.plugin_attrib_map:
 | 
			
		||||
@@ -678,7 +675,7 @@ class ElementBase(object):
 | 
			
		||||
 | 
			
		||||
        if attrib == 'substanzas':
 | 
			
		||||
            return self.iterables
 | 
			
		||||
        elif attrib in self.interfaces:
 | 
			
		||||
        elif attrib in self.interfaces or attrib == 'lang':
 | 
			
		||||
            get_method = "get_%s" % attrib.lower()
 | 
			
		||||
            get_method2 = "get%s" % attrib.title()
 | 
			
		||||
 | 
			
		||||
@@ -752,7 +749,7 @@ class ElementBase(object):
 | 
			
		||||
        if lang and attrib in self.lang_interfaces:
 | 
			
		||||
            kwargs['lang'] = lang
 | 
			
		||||
 | 
			
		||||
        if attrib in self.interfaces:
 | 
			
		||||
        if attrib in self.interfaces or attrib == 'lang':
 | 
			
		||||
            if value is not None:
 | 
			
		||||
                set_method = "set_%s" % attrib.lower()
 | 
			
		||||
                set_method2 = "set%s" % attrib.title()
 | 
			
		||||
@@ -838,7 +835,7 @@ class ElementBase(object):
 | 
			
		||||
        if lang and attrib in self.lang_interfaces:
 | 
			
		||||
            kwargs['lang'] = lang
 | 
			
		||||
 | 
			
		||||
        if attrib in self.interfaces:
 | 
			
		||||
        if attrib in self.interfaces or attrib == 'lang':
 | 
			
		||||
            del_method = "del_%s" % attrib.lower()
 | 
			
		||||
            del_method2 = "del%s" % attrib.title()
 | 
			
		||||
 | 
			
		||||
@@ -973,10 +970,6 @@ class ElementBase(object):
 | 
			
		||||
        :param keep: Indicates if the element should be kept if its text is
 | 
			
		||||
                     removed. Defaults to False.
 | 
			
		||||
        """
 | 
			
		||||
        path = self._fix_ns(name, split=True)
 | 
			
		||||
        element = self.xml.find(name)
 | 
			
		||||
        parent = self.xml
 | 
			
		||||
 | 
			
		||||
        default_lang = self.get_lang()
 | 
			
		||||
        if lang is None:
 | 
			
		||||
            lang = default_lang
 | 
			
		||||
@@ -984,32 +977,51 @@ class ElementBase(object):
 | 
			
		||||
        if not text and not keep:
 | 
			
		||||
            return self._del_sub(name, lang=lang)
 | 
			
		||||
 | 
			
		||||
        if element is None:
 | 
			
		||||
            # We need to add the element. If the provided name was
 | 
			
		||||
            # an XPath expression, some of the intermediate elements
 | 
			
		||||
            # may already exist. If so, we want to use those instead
 | 
			
		||||
            # of generating new elements.
 | 
			
		||||
            last_xml = self.xml
 | 
			
		||||
            walked = []
 | 
			
		||||
            for ename in path:
 | 
			
		||||
                walked.append(ename)
 | 
			
		||||
                element = self.xml.find("/".join(walked))
 | 
			
		||||
                if element is None:
 | 
			
		||||
                    element = ET.Element(ename)
 | 
			
		||||
                    if lang:
 | 
			
		||||
                        element.attrib['{%s}lang' % XML_NS] = lang
 | 
			
		||||
                    last_xml.append(element)
 | 
			
		||||
                parent = last_xml
 | 
			
		||||
                last_xml = element
 | 
			
		||||
            element = last_xml
 | 
			
		||||
        path = self._fix_ns(name, split=True)
 | 
			
		||||
        name = path[-1]
 | 
			
		||||
        parent = self.xml
 | 
			
		||||
 | 
			
		||||
        if lang:
 | 
			
		||||
            if element.attrib.get('{%s}lang' % XML_NS, default_lang) != lang:
 | 
			
		||||
                element = ET.Element(ename)
 | 
			
		||||
                element.attrib['{%s}lang' % XML_NS] = lang
 | 
			
		||||
                parent.append(element)
 | 
			
		||||
        # The first goal is to find the parent of the subelement, or, if
 | 
			
		||||
        # we can't find that, the closest grandparent element.
 | 
			
		||||
        missing_path = []
 | 
			
		||||
        search_order = path[:-1]
 | 
			
		||||
        while search_order:
 | 
			
		||||
            parent = self.xml.find('/'.join(search_order))
 | 
			
		||||
            ename = search_order.pop()
 | 
			
		||||
            if parent is not None:
 | 
			
		||||
                break
 | 
			
		||||
            else:
 | 
			
		||||
                missing_path.append(ename)
 | 
			
		||||
        missing_path.reverse()
 | 
			
		||||
 | 
			
		||||
        # Find all existing elements that match the desired
 | 
			
		||||
        # element path (there may be multiples due to different
 | 
			
		||||
        # languages values).
 | 
			
		||||
        if parent is not None:
 | 
			
		||||
            elements = self.xml.findall('/'.join(path))
 | 
			
		||||
        else:
 | 
			
		||||
            parent = self.xml
 | 
			
		||||
            elements = []
 | 
			
		||||
 | 
			
		||||
        # Insert the remaining grandparent elements that don't exist yet.
 | 
			
		||||
        for ename in missing_path:
 | 
			
		||||
            element = ET.Element(ename)
 | 
			
		||||
            parent.append(element)
 | 
			
		||||
            parent = element
 | 
			
		||||
 | 
			
		||||
        # Re-use an existing element with the proper language, if one exists.
 | 
			
		||||
        for element in elements:
 | 
			
		||||
            elang = element.attrib.get('{%s}lang' % XML_NS, default_lang)
 | 
			
		||||
            if not lang and elang == default_lang or lang and lang == elang:
 | 
			
		||||
                element.text = text
 | 
			
		||||
                return element
 | 
			
		||||
 | 
			
		||||
        # No useable element exists, so create a new one.
 | 
			
		||||
        element = ET.Element(name)
 | 
			
		||||
        element.text = text
 | 
			
		||||
        if lang and lang != default_lang:
 | 
			
		||||
            element.attrib['{%s}lang' % XML_NS] = lang
 | 
			
		||||
        parent.append(element)
 | 
			
		||||
        return element
 | 
			
		||||
 | 
			
		||||
    def _set_all_sub_text(self, name, values, keep=False, lang=None):
 | 
			
		||||
@@ -1184,6 +1196,7 @@ class ElementBase(object):
 | 
			
		||||
        out = []
 | 
			
		||||
        out += [x for x in self.interfaces]
 | 
			
		||||
        out += [x for x in self.loaded_plugins]
 | 
			
		||||
        out.append('lang')
 | 
			
		||||
        if self.iterables:
 | 
			
		||||
            out.append('substanzas')
 | 
			
		||||
        return out
 | 
			
		||||
@@ -1263,7 +1276,7 @@ class ElementBase(object):
 | 
			
		||||
        """
 | 
			
		||||
        return "{%s}%s" % (cls.namespace, cls.name)
 | 
			
		||||
 | 
			
		||||
    def get_lang(self):
 | 
			
		||||
    def get_lang(self, lang=None):
 | 
			
		||||
        result = self.xml.attrib.get('{%s}lang' % XML_NS, '')
 | 
			
		||||
        if not result and self.parent and self.parent():
 | 
			
		||||
            return self.parent()['lang']
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,6 @@
 | 
			
		||||
from sleekxmpp.test import *
 | 
			
		||||
from sleekxmpp.xmlstream.stanzabase import ElementBase
 | 
			
		||||
from sleekxmpp.thirdparty import OrderedDict
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class TestElementBase(SleekTest):
 | 
			
		||||
@@ -760,7 +761,7 @@ class TestElementBase(SleekTest):
 | 
			
		||||
          <foo xmlns="foo" />
 | 
			
		||||
        """)
 | 
			
		||||
 | 
			
		||||
        self.assertFalse(stanza['bar'], 
 | 
			
		||||
        self.assertFalse(stanza['bar'],
 | 
			
		||||
                "Returned True for missing bool interface element.")
 | 
			
		||||
 | 
			
		||||
        stanza['bar'] = True
 | 
			
		||||
@@ -797,7 +798,7 @@ class TestElementBase(SleekTest):
 | 
			
		||||
            namespace = 'baz'
 | 
			
		||||
            plugin_attrib = name
 | 
			
		||||
            plugin_multi_attrib = 'bazs'
 | 
			
		||||
           
 | 
			
		||||
 | 
			
		||||
        register_stanza_plugin(TestStanza, TestMultiStanza1, iterable=True)
 | 
			
		||||
        register_stanza_plugin(TestStanza, TestMultiStanza2, iterable=True)
 | 
			
		||||
 | 
			
		||||
@@ -829,9 +830,9 @@ class TestElementBase(SleekTest):
 | 
			
		||||
              <baz xmlns="baz" />
 | 
			
		||||
            """)
 | 
			
		||||
 | 
			
		||||
        self.assertEqual(len(bars), 2, 
 | 
			
		||||
        self.assertEqual(len(bars), 2,
 | 
			
		||||
                "Wrong number of <bar /> stanzas: %s" % len(bars))
 | 
			
		||||
        self.assertEqual(len(bazs), 2, 
 | 
			
		||||
        self.assertEqual(len(bazs), 2,
 | 
			
		||||
                "Wrong number of <baz /> stanzas: %s" % len(bazs))
 | 
			
		||||
 | 
			
		||||
    def testSetMultiAttrib(self):
 | 
			
		||||
@@ -853,7 +854,7 @@ class TestElementBase(SleekTest):
 | 
			
		||||
            namespace = 'baz'
 | 
			
		||||
            plugin_attrib = name
 | 
			
		||||
            plugin_multi_attrib = 'bazs'
 | 
			
		||||
           
 | 
			
		||||
 | 
			
		||||
        register_stanza_plugin(TestStanza, TestMultiStanza1, iterable=True)
 | 
			
		||||
        register_stanza_plugin(TestStanza, TestMultiStanza2, iterable=True)
 | 
			
		||||
 | 
			
		||||
@@ -906,7 +907,7 @@ class TestElementBase(SleekTest):
 | 
			
		||||
            namespace = 'baz'
 | 
			
		||||
            plugin_attrib = name
 | 
			
		||||
            plugin_multi_attrib = 'bazs'
 | 
			
		||||
           
 | 
			
		||||
 | 
			
		||||
        register_stanza_plugin(TestStanza, TestMultiStanza1, iterable=True)
 | 
			
		||||
        register_stanza_plugin(TestStanza, TestMultiStanza2, iterable=True)
 | 
			
		||||
 | 
			
		||||
@@ -938,5 +939,313 @@ class TestElementBase(SleekTest):
 | 
			
		||||
        self.assertEqual(len(stanza['substanzas']), 2,
 | 
			
		||||
            "Wrong number of substanzas: %s" % len(stanza['substanzas']))
 | 
			
		||||
 | 
			
		||||
    def testDefaultLang(self):
 | 
			
		||||
        """Test setting a normal subinterface when a default language is set"""
 | 
			
		||||
 | 
			
		||||
        class TestStanza(ElementBase):
 | 
			
		||||
            name = 'foo'
 | 
			
		||||
            namespace = 'test'
 | 
			
		||||
            interfaces = set(['test'])
 | 
			
		||||
            sub_interfaces = interfaces
 | 
			
		||||
            lang_interfaces = interfaces
 | 
			
		||||
 | 
			
		||||
        stanza = TestStanza()
 | 
			
		||||
        stanza['lang'] = 'sv'
 | 
			
		||||
        stanza['test'] = 'hej'
 | 
			
		||||
 | 
			
		||||
        self.check(stanza, """
 | 
			
		||||
          <foo xmlns="test" xml:lang="sv">
 | 
			
		||||
            <test>hej</test>
 | 
			
		||||
          </foo>
 | 
			
		||||
        """)
 | 
			
		||||
 | 
			
		||||
        self.assertEqual(stanza['test'], 'hej',
 | 
			
		||||
                "Incorrect subinterface value: %s" % stanza['test'])
 | 
			
		||||
 | 
			
		||||
        self.assertEqual(stanza['test|sv'], 'hej',
 | 
			
		||||
                "Incorrect subinterface value: %s" % stanza['test|sv'])
 | 
			
		||||
 | 
			
		||||
    def testSpecifyLangWithDefault(self):
 | 
			
		||||
        """Test specifying various languages."""
 | 
			
		||||
 | 
			
		||||
        class TestStanza(ElementBase):
 | 
			
		||||
            name = 'foo'
 | 
			
		||||
            namespace = 'test'
 | 
			
		||||
            interfaces = set(['test'])
 | 
			
		||||
            sub_interfaces = interfaces
 | 
			
		||||
            lang_interfaces = interfaces
 | 
			
		||||
 | 
			
		||||
        stanza = TestStanza()
 | 
			
		||||
        stanza['lang'] = 'sv'
 | 
			
		||||
        stanza['test'] = 'hej'
 | 
			
		||||
        stanza['test|en'] = 'hi'
 | 
			
		||||
        stanza['test|es'] = 'hola'
 | 
			
		||||
 | 
			
		||||
        self.check(stanza, """
 | 
			
		||||
          <foo xmlns="test" xml:lang="sv">
 | 
			
		||||
            <test>hej</test>
 | 
			
		||||
            <test xml:lang="en">hi</test>
 | 
			
		||||
            <test xml:lang="es">hola</test>
 | 
			
		||||
          </foo>
 | 
			
		||||
        """)
 | 
			
		||||
 | 
			
		||||
        self.assertEqual(stanza['test'], 'hej',
 | 
			
		||||
                "Incorrect subinterface value: %s" % stanza['test'])
 | 
			
		||||
 | 
			
		||||
        self.assertEqual(stanza['test|sv'], 'hej',
 | 
			
		||||
                "Incorrect subinterface value: %s" % stanza['test|sv'])
 | 
			
		||||
 | 
			
		||||
        self.assertEqual(stanza['test|en'], 'hi',
 | 
			
		||||
                "Incorrect subinterface value: %s" % stanza['test|en'])
 | 
			
		||||
 | 
			
		||||
        self.assertEqual(stanza['test|es'], 'hola',
 | 
			
		||||
                "Incorrect subinterface value: %s" % stanza['test|es'])
 | 
			
		||||
 | 
			
		||||
    def testSpecifyLangWithNoDefault(self):
 | 
			
		||||
        """Test specifying various languages."""
 | 
			
		||||
 | 
			
		||||
        class TestStanza(ElementBase):
 | 
			
		||||
            name = 'foo'
 | 
			
		||||
            namespace = 'test'
 | 
			
		||||
            interfaces = set(['test'])
 | 
			
		||||
            sub_interfaces = interfaces
 | 
			
		||||
            lang_interfaces = interfaces
 | 
			
		||||
 | 
			
		||||
        stanza = TestStanza()
 | 
			
		||||
        stanza['test'] = 'hej'
 | 
			
		||||
        stanza['test|en'] = 'hi'
 | 
			
		||||
        stanza['test|es'] = 'hola'
 | 
			
		||||
 | 
			
		||||
        self.check(stanza, """
 | 
			
		||||
          <foo xmlns="test">
 | 
			
		||||
            <test>hej</test>
 | 
			
		||||
            <test xml:lang="en">hi</test>
 | 
			
		||||
            <test xml:lang="es">hola</test>
 | 
			
		||||
          </foo>
 | 
			
		||||
        """)
 | 
			
		||||
 | 
			
		||||
        self.assertEqual(stanza['test'], 'hej',
 | 
			
		||||
                "Incorrect subinterface value: %s" % stanza['test'])
 | 
			
		||||
 | 
			
		||||
        self.assertEqual(stanza['test|en'], 'hi',
 | 
			
		||||
                "Incorrect subinterface value: %s" % stanza['test|en'])
 | 
			
		||||
 | 
			
		||||
        self.assertEqual(stanza['test|es'], 'hola',
 | 
			
		||||
                "Incorrect subinterface value: %s" % stanza['test|es'])
 | 
			
		||||
 | 
			
		||||
    def testModifyLangInterfaceWithDefault(self):
 | 
			
		||||
        """Test resetting an interface when a default lang is used."""
 | 
			
		||||
 | 
			
		||||
        class TestStanza(ElementBase):
 | 
			
		||||
            name = 'foo'
 | 
			
		||||
            namespace = 'test'
 | 
			
		||||
            interfaces = set(['test'])
 | 
			
		||||
            sub_interfaces = interfaces
 | 
			
		||||
            lang_interfaces = interfaces
 | 
			
		||||
 | 
			
		||||
        stanza = TestStanza()
 | 
			
		||||
        stanza['lang'] = 'es'
 | 
			
		||||
        stanza['test'] = 'hola'
 | 
			
		||||
        stanza['test|en'] = 'hi'
 | 
			
		||||
 | 
			
		||||
        self.check(stanza, """
 | 
			
		||||
          <foo xmlns="test" xml:lang="es">
 | 
			
		||||
            <test>hola</test>
 | 
			
		||||
            <test xml:lang="en">hi</test>
 | 
			
		||||
          </foo>
 | 
			
		||||
        """)
 | 
			
		||||
 | 
			
		||||
        stanza['test'] = 'adios'
 | 
			
		||||
        stanza['test|en'] = 'bye'
 | 
			
		||||
 | 
			
		||||
        self.check(stanza, """
 | 
			
		||||
          <foo xmlns="test" xml:lang="es">
 | 
			
		||||
            <test>adios</test>
 | 
			
		||||
            <test xml:lang="en">bye</test>
 | 
			
		||||
          </foo>
 | 
			
		||||
        """)
 | 
			
		||||
 | 
			
		||||
        self.assertEqual(stanza['test'], 'adios',
 | 
			
		||||
                "Incorrect subinterface value: %s" % stanza['test'])
 | 
			
		||||
 | 
			
		||||
        self.assertEqual(stanza['test|es'], 'adios',
 | 
			
		||||
                "Incorrect subinterface value: %s" % stanza['test|es'])
 | 
			
		||||
 | 
			
		||||
        self.assertEqual(stanza['test|en'], 'bye',
 | 
			
		||||
                "Incorrect subinterface value: %s" % stanza['test|en'])
 | 
			
		||||
 | 
			
		||||
        stanza['test|es'] = 'hola'
 | 
			
		||||
 | 
			
		||||
        self.check(stanza, """
 | 
			
		||||
          <foo xmlns="test" xml:lang="es">
 | 
			
		||||
            <test>hola</test>
 | 
			
		||||
            <test xml:lang="en">bye</test>
 | 
			
		||||
          </foo>
 | 
			
		||||
        """)
 | 
			
		||||
 | 
			
		||||
        self.assertEqual(stanza['test'], 'hola',
 | 
			
		||||
                "Incorrect subinterface value: %s" % stanza['test'])
 | 
			
		||||
 | 
			
		||||
        self.assertEqual(stanza['test|es'], 'hola',
 | 
			
		||||
                "Incorrect subinterface value: %s" % stanza['test|es'])
 | 
			
		||||
 | 
			
		||||
    def testModifyLangInterfaceWithNoDefault(self):
 | 
			
		||||
        """Test resetting an interface when no default lang is used."""
 | 
			
		||||
 | 
			
		||||
        class TestStanza(ElementBase):
 | 
			
		||||
            name = 'foo'
 | 
			
		||||
            namespace = 'test'
 | 
			
		||||
            interfaces = set(['test'])
 | 
			
		||||
            sub_interfaces = interfaces
 | 
			
		||||
            lang_interfaces = interfaces
 | 
			
		||||
 | 
			
		||||
        stanza = TestStanza()
 | 
			
		||||
        stanza['test'] = 'hola'
 | 
			
		||||
        stanza['test|en'] = 'hi'
 | 
			
		||||
 | 
			
		||||
        self.check(stanza, """
 | 
			
		||||
          <foo xmlns="test">
 | 
			
		||||
            <test>hola</test>
 | 
			
		||||
            <test xml:lang="en">hi</test>
 | 
			
		||||
          </foo>
 | 
			
		||||
        """)
 | 
			
		||||
 | 
			
		||||
        stanza['test'] = 'adios'
 | 
			
		||||
        stanza['test|en'] = 'bye'
 | 
			
		||||
 | 
			
		||||
        self.check(stanza, """
 | 
			
		||||
          <foo xmlns="test">
 | 
			
		||||
            <test>adios</test>
 | 
			
		||||
            <test xml:lang="en">bye</test>
 | 
			
		||||
          </foo>
 | 
			
		||||
        """)
 | 
			
		||||
 | 
			
		||||
        self.assertEqual(stanza['test'], 'adios',
 | 
			
		||||
                "Incorrect subinterface value: %s" % stanza['test'])
 | 
			
		||||
 | 
			
		||||
        self.assertEqual(stanza['test'], 'adios',
 | 
			
		||||
                "Incorrect subinterface value: %s" % stanza['test|es'])
 | 
			
		||||
 | 
			
		||||
        self.assertEqual(stanza['test|en'], 'bye',
 | 
			
		||||
                "Incorrect subinterface value: %s" % stanza['test|en'])
 | 
			
		||||
 | 
			
		||||
    def testDelInterfacesWithDefaultLang(self):
 | 
			
		||||
        """Test deleting interfaces with a default lang set."""
 | 
			
		||||
 | 
			
		||||
        class TestStanza(ElementBase):
 | 
			
		||||
            name = 'foo'
 | 
			
		||||
            namespace = 'test'
 | 
			
		||||
            interfaces = set(['test'])
 | 
			
		||||
            sub_interfaces = interfaces
 | 
			
		||||
            lang_interfaces = interfaces
 | 
			
		||||
 | 
			
		||||
        stanza = TestStanza()
 | 
			
		||||
        stanza['lang'] = 'en'
 | 
			
		||||
        stanza['test'] = 'hi'
 | 
			
		||||
        stanza['test|no'] = 'hej'
 | 
			
		||||
        stanza['test|fr'] = 'bonjour'
 | 
			
		||||
 | 
			
		||||
        self.check(stanza, """
 | 
			
		||||
          <foo xmlns="test" xml:lang="en">
 | 
			
		||||
            <test>hi</test>
 | 
			
		||||
            <test xml:lang="no">hej</test>
 | 
			
		||||
            <test xml:lang="fr">bonjour</test>
 | 
			
		||||
          </foo>
 | 
			
		||||
        """)
 | 
			
		||||
 | 
			
		||||
        del stanza['test']
 | 
			
		||||
 | 
			
		||||
        self.check(stanza, """
 | 
			
		||||
          <foo xmlns="test" xml:lang="en">
 | 
			
		||||
            <test xml:lang="no">hej</test>
 | 
			
		||||
            <test xml:lang="fr">bonjour</test>
 | 
			
		||||
          </foo>
 | 
			
		||||
        """)
 | 
			
		||||
 | 
			
		||||
        del stanza['test|no']
 | 
			
		||||
 | 
			
		||||
        self.check(stanza, """
 | 
			
		||||
          <foo xmlns="test" xml:lang="en">
 | 
			
		||||
            <test xml:lang="fr">bonjour</test>
 | 
			
		||||
          </foo>
 | 
			
		||||
        """)
 | 
			
		||||
 | 
			
		||||
    def testDelInterfacesWithNoDefaultLang(self):
 | 
			
		||||
        """Test deleting interfaces with no default lang set."""
 | 
			
		||||
 | 
			
		||||
        class TestStanza(ElementBase):
 | 
			
		||||
            name = 'foo'
 | 
			
		||||
            namespace = 'test'
 | 
			
		||||
            interfaces = set(['test'])
 | 
			
		||||
            sub_interfaces = interfaces
 | 
			
		||||
            lang_interfaces = interfaces
 | 
			
		||||
 | 
			
		||||
        stanza = TestStanza()
 | 
			
		||||
        stanza['test'] = 'hi'
 | 
			
		||||
        stanza['test|no'] = 'hej'
 | 
			
		||||
        stanza['test|fr'] = 'bonjour'
 | 
			
		||||
 | 
			
		||||
        self.check(stanza, """
 | 
			
		||||
          <foo xmlns="test">
 | 
			
		||||
            <test>hi</test>
 | 
			
		||||
            <test xml:lang="no">hej</test>
 | 
			
		||||
            <test xml:lang="fr">bonjour</test>
 | 
			
		||||
          </foo>
 | 
			
		||||
        """)
 | 
			
		||||
 | 
			
		||||
        del stanza['test']
 | 
			
		||||
 | 
			
		||||
        self.check(stanza, """
 | 
			
		||||
          <foo xmlns="test">
 | 
			
		||||
            <test xml:lang="no">hej</test>
 | 
			
		||||
            <test xml:lang="fr">bonjour</test>
 | 
			
		||||
          </foo>
 | 
			
		||||
        """)
 | 
			
		||||
 | 
			
		||||
        del stanza['test|no']
 | 
			
		||||
 | 
			
		||||
        self.check(stanza, """
 | 
			
		||||
          <foo xmlns="test">
 | 
			
		||||
            <test xml:lang="fr">bonjour</test>
 | 
			
		||||
          </foo>
 | 
			
		||||
        """)
 | 
			
		||||
 | 
			
		||||
    def testStarLang(self):
 | 
			
		||||
        """Test using interface|*."""
 | 
			
		||||
 | 
			
		||||
        class TestStanza(ElementBase):
 | 
			
		||||
            name = 'foo'
 | 
			
		||||
            namespace = 'test'
 | 
			
		||||
            interfaces = set(['test'])
 | 
			
		||||
            sub_interfaces = interfaces
 | 
			
		||||
            lang_interfaces = interfaces
 | 
			
		||||
 | 
			
		||||
        data = OrderedDict()
 | 
			
		||||
        data['en'] = 'hi'
 | 
			
		||||
        data['fr'] = 'bonjour'
 | 
			
		||||
        data['no'] = 'hej'
 | 
			
		||||
 | 
			
		||||
        stanza = TestStanza()
 | 
			
		||||
        stanza['test|*'] = data
 | 
			
		||||
 | 
			
		||||
        self.check(stanza, """
 | 
			
		||||
          <foo xmlns="test">
 | 
			
		||||
            <test xml:lang="en">hi</test>
 | 
			
		||||
            <test xml:lang="fr">bonjour</test>
 | 
			
		||||
            <test xml:lang="no">hej</test>
 | 
			
		||||
          </foo>
 | 
			
		||||
        """)
 | 
			
		||||
 | 
			
		||||
        data2 = stanza['test|*']
 | 
			
		||||
 | 
			
		||||
        self.assertEqual(data, data2,
 | 
			
		||||
                "Did not extract expected language data: %s" % data2)
 | 
			
		||||
 | 
			
		||||
        del stanza['test|*']
 | 
			
		||||
 | 
			
		||||
        self.check(stanza, """
 | 
			
		||||
          <foo xmlns="test" />
 | 
			
		||||
        """)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
suite = unittest.TestLoader().loadTestsFromTestCase(TestElementBase)
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user