This file is indexed.

/usr/share/pyshared/gtkmvc/observer.py is in python-gtkmvc 1.99.1-1build1.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
#  -------------------------------------------------------------------------
#  Author: Roberto Cavada <roboogle@gmail.com>
#
#  Copyright (C) 2006 by Roberto Cavada
#
#  pygtkmvc is free software; you can redistribute it and/or
#  modify it under the terms of the GNU Lesser General Public
#  License as published by the Free Software Foundation; either
#  version 2 of the License, or (at your option) any later version.
#
#  pygtkmvc is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
#  Lesser General Public License for more details.
#
#  You should have received a copy of the GNU Lesser General Public
#  License along with this library; if not, write to the Free Software
#  Foundation, Inc., 51 Franklin Street, Fifth Floor,
#  Boston, MA 02110, USA.
#
#  For more information on pygtkmvc see <http://pygtkmvc.sourceforge.net>
#  or email to the author Roberto Cavada <roboogle@gmail.com>.
#  Please report bugs to <roboogle@gmail.com>.
#  -------------------------------------------------------------------------

from support import decorators, utils, log

import inspect
import types
import collections


class NTInfo (dict):
    """
    A container for information attached to a notification.
    This class is a dictionary-like object used:

    1. As class when defining notification methods in observers, as it
       contains the flags identifying the notification types.

    2. As class instance as parameter when a notification methods is
       called in observers.


    **Notification Type Flags**
    
    Notification methods are declared either statically or dynamically 
    through :meth:`Observer.observe`. In both cases the type of the
    notification is defined by setting to `True` some flags. Flags can
    be set in any combination for multi-type notification
    methods. Flags are:

    assign
       For notifications issued when OPs are assigned.
    before
       For notifications called before a modifying method is called.
    after
       For notifications called after a modifying method is called.
    signal
       For notifications called when a signal is emitted.

    
    **Instance content**

    Instances of class `NTInfo` will be received as the last argument
    (`info`) of any notification method::

      def notification_method(self, model, name, info)

    NTInfo is a dictionary (with some particular behaviour added)
    containing some information which is independent on the
    notification type, and some other information wich depends on the
    notification type.


    **Common to all types**

    For all notification types, NTInfo contains:

    model
       the model containing the observable property triggering the
       notification. `model` is also passed as first argument of the
       notification method.

    prop_name
       the name of the observable property triggering the notification. `name`
       is also passed as second argument of the notification method.
      
    Furthermore, any keyword argument not listed here is copied
    without modification into `info`.

    There are further information depending on the specific
    notification type:

    **For Assign-type**

    assign
       flag set to `True`

    old
       the value that the observable property had before being
       changed.

    new
       the new value that the observable property has been
       changed to.


    **For Before method call type**

    before
       flag set to `True`

    instance
       the object instance which the method that is being called belongs to.

    method_name
       the name of the method that is being called. 

    args
       tuple of the arguments of the method that is being called. 

    kwargs
       dictionary of the keyword arguments of the method that
       is being called.


    **For After method call type**

    after
       flag set to `True`

    instance
       the object instance which the method that has been 
       called belongs to.

    method_name
       the name of the method that has been called. 

    args
       tuple of the arguments of the method that has been called. 

    kwargs
       dictionary of the keyword arguments of the method that
       has been called.

    result
       the value returned by the method which has been called. 

    **For Signal-type**

    signal
       flag set to `True`

    arg
       the argument which was optionally specified when invoking
       emit() on the signal observable property.

    **Information access**

    The information carried by a NTInfo instance passed to a
    notification method can be retrieved using the instance as a
    dictionary, or accessing directly to the information as an
    attribute of the instance. For example::
       
       # This is a multi-type notification
       @Observer.observe("op1", assign=True, hello="Ciao")
       @Observer.observe("op2", after=True, before=True)
       def notify_me(self, model, name, info):
           assert info["model"] == model # access as dict key
           assert info.prop_name == name # access as attribute

           if "assign" in info:
              assert info.old == info["old"]
              assert "hello" in info and "ciao" == info.hello
              print "Assign from", info.old, "to", info.new
           else:
              assert "before" in info or "after" in info
              assert "hello" not in info
              print "Method name=", info.method_name
              if "after" in info: print "Method returned", info.result    
              pass
              
           return   

    As already told, the type carried by a NTInfo instance can be
    accessed through boolean flags `assign`, `before`, `after` and
    `signal`. Furthermore, any other information specified at
    declaration time (keyword argument 'hello' in the previous
    example) will be accessible in the corresponding notification
    method.

    .. versionadded:: 1.99.1

    """

    # At least one of the keys in this set is required when constructing
    __ONE_REQUESTED = frozenset("assign before after signal".split())
    __ALL_REQUESTED = frozenset("model prop_name".split())

    def __init__(self, _type, *args, **kwargs):
        dict.__init__(self, *args, **kwargs)
        
        # checks the content provided by the user        
        if not (_type in self and self[_type]):
            raise KeyError("flag '%s' must be set in given arguments" % _type)

        # all requested are provided by the framework, not the user
        assert NTInfo.__ALL_REQUESTED <= set(self)

        # now removes all type-flags not related to _type
        for flag in NTInfo.__ONE_REQUESTED:
            if flag != _type and flag in self: del self[flag]
            pass
        
        return

    def __getattr__(self, name):
        """
        All dictionary keys are also available as attributes.
        """
        try:
            return self[name]
        except KeyError: 
            raise AttributeError("NTInfo object has no attribute '%s'.\n"
                                 "Existing attributes are: %s" % (name, str(self)))
        pass

    pass # end of class NTInfo
