Ejemplo n.º 1
0
 def test_skip_nodes(self):
     from generic.registry import Registry
     from generic.registry import SimpleAxis
     registry = Registry(('one', SimpleAxis()), ('two', SimpleAxis()),
                         ('three', SimpleAxis()))
     registry.register('foo', one=1, three=3)
     self.assertEqual(registry.lookup(1, three=3), 'foo')
Ejemplo n.º 2
0
 def test_miss(self):
     from generic.registry import Registry
     from generic.registry import SimpleAxis
     registry = Registry(('one', SimpleAxis()), ('two', SimpleAxis()),
                         ('three', SimpleAxis()))
     registry.register('foo', 1, 2)
     self.assertEqual(registry.lookup(one=1, three=3), None)
Ejemplo n.º 3
0
 def test_miss(self):
     from generic.registry import Registry
     from generic.registry import SimpleAxis
     registry = Registry(
         ('one', SimpleAxis()),
         ('two', SimpleAxis()),
         ('three', SimpleAxis())
         )
     registry.register('foo', 1, 2)
     self.assertEqual(registry.lookup(one=1, three=3), None)
Ejemplo n.º 4
0
 def test_skip_nodes(self):
     from generic.registry import Registry
     from generic.registry import SimpleAxis
     registry = Registry(
         ('one', SimpleAxis()),
         ('two', SimpleAxis()),
         ('three', SimpleAxis())
         )
     registry.register('foo', one=1, three=3)
     self.assertEqual(registry.lookup(1, three=3), 'foo')
Ejemplo n.º 5
0
    def __init__(self, argspec, params_arity):
        """ Initialize dispatcher with ``argspec`` of type
        :class:`inspect.ArgSpec` and ``params_arity`` that represent number
        params."""
        # Check if we have enough positional arguments for number of type params
        if arity(argspec) < params_arity:
            raise TypeError("Not enough positional arguments "
                            "for number of type parameters provided.")

        self.argspec = argspec
        self.params_arity = params_arity

        axis = [("arg_%d" % n, TypeAxis()) for n in range(params_arity)]
        self.registry = Registry(*axis)
Ejemplo n.º 6
0
 def test_get_registration(self):
     from generic.registry import Registry
     from generic.registry import SimpleAxis
     from generic.registry import TypeAxis
     registry = Registry(('type', TypeAxis()), ('name', SimpleAxis()))
     registry.register('one', object)
     registry.register('two', DummyA, 'foo')
     self.assertEqual(registry.get_registration(object), 'one')
     self.assertEqual(registry.get_registration(DummyA, 'foo'), 'two')
     self.assertEqual(registry.get_registration(object, 'foo'), None)
     self.assertEqual(registry.get_registration(DummyA), None)
Ejemplo n.º 7
0
 def test_bad_lookup(self):
     from generic.registry import Registry
     from generic.registry import SimpleAxis
     registry = Registry(('name', SimpleAxis()), ('grade', SimpleAxis()))
     self.assertRaises(ValueError, registry.register, 1, foo=1)
     self.assertRaises(ValueError, registry.lookup, foo=1)
     self.assertRaises(ValueError, registry.register, 1, 'foo', name='foo')
Ejemplo n.º 8
0
 def test_override(self):
     from generic.registry import Registry
     from generic.registry import SimpleAxis
     registry = Registry(('name', SimpleAxis()))
     registry.register(1, name='foo')
     registry.override(2, name='foo')
     self.assertEqual(registry.lookup('foo'), 2)
Ejemplo n.º 9
0
 def test_get_registration(self):
     from generic.registry import Registry
     from generic.registry import SimpleAxis
     from generic.registry import TypeAxis
     registry = Registry(('type', TypeAxis()),
                         ('name', SimpleAxis()))
     registry.register('one', object)
     registry.register('two', DummyA, 'foo')
     self.assertEqual(registry.get_registration(object), 'one')
     self.assertEqual(registry.get_registration(DummyA, 'foo'), 'two')
     self.assertEqual(registry.get_registration(object, 'foo'), None)
     self.assertEqual(registry.get_registration(DummyA), None)
