我是 python 的新手,并且是静态类型检查器的忠实粉丝。我有一些代码可以使用 Bottle 框架处理文件上传。见下文。
def transcribe_upload(upload: FileUpload) -> Alternative:
audio:AudioSource = upload_source(upload)
...
def upload_source(upload:FileUpload) -> AudioSource:
...
我犯了一个非常简单的错误,将
upload.file
(类文件对象)传递给 upload_source
而不是整个 FileUpload
对象。
def transcribe_upload(upload: FileUpload) -> Alternative:
audio:AudioSource = upload_source(upload.file) # This is incorrect!
类型检查器没有发现它。事实上,它没有捕获传递给
upload_source
的任何不正确参数:
def transcribe_upload(upload: FileUpload) -> Alternative:
audio:AudioSource = upload_source(4) # Why isn't mypy giving me an error?
audio:AudioSource = upload_source(upload.asdf) # Why isn't mypy giving me an error?
怎么回事?我分别测试了一些基本函数,当我试图将一个数字传递给一个需要字符串的函数时,类型检查器被捕获了,它起作用了。我在这里错过了什么?
编辑
@kojiro 建议
FileUpload
等同于 Any
。我认为这可能是正确的。这是FileUpload
的来源。它是这样导入的:from bottle import FileUpload
.
如果是这样,为什么让我像使用
FileUpload
一样使用它呢? (如果我搞砸了名字,比如FileUpld
,它确实会给我一个错误)。
更重要的是,我如何获得真正的类型?我想瓶子作者必须添加它们?
bottle
不是静态类型库(它在 bottle.py
中不提供类型注释)。它作为单个 bottle.py
(而不是 包)的组织也阻止您自己制作 py.typed
,否则 mypy 至少可以获取类属性、函数/方法签名,和全局变量(即使它们没有任何输入信息)。
获得“真实类型”的唯一方法是
bottle
维护者添加它们。假设这不会发生,您有多种选择:
生成骨架轮廓(Python存根文件,扩展名
.pyi
),这将有助于完成基本代码。这将捕获变量、函数和类 existence,但不会捕获变量和函数签名类型信息(仅仅是因为 bottle.py
一开始就没有)。
stubgen
工具可以在大约一秒钟内生成骨骼轮廓,如果您已经安装了 mypy,您应该已经拥有该工具。
通过在bottle 的测试套件 上运行pyannotate 或MonkeyType 来收集运行时类型,并使用这些工具生成
.pyi
。这比只运行 stubgen
更准确,但最终质量取决于测试套件,并且很可能导致 mypy 的大量误报警告,特别是对于 descriptor classes like bottle 的 DictProperty
和lazy_attribute
.
使用pytype的类型推断来生成
.pyi
。这通常会产生更多可用的存根,但代价是非常长的推理过程,最终可能会构建依赖图并扫描您的大部分site-packages
,并且如果bottle
有很多复杂的第三-党的依赖。
你应该最终得到一个单一的
bottle.pyi
,你必须移动到与bottle.py
相同的目录。这应该在您的虚拟环境的 site-packages
中。完成 2. 或 3. 后,mypy
应该能够正确识别打字错误。