Beispiel #1
0
def test_custom_hook_registration(request, is_internal):

    hook_name = 'some_hook'
    with pytest.raises(LookupError):
        gossip.get_hook(hook_name)

    class MyPlugin(PluginInterface):

        def get_name(self):
            return "plugin"

        @plugins.registers_on(hook_name)
        def unknown(self):
            pass
    p = MyPlugin()
    plugins.manager.install(p, activate=True, is_internal=is_internal)

    @request.addfinalizer
    def cleanup():              # pylint: disable=unused-variable
        plugins.manager.uninstall(p)

    registrations = gossip.get_hook(hook_name).get_registrations()
    assert len(registrations) == 1
    [r] = registrations
    if PY2:
        assert r.func.__func__ is MyPlugin.unknown.__func__  # pylint: disable=no-member
    else:
        assert r.func.__func__ is MyPlugin.unknown

    # make sure we deactivate properly as well
    plugins.manager.deactivate(p)
    assert not gossip.get_hook(hook_name).get_registrations()
Beispiel #2
0
def test_custom_hook_registration():

    hook_name = 'some_hook'
    with pytest.raises(LookupError):
        gossip.get_hook(hook_name)

    class MyPlugin(PluginInterface):

        def get_name(self):
            return "plugin"

        @plugins.registers_on(hook_name)
        def unknown(self):
            pass
    p = MyPlugin()
    plugins.manager.install(p, activate=True)
    registrations = gossip.get_hook(hook_name).get_registrations()
    assert 1 == len(registrations)
    [r] = registrations
    if PY2:
        assert r.func.__func__ is MyPlugin.unknown.__func__
    else:
        assert r.func.__func__ is MyPlugin.unknown

    # make sure we deactivate properly as well
    plugins.manager.deactivate(p)
    assert not gossip.get_hook(hook_name).get_registrations()
Beispiel #3
0
def test_multiple_registers_on(request):
    hook_names = ['some_hook_{}'.format(i) for i in range(2)]

    class MyPlugin(PluginInterface):

        def get_name(self):
            return "plugin"

        @plugins.registers_on(hook_names[0])
        @plugins.registers_on(hook_names[1])
        def unknown(self):
            pass

    expected_func = MyPlugin.unknown.__func__ if PY2 else MyPlugin.unknown
    p = MyPlugin()
    plugins.manager.install(p, activate=True)
    @request.addfinalizer
    def cleanup():              # pylint: disable=unused-variable
        plugins.manager.uninstall(p)

    for hook_name in hook_names:
        registrations = gossip.get_hook(hook_name).get_registrations()
        assert len(registrations) == 1
        assert registrations[0].func.__func__ is expected_func

    plugins.manager.deactivate(p)

    for hook_name in hook_names:
        assert not gossip.get_hook(hook_name).get_registrations()
Beispiel #4
0
def test_custom_hook_registration():

    hook_name = 'some_hook'
    with pytest.raises(LookupError):
        gossip.get_hook(hook_name)

    class MyPlugin(PluginInterface):

        def get_name(self):
            return "plugin"

        @plugins.registers_on(hook_name)
        def unknown(self):
            pass
    p = MyPlugin()
    plugins.manager.install(p, activate=True)
    registrations = gossip.get_hook(hook_name).get_registrations()
    assert 1 == len(registrations)
    [r] = registrations
    if PY2:
        assert r.func.__func__ is MyPlugin.unknown.__func__
    else:
        assert r.func.__func__ is MyPlugin.unknown

    # make sure we deactivate properly as well
    plugins.manager.deactivate(p)
    assert not gossip.get_hook(hook_name).get_registrations()
