summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/howto/stanzas.rst401
-rw-r--r--slixmpp/basexmpp.py139
-rw-r--r--slixmpp/pluginsdict.py193
-rw-r--r--slixmpp/types.py207
4 files changed, 701 insertions, 239 deletions
diff --git a/docs/howto/stanzas.rst b/docs/howto/stanzas.rst
index d52a90d4..56dfce79 100644
--- a/docs/howto/stanzas.rst
+++ b/docs/howto/stanzas.rst
@@ -3,28 +3,411 @@
How to Work with Stanza Objects
===============================
+Slixmpp provides a large variety of facilities for abstracting the underlying
+XML payloads of XMPP. Most of the visible user interface comes in a
+dict-like interface provided in a specific ``__getitem__`` implementation
+for :class:`~slixmpp.xmlstream.ElementBase` objects.
+
+
+As a very high-level example, here is how to create a stanza with
+an XEP-0191 payload, assuming the :class:`xep_0191 <slixmpp.plugins.xep_0191.XEP_0191>`
+plugin is loaded:
+
+.. code-block:: python
+
+ from slixmpp.stanza import Iq
+ iq = Iq()
+ iq['to'] = 'toto@example.com'
+ iq['type'] = 'set'
+ iq['block']['items'] = {'a@example.com', 'b@example.com'}
+
+Printing the resulting :class:`~slixmpp.stanaz.Iq` object gives us the
+following XML (reformatted for readability):
+
+.. code-block:: xml
+
+ <iq xmlns="jabber:client" id="0" to="toto@example.com" type="set">
+ <block xmlns="urn:xmpp:blocking">
+ <item jid="b@example.com" />
+ <item jid="a@example.com" />
+ </block>
+ </iq>
+
+
+Realistically, users of the Slixmpp library should make use of the shorthand
+functions available in their :class:`~.ClientXMPP` or
+:class:`~.ComponentXMPP` objects to create :class:`~.Iq`, :class:`~.Message`
+or :class:`~.Presence` objects that are bound to a stream, and which have
+a generated unique identifier.
+
+The most relevant functions are:
+
+.. autofunction:: slixmpp.BaseXMPP.make_iq_get
+
+.. autofunction:: slixmpp.BaseXMPP.make_iq_set
+
+.. autofunction:: slixmpp.BaseXMPP.make_message
+
+.. autofunction:: slixmpp.BaseXMPP.make_presence
+
+The previous example then becomes:
+
+.. code-block:: python
+
+ iq = xmpp.make_iq_get(ito='toto@example.com')
+ iq['block']['items'] = {'a@example.com', 'b@example.com'}
+
+
+.. note::
+
+ xml:lang is handled by piping the lang name after the attribute. For
+ example ``message['body|fr']`` will return the ``<body/>`` attribute
+ with ``xml:lang="fr``.
+
+The next sections will try to explain as clearly as possible
+how the magic operates.
.. _create-stanza-interfaces:
Defining Stanza Interfaces
--------------------------
+The stanza interface is very rich and let developers have full control
+over the API they want to have to manipulate stanzas.
-.. _create-stanza-plugins:
+The entire interface is defined as class attributes that are redefined
+when subclassing :class:`~.ElementBase` when `creating a stanza plugin <create-stanza-plugins>`_.
-Creating Stanza Plugins
------------------------
+The main attributes defining a stanza interface:
+- plugin_attrib_: ``str``, the name of this element on the parent
+- plugin_multi_attrib_: ``str``, the name of the iterable for this element on the parent
+- interfaces_: ``set``, all known interfaces for this element
+- sub_interfaces_: ``set`` (subset of ``interfaces``), for sub-elements with only text nodes
+- bool_interfaces_: ``set`` (subset of ``interfaces``), for empty-sub-elements
+- overrides_: ``list`` (subset of ``interfaces``), for ``interfaces`` to ovverride on the parent
+- is_extension_: ``bool``, if the element is only an extension of the parent stanza
-.. _create-extension-plugins:
+.. _plugin_attrib:
-Creating a Stanza Extension
----------------------------
+plugin_attrib
+~~~~~~~~~~~~~
+The ``plugin_attrib`` string is the defining element of any stanza plugin,
+as it the name through which the element is accessed (except for ``overrides``
+and ``is_extension``).
+The extension is then registered through the help of :func:`~.register_stanza_plugin`
+which will attach the plugin to its parent.
-.. _override-parent-interfaces:
+.. code-block:: python
-Overriding a Parent Stanza
---------------------------
+ from slixmpp import ElementBase, Iq
+
+ class Payload(ElementBase):
+ name = 'apayload'
+ plugin_attrib = 'mypayload'
+ namespace = 'x-toto'
+
+ register_stanza_plugin(Iq, Payload)
+
+ iq = Iq()
+ iq.enable('mypayload') # Similar to iq['mypayload']
+
+The :class:`~.Iq` element created now contains our custom ``<apayload/>`` element.
+
+.. code-block:: xml
+
+ <iq xmlns="jabber:client" id="0">
+ <apayload xmlns="x-toto"/>
+ </iq>
+
+
+.. _plugin_multi_attrib:
+
+plugin_multi_attrib
+~~~~~~~~~~~~~~~~~~~
+
+The :func:`~.register_stanza_plugin` function has an ``iterable`` parameter, which
+defaults to ``False``. When set to ``True``, it means that iterating over the element
+is possible.
+
+
+.. code-block:: python
+
+ class Parent(ElementBase):
+ pass # does not matter
+
+ class Sub(ElementBase):
+ name = 'sub'
+ plugin_attrib = 'sub'
+
+ class Sub2(ElementBase):
+ name = 'sub2'
+ plugin_attrib = 'sub2'
+
+ register_stanza_plugin(Parent, Sub, iterable=True)
+ register_stanza_plugin(Parent, Sub2, iterable=True)
+
+ parent = Parent()
+ parent.append(Sub())
+ parent.append(Sub2())
+ parent.append(Sub2())
+ parent.append(Sub())
+
+ for element in parent:
+ do_something # A mix of Sub and Sub2 elements
+
+In this situation, iterating over ``parent`` will yield each of the appended elements,
+one after the other.
+
+Sometimes you only want one specific type of sub-element, which is the use of
+the ``plugin_multi_attrib`` string interface. This name will be mapped on the
+parent, just like ``plugin_attrib``, but will return a list of all elements
+of the same type only.
+
+Re-using our previous example:
+
+.. code-block:: python
+
+ class Parent(ElementBase):
+ pass # does not matter
+
+ class Sub(ElementBase):
+ name = 'sub'
+ plugin_attrib = 'sub'
+ plugin_multi_attrib = 'subs'
+
+ class Sub2(ElementBase):
+ name = 'sub2'
+ plugin_attrib = 'sub2'
+ plugin_multi_attrib = 'subs2'
+
+ register_stanza_plugin(Parent, Sub, iterable=True)
+ register_stanza_plugin(Parent, Sub2, iterable=True)
+
+ parent = Parent()
+ parent.append(Sub())
+ parent.append(Sub2())
+ parent.append(Sub2())
+ parent.append(Sub())
+
+ for sub in parent['subs']:
+ do_something # ony Sub objects here
+
+ for sub2 in parent['subs2']:
+ do_something # ony Sub2 objects here
+
+
+.. _interfaces:
+
+interfaces
+~~~~~~~~~~
+
+The ``interfaces`` set **must** contain all the known ways to interact with
+this element. It does not include plugins (registered to the element through
+:func:`~.register_stanza_plugin`), which are dynamic.
+
+By default, a name present in ``interfaces`` will be mapped to an attribute
+of the element with the same name.
+
+.. code-block:: python
+
+ class Example(Element):
+ name = 'example'
+ interfaces = {'toto'}
+
+ example = Example()
+ example['toto'] = 'titi'
+
+In this case, ``example`` contains ``<example toto="titi"/>``.
+
+For empty and text_only sub-elements, there are sub_interfaces_ and
+bool_interfaces_ (the keys **must** still be in ``interfaces``.
+
+You can however define any getter, setter, and delete custom method for any of
+those interfaces. Keep in mind that if one of the three is not custom,
+Slixmpp will use the default one, so you have to make sure that either you
+redefine all get/set/del custom methods, or that your custom methods are
+compatible with the default ones.
+
+In the following example, we want the ``toto`` attribute to be an integer.
+
+.. code-block:: python
+
+ class Example(Element):
+ interfaces = {'toto', 'titi', 'tata'}
+
+ def get_toto(self) -> Optional[int]:
+ try:
+ return int(self.xml.attrib.get('toto', ''))
+ except ValueError:
+ return None
+
+ def set_toto(self, value: int):
+ int(value) # make sure the value is an int
+ self.xml.attrib['toto'] = str(value)
+
+ example = Example()
+ example['tata'] = "Test" # works
+ example['toto'] = 1 # works
+ print(type(example['toto'])) # the value is an int
+ example['toto'] = "Test 2" # ValueError
+
+
+One important thing to keep in mind is that the ``get_`` methods must be resilient
+(when having a default value makes sense) because they are called on objects
+received from the network.
+
+.. _sub_interfaces:
+
+sub_interfaces
+~~~~~~~~~~~~~~
+
+The ``bool_interfaces`` set allows mapping an interface to the text node of
+sub-element of the current payload, with the same namespace
+
+Here is a simple example:
+
+.. code-block:: python
+
+ class FirstLevel(ElementBase):
+ name = 'first'
+ namespace = 'ns'
+ interfaces = {'second'}
+ sub_interfaces = {'second'}
+
+ parent = FirstLevel()
+ parent['second'] = 'Content of second node'
+
+
+Which will produces the following:
+
+.. code-block:: xml
+
+ <first xmlns="ns">
+ <second>Content of second node</second>
+ </first>
+
+We can see that ``sub_interfaces`` allows to quickly create a sub-element and
+manipulate its text node without requiring a custom element, getter or setter.
+
+.. _bool_interfaces:
+
+bool_interfaces
+~~~~~~~~~~~~~~~
+
+The ``bool_interfaces`` set allows mapping an interface to a direct sub-element of the
+current payload, with the same namespace.
+
+
+Here is a simple example:
+
+.. code-block:: python
+
+ class FirstLevel(ElementBase):
+ name = 'first'
+ namespace = 'ns'
+ interfaces = {'second'}
+ bool_interfaces = {'second'}
+
+ parent = FirstLevel()
+ parent['second'] = True
+
+
+Which will produces the following:
+
+.. code-block:: xml
+
+ <first xmlns="ns">
+ <second/>
+ </first>
+
+We can see that ``bool_interfaces`` allows to quickly create sub-elements with no
+content, without the need to create a custom class or getter/setter.
+
+overrides
+~~~~~~~~~
+
+List of ``interfaces`` on the present element that should override the
+parent ``interfaces`` with the same name.
+
+.. code-block:: python
+
+ class Parent(ElementBase):
+ name = 'parent'
+ interfaces = {'toto', 'titi'}
+
+ class Sub(ElementBase):
+ name = 'sub'
+ plugin_attrib = name
+ interfaces = {'toto', 'titi'}
+ overrides = ['toto']
+
+ register_stanza_plugin(Parent, Sub)
+
+ parent = Parent()
+ parent['toto'] = 'test' # equivalent to parent['sub']['toto'] = "test"
+
+is_extension
+~~~~~~~~~~~~
+
+Stanza extensions are a specific kind of stanza plugin which have
+the ``is_extension`` class attribute set to ``True``.
+
+The following code will directly plug the extension into the
+:class:`~.Message` element, allowing direct access
+to the interface:
+
+.. code-block:: python
+
+ class MyCustomExtension(ElementBase):
+ is_extension = True
+ name = 'mycustom'
+ namespace = 'custom-ns'
+ plugin_attrib = 'mycustom'
+ interfaces = {'mycustom'}
+
+ register_stanza_plugin(Message, MyCustomExtension)
+
+With this extension, we can do the folliowing:
+
+.. code-block:: python
+
+ message = Message()
+ message['mycustom'] = 'toto'
+
+Without the extension, obtaining the same results would be:
+
+.. code-block:: python
+
+ message = Message()
+ message['mycustom']['mycustom'] = 'toto'
+
+
+The extension is therefore named extension because it extends the
+parent element transparently.
+
+
+.. _create-stanza-plugins:
+
+Creating Stanza Plugins
+-----------------------
+
+A stanza plugin is a class that inherits from :class:`~.ElementBase`, and
+**must** contain at least the following attributes:
+
+- name: XML element name (e.g. ``toto`` if the element is ``<toto/>``
+- namespace: The XML namespace of the element.
+- plugin_attrib_: ``str``, the name of this element on the parent
+- interfaces_: ``set``, all known interfaces for this element
+
+It is then registered through :func:`~.register_stanza_plugin` on the parent
+element.
+
+.. note::
+
+ :func:`~.register_stanza_plugin` should NOT be called at the module level,
+ because it executes code, and executing code at the module level can slow
+ down import significantly!
diff --git a/slixmpp/basexmpp.py b/slixmpp/basexmpp.py
index e94883b1..25aa0d75 100644
--- a/slixmpp/basexmpp.py
+++ b/slixmpp/basexmpp.py
@@ -11,6 +11,9 @@ import asyncio
import logging
from typing import (
+ Dict,
+ Optional,
+ Union,
TYPE_CHECKING,
)
@@ -18,14 +21,22 @@ from slixmpp import plugins, roster, stanza
from slixmpp.api import APIRegistry
from slixmpp.exceptions import IqError, IqTimeout
-from slixmpp.stanza import Message, Presence, Iq, StreamError
+from slixmpp.stanza import (
+ Message,
+ Presence,
+ Iq,
+ StreamError,
+)
from slixmpp.stanza.roster import Roster
from slixmpp.xmlstream import XMLStream, JID
from slixmpp.xmlstream import ET, register_stanza_plugin
from slixmpp.xmlstream.matcher import MatchXPath
from slixmpp.xmlstream.handler import Callback
-from slixmpp.xmlstream.stanzabase import XML_NS
+from slixmpp.xmlstream.stanzabase import (
+ ElementBase,
+ XML_NS,
+)
from slixmpp.plugins import PluginManager, load_plugin
@@ -33,8 +44,16 @@ from slixmpp.plugins import PluginManager, load_plugin
log = logging.getLogger(__name__)
+from slixmpp.types import (
+ PresenceShows,
+ PresenceTypes,
+ MessageTypes,
+ IqTypes,
+)
+
if TYPE_CHECKING:
- from slixmpp.types import PluginsDict
+ # Circular imports
+ from slixmpp.pluginsdict import PluginsDict
class BaseXMPP(XMLStream):
@@ -229,7 +248,7 @@ class BaseXMPP(XMLStream):
self.plugin[name].post_init()
self.plugin[name].post_inited = True
- def register_plugin(self, plugin, pconfig=None, module=None):
+ def register_plugin(self, plugin: str, pconfig: Optional[Dict] = None, module=None):
"""Register and configure a plugin for use in this stream.
:param plugin: The name of the plugin class. Plugin names must
@@ -279,32 +298,34 @@ class BaseXMPP(XMLStream):
"""Return a plugin given its name, if it has been registered."""
return self.plugin.get(key, default)
- def Message(self, *args, **kwargs):
+ def Message(self, *args, **kwargs) -> Message:
"""Create a Message stanza associated with this stream."""
msg = Message(self, *args, **kwargs)
msg['lang'] = self.default_lang
return msg
- def Iq(self, *args, **kwargs):
+ def Iq(self, *args, **kwargs) -> Iq:
"""Create an Iq stanza associated with this stream."""
return Iq(self, *args, **kwargs)
- def Presence(self, *args, **kwargs):
+ def Presence(self, *args, **kwargs) -> Presence:
"""Create a Presence stanza associated with this stream."""
pres = Presence(self, *args, **kwargs)
pres['lang'] = self.default_lang
return pres
- def make_iq(self, id=0, ifrom=None, ito=None, itype=None, iquery=None):
- """Create a new Iq stanza with a given Id and from JID.
+ def make_iq(self, id: str = "0", ifrom: Optional[JID] = None,
+ ito: Optional[JID] = None, itype: Optional[IqTypes] = None,
+ iquery: Optional[str] = None) -> Iq:
+ """Create a new :class:`~.Iq` stanza with a given Id and from JID.
:param id: An ideally unique ID value for this stanza thread.
Defaults to 0.
- :param ifrom: The from :class:`~slixmpp.xmlstream.jid.JID`
+ :param ifrom: The from :class:`~.JID`
to use for this stanza.
- :param ito: The destination :class:`~slixmpp.xmlstream.jid.JID`
+ :param ito: The destination :class:`~.JID`
for this stanza.
- :param itype: The :class:`~slixmpp.stanza.iq.Iq`'s type,
+ :param itype: The :class:`~.Iq`'s type,
one of: ``'get'``, ``'set'``, ``'result'``,
or ``'error'``.
:param iquery: Optional namespace for adding a query element.
@@ -317,15 +338,17 @@ class BaseXMPP(XMLStream):
iq['query'] = iquery
return iq
- def make_iq_get(self, queryxmlns=None, ito=None, ifrom=None, iq=None):
- """Create an :class:`~slixmpp.stanza.iq.Iq` stanza of type ``'get'``.
+ def make_iq_get(self, queryxmlns: Optional[str] =None,
+ ito: Optional[JID] = None, ifrom: Optional[JID] = None,
+ iq: Optional[Iq] = None) -> Iq:
+ """Create an :class:`~.Iq` stanza of type ``'get'``.
Optionally, a query element may be added.
:param queryxmlns: The namespace of the query to use.
- :param ito: The destination :class:`~slixmpp.xmlstream.jid.JID`
+ :param ito: The destination :class:`~.JID`
for this stanza.
- :param ifrom: The ``'from'`` :class:`~slixmpp.xmlstream.jid.JID`
+ :param ifrom: The ``'from'`` :class:`~.JID`
to use for this stanza.
:param iq: Optionally use an existing stanza instead
of generating a new one.
@@ -340,15 +363,17 @@ class BaseXMPP(XMLStream):
iq['from'] = ifrom
return iq
- def make_iq_result(self, id=None, ito=None, ifrom=None, iq=None):
+ def make_iq_result(self, id: Optional[str] = None,
+ ito: Optional[JID] = None, ifrom: Optional[JID] = None,
+ iq: Optional[Iq] = None) -> Iq:
"""
- Create an :class:`~slixmpp.stanza.iq.Iq` stanza of type
+ Create an :class:`~.Iq` stanza of type
``'result'`` with the given ID value.
:param id: An ideally unique ID value. May use :meth:`new_id()`.
- :param ito: The destination :class:`~slixmpp.xmlstream.jid.JID`
+ :param ito: The destination :class:`~.JID`
for this stanza.
- :param ifrom: The ``'from'`` :class:`~slixmpp.xmlstream.jid.JID`
+ :param ifrom: The ``'from'`` :class:`~.JID`
to use for this stanza.
:param iq: Optionally use an existing stanza instead
of generating a new one.
@@ -365,21 +390,23 @@ class BaseXMPP(XMLStream):
iq['from'] = ifrom
return iq
- def make_iq_set(self, sub=None, ito=None, ifrom=None, iq=None):
+ def make_iq_set(self, sub: Optional[Union[ElementBase, ET.Element]] = None,
+ ito: Optional[JID] = None, ifrom: Optional[JID] = None,
+ iq: Optional[Iq] = None) -> Iq:
"""
- Create an :class:`~slixmpp.stanza.iq.Iq` stanza of type ``'set'``.
+ Create an :class:`~.Iq` stanza of type ``'set'``.
Optionally, a substanza may be given to use as the
stanza's payload.
:param sub: Either an
- :class:`~slixmpp.xmlstream.stanzabase.ElementBase`
+ :class:`~.ElementBase`
stanza object or an
:class:`~xml.etree.ElementTree.Element` XML object
- to use as the :class:`~slixmpp.stanza.iq.Iq`'s payload.
- :param ito: The destination :class:`~slixmpp.xmlstream.jid.JID`
+ to use as the :class:`~.Iq`'s payload.
+ :param ito: The destination :class:`~.JID`
for this stanza.
- :param ifrom: The ``'from'`` :class:`~slixmpp.xmlstream.jid.JID`
+ :param ifrom: The ``'from'`` :class:`~.JID`
to use for this stanza.
:param iq: Optionally use an existing stanza instead
of generating a new one.
@@ -399,7 +426,7 @@ class BaseXMPP(XMLStream):
condition='feature-not-implemented',
text=None, ito=None, ifrom=None, iq=None):
"""
- Create an :class:`~slixmpp.stanza.iq.Iq` stanza of type ``'error'``.
+ Create an :class:`~.Iq` stanza of type ``'error'``.
:param id: An ideally unique ID value. May use :meth:`new_id()`.
:param type: The type of the error, such as ``'cancel'`` or
@@ -407,9 +434,9 @@ class BaseXMPP(XMLStream):
:param condition: The error condition. Defaults to
``'feature-not-implemented'``.
:param text: A message describing the cause of the error.
- :param ito: The destination :class:`~slixmpp.xmlstream.jid.JID`
+ :param ito: The destination :class:`~.JID`
for this stanza.
- :param ifrom: The ``'from'`` :class:`~slixmpp.xmlstream.jid.JID`
+ :param ifrom: The ``'from'`` :class:`~jid.JID`
to use for this stanza.
:param iq: Optionally use an existing stanza instead
of generating a new one.
@@ -426,17 +453,19 @@ class BaseXMPP(XMLStream):
iq['from'] = ifrom
return iq
- def make_iq_query(self, iq=None, xmlns='', ito=None, ifrom=None):
+ def make_iq_query(self, iq: Optional[Iq] = None, xmlns: str = '',
+ ito: Optional[JID] = None,
+ ifrom: Optional[JID] = None) -> Iq:
"""
- Create or modify an :class:`~slixmpp.stanza.iq.Iq` stanza
+ Create or modify an :class:`~.Iq` stanza
to use the given query namespace.
:param iq: Optionally use an existing stanza instead
of generating a new one.
:param xmlns: The query's namespace.
- :param ito: The destination :class:`~slixmpp.xmlstream.jid.JID`
+ :param ito: The destination :class:`~.JID`
for this stanza.
- :param ifrom: The ``'from'`` :class:`~slixmpp.xmlstream.jid.JID`
+ :param ifrom: The ``'from'`` :class:`~.JID`
to use for this stanza.
"""
if not iq:
@@ -448,7 +477,7 @@ class BaseXMPP(XMLStream):
iq['from'] = ifrom
return iq
- def make_query_roster(self, iq=None):
+ def make_query_roster(self, iq: Optional[Iq] = None) -> ET.Element:
"""Create a roster query element.
:param iq: Optionally use an existing stanza instead
@@ -458,11 +487,14 @@ class BaseXMPP(XMLStream):
iq['query'] = 'jabber:iq:roster'
return ET.Element("{jabber:iq:roster}query")
- def make_message(self, mto, mbody=None, msubject=None, mtype=None,
- mhtml=None, mfrom=None, mnick=None):
+ def make_message(self, mto: JID, mbody: Optional[str] = None,
+ msubject: Optional[str] = None,
+ mtype: Optional[MessageTypes] = None,
+ mhtml: Optional[str] = None, mfrom: Optional[JID] = None,
+ mnick: Optional[str] = None) -> Message:
"""
Create and initialize a new
- :class:`~slixmpp.stanza.message.Message` stanza.
+ :class:`~.Message` stanza.
:param mto: The recipient of the message.
:param mbody: The main contents of the message.
@@ -484,11 +516,16 @@ class BaseXMPP(XMLStream):
message['html']['body'] = mhtml
return message
- def make_presence(self, pshow=None, pstatus=None, ppriority=None,
- pto=None, ptype=None, pfrom=None, pnick=None):
+ def make_presence(self, pshow: Optional[PresenceShows] = None,
+ pstatus: Optional[str] = None,
+ ppriority: Optional[int] = None,
+ pto: Optional[JID] = None,
+ ptype: Optional[PresenceTypes] = None,
+ pfrom: Optional[JID] = None,
+ pnick: Optional[str] = None) -> Presence:
"""
Create and initialize a new
- :class:`~slixmpp.stanza.presence.Presence` stanza.
+ :class:`~.Presence` stanza.
:param pshow: The presence's show value.
:param pstatus: The presence's status message.
@@ -508,11 +545,14 @@ class BaseXMPP(XMLStream):
presence['nick'] = pnick
return presence
- def send_message(self, mto, mbody, msubject=None, mtype=None,
- mhtml=None, mfrom=None, mnick=None):
+ def send_message(self, mto: JID, mbody: Optional[str] = None,
+ msubject: Optional[str] = None,
+ mtype: Optional[MessageTypes] = None,
+ mhtml: Optional[str] = None, mfrom: Optional[JID] = None,
+ mnick: Optional[str] = None):
"""
Create, initialize, and send a new
- :class:`~slixmpp.stanza.message.Message` stanza.
+ :class:`~.Message` stanza.
:param mto: The recipient of the message.
:param mbody: The main contents of the message.
@@ -528,11 +568,16 @@ class BaseXMPP(XMLStream):
self.make_message(mto, mbody, msubject, mtype,
mhtml, mfrom, mnick).send()
- def send_presence(self, pshow=None, pstatus=None, ppriority=None,
- pto=None, pfrom=None, ptype=None, pnick=None):
+ def send_presence(self, pshow: Optional[PresenceShows] = None,
+ pstatus: Optional[str] = None,
+ ppriority: Optional[int] = None,
+ pto: Optional[JID] = None,
+ ptype: Optional[PresenceTypes] = None,
+ pfrom: Optional[JID] = None,
+ pnick: Optional[str] = None):
"""
Create, initialize, and send a new
- :class:`~slixmpp.stanza.presence.Presence` stanza.
+ :class:`~.Presence` stanza.
:param pshow: The presence's show value.
:param pstatus: The presence's status message.
@@ -549,7 +594,7 @@ class BaseXMPP(XMLStream):
ptype='subscribe', pnick=None):
"""
Create, initialize, and send a new
- :class:`~slixmpp.stanza.presence.Presence` stanza of
+ :class:`~.Presence` stanza of
type ``'subscribe'``.
:param pto: The recipient of a directed presence.
diff --git a/slixmpp/pluginsdict.py b/slixmpp/pluginsdict.py
new file mode 100644
index 00000000..d9954f51
--- /dev/null
+++ b/slixmpp/pluginsdict.py
@@ -0,0 +1,193 @@
+# Slixmpp: The Slick XMPP Library
+# Copyright © 2021 Mathieu Pasquet <mathieui@mathieui.net>
+# This file is part of Slixmpp.
+# See the file LICENSE for copying permission.
+
+try:
+ from typing import TypedDict
+except ImportError:
+ from typing_extensions import TypedDict
+
+# Plugins mega-dict
+
+from slixmpp.plugins.xep_0004 import XEP_0004
+from slixmpp.plugins.xep_0009 import XEP_0009
+from slixmpp.plugins.xep_0012 import XEP_0012
+from slixmpp.plugins.xep_0013 import XEP_0013
+from slixmpp.plugins.xep_0020 import XEP_0020
+from slixmpp.plugins.xep_0027 import XEP_0027
+from slixmpp.plugins.xep_0030 import XEP_0030
+from slixmpp.plugins.xep_0033 import XEP_0033
+from slixmpp.plugins.xep_0045 import XEP_0045
+from slixmpp.plugins.xep_0047 import XEP_0047
+from slixmpp.plugins.xep_0049 import XEP_0049
+from slixmpp.plugins.xep_0050 import XEP_0050
+from slixmpp.plugins.xep_0054 import XEP_0054
+from slixmpp.plugins.xep_0059 import XEP_0059
+from slixmpp.plugins.xep_0060 import XEP_0060
+from slixmpp.plugins.xep_0065 import XEP_0065
+from slixmpp.plugins.xep_0066 import XEP_0066
+from slixmpp.plugins.xep_0070 import XEP_0070
+from slixmpp.plugins.xep_0071 import XEP_0071
+from slixmpp.plugins.xep_0077 import XEP_0077
+from slixmpp.plugins.xep_0079 import XEP_0079
+from slixmpp.plugins.xep_0080 import XEP_0080
+from slixmpp.plugins.xep_0082 import XEP_0082
+from slixmpp.plugins.xep_0084 import XEP_0084
+from slixmpp.plugins.xep_0085 import XEP_0085
+from slixmpp.plugins.xep_0086 import XEP_0086
+from slixmpp.plugins.xep_0092 import XEP_0092
+from slixmpp.plugins.xep_0106 import XEP_0106
+from slixmpp.plugins.xep_0107 import XEP_0107
+from slixmpp.plugins.xep_0108 import XEP_0108
+from slixmpp.plugins.xep_0115 import XEP_0115
+from slixmpp.plugins.xep_0118 import XEP_0118
+from slixmpp.plugins.xep_0122 import XEP_0122
+from slixmpp.plugins.xep_0128 import XEP_0128
+from slixmpp.plugins.xep_0131 import XEP_0131
+from slixmpp.plugins.xep_0133 import XEP_0133
+from slixmpp.plugins.xep_0152 import XEP_0152
+from slixmpp.plugins.xep_0153 import XEP_0153
+from slixmpp.plugins.xep_0163 import XEP_0163
+from slixmpp.plugins.xep_0172 import XEP_0172
+from slixmpp.plugins.xep_0184 import XEP_0184
+from slixmpp.plugins.xep_0186 import XEP_0186
+from slixmpp.plugins.xep_0191 import XEP_0191
+from slixmpp.plugins.xep_0196 import XEP_0196
+from slixmpp.plugins.xep_0198 import XEP_0198
+from slixmpp.plugins.xep_0199 import XEP_0199
+from slixmpp.plugins.xep_0202 import XEP_0202
+from slixmpp.plugins.xep_0203 import XEP_0203
+from slixmpp.plugins.xep_0221 import XEP_0221
+from slixmpp.plugins.xep_0222 import XEP_0222
+from slixmpp.plugins.xep_0223 import XEP_0223
+from slixmpp.plugins.xep_0224 import XEP_0224
+from slixmpp.plugins.xep_0231 import XEP_0231
+from slixmpp.plugins.xep_0235 import XEP_0235
+from slixmpp.plugins.xep_0249 import XEP_0249
+from slixmpp.plugins.xep_0256 import XEP_0256
+from slixmpp.plugins.xep_0257 import XEP_0257
+from slixmpp.plugins.xep_0258 import XEP_0258
+from slixmpp.plugins.xep_0279 import XEP_0279
+from slixmpp.plugins.xep_0280 import XEP_0280
+from slixmpp.plugins.xep_0297 import XEP_0297
+from slixmpp.plugins.xep_0300 import XEP_0300
+from slixmpp.plugins.xep_0308 import XEP_0308
+from slixmpp.plugins.xep_0313 import XEP_0313
+from slixmpp.plugins.xep_0319 import XEP_0319
+from slixmpp.plugins.xep_0332 import XEP_0332
+from slixmpp.plugins.xep_0333 import XEP_0333
+from slixmpp.plugins.xep_0334 import XEP_0334
+from slixmpp.plugins.xep_0335 import XEP_0335
+from slixmpp.plugins.xep_0352 import XEP_0352
+from slixmpp.plugins.xep_0353 import XEP_0353
+from slixmpp.plugins.xep_0359 import XEP_0359
+from slixmpp.plugins.xep_0363 import XEP_0363
+from slixmpp.plugins.xep_0369 import XEP_0369
+from slixmpp.plugins.xep_0377 import XEP_0377
+from slixmpp.plugins.xep_0380 import XEP_0380
+from slixmpp.plugins.xep_0382 import XEP_0382
+from slixmpp.plugins.xep_0394 import XEP_0394
+from slixmpp.plugins.xep_0403 import XEP_0403
+from slixmpp.plugins.xep_0404 import XEP_0404
+from slixmpp.plugins.xep_0405 import XEP_0405
+from slixmpp.plugins.xep_0421 import XEP_0421
+from slixmpp.plugins.xep_0422 import XEP_0422
+from slixmpp.plugins.xep_0424 import XEP_0424
+from slixmpp.plugins.xep_0425 import XEP_0425
+from slixmpp.plugins.xep_0428 import XEP_0428
+from slixmpp.plugins.xep_0437 import XEP_0437
+from slixmpp.plugins.xep_0439 import XEP_0439
+from slixmpp.plugins.xep_0444 import XEP_0444
+
+
+class PluginsDict(TypedDict):
+ xep_0004: XEP_0004
+ xep_0009: XEP_0009
+ xep_0012: XEP_0012
+ xep_0013: XEP_0013
+ xep_0020: XEP_0020
+ xep_0027: XEP_0027
+ xep_0030: XEP_0030
+ xep_0033: XEP_0033
+ xep_0045: XEP_0045
+ xep_0047: XEP_0047
+ xep_0049: XEP_0049
+ xep_0050: XEP_0050
+ xep_0054: XEP_0054
+ xep_0059: XEP_0059
+ xep_0060: XEP_0060
+ xep_0065: XEP_0065
+ xep_0066: XEP_0066
+ xep_0070: XEP_0070
+ xep_0071: XEP_0071
+ xep_0077: XEP_0077
+ xep_0079: XEP_0079
+ xep_0080: XEP_0080
+ xep_0082: XEP_0082
+ xep_0084: XEP_0084
+ xep_0085: XEP_0085
+ xep_0086: XEP_0086
+ xep_0092: XEP_0092
+ xep_0106: XEP_0106
+ xep_0107: XEP_0107
+ xep_0108: XEP_0108
+ xep_0115: XEP_0115
+ xep_0118: XEP_0118
+ xep_0122: XEP_0122
+ xep_0128: XEP_0128
+ xep_0131: XEP_0131
+ xep_0133: XEP_0133
+ xep_0152: XEP_0152
+ xep_0153: XEP_0153
+ xep_0163: XEP_0163
+ xep_0172: XEP_0172
+ xep_0184: XEP_0184
+ xep_0186: XEP_0186
+ xep_0191: XEP_0191
+ xep_0196: XEP_0196
+ xep_0198: XEP_0198
+ xep_0199: XEP_0199
+ xep_0202: XEP_0202
+ xep_0203: XEP_0203
+ xep_0221: XEP_0221
+ xep_0222: XEP_0222
+ xep_0223: XEP_0223
+ xep_0224: XEP_0224
+ xep_0231: XEP_0231
+ xep_0235: XEP_0235
+ xep_0249: XEP_0249
+ xep_0256: XEP_0256
+ xep_0257: XEP_0257
+ xep_0258: XEP_0258
+ xep_0279: XEP_0279
+ xep_0280: XEP_0280
+ xep_0297: XEP_0297
+ xep_0300: XEP_0300
+ xep_0308: XEP_0308
+ xep_0313: XEP_0313
+ xep_0319: XEP_0319
+ xep_0332: XEP_0332
+ xep_0333: XEP_0333
+ xep_0334: XEP_0334
+ xep_0335: XEP_0335
+ xep_0352: XEP_0352
+ xep_0353: XEP_0353
+ xep_0359: XEP_0359
+ xep_0363: XEP_0363
+ xep_0369: XEP_0369
+ xep_0377: XEP_0377
+ xep_0380: XEP_0380
+ xep_0382: XEP_0382
+ xep_0394: XEP_0394
+ xep_0403: XEP_0403
+ xep_0404: XEP_0404
+ xep_0405: XEP_0405
+ xep_0421: XEP_0421
+ xep_0422: XEP_0422
+ xep_0424: XEP_0424
+ xep_0425: XEP_0425
+ xep_0428: XEP_0428
+ xep_0437: XEP_0437
+ xep_0439: XEP_0439
+ xep_0444: XEP_0444
diff --git a/slixmpp/types.py b/slixmpp/types.py
index c48ed97b..44e24a1e 100644
--- a/slixmpp/types.py
+++ b/slixmpp/types.py
@@ -4,193 +4,34 @@
# See the file LICENSE for copying permission.
"""
-This file contains boilerplate to define types relevant to slixmpp,
-such as the plugins dict.
+This file contains boilerplate to define types relevant to slixmpp.
"""
try:
- from typing import TypedDict
+ from typing import (
+ Literal,
+ )
except ImportError:
- from typing_extensions import TypedDict
+ from typing_extensions import (
+ Literal,
+ )
-from slixmpp.plugins.xep_0004 import XEP_0004
-from slixmpp.plugins.xep_0009 import XEP_0009
-from slixmpp.plugins.xep_0012 import XEP_0012
-from slixmpp.plugins.xep_0013 import XEP_0013
-from slixmpp.plugins.xep_0020 import XEP_0020
-from slixmpp.plugins.xep_0027 import XEP_0027
-from slixmpp.plugins.xep_0030 import XEP_0030
-from slixmpp.plugins.xep_0033 import XEP_0033
-from slixmpp.plugins.xep_0045 import XEP_0045
-from slixmpp.plugins.xep_0047 import XEP_0047
-from slixmpp.plugins.xep_0049 import XEP_0049
-from slixmpp.plugins.xep_0050 import XEP_0050
-from slixmpp.plugins.xep_0054 import XEP_0054
-from slixmpp.plugins.xep_0059 import XEP_0059
-from slixmpp.plugins.xep_0060 import XEP_0060
-from slixmpp.plugins.xep_0065 import XEP_0065
-from slixmpp.plugins.xep_0066 import XEP_0066
-from slixmpp.plugins.xep_0070 import XEP_0070
-from slixmpp.plugins.xep_0071 import XEP_0071
-from slixmpp.plugins.xep_0077 import XEP_0077
-from slixmpp.plugins.xep_0079 import XEP_0079
-from slixmpp.plugins.xep_0080 import XEP_0080
-from slixmpp.plugins.xep_0082 import XEP_0082
-from slixmpp.plugins.xep_0084 import XEP_0084
-from slixmpp.plugins.xep_0085 import XEP_0085
-from slixmpp.plugins.xep_0086 import XEP_0086
-from slixmpp.plugins.xep_0092 import XEP_0092
-from slixmpp.plugins.xep_0106 import XEP_0106
-from slixmpp.plugins.xep_0107 import XEP_0107
-from slixmpp.plugins.xep_0108 import XEP_0108
-from slixmpp.plugins.xep_0115 import XEP_0115
-from slixmpp.plugins.xep_0118 import XEP_0118
-from slixmpp.plugins.xep_0122 import XEP_0122
-from slixmpp.plugins.xep_0128 import XEP_0128
-from slixmpp.plugins.xep_0131 import XEP_0131
-from slixmpp.plugins.xep_0133 import XEP_0133
-from slixmpp.plugins.xep_0152 import XEP_0152
-from slixmpp.plugins.xep_0153 import XEP_0153
-from slixmpp.plugins.xep_0163 import XEP_0163
-from slixmpp.plugins.xep_0172 import XEP_0172
-from slixmpp.plugins.xep_0184 import XEP_0184
-from slixmpp.plugins.xep_0186 import XEP_0186
-from slixmpp.plugins.xep_0191 import XEP_0191
-from slixmpp.plugins.xep_0196 import XEP_0196
-from slixmpp.plugins.xep_0198 import XEP_0198
-from slixmpp.plugins.xep_0199 import XEP_0199
-from slixmpp.plugins.xep_0202 import XEP_0202
-from slixmpp.plugins.xep_0203 import XEP_0203
-from slixmpp.plugins.xep_0221 import XEP_0221
-from slixmpp.plugins.xep_0222 import XEP_0222
-from slixmpp.plugins.xep_0223 import XEP_0223
-from slixmpp.plugins.xep_0224 import XEP_0224
-from slixmpp.plugins.xep_0231 import XEP_0231
-from slixmpp.plugins.xep_0235 import XEP_0235
-from slixmpp.plugins.xep_0249 import XEP_0249
-from slixmpp.plugins.xep_0256 import XEP_0256
-from slixmpp.plugins.xep_0257 import XEP_0257
-from slixmpp.plugins.xep_0258 import XEP_0258
-from slixmpp.plugins.xep_0279 import XEP_0279
-from slixmpp.plugins.xep_0280 import XEP_0280
-from slixmpp.plugins.xep_0297 import XEP_0297
-from slixmpp.plugins.xep_0300 import XEP_0300
-from slixmpp.plugins.xep_0308 import XEP_0308
-from slixmpp.plugins.xep_0313 import XEP_0313
-from slixmpp.plugins.xep_0319 import XEP_0319
-from slixmpp.plugins.xep_0332 import XEP_0332
-from slixmpp.plugins.xep_0333 import XEP_0333
-from slixmpp.plugins.xep_0334 import XEP_0334
-from slixmpp.plugins.xep_0335 import XEP_0335
-from slixmpp.plugins.xep_0352 import XEP_0352
-from slixmpp.plugins.xep_0353 import XEP_0353
-from slixmpp.plugins.xep_0359 import XEP_0359
-from slixmpp.plugins.xep_0363 import XEP_0363
-from slixmpp.plugins.xep_0369 import XEP_0369
-from slixmpp.plugins.xep_0377 import XEP_0377
-from slixmpp.plugins.xep_0380 import XEP_0380
-from slixmpp.plugins.xep_0382 import XEP_0382
-from slixmpp.plugins.xep_0394 import XEP_0394
-from slixmpp.plugins.xep_0403 import XEP_0403
-from slixmpp.plugins.xep_0404 import XEP_0404
-from slixmpp.plugins.xep_0405 import XEP_0405
-from slixmpp.plugins.xep_0421 import XEP_0421
-from slixmpp.plugins.xep_0422 import XEP_0422
-from slixmpp.plugins.xep_0424 import XEP_0424
-from slixmpp.plugins.xep_0425 import XEP_0425
-from slixmpp.plugins.xep_0428 import XEP_0428
-from slixmpp.plugins.xep_0437 import XEP_0437
-from slixmpp.plugins.xep_0439 import XEP_0439
-from slixmpp.plugins.xep_0444 import XEP_0444
+PresenceTypes = Literal[
+ 'error', 'probe', 'subscribe', 'subscribed',
+ 'unavailable', 'unsubscribe', 'unsubscribed',
+]
+PresenceShows = Literal[
+ 'away', 'chat', 'dnd', 'xa',
+]
+
+
+MessageTypes = Literal[
+ 'chat', 'error', 'groupchat',
+ 'headline', 'normal',
+]
+
+IqTypes = Literal[
+ "error", "get", "set", "result",
+]
-class PluginsDict(TypedDict):
- xep_0004: XEP_0004
- xep_0009: XEP_0009
- xep_0012: XEP_0012
- xep_0013: XEP_0013
- xep_0020: XEP_0020
- xep_0027: XEP_0027
- xep_0030: XEP_0030
- xep_0033: XEP_0033
- xep_0045: XEP_0045
- xep_0047: XEP_0047
- xep_0049: XEP_0049
- xep_0050: XEP_0050
- xep_0054: XEP_0054
- xep_0059: XEP_0059
- xep_0060: XEP_0060
- xep_0065: XEP_0065
- xep_0066: XEP_0066
- xep_0070: XEP_0070
- xep_0071: XEP_0071
- xep_0077: XEP_0077
- xep_0079: XEP_0079
- xep_0080: XEP_0080
- xep_0082: XEP_0082
- xep_0084: XEP_0084
- xep_0085: XEP_0085
- xep_0086: XEP_0086
- xep_0092: XEP_0092
- xep_0106: XEP_0106
- xep_0107: XEP_0107
- xep_0108: XEP_0108
- xep_0115: XEP_0115
- xep_0118: XEP_0118
- xep_0122: XEP_0122
- xep_0128: XEP_0128
- xep_0131: XEP_0131
- xep_0133: XEP_0133
- xep_0152: XEP_0152
- xep_0153: XEP_0153
- xep_0163: XEP_0163
- xep_0172: XEP_0172
- xep_0184: XEP_0184
- xep_0186: XEP_0186
- xep_0191: XEP_0191
- xep_0196: XEP_0196
- xep_0198: XEP_0198
- xep_0199: XEP_0199
- xep_0202: XEP_0202
- xep_0203: XEP_0203
- xep_0221: XEP_0221
- xep_0222: XEP_0222
- xep_0223: XEP_0223
- xep_0224: XEP_0224
- xep_0231: XEP_0231
- xep_0235: XEP_0235
- xep_0249: XEP_0249
- xep_0256: XEP_0256
- xep_0257: XEP_0257
- xep_0258: XEP_0258
- xep_0279: XEP_0279
- xep_0280: XEP_0280
- xep_0297: XEP_0297
- xep_0300: XEP_0300
- xep_0308: XEP_0308
- xep_0313: XEP_0313
- xep_0319: XEP_0319
- xep_0332: XEP_0332
- xep_0333: XEP_0333
- xep_0334: XEP_0334
- xep_0335: XEP_0335
- xep_0352: XEP_0352
- xep_0353: XEP_0353
- xep_0359: XEP_0359
- xep_0363: XEP_0363
- xep_0369: XEP_0369
- xep_0377: XEP_0377
- xep_0380: XEP_0380
- xep_0382: XEP_0382
- xep_0394: XEP_0394
- xep_0403: XEP_0403
- xep_0404: XEP_0404
- xep_0405: XEP_0405
- xep_0421: XEP_0421
- xep_0422: XEP_0422
- xep_0424: XEP_0424
- xep_0425: XEP_0425
- xep_0428: XEP_0428
- xep_0437: XEP_0437
- xep_0439: XEP_0439
- xep_0444: XEP_0444