Changelog

Version 0.8

New XEP implementations

  • aioxmpp.adhoc (XEP-0050): Support for using Ad-Hoc commands; publishing own Ad-Hoc commands for others to use is not supported yet.

New major features

New examples

  • adhoc_browser: A graphical tool to browse and execute Ad-Hoc Commands. Requires PyQt5. Run make in the examples directory and start with python3 -m adhoc_browser.
  • entity_items.py, entity_info.py: Show service discovery info and items for arbitrary JIDs.
  • list_adhoc_commands.py: List the Ad-Hoc commands offered by an entity.

Breaking changes

Changes to the connection procedure:

Changes in aioxmpp.Client (formerly aioxmpp.AbstractClient, see in the deprecations below for the name change)

  • The number of connection attempts made before the first connection is successful is now bounded, configurable through the new parameter max_initial_attempts. The default is at 4, which gives (together with the default exponential backoff parameters) a minimum time of attempted connections of about 5 seconds.
  • on_stream_suspended() was added (this is not a breaking change, but belongs to the aioxmpp.Client changes discussed here).
  • on_stream_destroyed() got a new argument reason which gives the exception which caused the stream to be destroyed.

Other breaking changes:

  • aioxmpp.tracking.MessageState.UNKNOWN renamed to CLOSED.

  • aioxmpp.disco.Node.iter_items(), iter_features() and iter_identities() now get the request stanza passed as first argument.

  • aioxmpp.Presence.show now uses the aioxmpp.PresenceShow enumeration. The breakage is similar to the breakage in the 0.7 release; if I had thought of it at that time, I would have made the change back then, but it was overlooked.

    Again, a utility script (find-v0.8-type-transitions.sh) is provided which helps finding locations of code which need changing. See the Version 0.7 for details.

  • Presence states with show set to DND now order highest (before, DND ordered lowest). The rationale is that if a user indicates DND state at one resource, one should probably respect the Do-Not-Disturb request on all resources.

The following changes are not severe, but may still break code depending on how it is used:

  • aioxmpp.disco.Service was split into aioxmpp.DiscoClient and aioxmpp.DiscoServer.

    If you need to be compatible with old versions, use code like this:

    try:
        from aioxmpp import DiscoClient, DiscoServer
    except ImportError:
        import aioxmpp.disco
        DiscoClient = aioxmpp.disco.Service
        DiscoServer = aioxmpp.disco.Service
    
  • Type coercion in XSO descriptors now behaves differently. Previously, None was hard-coded to be exempt from type coercion; this allowed any Text, ChildText, Attr and other scalar descriptor to be assigned None, unless a validator which explicitly forbade that was installed. The use case was to have a default, absence-indicating value which is outside the valid value range of the type_.

    This is now handled by exempting the default of the descriptor from type coercion and thus allowing assignment of that default by default. The change thus only affects descriptors which have a default other than None (which includes an unset default).

Minor features and bug fixes

Deprecations