Beispiel #5
0
def test_register_no_op_solves_dependencies(timeline):
    timeline.register(needs=['1'], provides=['0'])
    timeline.register(needs=['2'], provides=['1'])
    assert len(gossip.get_hook(timeline.hook_name)._registrations) == 2  # pylint: disable=protected-access

    with pytest.raises(CannotResolveDependencies) as caught:
        timeline.trigger()
    assert caught.value.unmet_dependencies == set(['2'])

    timeline.get_hook().register_no_op(provides=['2'])
    # Make sure "register_no_op" is not registred as "regular" callback
    assert len(gossip.get_hook(timeline.hook_name)._registrations) == 2  # pylint: disable=protected-access
    assert len(gossip.get_hook(timeline.hook_name)._empty_regisrations) == 1  # pylint: disable=protected-access

    timeline.trigger()
Beispiel #6
0
def test_undefine(hook_name):
    gossip.define(hook_name)

    @gossip.register(hook_name)
    def handler():
        pass

    hook = gossip.get_hook(hook_name)
    hook.register_no_op()

    hook.undefine()
    gossip.define(hook_name)

    assert not gossip.get_hook(hook_name).get_registrations()
    assert not gossip.get_hook(hook_name).get_registrations(include_empty=True)
Beispiel #7
0
def test_register_no_op_solves_dependencies(timeline):
    timeline.register(needs=['1'], provides=['0'])
    timeline.register(needs=['2'], provides=['1'])
    assert len(gossip.get_hook(timeline.hook_name)._registrations) == 2  # pylint: disable=protected-access

    with pytest.raises(CannotResolveDependencies) as caught:
        timeline.trigger()
    assert caught.value.unmet_dependencies == set(['2'])

    timeline.get_hook().register_no_op(provides=['2'])
    # Make sure "register_no_op" is not registred as "regular" callback
    assert len(gossip.get_hook(timeline.hook_name)._registrations) == 2  # pylint: disable=protected-access
    assert len(gossip.get_hook(timeline.hook_name)._empty_regisrations) == 1  # pylint: disable=protected-access

    timeline.trigger()
Beispiel #8
0
 def _get_plugin_registrations(self, plugin):
     returned = []
     unknown = []
     for method_name in dir(type(plugin)):
         if method_name in _SKIPPED_PLUGIN_METHOD_NAMES:
             continue
         if method_name.startswith("_"):
             continue
         method = getattr(plugin, method_name)
         hook_name = try_get_mark(method, "register_on")
         if hook_name is None:
             expect_exists = True
             hook_name = "slash.{0}".format(method_name)
         else:
             expect_exists = False
         try:
             if expect_exists:
                 hook = gossip.get_hook(hook_name)
             else:
                 hook = gossip.hooks.get_or_create_hook(hook_name)
                 if not hook.is_defined() and hook.group.is_strict():
                     raise LookupError()
         except LookupError:
             unknown.append(hook_name)
             continue
         assert hook is not None
         returned.append((hook, method))
     if unknown:
         raise IncompatiblePlugin("Unknown hooks: {0}".format(", ".join(unknown)))
     return returned
Beispiel #9
0
def registrations():
    @gossip.register("group.hook1")
    def handler1():
        pass

    @gossip.register("group.hook2", token="token1")
    def handler2():
        pass

    @gossip.register("group2.subgroup.hook3", token="token1")
    def handler3():
        pass

    @gossip.register("group3.subgroup.subgroup2.hook4", token="token2")
    def handler4():
        pass

    handler_no_op = gossip.get_hook(
        "group3.subgroup.subgroup2.hook4").register_no_op(token="token1")

    return Munch(handler1=handler1,
                 handler2=handler2,
                 handler3=handler3,
                 handler4=handler4,
                 handler_no_op=handler_no_op)
Beispiel #10
0
def ensure_custom_hook(hook_name):
    """
    Like :func:`.add_custom_hook`, only forgives if the hook already exists
    """
    try:
        return gossip.get_hook("slash.{0}".format(hook_name))
    except LookupError:
        return _define(hook_name)
Beispiel #11
0
def ensure_custom_hook(hook_name):
    """
    Like :func:`.add_custom_hook`, only forgives if the hook already exists
    """
    try:
        return gossip.get_hook("slash.{}".format(hook_name))
    except LookupError:
        return _define(hook_name)
