Ian Bicking: the old part of his blog

Sad conflicting packages

Sigh... I've decided that PyDispatcher is probably the right thing for SQLObject events -- I think it's a predictable and easy-to-understand package for this context, and I really prefer phrasing this in terms of events. But PyDispatcher conflicts with RuleDispatch, because they both use the package dispatch. Not a problem unless you want to use them both at once. Which is certain to happen, since TurboGears added the JSON code I mentioned (that uses RuleDispatch), and also uses SQLObject.

This is annoying. Maybe I'll think again about using RuleDispatch... but I feel unnecessarily forced into the decision.

Created 31 Oct '05

Comments:

Have you looked at FibraNet?

It is much simpler than PyDispatcher, and may suit your needs better.

# anonymous

PyDispatcher isn't that complicated, really. Not very complicated at all, at least when I consider what I want to do with it. And it seems better documented than FibraNet.

# Ian Bicking

I agree with the general lament: that an unambiguous namespace means having to deal with packages that have the same name.

You can, of course, get around that in any specific code with import foo as bar.

In this specific case, though, should the JSON code just be reimplemented using PyDispatcher? I must admit to sharing your preference for the simple, hugely flexible PyDispatcher.

# Ben Finney

I may be a little naive about event dispatching mechanisms, but when it comes to simplicity, how simple can they get, and exactly what flexibility is required?

I've used FibraNet (back when it was just called 'EventNet'), the event/signal mechanism in PGU, and PyDispatcher. From my experience, EventNet was the most simple. One line to post an event:

eventnet.driver.post('my_event', arg1=something, arg2=something_else)

and one line to register a callable to receive an event:

@eventnet.driver.subscribe('my_event')

def my_event_handler(event): print event.name, event.arg1, event.arg2

EventNet does force you to keep track of references, and explicitly unsubscribe event handlers, as it does not use weak references. This can result in some extra code.

I've found writing code like this can be either very elegant, or very confusing. This situation gets amplified (for better or worse) once you start using the eventnet.net module, which works well for simple IPC, though I do not know how safe it is.

I am curious, how exactly are you planning to use an event dispatcher in SQLObject, and what problems will it help solve?

# anonymous

How is this simpler:

eventnet.driver.post('my_event', arg1=something, arg2=something_else)

Than this:

dispatcher.send('my_event', arg1=something, arg2=something_else)

Or listening with:

dispatcher.connect(my_event_handler, 'my_event')

It's not a decorator, but that would be very easy to implement. PyDispatcher also has has the concept of "sender", which I find useful, as I'm actually expecting to listen to events on a per-class basis (and SQLObject classes are the senders).

The events I'm proposing are listed in sqlobject.events in the repository -- it could quickly become a core part of how basic concepts like joins and columns are implemented. E.g., a column with a cascade=True setting would listen for a delete event.

# Ian Bicking

PyDispatcher doesn't really apply to the JSON code, so that's not an option. The name conflict doesn't help, because you simply can't have two distributions loaded with the same top-level name (except maybe with the technique PJE mentioned, though that requires repackaging the libraries, at which point I could just rename the package).

# Ian Bicking

Well, I was suggesting that if enough people asked for it, then the authors of the respective packages (i.e., me and Patrick O'Brien) would probably be willing to include that code for compatibility's sake.

# Phillip J. Eby

Patrick doesn't do much with PyDispatcher these days AFAIK, but I'd certainly be willing to incorporate changes that would let the two packages coexist. Heck, if I recall correctly from our earlier discussion the two packages can actually be dumped into the same directory and both continue to function as expected.

# Mike Fletcher

Hmm, should have finished reading the whole comment thread. Apparently Patrick is all over it :) .


I'm more than happy to defer to you, Mike, since you've been shepherding the code for some time now. I appreciate all the work you've done to make the code available, fix bugs, add enhancements, etc.


You know, you could package one or the other so it's a namespace package, as long as there aren't any conflicting names within the two dispatch packages. Just add something like:

try:
    from pkg_resources import declare_namespace
except ImportError:
    pass
else:
    declare_namespace(__name__)

to the end of both dispatch/__init__.py files. The only downside is that it forces both packages' __init__ modules to be loaded when you import dispatch.

# Phillip J. Eby

I agree, this situation is unfortunate. I would gladly support any solution that will make it easier for people to use both packages. In the mean time, what we have done with Schevo is simply included pydispatcher as a subpackage of schevo. Call it a fork, if you will. Then we use it like this:

from schevo.dispatcher import dispatcher
from schevo.dispatcher.errors import DispatcherKeyError

I don't think this is the ideal solution. And certainly Eggs makes dependency management much more palatable than it used to be, so someone may come up with something better. But if a simple solution isn't forthcoming, then sometimes you just do what you gotta do. You would not offend me in the slightest if you took the same approach with SQLObject. :-)

# Patrick K. O'Brien

Yeah, I'm thinking about doing that as well. I could repackage it as pydispatcher, but that makes the installation harder to handle, because I'd have to give that new package a name, and people couldn't install strictly from PyPI if they were using easy_install (unless I registered it, which I don't want to do... unless maybe it was a hidden registration, which might actually work...)

# Ian Bicking

# mymodule

import sys

# manipulate sys.path, to be sure you get the right dispatch

import dispatch as d

del sys.modules['dispatch']

# now refer to this dispatch in your code only as mymodule.d

import dispatch

# second dispatch

# But yes, this namespace handling sucks :)

# Andreas Kostyrka