让 mypy 警告不同类型变量的相等性检查
Let mypy warn about equality checks of variables with different type
mypy --strict
允许以下最小示例而不会出现任何错误:
a: int = 1
b: str = '1'
if a == b:
pass
else:
pass
是否有可能让它发出关于 if a == b:
行的错误(或至少是警告)?
编辑:我下面的原始答案描述了如何通过编写自定义 mypy 插件来实现这一点。
但是,as of mypy 0.700,现在可以通过 --strict-equality
标志直接执行此操作。请注意,截至撰写本文时,默认情况下不会通过 --strict
标志启用此标志。
例如上面原程序上的运行mypy会产生如下错误:
test.py:4: error: Non-overlapping equality check (left operand type: "int", right operand type: "str")
您可以在 mypy 命令行标志文档的 Miscellaneous strictness options 部分底部附近找到有关此标志的更多详细信息。
这可以使用(目前处于试验阶段且未记录的)插件 API。
简而言之,在项目中的某处添加以下文件:
from typing import Callable, Optional, Type
from mypy.plugin import MethodContext, Plugin
from mypy.meet import is_overlapping_types
class StrictEqualityPlugin(Plugin):
def get_method_hook(self, fullname: str) -> Optional[Callable[[MethodContext], Type]]:
if fullname.endswith('__eq__') or fullname.endswith('__ne__'):
return strict_check_callback
def strict_check_callback(ctx: MethodContext) -> Type:
if len(ctx.arg_types) == 1 and len(ctx.arg_types[0]) == 1:
# Note: Expressions of the form 'base_type == arg_type' get
# translated into `base_type.__eq__(arg_type)`.
base_type = ctx.type
arg_type = ctx.arg_types[0][0]
# Two types are overlapping if one of the types could potentially be the
# same as or a subtype of the other.
#
# If you want something even stricter, add `from mypy.sametypes import is_same_type`
# up at the top and call `is_same_type` instead of `is_overlapping_types`.
if not is_overlapping_types(base_type, arg_type):
ctx.api.msg.warn(
"The left and right operands have disjoint types ({} and {})".format(
ctx.api.msg.format(base_type),
ctx.api.msg.format(arg_type),
),
ctx.context)
return ctx.default_return_type
def plugin(mypy_version: str) -> Plugin:
return StrictEqualityPlugin
我们假设这个文件的名称是 strict_equality_plugins.py
.
然后,在项目的顶层创建一个 mypy.ini
文件。该文件应至少包含以下内容:
[mypy]
plugins = ./path/to/strict_equality_plugins.py
然后,运行 根项目中的 mypy 将产生如下错误:
foo.py:1: warning: The left and right operands have disjoint types ("int" and "str")
免责声明: mypy 项目的插件 API 是高度实验性的——我不保证这个插件将在未来的 mypy 版本中继续不加修改地工作.
mypy --strict
允许以下最小示例而不会出现任何错误:
a: int = 1
b: str = '1'
if a == b:
pass
else:
pass
是否有可能让它发出关于 if a == b:
行的错误(或至少是警告)?
编辑:我下面的原始答案描述了如何通过编写自定义 mypy 插件来实现这一点。
但是,as of mypy 0.700,现在可以通过 --strict-equality
标志直接执行此操作。请注意,截至撰写本文时,默认情况下不会通过 --strict
标志启用此标志。
例如上面原程序上的运行mypy会产生如下错误:
test.py:4: error: Non-overlapping equality check (left operand type: "int", right operand type: "str")
您可以在 mypy 命令行标志文档的 Miscellaneous strictness options 部分底部附近找到有关此标志的更多详细信息。
这可以使用(目前处于试验阶段且未记录的)插件 API。
简而言之,在项目中的某处添加以下文件:
from typing import Callable, Optional, Type
from mypy.plugin import MethodContext, Plugin
from mypy.meet import is_overlapping_types
class StrictEqualityPlugin(Plugin):
def get_method_hook(self, fullname: str) -> Optional[Callable[[MethodContext], Type]]:
if fullname.endswith('__eq__') or fullname.endswith('__ne__'):
return strict_check_callback
def strict_check_callback(ctx: MethodContext) -> Type:
if len(ctx.arg_types) == 1 and len(ctx.arg_types[0]) == 1:
# Note: Expressions of the form 'base_type == arg_type' get
# translated into `base_type.__eq__(arg_type)`.
base_type = ctx.type
arg_type = ctx.arg_types[0][0]
# Two types are overlapping if one of the types could potentially be the
# same as or a subtype of the other.
#
# If you want something even stricter, add `from mypy.sametypes import is_same_type`
# up at the top and call `is_same_type` instead of `is_overlapping_types`.
if not is_overlapping_types(base_type, arg_type):
ctx.api.msg.warn(
"The left and right operands have disjoint types ({} and {})".format(
ctx.api.msg.format(base_type),
ctx.api.msg.format(arg_type),
),
ctx.context)
return ctx.default_return_type
def plugin(mypy_version: str) -> Plugin:
return StrictEqualityPlugin
我们假设这个文件的名称是 strict_equality_plugins.py
.
然后,在项目的顶层创建一个 mypy.ini
文件。该文件应至少包含以下内容:
[mypy]
plugins = ./path/to/strict_equality_plugins.py
然后,运行 根项目中的 mypy 将产生如下错误:
foo.py:1: warning: The left and right operands have disjoint types ("int" and "str")
免责声明: mypy 项目的插件 API 是高度实验性的——我不保证这个插件将在未来的 mypy 版本中继续不加修改地工作.