示例#1
0
def test_warning_on_call_vs_hookspec_arg_mismatch():
    """Verify that is a hook is called with less arguments then defined in the
    spec that a warning is emitted.
    """
    class Spec:
        @hookspec
        def myhook(self, arg1, arg2):
            pass

    class Plugin:
        @hookimpl
        def myhook(self, arg1):
            pass

    pm = PluginManager(hookspec.project_name)
    pm.register(Plugin())
    pm.add_hookspecs(Spec())

    with warnings.catch_warnings(record=True) as warns:
        warnings.simplefilter('always')

        # calling should trigger a warning
        pm.hook.myhook(arg1=1)

        assert len(warns) == 1
        warning = warns[-1]
        assert issubclass(warning.category, Warning)
        assert "Argument(s) ('arg2',)" in str(warning.message)
示例#2
0
def test_prefix_hookimpl_dontmatch_module():
    with pytest.deprecated_call():
        pm = PluginManager(hookspec.project_name, "hello_")

    class BadPlugin(object):
        hello_module = __import__("email")

    pm.register(BadPlugin())
    pm.check_pending()
示例#3
0
def test_implprefix_deprecated():
    with pytest.deprecated_call():
        pm = PluginManager("blah", implprefix="blah_")

    class Plugin:
        def blah_myhook(self, arg1):
            return arg1

    with pytest.deprecated_call():
        pm.register(Plugin())
示例#4
0
def test_register_dynamic_attr(he_pm: PluginManager) -> None:
    class A:
        def __getattr__(self, name):
            if name[0] != "_":
                return 42
            raise AttributeError()

    a = A()
    he_pm.register(a)
    assert not he_pm.get_hookcallers(a)
示例#5
0
def test_register_mismatch_arg(he_pm: PluginManager) -> None:
    class hello:
        @hookimpl
        def he_method1(self, qlwkje):
            pass

    plugin = hello()

    with pytest.raises(PluginValidationError) as excinfo:
        he_pm.register(plugin)
    assert excinfo.value.plugin is plugin
示例#6
0
def test_register_mismatch_method(he_pm: PluginManager) -> None:
    class hello:
        @hookimpl
        def he_method_notexists(self):
            pass

    plugin = hello()

    he_pm.register(plugin)
    with pytest.raises(PluginValidationError) as excinfo:
        he_pm.check_pending()
    assert excinfo.value.plugin is plugin
示例#7
0
def test_no_hookspec(pm: PluginManager) -> None:
    """A hook with hookimpls can still be called even if no hookspec
    was registered for it (and call_pending wasn't called to check
    against it).
    """
    class Plugin:
        @hookimpl
        def hello(self, arg):
            return "Plugin.hello"

    pm.register(Plugin())

    assert pm.hook.hello(arg=10, extra=20) == ["Plugin.hello"]
示例#8
0
def test_register_hookwrapper_not_a_generator_function(
        he_pm: PluginManager) -> None:
    class hello:
        @hookimpl(hookwrapper=True)
        def he_method1(self):
            pass  # pragma: no cover

    plugin = hello()

    with pytest.raises(PluginValidationError,
                       match="generator function") as excinfo:
        he_pm.register(plugin)
    assert excinfo.value.plugin is plugin
示例#9
0
def test_subset_hook_caller(pm: PluginManager) -> None:
    class Hooks:
        @hookspec
        def he_method1(self, arg):
            pass

    pm.add_hookspecs(Hooks)

    out = []

    class Plugin1:
        @hookimpl
        def he_method1(self, arg):
            out.append(arg)

    class Plugin2:
        @hookimpl
        def he_method1(self, arg):
            out.append(arg * 10)

    class PluginNo:
        pass

    plugin1, plugin2, plugin3 = Plugin1(), Plugin2(), PluginNo()
    pm.register(plugin1)
    pm.register(plugin2)
    pm.register(plugin3)
    pm.hook.he_method1(arg=1)
    assert out == [10, 1]
    out[:] = []

    hc = pm.subset_hook_caller("he_method1", [plugin1])
    hc(arg=2)
    assert out == [20]
    out[:] = []

    hc = pm.subset_hook_caller("he_method1", [plugin2])
    hc(arg=2)
    assert out == [2]
    out[:] = []

    pm.unregister(plugin1)
    hc(arg=2)
    assert out == []
    out[:] = []

    pm.hook.he_method1(arg=1)
    assert out == [10]

    assert repr(hc) == "<_SubsetHookCaller 'he_method1'>"
