目录
  • 实践环境
  • 例1 注册类函数为插件函数
  • 例2 注册模块函数为插件函数
    • myhookspec.py
    • myhookimpl.py
    • other.py
    • example.py
  • 例3:自定义插件类实现hook函数免@hookimpl装饰器
    • myhookspec.py
    • other.py
    • example.py
  • 参考连接

    代码为例进行说明

    实践环境

    Python 3.6.5

    pluggy 0.13.0

    例1 注册类函数为插件函数

    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
    import pluggy
    hookspec = pluggy.HookspecMarker("myproject")  # hook 标签 用于标记hook
    hookimpl = pluggy.HookimplMarker("myproject")  # hook 实现标签 用于标记hook的一个或多个实现
    class MySpec(object):
        """hook 集合"""
        @hookspec
        def myhook(self, arg1, arg2):
            pass
        @hookspec
        def my_hook_func1(self, arg1, arg2):
            pass
        @hookspec
        def my_hook_func2(self, arg1, arg2):
            pass
    # 插件类
    class Plugin_1(object):
        """hook实现类1"""
        @hookimpl
        def myhook(self, arg1, arg2):
            print("Plugin_1.myhook called")
            return arg1 + arg2
        @hookimpl
        def my_hook_func2(self, arg1, arg2):
            print("Plugin_1.my_hook_func2 called, args:", arg1, arg2)
        def my_hook_func3(self, arg1, arg2):
            print("Plugin_1.my_hook_func3 called, args:", arg1, arg2)
    class Plugin_2(object):
        """hook实现类2"""
        @hookimpl
        def myhook(self, arg1, arg2):
            print("Plugin_2.myhook called")
            return arg1 - arg2
        @hookimpl
        def my_hook_func2(self, arg1, arg2):
            print("Plugin_2.my_hook_func2, args:", arg1, arg2)
    # 初始化 PluginManager
    pm = pluggy.PluginManager("myproject")
    # 登记hook集合(hook函数声明)
    pm.add_hookspecs(MySpec)
    # 注册插件(hook函数实现)
    pm.register(Plugin_1())
    pm.register(Plugin_2())
    # 调用自定义hook
    results = pm.hook.myhook(arg1=1, arg2=2) # 调用两个插件类中的同名hook函数 # 后注册的插件中的函数会先被调用
    print(results) # 输出 [-1, 3]
    results = pm.hook.my_hook_func1(arg1="name", arg2="shouke")
    print(results)
    pm.hook.my_hook_func2(arg1="addr", arg2="sz")
    

    运行结果

    Plugin_2.myhook called
    Plugin_1.myhook called
    [-1, 3]
    []
    Plugin_2.my_hook_func2, args: addr sz
    Plugin_1.my_hook_func2 called, args: addr sz

    例2 注册模块函数为插件函数

    myhookspec.pymyhookimpl.pyother.pyexample.py位于同一包目录下

    myhookspec.py

    import pluggy
    hookspec = pluggy.HookspecMarker("myproject")  # hook 标签 用于标记hook
    hookimpl = pluggy.HookimplMarker("myproject")  # hook 实现标签 用于标记hook的一个或多个实现
    @hookspec
    def global_hook_func1(arg1, arg2):
        pass

    myhookimpl.py

    import pluggy
    from myhookspec import hookimpl
    @hookimpl
    def global_hook_func1(arg1, arg2):
        print("global_hook_func1 in myhookimpl.py, args:", arg1, arg2)
        return "myhookimpl.py"

    other.py

    from myhookspec import hookimpl
    @hookimpl
    def global_hook_func1(arg1, arg2):
        print("global_hook_func1 in other.py, args:", arg1, arg2)
        return "other.py"

    example.py

    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
    import sys
    import pluggy
    import myhookspec
    import myhookimpl
    import other
    # 初始化 PluginManager
    pm = pluggy.PluginManager("myproject")
    # 登记hook集合
    pm.add_hookspecs(myhookspec)
    # 登记hook的实现
    pm.register(myhookimpl) # 插件也可以是模块
    pm.register(other)
    print(pm.hook.global_hook_func1(arg1="name", arg2="shouke"))

    example.py运行结果如下

    global_hook_func1 in other.py, args: name shouke
    global_hook_func1 in myhookimpl.py, args: name shouke
    ['other.py', 'myhookimpl.py']

    例3:自定义插件类实现hook函数免@hookimpl装饰器

    myhookspec.py

    import pluggy
    hookspec = pluggy.HookspecMarker("myproject")
    @hookspec
    def mytest_hook_func1(arg1, arg2):
        pass

    other.py

    def mytest_hook_func1(arg1, arg2):
        print("global_hook_func1 in other.py, args:", arg1, arg2)
        return "other.py"

    example.py

    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
    import inspect
    import pluggy
    import myhookspec
    import other
    class PytestPluginManager(pluggy.PluginManager):
        """
        插件类,实现不用@HookimplMarkerInstance装饰的函数也可以当做函数体
        """
        def parse_hookimpl_opts(self, plugin, name):
            # 规定免@hookimpl装饰的 hooks 函数总是以 mytest_打头,这样以避免访问非可读属性
            if not name.startswith("mytest_"):
                return
            method = getattr(plugin, name)
            opts = super().parse_hookimpl_opts(plugin, name)
            # 考虑hook只能为函数(consider only actual functions for hooks)
            if not inspect.isroutine(method):
                return
            # 收集未被标记的,以mytest打头的hook函数,(collect unmarked hooks as long as they have the `pytest_' prefix)
            if opts is None and name.startswith("mytest_"):
                opts = {}
            return opts
    # 初始化 PluginManager
    pm = PytestPluginManager("myproject")
    # 登记hook集合
    pm.add_hookspecs(myhookspec)
    # 登记hook的实现
    pm.register(other)
    pm.hook.mytest_hook_func1(arg1="addr", arg2="sz")

    参考连接

    https://pypi.org/project/pluggy/

    声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。