Version 0.7

  • License change: As of version 0.7, aioxmpp is distributed under the terms of the GNU Lesser General Public License version 3 or later (LGPLv3+). The exact terms are, as usual, found by taking a look at COPYING.LESSER in the source code repository.

  • New XEP implementations:

    • aioxmpp.forms (XEP-0004): An implementation of the Data Forms XEP. Take a look and see where it gets you.
  • New features in the aioxmpp.xso submodule:

  • Often-used names have now been moved to the aioxmpp namespace:

  • Horribly Breaking Change in the future: aioxmpp.IQ.type_, aioxmpp.Message.type_, aioxmpp.Presence.type_ and aioxmpp.stanza.Error.type_ now use aioxmpp.xso.EnumType, with corresponding enumerations (see docs of the respective attributes).

    This will break about every piece of code ever written for aioxmpp, and it is not trivial to fix automatically. This is why the following fallbacks have been implemented:

    1. The type_ attributes still accept their string (or None in the case of Presence.type_) values when being written. When being read, the attributes always return the actual enumeration value.
    2. The relevant enumeration members compare equal (and hash equally) to their values. Thus, MessageType.CHAT == "chat" is still true (and MessageType.CHAT != "chat" is false).
    3. register_message_callback(), register_presence_callback(), and register_iq_request_coro(), as well as their corresponding un-registration methods, all accept the string variants for their arguments, internally mapping them to the actual enumeration values.

    Note

    As a matter of fact (good news!), with only the fallbacks and no code fixes, the aioxmpp test suite passes. So it is likely that you will not notice any breakage in the 0.7 release, giving you quite some time to react.

    These fallbacks will be removed with aioxmpp 1.0, making the legacy use raise TypeError or fail silently. Each of these fallbacks currently produces a DeprecationWarning.

    Note

    DeprecationWarning warnings are not shown by default in Python 3. To enable them, either run the interpreter with the -Wd option, un-filter them explicitly using warnings.simplefilter("always") at the top of your program, or explore other options as documented in warnings.

    So, now I said I will be breaking all your code, how do you fix it? There are two ways to find affected pieces of code: (1) run it with warnings (see above), which will find all affected pieces of code and (2) use the shell script provided at utils/find-v0.7-type-transitions.sh to find a subset of potentially affected pieces of code automatically. The shell script uses The Silver Searcher (ag) (find it in your distributions package repositories, I know it is there on Fedora, Arch and Debian!) and regular expressions to find common patterns. Example usage:

    # find everything in the current subdirectory
    $ $AIOXMPPPATH/utils/find-v0.7-type-transitions.sh
    # only search in the foobar/ subdirectory
    $ $AIOXMPPPATH/utils/find-v0.7-type-transitions.sh foobar/
    # only look at the foobar/baz.py file
    $ $AIOXMPPPATH/utils/find-v0.7-type-transitions.sh foobar/baz.py
    

    The script was built while fixing aioxmpp itself after the bug. It has not found all affected pieces of code, but the vast majority. The others can be found by inspecting DeprecationWarning warnings being emitted.

  • The aioxmpp.security_layer.make() makes creating a security layer much less cumbersome than before. It provides a simple interface supporting password authentication, certificate pinning and others.

    The interface of this function will be extended in the future when more authentication or certificate verification mechanisms come around.

  • The two methods aioxmpp.muc.Service.get_room_config(), aioxmpp.muc.Service.set_room_config() have been implemented, allowing to manage MUC room configurations.

  • Fix bug in aioxmpp.xso.ChildValueMultiMap.to_sax() which rendered XSOs with that descriptor useless.

  • Fix documentation on aioxmpp.PresenceManagedClient.set_presence().

  • aioxmpp.callbacks.AdHocSignal now logs when coroutines registered with aioxmpp.callbacks.AdHocSignal.SPAWN_WITH_LOOP() raise exceptions or return non-None values. See the documentation of SPAWN_WITH_LOOP() for details.

  • aioxmpp.pubsub.xso.as_payload_class() is a decorator (akin to aioxmpp.IQ.as_payload_class()) to declare that your XSO shall be allowed as pubsub payload.

  • register_message_callback() and register_presence_callback() now explicitly raise ValueError when an attempt to overwrite an existing listener is made, instead of silently replacing the callback.

Version 0.7.2

  • Fix resource leak which would emit:

    task: <Task pending coro=<OrderedStateMachine.wait_for() running at /home/horazont/Projects/python/aioxmpp/aioxmpp/statemachine.py:170> wait_for=<Future pending cb=[Task._wakeup()]> cb=[XMLStream._stream_starts_closing()]>
    
  • Improve compatibility of aioxmpp.muc with Prosody 0.9 and below, which misses sending the 110 status code on some presences.

  • Handle inbound message stanzas with empty from attribute. Those are legal as per RFC 6120, but were not handled properly.

