Maintainabiity

Specify topic tree def

Topic Specification can be used to have better control over your topic hierarchy. If you don’t specify your application’s topics, PyPubSub infers them from the first subscribed listener of each topic. E.g.:

def listener1(arg1,      arg2=None): pass
def listener2(arg1=None, arg2=None): pass

pub.subscribe(listener1, 'topic.sub')
pub.subscribe(listener2, 'topic.sub')

Because listener1 is the first to be subscribed to ‘topic.sub’ topic, PyPubSub uses it to infer the specification of ‘topic.sub’: the specification is “messages of that topic must provide data for arg1, and may provide data for arg2”. The second listener subscribed, listener2, is allowed to subscribe because it is compatible with the topic’s specification created at the previous call. What if your intent was that arg1 is optional as well, i.e. the signature of listener1 is wrong (it should provide a default value for arg1)? Or what if per chance listener2 gets subscribed first (could happen if both are subscribed in different modules whose load order changes)?

The only way to not depend on the order of subscription of listeners is to use Topic definition providers (TDP). This is described below.

Topic Definition Providers

The easiest way to understand a topic tree definition is to get PyPubSub to output one for your application via pub.exportTopicTreeSpec(). Here is an example, taken from the file examples/advanced/kwargs_topics.py generated by that function, assuming two root topics ‘topic_1’ and ‘topic_2’ and the call pub.exportTopicTreeSpec('kwargs_topics'):

# Automatically generated by TopicTreeSpecPrinter(**kwargs).
# The kwargs were:
# - fileObj: file
# - width: 70
# - treeDoc: None
# - indentStep: 4
# - footer: '# End of topic tree definition. Note that application may l...'


class topic_1:
    """
    Explain when topic_1 should be used
    """

    def msgDataSpec(msg):
        """
        - msg: a text string message for recipient
        """

    class subtopic_11:
        """
        Explain when subtopic_11 should be used
        """

        def msgDataSpec(msg, msg2, extra=None):
            """
            - extra: something optional
            - msg2: a text string message #2 for recipient
            """


class topic_2:
    """
    Some something useful about topic2
    """

    def msgDataSpec(msg=None):
        """
        - msg: a text string
        """

    class subtopic_21:
        """
        description for subtopic 21
        """

        def msgDataSpec(msg, arg1=None):
            """
            - arg1: UNDOCUMENTED
            """

# End of topic tree definition. Note that application may load
# more than one definitions provider.

This shows how the topic definition tree is defined using a Python module with a nested class tree that represents the topics, and msgDataSpec() functions that represent the listener signatures for the given topics. This also shows how it is possible to document each topic and message datum.

An application uses the above module via the following:

import kwargs_topics
pub.addTopicDefnProvider( kwargs_topics, pub.TOPIC_TREE_FROM_CLASS )

The format type is pub.TOPIC_TREE_FROM_CLASS because once imported, the kwargs_topics object is a module containing topic definitions as classes; based on that setting, PyPubSub will look for all classes in the kwargs_topics object, and instantiate one topic definition for each one.

See examples/advanced/main_kwargs.py for an example of using a topic tree definition in an application.

It is possible to support other formats for topic tree definition. For example, pubsub.utils.XmlTopicDefnProvider was contributed to PyPubSub by one of its devoted users. A new type of provider need only adhere to the pub.ITopicTreeDefnProvider interface; pub.addTopicDefnProvider() accepts any instance that implements from that interface:

xmlString = open('xml_topics.xml', 'r').read()
provider = XmlTopicDefnProvider(xmlString)
pub.addTopicDefnProvider( provider )

It is typically useful to combine topic tree definition with the following call, placed once at the beginning of an application:

pub.setTopicUnspecifiedFatal(True)

Then any attempt to use a topic that is not defined in the topic tree definition will raise an pub.TopicUnspecifiedError.

Note that any topic that does not have a docstring is not considered to be defined. This may allow for some temporary “undefining” of topics.