Example #1
0
    def __init__(self):
        for signal in self.__signals__.values():
            ctl = signal.default_control(self)
            setattr(self, "_%s_ctl" % pyname(signal.name), ctl)
            if not isinstance(signal, DelegateSignal):
                setattr(self, "_%s_book" % pyname(signal.name), ctl._runner)

            # Registra os métodos criados pelo mecanismo on_signal...
            auto_method = getattr(self, "on_" + pyname(signal.name), None)
            if auto_method is not None:
                kwargs = {"owner": self}
                if signal._num_filters == 0:
                    self.listen(signal.name, auto_method, **kwargs)
                else:
                    args = (None,) * signal._num_filters
                    args += (auto_method,)
                    self.listen(signal.name, *args, **kwargs)

            # Registra os métodos criados pelo mecanismo @listen
            marked_listen = self.__marked_listen__.get(signal.name, [])
            for (func_name, args, kwargs) in marked_listen:
                handler = getattr(self, func_name)
                filters = args[: signal._num_filters] or (None,) * signal._num_filters
                args = args[signal._num_filters :]
                args = filters + (handler,) + args
                kwargs = kwargs.copy()
                kwargs["owner"] = self
                self.listen(signal.name, *args, **kwargs)
Example #2
0
    def new_signal(self, name, *filters, **kwds):
        '''Cria um novo sinal para o evento global.

        Possui uma assinatura variável onde o tipo de sinal é escolhido
        automaticamente a partir dos argumentos

        signal('foo', num_args=1)
            Sinal simples chamado 'foo' com apenas 1 argumento.

        signal('foo', 'bar')
            Sinal filtrado chamado 'foo' que requer um argumento extra 'bar'

        signal('foo', delegate_to=obj)
            Delega sinal 'foo' para o objeto fornecido em *delegate_to*
        '''

        cls = type(self)
        attr = pyname(name)

        # Organiza delegações e salva delegado em atributo
        if 'delegate_to' in kwds:
            delegate_obj = kwds['delegate_to']
            try:
                delegate_attr = self._delegates[id(delegate_obj)]
            except KeyError:
                delegate_attr = '_delegate_%s' % self._delegate_idx
                self._delegates[id(delegate_obj)] = delegate_attr
                self._delegate_idx += 1
            setattr(self, delegate_attr, delegate_obj)
            kwds['delegate_to'] = delegate_attr

        # Cria sinal
        signal_obj = signal(name, *filters, **kwds)
        if name in cls.__signals__:
            raise ValueError('global signal already exists: %r' % name)
        cls.__signals__[attr] = signal_obj
        setattr(cls, pyname(name), signal_obj)

        # Cria os métodos do tipo listen_<> e tipo trigger_<>
        lname = 'listen_' + attr
        tname = 'trigger_' + attr
        listen_method = signal_obj._factory_listen_method()
        trigger_method = signal_obj._factory_trigger_method()
        setattr(cls, lname, listen_method)
        setattr(cls, tname, trigger_method)

        # Inicializa SignalCtl
        ctl = signal_obj.default_control()
        setattr(self, '_%s_ctl' % attr, ctl)
        if not isinstance(signal, DelegateSignal):
            setattr(self, '_%s_book' % attr, ctl._runner)
Example #3
0
    def _factory_trigger_method(self):
        signal = self  # não confundir com o self da função fabricada!
        attr_name = pyname('_%s_book' % signal.name)

        # Especializamos para 0, 1 ou 2 argumentos por questões de performance
        if signal.num_args == 0:
            def trigger_method(self, key):
                book = getattr(self, attr_name)
                kbook = book.get(key, None)
                if kbook is not None:
                    for wrapped_func in kbook:
                        wrapped_func()
                else:
                    gen_book = book.get(None, None)
                    if gen_book is not None:
                        for func in gen_book:
                            func(key)

        elif signal.num_args == 1:
            def trigger_method(self, key, arg):
                book = getattr(self, attr_name)
                kbook = book.get(key, None)
                if kbook is not None:
                    for wrapped_func in kbook:
                        wrapped_func(arg)
                else:
                    gen_book = book.get(None, None)
                    if gen_book is not None:
                        for func in gen_book:
                            func(key, arg)

        else:
            def trigger_method(self, key, *args):
                if len(args) != signal.num_args:
                    raise TypeError('expected %s arguments' % self.num_args)

                book = getattr(self, attr_name)
                kbook = book.get(key, None)
                if kbook is not None:
                    for wrapped_func in kbook:
                        wrapped_func(*args)
                else:
                    gen_book = book.get(None, None)
                    if gen_book is not None:
                        for func in gen_book:
                            func(key, *args)

        trigger_method.__name__ = 'trigger_' + pyname(signal.name)
        # trigger_method.__doc__ = (trigger_method.__doc__
        #                            % {'signal': signal.name})
        return trigger_method
