summaryrefslogtreecommitdiff
path: root/slixmpp/xmlstream/handler
diff options
context:
space:
mode:
Diffstat (limited to 'slixmpp/xmlstream/handler')
-rw-r--r--slixmpp/xmlstream/handler/base.py32
-rw-r--r--slixmpp/xmlstream/handler/callback.py28
-rw-r--r--slixmpp/xmlstream/handler/collector.py40
-rw-r--r--slixmpp/xmlstream/handler/coroutine_callback.py39
-rw-r--r--slixmpp/xmlstream/handler/waiter.py45
-rw-r--r--slixmpp/xmlstream/handler/xmlcallback.py5
-rw-r--r--slixmpp/xmlstream/handler/xmlwaiter.py5
7 files changed, 129 insertions, 65 deletions
diff --git a/slixmpp/xmlstream/handler/base.py b/slixmpp/xmlstream/handler/base.py
index 1e657777..0bae5674 100644
--- a/slixmpp/xmlstream/handler/base.py
+++ b/slixmpp/xmlstream/handler/base.py
@@ -4,10 +4,19 @@
# Part of Slixmpp: The Slick XMPP Library
# :copyright: (c) 2011 Nathanael C. Fritz
# :license: MIT, see LICENSE for more details
+from __future__ import annotations
+
import weakref
+from weakref import ReferenceType
+from typing import Optional, TYPE_CHECKING, Union
+from slixmpp.xmlstream.matcher.base import MatcherBase
+from xml.etree.ElementTree import Element
+
+if TYPE_CHECKING:
+ from slixmpp.xmlstream import XMLStream, StanzaBase
-class BaseHandler(object):
+class BaseHandler:
"""
Base class for stream handlers. Stream handlers are matched with
@@ -26,8 +35,13 @@ class BaseHandler(object):
:param stream: The :class:`~slixmpp.xmlstream.xmlstream.XMLStream`
instance that the handle will respond to.
"""
+ name: str
+ stream: Optional[ReferenceType[XMLStream]]
+ _destroy: bool
+ _matcher: MatcherBase
+ _payload: Optional[StanzaBase]
- def __init__(self, name, matcher, stream=None):
+ def __init__(self, name: str, matcher: MatcherBase, stream: Optional[XMLStream] = None):
#: The name of the handler
self.name = name
@@ -41,33 +55,33 @@ class BaseHandler(object):
self._payload = None
self._matcher = matcher
- def match(self, xml):
+ def match(self, xml: StanzaBase) -> bool:
"""Compare a stanza or XML object with the handler's matcher.
:param xml: An XML or
- :class:`~slixmpp.xmlstream.stanzabase.ElementBase` object
+ :class:`~slixmpp.xmlstream.stanzabase.StanzaBase` object
"""
return self._matcher.match(xml)
- def prerun(self, payload):
+ def prerun(self, payload: StanzaBase) -> None:
"""Prepare the handler for execution while the XML
stream is being processed.
- :param payload: A :class:`~slixmpp.xmlstream.stanzabase.ElementBase`
+ :param payload: A :class:`~slixmpp.xmlstream.stanzabase.StanzaBase`
object.
"""
self._payload = payload
- def run(self, payload):
+ def run(self, payload: StanzaBase) -> None:
"""Execute the handler after XML stream processing and during the
main event loop.
- :param payload: A :class:`~slixmpp.xmlstream.stanzabase.ElementBase`
+ :param payload: A :class:`~slixmpp.xmlstream.stanzabase.StanzaBase`
object.
"""
self._payload = payload
- def check_delete(self):
+ def check_delete(self) -> bool:
"""Check if the handler should be removed from the list
of stream handlers.
"""
diff --git a/slixmpp/xmlstream/handler/callback.py b/slixmpp/xmlstream/handler/callback.py
index 93cec6b7..50dd4c66 100644
--- a/slixmpp/xmlstream/handler/callback.py
+++ b/slixmpp/xmlstream/handler/callback.py
@@ -1,10 +1,17 @@
-
# slixmpp.xmlstream.handler.callback
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Part of Slixmpp: The Slick XMPP Library
# :copyright: (c) 2011 Nathanael C. Fritz
# :license: MIT, see LICENSE for more details
+from __future__ import annotations
+
+from typing import Optional, Callable, Any, TYPE_CHECKING
from slixmpp.xmlstream.handler.base import BaseHandler
+from slixmpp.xmlstream.matcher.base import MatcherBase
+
+if TYPE_CHECKING:
+ from slixmpp.xmlstream.stanzabase import StanzaBase
+ from slixmpp.xmlstream.xmlstream import XMLStream
class Callback(BaseHandler):
@@ -28,8 +35,6 @@ class Callback(BaseHandler):
:param matcher: A :class:`~slixmpp.xmlstream.matcher.base.MatcherBase`
derived object for matching stanza objects.
:param pointer: The function to execute during callback.
- :param bool thread: **DEPRECATED.** Remains only for
- backwards compatibility.
:param bool once: Indicates if the handler should be used only
once. Defaults to False.
:param bool instream: Indicates if the callback should be executed
@@ -38,31 +43,36 @@ class Callback(BaseHandler):
:param stream: The :class:`~slixmpp.xmlstream.xmlstream.XMLStream`
instance this handler should monitor.
"""
+ _once: bool
+ _instream: bool
- def __init__(self, name, matcher, pointer, thread=False,
- once=False, instream=False, stream=None):
+ def __init__(self, name: str, matcher: MatcherBase,
+ pointer: Callable[[StanzaBase], Any],
+ once: bool = False, instream: bool = False,
+ stream: Optional[XMLStream] = None):
BaseHandler.__init__(self, name, matcher, stream)
+ self._pointer: Callable[[StanzaBase], Any] = pointer
self._pointer = pointer
self._once = once
self._instream = instream
- def prerun(self, payload):
+ def prerun(self, payload: StanzaBase) -> None:
"""Execute the callback during stream processing, if
the callback was created with ``instream=True``.
:param payload: The matched
- :class:`~slixmpp.xmlstream.stanzabase.ElementBase` object.
+ :class:`~slixmpp.xmlstream.stanzabase.StanzaBase` object.
"""
if self._once:
self._destroy = True
if self._instream:
self.run(payload, True)
- def run(self, payload, instream=False):
+ def run(self, payload: StanzaBase, instream: bool = False) -> None:
"""Execute the callback function with the matched stanza payload.
:param payload: The matched
- :class:`~slixmpp.xmlstream.stanzabase.ElementBase` object.
+ :class:`~slixmpp.xmlstream.stanzabase.StanzaBase` object.
:param bool instream: Force the handler to execute during stream
processing. This should only be used by
:meth:`prerun()`. Defaults to ``False``.
diff --git a/slixmpp/xmlstream/handler/collector.py b/slixmpp/xmlstream/handler/collector.py
index 8d012873..a5ee109c 100644
--- a/slixmpp/xmlstream/handler/collector.py
+++ b/slixmpp/xmlstream/handler/collector.py
@@ -4,11 +4,17 @@
# Part of Slixmpp: The Slick XMPP Library
# :copyright: (c) 2012 Nathanael C. Fritz, Lance J.T. Stout
# :license: MIT, see LICENSE for more details
+from __future__ import annotations
+
import logging
-from queue import Queue, Empty
+from typing import List, Optional, TYPE_CHECKING
+from slixmpp.xmlstream.stanzabase import StanzaBase
from slixmpp.xmlstream.handler.base import BaseHandler
+from slixmpp.xmlstream.matcher.base import MatcherBase
+if TYPE_CHECKING:
+ from slixmpp.xmlstream.xmlstream import XMLStream
log = logging.getLogger(__name__)
@@ -27,35 +33,35 @@ class Collector(BaseHandler):
:param stream: The :class:`~slixmpp.xmlstream.xmlstream.XMLStream`
instance this handler should monitor.
"""
+ _stanzas: List[StanzaBase]
- def __init__(self, name, matcher, stream=None):
+ def __init__(self, name: str, matcher: MatcherBase, stream: Optional[XMLStream] = None):
BaseHandler.__init__(self, name, matcher, stream=stream)
- self._payload = Queue()
+ self._stanzas = []
- def prerun(self, payload):
+ def prerun(self, payload: StanzaBase) -> None:
"""Store the matched stanza when received during processing.
:param payload: The matched
- :class:`~slixmpp.xmlstream.stanzabase.ElementBase` object.
+ :class:`~slixmpp.xmlstream.stanzabase.StanzaBase` object.
"""
- self._payload.put(payload)
+ self._stanzas.append(payload)
- def run(self, payload):
+ def run(self, payload: StanzaBase) -> None:
"""Do not process this handler during the main event loop."""
pass
- def stop(self):
+ def stop(self) -> List[StanzaBase]:
"""
Stop collection of matching stanzas, and return the ones that
have been stored so far.
"""
+ stream_ref = self.stream
+ if stream_ref is None:
+ raise ValueError('stop() called without a stream!')
+ stream = stream_ref()
+ if stream is None:
+ raise ValueError('stop() called without a stream!')
self._destroy = True
- results = []
- try:
- while True:
- results.append(self._payload.get(False))
- except Empty:
- pass
-
- self.stream().remove_handler(self.name)
- return results
+ stream.remove_handler(self.name)
+ return self._stanzas
diff --git a/slixmpp/xmlstream/handler/coroutine_callback.py b/slixmpp/xmlstream/handler/coroutine_callback.py
index 6568ba9f..524cca54 100644
--- a/slixmpp/xmlstream/handler/coroutine_callback.py
+++ b/slixmpp/xmlstream/handler/coroutine_callback.py
@@ -4,8 +4,19 @@
# Part of Slixmpp: The Slick XMPP Library
# :copyright: (c) 2011 Nathanael C. Fritz
# :license: MIT, see LICENSE for more details
+from __future__ import annotations
+
+from asyncio import iscoroutinefunction, ensure_future
+from typing import Optional, Callable, Awaitable, TYPE_CHECKING
+
+from slixmpp.xmlstream.stanzabase import StanzaBase
from slixmpp.xmlstream.handler.base import BaseHandler
-from slixmpp.xmlstream.asyncio import asyncio
+from slixmpp.xmlstream.matcher.base import MatcherBase
+
+CoroutineFunction = Callable[[StanzaBase], Awaitable[None]]
+
+if TYPE_CHECKING:
+ from slixmpp.xmlstream.xmlstream import XMLStream
class CoroutineCallback(BaseHandler):
@@ -34,45 +45,49 @@ class CoroutineCallback(BaseHandler):
instance this handler should monitor.
"""
- def __init__(self, name, matcher, pointer, once=False,
- instream=False, stream=None):
+ _once: bool
+ _instream: bool
+
+ def __init__(self, name: str, matcher: MatcherBase,
+ pointer: CoroutineFunction, once: bool = False,
+ instream: bool = False, stream: Optional[XMLStream] = None):
BaseHandler.__init__(self, name, matcher, stream)
- if not asyncio.iscoroutinefunction(pointer):
+ if not iscoroutinefunction(pointer):
raise ValueError("Given function is not a coroutine")
- async def pointer_wrapper(stanza, *args, **kwargs):
+ async def pointer_wrapper(stanza: StanzaBase) -> None:
try:
- await pointer(stanza, *args, **kwargs)
+ await pointer(stanza)
except Exception as e:
stanza.exception(e)
- self._pointer = pointer_wrapper
+ self._pointer: CoroutineFunction = pointer_wrapper
self._once = once
self._instream = instream
- def prerun(self, payload):
+ def prerun(self, payload: StanzaBase) -> None:
"""Execute the callback during stream processing, if
the callback was created with ``instream=True``.
:param payload: The matched
- :class:`~slixmpp.xmlstream.stanzabase.ElementBase` object.
+ :class:`~slixmpp.xmlstream.stanzabase.StanzaBase` object.
"""
if self._once:
self._destroy = True
if self._instream:
self.run(payload, True)
- def run(self, payload, instream=False):
+ def run(self, payload: StanzaBase, instream: bool = False) -> None:
"""Execute the callback function with the matched stanza payload.
:param payload: The matched
- :class:`~slixmpp.xmlstream.stanzabase.ElementBase` object.
+ :class:`~slixmpp.xmlstream.stanzabase.StanzaBase` object.
:param bool instream: Force the handler to execute during stream
processing. This should only be used by
:meth:`prerun()`. Defaults to ``False``.
"""
if not self._instream or instream:
- asyncio.ensure_future(self._pointer(payload))
+ ensure_future(self._pointer(payload))
if self._once:
self._destroy = True
del self._pointer
diff --git a/slixmpp/xmlstream/handler/waiter.py b/slixmpp/xmlstream/handler/waiter.py
index 758cd1f1..dde49754 100644
--- a/slixmpp/xmlstream/handler/waiter.py
+++ b/slixmpp/xmlstream/handler/waiter.py
@@ -4,13 +4,20 @@
# Part of Slixmpp: The Slick XMPP Library
# :copyright: (c) 2011 Nathanael C. Fritz
# :license: MIT, see LICENSE for more details
+from __future__ import annotations
+
import logging
-import asyncio
-from asyncio import Queue, wait_for, TimeoutError
+from asyncio import Event, wait_for, TimeoutError
+from typing import Optional, TYPE_CHECKING, Union
+from xml.etree.ElementTree import Element
import slixmpp
+from slixmpp.xmlstream.stanzabase import StanzaBase
from slixmpp.xmlstream.handler.base import BaseHandler
+from slixmpp.xmlstream.matcher.base import MatcherBase
+if TYPE_CHECKING:
+ from slixmpp.xmlstream.xmlstream import XMLStream
log = logging.getLogger(__name__)
@@ -28,24 +35,27 @@ class Waiter(BaseHandler):
:param stream: The :class:`~slixmpp.xmlstream.xmlstream.XMLStream`
instance this handler should monitor.
"""
+ _event: Event
- def __init__(self, name, matcher, stream=None):
+ def __init__(self, name: str, matcher: MatcherBase, stream: Optional[XMLStream] = None):
BaseHandler.__init__(self, name, matcher, stream=stream)
- self._payload = Queue()
+ self._event = Event()
- def prerun(self, payload):
+ def prerun(self, payload: StanzaBase) -> None:
"""Store the matched stanza when received during processing.
:param payload: The matched
- :class:`~slixmpp.xmlstream.stanzabase.ElementBase` object.
+ :class:`~slixmpp.xmlstream.stanzabase.StanzaBase` object.
"""
- self._payload.put_nowait(payload)
+ if not self._event.is_set():
+ self._event.set()
+ self._payload = payload
- def run(self, payload):
+ def run(self, payload: StanzaBase) -> None:
"""Do not process this handler during the main event loop."""
pass
- async def wait(self, timeout=None):
+ async def wait(self, timeout: Optional[int] = None) -> Optional[StanzaBase]:
"""Block an event handler while waiting for a stanza to arrive.
Be aware that this will impact performance if called from a
@@ -59,17 +69,24 @@ class Waiter(BaseHandler):
:class:`~slixmpp.xmlstream.xmlstream.XMLStream.response_timeout`
value.
"""
+ stream_ref = self.stream
+ if stream_ref is None:
+ raise ValueError('wait() called without a stream')
+ stream = stream_ref()
+ if stream is None:
+ raise ValueError('wait() called without a stream')
if timeout is None:
timeout = slixmpp.xmlstream.RESPONSE_TIMEOUT
- stanza = None
try:
- stanza = await self._payload.get()
+ await wait_for(
+ self._event.wait(), timeout, loop=stream.loop
+ )
except TimeoutError:
log.warning("Timed out waiting for %s", self.name)
- self.stream().remove_handler(self.name)
- return stanza
+ stream.remove_handler(self.name)
+ return self._payload
- def check_delete(self):
+ def check_delete(self) -> bool:
"""Always remove waiters after use."""
return True
diff --git a/slixmpp/xmlstream/handler/xmlcallback.py b/slixmpp/xmlstream/handler/xmlcallback.py
index b44b2da1..c1adc815 100644
--- a/slixmpp/xmlstream/handler/xmlcallback.py
+++ b/slixmpp/xmlstream/handler/xmlcallback.py
@@ -4,6 +4,7 @@
# This file is part of Slixmpp.
# See the file LICENSE for copying permission.
from slixmpp.xmlstream.handler import Callback
+from slixmpp.xmlstream.stanzabase import StanzaBase
class XMLCallback(Callback):
@@ -17,7 +18,7 @@ class XMLCallback(Callback):
run -- Overrides Callback.run
"""
- def run(self, payload, instream=False):
+ def run(self, payload: StanzaBase, instream: bool = False) -> None:
"""
Execute the callback function with the matched stanza's
XML contents, instead of the stanza itself.
@@ -30,4 +31,4 @@ class XMLCallback(Callback):
stream processing. Used only by prerun.
Defaults to False.
"""
- Callback.run(self, payload.xml, instream)
+ Callback.run(self, payload.xml, instream) # type: ignore
diff --git a/slixmpp/xmlstream/handler/xmlwaiter.py b/slixmpp/xmlstream/handler/xmlwaiter.py
index 6eb6577e..f730efec 100644
--- a/slixmpp/xmlstream/handler/xmlwaiter.py
+++ b/slixmpp/xmlstream/handler/xmlwaiter.py
@@ -3,6 +3,7 @@
# Copyright (C) 2010 Nathanael C. Fritz
# This file is part of Slixmpp.
# See the file LICENSE for copying permission.
+from slixmpp.xmlstream.stanzabase import StanzaBase
from slixmpp.xmlstream.handler import Waiter
@@ -17,7 +18,7 @@ class XMLWaiter(Waiter):
prerun -- Overrides Waiter.prerun
"""
- def prerun(self, payload):
+ def prerun(self, payload: StanzaBase) -> None:
"""
Store the XML contents of the stanza to return to the
waiting event handler.
@@ -27,4 +28,4 @@ class XMLWaiter(Waiter):
Arguments:
payload -- The matched stanza object.
"""
- Waiter.prerun(self, payload.xml)
+ Waiter.prerun(self, payload.xml) # type: ignore