我正在尝试使用存根文件为 Python 包中包装的本机库提供更好的类型注释。
考虑以下玩具示例: 封装结构:
. geometry
|- typing
| `- __init__.pyi
|- geometry.cpython-39-x86_64-linux-gnu.so
|- __init__.py
|- __init__.pyi
`- py.typed
存根文件具有以下内容:
geometry/typing__init__.pyi
import geometry
import typing
Point = tuple[int, int]
Primitive = geometry.Circle | geometry.Rect
Primitives = typing.Sequence[Primitive]
geometry/__init__.pyi
import geometry.typing
class Circle:
center: geometry.typing.Point
radius: int
def __init__(self, center: geometry.typing.Point, radius: int): ...
class Rect:
top_left: geometry.typing.Point
width: int
height: int
def __init__(self, top_left: geometry.typing.Point, width: int, height: int): ...
def calculate_union_area(primitives: geometry.typing.Primitives) -> float: ...
geometry/__init__.py
from .geometry import Circle, Rect, calculate_union_area
通过:
mypy.stubtest
运行python -m mypy.stubtest geometry
给出以下输出:
error: not checking stubs due to mypy build errors:
geometry/__init__.pyi:4: error: Name "geometry.typing.Point" is not defined [name-defined]
geometry/__init__.pyi:7: error: Name "geometry.typing.Point" is not defined [name-defined]
geometry/__init__.pyi:10: error: Name "geometry.typing.Point" is not defined [name-defined]
geometry/__init__.pyi:14: error: Name "geometry.typing.Point" is not defined [name-defined]
geometry/__init__.pyi:16: error: Name "geometry.typing.Primitives" is not defined [name-defined]
如果我尝试在外部文件中使用
geometry.typing
中的类型:
import geometry
import geometry.typing
from geometry.typing import Point
def foo(pt: Point) -> None:
print(pt)
foo((1, 2))
foo(('bar', 31))
def baz(primitives: geometry.typing.Primitives) -> None:
print(len(primitives))
baz([geometry.Circle([0, 0], 3)), geometry.Rect((1, 2), width=10, height=10)])
来自 pylance 和 Pyright 语言服务器的类型提示和自动完成功能按预期工作。
在上面的示例中调用 mypy 作为
python -m mypy --strict --follow_imports_for_stubs main.py
再次给出有关使用 geometry.typing.Primitives
注释的错误:Name "geometry.typing.Primitives" is not defined [name-defined]
,但解析了 Point
名称,甚至其类型抱怨 foo(('bar', 31))
中的错误使用。
版本:
我的py版本:0.991
python版本:3.10.9
所以,问题如下:
通过全名使用别名类型时如何让 mypy 满意?
注意:将
geometry.typing.__init__.pyi
更改为 geometry.typing.__init__.py
与
import typing
if typing.TYPE_CHECKING:
# same content goes here
什么也没做 - 错误仍然存在。
注意:使用
from geometry.typing import Name
形式并非如此,因为在实际示例中,模块之间可能存在名称冲突。
注意:使用
from geometry.typing import Name as geometry_typing_Name
形式也不是这样,因为它看起来很难看,除此之外,它是解决可能的 mypy 检查器问题的拐杖。
我有一个类似的问题,我在这里的讨论中解决了https://github.com/konradhalas/dacite/issues/133
在你的情况下,它会涉及到添加 init.pyi 文件(可能在这个文件中:geometry/typing__init__.pyi)类似的想法
__all__ = [
"Point",
"Primitives"]
另请参阅此处有关 __all__ 的讨论:Python 中 __all__ 是什么意思?