Beispiel #12
0
def test_needs_provides_cyclic_complex(timeline):
    timeline.register(needs=['1'], provides=['0'])
    timeline.register(needs=['2'], provides=['1'])
    timeline.register(needs=['3'], provides=['2'])
    timeline.register(needs=['4'], provides=['3'])
    with pytest.raises(CannotResolveDependencies):
        timeline.register(needs=['0'], provides=['4'])
    # make sure the cyclic registration was not added
    assert len(gossip.get_hook(timeline.hook_name)._registrations) == 4  # pylint: disable=protected-access
Beispiel #13
0
def test_needs_provides_cyclic_complex(timeline):
    timeline.register(needs=['1'], provides=['0'])
    timeline.register(needs=['2'], provides=['1'])
    timeline.register(needs=['3'], provides=['2'])
    timeline.register(needs=['4'], provides=['3'])
    with pytest.raises(CannotResolveDependencies):
        timeline.register(needs=['0'], provides=['4'])
    # make sure the cyclic registration was not added
    assert len(gossip.get_hook(timeline.hook_name)._registrations) == 4  # pylint: disable=protected-access
Beispiel #14
0
def test_forbid_muting(params):
    name_for_mute, forbid_name, is_group, is_allowed = params
    getter = gossip.get_group if is_group else gossip.get_hook
    forbidden_obj = getter(forbid_name)
    forbidden_obj.forbid_muting()

    hook = gossip.get_hook(name_for_mute)
    assert hook.can_be_muted() == is_allowed

    forbidden_obj.allow_muting()
    assert hook.can_be_muted() == is_allowed
Beispiel #15
0
def test_get_registrations_include_empty(hook_name, include_empty):
    gossip.define(hook_name)

    @gossip.register(hook_name)
    def handler():
        pass

    hook = gossip.get_hook(hook_name)
    hook.register_no_op()

    expected = 2 if include_empty else 1
    assert len(hook.get_registrations(include_empty=include_empty)) == expected
Beispiel #16
0
    def _get_plugin_registrations(self, plugin):
        returned = []
        unknown = []
        global_needs = try_get_mark(plugin, 'plugin_needs', [])
        global_provides = try_get_mark(plugin, 'plugin_provides', [])
        for method_name in dir(type(plugin)):
            if method_name in _SKIPPED_PLUGIN_METHOD_NAMES:
                continue

            method = getattr(plugin, method_name)

            if not hasattr(method, '__call__'):
                continue

            hook_name = try_get_mark(method, 'register_on', NOTHING)

            if hook_name is None:
                # asked not to register for nothing
                continue

            if hook_name is not NOTHING:
                expect_exists = False
            else:
                if method_name.startswith('_'):
                    continue
                expect_exists = True
                hook_name = "slash.{0}".format(method_name)

            plugin_needs = try_get_mark(method, 'plugin_needs', []) + global_needs
            plugin_provides = try_get_mark(method, 'plugin_provides', []) + global_provides

            try:
                if expect_exists:
                    hook = gossip.get_hook(hook_name)
                else:
                    hook = gossip.hooks.get_or_create_hook(hook_name)
                    if not hook.is_defined() and hook.group.is_strict():
                        raise LookupError()
            except LookupError:
                unknown.append(hook_name)
                continue
            assert hook is not None
            returned.append((hook, method, plugin_needs, plugin_provides))
        if unknown:
            raise IncompatiblePlugin("Unknown hooks: {0}".format(", ".join(unknown)))
        return returned
Beispiel #17
0
def registrations():
    @gossip.register("group.hook1")
    def handler1():
        pass

    @gossip.register("group.hook2", token="token1")
    def handler2():
        pass

    @gossip.register("group2.subgroup.hook3", token="token1")
    def handler3():
        pass

    @gossip.register("group3.subgroup.subgroup2.hook4", token="token2")
    def handler4():
        pass

    handler_no_op = gossip.get_hook("group3.subgroup.subgroup2.hook4").register_no_op(token="token1")

    return Munch(handler1=handler1, handler2=handler2, handler3=handler3, handler4=handler4,
                 handler_no_op=handler_no_op)