Ejemplo n.º 10
0
    def test_one_axis_no_specificity(self):
        from generic.registry import Registry
        from generic.registry import SimpleAxis
        registry = Registry(('foo', SimpleAxis()))
        a = object()
        b = object()
        registry.register(a)
        registry.register(b, 'foo')

        self.assertEqual(registry.lookup(), a)
        self.assertEqual(registry.lookup('foo'), b)
        self.assertEqual(registry.lookup('bar'), None)
Ejemplo n.º 11
0
 def test_override(self):
     from generic.registry import Registry
     from generic.registry import SimpleAxis
     registry = Registry(('name', SimpleAxis()))
     registry.register(1, name='foo')
     registry.override(2, name='foo')
     self.assertEqual(registry.lookup('foo'), 2)
Ejemplo n.º 12
0
class Manager(object):
    """ Event manager."""
    def __init__(self):
        axes = (("event_type", TypeAxis()), )
        self.registry = Registry(*axes)

    def subscribe(self, handler, event_type):
        """ Subscribe ``handler`` to specified ``event_type``."""
        handler_set = self.registry.get_registration(event_type)
        if not handler_set:
            handler_set = self._register_handler_set(event_type)
        handler_set.handlers.add(handler)

    def unsubscribe(self, handler, event_type):
        """ Unsubscribe ``handler`` from ``event_type``."""
        handler_set = self.registry.get_registration(event_type)
        if handler_set and handler in handler_set.handlers:
            handler_set.handlers.remove(handler)

    def fire(self, event):
        """ Fire event instance."""
        handler_set = self.registry.lookup(event)
        for handler in handler_set.all_handlers:
            handler(event)

    def _register_handler_set(self, event_type):
        """ Register new handler set for ``event_type``."""
        # Collect handler sets for supertypes
        parent_handler_sets = []
        parents = event_type.__bases__
        for parent in parents:
            parent_handlers = self.registry.get_registration(parent)
            if parent_handlers is None:
                parent_handlers = self._register_handler_set(parent)
            parent_handler_sets.append(parent_handlers)

        handler_set = HandlerSet(parents=parent_handler_sets, handlers=set())
        self.registry.register(handler_set, event_type)
        return handler_set

    def subscriber(self, event_type):
        """ Decorator for subscribing decorated functions.

        Works like this:

            >>> @mymanager.subscriber(MyEvent)
            ... def mysubscriber(evt):
            ...     # handle event
            ...     return

            >>> mymanager.fire(MyEvent())

        """
        def registrator(func):
            self.subscribe(func, event_type)
            return func

        return registrator
Ejemplo n.º 13
0
class Manager(object):
    """ Event manager."""

    def __init__(self):
        axes = (("event_type", TypeAxis()),)
        self.registry = Registry(*axes)

    def subscribe(self, handler, event_type):
        """ Subscribe ``handler`` to specified ``event_type``."""
        handler_set = self.registry.get_registration(event_type)
        if not handler_set:
            handler_set = self._register_handler_set(event_type)
        handler_set.handlers.add(handler)

    def unsubscribe(self, handler, event_type):
        """ Unsubscribe ``handler`` from ``event_type``."""
        handler_set = self.registry.get_registration(event_type)
        if handler_set and handler in handler_set.handlers:
            handler_set.handlers.remove(handler)

    def fire(self, event):
        """ Fire event instance."""
        handler_set = self.registry.lookup(event)
        for handler in handler_set.all_handlers:
            handler(event)

    def _register_handler_set(self, event_type):
        """ Register new handler set for ``event_type``."""
        # Collect handler sets for supertypes
        parent_handler_sets = []
        parents = event_type.__bases__
        for parent in parents:
            parent_handlers = self.registry.get_registration(parent)
            if parent_handlers is None:
                parent_handlers = self._register_handler_set(parent)
            parent_handler_sets.append(parent_handlers)

        handler_set = HandlerSet(parents=parent_handler_sets, handlers=set())
        self.registry.register(handler_set, event_type)
        return handler_set

    def subscriber(self, event_type):
        """ Decorator for subscribing decorated functions.

        Works like this:

            >>> @mymanager.subscriber(MyEvent)
            ... def mysubscriber(evt):
            ...     # handle event
            ...     return

            >>> mymanager.fire(MyEvent())

        """
        def registrator(func):
            self.subscribe(func, event_type)
            return func
        return registrator
