This file is indexed.

/usr/share/pyshared/gtkmvc/support/metaclasses.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
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
#  Author: Roberto Cavada <roboogle@gmail.com>
#
#  Copyright (c) 2005 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>.

import new
import re
import types
import inspect
import sys
import fnmatch
import itertools

import gtkmvc.support.wrappers as wrappers
from gtkmvc.support.utils import getmembers
from gtkmvc.support.log import logger
from gtkmvc.support.exceptions import DecoratorError, TooManyCandidatesError

# ----------------------------------------------------------------------

OBS_TUPLE_NAME = "__observables__"

# old name, supported only for backward compatilibity, do not use it
# anymore in new code
PROPS_MAP_NAME = "__properties__" 

# This keeps the names of all observable properties (old and new)
ALL_OBS_SET = "__all_observables__"

# name of the variable that hold a property value
PROP_NAME = "_prop_%(prop_name)s"

# these are the names of the internal maps associating logical
# properties names to their getters/setters
LOGICAL_GETTERS_MAP_NAME = "_getdict"
LOGICAL_SETTERS_MAP_NAME = "_setdict"

# WARNING! These variables and code using them is deprecated These are
# the names for property getter/setter methods that depend on property
# name
GET_PROP_NAME = "get_%(prop_name)s_value"
SET_PROP_NAME = "set_%(prop_name)s_value"

# There are the names for generic property getter/setter methods
GET_GENERIC_NAME = "get__value"
SET_GENERIC_NAME = "set__value"

# this used for pattern matching
WILDCARDS = frozenset("[]!*?")