Example #4
0
    def _populate_namespace(cls, name, bases, ns):
        """Retorna o namespace ns acrescentado dos métodos trigger_* e
        listen_* apropriados para a classe em questão"""

        ns = dict(ns)

        # Lê os sinais e monta um dicionário de sinais
        signals = {}
        for C in reversed(bases):
            signals.update(getattr(C, "__signals__", {}))
        for attr, value in ns.items():
            if isinstance(value, Signal):
                signals[attr] = value
        ns["__signals__"] = signals

        # Cria os métodos do tipo listen_* e tipo trigger_*
        for signal in signals.values():
            lname = "listen_" + pyname(signal.name)
            tname = "trigger_" + pyname(signal.name)
            ns["_" + lname] = signal._factory_listen_method()
            if lname not in ns:
                ns[lname] = ns["_" + lname]
            ns["_" + tname] = signal._factory_trigger_method()
            if tname not in ns:
                ns[tname] = ns["_" + tname]

        # Escaneia todos os métodos decorados com @listen
        listen = {}
        for C in reversed(bases):
            listen.update(getattr(C, "__marked_listen__", {}))
        for attr, value in ns.items():
            if hasattr(value, "_listen_args"):
                for name, args, kwds in getattr(value, "_listen_args"):
                    L = listen.setdefault(name, [])
                    L.append((attr, args, kwds))

        ns["__marked_listen__"] = listen

        # Atribui valores de slots, caso necessário
        if "__slots__" in ns:
            slots = list(ns["__slots__"])
            for signal_name, signal in signals.items():
                if not isinstance(signal, DelegateSignal):
                    slots.append("_%s_ctl" % signal_name)
                    slots.append("_%s_book" % signal_name)
            ns["__slots__"] = slots

        return ns
Example #5
0
    def _factory_trigger_method(self):
        signal = self  # não confundir com o self da função fabricada!
        attr_name = pyname('_%s_book' % signal.name)

        # Especializamos para 0, 1 ou 2 argumentos por questões de performance
        if signal.num_args == 0:
            def trigger_method(self):
                book = getattr(self, attr_name)
                for wrapped_func in book:
                    wrapped_func()

        elif signal.num_args == 1:
            def trigger_method(self, arg):
                book = getattr(self, attr_name)
                for wrapped_func in book:
                    wrapped_func(arg)

        elif signal.num_args == 2:
            def trigger_method(self, arg1, arg2):
                book = getattr(self, attr_name)
                for wrapped_func in book:
                    wrapped_func(arg1, arg2)

        else:
            def trigger_method(self, *args):
                if len(args) != signal.num_args:
                    raise TypeError('expected %s arguments' % self.num_args)

                book = getattr(self, attr_name)
                for wrapped_func in book:
                    wrapped_func(*args)

        trigger_method.__name__ = 'trigger_' + pyname(signal.name)
        # trigger_method.__doc__ = trigger_method.__doc__ % \
        #                         {'signal': signal.name}
        return trigger_method