Beispiel #18
0
def test_registers_on_kwargs(class_level_needs, class_level_provides):

    needs_decorator = plugins.needs('other_requirement')
    provides_decorator = plugins.provides('another_provided_requirement')

    @slash.plugins.active  # pylint: disable=unused-variable
    @maybe_decorate(needs_decorator, class_level_needs)
    @maybe_decorate(provides_decorator, class_level_provides)
    class SamplePlugin(PluginInterface):
        def get_name(self):
            return 'sample'

        @plugins.registers_on('some.hook',
                              provides=['provided_requirement'],
                              needs=['some_requirement'],
                              tags=['tag'])
        @maybe_decorate(needs_decorator, not class_level_needs)
        @maybe_decorate(provides_decorator, not class_level_provides)
        def plugin_method(self):
            pass

    @gossip.register('some.hook',
                     provides=['some_requirement', 'other_requirement'])
    def _unused():
        pass

    gossip.trigger('some.hook')
    hook = gossip.get_hook('some.hook')
    [registration] = [
        reg for reg in hook.get_registrations()
        if reg.func.__name__ == 'plugin_method'
    ]
    assert registration.tags == {'tag'}
    assert registration.needs == frozenset(
        ['some_requirement', 'other_requirement'])
    assert registration.provides == frozenset(
        ['provided_requirement', 'another_provided_requirement'])
Beispiel #19
0
def test_get_hook(hook_name):
    with pytest.raises(LookupError):
        gossip.get_hook(hook_name)
    hook = gossip.define(hook_name)
    assert gossip.get_hook(hook_name) is hook
Beispiel #20
0
def test_hook_documentation():
    docstring = "fdkjfkdjfd"
    gossip.define("some_hook", doc=docstring)
    assert gossip.get_hook("some_hook").doc == docstring
Beispiel #21
0
    def _get_plugin_registrations(self, plugin):
        plugin_name = plugin.get_name()
        returned = []
        unknown = []
        global_needs = try_get_mark(plugin, 'plugin_needs', [])
        global_provides = try_get_mark(plugin, 'plugin_provides', [])

        has_session_end = has_session_start = False

        for method_name in dir(type(plugin)):
            if method_name in _SKIPPED_PLUGIN_METHOD_NAMES:
                continue

            method = getattr(plugin, method_name)

            if not hasattr(method, '__call__'):
                continue

            hook_name = try_get_mark(method, 'register_on', NOTHING)

            if hook_name is None:
                # asked not to register for nothing
                continue

            if not try_get_mark(method, 'register_if', True):
                continue

            if hook_name is not NOTHING:
                expect_exists = False
            else:
                if method_name.startswith('_'):
                    continue
                expect_exists = True
                hook_name = "slash.{0}".format(method_name)

            plugin_needs = try_get_mark(method, 'plugin_needs',
                                        []) + global_needs
            plugin_provides = try_get_mark(method, 'plugin_provides',
                                           []) + global_provides

            try:
                if expect_exists:
                    hook = gossip.get_hook(hook_name)
                else:
                    hook = gossip.hooks.get_or_create_hook(hook_name)
                    if not hook.is_defined() and hook.group.is_strict():
                        raise LookupError()
            except LookupError:
                unknown.append(hook_name)
                continue
            assert hook is not None
            kwargs = {
                'needs': plugin_needs,
                'provides': plugin_provides,
                'token': self._get_token(plugin_name),
            }
            if hook_name == 'slash.session_start':
                has_session_start = True
                kwargs['toggles_on'] = plugin.__toggles__['session']
            elif hook_name == 'slash.session_end':
                has_session_end = True
                kwargs['toggles_off'] = plugin.__toggles__['session']

            returned.append((hook, method, kwargs))

        if has_session_end and not has_session_start:
            returned.append(
                (gossip.get_hook('slash.session_start'), lambda: None, {
                    'toggles_on': plugin.__toggles__['session']
                }))
        if unknown:
            raise IncompatiblePlugin("Unknown hooks: {0}".format(
                ", ".join(unknown)))
        return returned