Version 0.6

Version 0.6.1

Version 0.5

  • Support for XEP-0045 multi-user chats is now available in the aioxmpp.muc subpackage.

  • Mostly transparent support for XEP-0115 (Entity Capabilities) is now available using the aioxmpp.entitycaps subpackage.

  • Support for transparent non-scalar attributes, which get mapped to XSOs. Use cases are dicts mapping language tags to strings (such as for message body elements) or sets of values which are represented by discrete XML elements.

    For this, the method get_formatted_type() was added to aioxmpp.xso.AbstractType and two new descriptors, aioxmpp.xso.ChildValueMap and aioxmpp.xso.ChildValueList, were implemented.

    ChildValueMap A mapping of keys to values, generated by child tags.
    ChildValueList A list of values, generated by child tags.
    ChildTextMap A specialised version of ChildValueMap which uses TextChildMap together with structs.LanguageMap to convert the AbstractTextChild subclass xso_type to and from a language-text mapping.

    Breaking change: The above descriptors are now used at several places, breaking the way these attributes need to be accessed:

  • Several stability improvements have been made. A race condition during stream management resumption was fixed and aioxmpp.node.AbstractClient instances now stop if non-OSError exceptions emerge from the stream (as these usually indicate an implementation or user error).

    aioxmpp.callbacks.AdHocSignal now provides full exception isolation.

  • Support for capturing the raw XML events used for creating aioxmpp.xso.XSO instances from SAX is now provided through aioxmpp.xso.CapturingXSO. Helper functions to work with these events are also provided, most notably aioxmpp.xso.events_to_sax(), which can be used to re-create the original XML from those events.

    The main use case is to be able to write out a transcript of received XML data, independent of XSO-level understanding for the data received, provided the parts which are understood are semantically correct (transcripts will be incomplete if parsing fails due to incorrect contents).

    CapturingXSO(*args, **kwargs) The following class methods is provided by the metaclass (which is not
    capture_events(receiver, dest) Capture all events sent to receiver in the sequence dest.
    events_to_sax(events, dest) Convert an iterable events of XSO events to SAX events by calling the

    This feature is already used in aioxmpp.disco.xso.InfoQuery, which now inherits from CapturingXSO and provides its transcript (if available) at captured_events.

  • The core SASL implementation has been refactored in its own independent package, aiosasl. Only the XMPP specific parts reside in aioxmpp.sasl and aioxmpp now depends on aiosasl.

  • aioxmpp.stream.StanzaStream.register_message_callback() is more clearly specified now, a bug in the documentation has been fixed.

  • aioxmpp.stream_xsos is now called aioxmpp.nonza, in accordance with XEP-0360.

  • aioxmpp.xso.Date and aioxmpp.xso.Time are now available to for XEP-0082 use. In addition, support for the legacy date time format is now provided in aioxmpp.xso.DateTime.

    Date Implement the Date type from XEP-0082.
    Time Implement the Time type from XEP-0082.
    DateTime(*[, legacy]) Parse the value as ISO datetime, possibly including microseconds and timezone information.
  • The Python 3.5 compatibility of the test suite has been improved. In a corner-case, StopIteration was emitted from data_received, which caused a test to fail with a RuntimeError due to implementation of PEP 0479 in Python 3.5. See the issue at github.

  • Helper functions for reading and writing single XSOs (and their children) to binary file-like objects have been introduced.

    write_single_xso(x, dest) Write a single XSO x to a binary file-like object dest.
    read_xso(src, xsomap) Read a single XSO from a binary file-like input src containing an XML document.
    read_single_xso(src, type_) Read a single XSO of the given type_ from the binary file-like input src and return the instance.
  • In 0.5.4, aioxmpp.network was re-written. More details will follow in the 0.6 changelog. The takeaway is that the network stack now automatically reloads the DNS configuration after the first timeout, to accomodate to changing resolvers.

Version 0.4

  • Documentation change: A simple sphinx extension has been added which auto-detects coroutines and adds a directive to mark up signals.

    The latter has been added to relevant places and the former automatically improves the documentations quality.

  • aioxmpp.roster.Service now implements presence subscription management. To track the presence of peers, aioxmpp.presence has been added.

  • aioxmpp.stream and aioxmpp.nonza are part of the public API now. aioxmpp.nonza has gained the XSOs for SASL (previously in aioxmpp.sasl) and StartTLS (previously in aioxmpp.security_layer).

  • aioxmpp.xso.XSO subclasses now support copying and deepcopying.

  • aioxmpp.protocol has been moved into the internal API part.

  • aioxmpp.Message specification fixed to have "normal" as default for type_ and relax the unknown child policy.

  • Possibly breaking change: aioxmpp.xso.XSO.DECLARE_NS is now automatically generated by the meta class aioxmpp.xso.model.XMLStreamClass. See the documentation for the detailed rules.

    To get the old behaviour for your class, you have to put DECLARE_NS = {} in its declaration.

  • aioxmpp.stream.StanzaStream has a positional, optional argument (local_jid) for ejabberd compatiblity.

  • Several fixes and workarounds, finally providing ejabberd compatibility:

    • aioxmpp.nonza.StartTLS declares its namespace prefixless. Otherwise, connections to some versions of ejabberd fail in a very humorous way: client says “I want to start TLS”, server says “You have to use TLS” and closes the stream with a policy-violation stream error.
    • Most XSOs now declare their namespace prefixless, too.
    • Support for legacy (RFC 3921) XMPP session negotiation implemented in aioxmpp.node.AbstractClient. See aioxmpp.rfc3921.
    • aioxmpp.stream.StanzaStream now supports incoming IQs with the bare JID of the local entity as sender, taking them as coming from the server.
  • Allow pinning of certificates for which no issuer certificate is available, because it is missing in the server-provided chain and not available in the local certificate store. This is, with respect to trust, treated equivalent to a self-signed cert.

  • Fix stream management state going out-of-sync when an erroneous stanza (unknown payload, type or validator errors on the payload) was received. In addition, IQ replies which cannot be processed raise aioxmpp.errors.ErroneousStanza from aioxmpp.stream.StanzaStream.send_iq_and_wait_for_reply() and when registering futures for the response using aioxmpp.stream.StanzaStream.register_iq_response_future(). See the latter for details on the semantics.

  • Fixed a bug in aioxmpp.xml.XMPPXMLGenerator which would emit elements in the wrong namespace if the meaning of a XML namespace prefix was being changed at the same time an element was emitted using that namespace.

  • The defaults for unknown child and attribute policies on aioxmpp.xso.XSO are now DROP and not FAIL. This is for better compatibility with old implementations and future features.

Version 0.3

  • Breaking change: The required keyword argument on most aioxmpp.xso descriptors has been removed. The semantics of the default keyword argument have been changed.

    Before 0.3, the XML elements represented by descriptors were not required by default and had to be marked as required e.g. by setting required=True in xso.Attr constructor.

    Since 0.3, the descriptors are generally required by default. However, the interface on how to change that is different. Attributes and text have a default keyword argument which may be set to a value (which may also be None). In that case, that value indicates that the attribute or text is absent: it is used if the attribute or text is missing in the source XML and if the attribute or text is set to the default value, it will not be emitted in XML.

    Children do not support default values other than None; thus, they are simply controlled by a boolean flag required which needs to be passed to the constructor.

  • The class attributes SERVICE_BEFORE and SERVICE_AFTER have been renamed to ORDER_BEFORE and ORDER_AFTER respectively.

    The aioxmpp.service.Service class has additional support to handle the old attributes, but will emit a DeprecationWarning if they are used on a class declaration.

    See aioxmpp.service.Meta.SERVICE_AFTER for more information on the deprecation cycle of these attributes.