[Zope-CVS] CVS: Packages/pypes/pypes - event.py:1.5
Casey Duncan
casey at zope.com
Wed Mar 3 23:29:47 EST 2004
Update of /cvs-repository/Packages/pypes/pypes
In directory cvs.zope.org:/tmp/cvs-serv12779
Modified Files:
event.py
Log Message:
Use persistent weakrefs for event listener registrations
Add event service persistence tests
=== Packages/pypes/pypes/event.py 1.4 => 1.5 ===
--- Packages/pypes/pypes/event.py:1.4 Sun Feb 8 22:56:21 2004
+++ Packages/pypes/pypes/event.py Wed Mar 3 23:29:45 2004
@@ -17,9 +17,10 @@
from __future__ import generators
import cPickle
-from types import TypeType, ClassType
+from types import ClassType
from BTrees.OOBTree import OOBTree, OOTreeSet
from persistent import Persistent
+from persistent.wref import WeakRef
from zope.interface import implements
from pypes.interfaces import IEventService
from pypes.exceptions import EventRegistrationError
@@ -32,7 +33,10 @@
class EventService(Persistent):
"""Persistent event service
- Note: event message types registered must be pickleable
+ - Event message types must be types or classes
+
+ - Listeners are referenced using persistent weakrefs. This means that
+ all registered listeners must be Persistent instances.
"""
implements(IEventService)
@@ -43,12 +47,14 @@
def registerListener(self, obj, method_name, message_type):
method = getattr(obj, method_name)
+ if not isinstance(obj, Persistent):
+ raise TypeError, 'Event listener not persistent'
if not callable(method):
raise TypeError, 'Event listener method registered is not callable'
- if not isinstance(message_type, (TypeType, ClassType)):
+ if not isinstance(message_type, (type, ClassType)):
raise TypeError, 'Event listener message_type must be type or class'
type_key = _msgTypeKey(message_type)
- pair = (obj, method_name)
+ pair = (WeakRef(obj), method_name)
try:
reglist = self._listeners[type_key]
except KeyError:
@@ -62,7 +68,7 @@
type_key = _msgTypeKey(message_type)
try:
listeners = self._listeners[type_key]
- listeners.remove((obj, method_name))
+ listeners.remove((WeakRef(obj), method_name))
except (KeyError, ValueError):
raise EventRegistrationError, (obj, method_name, message_type)
else:
@@ -90,23 +96,23 @@
def isListener(self, obj, message_type):
try:
- listeners = self._listeners[_msgTypeKey(message_type)]
+ reglist = self._listeners[_msgTypeKey(message_type)]
except KeyError:
return False
else:
- for listener, name in listeners:
- if listener is obj:
+ for listener, name in self._iterRegistrations(reglist):
+ if obj is listener:
return True
return False
def wouldReceive(self, obj, message_type):
for super_type in _mro(message_type):
try:
- listeners = self._listeners[_msgTypeKey(super_type)]
+ reglist = self._listeners[_msgTypeKey(super_type)]
except KeyError:
continue
- for listener, name in listeners:
- if listener is obj:
+ for listener, name in self._iterRegistrations(reglist):
+ if obj is listener:
return True
return False
@@ -116,7 +122,13 @@
except KeyError:
# Nothing is registered for this type
return iter(())
- return iter(reglist)
+ return self._iterRegistrations(reglist)
+
+ def _iterRegistrations(self, reglist):
+ for listener, name in reglist:
+ listener = listener()
+ if listener is not None:
+ yield listener, name
def iterReceivers(self, message_type):
rlists = []
@@ -129,7 +141,7 @@
# Optimize for the case where only one type has registrants
# We don't need to enforce uniqueness in this case the
# list is already unique
- return iter(rlists[0])
+ return self._iterRegistrations(rlists[0])
elif rlists:
return self._iterReceiversLists(rlists)
else:
@@ -138,16 +150,22 @@
def _iterReceiversLists(self, rlists):
# Iterate the receivers for each lists in turn,
# making sure each (obj, name) pair is only returned once
- seenpairs = {}
+ seen = {}
for receivers in rlists:
- for pair in receivers:
- if not seenpairs.has_key(pair):
- seenpairs[pair] = None
+ for listener, name in receivers:
+ listener = listener()
+ pair = (listener, name)
+ if listener is not None and pair not in seen:
+ seen[pair] = True
yield pair
def iterMessageTypes(self):
for typekey in self._listeners.keys():
yield _msgTypeFromKey(typekey)
+
+ # XXX Need to add mechanism to clean stale listener references
+ # perhaps this should be opportunistic as part of registerListener
+ # or a separate method or both
def _mro(typeobj):
"""Calculate and return the method resolution order. Works for
More information about the Zope-CVS
mailing list