From fed55d3dda2c01dca7e9b9ea036c4b7b756510ff Mon Sep 17 00:00:00 2001 From: mathieui Date: Wed, 21 Apr 2021 23:20:25 +0200 Subject: typing: matchers and senders Leftover error that I cannot fix: * https://github.com/python/mypy/issues/708 Leftover error that I am unsure of what to do: * xml handlers are not properly typed (it seems like nothing in slix is using it, considering a removal instead of adding an Union everywhere) --- slixmpp/xmlstream/handler/base.py | 31 ++++++++++++----- slixmpp/xmlstream/handler/callback.py | 28 +++++++++++----- slixmpp/xmlstream/handler/collector.py | 40 ++++++++++++---------- slixmpp/xmlstream/handler/coroutine_callback.py | 38 ++++++++++++++------- slixmpp/xmlstream/handler/waiter.py | 44 +++++++++++++++++-------- slixmpp/xmlstream/handler/xmlcallback.py | 3 +- slixmpp/xmlstream/handler/xmlwaiter.py | 3 +- 7 files changed, 125 insertions(+), 62 deletions(-) (limited to 'slixmpp/xmlstream/handler') diff --git a/slixmpp/xmlstream/handler/base.py b/slixmpp/xmlstream/handler/base.py index 1e657777..e1edb249 100644 --- a/slixmpp/xmlstream/handler/base.py +++ b/slixmpp/xmlstream/handler/base.py @@ -4,10 +4,18 @@ # 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 +from slixmpp.xmlstream.matcher.base import MatcherBase + +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 +34,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 +54,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..5d792bf9 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 + _pointer: Callable[[StanzaBase], Any] - 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 = 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..d41cd7ba 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,15 +45,20 @@ class CoroutineCallback(BaseHandler): instance this handler should monitor. """ - def __init__(self, name, matcher, pointer, once=False, - instream=False, stream=None): + _once: bool + _instream: bool + _pointer: CoroutineFunction + + 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) @@ -50,29 +66,29 @@ class CoroutineCallback(BaseHandler): 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..684bd32f 100644 --- a/slixmpp/xmlstream/handler/waiter.py +++ b/slixmpp/xmlstream/handler/waiter.py @@ -4,13 +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 logging -import asyncio -from asyncio import Queue, wait_for, TimeoutError +from asyncio import Event, wait_for, TimeoutError +from typing import Optional, TYPE_CHECKING 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 +34,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 +68,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..31534033 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. diff --git a/slixmpp/xmlstream/handler/xmlwaiter.py b/slixmpp/xmlstream/handler/xmlwaiter.py index 6eb6577e..65185a5f 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. -- cgit v1.2.3 From f2d7e86fc7426d6bdda244a4f399c7930b5624cc Mon Sep 17 00:00:00 2001 From: mathieui Date: Mon, 5 Jul 2021 22:25:38 +0200 Subject: typing: add a bunch of type ignores because this is too smart for mypy and I do not want to rewrite those things right now. --- slixmpp/xmlstream/handler/xmlcallback.py | 2 +- slixmpp/xmlstream/handler/xmlwaiter.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'slixmpp/xmlstream/handler') diff --git a/slixmpp/xmlstream/handler/xmlcallback.py b/slixmpp/xmlstream/handler/xmlcallback.py index 31534033..c1adc815 100644 --- a/slixmpp/xmlstream/handler/xmlcallback.py +++ b/slixmpp/xmlstream/handler/xmlcallback.py @@ -31,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 65185a5f..f730efec 100644 --- a/slixmpp/xmlstream/handler/xmlwaiter.py +++ b/slixmpp/xmlstream/handler/xmlwaiter.py @@ -28,4 +28,4 @@ class XMLWaiter(Waiter): Arguments: payload -- The matched stanza object. """ - Waiter.prerun(self, payload.xml) + Waiter.prerun(self, payload.xml) # type: ignore -- cgit v1.2.3 From ed3bb878a75c84c2be74d1212226298967ee26e5 Mon Sep 17 00:00:00 2001 From: mathieui Date: Mon, 5 Jul 2021 22:28:38 +0200 Subject: handler: fix more types --- slixmpp/xmlstream/handler/base.py | 3 ++- slixmpp/xmlstream/handler/callback.py | 2 +- slixmpp/xmlstream/handler/coroutine_callback.py | 3 +-- slixmpp/xmlstream/handler/waiter.py | 3 ++- 4 files changed, 6 insertions(+), 5 deletions(-) (limited to 'slixmpp/xmlstream/handler') diff --git a/slixmpp/xmlstream/handler/base.py b/slixmpp/xmlstream/handler/base.py index e1edb249..0bae5674 100644 --- a/slixmpp/xmlstream/handler/base.py +++ b/slixmpp/xmlstream/handler/base.py @@ -8,8 +8,9 @@ from __future__ import annotations import weakref from weakref import ReferenceType -from typing import Optional, TYPE_CHECKING +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 diff --git a/slixmpp/xmlstream/handler/callback.py b/slixmpp/xmlstream/handler/callback.py index 5d792bf9..50dd4c66 100644 --- a/slixmpp/xmlstream/handler/callback.py +++ b/slixmpp/xmlstream/handler/callback.py @@ -45,13 +45,13 @@ class Callback(BaseHandler): """ _once: bool _instream: bool - _pointer: Callable[[StanzaBase], Any] 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 diff --git a/slixmpp/xmlstream/handler/coroutine_callback.py b/slixmpp/xmlstream/handler/coroutine_callback.py index d41cd7ba..524cca54 100644 --- a/slixmpp/xmlstream/handler/coroutine_callback.py +++ b/slixmpp/xmlstream/handler/coroutine_callback.py @@ -47,7 +47,6 @@ class CoroutineCallback(BaseHandler): _once: bool _instream: bool - _pointer: CoroutineFunction def __init__(self, name: str, matcher: MatcherBase, pointer: CoroutineFunction, once: bool = False, @@ -62,7 +61,7 @@ class CoroutineCallback(BaseHandler): except Exception as e: stanza.exception(e) - self._pointer = pointer_wrapper + self._pointer: CoroutineFunction = pointer_wrapper self._once = once self._instream = instream diff --git a/slixmpp/xmlstream/handler/waiter.py b/slixmpp/xmlstream/handler/waiter.py index 684bd32f..dde49754 100644 --- a/slixmpp/xmlstream/handler/waiter.py +++ b/slixmpp/xmlstream/handler/waiter.py @@ -8,7 +8,8 @@ from __future__ import annotations import logging from asyncio import Event, wait_for, TimeoutError -from typing import Optional, TYPE_CHECKING +from typing import Optional, TYPE_CHECKING, Union +from xml.etree.ElementTree import Element import slixmpp from slixmpp.xmlstream.stanzabase import StanzaBase -- cgit v1.2.3