Beispiel #22
0
def get_hook_by_name(hook_name):
    """
    Returns a hook (if exists) by its name, otherwise returns None
    """
    return gossip.get_hook('slash.{0}'.format(hook_name))
Beispiel #23
0
        def get_name(self):
            return 'sample'

        @plugins.registers_on('some.hook', provides=['provided_requirement'], needs=['some_requirement'], tags=['tag'])
        @maybe_decorate(needs_decorator, not class_level_needs)
        @maybe_decorate(provides_decorator, not class_level_provides)
        def plugin_method(self):
            pass


    @gossip.register('some.hook', provides=['some_requirement', 'other_requirement'])
    def _unused():
        pass

    gossip.trigger('some.hook')
    hook = gossip.get_hook('some.hook')
    [registration] = [reg for reg in hook.get_registrations() if reg.func.__name__ == 'plugin_method']
    assert registration.tags == {'tag'}
    assert registration.needs == frozenset(['some_requirement', 'other_requirement'])
    assert registration.provides == frozenset(['provided_requirement', 'another_provided_requirement'])


def test_registers_on_with_private_methods(restore_plugins_on_cleanup, checkpoint):

    @slash.plugins.active  # pylint: disable=unused-variable
    class SamplePlugin(PluginInterface):

        def get_name(self):
            return 'sample'

        @plugins.registers_on('some_hook')
Beispiel #24
0
def get_hook_by_name(hook_name):
    """
    Returns a hook (if exists) by its name, otherwise returns None
    """
    return gossip.get_hook('slash.{}'.format(hook_name))
Beispiel #25
0
def remove_custom_hook(hook_name):
    """
    Removes a hook from the set of available hooks
    """
    gossip.get_hook("slash.{}".format(hook_name)).undefine()
    globals().pop(hook_name)
Beispiel #26
0
    def _get_plugin_registrations(self, plugin):
        plugin_name = plugin.get_name()
        returned = []
        unknown = []
        global_needs = try_get_mark(plugin, 'plugin_needs', [])
        global_provides = try_get_mark(plugin, 'plugin_provides', [])

        has_session_end = has_session_start = False

        register_no_op_hooks = set()
        if global_provides:
            register_no_op_hooks.update(
                hook.full_name
                for hook in gossip.get_group('slash').get_hooks())

        for method_name in dir(type(plugin)):
            if method_name in _SKIPPED_PLUGIN_METHOD_NAMES:
                continue

            method = getattr(plugin, method_name)

            if not hasattr(method, '__call__'):
                continue

            registration_list = try_get_mark(method, 'register_on', NOTHING)

            if registration_list is not NOTHING:
                registration_list = registration_list[:]
            else:
                if method_name.startswith('_'):
                    continue
                registration_list = [
                    RegistrationInfo("slash.{}".format(method_name),
                                     expect_exists=True)
                ]

            for registration_info in registration_list:
                if registration_info.hook_name is None:
                    # asked not to register for nothing
                    continue

                if not try_get_mark(method, 'register_if', True):
                    continue

                plugin_needs = list(
                    itertools.chain(
                        try_get_mark(method, 'plugin_needs', []), global_needs,
                        registration_info.register_kwargs.get('needs', [])))

                plugin_provides = list(
                    itertools.chain(
                        try_get_mark(method, 'plugin_provides', []),
                        global_provides,
                        registration_info.register_kwargs.get('provides', [])))

                try:
                    if registration_info.expect_exists:
                        hook = gossip.get_hook(registration_info.hook_name)
                    else:
                        hook = gossip.hooks.get_or_create_hook(
                            registration_info.hook_name)
                        if not hook.is_defined() and hook.group.is_strict():
                            raise LookupError()
                except LookupError:
                    unknown.append(registration_info.hook_name)
                    continue

                assert hook is not None
                register_no_op_hooks.discard(registration_info.hook_name)

                kwargs = registration_info.register_kwargs.copy()
                kwargs.update({
                    'needs': plugin_needs,
                    'provides': plugin_provides,
                    'token': self._get_token(plugin_name),
                })
                if registration_info.hook_name == 'slash.session_start':
                    has_session_start = True
                    kwargs['toggles_on'] = plugin.__toggles__['session']
                elif registration_info.hook_name == 'slash.session_end':
                    has_session_end = True
                    kwargs['toggles_off'] = plugin.__toggles__['session']

                returned.append((hook, method, kwargs))

        if has_session_end and not has_session_start:
            hook = gossip.get_hook('slash.session_start')
            returned.append((hook, lambda: None, {
                'toggles_on': plugin.__toggles__['session']
            }))
            register_no_op_hooks.discard(hook.full_name)

        for hook_name in register_no_op_hooks:
            hook = gossip.get_hook(hook_name)
            hook.register_no_op(provides=global_provides,
                                token=self._get_token(plugin_name))

        if unknown:
            raise IncompatiblePlugin("Unknown hooks: {}".format(
                ", ".join(unknown)))
        return returned