示例#10
0
def _register_hooks(hook_manager: PluginManager, hooks: Iterable[Any]) -> None:
    """Register all hooks as specified in ``hooks`` with the global ``hook_manager``.

    Args:
        hook_manager: Hook manager instance to register the hooks with.
        hooks: Hooks that need to be registered.

    """
    for hooks_collection in hooks:
        # Sometimes users might call hook registration more than once, in which
        # case hooks have already been registered, so we perform a simple check
        # here to avoid an error being raised and break user's workflow.
        if not hook_manager.is_registered(hooks_collection):
            hook_manager.register(hooks_collection)
示例#11
0
    def test_argmismatch(self):
        class Api:
            def hello(self, arg):
                "api hook 1"
        pm = PluginManager("he")
        pm.addhooks(Api)

        class Plugin:
            def hello(self, argwrong):
                pass

        with pytest.raises(PluginValidationError) as exc:
            pm.register(Plugin())
        assert "argwrong" in str(exc.value)
示例#12
0
    def test_argmismatch(self):
        class Api:
            def hello(self, arg):
                "api hook 1"

        pm = PluginManager("he")
        pm.addhooks(Api)

        class Plugin:
            def hello(self, argwrong):
                pass

        with pytest.raises(PluginValidationError) as exc:
            pm.register(Plugin())
        assert "argwrong" in str(exc.value)
示例#13
0
    def test_firstresult_definition(self):
        class Api:
            def hello(self, arg):
                "api hook 1"
            hello.firstresult = True
        pm = PluginManager("he")
        pm.addhooks(Api)

        class Plugin:
            def hello(self, arg):
                return arg + 1

        pm.register(Plugin())
        res = pm.hook.hello(arg=3)
        assert res == 4
示例#14
0
文件: plugins.py 项目: inkhey/tracim
def _register_all(plugin_manager: pluggy.PluginManager,
                  plugins: typing.Dict[str, types.ModuleType]):
    # INFO - G.M - 2019-12-02 - sort plugins by name here to have predictable
    # order for plugin registration according to plugin_name.
    plugins = collections.OrderedDict(sorted(plugins.items()))
    for plugin_name, module in plugins.items():
        plugin_manager.register(module)
        try:
            entry_point = getattr(module, PLUGIN_ENTRY_POINT_NAME)
            entry_point(plugin_manager)
        except AttributeError:
            logger.warning(
                plugin_manager,
                "Cannot find plugin entry point '{}' in '{}' plugin".format(
                    PLUGIN_ENTRY_POINT_NAME, plugin_name),
            )
示例#15
0
def create_app():
    pm = PluginManager('fp')
    pm.add_hookspecs(hooks)
    pm.register(impl)
    pm.load_setuptools_entrypoints('flaskplug')

    app = Flask(__name__)
    for bp in pm.hook.fp_load_blueprints():
        if isinstance(bp, dict):
            app.register_blueprint(**bp)
        elif isinstance(bp, tuple):
            app.register_blueprint(bp[0], **bp[1])
        else:
            app.register_blueprint(bp)

    return app
示例#16
0
def test_register_historic_incompat_hookwrapper(pm: PluginManager) -> None:
    class Hooks:
        @hookspec(historic=True)
        def he_method1(self, arg):
            pass

    pm.add_hookspecs(Hooks)

    out = []

    class Plugin:
        @hookimpl(hookwrapper=True)
        def he_method1(self, arg):
            out.append(arg)

    with pytest.raises(PluginValidationError):
        pm.register(Plugin())
示例#17
0
def test_call_with_too_few_args(pm: PluginManager) -> None:
    class Hooks:
        @hookspec
        def he_method1(self, arg):
            pass

    pm.add_hookspecs(Hooks)

    class Plugin1:
        @hookimpl
        def he_method1(self, arg):
            0 / 0

    pm.register(Plugin1())
    with pytest.raises(HookCallError):
        with pytest.warns(UserWarning):
            pm.hook.he_method1()
示例#18
0
    def test_firstresult_definition(self):
        class Api:
            def hello(self, arg):
                "api hook 1"

            hello.firstresult = True

        pm = PluginManager("he")
        pm.addhooks(Api)

        class Plugin:
            def hello(self, arg):
                return arg + 1

        pm.register(Plugin())
        res = pm.hook.hello(arg=3)
        assert res == 4