Ejemplo n.º 14
0
    def test_one_axis_no_specificity(self):
        from generic.registry import Registry
        from generic.registry import SimpleAxis
        registry = Registry(('foo', SimpleAxis()))
        a = object()
        b = object()
        registry.register(a)
        registry.register(b, 'foo')

        self.assertEqual(registry.lookup(), a)
        self.assertEqual(registry.lookup('foo'), b)
        self.assertEqual(registry.lookup('bar'), None)
Ejemplo n.º 15
0
    def __init__(self, argspec, params_arity):
        """ Initialize dispatcher with ``argspec`` of type
        :class:`inspect.ArgSpec` and ``params_arity`` that represent number
        params."""
        # Check if we have enough positional arguments for number of type params
        if arity(argspec) < params_arity:
            raise TypeError("Not enough positional arguments "
                            "for number of type parameters provided.")

        self.argspec = argspec
        self.params_arity = params_arity

        axis = [("arg_%d" % n, TypeAxis()) for n in range(params_arity)]
        self.registry = Registry(*axis)
Ejemplo n.º 16
0
class Manager(object):
    """ Event manager

    Provides API for subscribing for and firing events. There's also global
    event manager instantiated at module level with functions
    :func:`.subscribe`, :func:`.fire` and decorator :func:`.subscriber` aliased
    to corresponding methods of class.
    """
    def __init__(self):
        axes = (("event_type", TypeAxis()), )
        self.registry = Registry(*axes)

    def subscribe(self, handler, event_type):
        """ Subscribe ``handler`` to specified ``event_type``"""
        handler_set = self.registry.get_registration(event_type)
        if not handler_set:
            handler_set = self._register_handler_set(event_type)
        handler_set.handlers.add(handler)

    def unsubscribe(self, handler, event_type):
        """ Unsubscribe ``handler`` from ``event_type``"""
        handler_set = self.registry.get_registration(event_type)
        if handler_set and handler in handler_set.handlers:
            handler_set.handlers.remove(handler)

    def fire(self, event):
        """ Fire ``event``

        All subscribers will be executed with no determined order.
        """
        handler_set = self.registry.lookup(event)
        for handler in handler_set.all_handlers:
            handler(event)

    def _register_handler_set(self, event_type):
        """ Register new handler set for ``event_type``."""
        # Collect handler sets for supertypes
        parent_handler_sets = []
        parents = event_type.__bases__
        for parent in parents:
            parent_handlers = self.registry.get_registration(parent)
            if parent_handlers is None:
                parent_handlers = self._register_handler_set(parent)
            parent_handler_sets.append(parent_handlers)

        handler_set = HandlerSet(parents=parent_handler_sets, handlers=set())
        self.registry.register(handler_set, event_type)
        return handler_set

    def subscriber(self, event_type):
        """ Decorator for subscribing handlers

        Works like this:

            >>> @mymanager.subscriber(MyEvent)
            ... def mysubscriber(evt):
            ...     # handle event
            ...     return

            >>> mymanager.fire(MyEvent())

        """
        def registrator(func):
            self.subscribe(func, event_type)
            return func

        return registrator