Beispiel #27
0
 def get_hook(self):
     return gossip.get_hook(self.hook_name)
Beispiel #28
0
def remove_custom_hook(hook_name):
    """
    Removes a hook from the set of available hooks
    """
    gossip.get_hook("slash.{0}".format(hook_name)).undefine()
    globals().pop(hook_name)
Beispiel #29
0
def test_unregister_all_on_hook(registered_hooks):
    assert all(r.works() for r in registered_hooks)
    gossip.get_hook(registered_hooks[0].name).unregister_all()
    assert not registered_hooks[0].works()
    assert all(r.works() for r in registered_hooks[1:])
Beispiel #30
0
    def _get_plugin_registrations(self, plugin):
        plugin_name = plugin.get_name()
        returned = []
        unknown = []
        global_needs = try_get_mark(plugin, 'plugin_needs', [])
        global_provides = try_get_mark(plugin, 'plugin_provides', [])

        has_session_end = has_session_start = False

        for method_name in dir(type(plugin)):
            if method_name in _SKIPPED_PLUGIN_METHOD_NAMES:
                continue

            method = getattr(plugin, method_name)

            if not hasattr(method, '__call__'):
                continue

            hook_name = try_get_mark(method, 'register_on', NOTHING)

            if hook_name is None:
                # asked not to register for nothing
                continue

            if not try_get_mark(method, 'register_if', True):
                continue

            if hook_name is not NOTHING:
                expect_exists = False
            else:
                if method_name.startswith('_'):
                    continue
                expect_exists = True
                hook_name = "slash.{0}".format(method_name)

            plugin_needs = try_get_mark(method, 'plugin_needs', []) + global_needs
            plugin_provides = try_get_mark(method, 'plugin_provides', []) + global_provides

            try:
                if expect_exists:
                    hook = gossip.get_hook(hook_name)
                else:
                    hook = gossip.hooks.get_or_create_hook(hook_name)
                    if not hook.is_defined() and hook.group.is_strict():
                        raise LookupError()
            except LookupError:
                unknown.append(hook_name)
                continue
            assert hook is not None
            kwargs = {
                'needs': plugin_needs,
                'provides': plugin_provides,
                'token': self._get_token(plugin_name),
            }
            if hook_name == 'slash.session_start':
                has_session_start = True
                kwargs['toggles_on'] = plugin.__toggles__['session']
            elif hook_name == 'slash.session_end':
                has_session_end = True
                kwargs['toggles_off'] = plugin.__toggles__['session']

            returned.append((hook, method, kwargs))

        if has_session_end and not has_session_start:
            returned.append((gossip.get_hook('slash.session_start'), lambda: None, {'toggles_on': plugin.__toggles__['session']}))
        if unknown:
            raise IncompatiblePlugin("Unknown hooks: {0}".format(", ".join(unknown)))
        return returned