class PropertyMeta (type):
    """This is a meta-class that provides auto-property support.
    The idea is to allow programmers to define some properties which
    will be automatically connected to auto-generated code which handles
    access to those properties.
    How can you use this meta-class?
    First, '__metaclass__ = PropertyMeta' must be class member of the class
    you want to make the automatic properties handling.
    Second, '__properties__' must be a map containing the properties names
    as keys, values will be initial values for properties.
    That's all: after the instantiation, your class will contain all properties
    you named inside '__properties__'. Each of them will be also associated
    to a couple of automatically-generated functions which get and set the
    property value inside a generated member variable.
    About names: suppose the property is called 'x'.  The generated variable
    (which keeps the real value of the property x) is called _prop_x.
    The getter is called get_prop_x(self), and the setter is called
    'set_prop_x(self, value)'.

    Customization:
    The base implementation of getter is to return the value stored in the
    variable associated to the property. The setter simply sets its value.
    Programmers can override basic behaviour for getters or setters simply by
    defining their getters and setters (see at the names convention above).
    The customized function can lie everywhere in the user classes hierarchy.
    Every overridden function will not be generated by the metaclass.

    To supply your own methods is good for few methods, but can result in a
    very unconfortable way for many methods. In this case you can extend
    the meta-class, and override methods get_[gs]etter_source with your
    implementation (this can be probably made better).
    An example is provided in meta-class PropertyMetaVerbose below.
    """
    
    def __init__(cls, name, bases, _dict):
        """class constructor"""
        type.__init__(cls, name, bases, _dict)
       
        # the set of all obs (it is calculated and stored below)
        obs = set()

        # processes now all names in __observables__ 
        conc_props, log_props = type(cls).__get_observables_sets__(cls)

        # processes all concrete properties
        for prop in conc_props:
            val = _dict[prop] # must exist if concrete
            type(cls).__create_conc_prop_accessors__(cls, prop, val)
            obs.add(prop)
            pass

        # processes all logical properties, and adds the actual log
        # properties to the list of all observables
        _getdict = getattr(cls, LOGICAL_GETTERS_MAP_NAME, dict())
        _setdict = getattr(cls, LOGICAL_SETTERS_MAP_NAME, dict())

        real_log_props = type(cls).__create_log_props(cls, log_props, 
                                                      _getdict, _setdict)
        obs |= real_log_props

        # after using the maps, it is time to clear them to make
        # them available to the next class in the mro.
        _getdict.clear()
        _setdict.clear()

        # processes all names in __properties__ (deprecated,
        # overloaded by __observables__)
        props = getattr(cls, PROPS_MAP_NAME, {})      
        if len(props) > 0: 
            import warnings
            warnings.warn("In class %s.%s the use of attribute '%s' in "
                          "models is deprecated."
                          " Use the tuple '%s' instead (see the manual)" \
                              % (cls.__module__, cls.__name__,  
                                 PROPS_MAP_NAME, OBS_TUPLE_NAME), 
                          DeprecationWarning)
            pass
        for prop in (x for x in props.iterkeys() if x not in obs):
            type(cls).__create_conc_prop_accessors__(cls, prop, props[prop])
            obs.add(prop)
            pass

        # generates the list of _all_ properties available for this
        # class (also from bases)
        for base in bases: obs |= getattr(base, ALL_OBS_SET, set())
        setattr(cls, ALL_OBS_SET, frozenset(obs))
        logger.debug("class %s.%s has observables: %s" \
                         % (cls.__module__, cls.__name__, obs))
        return


    def __get_observables_sets__(cls):
        """Returns a pair of frozensets. First set of strings is the set
        of concrete properties, obtained by expanding wildcards
        found in class field __observables__. Expansion works only
        with names not prefixed with __.

        Second set of strings contains the names of the logical
        properties. This set may still contain logical properties
        which have not been associated with a getter (and
        optionally with a setter).
        """
        conc_prop_set = set()
        log_prop_set = set()

        not_found = []
        names = cls.__dict__.get(OBS_TUPLE_NAME, tuple())
        
        if not isinstance(names, types.ListType) and \
                not isinstance(names, types.TupleType):
            raise TypeError("In class %s.%s attribute '%s' must be a list or tuple" %
                            (cls.__module__, cls.__name__, OBS_TUPLE_NAME))

        for name in names:
            if type(name) != types.StringType:
                raise TypeError("In class %s.%s attribute '%s' must contain"\
                                    " only strings (found %s)" % 
                                (cls.__module__, cls.__name__, OBS_TUPLE_NAME,
                                 type(name)))
            if (cls.__dict__.has_key(name) and not 
                isinstance(getattr(cls, name), types.MethodType)): 
                conc_prop_set.add(name)
            else: not_found.append(name)
            pass
                
        # now searches all possible matches for those that have not
        # been found, and collects all logical properties as well
        # (those which do not match, and do not contain patterns)
        concrete_members = [x for x,v in cls.__dict__.iteritems()
                            if (not x.startswith("__") and
                                not isinstance(v, types.FunctionType) and 
                                not isinstance(v, types.MethodType) and 
                                type(v) is not classmethod and 
                                x not in conc_prop_set)]

        for pat in not_found:
            if frozenset(pat) & WILDCARDS:
                matches = fnmatch.filter(concrete_members, pat)
                if 0 == len(matches):
                    logger.warning("In class %s.%s observable pattern '%s' " \
                                       "did not match any existing attribute." % \
                                       (cls.__module__, cls.__name__, pat))
                else: conc_prop_set |= set(matches)
            else: # here pat has to be a logical property
                log_prop_set.add(pat)
                pass
            
            pass        
        
        return (frozenset(conc_prop_set), frozenset(log_prop_set))


    def __create_log_props(cls, log_props, _getdict, _setdict):
        """Creates all the logical property. 

        The list of names of properties to be created is passed
        with frozenset log_props. The getter/setter information is
        taken from _{get,set}dict.

        This method resolves also wildcards in names, and performs
        all checks to ensure correctness.

        Returns the frozen set of the actually created properties
        (as not log_props may be really created, e.g. when no
        getter is provided, and a warning is issued).
        """
        
        real_log_props = set()
        resolved_getdict = {} 
        resolved_setdict = {} 

        for _dict_name, _dict, _resolved_dict in (("getter", 
                                                   _getdict, resolved_getdict), 
                                                  ("setter", 
                                                   _setdict, resolved_setdict)):
            # first resolve all wildcards
            for pat, ai in ((pat, ai) 
                            for pat, ai in _dict.iteritems()
                            if frozenset(pat) & WILDCARDS):
                matches = fnmatch.filter(log_props, pat)
                for match in matches:
                    if match in _resolved_dict:
                        raise NameError("In class %s.%s %s property '%s' "
                                        "is matched multiple times by patterns" % \
                                        (cls.__module__, cls.__name__, _dict_name, match))
                    _resolved_dict[match] = ai
                    pass

                if not matches:
                    logger.warning("In class %s.%s %s pattern '%s' " 
                                   "did not match any existing logical property." % \
                                   (cls.__module__, cls.__name__, _dict_name, pat))
                    pass
                pass

            # now adds the exact matches (no wilcards) which override
            # the pattern-matches
            _resolved_dict.update((name, ai)
                                  for name, ai in _dict.iteritems()
                                  if name in log_props)

            # checks that all getter/setter have a corresponding logical property
            not_found = [name for name in _resolved_dict 
                         if name not in log_props]

            if not_found:
                logger.warning("In class %s.%s logical %s were declared for"\
                                   "non-existant observables: %s" % \
                                   (cls.__module__, cls.__name__, _dict_name, str(not_found)))
                pass
            pass
        
        # creates the properties
        for name in log_props:
            # finds the getter
            ai_get = resolved_getdict.get(name, None)
            if ai_get: 
                # decorator-based
                _getter = type(cls).get_getter(cls, name, ai_get.func, 
                                               ai_get.has_args)
            else: 
                # old style
                _getter = type(cls).get_getter(cls, name)
                if _getter is None:
                    raise RuntimeError("In class %s.%s logical observable '%s' "\
                                           "has no getter method" % \
                                           (cls.__module__, cls.__name__, name))
                pass
            
            # finds the setter
            ai_set = resolved_setdict.get(name, None)
            if ai_set:
                # decorator-based
                if ai_get:
                    _setter =  type(cls).get_setter(cls, name, 
                                                    ai_set.func, ai_set.has_args,
                                                    ai_get.func, ai_get.has_args)
                else:
                    # the getter is old style. _getter is already
                    # resolved wrt the name it may take, so
                    # getter_takes_name is False
                    _setter =  type(cls).get_setter(cls, name, 
                                                    ai_set.func, ai_set.has_args,
                                                    _getter, False)
                    pass
            else:
                # old style setter
                if ai_get: 
                    _setter =  type(cls).get_setter(cls, name, 
                                                    None, None,
                                                    ai_get.func, 
                                                    ai_get.has_args)
                else: _setter =  type(cls).get_setter(cls, name)
                pass
            
            # here _setter can be None            
            prop = property(_getter, _setter)
            setattr(cls, name, prop)
            real_log_props.add(name)                
            pass

        # checks that all setters have a getter
        setters_no_getters = (set(resolved_setdict) - real_log_props) & log_props
        if setters_no_getters:
            logger.warning("In class %s.%s logical setters have no "
                           "getters: %s" % \
                               (cls.__module__, cls.__name__, 
                                ", ".join(setters_no_getters)))
            pass

        return frozenset(real_log_props)



    def __create_conc_prop_accessors__(cls, prop_name, default_val):
        """Private method that creates getter and setter, and the
        corresponding property. This is used for concrete
        properties."""
        getter_name = "get_prop_%s" % prop_name
        setter_name = "set_prop_%s" % prop_name

        members_names = cls.__dict__.keys()

        # checks if accessors are already defined:
        if getter_name not in members_names:
            _getter = type(cls).get_getter(cls, prop_name)
            setattr(cls, getter_name, _getter)
        else:
            logger.debug("Custom member '%s' overloads generated getter of property '%s'" \
                             % (getter_name, prop_name))
            pass

        if setter_name not in members_names:
            _setter = type(cls).get_setter(cls, prop_name)
            setattr(cls, setter_name, _setter)
        else:
            logger.warning("Custom member '%s' overloads generated setter of property '%s'" \
                               % (setter_name, prop_name))
            pass

        # creates the property
        prop = property(getattr(cls, getter_name), getattr(cls, setter_name))
        setattr(cls, prop_name, prop)

        # creates the underlaying variable if needed
        varname = PROP_NAME % {'prop_name' : prop_name}
        if varname not in members_names: 
            setattr(cls, varname, cls.create_value(varname, default_val))
            
        else: logger.warning("In class %s.%s automatic property builder found a "
                             "possible clashing with attribute '%s'" \
                                 % (cls.__module__, cls.__name__, varname))        
        return

    def has_prop_attribute(cls, prop_name):
        """This methods returns True if there exists a class attribute
        for the given property. The attribute is searched locally
        only"""
        props = getattr(cls, PROPS_MAP_NAME, {})

        return (cls.__dict__.has_key(prop_name) and 
                type(cls.__dict__[prop_name]) != types.FunctionType)
    
    def check_value_change(cls, old, new):
        """Checks whether the value of the property changed in type
        or if the instance has been changed to a different instance.
        If true, a call to model._reset_property_notification should
        be called in order to re-register the new property instance
        or type"""
        return  type(old) != type(new) or \
               isinstance(old, wrappers.ObsWrapperBase) and (old != new)
    
    def create_value(cls, prop_name, val, model=None):
        """This is used to create a value to be assigned to a
        property. Depending on the type of the value, different values
        are created and returned. For example, for a list, a
        ListWrapper is created to wrap it, and returned for the
        assignment. model is different from None when the value is
        changed (a model exists). Otherwise, during property creation
        model is None"""

        if isinstance(val, tuple):
            # this might be a class instance to be wrapped
            # (thanks to Tobias Weber for
            # providing a bug fix to avoid TypeError (in 1.99.1)
            if len(val) == 3:
                try: 
                    wrap_instance = isinstance(val[1], val[0]) and \
                        (isinstance(val[2], tuple) or
                         isinstance(val[2], list))
                except TypeError: 
                    pass # not recognized, it must be another type of tuple
                else:
                    if wrap_instance:
                        res = wrappers.ObsUserClassWrapper(val[1], val[2])
                        if model: res.__add_model__(model, prop_name)
                        return res
                    pass
                pass
            pass
        
        elif isinstance(val, list):
            res = wrappers.ObsListWrapper(val)
            if model: res.__add_model__(model, prop_name)
            return res

        elif isinstance(val, dict):            
            res = wrappers.ObsMapWrapper(val)
            if model: res.__add_model__(model, prop_name)
            return res

        return val


    # ------------------------------------------------------------
    #               Services    
    # ------------------------------------------------------------

    # Override these:
    def get_getter(cls, prop_name, 
                   user_getter=None, getter_takes_name=False):
        """Returns a function wich is a getter for a property.
        prop_name is the name off the property.

        user_getter is an optional function doing the work. If
        specified, that function will be called instead of getting
        the attribute whose name is in 'prop_name'. 

        If user_getter is specified with a False value for
        getter_takes_name (default), than the method is used to get
        the value of the property. If True is specified for
        getter_takes_name, then the user_getter is called by
        passing the property name (i.e. it is considered a general
        method which receive the property name whose value has to
        be returned.)
        """
        if user_getter: 
            if getter_takes_name: # wraps the property name
                def _getter(self): return user_getter(self, prop_name)
            else: _getter = user_getter
            return _getter

        def _getter(self): return getattr(self, 
                                          PROP_NAME % {'prop_name' : prop_name})
        return _getter


    def get_setter(cls, prop_name, 
                   user_setter=None, setter_takes_name=False,
                   user_getter=None, getter_takes_name=False):
        """Similar to get_getter, but for setting property
        values. If user_getter is specified, that it may be used to
        get the old value of the property before setting it (this
        is the case in some derived classes' implementation). if
        getter_takes_name is True and user_getter is not None, than
        the property name is passed to the given getter to retrieve
        the property value."""

        if user_setter:
            if setter_takes_name:
                # wraps the property name
                def _setter(self, val): return user_setter(self, prop_name, val)
            else: _setter = user_setter
            return _setter
        
        def _setter(self, val): setattr(self, 
                                        PROP_NAME % {'prop_name' : prop_name}, 
                                        val)
        return _setter

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