# ----------------------------------------------------------------------
    


@decorators.good_decorator_accepting_args
def observes(*args):
    """
    Decorate a method in an :class:`Observer` subclass as a notification.
    Takes one to many property names as strings. If any of them changes
    in a model we observe, the method is called. The name of the property 
    will be passed to the method. 

    The type of notification is inferred from the number of arguments. Valid
    signature are::

      def value_notify(self, model, name, old, new)
      def before_notify(self, model, name, instance, method_name, args, kwargs)
      def after_notify(self, model, name, instance, method_name, res, args, kwargs)
      def signal_notify(self, model, name, arg)

    .. versionadded:: 1.99.0

    .. deprecated:: 1.99.1
       Use :meth:`Observer.observe` instead, which offers more features.
    """

    @decorators.good_decorator
    def _decorator(_notified):
        # marks the method with observed properties
        _list = getattr(_notified, Observer._CUST_OBS_, list())        

        # here the notificaion type is inferred out of the number of
        # arguments of the notification method. This is not
        # particularly robust.
        margs, mvarargs, _, _ = inspect.getargspec(_notified)
        mnumargs = len(margs)
        if not mvarargs:
            args_to_type = { 4 : 'signal',
                             5 : 'assign',
                             7 : 'before',
                             8 : 'after', 
                             }
            try : 
                type_kw = args_to_type[mnumargs]
                # warning: flag _old_style_call is used this as
                # deprecated call mechanism like in
                # <property_<name>_...
                _list += [(arg, dict({type_kw : True, 
                                      'old_style_call' : True}))
                          for arg in args]
                setattr(_notified, Observer._CUST_OBS_, _list)

            except KeyError:
                log.logger.warn("Ignoring notification %s: wrong number of"
                                " arguments (given %d, expected in (%s))", 
                                _notified.__name__, mnumargs, 
                                ",".join(map(str, args_to_type)))
                pass
        else:
            log.logger.warn("Ignoring notification %s: variable arguments"
                            " prevent type inference", _notified.__name__)
            pass
        return _notified

    # checks arguments
    if 0 == len(args): 
        raise TypeError("decorator observe() takes one of more arguments (0 given)")
    if [a for a in args if type(a) != str]:
        raise TypeError("decorator observe() takes only strings as arguments")    

    log.logger.warning("Decorator observer.observers is deprecated:"
                       "use Observer.observe instead")
    return _decorator
# ----------------------------------------------------------------------


