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.

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)))
        else:
            log.logger.warn("Ignoring notification %s: variable arguments"
                            " prevent type inference", _notified.__name__)
        return _notified

    # checks arguments
    if 0 == len(args):
        raise TypeError("decorator observe() takes one of more "
                        "arguments (0 given)")
    if any(a for a in args if not isinstance(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