From 8aa4396e4490a964e3e1b1a5e6f555e97c16fd3d Mon Sep 17 00:00:00 2001 From: Lance Stout Date: Tue, 31 May 2011 12:48:43 -0700 Subject: [PATCH 1/2] Begin experimental use of exceptions. Provides IqTimeout and IqError which are raised when an Iq response does not arrive in time, or it arrives with type='error'. --- sleekxmpp/clientxmpp.py | 11 +++-------- sleekxmpp/exceptions.py | 13 +++++++++++++ sleekxmpp/stanza/iq.py | 8 +++++++- sleekxmpp/test/sleektest.py | 1 + tests/test_stream_handlers.py | 5 ++++- tests/test_stream_roster.py | 15 ++++----------- 6 files changed, 32 insertions(+), 21 deletions(-) diff --git a/sleekxmpp/clientxmpp.py b/sleekxmpp/clientxmpp.py index fb5b208..7771054 100644 --- a/sleekxmpp/clientxmpp.py +++ b/sleekxmpp/clientxmpp.py @@ -231,8 +231,8 @@ class ClientXMPP(BaseXMPP): 'subscription': subscription, 'groups': groups}} response = iq.send(block, timeout, callback) - if response in [False, None] or not isinstance(response, Iq): - return response + if response is None: + return None return response['type'] == 'result' def del_roster_item(self, jid): @@ -265,12 +265,7 @@ class ClientXMPP(BaseXMPP): iq.enable('roster') response = iq.send(block, timeout, callback) - if response == False: - self.event('roster_timeout') - - if response in [False, None] or not isinstance(response, Iq): - return response - else: + if callback is None: return self._handle_roster(response, request=True) def _handle_stream_features(self, features): diff --git a/sleekxmpp/exceptions.py b/sleekxmpp/exceptions.py index 4727f0c..72c0860 100644 --- a/sleekxmpp/exceptions.py +++ b/sleekxmpp/exceptions.py @@ -52,3 +52,16 @@ class XMPPError(Exception): self.extension = extension self.extension_ns = extension_ns self.extension_args = extension_args + + +class IqTimeout(Exception): + + """ + An exception which indicates that an IQ request response has not been + received within the alloted time window. + """ + +class IqError(Exception): + + def __init__(self, iq): + self.iq = iq diff --git a/sleekxmpp/stanza/iq.py b/sleekxmpp/stanza/iq.py index 4a12a87..71419bc 100644 --- a/sleekxmpp/stanza/iq.py +++ b/sleekxmpp/stanza/iq.py @@ -11,6 +11,7 @@ from sleekxmpp.stanza.rootstanza import RootStanza from sleekxmpp.xmlstream import StanzaBase, ET from sleekxmpp.xmlstream.handler import Waiter, Callback from sleekxmpp.xmlstream.matcher import MatcherId +from sleekxmpp.exceptions import IqTimeout, IqError class Iq(RootStanza): @@ -197,7 +198,12 @@ class Iq(RootStanza): waitfor = Waiter('IqWait_%s' % self['id'], MatcherId(self['id'])) self.stream.register_handler(waitfor) StanzaBase.send(self, now=now) - return waitfor.wait(timeout) + result = waitfor.wait(timeout) + if not result: + raise IqTimeout() + if result['type'] == 'error': + raise IqError(result) + return result else: return StanzaBase.send(self, now=now) diff --git a/sleekxmpp/test/sleektest.py b/sleekxmpp/test/sleektest.py index 7802a9b..b607a94 100644 --- a/sleekxmpp/test/sleektest.py +++ b/sleekxmpp/test/sleektest.py @@ -16,6 +16,7 @@ import sleekxmpp from sleekxmpp import ClientXMPP, ComponentXMPP from sleekxmpp.stanza import Message, Iq, Presence from sleekxmpp.test import TestSocket, TestLiveSocket +from sleekxmpp.exceptions import XMPPError, IqTimeout, IqError from sleekxmpp.xmlstream import ET, register_stanza_plugin from sleekxmpp.xmlstream import ElementBase, StanzaBase from sleekxmpp.xmlstream.tostring import tostring diff --git a/tests/test_stream_handlers.py b/tests/test_stream_handlers.py index dae4456..1b831e2 100644 --- a/tests/test_stream_handlers.py +++ b/tests/test_stream_handlers.py @@ -90,7 +90,10 @@ class TestHandlers(SleekTest): iq['id'] = 'test2' iq['type'] = 'set' iq['query'] = 'test2' - reply = iq.send(block=True, timeout=0) + try: + reply = iq.send(block=True, timeout=0) + except IqTimeout: + pass self.xmpp.add_event_handler('message', waiter_handler, threaded=True) diff --git a/tests/test_stream_roster.py b/tests/test_stream_roster.py index e1aa176..9516374 100644 --- a/tests/test_stream_roster.py +++ b/tests/test_stream_roster.py @@ -111,19 +111,12 @@ class TestStreamRoster(SleekTest): def testRosterTimeout(self): """Test handling a timed out roster request.""" self.stream_start() - events = [] - def roster_timeout(event): - events.append('roster_timeout') + def do_test(): + self.xmpp.get_roster(timeout=0) + time.sleep(.1) - self.xmpp.add_event_handler('roster_timeout', roster_timeout) - self.xmpp.get_roster(timeout=0) - - # Give the event queue time to process. - time.sleep(.1) - - self.failUnless(events == ['roster_timeout'], - "Roster timeout event not triggered: %s." % events) + self.assertRaises(IqTimeout, do_test) def testRosterCallback(self): """Test handling a roster request callback.""" From 20d053807da1f59a2f7507fb7bb3845d31e27445 Mon Sep 17 00:00:00 2001 From: Lance Stout Date: Wed, 1 Jun 2011 15:28:33 -0700 Subject: [PATCH 2/2] IqTimeout now references the original sent stanza. A little extra bit of docs for IqError. --- sleekxmpp/exceptions.py | 8 ++++++++ sleekxmpp/stanza/iq.py | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/sleekxmpp/exceptions.py b/sleekxmpp/exceptions.py index 72c0860..8329a3c 100644 --- a/sleekxmpp/exceptions.py +++ b/sleekxmpp/exceptions.py @@ -61,7 +61,15 @@ class IqTimeout(Exception): received within the alloted time window. """ + def __init__(self, iq): + self.iq = iq + class IqError(Exception): + """ + An exception raised when an Iq stanza of type 'error' is received + after making a blocking send call. + """ + def __init__(self, iq): self.iq = iq diff --git a/sleekxmpp/stanza/iq.py b/sleekxmpp/stanza/iq.py index 71419bc..f05dad1 100644 --- a/sleekxmpp/stanza/iq.py +++ b/sleekxmpp/stanza/iq.py @@ -200,7 +200,7 @@ class Iq(RootStanza): StanzaBase.send(self, now=now) result = waitfor.wait(timeout) if not result: - raise IqTimeout() + raise IqTimeout(self) if result['type'] == 'error': raise IqError(result) return result