class ObservablePropertyMeta (PropertyMeta):
  """Classes instantiated by this meta-class must provide a method named
  notify_property_change(self, prop_name, old, new)"""
  def __init__(cls, name, bases, dict):
    PropertyMeta.__init__(cls, name, bases, dict)
    return    

  def get_getter(cls, prop_name, 
                 user_getter=None, getter_takes_name=False):
      """This implementation returns the PROP_NAME value if there
      exists such property. Otherwise there must exist a logical
      getter (user_getter) which the value is taken from.  If no
      getter is found, None is returned (i.e. the property cannot
      be created)"""

      has_prop_variable = cls.has_prop_attribute(prop_name) 

      # WARNING! Deprecated
      has_specific_getter = hasattr(cls, GET_PROP_NAME % {'prop_name' : prop_name})
      has_general_getter = hasattr(cls, GET_GENERIC_NAME)

      if not (has_prop_variable or 
              has_specific_getter or has_general_getter or user_getter):
          return None
      
      # when property variable is given, it overrides all the getters
      if has_prop_variable:          
          if has_specific_getter or user_getter: 
              logger.warning("In class %s.%s ignoring custom logical getter "
                             "for property '%s' as a corresponding "
                             "attribute exists" \
                                 % (cls.__module__, cls.__name__, prop_name))              
              pass
          # user_getter is ignored here, so it has not to be passed up
          user_getter = None; getter_takes_name = False
      else:
            
          # uses logical getter. Sees if the getter needs to receive
          # the property name (i.e. if the getter is used for multiple
          # properties)
          if user_getter: pass
          else:
              if has_specific_getter: 
                  # this is done to delay getter call, to have
                  # bound methods to allow overloading of getter in
                  # derived classes
                  def __getter(self):
                      _getter = getattr(self, GET_PROP_NAME % {'prop_name' : prop_name})
                      return _getter()
                  #previously it was simply:
                  #user_getter = getattr(cls, GET_PROP_NAME % {'prop_name' : prop_name})
                  user_getter = __getter
                  getter_takes_name = False
              else:
                  assert has_general_getter
                  def __getter(self, name):
                      _getter = getattr(self, GET_GENERIC_NAME)
                      return _getter(name)
                  #user_getter = getattr(cls, GET_GENERIC_NAME)
                  user_getter = __getter
                  getter_takes_name = True
                  pass
              pass
          pass
      
      return PropertyMeta.get_getter(cls, prop_name, user_getter, getter_takes_name)

  
  def get_setter(cls, prop_name, 
                 user_setter=None, setter_takes_name=False,
                 user_getter=None, getter_takes_name=False):
      """The setter follows the rules of the getter. First search
      for property variable, then logical custom setter. If no
      setter is found, None is returned (i.e. the property is
      read-only.)"""

      has_prop_variable = cls.has_prop_attribute(prop_name)

      # WARNING! These are deprecated
      has_specific_setter = hasattr(cls, SET_PROP_NAME % {'prop_name' : prop_name})
      has_general_setter = hasattr(cls, SET_GENERIC_NAME)
      
      if not (has_prop_variable or 
              has_specific_setter or has_general_setter or user_setter):
          return None

      if has_prop_variable:
          if has_specific_setter or user_setter:
              logger.warning("In class %s.%s ignoring custom logical setter "
                             "for property '%s' as a corresponding "
                             "attribute exists" \
                                 % (cls.__module__, cls.__name__, prop_name))
              pass 
          user_setter = user_getter = None
          setter_takes_name = getter_takes_name = False
      else:
          if user_setter: pass
          else:
              if has_specific_setter: 
                  def __setter(self, val):
                      _setter = getattr(self, SET_PROP_NAME % {'prop_name' : prop_name})
                      _setter(val)
                      pass
                  user_setter = __setter
                  #user_setter = getattr(cls, SET_PROP_NAME % {'prop_name' : prop_name})
                  setter_takes_name = False
              else:
                  assert has_general_setter
                  def __setter(self, name, val):
                      _setter = getattr(self, SET_GENERIC_NAME)
                      _setter(name, val)
                      pass
                  user_setter = __setter
                  #user_setter = getattr(cls, SET_GENERIC_NAME)
                  setter_takes_name = True
                  pass
              pass
          pass
      
      # the final setter is a combination of a basic setter, and
      # the getter (see how inner_{getter,setter} are used in
      # _setter below)
      _inner_setter = PropertyMeta.get_setter(cls, prop_name, 
                                              user_setter, setter_takes_name,
                                              user_getter, getter_takes_name)      


      _inner_getter = type(cls).get_getter(cls, prop_name, user_getter, getter_takes_name) 

      def _setter(self, val):
          old = _inner_getter(self)
          new = type(self).create_value(prop_name, val, self)
          _inner_setter(self, new)
          if type(self).check_value_change(old, new): 
              self._reset_property_notification(prop_name, old)
              pass
          self.notify_property_value_change(prop_name, old, val)
          return
      return _setter

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


