我正在尝试运行一个命令,该命令在作为目录提供的一些 Python 源代码中提供有关类型检查、静态代码分析等的一些聚合信息。如果存在这样的东西,那么我想将其添加到在某些
CI管道期间调用的
Makefile
以验证代码库。
我创建了这个虚拟源代码文件,但存在运行时问题
def foo_func(my_num):
return 1 + my_num
def bar_func():
foo_func("foo")
if __name__ == "__main__":
bar_func()
它抛出此运行时错误:
类型错误:+ 不支持的操作数类型:“int”和“str”。
现在我尝试使用各种工具来检测这种类型的错误,但它们都未能发现此类问题。请参阅以下列表中的命令:
pyflakes foo_sample.py
,flake8 foo_sample.py
,pylint foo_sample.py
,mypy --check-untyped-defs foo_sample.py
,prospector --strictness veryhigh foo_sample.py
我知道我可以使用
unittest
检测这些问题,但代码库相当大并且在某种程度上未经测试。我们经常看到运行时错误,并通过单元测试或集成测试来解决它们。然而,我们希望在 CI 管道的执行过程中检测到它们。
有没有办法在运行代码本身之前运行此类检查?
如何避免在运行时发现这些错误?
未声明的类型被认为是
Any
类型,并且不由 mypy
进行类型检查。需要更严格的配置来确保 mypy
强制您设置类型。具体来说,您需要 disallow_untyped_defs
,这应该会导致您得到以下结果:
$ cat test.py
def foo_func(my_num: int) -> int:
return 1 + my_num
def bar_func() -> None:
foo_func("foo")
if __name__ == "__main__":
bar_func()
$ mypy test.py
test.py:6: error: Argument 1 to "foo_func" has incompatible type "str"; expected "int"
Found 1 error in 1 file (checked 1 source file)
disallow_any_generics
和 warn_return_any
。 配置示例。
我发现 pytype 在这种情况下很有用。
在此代码上调用
pytype broken_code.py
时:
def foo_func(my_num):
return 1 + my_num
def bar_func():
foo_func("foo")
def run_func(my_func):
my_func()
if __name__ == "__main__":
bar_func()
run_func(bar_func())
我在输出中正确找到:
line 3, in foo_func: unsupported operand type(s) for +: 'int' and 'str' [unsupported-operands]
line 10, in run_func: 'NoneType' object is not callable [not-callable]
命令退出时出现错误,因此
Makefile
调用它可能会阻止 CI 环境中管道的执行。
此外,可以通过代码中的注释启用或禁用那些错误检查,例如
[unsupported-operands]
等,例如,
# pytype: disable=attribute-error
# pytype: enable=attribute-error
请参阅文档中如何使用这些注释,错误类。