Showing posts with label boduch. Show all posts
Showing posts with label boduch. Show all posts

Friday, July 3, 2009

Subscribing To Event Subscritions In Python

New in the latest version of the boduch Python library is the Subscription class. This abstraction is used to represent active event subscriptions to event handles. A Subscription instance ties together the Event class and the Handle class. The Handle providing the callback functionality that is executed when a given event takes place that the handle as a subscription to. As with previous versions, the event handle still uses the subscribe() function to subscribe to particular events. However, in previous versions, this function didn't actually return anything. The function will now return a Subscription instance. This functionality was added so that developers can have an easier method in which to reference which events will cause a given behavior to take place. The following is an example of a Subscription instance being returned.
#Example; Subscribing to a boduch Set event.

#Import required objects.
from boduch.event import subscribe, EventSetPush
from boduch.handle import Handle
from boduch.data import Set

#Simple handle.
class MyHandle(Handle):
def __init__(self, *args, **kw):
Handle.__init__(self, *args, **kw)

def run(self):
print "Running my handle."

if __name__=="__main__":
#Create a new subscription instance by subscribing to the event.
print "Subscribing"
sub=subscribe(EventSetPush, MyHandle)
print "Subscribed", sub

#Make sure the simple handle works.
Set().push("data")
In the example above, we define a simple event handle called MyHandle. We then subscribe this handle to the EventSetPush event to instantiate a new Subscription instance. Each Subscription instance holds a reference to both the handle and the event that the handle has subscribed to. Additionally, Subscription instances also define behavior. Since a Subscription instance holds a reference to the given event, we can use this instance hold build further subscriptions for this event. The core event handles inside the library already define and expose Subscription instances and can be used to create subscriptions for new event handles as the example below illustrates.
#Example; Subscribing to a boduch Set event via subscription.

#Import required objects.
from boduch.subscription import SubSetPush
from boduch.handle import Handle
from boduch.data import Set

#Simple handle.
class MyHandle(Handle):
def __init__(self, *args, **kw):
Handle.__init__(self, *args, **kw)

def run(self):
print "Running my handle."

if __name__=="__main__":
#Create a new subscription instance by subscribing to the event.
print "Subscribing"
sub=SubSetPush.subscribe(MyHandle)
print "Subscribed", sub

#Make sure the simple handle works.
Set().push("data")

Thursday, May 28, 2009

Stateful Python Lists

The Python programming language defines list objects as one of the primitive language types. Lists, are similar to arrays in more traditional programming languages. Of course, Python lists are mutable types, as are arrays. The main difference between Python lists and traditional arrays are similar in most other comparisons of Python to other languages; Python lists are more flexible and elegant. However, Python lists are not magic. One situation where Python lists have the potential to easily fall apart is when used in a multi-threaded environment. This fact isn't exclusive to lists, the same risk involved with passing data across threads applies to all types. The good news is that this can be easily remedied with lists. Python list instances support the notion of "pushing" and "pulling" data. This is a useful thought construct because this transfers directly to the design. Any given list instance can be "pushing" state when adding data to the list or a "pulling" state when retrieving data from the list.

The Set class in the boduch Python library is essentially a Python list that publishes events. These events that are published by Set instances have the potential to be handled in a multi-threaded environment. If Set instances are being both "pushed" to and "pulled" from in a multi-threaded environment, this could be very dangerous. Data that is expected to exist in the set instance when "pulled" may not have arrived yet. In this scenario, it would be useful to know what state the Set instance is in. By combining both the Set and StateMachine classes as demonstrated below, we end up with a "stateful" Python list. The implementation of the StatefulSet shown here isn't fully thread safe. This is because it is incomplete. However, the code used in the main program is thread safe.
#example; Creating a multi-threaded Python list with a boduch Set.

#Necessary imports.
from boduch.event import threaded, subscribe, EventSetPush
from boduch.handle import Handle, HandleSetPush
from boduch.data import Set
from boduch.state import StateMachine
from boduch.type import is_type
from boduch import PRIORITY_MINOR, PRIORITY_CRITICAL

#A handle for Set.push() method invocations.
class HandlePreStatefulSetPush(Handle):
#This gets a higher than critical priority since it is
#intended to run before the core behavior.
priority=PRIORITY_CRITICAL+1
def __init__(self, *args, **kw):
Handle.__init__(self, *args, **kw)

