gpt4 book ai didi

python - 如何注释插入式钩子(Hook)规范的类型?

转载 作者:行者123 更新时间:2023-12-01 08:20:33 29 4
gpt4 key购买 nike

我想将类型注释添加到我的插件钩子(Hook)规范中,以便可以对钩子(Hook)实现进行类型检查。使用 pluggy documentation 中的这个简化示例:

import pluggy  # type: ignore

hookspec = pluggy.HookspecMarker("myproject")
hookimpl = pluggy.HookimplMarker("myproject")


class MySpec(object):
"""A hook specification namespace."""

@hookspec
def myhook(self, arg1, arg2):
"""My special little hook that you can customize."""


class Plugin_1(object):
"""A hook implementation namespace."""

@hookimpl
def myhook(self, arg1, arg2):
print("inside Plugin_1.myhook()")
return arg1 + arg2 + "a" # intentional error


# create a manager and add the spec
pm = pluggy.PluginManager("myproject")
pm.add_hookspecs(MySpec)
# register plugins
pm.register(Plugin_1())
# call our `myhook` hook
# intentional incompatible type for parameter arg2
results = pm.hook.myhook(arg1=1, arg2="1")
print(results)

我相信正确的有效注释是:

def myhook(self, arg1: int, arg2: int) -> int: ...

我尝试将此注释添加到 hookspec 中。正如我所料,这不起作用。我相信这是因为 Pluggy 实现的间接是动态的。必须运行该代码,以便add_hookspecs()方法PluginManager可以定义可用的钩子(Hook)。

我看到pm.hook类型为pluggy.hooks._HookRelaypm.hook.myhookpluggy.hooks._HookCaller 的一个实例其中有 __call__()方法。

我尝试使用stubgen制作一套 .pyi Pluggy 文件,然后将注释添加到 pluggy.hooks._HookCaller有两种不同的方式:

class _HookCaller:
def __init__(self, trace: Any) -> None: ...
def myhook(self, arg1: int, arg2: int) -> int: ...
def __call__(self, arg1: int, arg2: int) -> int: ...

当我执行MYPYPATH=./stubs mypy --verboes example.py时我可以看到hooks.pyi正在解析,但未检测到参数类型不匹配。即使我删除 # type: ignore,此行为也是一致的来自import pluggy的注释.

问题:

  1. 是否可以定义为外部.pyi文件中,类型注释为myhook()钩子(Hook)?
  2. 如果是这样,那会是什么 .pyi文件包含以及我将其存储在哪里以便 mypy运行类型检查时会拾取它吗?
  3. 是否可以进行注释,以便钩子(Hook)实现者和钩子(Hook)调用者都获得有用的类型提示?

最佳答案

第一个问题是 @hookspec 消除了 myhook 方法的类型提示:

from typing import TypeVar, Callable, Any, cast

# Improvement suggested by @oremanj on python/typing gitter
F = TypeVar("F", bound=Callable[..., Any])
hookspec = cast(Callable[[F], F], pluggy.HookspecMarker("myproject"))

该解决方法不需要外部 .pyi 文件。只需使用现有的钩子(Hook)规范来定义类型提示。这解决了 Q1 和 Q2:您不需要 .pyi 文件。只需使用 typing.cast() 给 mypy 一个提示,它无法从静态分析中学习:

# Add cast so that mypy knows that pm.hook
# is actually a MySpec instance. Without this
# hint there really is no way for mypy to know
# this.
pm.hook = cast(MySpec, pm.hook)

可以通过添加注释来检查:

# Uncomment these when running through mypy to see
# how mypy regards the type
reveal_type(pm.hook)
reveal_type(pm.hook.myhook)
reveal_type(MySpec.myhook)

通过 mypy 运行它:

plug.py:24: error: Unsupported operand types for + ("int" and "str")
plug.py:42: error: Revealed type is 'plug.MySpec'
plug.py:43: error: Revealed type is 'def (arg1: builtins.int, arg2: builtins.int) -> builtins.int'
plug.py:44: error: Revealed type is 'def (self: plug.MySpec, arg1: builtins.int, arg2: builtins.int) -> builtins.int'
plug.py:47: error: Argument "arg2" to "myhook" of "MySpec" has incompatible type "str"; expected "int"

现在 mypy 捕获了钩子(Hook)调用者和钩子(Hook)实现上的类型问题(Q3)!

完整代码:

import pluggy  # type: ignore
from typing import TypeVar, Callable, Any, cast

# Improvement suggested by @oremanj on python/typing gitter
F = TypeVar("F", bound=Callable[..., Any])
hookspec = cast(Callable[[F], F], pluggy.HookspecMarker("myproject"))
hookimpl = pluggy.HookimplMarker("myproject")


class MySpec(object):
"""A hook specification namespace."""

@hookspec
def myhook(self, arg1: int, arg2: int) -> int:
"""My special little hook that you can customize."""


class Plugin_1(object):
"""A hook implementation namespace."""

@hookimpl
def myhook(self, arg1: int, arg2: int) -> int:
print("inside Plugin_1.myhook()")
return arg1 + arg2 + 'a'


# create a manager and add the spec
pm = pluggy.PluginManager("myproject")
pm.add_hookspecs(MySpec)

# register plugins
pm.register(Plugin_1())

# Add cast so that mypy knows that pm.hook
# is actually a MySpec instance. Without this
# hint there really is no way for mypy to know
# this.
pm.hook = cast(MySpec, pm.hook)

# Uncomment these when running through mypy to see
# how mypy regards the type
# reveal_type(pm.hook)
# reveal_type(pm.hook.myhook)
# reveal_type(MySpec.myhook)

# this will now be caught by mypy
results = pm.hook.myhook(arg1=1, arg2="1")
print(results)

关于python - 如何注释插入式钩子(Hook)规范的类型?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54674679/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com