Updated presence stanza with documentation and PEP8 style.

This commit is contained in:
Lance Stout 2010-08-03 17:30:34 -04:00
parent 939ae298c2
commit 41ab2b8460
2 changed files with 178 additions and 87 deletions

View file

@ -6,26 +6,90 @@
See the file LICENSE for copying permission. See the file LICENSE for copying permission.
""" """
from . error import Error from sleekxmpp.stanza import Error
from . rootstanza import RootStanza from sleekxmpp.stanza.rootstanza import RootStanza
from .. xmlstream.stanzabase import StanzaBase, ET from sleekxmpp.xmlstream.stanzabase import StanzaBase, ET
class Presence(RootStanza): class Presence(RootStanza):
interfaces = set(('type', 'to', 'from', 'id', 'show', 'status', 'priority'))
types = set(('available', 'unavailable', 'error', 'probe', 'subscribe', 'subscribed', 'unsubscribe', 'unsubscribed')) """
showtypes = set(('dnd', 'chat', 'xa', 'away')) XMPP's <presence> stanza allows entities to know the status of other
sub_interfaces = set(('show', 'status', 'priority')) clients and components. Since it is currently the only multi-cast
name = 'presence' stanza in XMPP, many extensions add more information to <presence>
plugin_attrib = name stanzas to broadcast to every entry in the roster, such as
capabilities, music choices, or locations (XEP-0115: Entity Capabilities
and XEP-0163: Personal Eventing Protocol).
Since <presence> stanzas are broadcast when an XMPP entity changes
its status, the bulk of the traffic in an XMPP network will be from
<presence> stanzas. Therefore, do not include more information than
necessary in a status message or within a <presence> stanza in order
to help keep the network running smoothly.
Example <presence> stanzas:
<presence />
<presence from="user@example.com">
<show>away</show>
<status>Getting lunch.</status>
<priority>5</priority>
</presence>
<presence type="unavailable" />
<presence to="user@otherhost.com" type="subscribe" />
Stanza Interface:
priority -- A value used by servers to determine message routing.
show -- The type of status, such as away or available for chat.
status -- Custom, human readable status message.
Attributes:
types -- One of: available, unavailable, error, probe,
subscribe, subscribed, unsubscribe,
and unsubscribed.
showtypes -- One of: away, chat, dnd, and xa.
Methods:
reply -- Overrides StanzaBase.reply
setShow -- Set the value of the <show> element.
getType -- Get the value of the type attribute or <show> element.
setType -- Set the value of the type attribute or <show> element.
getPriority -- Get the value of the <priority> element.
setPriority -- Set the value of the <priority> element.
"""
namespace = 'jabber:client' namespace = 'jabber:client'
name = 'presence'
interfaces = set(('type', 'to', 'from', 'id', 'show',
'status', 'priority'))
sub_interfaces = set(('show', 'status', 'priority'))
plugin_attrib = name
types = set(('available', 'unavailable', 'error', 'probe', 'subscribe',
'subscribed', 'unsubscribe', 'unsubscribed'))
showtypes = set(('dnd', 'chat', 'xa', 'away'))
def setShow(self, show): def setShow(self, show):
"""
Set the value of the <show> element.
Arguments:
show -- Must be one of: away, chat, dnd, or xa.
"""
if show in self.showtypes: if show in self.showtypes:
self._setSubText('show', text=show) self._setSubText('show', text=show)
return self return self
def setType(self, value): def setType(self, value):
"""
Set the type attribute's value, and the <show> element
if applicable.
Arguments:
value -- Must be in either self.types or self.showtypes.
"""
if value in self.types: if value in self.types:
self['show'] = None self['show'] = None
if value == 'available': if value == 'available':
@ -36,14 +100,32 @@ class Presence(RootStanza):
return self return self
def setPriority(self, value): def setPriority(self, value):
self._setSubText('priority', text = str(value)) """
Set the entity's priority value. Some server use priority to
determine message routing behavior.
Bot clients should typically use a priority of 0 if the same
JID is used elsewhere by a human-interacting client.
Arguments:
value -- An integer value greater than or equal to 0.
"""
self._setSubText('priority', text=str(value))
def getPriority(self): def getPriority(self):
"""
Return the value of the <presence> element as an integer.
"""
p = self._getSubText('priority') p = self._getSubText('priority')
if not p: p = 0 if not p:
p = 0
return int(p) return int(p)
def getType(self): def getType(self):
"""
Return the value of the <presence> stanza's type attribute, or
the value of the <show> element.
"""
out = self._getAttr('type') out = self._getAttr('type')
if not out: if not out:
out = self['show'] out = self['show']
@ -52,6 +134,11 @@ class Presence(RootStanza):
return out return out
def reply(self): def reply(self):
"""
Set the appropriate presence reply type.
Overrides StanzaBase.reply.
"""
if self['type'] == 'unsubscribe': if self['type'] == 'unsubscribe':
self['type'] = 'unsubscribed' self['type'] = 'unsubscribed'
elif self['type'] == 'subscribe': elif self['type'] == 'subscribe':