Ejemplo n.º 17
0
class FunctionDispatcher(object):
    """ Multidispatcher for functions

    This object dispatch calls to function by its argument types. Usually it is
    produced by :func:`.multifunction` decorator.

    You should not manually create objects of this type.
    """

    def __init__(self, argspec, params_arity):
        """ Initialize dispatcher with ``argspec`` of type
        :class:`inspect.ArgSpec` and ``params_arity`` that represent number
        params."""
        # Check if we have enough positional arguments for number of type params
        if arity(argspec) < params_arity:
            raise TypeError("Not enough positional arguments "
                            "for number of type parameters provided.")

        self.argspec = argspec
        self.params_arity = params_arity

        axis = [("arg_%d" % n, TypeAxis()) for n in range(params_arity)]
        self.registry = Registry(*axis)

    def check_rule(self, rule, *argtypes):
        # Check if we have the right number of parametrized types
        if len(argtypes) != self.params_arity:
            raise TypeError("Wrong number of type parameters.")

        # Check if we have the same argspec (by number of args)
        rule_argspec = inspect.getargspec(rule)
        if not is_equalent_argspecs(rule_argspec, self.argspec):
            raise TypeError("Rule does not conform "
                            "to previous implementations.")

    def register_rule(self, rule, *argtypes):
        """ Register new ``rule`` for ``argtypes``."""
        self.check_rule(rule, *argtypes)
        self.registry.register(rule, *argtypes)

    def override_rule(self, rule, *argtypes):
        """ Override ``rule`` for ``argtypes``."""
        self.check_rule(rule, *argtypes)
        self.registry.override(rule, *argtypes)

    def lookup_rule(self, *args):
        """ Lookup rule by ``args``. Returns None if no rule was found."""
        args = args[:self.params_arity]
        rule = self.registry.lookup(*args)
        if rule is None:
            raise TypeError("No available rule found for %r" % (args,))
        return rule

    def when(self, *argtypes):
        """ Decorator for registering new case for multifunction

        New case will be registered for types identified by ``argtypes``. The
        length of ``argtypes`` should be equal to the length of ``argtypes``
        argument were passed corresponding :func:`.multifunction` call, which
        also indicated the number of arguments multifunction dispatches on.
        """
        def register_rule(func):
            self.register_rule(func, *argtypes)
            return self
        return register_rule

    @property
    def otherwise(self):
        """ Decorator which registeres "catch-all" case for multifunction"""
        def register_rule(func):
            self.register_rule(func, [object]*self.params_arity)
            return self
        return register_rule

    def override(self, *argtypes):
        """ Decorator for overriding case for ``argtypes``"""
        def override_rule(func):
            self.override_rule(func, *argtypes)
            return self
        return override_rule

    def __call__(self, *args, **kwargs):
        """ Dispatch call to appropriate rule."""
        rule = self.lookup_rule(*args)
        return rule(*args, **kwargs)
Ejemplo n.º 18
0
 def test_conflict_error(self):
     from generic.registry import Registry
     from generic.registry import SimpleAxis
     registry = Registry(('name', SimpleAxis()))
     registry.register(object(), name='foo')
     self.assertRaises(ValueError, registry.register, object(), 'foo')
Ejemplo n.º 19
0
 def __init__(self):
     axes = (("event_type", TypeAxis()), )
     self.registry = Registry(*axes)