示例#19
0
def test_argmismatch(pm: PluginManager) -> None:
    class Api:
        @hookspec
        def hello(self, arg):
            "api hook 1"

    pm.add_hookspecs(Api)

    class Plugin:
        @hookimpl
        def hello(self, argwrong):
            pass

    with pytest.raises(PluginValidationError) as exc:
        pm.register(Plugin())

    assert "argwrong" in str(exc.value)
示例#20
0
def test_pm_name(pm: PluginManager) -> None:
    class A:
        pass

    a1 = A()
    name = pm.register(a1, name="hello")
    assert name == "hello"
    pm.unregister(a1)
    assert pm.get_plugin("hello") is None
    assert not pm.is_registered(a1)
    assert not pm.get_plugins()
    name2 = pm.register(a1, name="hello")
    assert name2 == name
    pm.unregister(name="hello")
    assert pm.get_plugin("hello") is None
    assert not pm.is_registered(a1)
    assert not pm.get_plugins()
示例#21
0
def test_plugin_getattr_raises_errors():
    """Pluggy must be able to handle plugins which raise weird exceptions
    when getattr() gets called (#11).
    """
    class DontTouchMe:
        def __getattr__(self, x):
            raise Exception('cant touch me')

    class Module:
        pass

    module = Module()
    module.x = DontTouchMe()

    pm = PluginManager(hookspec.project_name)
    # register() would raise an error
    pm.register(module, 'donttouch')
    assert pm.get_plugin('donttouch') is module
示例#22
0
def test_prefix_hookimpl():
    pm = PluginManager(hookspec.project_name, "hello_")

    class HookSpec(object):
        @hookspec
        def hello_myhook(self, arg1):
            """ add to arg1 """

    pm.add_hookspecs(HookSpec)

    class Plugin(object):
        def hello_myhook(self, arg1):
            return arg1 + 1

    pm.register(Plugin())
    pm.register(Plugin())
    results = pm.hook.hello_myhook(arg1=17)
    assert results == [18, 18]
示例#23
0
    def test_prefix_hookimpl(self):
        pm = PluginManager(hookspec.project_name, "hello_")

        class HookSpec:
            @hookspec
            def hello_myhook(self, arg1):
                """ add to arg1 """

        pm.add_hookspecs(HookSpec)

        class Plugin:
            def hello_myhook(self, arg1):
                return arg1 + 1

        pm.register(Plugin())
        pm.register(Plugin())
        results = pm.hook.hello_myhook(arg1=17)
        assert results == [18, 18]
示例#24
0
def test_plugin_getattr_raises_errors():
    """Pluggy must be able to handle plugins which raise weird exceptions
    when getattr() gets called (#11).
    """
    class DontTouchMe(object):
        def __getattr__(self, x):
            raise Exception('cant touch me')

    class Module(object):
        pass

    module = Module()
    module.x = DontTouchMe()

    pm = PluginManager(hookspec.project_name)
    # register() would raise an error
    pm.register(module, 'donttouch')
    assert pm.get_plugin('donttouch') is module
示例#25
0
def test_set_blocked(pm: PluginManager) -> None:
    class A:
        pass

    a1 = A()
    name = pm.register(a1)
    assert name is not None
    assert pm.is_registered(a1)
    assert not pm.is_blocked(name)
    pm.set_blocked(name)
    assert pm.is_blocked(name)
    assert not pm.is_registered(a1)

    pm.set_blocked("somename")
    assert pm.is_blocked("somename")
    assert not pm.register(A(), "somename")
    pm.unregister(name="somename")
    assert pm.is_blocked("somename")
示例#26
0
def test_plugin_getattr_raises_errors() -> None:
    """Pluggy must be able to handle plugins which raise weird exceptions
    when getattr() gets called (#11).
    """
    class DontTouchMe:
        def __getattr__(self, x):
            raise Exception("can't touch me")

    class Module:
        pass

    module = Module()
    module.x = DontTouchMe()  # type: ignore[attr-defined]

    pm = PluginManager(hookspec.project_name)
    # register() would raise an error
    pm.register(module, "donttouch")
    assert pm.get_plugin("donttouch") is module