class ObservablePropertyMetaMT (ObservablePropertyMeta):
  """This class provides multithreading support for accesing
  properties, through a locking mechanism. It is assumed a lock is
  owned by the class that uses it. A Lock object called _prop_lock
  is assumed to be a member of the using class. see for example class
  ModelMT"""
  def __init__(cls, name, bases, dict):
    ObservablePropertyMeta.__init__(cls, name, bases, dict)
    return 
    
  def get_setter(cls, prop_name, 
                 user_setter=None, setter_takes_name=False,
                 user_getter=None, getter_takes_name=False):
      """The setter follows the rules of the getter. First search
      for property variable, then logical custom getter/seter pair
      methods"""

      _inner_setter = ObservablePropertyMeta.get_setter(cls, prop_name,
                                                        user_setter, setter_takes_name,
                                                        user_getter, getter_takes_name)
      def _setter(self, val):
          self._prop_lock.acquire()
          _inner_setter(self, val)
          self._prop_lock.release()
          return
      return _setter

  pass #end of class


try:
  from sqlobject import Col
  from sqlobject.inheritance import InheritableSQLObject
  from sqlobject.events import listen, RowUpdateSignal
  
  class ObservablePropertyMetaSQL (InheritableSQLObject.__metaclass__,
                                   ObservablePropertyMeta):
    """Classes instantiated by this meta-class must provide a method
    named notify_property_change(self, prop_name, old, new)"""

    def __init__(cls, name, bases, dict):
      InheritableSQLObject.__metaclass__.__init__(cls, name, bases, dict)
      ObservablePropertyMeta.__init__(cls, name, bases, dict)

      listen(cls.update_listener, cls, RowUpdateSignal)
      return    

    def __create_conc_prop_accessors__(cls, prop_name, default_val):
      if not isinstance(default_val, Col):
        # this is not a SQLObject column (likely a normal concrete
        # observable property)
        ObservablePropertyMeta.__create_conc_prop_accessors__(cls, 
                                                              prop_name, 
                                                              default_val)
        pass
      return
    
    def update_listener(cls, instance, kwargs):
      conc_pnames, _ = type(cls).__get_observables_sets__(cls)
      for k in kwargs:
        if k in conc_pnames:
          _old = getattr(instance, k)
          _new = kwargs[k]
          instance.notify_property_value_change(k, _old, _new)
          pass
        pass
      return
    
    pass #end of class
except: pass
  
try:
  from gobject import GObjectMeta
  class ObservablePropertyGObjectMeta (ObservablePropertyMeta, GObjectMeta): pass
  class ObservablePropertyGObjectMetaMT (ObservablePropertyMetaMT, GObjectMeta): pass    
except:
  class ObservablePropertyGObjectMeta (ObservablePropertyMeta): pass
  class ObservablePropertyGObjectMetaMT (ObservablePropertyMetaMT): pass
  pass