Example #6
0
    def listen(self, signal, *args, **kwds):
        """Registra um handler para um determinado sinal.

        A assinatura correta para esta função depende do tipo de sinal
        considerado. Para sinais simples, basta utilizar::

            obj.listen(<nome do sinal>, <handler>)

        Sinais filtrados (aqueles que pedem um ou mais argumentos adicionais),
        devem ser registrados como::

            obj.listen(<nome do sinal>, <filtro>, <handler>)

        Opcionalmente, é possível acrescentar argumentos por nome ou posição
        que serão passados automaticamente para o handler quando o sinal for
        acionado.
        """

        implementation = getattr(self, "listen_" + pyname(signal))
        return implementation(*args, **kwds)
Example #7
0
        def listen_method(self, *args, **kwargs):
            '''vsds %(signal)s'''

            # Confere argumentos de entrada
            args_ = kwargs.pop('args', None)
            kwargs_ = kwargs.pop('kwargs', None)
            owner = kwargs.pop('owner', None)
            if args_:
                args = args_
            if kwargs_:
                kwargs = kwargs_

            # Extrai os filtros, caso necessário
            filter_args = args[:signal._num_filters]
            try:
                handler = args[signal._num_filters]
            except IndexError:
                handler = None
            args = args[signal._num_filters + 1:]

            if args_ is not None and args:
                raise TypeError('cannot specify the args parameter and also '
                                'insert positional arguments')
            if kwargs_ is not None and kwargs:
                raise TypeError('cannot specify the kwargs parameter and also '
                                'insert keyword arguments')

            # Caso handler=None, estamos chamando o método listen na versão
            # de decorador
            if handler is None:
                def decorator(func):
                    args_ = filter_args + (func,)
                    kwargs_ = {'args': args, 'kwargs': kwargs, 'owner': owner}
                    return listen_method(self, *args_, **kwargs_)
                return decorator

            # Registra nas listas de controle
            wrapped = wrap_handler(
                handler, args, kwargs, pre_args=signal.num_args)
            ctl = getattr(self, '_%s_ctl' % pyname(signal.name))

            if signal._num_filters == 0:
                idx = len(ctl._data)
                elem = ControlElem(idx, owner, wrapped, handler, args, kwargs)
                ctl._runner.append(wrapped)
                ctl._data.append(elem)
                return idx

            elif signal._num_filters == 1:
                key = filter_args[0]
                ids = {}

                if key is None:
                    # Registra como handler de todas os filtros no livro
                    for k in ctl._runner:
                        if k is None:
                            continue
                        wrapped_i = wrap_handler(handler, (k,) + args, kwargs,
                                                 pre_args=signal.num_args)
                        ids[k] = listen_method(self, k, wrapped_i)

                    # Cria um elemento de controle substituindo o campo
                    # "wrapped" pelo dicionário das ids em cada filtro
                    control = ctl._data.setdefault(None, [])
                    book = ctl._runner.setdefault(None, [])
                    idx = len(control)
                    elem = ControlElem(idx, owner, ids, handler, args, kwargs)
                    control.append(elem)
                    book.append(
                        wrap_handler(
                            handler, args, kwargs, pre_args=signal.num_args))

                    return (None, idx)
                else:
                    try:
                        idx = len(ctl._data[key])
                    except KeyError:
                        ctl._data[key] = []
                        ctl._runner[key] = []

                        for ctl_e in ctl._data.get(None, []):
                            wrapped_i = wrap_handler(
                                ctl_e.handler, (key,) + ctl_e.args,
                                ctl_e.kwargs, signal.num_args)
                            ctl_e.wrapped[key] = listen_method(
                                self, key, wrapped_i)

                        idx = len(ctl._data[key])

                    elem = ControlElem(
                        idx, owner, wrapped, handler, args, kwargs)
                    ctl._runner[key].append(wrapped)
                    ctl._data[key].append(elem)
                    return key, idx

            else:
                book = ctl._runner[filter_args]
                control = ctl._data[filter_args]
            raise RuntimeError
Example #8
0
 def __init__(self, name, num_args=0):
     self.name = name
     self.num_args = num_args
     self._num_filters = 0
     self._ctl_name = '_%s_ctl' % pyname(self.name)
Example #9
0
    def trigger(self, signal, *args, **kwds):
        """Aciona o sinal com os argumentos fornecidos."""

        implementation = getattr(self, "trigger_" + pyname(signal))
        return implementation(*args, **kwds)