Ejemplo n.º 20
0
class Manager(object):
    """ Event manager

    Provides API for subscribing for and firing events. There's also global
    event manager instantiated at module level with functions
    :func:`.subscribe`, :func:`.fire` and decorator :func:`.subscriber` aliased
    to corresponding methods of class.
    """

    def __init__(self):
        axes = (("event_type", TypeAxis()),)
        self.registry = Registry(*axes)

    def subscribe(self, handler, event_type):
        """ Subscribe ``handler`` to specified ``event_type``"""
        handler_set = self.registry.get_registration(event_type)
        if not handler_set:
            handler_set = self._register_handler_set(event_type)
        handler_set.handlers.add(handler)

    def unsubscribe(self, handler, event_type):
        """ Unsubscribe ``handler`` from ``event_type``"""
        handler_set = self.registry.get_registration(event_type)
        if handler_set and handler in handler_set.handlers:
            handler_set.handlers.remove(handler)

    def fire(self, event):
        """ Fire ``event``

        All subscribers will be executed with no determined order.
        """
        handler_set = self.registry.lookup(event)
        for handler in handler_set.all_handlers:
            handler(event)

    def _register_handler_set(self, event_type):
        """ Register new handler set for ``event_type``."""
        # Collect handler sets for supertypes
        parent_handler_sets = []
        parents = event_type.__bases__
        for parent in parents:
            parent_handlers = self.registry.get_registration(parent)
            if parent_handlers is None:
                parent_handlers = self._register_handler_set(parent)
            parent_handler_sets.append(parent_handlers)

        handler_set = HandlerSet(parents=parent_handler_sets, handlers=set())
        self.registry.register(handler_set, event_type)
        return handler_set

    def subscriber(self, event_type):
        """ Decorator for subscribing handlers

        Works like this:

            >>> @mymanager.subscriber(MyEvent)
            ... def mysubscriber(evt):
            ...     # handle event
            ...     return

            >>> mymanager.fire(MyEvent())

        """
        def registrator(func):
            self.subscribe(func, event_type)
            return func
        return registrator
Ejemplo n.º 21
0
 def test_lookup_too_many_keys(self):
     from generic.registry import Registry
     from generic.registry import SimpleAxis
     registry = Registry(('name', SimpleAxis()))
     self.assertRaises(ValueError, registry.lookup, 'one', 'two')
Ejemplo n.º 22
0
    def test_two_axes(self):
        from generic.registry import Registry
        from generic.registry import SimpleAxis
        from generic.registry import TypeAxis
        registry = Registry(('type', TypeAxis()), ('name', SimpleAxis()))

        target1 = Target('one')
        registry.register(target1, object)

        target2 = Target('two')
        registry.register(target2, DummyA)

        target3 = Target('three')
        registry.register(target3, DummyA, 'foo')

        context1 = object()
        self.assertEqual(registry.lookup(context1), target1)

        context2 = DummyB()
        self.assertEqual(registry.lookup(context2), target2)
        self.assertEqual(registry.lookup(context2, 'foo'), target3)

        target4 = object()
        registry.register(target4, DummyB)

        self.assertEqual(registry.lookup(context2), target4)
        self.assertEqual(registry.lookup(context2, 'foo'), target3)
Ejemplo n.º 23
0
    def test_two_axes(self):
        from generic.registry import Registry
        from generic.registry import SimpleAxis
        from generic.registry import TypeAxis
        registry = Registry(('type', TypeAxis()),
                            ('name', SimpleAxis()))

        target1 = Target('one')
        registry.register(target1, object)

        target2 = Target('two')
        registry.register(target2, DummyA)

        target3 = Target('three')
        registry.register(target3, DummyA, 'foo')

        context1 = object()
        self.assertEqual(registry.lookup(context1), target1)

        context2 = DummyB()
        self.assertEqual(registry.lookup(context2), target2)
        self.assertEqual(registry.lookup(context2, 'foo'), target3)

        target4 = object()
        registry.register(target4, DummyB)

        self.assertEqual(registry.lookup(context2), target4)
        self.assertEqual(registry.lookup(context2, 'foo'), target3)
Ejemplo n.º 24
0
 def test_conflict_error(self):
     from generic.registry import Registry
     from generic.registry import SimpleAxis
     registry = Registry(('name', SimpleAxis()))
     registry.register(object(), name='foo')
     self.assertRaises(ValueError, registry.register, object(), 'foo')
