~certify-web-dev/twisted/certify-trunk

« back to all changes in this revision

Viewing changes to twisted/xish/utility.py

  • Committer: Bazaar Package Importer
  • Author(s): Matthias Klose
  • Date: 2004-06-21 22:01:11 UTC
  • mto: (2.2.3 sid)
  • mto: This revision was merged to the branch mainline in revision 3.
  • Revision ID: james.westby@ubuntu.com-20040621220111-vkf909euqnyrp3nr
Tags: upstream-1.3.0
ImportĀ upstreamĀ versionĀ 1.3.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# -*- test-case-name: twisted.test.test_xishutil -*-
 
2
#
 
3
# Twisted, the Framework of Your Internet
 
4
# Copyright (C) 2001 Matthew W. Lefkowitz
 
5
 
6
# This library is free software; you can redistribute it and/or
 
7
# modify it under the terms of version 2.1 of the GNU Lesser General Public
 
8
# License as published by the Free Software Foundation.
 
9
 
10
# This library is distributed in the hope that it will be useful,
 
11
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
12
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
13
# Lesser General Public License for more details.
 
14
 
15
# You should have received a copy of the GNU Lesser General Public
 
16
# License along with this library; if not, write to the Free Software
 
17
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
18
 
 
19
def _isStr(s):
 
20
    """Internal method to determine if an object is a string """
 
21
    return isinstance(s, type('')) or isinstance(s, type(u''))
 
22
 
 
23
class _MethodWrapper(object):
 
24
    """Internal class for tracking method calls """
 
25
    def __init__(self, method, *args, **kwargs):
 
26
        self.method = method
 
27
        self.args = args
 
28
        self.kwargs = kwargs
 
29
 
 
30
    def __call__(self, *args, **kwargs):
 
31
        nargs = self.args + args
 
32
        nkwargs = self.kwargs.copy()
 
33
        nkwargs.update(kwargs)
 
34
        self.method(*nargs, **nkwargs)        
 
35
 
 
36
class CallbackList:
 
37
    def __init__(self):
 
38
        self.callbacks = {}
 
39
 
 
40
    def addCallback(self, onetime, method, *args, **kwargs):
 
41
        if not method in self.callbacks:
 
42
            self.callbacks[method] = (_MethodWrapper(method, *args, **kwargs), onetime)
 
43
 
 
44
    def removeCallback(self, method):
 
45
        if method in self.callbacks:
 
46
            del self.callbacks[method]
 
47
 
 
48
    def callback(self, *args, **kwargs):
 
49
        for key, (methodwrapper, onetime) in self.callbacks.items():
 
50
            methodwrapper(*args, **kwargs)
 
51
            if onetime:
 
52
                del self.callbacks[key]
 
53
 
 
54
from twisted.xish import xpath
 
55
 
 
56
class EventDispatcher:
 
57
    def __init__(self, eventprefix = "//event/"):
 
58
        self.prefix = eventprefix
 
59
        self._eventObservers = {}
 
60
        self._xpathObservers = {}
 
61
        self._dispatchDepth = 0  # Flag indicating levels of dispatching in progress
 
62
        self._updateQueue = [] # Queued updates for observer ops
 
63
 
 
64
    def _isEvent(self, event):
 
65
        return _isStr(event) and self.prefix == event[0:len(self.prefix)]
 
66
 
 
67
    def addOnetimeObserver(self, event, observerfn, *args, **kwargs):
 
68
        self._addObserver(True, event, observerfn, *args, **kwargs)
 
69
 
 
70
    def addObserver(self, event, observerfn, *args, **kwargs):
 
71
        self._addObserver(False, event, observerfn, *args, **kwargs)
 
72
 
 
73
    # AddObserver takes several different types of arguments
 
74
    # - xpath (string or object form)
 
75
    # - event designator (string that starts with a known prefix)
 
76
    def _addObserver(self, onetime, event, observerfn, *args, **kwargs):
 
77
        # If this is happening in the middle of the dispatch, queue
 
78
        # it up for processing after the dispatch completes
 
79
        if self._dispatchDepth > 0:
 
80
            self._updateQueue.append(lambda:self.addObserver(event, observerfn, *args, **kwargs))
 
81
            return
 
82
 
 
83
        observers = None
 
84
 
 
85
        if _isStr(event):
 
86
            if self.prefix == event[0:len(self.prefix)]:
 
87
                # Treat as event
 
88
                observers = self._eventObservers
 
89
            else:
 
90
                # Treat as xpath
 
91
                event = xpath.intern(event)
 
92
                observers = self._xpathObservers
 
93
        else:
 
94
            # Treat as xpath
 
95
            observers = self._xpathObservers
 
96
 
 
97
        if not event in observers:
 
98
            cbl = CallbackList()
 
99
            cbl.addCallback(onetime, observerfn, *args, **kwargs)
 
100
            observers[event] = cbl
 
101
        else:
 
102
            observers[event].addCallback(onetime, observerfn, *args, **kwargs)
 
103
 
 
104
 
 
105
    def removeObserver(self, event, observerfn):
 
106
        # If this is happening in the middle of the dispatch, queue
 
107
        # it up for processing after the dispatch completes
 
108
        if self._dispatchDepth > 0:
 
109
            self._updateQueue.append(lambda:self.removeObserver(event, observerfn))
 
110
            return
 
111
 
 
112
        observers = None
 
113
 
 
114
        if _isStr(event):
 
115
            if self.prefix == event[0:len(self.prefix)]:
 
116
                observers = self._eventObservers
 
117
            else:
 
118
                event = xpath.intern(event)
 
119
                observers = self._xpathObservers
 
120
        else:
 
121
            observers = self._xpathObservers
 
122
 
 
123
        assert event in observers
 
124
        observers[event].removeCallback(observerfn)
 
125
 
 
126
 
 
127
    def dispatch(self, object, event = None):
 
128
        # Aiyiyi! If this dispatch occurs within a dispatch
 
129
        # we need to preserve the original dispatching flag
 
130
        # and not mess up the updateQueue
 
131
        self._dispatchDepth = self._dispatchDepth + 1
 
132
            
 
133
        if event != None:
 
134
            if event in self._eventObservers:
 
135
                self._eventObservers[event].callback(object)
 
136
        else:
 
137
            for (query, callbacklist) in self._xpathObservers.iteritems():
 
138
                if query.matches(object):
 
139
                    callbacklist.callback(object)
 
140
 
 
141
        self._dispatchDepth = self._dispatchDepth -1
 
142
 
 
143
        # If this is a dispatch within a dispatch, don't
 
144
        # do anything with the updateQueue -- it needs to
 
145
        # wait until we've back all the way out of the stack
 
146
        if self._dispatchDepth == 0:
 
147
            # Deal with pending update operations
 
148
            for f in self._updateQueue:
 
149
                f()
 
150
            self._updateQueue = []
 
151