~ubuntu-branches/ubuntu/wily/grass/wily

« back to all changes in this revision

Viewing changes to .pc/allows-to-typo.patch/lib/python/pydispatch/signal.py

Tags: 7.0.0~rc1+ds1-1~exp1
* New upstream release candidate.
* Repack upstream tarball, remove precompiled Python objects.
* Add upstream metadata.
* Update gbp.conf and Vcs-Git URL to use the experimental branch.
* Update watch file for GRASS 7.0.
* Drop build dependencies for Tcl/Tk, add build dependencies:
  python-numpy, libnetcdf-dev, netcdf-bin, libblas-dev, liblapack-dev
* Update Vcs-Browser URL to use cgit instead of gitweb.
* Update paths to use grass70.
* Add configure options: --with-netcdf, --with-blas, --with-lapack,
  remove --with-tcltk-includes.
* Update patches for GRASS 7.
* Update copyright file, changes:
  - Update copyright years
  - Group files by license
  - Remove unused license sections
* Add patches for various typos.
* Fix desktop file with patch instead of d/rules.
* Use minimal dh rules.
* Bump Standards-Version to 3.9.6, no changes.
* Use dpkg-maintscript-helper to replace directories with symlinks.
  (closes: #776349)
* Update my email to use @debian.org address.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# -*- coding: utf-8 -*-
 
2
"""
 
3
Created on Mon Mar 11 18:39:13 2013
 
4
 
 
5
@author Vaclav Petras <wenzeslaus gmail.com>
 
6
"""
 
7
 
 
8
 
 
9
from grass.pydispatch import dispatcher
 
10
 
 
11
 
 
12
def _islambda(function):
 
13
    """
 
14
    Tests if object is a lambda function.
 
15
 
 
16
    Should work on the most of Python implementations where name of lambda
 
17
    function is not unique.
 
18
 
 
19
    >>> mylambda = lambda x: x*x
 
20
    >>> _islambda(mylambda)
 
21
    True
 
22
    >>> _islambda(_islambda)
 
23
    False
 
24
    """
 
25
    return isinstance(function, type(lambda: None)) and function.__name__== (lambda: None).__name__
 
26
 
 
27
 
 
28
class Signal(object):
 
29
    """
 
30
 
 
31
    The signal object is created usually as a instance attribute.
 
32
    However, it can be created anywhere.
 
33
 
 
34
    >>> signal1 = Signal('signal1')
 
35
 
 
36
    The function has to be connected to a signal in order to be called when
 
37
    the signal is emitted. The connection can be done where the function is
 
38
    defined (e. g., a class) but also on some other place, typically,
 
39
    user of a class connects some signal to the method of some other class.
 
40
 
 
41
    >>> def handler1():
 
42
    ...     print "from handler1"
 
43
    >>> signal1.connect(handler1)
 
44
 
 
45
    Emitting of the signal is done usually only in the class which has the
 
46
    signal as a instance attribute. Again, generally, it can be emitted
 
47
    anywhere.
 
48
 
 
49
    >>> signal1.emit()
 
50
    from handler1
 
51
 
 
52
    The signal can have parameters. These parameters are specified when
 
53
    emitting but should be documented together with the signal (e.g., in the
 
54
    class documentation). Parameters should be keyword arguments and handlers
 
55
    must use these names (if the names cannot be the same, lambda function
 
56
    can be used to overcome this problem).
 
57
 
 
58
    >>> signal2 = Signal('signal2')
 
59
    >>> def handler2(text):
 
60
    ...     print "handler2: %s" % text
 
61
    >>> signal2.connect(handler2)
 
62
    >>> signal2.emit(text="Hello")
 
63
    handler2: Hello
 
64
 
 
65
    Do not emit the same signal with different parameters when emitting at
 
66
    different places.
 
67
 
 
68
    A handler is the standard function, lambda function, method or any other
 
69
    callable object.
 
70
 
 
71
    >>> import sys
 
72
    >>> signal2.connect(lambda text:
 
73
    ...                 sys.stdout.write('lambda handler: %s\\n' % text))
 
74
    >>> signal2.emit(text="Hi")
 
75
    handler2: Hi
 
76
    lambda handler: Hi
 
77
 
 
78
    The handler function can have only some of the signal parameters or no
 
79
    parameters at all even if the signal has some.
 
80
 
 
81
    >>> def handler3():
 
82
    ...     print "from handler3"
 
83
    >>> signal2.connect(handler3)
 
84
    >>> signal2.emit(text="Ciao")
 
85
    handler2: Ciao
 
86
    lambda handler: Ciao
 
87
    from handler3
 
88
 
 
89
    It is possible to use signal as a handler. By this, signals can be
 
90
    forwarded from one object to another. In other words, one object can
 
91
    expose signal of some object.
 
92
 
 
93
    >>> signal3 = Signal('signal3')
 
94
    >>> signal3.connect(handler3)
 
95
    >>> signal1.connect(signal3)
 
96
    >>> signal1.emit()
 
97
    from handler1
 
98
    from handler3
 
99
 
 
100
    It is possible to disconnect a particular handler.
 
101
 
 
102
    >>> signal3.disconnect(handler3)
 
103
    >>> signal1.emit()
 
104
    from handler1
 
105
    >>> signal2.disconnect(handler2)
 
106
    >>> signal2.disconnect(handler3)
 
107
    >>> signal2.emit(text='Hello')
 
108
    lambda handler: Hello
 
109
    """
 
110
    # TODO: use the name for debugging
 
111
    def __init__(self, name):
 
112
        """Creates a signal object.
 
113
 
 
114
        The parameter name is used for debugging.
 
115
        """
 
116
        self._name = name
 
117
 
 
118
    def connect(self, handler, weak=None):
 
119
        """
 
120
        Connects handler to a signal.
 
121
 
 
122
        Typically, a signal is defined in some class and the user of this
 
123
        class connects to the signal::
 
124
 
 
125
            from module import SomeClass
 
126
            ...
 
127
            self.someObject = SomeClass()
 
128
            self.someObject.connect(self.someMethod)
 
129
 
 
130
        Usually, it is not needed to set the weak parameter. This method
 
131
        creates weak references for all handlers but for lambda functions, it
 
132
        automaticaly creates (standard) references (otherwise, lambdas would be
 
133
        garbage collected. If you want to force some behaviour, specify the
 
134
        weak parameter.
 
135
 
 
136
        >>> signal1 = Signal('signal1')
 
137
        >>> import sys
 
138
        >>> signal1.connect(lambda: sys.stdout.write('will print\\n'))
 
139
        >>> signal1.connect(lambda: sys.stdout.write('will print\\n'), weak=False)
 
140
        >>> signal1.connect(lambda: sys.stdout.write('will not print'), weak=True)
 
141
        >>> signal1.emit()
 
142
        will print
 
143
        will print
 
144
        """
 
145
        if weak is None:
 
146
            if _islambda(handler):
 
147
                weak = False
 
148
            else:
 
149
                weak = True
 
150
        dispatcher.connect(receiver=handler, signal=self, weak=weak)
 
151
 
 
152
    def disconnect(self, handler, weak=True):
 
153
        """
 
154
        Disconnects a specified handler.
 
155
 
 
156
        It is not necessary to disconnect object when it is deleted.
 
157
        Underlying PyDispatcher will take care of connections to deleted
 
158
        objects.
 
159
 
 
160
        >>> signal1 = Signal('signal1')
 
161
        >>> import sys
 
162
        >>> signal1.connect(sys.stdout.write)
 
163
        >>> signal1.disconnect(sys.stdout.write)
 
164
 
 
165
        The weak parameter of must have the same value as for connection.
 
166
        If you not specified the parameter when connecting,
 
167
        you don't have to specify it when disconnecting.
 
168
 
 
169
        Disconnecting the not-connected handler will result in error.
 
170
 
 
171
        >>> signal1.disconnect(sys.stdout.flush)  #doctest: +ELLIPSIS
 
172
        Traceback (most recent call last):
 
173
        DispatcherKeyError: 'No receivers found for signal <__main__.Signal object at 0x...> from sender _Any'
 
174
 
 
175
        Disconnecting the non-exiting or unknown handler will result in error.
 
176
 
 
177
        >>> signal1.disconnect(some_function)
 
178
        Traceback (most recent call last):
 
179
        NameError: name 'some_function' is not defined
 
180
        >>> signal1.emit()
 
181
        """
 
182
        dispatcher.disconnect(receiver=handler, signal=self, weak=weak)
 
183
 
 
184
    # TODO: remove args?, make it work for args?
 
185
    # TODO: where to put documentation
 
186
    def emit(self, *args, **kwargs):
 
187
        """
 
188
        Emits the signal which means that all connected handlers will be
 
189
        called.
 
190
 
 
191
        It is advised to have signals as instance attributes and emit signals
 
192
        only in the class which owns the signal::
 
193
 
 
194
            class Abc(object):
 
195
                def __init__(self):
 
196
                    self.colorChanged = Signal('Abc.colorChanged')
 
197
                    ...
 
198
                def setColor(self, color):
 
199
                    ...
 
200
                    self.colorChanged.emit(oldColor=self.Color, newColor=color)
 
201
                    ...
 
202
 
 
203
        Documentation of an signal should be placed to the class documentation
 
204
        or to the code (this need to be more specified).
 
205
 
 
206
        Calling a signal from outside the class is usually not good
 
207
        practice. The only case when it is permitted is when signal is the part
 
208
        of some globaly shared object and permision to emit is stayed in the
 
209
        documentation.
 
210
 
 
211
        The parameters of the emit function must be the same as the parameters
 
212
        of the handlers. However, handler can ommit some parameters.
 
213
        The associated parameters shall be documented for each Signal instance.
 
214
        Use only keyword arguments when emitting.
 
215
 
 
216
        >>> signal1 = Signal('signal1')
 
217
        >>> def mywrite(text):
 
218
        ...     print text
 
219
        >>> signal1.connect(mywrite)
 
220
        >>> signal1.emit(text='Hello')
 
221
        Hello
 
222
        >>> signal1.emit()
 
223
        Traceback (most recent call last):
 
224
        TypeError: mywrite() takes exactly 1 argument (0 given)
 
225
        >>> signal1.emit('Hello')
 
226
        Traceback (most recent call last):
 
227
        TypeError: send() got multiple values for keyword argument 'signal'
 
228
        """
 
229
        dispatcher.send(signal=self, *args, **kwargs)
 
230
 
 
231
    # TODO: remove args?
 
232
    def __call__(self, *args, **kwargs):
 
233
        """Allows to emit signal with function call syntax.
 
234
 
 
235
        It allows to handle signal as a function or other callable object.
 
236
        So, the signal can be in the list of fuctions or can be connected as
 
237
        a handler for another signal.
 
238
        However, it is strongly recommended to use emit method for direct
 
239
        signal emitting.
 
240
        The use of emit method is more explicit than the function call
 
241
        and thus it it clear that we are using signal.
 
242
 
 
243
        >>> signal1 = Signal('signal1')
 
244
        >>> def mywrite(text):
 
245
        ...     print text
 
246
        >>> signal1.connect(mywrite)
 
247
        >>> functions = [signal1, lambda text: mywrite(text + '!')]
 
248
        >>> for function in functions:
 
249
        ...     function(text='text')
 
250
        text
 
251
        text!
 
252
 
 
253
        The other reason why the function call should not by used when it is
 
254
        possible to use emit method is that this function does ugly hack to
 
255
        enable calling as a signal handler. The signal parameter is deleted
 
256
        when it is in named keyword arguments. As a consequence, when the
 
257
        signal is emitted with the signal parameter (which is a very bad
 
258
        name for parameter when using signals), the error is much more readable
 
259
        when using emit than function call. Concluding remark is that
 
260
        emit behaves more predictable.
 
261
 
 
262
        >>> signal1.emit(signal='Hello')
 
263
        Traceback (most recent call last):
 
264
        TypeError: send() got multiple values for keyword argument 'signal'
 
265
        >>> signal1(signal='Hello')
 
266
        Traceback (most recent call last):
 
267
        TypeError: mywrite() takes exactly 1 argument (0 given)
 
268
        """
 
269
        if 'signal' in kwargs:
 
270
            del kwargs['signal']
 
271
        self.emit(*args, **kwargs)
 
272
 
 
273
 
 
274
if __name__ == '__main__':
 
275
    import doctest
 
276
    doctest.testmod()