示例#27
0
def test_firstresult_returns_none(pm: PluginManager) -> None:
    """If None results are returned by underlying implementations ensure
    the multi-call loop returns a None value.
    """
    class Api:
        @hookspec(firstresult=True)
        def hello(self, arg):
            "api hook 1"

    pm.add_hookspecs(Api)

    class Plugin1:
        @hookimpl
        def hello(self, arg):
            return None

    pm.register(Plugin1())
    res = pm.hook.hello(arg=3)
    assert res is None
示例#28
0
def load_plugins(
    manager: PluginManager,
    plugins: Iterable[str] = (),
    logger: Logger = default_logger,
) -> None:
    """
    Load plugins explicitly.

    Args:
        manager: A plugin manager to load plugins.
        plugins: Plugin paths to load.
        logger: A logger.
    Raises:
        RuntimeError: when a given plugin cannot be loaded as a module.
        Exception: when loading a plugin fails.
    """
    modules = (_load_module(path, logger) for path in plugins)
    for module in modules:
        manager.register(module)
示例#29
0
def test_pm(pm: PluginManager) -> None:
    """Basic registration with objects"""
    class A:
        pass

    a1, a2 = A(), A()
    pm.register(a1)
    assert pm.is_registered(a1)
    pm.register(a2, "hello")
    assert pm.is_registered(a2)
    out = pm.get_plugins()
    assert a1 in out
    assert a2 in out
    assert pm.get_plugin("hello") == a2
    assert pm.unregister(a1) == a1
    assert not pm.is_registered(a1)

    out2 = pm.list_name_plugin()
    assert len(out2) == 1
    assert out2 == [("hello", a2)]
示例#30
0
def test_with_result_memorized(pm: PluginManager,
                               result_callback: bool) -> None:
    """Verify that ``_HookCaller._maybe_apply_history()`
    correctly applies the ``result_callback`` function, when provided,
    to the result from calling each newly registered hook.
    """
    out = []
    if not result_callback:
        callback = None
    else:

        def callback(res) -> None:
            out.append(res)

    class Hooks:
        @hookspec(historic=True)
        def he_method1(self, arg):
            pass

    pm.add_hookspecs(Hooks)

    class Plugin1:
        @hookimpl
        def he_method1(self, arg):
            return arg * 10

    pm.register(Plugin1())

    he_method1 = pm.hook.he_method1
    he_method1.call_historic(result_callback=callback, kwargs=dict(arg=1))

    class Plugin2:
        @hookimpl
        def he_method1(self, arg):
            return arg * 10

    pm.register(Plugin2())
    if result_callback:
        assert out == [10, 10]
    else:
        assert out == []
示例#31
0
def test_repr() -> None:
    class Plugin:
        @hookimpl
        def myhook(self):
            raise NotImplementedError()

    pm = PluginManager(hookspec.project_name)

    plugin = Plugin()
    pname = pm.register(plugin)
    assert repr(pm.hook.myhook.get_hookimpls()[0]) == (
        f"<HookImpl plugin_name={pname!r}, plugin={plugin!r}>")
示例#32
0
def test_repr():
    class Plugin:
        @hookimpl
        def myhook(self):
            raise NotImplementedError()

    pm = PluginManager(hookspec.project_name)

    plugin = Plugin()
    pname = pm.register(plugin)
    assert repr(pm.hook.myhook._nonwrappers[0]) == (
        "<HookImpl plugin_name=%r, plugin=%r>" % (pname, plugin))
示例#33
0
def test_register(pm: PluginManager) -> None:
    class MyPlugin:
        @hookimpl
        def he_method1(self):
            ...

    my = MyPlugin()
    pm.register(my)
    assert pm.get_plugins() == {my}
    my2 = MyPlugin()
    pm.register(my2)
    assert pm.get_plugins() == {my, my2}

    assert pm.is_registered(my)
    assert pm.is_registered(my2)
    pm.unregister(my)
    assert not pm.is_registered(my)
    assert pm.get_plugins() == {my2}

    with pytest.raises(AssertionError, match=r"not registered"):
        pm.unregister(my)
示例#34
0
    def test_hapmypath(self):
        class Api:
            def hello(self, arg):
                "api hook 1"
        pm = PluginManager("he")
        pm.addhooks(Api)
        hook = pm.hook
        assert hasattr(hook, 'hello')
        assert repr(hook.hello).find("hello") != -1

        class Plugin:
            def hello(self, arg):
                return arg + 1

        plugin = Plugin()
        pm.register(plugin)
        l = hook.hello(arg=3)
        assert l == [4]
        assert not hasattr(hook, 'world')
        pm.unregister(plugin)
        assert hook.hello(arg=3) == []