Ejemplo n.º 25
0
class FunctionDispatcher(object):
    """ Multidispatcher for functions

    This object dispatch calls to function by its argument types. Usually it is
    produced by :func:`.multifunction` decorator.

    You should not manually create objects of this type.
    """
    def __init__(self, argspec, params_arity):
        """ Initialize dispatcher with ``argspec`` of type
        :class:`inspect.ArgSpec` and ``params_arity`` that represent number
        params."""
        # Check if we have enough positional arguments for number of type params
        if arity(argspec) < params_arity:
            raise TypeError("Not enough positional arguments "
                            "for number of type parameters provided.")

        self.argspec = argspec
        self.params_arity = params_arity

        axis = [("arg_%d" % n, TypeAxis()) for n in range(params_arity)]
        self.registry = Registry(*axis)

    def check_rule(self, rule, *argtypes):
        # Check if we have the right number of parametrized types
        if len(argtypes) != self.params_arity:
            raise TypeError("Wrong number of type parameters.")

        # Check if we have the same argspec (by number of args)
        rule_argspec = inspect.getargspec(rule)
        if not is_equalent_argspecs(rule_argspec, self.argspec):
            raise TypeError("Rule does not conform "
                            "to previous implementations.")

    def register_rule(self, rule, *argtypes):
        """ Register new ``rule`` for ``argtypes``."""
        self.check_rule(rule, *argtypes)
        self.registry.register(rule, *argtypes)

    def override_rule(self, rule, *argtypes):
        """ Override ``rule`` for ``argtypes``."""
        self.check_rule(rule, *argtypes)
        self.registry.override(rule, *argtypes)

    def lookup_rule(self, *args):
        """ Lookup rule by ``args``. Returns None if no rule was found."""
        args = args[:self.params_arity]
        rule = self.registry.lookup(*args)
        if rule is None:
            raise TypeError("No available rule found for %r" % (args, ))
        return rule

    def when(self, *argtypes):
        """ Decorator for registering new case for multifunction

        New case will be registered for types identified by ``argtypes``. The
        length of ``argtypes`` should be equal to the length of ``argtypes``
        argument were passed corresponding :func:`.multifunction` call, which
        also indicated the number of arguments multifunction dispatches on.
        """
        def register_rule(func):
            self.register_rule(func, *argtypes)
            return self

        return register_rule

    @property
    def otherwise(self):
        """ Decorator which registeres "catch-all" case for multifunction"""
        def register_rule(func):
            self.register_rule(func, [object] * self.params_arity)
            return self

        return register_rule

    def override(self, *argtypes):
        """ Decorator for overriding case for ``argtypes``"""
        def override_rule(func):
            self.override_rule(func, *argtypes)
            return self

        return override_rule

    def __call__(self, *args, **kwargs):
        """ Dispatch call to appropriate rule."""
        rule = self.lookup_rule(*args)
        return rule(*args, **kwargs)
Ejemplo n.º 26
0
 def __init__(self):
     axes = (("event_type", TypeAxis()),)
     self.registry = Registry(*axes)
