Extending functionality

The design of pysig is flexible so that the user can override most of it’s functionality. We will show a couple of examples of how that can be useful.

The basics

Each router object can be instructed to use different classes. when constructing Sender, Event or Signal objects. This can be done when a new router object is created, likewise:

import sig

class MySender(sig.Sender): pass
class MySignal(sig.Signal): pass
class MyEvent(sig.Event): pass

router = sig.Router(class_sender= MySender, class_event= MyEvent, class_signal= MySignal)

Or it can be done on the fly, like this:

router.class_sender = MySender
router.class_event = MyEvent
router.class_signal = MySignal

If you intend to modify the behavior of the Signal class, just for a particular Sender, this is how you may proceed:

# find my sender
sender = router.getSender("my_sender")

# all signals created by this sender, from now on, will be
# instances of MySignal class
sender.class_signal = MySignal

Exteding Signal class

The Signal class is responsible for triggering events in pysig. The Signal object is created by the Sender class using the method getSignal, just like you’ve seen above.

By overriding the trigger method of the Signal class, we can add or modify the data parameter or we may even add other types of information to the info parameter.

Due to the fact that the info parameter passed to the callback of a listener, is a dictionary object, we may add additional information if we hook the Signal class and override the trigger method.

The information we’ve decided to add to the info parameter in the following example, is the number of occurences of each event sent by any sender. For that matter, we’ve registered a listener to the router broadcast event, in order to capture all events and we’ve used it to print the number of occurrences of that particular event, whenever is triggered.

The number of occurrences is stored globaly and added to the info parameter by our new Signal class called MySignal.

The full example looks like this:

Example

import sig

# counts the number of occurrences for each key
count_dict = {}
def count_message_from(key):
        global count_dict
        value = count_dict.get(key,0)
        value += 1
        count_dict[key] = value
        return value

# my own signal class
class MySignal(sig.Signal):

        def __init__(self, objevent, broad_events):
                sig.Signal.__init__(self, objevent, broad_events)

        def trigger(self, data):
                event_name  = self.objevent.getName()
                sender_name = self.objsender.getName()

                # count each message occurrence count
                value = count_message_from("%s:%s" % (sender_name, event_name))
                self.event_info["count"] = value

                # call super
                sig.Signal.trigger(self, data)

# listener callback
def listen_to_any(info, data):
        sender = info.get("sender")
        event  = info.get("event")
        occur  = info.get("count")
        print "Sender: %17.17s Event: %12.12s Occurrence: %u times" % (sender, event, occur)

# print statistics
def print_statistics():
        print "\nEvent statistics:"
        for key, value in count_dict.iteritems():
                print "%30.30s was triggered %u times" % (key, value)

# create router and instruct it to use a custom  Signal class
router = sig.Router(class_signal= MySignal)

# register broadcast listener
router.addListener(listen_to_any)

# create sender (connect event will be triggered)
my_events = ["my_event_1", "my_event_2"]
sender = router.addSender("my_sender", my_events)

# disconnect sender (disconnect event will be triggered)
router.removeSender(sender)

# connect sender again (connect event will be triggered)
sender = router.addSender("my_sender", my_events)

# connect another sender
sender2 = router.addSender("my_second_sender", my_events)

# trigger some events
sender.getSignal(my_events[0]).trigger(None)
sender2.getSignal(my_events[1]).trigger(None)

# remove senders
router.removeSender(sender)
router.removeSender(sender2)

# print statistics
print_statistics()

And the output:

Sender:         my_sender Event:     #connect Occurrence: 1 times
Sender:         my_sender Event:  #disconnect Occurrence: 1 times
Sender:         my_sender Event:     #connect Occurrence: 2 times
Sender:  my_second_sender Event:     #connect Occurrence: 1 times
Sender:         my_sender Event:   my_event_1 Occurrence: 1 times
Sender:  my_second_sender Event:   my_event_2 Occurrence: 1 times
Sender:         my_sender Event:  #disconnect Occurrence: 2 times
Sender:  my_second_sender Event:  #disconnect Occurrence: 1 times

Event statistics:
     my_second_sender:#connect was triggered 1 times
         my_sender:#disconnect was triggered 2 times
  my_second_sender:#disconnect was triggered 1 times
            my_sender:#connect was triggered 2 times
   my_second_sender:my_event_2 was triggered 1 times
          my_sender:my_event_1 was triggered 1 times

By modifying only the class_signal member of a Sender object, we can achieve the same effect but just for a particular sender.