class Observer (object):
    """
    .. note::

       Most methods in this class are used internally by the
       framework.  Do not override them in subclasses.
    """

    # this is internal
    _CUST_OBS_ = "__custom_observes__"
    # ----------------------------------------------------------------------   


    @classmethod
    @decorators.good_decorator_accepting_args
    def observe(cls, *args, **kwargs):
        """
        Mark a method as recieving notifications. Comes in two flavours:

        .. method:: observe(name, **types)
           :noindex:

           A decorator living in the class. Can be applied more than once to
           the same method, provided the names differ.
           
           *name* is the property we want to be notified about as a string.
           
           *types* are boolean values denoting the types of
           notifications desired. At least one of the following has to be
           passed as True: assign, before, after, signal.

           Excess keyword arguments are passed to the method as part of the
           info dictionary.

        .. method:: observe(callable, name, **types)
           :noindex:

           An instance method to define notifications at runtime. Works as
           above.
           
           *callable* is the method to send notifications to. The effect will
           be as if this had been decorated.

        In all cases the notification method must take exactly three
        arguments: the model object, the name of the property that changed,
        and an :class:`NTInfo` object describing the change.

        .. warning::
      
           Due to limitation in the dynamic registration (in version
           1.99.1), declarations of dynamic notifications must occur
           before registering self as an observer of the models whose
           properties the notifications are supposed to be
           observing. A hack for this limitation, is to first relieve
           any interesting model before dynamically register the
           notifications, and then re-observe those models.

        .. versionadded:: 1.99.1
        """
        
        @decorators.good_decorator
        def _decorator(_notified):
            # marks the method with observed properties
            _list = getattr(_notified, Observer._CUST_OBS_, list())
            _list.append((name, kwargs))
            setattr(_notified, Observer._CUST_OBS_, _list)
            return _notified 

        # handles arguments
        if args and isinstance(args[0], cls):
            # used as instance method, for declaring notifications
            # dynamically
            if len(args) != 3: 
                raise TypeError("observe() takes exactly three arguments"
                                " when called (%d given)" % len(args))
            
            self = args[0]
            notified = args[1]
            name = args[2]            

            assert isinstance(self, Observer), "Method Observer.observe " \
                "must be called with an Observer instance as first argument"
            if not callable(notified):
                raise TypeError("Second argument of observe() must be a callable")
            if type(name) != str: 
                raise TypeError("Third argument of observe() must be a string")
            
            self.__register_notification(name, notified, kwargs)
            return None

        # used statically as decorator
        if len(args) != 1: 
            raise TypeError("observe() takes exactly one argument when used"
                            " as decorator (%d given)" % len(args))
        name = args[0]
        if type(name) != str: 
            raise TypeError("First argument of observe() must be a string")
        return _decorator            
    # ----------------------------------------------------------------------


    def __init__(self, model=None, spurious=False):
        """
        *model* is passed to :meth:`observe_model` if given.
        
        *spurious* indicates interest to be notified even when
        the value hasn't changed, like for: ::

         model.prop = model.prop

        .. versionadded:: 1.2.0
           Before that observers had to filter out spurious
           notifications themselves, as if the default was `True`. With
           :class:`~gtkmvc.observable.Signal` support this is no longer
           necessary.
        """

        # --------------------------------------------------------- #
        # This turns the decorator 'observe' an instance method
        def __observe(*args, **kwargs): self.__original_observe(self, *args, **kwargs)
        __observe.__name__ = self.observe.__name__
        __observe.__doc__ = self.observe.__doc__
        self.__original_observe = self.observe
        self.observe = __observe
        # --------------------------------------------------------- #

        self.__accepts_spurious__ = spurious

        # NOTE: In rev. 202 these maps were unified into
        #   __CUST_OBS_MAP only (the map contained pairs (method,
        #   args). However, this broke backward compatibility of code
        #   accessing the map through
        #   get_observing_methods. Now the informatio is split
        #   and the original information restored. To access the
        #   additional information (number of additional arguments
        #   required by observing methods) use the newly added methods.

        # Private maps: do not change/access them directly, use
        # methods to access them:
        self.__CUST_OBS_MAP = {} # prop name --> set of observing methods
        self.__CUST_OBS_KWARGS = {} # observing method --> flag 

        processed_props = set() # tracks already processed properties

        # searches all custom observer methods
        for cls in inspect.getmro(type(self)):
            # list of (method-name, method-object, list of (prop-name, kwargs))
            meths = [ (name, meth, getattr(meth, Observer._CUST_OBS_))
                      for name, meth in cls.__dict__.iteritems()
                      if (inspect.isfunction(meth) and 
                          hasattr(meth, Observer._CUST_OBS_)) ]

            # props processed in this class. This is used to avoid
            # processing the same props in base classes.
            cls_processed_props = set() 
            
            # since this is traversed top-bottom in the mro, the
            # first found match is the one to care
            for name, meth, pnames_ka in meths:
                _method = getattr(self, name) # the most top avail method 

                # WARNING! Here we store the top-level method in the
                # mro, not the (unbound) method which has been
                # declared by the user with the decorator.
                for pname, ka in pnames_ka:
                    if pname not in processed_props:
                        self.__register_notification(pname, _method, ka)
                        cls_processed_props.add(pname)
                        pass
                    pass
                pass 
            
            # accumulates props processed in this class
            processed_props |= cls_processed_props
            pass # end of loop over classes in the mro

        if model: self.observe_model(model)
        return   
    
    def observe_model(self, model):
        """Starts observing the given model"""
        return model.register_observer(self)

    def relieve_model(self, model):
        """Stops observing the given model"""
        return model.unregister_observer(self)
    
    def accepts_spurious_change(self):
        """
        Returns True if this observer is interested in receiving
        spurious value changes. This is queried by the model when
        notifying a value change."""
        return self.__accepts_spurious__

    def get_observing_methods(self, prop_name):
        """
        Return a possibly empty set of callables registered with
        :meth:`observe` for *prop_name*.
        
        .. versionadded:: 1.99.1
           Replaces :meth:`get_custom_observing_methods`.
        """
        return self.__CUST_OBS_MAP.get(prop_name, set())

    # this is done to keep backward compatibility
    get_custom_observing_methods = get_observing_methods
    

    def get_observing_method_kwargs(self, prop_name, method):
        """
        Returns the keyword arguments which were specified when
        declaring a notification method, either statically of
        synamically with :meth:`Observer.observe`.

        *method* a callable that was registered with
        :meth:`observes`.
        
        :rtype: dict
        """
        return self.__CUST_OBS_KWARGS[(prop_name, method)]
    

    def remove_observing_method(self, prop_names, method):
        """
        Remove dynamic notifications.
        
        *method* a callable that was registered with :meth:`observe`.
        
        *prop_names* a sequence of strings. This need not correspond to any
        one `add` call.

        .. note::

           This can revert the effects of a decorator at runtime. Don't.
        """
        for prop_name in prop_names:
            _set = self.__CUST_OBS_MAP.get(prop_name, set())
            if method in _set: _set.remove(method)
            key = (prop_name, method)
            if key in self.__CUST_OBS_KWARGS: del self.__CUST_OBS_KWARGS[key]
            pass
        
        return

    def is_observing_method(self, prop_name, method):
        """
        Returns `True` if the given method was previously added as an
        observing method, either dynamically or via decorator.
        """
        return (prop_name, method) in self.__CUST_OBS_KWARGS


    def __register_notification(self, prop_name, method, kwargs):
        """Internal service which associates the given property name
        to the method, and the (prop_name, method) with the given
        kwargs dictionary. If needed merges the dictionary, if the
        given (prop_name, method) pair was already registered (in this
        case the last registration wins in case of overlapping.)

        If given prop_name and method have been already registered, a
        ValueError exception is raised."""

        key = (prop_name, method)
        if key in self.__CUST_OBS_KWARGS:
            raise ValueError("In %s method '%s' has been declared "
                             "to be a notification for property '%s' "
                             "multiple times (only one is allowed)." % \
                                 (self.__class__, 
                                  method.__name__, prop_name))
                
        # fills the internal structures
        if not self.__CUST_OBS_MAP.has_key(prop_name):
            self.__CUST_OBS_MAP[prop_name] = set()
            pass
        self.__CUST_OBS_MAP[prop_name].add(method)

        self.__CUST_OBS_KWARGS[key] = kwargs
        return

    pass # end of class
# ----------------------------------------------------------------------