def run(self):
#Check if we are handling a StatefulSet event. If
#so, set goes into a pushing state.
set_obj=self.get_event_data("set")
if is_type(set_obj, "StatefulSet"):
set_obj.change_state("PUSHING")

#A handle for Set.push() method invocations.
class HandlePostStatefulSetPush(Handle):
#This handle gets a minor priority since it is
#intended to run after all the pushing is complete.
priority=PRIORITY_MINOR
def __init__(self, *args, **kw):
Handle.__init__(self, *args, **kw)

def run(self):
#Check if we are handling a StatefulSet event. If
#so, set goes into a ready state.
set_obj=self.get_event_data("set")
if is_type(set_obj, "StatefulSet"):
set_obj.change_state("READY")

#A stateful version of the Set class.
class StatefulSet(StateMachine, Set):
def __init__(self, *args, **kw):
#Initialize the base classes and populate the
#potential set states.
StateMachine.__init__(self, *args, **kw)
Set.__init__(self, *args, **kw)
self.add_state("READY")
self.add_state("PUSHING")

def _push(self, data):
#Change to a pushing state before actually pushing data.
self.change_state("PUSHING")
self.push(data)

def _get(self, index):
#Don't attempt to return anything while in a pushing state.
while self=="PUSHING":
print "Hold on, still pushing data."
pass
return self[index]

#Subscribe the custom stateful handles.
subscribe(EventSetPush, HandlePreStatefulSetPush)
subscribe(EventSetPush, HandlePostStatefulSetPush)

#Main program.
if __name__=="__main__":
#Enable threaded event mode.
threaded(True)
#Instantiate a stateful set.
set_obj=StatefulSet()
#Populate the set while retrieving data in a thread-safe manor.
for i in range(0,10):
set_obj._push("SET DATA"+str(i))
print set_obj._get(i)

Wednesday, May 6, 2009

Creating State Machines in Python

In the UML, state machines help modelers understand the various states the system in question goes through. When the system is in one state, the available behavior differs from when the system is in another state. Visualizing these states by drawing them as UML elements is an extremely powerful tool. State machines are not only powerful for examining the potential states of a given system, but also in helping to understand the transitions that could potentially take place between these states. In object-orientated systems, the concept of objects being in one state or another is often implemented in code, even if implicitly. Given that this is object-oriented code we are working with, and the whole idea behind object orientation is to assist with creating realistic abstractions, why not use the concept of state machines directly in code? The 0.1.6 version of the boduch Python library tries to realize this possibility. Although this is the first iteration of this new feature, with lots of work left to do, it seems promising. Below is an example of the new StateMachine class in use.

#Example; Using boduch state machines.

from boduch.state import StateMachine
from boduch.predicate import Equal

#Define two predicate functions used to return
#the predicate variables.
def get_o1():
return o1

def get_o2():
return o2

#The two predicate variables. Notice they
#aren't equal.
o1=1
o2=2

#Construct a state machine instance.
state_obj=StateMachine()

#Construct a predicate instance using the
#two previously defined predicate functions.
predicate_obj=Equal(get_o1, get_o2)

#Populate the state machine with two states.
state_obj.add_state("RUNNING")
state_obj.add_state("STOPPED")

#Add a state transition to the machine using
#the previously defined predicate. Once true,
#the machine will be in the target state.
state_obj.add_transition("STOPPED", predicate_obj)

if __name__=="__main__":
#Change the machine to a RUNNING state.
state_obj.change_state("RUNNING")
print state_obj.current_state

#Change the value of the predicate variable.
o2=1
print "o2 now equals o1"

#Check for any state changes.
state_obj.transition()
print state_obj.current_state

Be brief overview of the above code follows below.
  • Import the classes required. There are StateMachine and Equal.
  • Define the predicate functions. These functions are used by the predicate associated with the state machine. They are invoked each time the predicate is evaluated.
  • Define the predicate variables. These variables are global and are returned by the predicate functions. Any changes to these variables are reflected by invoking the predicate functions.
  • Create a new StateMachine instance. This is the main state machine involved in the example.
  • Create a new Equal predicate instance and use the predicate functions as operands.
  • Populate the state machine instance with some states. A state can be any Python object.
  • Add a new transition to the state machine using the previously defined Equal instance. When this predicate instance evaluates to true, the target state, in this case, "STOPPED", will become the active state.
  • Set the initial state to "RUNNING".
  • Change the value of one of the predicate variables. The predicate can now be considered equal.
  • Test the state machine for any state changes. Here, there are changes because the transition that was previously added to the state machine will evaluate to true, causing the target of the transition to become the active state.
  • The state machine is now in a "STOPPED" state.

Tuesday, March 24, 2009

Why we need a thread-safe publish/subscribe event system

Publish-subscribe event systems are a fairly common design pattern in modern computing. The concept becomes increasingly powerful in distributed systems where many nodes can subscribe to an event or topic emitted from a single node. The name publish-subscribe, or pub-sub, is used because it has a tight analogue in the real world. People with magazine or newspaper subscriptions receive updates when something is published. Because of this analogue, developers are more easily able to reason about events and why they occurred in complex software systems. In any given software system, some code will need to react to one or more events. These events can range from anything as simple as a mouse click to a complete database failure. The publish-subscribe pattern is infinitely extensible because any number of observers may subscribe to a single event. Subscriptions can also be canceled to as to offer architectural scalability in both directions; up and down. One bottleneck in a publish-subscribe framework can occur while the publishing object needs to wait until all subscribers have finished reacting to the event. In some cases, this is unavoidable such as when the publisher is expecting a value to be returned from one of the subscribers. In other cases, however, the publisher doesn't care about the subscribers or how they react to a published event. In a localized publish-subscribe system, that is, not a distributed publish-subscribe system, we could use threads for subscribers. If we were to build and use a framework such as this, where subscriptions react to events in separate threads of control, we would also need the ability to turn threading off and use the framework in the same way and have it still be functional. This is because threading is simply not an option in every scenario.

The boduch Python library offers a publish-subscribe event system such as this. The library is still in it's infancy but has the ability to run subscription event handles in new threads on control. The threading capability can also be switched on and off. The same code using the library can be run in either mode. Events are declared by specializing a base "Event" class. Likewise, event handles, or subscriptions, are declared by specializing a base "Handle" class. Developers can then subscribe to an event by passing an event class and a handle class to the subscribe function. Multiple handles may be listening to a given event type and if running in threaded mode, each handle will start a new thread of control. There are limits on the number of threads that are allowed to be run at a given time but this can be adjusted either manually or pragmatically. When running in threaded mode, or non-threaded mode for that matter, published events may be specified as atomic. This really only as an effect when the event system is running in threaded mode because it forces all handles for that particular event to run in the publisher's thread. When running in non-threaded mode, atomic publications are idempotent.

As mentioned earlier, there are several limitations to the boduch library since it is still in its infancy as a project. For instance, there is no way to specify a filter for event subscriptions. Subscribers may want to react to event types based on data contained within the event instance. In turn, there is no way to tack the source object that emitted the event. Finally, there is no real guarantee that proper ordering will be preserved when running in threaded mode. However, this can be worked-around. I haven't actually encountered a scenario where the ordering of instructions have been defective when running in threaded mode. This doesn't mean it is possible. I actually hope I do some day so I can incorporate more built in safety in the library.

Saturday, March 14, 2009

Using predicates with the boduch library

With the latest release of the boduch Python library, there are two new predicate classes available; Greater and Lesser. These predicates do exactly what the name says. The Greater predicate will evaluate to true if the first operand is greater than the second. The Lesser predicate will return true if the first operand is less than the operand. Here is an example of how we would use these predicates.
#Example; boduch predicates

from boduch.predicate import Greater, Lesser

if __name__=="__main__":
is_greater=Greater(2,1)
is_lesser=Lesser(1,2)

if is_greater:
print "is_greater is true."
else:
print "is_greater is false."
if is_lesser:
print "is_lesser is true."
else:
print "is_lesser is false"

Here, we have two predicate instances, is_greater and is_lesser. The is_greater variable is an instance of the Greater predicate and will evaluate to true in this case. The is_lesser variable is an instance of the Lesser predicate and will evaluate to true in this case.

With the latest release the library, predicate instances can also accept function objects as parameters. For example, consider the following modified example.
#Example; boduch predicates

from boduch.predicate import Greater, Lesser

number1=0
number2=0

def op1():
global number1
return number1

def op2():
global number2
return number2

def results():
global is_greater
global is_lesser
if is_greater:
print "is_greater is true."
else:
print "is_greater is false."
if is_lesser:
print "is_lesser is true."
else:
print "is_lesser is false"

if __name__=="__main__":
#Construct predicate instances using function objects as operands.
is_greater=Greater(op1,op2)
is_lesser=Lesser(op1,op2)

#Change the value of the operands.
number1=2
number2=1

#Print results.
results()

#Change the value of the operands.
number1=1
number2=2

#Print results.
results()

Here, we now have two variables, number1 and number2 that will act as operands. Next, we have two functions that will return these values, op1() and op2(). Next, the results() function simply prints the result of evaluating the predicates. In the main program, we construct the two predicate instances, passing the op1() and op2() functions as operand parameters. Next, we initialize the number1 and number2 variables and print the result of evaluating the predicates. Finally, we change the value of number1 and number2 and once more print the results. You'll notice that the results will have reflected the change in number1 and number2.

Wednesday, March 11, 2009

Interesting bug found in the boduch Python library

In the latest release of the boduch Python library, Set instances can now be iterated over. This is done by defining a custom iterator class, SetIterator, that is returned by the Set.__iter__() method. I thought I would further test out this new functionality in a hope that I would discover some new unit tests that I can include with the library. But before I could even get to the Set iteration testing, I discovered an entirely new bug with the Set class.

Firstly, here is the code I used to find the bug.
#Example; boduch Set bug.

from boduch.data import Set
from boduch.handle import Handle
from boduch.event import subscribe, threaded, EventSetPush

class MyHandle(Handle):
def __init__(self, *args, **kw):
Handle.__init__(self, *args, **kw)

def run(self):
pass

if __name__=="__main__":
threaded(True)
subscribe(EventSetPush, MyHandle)

set_obj1=Set()
set_obj2=Set()

set_obj1.push("data1")
set_obj2.push("data2")

print "SET1",set_obj1.data
print "SET2",set_obj2.data
Here, we defined a custom event handle called MyHandle. I the run method doesn't actually do anything because I discovered the bug before I wrote any handling code. In the main program, we set the event manager to threaded mode. Next, we subscribe our custom event handle to the EventSetPush event. This means that every time Set.push() is invoked, so is MyHandle.run() (in a new thread since we are running in threaded mode here). We then create two set instances and push some data onto each set. Finally, we print the underlying Python lists associated with each set instance.

Here is my initial output.
SET1 ['data1', 'data2']
SET2 ['data1', 'data2']
Slightly different from what was expected. Each set instance should have had one element each. Instead, the lists look identical. Naturally, I assumed that they were the same list. This lead me to start examining the thread manager, thinking that since I was testing in threaded mode, there must be some sort of cross-thread data contamination. Thankfully, the problem got much simpler since I was able to eliminate this as a potential cause. Next in line, the event manager. I tried everything to try and prove that the Set instances were in fact the same instance. Not so. The instances had different memory addresses.

I then realized that Set inherits from Type but the constructor for type is not invoked. Odd. I tried to think of a reason why I would want to inherit something with no static functionality and not initialize it. I think I may have done this because the underlying list instances of Set objects are stored in an attribute called data. Type instances also define a data attribute. I must have thought, during the original implementation, that defining a data attribute for the Set class would have some adverse effect on the Type functionality. Not so. So now, the Type constructor is invoked but with no parameters. This means that the initial value of the Set.data attribute is actually an empty dictionary since this is what the Type constructor will initialize it as. The Set constructor will then initialize the data attribute to a list accordingly.

This however, wasn't the problem either. I was still getting the strange output that pointed so convincingly at the fact that the Set.data attribute was pointing to the same list instance. So, I took a look at the way in which the data attribute is initialized for Set instances. The Set constructor will accept a data keyword parameter. The default value of this parameter is an empty list. This parameter then becomes the Set.data attribute. Just for fun, I decided to take away this parameter and have the data attribute be initialized as an empty list inside the constructor.

Sure enough, that did it. I got the correct output for my two set instances. The data attribute must have been pointing to the same keyword parameter variable. I have a felling that this may be caused somewhere in the event manager. Or maybe not. I haven't tested this scenario outside the library yet.

I'm going to get this release out as soon as possible. The data keyword parameter for the Set constructor will be removed for now. As a side note, this will also affect the iteration functionality for Hash instances in the next release since the Hash.__iter__() method will return a SetIterator instance containing the hash keys. Each key will simply need to be pushed onto the set instead.

Wednesday, March 4, 2009

Using predicates with the boduch library

The boduch Python library has a new Predicate class that can be used to evaluate predicates. The Predicate class is meant to be an abstract super class. As of the 0.1.2 release of the library, there is only an Equal predicate. This predicate can be used to test the equality of two specified values. For example, consider the following.
#Example; Using the boduch.predicate.Equal predicate.

from boduch.predicate import Equal

if __name__=="__main__":
val1="My Value"
val2="My Value"
while Equal(val1, val2):
print "Changing val1 in order to exit our loop."
val1="Exit"
print val1
In this example, we define two string values; val1 and val2. We then use the Equal predicate as our loop condition. The Equal predicate will always evaluate to true as long as the two specified operators are equal. The Equal predicate uses the == Python operator to evaluate the result. So, why bother with the boduch predicates? One reason would be consistency if you are using the library elsewhere in the application. Another reason may be readability.

The Equal predicate is actually a Python class. Every time we instantiate Equal(), we are actually evaluating against an Equal instance. The equal predicate defines overloaded operators that handle the comparison when the instance is used in that context. There are also events and handles for predicates in the boduch library. If necessary, other handles may subscribe to these events. However, the events published by predicates in the boduch library are atomic. This means that no new threads will be started for these handles.

The next release of the library should have some more interesting predicates such as Greater and Less.

Thursday, February 12, 2009

boduch 0.1.1

The 0.1.1 version of the boduch Python library is now available. Some changes include:
  • New Set and Hash functionality. Both object types now support the Python key/index notation.
  • More unit tests.
Here is an example that demonstrates the new Set and Hash functionality.
#Example; boduch data types.

from boduch.data import Set, Hash
from boduch.event import threaded

def test_set_data():
set_obj=Set()
set_obj.push("test1")
set_obj.push("test2")
print "SET:",set_obj[0]
print "SET:",set_obj[1]
set_obj[0]="updated test1"
set_obj[1]="updated test2"
print "SET:",set_obj[0]
print "SET:",set_obj[1]
del set_obj[0]
del set_obj[0]

def test_hash_data():
hash_obj=Hash()
hash_obj.push(("test1", "value1"))
hash_obj.push(("test2", "value1"))
print "HASH:",hash_obj["test1"]
print "HASH:",hash_obj["test2"]
hash_obj["test1"]="updated value1"
hash_obj["test2"]="updated value2"
print "HASH:",hash_obj["test1"]
print "HASH:",hash_obj["test2"]
del hash_obj["test1"]
del hash_obj["test2"]

if __name__=="__main__":
test_set_data()
test_hash_data()
threaded(True)
test_set_data()
test_hash_data()
As you can see, we can now treat Set and Hash instances as though they were Python list and dictionary instances respectively. The main difference being of course, all actions are carried out by event handlers. This enables threaded behaviour for some of the actions. For example, pushing new items and updating existing items will be handled in separate threads if threading is enabled.

Monday, February 9, 2009

Testing types with boduch

The boduch Python library provides a simple type testing utility function that allows truth tests for both primitive and user-defined data types. Python does offer built-in type testing utilities, but there is currently no unification between user-defined classes and primitive types. Here is an example of how to use the is_type() function.
#boduch type testing example.

from boduch.type import is_type

class MyBaseType:
pass

class MyType(MyBaseType):
pass

if __name__=="__main__":
print "Testing string type."
print is_type("my string", "str")
print "Testing boolean type."
print is_type(False, "boolean")
print "Testing a class type."
print is_type(MyType(), "MyType")
print "Testing for a base class."
print is_type(MyType(), "MyBaseType")
As you can see, we can significantly cut down the number of lines required for type testing with a single function. Also note, is_type() can also test if the specified instance belongs in an inheritance lattice, as demonstrated in this example.

Sunday, February 1, 2009

boduch 0.1.0

The 0.1.0 release of the boduch Python library is now available. Changes:
  • Minor release.
  • Refactored the interface package.
  • More API documentation.

Monday, January 26, 2009

boduch 0.0.9

The 0.0.9 release of the boduch Python library is now available. Changes include:
  • Completely replaced the LockManager class. The locking primitives for exchanging data between event threads is now handled by the Python queue module.
  • Added a new atomic parameter to the EventManager.publish() method. This allows handles to be executed by the same thread that published the event. Event when the event manager is running in threaded mode.
  • Added a new max_threads attribute to the ThreadManager class. This is the maximum number of threads allowed to execute.

Friday, January 23, 2009

boduch 0.0.8

The 0.0.8 release of the boduch Python library is now available. Changes include:
  • Implemented a new ThreadManager. This takes the responsibility of starting new threads away from the EventManager.
  • Created a new data package in boduch.event for the Set and Hash events.
  • Created a new data package in boduch.handle for the Set and Hash handles.
  • Minor bug fixes.

Saturday, January 17, 2009

boduch 0.0.7

The 0.0.7 release of the boduch Python package is now available. Changes include:
  • Implemented a new LockManager class for locking in threaded event handles.
  • Made some enhancements to the is_type() utility function.
  • Created some new type constants.

Tuesday, January 13, 2009

boduch 0.0.6

The 0.0.6 version of the boduch Python package is now available. Changes include:
  • Fixed a major bug in EventManager.subscribe() that allowed the same handle for a single event to be subscribed more than once.
  • Type instances now have a uuid attribute which is generated by the constructor.
  • EventThread will now inherit from Type.
  • Improved the EventManager interface.
  • Improved the Event and Handle interfaces.
  • Implemented new Set and Hash event handles.

Friday, January 9, 2009

boduch 0.0.5

The 0.0.5 version of the boduch Python library is now available. This is a minor release:
  • Added more unit tests.
  • Added more API documentation.

Wednesday, January 7, 2009

Implementing a cache with the boduch Python library

I'm going to show a simple example of how to use the boduch.data.Set class to implement a caching. The Set class is nothing but a Python list that emits events. All we need to do is subscribe to the appropriate Set events.
#Using the boduch.data.Set class to implement a cache.

from boduch.data import Set
from boduch.event import subscribe, EventSetPush, EventSetGet
from boduch.handle import Handle

class HandleMySetPush(Handle):
def __init__(self, *args, **kw):
Handle.__init__(self, *args, **kw)

def run(self):
new_obj=self.data['event'].data['obj']
print 'Cache updated. Now updating DB with %s'%new_obj

class HandleMySetGet(Handle):
def __init__(self, *args, **kw):
Handle.__init__(self, *args, **kw)

def run(self):
index=self.data['event'].data['index']
set_obj=self.data['event'].data['set']
print 'Checking if %s is cached.'%index
try:
set_obj.data[index]
except IndexError:
print 'Not cached. Need to retrieve from DB.'

if __name__=="__main__":
subscribe(EventSetPush, HandleMySetPush)
subscribe(EventSetGet, HandleMySetGet)
set_obj=Set()
set_obj.push('Hello World!')
set_obj.get(0)
Here, we have created two event handles for our Set instance; HandleMySetPush and HandleMySetGet. Both event handles are invoked for the Set.push() and the Set.get() methods respectively.

In the main program, we create our Set instance and subscribe our new handles to two Set events.

The first handle, HandleMySetPush, is invoked after the actual Set instance is updated. This means that once the cache has been updated, we now have an opportunity to update a database with this new value. Updating the database is simply an example use of this handler. You could perform whatever action needed.

The second handle, HandleMySetGet, is invoked before the the actual Set instance is updated. This means that the handler can check if the requested object is cached. If not, it now has an opportunity to update the cache before the invokee can complain about a non-existent element.

Tuesday, January 6, 2009

boduch 0.0.4

The boduch 0.0.4 Python tool library has been released. Some of the changes are:
  • Fixed a minor bug in the ISet interface.
  • The new Hash data type with event emission has been implemented.
  • Implemented a new handle for EventSetPush events.

Monday, January 5, 2009

New in boduch 0.0.4

I thought I'd mention what is going on development-wise in the boduch Python library. The upcoming 0.0.4 release has a new handler for EventSetPush events. This handler is what actually pushes data onto the set instance that produces the event. Typically, there is no point. The push() method may as well be responsible for actually pushing the data onto the set instance.

There are cases where we may want to send the data being pushed somewhere remote in addition to the set. Also, when creating reactive interfaces that "sit on top of" the library, this could potentially increase the responsiveness.

There will also be a new Hash data type. This data type is essentially a Python dictionary that will emit events. It will follow a similar interface as that provided by the Set data type.

Saturday, January 3, 2009

boduch 0.0.3

A minor maintenance release of the boduch Python package has been released. Some of the changes include:
  • The event manager can now execute in non-threaded mode.
  • Made some improvements to the event manager interface.
  • Created a new constants package with some priority constants.