示例#35
0
def test_historic_with_subset_hook_caller(pm: PluginManager) -> None:
    class Hooks:
        @hookspec(historic=True)
        def he_method1(self, arg):
            ...

    pm.add_hookspecs(Hooks)

    out = []

    class Plugin:
        @hookimpl
        def he_method1(self, arg):
            out.append(arg)

    plugin = Plugin()
    pm.register(plugin)

    class Plugin2:
        @hookimpl
        def he_method1(self, arg):
            out.append(arg * 10)

    shc = pm.subset_hook_caller("he_method1", remove_plugins=[plugin])
    shc.call_historic(kwargs=dict(arg=1))

    pm.register(Plugin2())
    assert out == [10]

    pm.register(Plugin())
    assert out == [10, 1]
示例#36
0
def test_plugin_double_register(pm: PluginManager) -> None:
    """Registering the same plugin more then once isn't allowed"""
    pm.register(42, name="abc")
    with pytest.raises(ValueError):
        pm.register(42, name="abc")
    with pytest.raises(ValueError):
        pm.register(42, name="def")
示例#37
0
def test_prefix_hookimpl(include_hookspec):
    with pytest.deprecated_call():
        pm = PluginManager(hookspec.project_name, "hello_")

    if include_hookspec:

        class HookSpec(object):
            @hookspec
            def hello_myhook(self, arg1):
                """ add to arg1 """

        pm.add_hookspecs(HookSpec)

    class Plugin(object):
        def hello_myhook(self, arg1):
            return arg1 + 1

    with pytest.deprecated_call():
        pm.register(Plugin())
        pm.register(Plugin())
    results = pm.hook.hello_myhook(arg1=17)
    assert results == [18, 18]
示例#38
0
def test_warn_when_deprecated_specified(recwarn):
    warning = DeprecationWarning("foo is deprecated")

    class Spec(object):
        @hookspec(warn_on_impl=warning)
        def foo(self):
            pass

    class Plugin(object):
        @hookimpl
        def foo(self):
            pass

    pm = PluginManager(hookspec.project_name)
    pm.add_hookspecs(Spec)

    with pytest.warns(DeprecationWarning) as records:
        pm.register(Plugin())
    (record,) = records
    assert record.message is warning
    assert record.filename == Plugin.foo.__code__.co_filename
    assert record.lineno == Plugin.foo.__code__.co_firstlineno
示例#39
0
def test_repr():
    class Plugin:
        @hookimpl
        def myhook():
            raise NotImplementedError()

    pm = PluginManager(hookspec.project_name)

    plugin = Plugin()
    pname = pm.register(plugin)
    assert repr(pm.hook.myhook._nonwrappers[0]) == (
        "<HookImpl plugin_name=%r, plugin=%r>" % (pname, plugin)
    )
示例#40
0
def test_warn_when_deprecated_specified(recwarn):
    warning = DeprecationWarning("foo is deprecated")

    class Spec(object):
        @hookspec(warn_on_impl=warning)
        def foo(self):
            pass

    class Plugin(object):
        @hookimpl
        def foo(self):
            pass

    pm = PluginManager(hookspec.project_name)
    pm.add_hookspecs(Spec)

    with pytest.warns(DeprecationWarning) as records:
        pm.register(Plugin())
    (record, ) = records
    assert record.message is warning
    assert record.filename == Plugin.foo.__code__.co_filename
    assert record.lineno == Plugin.foo.__code__.co_firstlineno
示例#41
0
def test_hookrelay_registration_by_specname(pm: PluginManager) -> None:
    """Verify hook caller instances may also be registered by specifying a
    specname option to the hookimpl"""
    class Api:
        @hookspec
        def hello(self, arg: object) -> None:
            "api hook 1"

    pm.add_hookspecs(Api)
    hook = pm.hook
    assert hasattr(hook, "hello")
    assert len(pm.hook.hello.get_hookimpls()) == 0

    class Plugin:
        @hookimpl(specname="hello")
        def foo(self, arg: int) -> int:
            return arg + 1

    plugin = Plugin()
    pm.register(plugin)
    out = hook.hello(arg=3)
    assert out == [4]