I'm interested in a generic event system for Python. I've searched the forum for similar topics, and I've searched the web for existing implementations. I haven't found exactly what I'm looking for.

I'm familiar with the Observer pattern. However, my implementation and other implementations lack strong support for concurrency and scheduling.

Do you know of anything that fits the bill or can you help me create an implementation?

I want to use this for simulations and games.

Recommended Answers

All 6 Replies

I know a very simple system called py-notify. See here http://home.gna.org/py-notify. It define 'signals' emitted by your code, which can be 'connected' to callback functions.

I've downloaded it, and I'm attempting to understand the source.

I wrote my own naive event loop, but I'm getting a maximum recursion depth exceeded RuntimeError.

##The MIT License
##
##Copyright (c) 2011 Larry Haskins
##
##Permission is hereby granted, free of charge, to any person obtaining a copy
##of this software and associated documentation files (the "Software"), to deal
##in the Software without restriction, including without limitation the rights
##to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
##copies of the Software, and to permit persons to whom the Software is
##furnished to do so, subject to the following conditions:
##
##The above copyright notice and this permission notice shall be included in
##all copies or substantial portions of the Software.
##
##THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
##IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
##FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
##AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
##LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
##OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
##THE SOFTWARE.

import collections
import heapq
import random
import time

__all__ = ['InstantNotification',
           'Notification',
           'InstantMessage',
           'Message'
           'Dispatcher']

class InstantNotification:

    __slots__ = ('type', 'sender', 'receivers')

    def __init__(self,
                 type,
                 sender=None,
                 receivers=None):
        self.type = type
        self.sender = sender
        self.receivers = receivers

class Notification(InstantNotification):

    __slots__ = ('delay')

    def __lt__(self, other):
        return self.delay < other.delay

class InstantMessage(InstantNotification):

    __slots__ = ('data')

    def __init__(self,
                 type,
                 data,
                 sender=None,
                 receivers=None):
        self.data = data
        super().__init__(type, sender, receivers)

class Message(InstantMessage):

    __slots__ = ('delay')

    def __lt__(self, other):
        return self.delay < other.delay

class Dispatcher:

    __slots__ = ('types', 'items')

    def __init__(self):
        self.types = collections.defaultdict(dict)
        self.items = list()

    def receive(self, item, delay):
        item.delay = delay
        heapq.heappush(self.items, item)

    def deliver(self, item):
        potential_receivers = self.types[item.type]
        receivers = item.receivers
        if receivers:
            for receiver in receivers:
                potential_receivers[receiver](item)
        else:
            for receiver in potential_receivers.values():
                receiver(item)

    def register(self, type, receiver, callback):
        self.types[type][receiver] = callback

    def unregister(self, type, key):
        del self.types[type][receiver]

    def update(self, decrement):
        while True:
            item = heapqueue.heappop(self.items)
            item.delay -= decrement
            if item.delay <= 0:
                self.dispatch(item)
            else:
                for item in self.items:
                    item.delay -= decrement
                break

if __name__ == '__main__':

    DISPATCHER = Dispatcher()

    class LightSwitch:

        def __init__(self):
            self.state = True
            self.switch()

        def switch(self):
            self.state = not self.state
            DISPATCHER.deliver(InstantMessage(LightSwitch, {'state': self.state}, self))

    class Waster:

        def __init__(self):
            DISPATCHER.register(LightSwitch, self, self.on_LightSwitch)

        #These make recursion errors!
        def on_LightSwitch(self, message):
            if not message.data['state']:
                if not message.sender.state:
                    print('Shiny lights are on at {t}!'.format(t=time.clock()))
                    message.sender.switch()

    class Saver:

        def __init__(self):
            DISPATCHER.register(LightSwitch, self, self.on_LightSwitch)

        def on_LightSwitch(self, message):
            if message.data['state']:
                if message.sender.state:
                    print("Keep those dang lights out! It's {t}!".format(t=time.clock()))
                    message.sender.switch()

    waster = Waster()
    saver = Saver()
    light_switch = LightSwitch()

What module is generating the error? Once you know that then you know to change that module to not be recursive if it is exceeding the limit.

The one I wrote. I'd have to take the time to discern the pattern in the traceback or limit the recursion limit. Otherwise there are just too many lines in the traceback.

Indeed you will have to trace it back because it's not generating it in that module.

I ended up checking out Panda3D's task and event system. Thanks for the replies.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.