Navigation Menu

Skip to content

Instantly share code, notes, and snippets.

@OddBloke
Last active August 22, 2017 09:41
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save OddBloke/aa598f118148bee85a3dda173d6d77ef to your computer and use it in GitHub Desktop.
Save OddBloke/aa598f118148bee85a3dda173d6d77ef to your computer and use it in GitHub Desktop.
eq_plugin.py: mypy plugin to check that types are only compared to themselves

How to Use

  1. Put eq_plugin.py somewhere in your project
  2. Add plugins=path/to/eq_plugin.py to the mypy section of your mypy.ini (see example in this gist)
  3. Run mypy

Example

$ mypy example.py  # Also in this gist
example.py:7: warning: Equality comparison between "example.MyClass" and "def () -> example.MyClass"
example.py:10: warning: Equality comparison between "example.MyClass" and "builtins.int"
from typing import Callable, Optional, Type
from mypy.plugin import MethodContext, Plugin
from mypy.subtypes import is_subtype
class CheckEqTypesMatch(Plugin):
def get_method_hook(
self, fullname: str) -> Optional[Callable[[MethodContext], Type]]:
if fullname.endswith('__eq__'):
return eq_callback
def eq_callback(ctx: MethodContext) -> Type:
if len(ctx.arg_types) == 1 and len(ctx.arg_types[0]) == 1:
arg_type = ctx.arg_types[0][0]
if ctx.type != arg_type and not is_subtype(arg_type, ctx.type):
ctx.api.msg.warn(
'Equality comparison between "{}" and "{}"'.format(
ctx.type, ctx.arg_types[0][0]), ctx.context)
return ctx.default_return_type
plugin = lambda _: CheckEqTypesMatch
from typing import *
class MyClass:
def __eq__(self, other) -> bool: ...
class MySubClass(MyClass): ...
if MyClass() == MyClass:
print('foo')
if MyClass() == 2:
pass
if MyClass() == MyClass():
pass
if MyClass() == MySubClass():
pass
[mypy]
plugins=
eq_plugin.py
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment