def get_setter(cls, prop_name,  # @NoSelf
                   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))

            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)
                        return
                    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)
                        return
                    user_setter = __setter
                    #user_setter = getattr(cls, SET_GENERIC_NAME)
                    setter_takes_name = True

        # 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):
            curr_frame = len(self._notify_stack)
            if prop_name not in self._notify_stack:
                self._notify_stack.append(prop_name)

            old = _inner_getter(self)
            new = type(self).create_value(prop_name, val, self)

            # to track dependencies
            olds = self.__before_property_value_change__(prop_name) if \
                self._has_observer() else ()
            self._notify_stack.extend(
                            map(operator.itemgetter(1), olds))

            # this is the unique place where the value is set:
            _inner_setter(self, new)

            if type(self).check_value_change(old, new):
                self._reset_property_notification(prop_name, old)

            self.notify_property_value_change(prop_name, old, val)

            # to notify dependencies
            self.__after_property_value_change__(prop_name, olds)

            del self._notify_stack[curr_frame:]
        return _setter