Ejemplo n.º 27
0
class FunctionDispatcher(Generic[T]):
    """ Multidispatcher for functions

    This object dispatch calls to function by its argument types. Usually it is
    produced by :func:`.multidispatch` decorator.

    You should not manually create objects of this type.
    """

    registry: Registry[T]

    def __init__(self, argspec: inspect.FullArgSpec,
                 params_arity: int) -> None:
        """ Initialize dispatcher with ``argspec`` of type
        :class:`inspect.ArgSpec` and ``params_arity`` that represent number
        params."""
        # Check if we have enough positional arguments for number of type params
        if _arity(argspec) < params_arity:
            raise TypeError("Not enough positional arguments "
                            "for number of type parameters provided.")

        self.argspec = argspec
        self.params_arity = params_arity

        axis = [(f"arg_{n:d}", TypeAxis()) for n in range(params_arity)]
        self.registry = Registry(*axis)

    def check_rule(self, rule: T, *argtypes: KeyType) -> None:
        # Check if we have the right number of parametrized types
        if len(argtypes) != self.params_arity:
            raise TypeError(
                f"Wrong number of type parameters: have {len(argtypes)}, expected {self.params_arity}."
            )

        # Check if we have the same argspec (by number of args)
        rule_argspec = inspect.getfullargspec(rule)
        left_spec = tuple(x and len(x) or 0 for x in rule_argspec[:4])
        right_spec = tuple(x and len(x) or 0 for x in self.argspec[:4])
        if left_spec != right_spec:
            raise TypeError(
                f"Rule does not conform to previous implementations: {left_spec} != {right_spec}."
            )

    def register_rule(self, rule: T, *argtypes: KeyType) -> None:
        """ Register new ``rule`` for ``argtypes``."""
        self.check_rule(rule, *argtypes)
        self.registry.register(rule, *argtypes)

    def register(self, *argtypes: KeyType) -> Callable[[T], T]:
        """ Decorator for registering new case for multidispatch

        New case will be registered for types identified by ``argtypes``. The
        length of ``argtypes`` should be equal to the length of ``argtypes``
        argument were passed corresponding :func:`.multidispatch` call, which
        also indicated the number of arguments multidispatch dispatches on.
        """
        def register_rule(func: T) -> T:
            self.register_rule(func, *argtypes)
            return func

        return register_rule

    def __call__(self, *args: Any, **kwargs: Any) -> Any:
        """ Dispatch call to appropriate rule."""
        trimmed_args = args[:self.params_arity]
        rule = self.registry.lookup(*trimmed_args)
        if not rule:
            print(self.registry._tree)
            raise TypeError(f"No available rule found for {trimmed_args!r}")
        return rule(*args, **kwargs)
Ejemplo n.º 28
0
class Manager:
    """ Event manager

    Provides API for subscribing for and firing events. There's also global
    event manager instantiated at module level with functions
    :func:`.subscribe`, :func:`.handle` and decorator :func:`.subscriber` aliased
    to corresponding methods of class.
    """

    registry: Registry[HandlerSet]

    def __init__(self) -> None:
        axes = (("event_type", TypeAxis()), )
        self.registry = Registry(*axes)

    def subscribe(self, handler: Handler, event_type: Type[Event]) -> None:
        """ Subscribe ``handler`` to specified ``event_type``"""
        handler_set = self.registry.get_registration(event_type)
        if handler_set is None:
            handler_set = self._register_handler_set(event_type)
        handler_set.add(handler)

    def unsubscribe(self, handler: Handler, event_type: Type[Event]) -> None:
        """ Unsubscribe ``handler`` from ``event_type``"""
        handler_set = self.registry.get_registration(event_type)
        if handler_set and handler in handler_set:
            handler_set.remove(handler)

    def handle(self, event: Event) -> None:
        """ Fire ``event``

        All subscribers will be executed with no determined order.
        """
        handler_sets = self.registry.query(event)
        for handler_set in handler_sets:
            if handler_set:
                for handler in set(handler_set):
                    handler(event)

    def _register_handler_set(self, event_type: Type[Event]) -> HandlerSet:
        """ Register new handler set for ``event_type``.
        """
        handler_set: HandlerSet = set()
        self.registry.register(handler_set, event_type)
        return handler_set

    def subscriber(self,
                   event_type: Type[Event]) -> Callable[[Handler], Handler]:
        """ Decorator for subscribing handlers

        Works like this:

            >>> mymanager = Manager()
            >>> class MyEvent():
            ...     pass
            >>> @mymanager.subscriber(MyEvent)
            ... def mysubscriber(evt):
            ...     # handle event
            ...     return

            >>> mymanager.handle(MyEvent())

        """
        def registrator(func: Handler) -> Handler:
            self.subscribe(func, event_type)
            return func

        return registrator