Ejemplo n.º 1
0
  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)
Ejemplo n.º 2
0
    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))
Ejemplo n.º 3
0
    def get_getter_source(cls, getter_name, prop_name):
        """This implementation returns the PROP_NAME value if there
      exists such property. If there exist a pair of methods
      __get_<prop_name>_value__ and __set_<prop_name>_value__ the
      value is taken from the getter. Otherwise if there exists the
      generic pair __get_value__ and __set_value__ the gettter is
      called. The getter method (specific or general) is called _only_
      if there exists no variable called PROP_NAME (see the user
      manual)"""

        has_prop_variable = cls.has_prop_attribute(prop_name)

        has_specific_getter = hasattr(
            cls, GET_PROP_NAME % {"prop_name": prop_name}
        ) and hasattr(  # has property getter and setter
            cls, SET_PROP_NAME % {"prop_name": prop_name}
        )

        has_general_getter = hasattr(cls, GET_GENERIC_NAME) and hasattr(  # has generic getter and setter
            cls, SET_GENERIC_NAME
        )

        assert has_prop_variable or has_specific_getter or has_general_getter, "no var/methods for '%s'" % prop_name

        # when property variable is given, it overrides all getters
        if has_prop_variable:
            getter = "self." + PROP_NAME
            if has_specific_getter:
                logger.warning(
                    "In class %s.%s ignoring custom getter/setter pair for property '%s' as a corresponding attribute exists"
                    % (cls.__module__, cls.__name__, prop_name)
                )

        # specific getter ovverides the general one
        elif has_specific_getter:
            getter = "self." + GET_PROP_NAME + "()"

        # generic getter
        else:
            getter = "self." + GET_GENERIC_NAME + "('%(prop_name)s')"

        # general getter ovverides the general one
        return ("def %(getter_name)s(self): return " + getter) % {"getter_name": getter_name, "prop_name": prop_name}
Ejemplo n.º 4
0
    def __create_prop_accessors__(cls, prop_name, default_val):
        """Private method that creates getter and setter, and the
        corresponding property"""
        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:
            src = type(cls).get_getter_source(cls, getter_name, prop_name)
            func = get_function_from_source(src)
            setattr(cls, getter_name, func)
        else:
            logger.debug("Custom member '%s' overloads generated getter of property '%s'", getter_name, prop_name)
            pass

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

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

        has_prop_variable = hasattr(cls, prop_name) or props.has_key(prop_name)
        if has_prop_variable:
            varname = PROP_NAME % {"prop_name": prop_name}
            if not varname in members_names:
                cls.__create_property(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,
                )
            pass

        return
Ejemplo n.º 5
0
    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
Ejemplo n.º 6
0
    def __get_observables_array__(cls):
        """Returns a set of strings by expanding wilcards found
        in class field __observables__. Expansion works only with
        names not prefixed with __"""
        import fnmatch

        res_set = set()

        not_found = []
        names = getattr(cls, 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 hasattr(cls, name) and getattr(cls, name) != types.MethodType:
                res_set.add(name)
            else:
                not_found.append(name)
            pass

        # now searches all possible matches for those that have not been found:
        for name in (
            x
            for x, v in cls.__dict__.iteritems()
            if not x.startswith("__") and type(v) != types.MethodType and x not in res_set
        ):
            for pat, i in zip(not_found, range(len(not_found))):
                if fnmatch.fnmatch(name, pat):
                    res_set.add(name)
                pass
            pass

        # finally, there might entries that have no corresponding
        # value, but there exist getter and setter methods. These
        # entries are valid only if they do not contain wilcards
        wilcards = frozenset("[]!*?")
        for name, nameset in zip(not_found, (frozenset(x) for x in not_found)):
            if len(nameset & wilcards) == 0:  # no wilcards in the name
                # has property getter and setter :
                if (
                    hasattr(cls, GET_PROP_NAME % {"prop_name": name})
                    and hasattr(cls, SET_PROP_NAME % {"prop_name": name})
                ) or (  # has generic getter and setter
                    hasattr(cls, GET_GENERIC_NAME) and hasattr(cls, SET_GENERIC_NAME)
                ):
                    res_set.add(name)
                else:  # the observable was not found!
                    logger.warning(
                        "In class %s.%s ignoring observable '%s' "
                        "which has no corresponding attribute"
                        " or custom getter/setter pair" % (cls.__module__, cls.__name__, name)
                    )
                    pass
                pass
            pass

        return res_set
Ejemplo n.º 7
0
  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
Ejemplo n.º 8
0
    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)