mypy --strict
allows the following minimal example without any error:
a: int = 1
b: str = '1'
if a == b:
pass
else:
pass
Is there a possibility to make it issue an error (or at least a warning) about the if a == b:
line?
Edit: My original answer below described how to implement this by writing a custom mypy plugin.
However, as of mypy 0.700, this is now possible to do directly via the --strict-equality
flag. Note that as of time of writing, this flag is not enabled by default via the --strict
flag.
For example, running mypy on the original program above will produce the following error:
test.py:4: error: Non-overlapping equality check (left operand type: "int", right operand type: "str")
You can find more details about this flag near the bottom of the Miscellaneous strictness options section of the mypy command line flags doc.
This is possible using the (currently experimental and undocumented) plugins API.
In short, add the following file somewhere within your project:
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
Let's assume that the name of this file is strict_equality_plugins.py
.
Then, within the top-level of your project, create a mypy.ini
file. The file should, at the bare minimum, contain the following:
[mypy]
plugins = ./path/to/strict_equality_plugins.py
Then, running mypy within your root project will produce errors like the following:
foo.py:1: warning: The left and right operands have disjoint types ("int" and "str")
Disclaimer: The plugin API of the mypy project is highly experimental -- I make no promises that this plugin will continue to work unmodified in future versions of mypy.