My favorites | Sign in
Project Logo
                
Code license: Apache License 2.0
Labels: python
People details
Project owners:
  dclinton

A library for creating and running callbacks and closures in Python.

Python documentation:

http://python-callbacks.googlecode.com/svn/trunk/doc/callbacks.html

View source:

http://code.google.com/p/python-callbacks/source/browse/trunk/callbacks.py

Features include:

Scopes: Callbacks can be registered in instance, class, module or global scope.
Priority levels: Callbacks can be given a priority, where higher priority callbacks will be run before lower priority callbacks.
Automatic requeuing: Callbacks can be marked as 'permanent' to be requeued automatically after being executed.
Callback chaining: Callbacks can be chained such that the result of the previous callback is used as the input for the next callback.
Genericity: Any callable object (a Callback instance, a function, a anonymous lambda function, or a class-based closure) can be used as a callback.
Iterators: Callbacks can be invoked automatically via RunAllCallbacks and RunCallbackChain, or iterated over manually with CallbackIterator and CopyFirstCallbackIterator.

Overview:

A callback is callable code that can be registered and executed at some point in the future in a different context. The callback pattern allows a library to handle arbitrary clients without knowing in advance what they will be.
The callback registration mechanism that allows client code to tell a class or module about a method that should be executed at a point in time in the future.
The library is used by two distinct groups: classes or modules that wish to register and execute callbacks, and clients that wish to register their code to be called back.
Classes or modules that register and run callbacks should first write a wrapper function around the RegisterCallback method. This method will be invoked by other classes and code that want to be called back at some point in the future. E.g.:
>>> from callbacks import RegisterCallback, RunAllCallbacks
>>> 
>>> class CallbackHost(object):
...   def RegisterSomeCallback(self, callback):
...     '''Registers the callback to be invoked by RunAllCallbacks.'''
...     RegisterCallback(self, 'some callback', callback)
...
...   def RunTheCallbacks(self):
...     '''Returns the results (in a list) of  each registed callback.'''
...     return RunAllCallbacks(self, 'some callback')
To use the registration methods, clients will provide a callback method in the form of a function, an anonymous lambda function, a class-based callable closure, or a Callback, PermanentCallback, or TemporaryCallback (or subclass) instance.
After the callbacks have been registered, the class can run all of the registed callbacks automatically by executing the RunAllCallbacks method. E.g.:
>>> from callbacks import PermanentCallback, Callback

>>> def MyCallback():
...   return 'MyCallback'

>>> host = CallbackHost()
>>> callback = PermanentCallback(MyCallback)
>>> host.RegisterSomeCallback(callback)
>>> host.RunTheCallbacks()
['MyCallback']
Class-based closures can also be registered:
>>> class MyClosure(object):
...   def __init__(self, string):
...      self.string = string
...   def __call__(self):
...      return self.string

>>> callback = PermanentCallback(MyClosure('MyClosure'))
>>> host.RegisterSomeCallback(callback)
>>> host.RunTheCallbacks()
['MyCallback', 'MyClosure']
As can higher-priority callbacks:
>>> callback = PermanentCallback(MyClosure('High priority'), priority=10)
>>> host.RegisterSomeCallback(callback)
>>> host.RunTheCallbacks()
['High priority', 'MyCallback', 'MyClosure']
By default, callbacks expire after being run once:
>>> callback = Callback(MyClosure('Run once'))
>>> host.RegisterSomeCallback(callback)
>>> host.RunTheCallbacks()
['High priority', 'MyCallback', 'MyClosure', 'Run once']
>>> host.RunTheCallbacks()
['High priority', 'MyCallback', 'MyClosure']

Another Example:

Imagine a TextProcessor class that is used to modify text. The TextProcessor wants to allow callers to provide their own text processing routines, and does so via a RegisterProcessor method. When the Process method is invoked, so are the registered text processors.

>>> import callbacks

>>> class TextProcessor(object):
...   '''A class that modifies text according to registered callbacks.'''
...
...   def RegisterProcessor(self, callback):
...     '''Registers a callback to be invoked when the text.'''
...     callbacks.RegisterCallback(self, 'process', callback)
...
...   def Process(self, text):
...     '''Runs all of the registered callbacks to process the text.'''
...     return callbacks.RunCallbackChain(self, 'process', text)
In the client:
>>> import re

>>> def Capitalize(text):
...   '''Returns the text with the first character capitalized.'''
...   return text.capitalize()

>>> def CompactWhitespace(text):
...   '''Returns the text with successive whitespace characters collapsed.'''
...   return re.sub('\\s+', ' ', text)     

>>> processor = TextProcessor()
>>> processor.RegisterProcessor(Capitalize)
>>> processor.RegisterProcessor(CompactWhitespace)
>>> processor.Process('four  score and  seven  years    ago...')
'Four score and seven years ago...'

Limitations and TODOs:

Function signatures are not validated. Helper code could be written to match callback signatures against a function specification or against a reference function.
Exceptions raised by callbacks are not handled automatically yet.
Automatic registration and execution wrappers could be created to simplify the one-line boilerplate functions.








Hosted by Google Code