View file

@ -2,52 +2,56 @@ import sleekxmpp
from sleektest import * from sleektest import *
from sleekxmpp.stanza.presence import Presence from sleekxmpp.stanza.presence import Presence
class TestPresenceStanzas(SleekTest): class TestPresenceStanzas(SleekTest):
def testPresenceShowRegression(self): def testPresenceShowRegression(self):
"""Regression check presence['type'] = 'dnd' show value working""" """Regression check presence['type'] = 'dnd' show value working"""
p = self.Presence() p = self.Presence()
p['type'] = 'dnd' p['type'] = 'dnd'
self.checkPresence(p, """ self.checkPresence(p, "<presence><show>dnd</show></presence>")
<presence><show>dnd</show></presence>
""")
def testPresenceType(self): def testPresenceType(self):
"""Test manipulating presence['type']""" """Test manipulating presence['type']"""
p = self.Presence() p = self.Presence()
p['type'] = 'available' p['type'] = 'available'
self.checkPresence(p, """ self.checkPresence(p, "<presence />")
<presence /> self.failUnless(p['type'] == 'available',
""") "Incorrect presence['type'] for type 'available'")
self.failUnless(p['type'] == 'available', "Incorrect presence['type'] for type 'available'")
for showtype in ['away', 'chat', 'dnd', 'xa']: for showtype in ['away', 'chat', 'dnd', 'xa']:
p['type'] = showtype p['type'] = showtype
self.checkPresence(p, """ self.checkPresence(p, """
<presence><show>%s</show></presence> <presence><show>%s</show></presence>
""" % showtype) """ % showtype)
self.failUnless(p['type'] == showtype, "Incorrect presence['type'] for type '%s'" % showtype) self.failUnless(p['type'] == showtype,
"Incorrect presence['type'] for type '%s'" % showtype)
p['type'] = None p['type'] = None
self.checkPresence(p, """ self.checkPresence(p, "<presence />")
<presence />
""")
def testPresenceUnsolicitedOffline(self): def testPresenceUnsolicitedOffline(self):
"""Unsolicted offline presence does not spawn changed_status or update roster""" """
Unsolicted offline presence does not spawn changed_status
or update the roster.
"""
p = self.Presence() p = self.Presence()
p['type'] = 'unavailable' p['type'] = 'unavailable'
p['from'] = 'bill@chadmore.com/gmail15af' p['from'] = 'bill@chadmore.com/gmail15af'
c = sleekxmpp.ClientXMPP('crap@wherever', 'password') c = sleekxmpp.ClientXMPP('crap@wherever', 'password')
happened = [] happened = []
def handlechangedpresence(event): def handlechangedpresence(event):
happened.append(True) happened.append(True)
c.add_event_handler("changed_status", handlechangedpresence) c.add_event_handler("changed_status", handlechangedpresence)
c._handlePresence(p) c._handlePresence(p)
self.failUnless(happened == [], "changed_status event triggered for superfulous unavailable presence") self.failUnless(happened == [],
self.failUnless(c.roster == {}, "Roster updated for superfulous unavailable presence") "changed_status event triggered for extra unavailable presence")
self.failUnless(c.roster == {},
"Roster updated for superfulous unavailable presence")
suite = unittest.TestLoader().loadTestsFromTestCase(TestPresenceStanzas) suite = unittest.TestLoader().loadTestsFromTestCase(TestPresenceStanzas)