diff --git a/slixmpp/xmlstream/asyncio.py b/slixmpp/xmlstream/asyncio.py new file mode 100644 index 00000000..52610d01 --- /dev/null +++ b/slixmpp/xmlstream/asyncio.py @@ -0,0 +1,32 @@ +""" +A module that monkey patches the standard asyncio module to add an +idle_call() method to the main loop. This method is used to execute a +callback whenever the loop is not busy handling anything else. This means +that it is a callback with lower priority than IO, timer, or even +call_soon() ones. These callback are called only once each. +""" + +import asyncio +from asyncio import tasks, events + +def idle_call(self, callback): + if tasks.iscoroutinefunction(callback): + raise TypeError("coroutines cannot be used with idle_call()") + handle = events.Handle(callback, [], self) + self._idle.append(handle) + +def my_run_once(self): + if self._idle: + self._ready.append(events.Handle(lambda: None, (), self)) + real_run_once(self) + if self._idle: + handle = self._idle.pop(0) + handle._run() + +cls = asyncio.get_event_loop().__class__ + +cls._idle = [] +cls.idle_call = idle_call +real_run_once = cls._run_once +cls._run_once = my_run_once + diff --git a/slixmpp/xmlstream/resolver.py b/slixmpp/xmlstream/resolver.py index a3697d14..f2c3f989 100644 --- a/slixmpp/xmlstream/resolver.py +++ b/slixmpp/xmlstream/resolver.py @@ -8,7 +8,7 @@ :license: MIT, see LICENSE for more details """ -import asyncio +from slixmpp.xmlstream.asyncio import asyncio import socket import logging import random diff --git a/slixmpp/xmlstream/xmlstream.py b/slixmpp/xmlstream/xmlstream.py index 187bfbc5..f1abfca6 100644 --- a/slixmpp/xmlstream/xmlstream.py +++ b/slixmpp/xmlstream/xmlstream.py @@ -12,7 +12,6 @@ :license: MIT, see LICENSE for more details """ -import asyncio import functools import copy import logging @@ -23,6 +22,7 @@ import uuid import xml.etree.ElementTree +from slixmpp.xmlstream.asyncio import asyncio from slixmpp.xmlstream import tostring from slixmpp.xmlstream.stanzabase import StanzaBase, ElementBase from slixmpp.xmlstream.resolver import resolve, default_resolver @@ -377,7 +377,8 @@ class XMLStream(object): elif self.xml_depth == 1: # A stanza is an XML element that is a direct child of # the root element, hence the check of depth == 1 - self.__spawn_event(xml) + asyncio.get_event_loop().\ + idle_call(functools.partial(self.__spawn_event, xml)) if self.xml_root is not None: # Keep the root element empty of children to # save on memory use.