From 4065f90a8afed8cae0f09a838583276f5b8e7b33 Mon Sep 17 00:00:00 2001 From: "Michael J. Sullivan" Date: Wed, 9 Oct 2019 13:03:45 -0700 Subject: [PATCH] Fix operator error messages for __div__ and __cmp__ on python 2 Currently the code for turning method call errors into operator error messages doesn't detect __div__ and __cmp__, so fix that. One of my main motivations here is that this fixes type ignoring these with an error code, since previously the real error would be `arg-type` but the note would be `operator`. --- mypy/messages.py | 10 ++++++++-- test-data/unit/check-expressions.test | 11 ++++++++--- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/mypy/messages.py b/mypy/messages.py index 1a947d80bf006..7eb03b3ffe2e7 100644 --- a/mypy/messages.py +++ b/mypy/messages.py @@ -27,7 +27,8 @@ ) from mypy.typetraverser import TypeTraverserVisitor from mypy.nodes import ( - TypeInfo, Context, MypyFile, op_methods, FuncDef, reverse_builtin_aliases, + TypeInfo, Context, MypyFile, op_methods, op_methods_to_symbols, + FuncDef, reverse_builtin_aliases, ARG_POS, ARG_OPT, ARG_NAMED, ARG_NAMED_OPT, ARG_STAR, ARG_STAR2, ReturnStmt, NameExpr, Var, CONTRAVARIANT, COVARIANT, SymbolNode, CallExpr @@ -353,7 +354,7 @@ def incompatible_argument(self, else: base = extract_type(name) - for op, method in op_methods.items(): + for method, op in op_methods_to_symbols.items(): for variant in method, '__r' + method[2:]: # FIX: do not rely on textual formatting if name.startswith('"{}" of'.format(variant)): @@ -366,6 +367,11 @@ def incompatible_argument(self, context, code=codes.OPERATOR) return codes.OPERATOR + if name.startswith('"__cmp__" of'): + self.unsupported_operand_types("comparison", arg_type, base, + context, code=codes.OPERATOR) + return codes.INDEX + if name.startswith('"__getitem__" of'): self.invalid_index_type(arg_type, callee.arg_types[n - 1], base, context, code=codes.INDEX) diff --git a/test-data/unit/check-expressions.test b/test-data/unit/check-expressions.test index 42efa40485010..ab2f6569de03f 100644 --- a/test-data/unit/check-expressions.test +++ b/test-data/unit/check-expressions.test @@ -474,15 +474,15 @@ class B: a, b, c, bo = None, None, None, None # type: (A, B, C, bool) bo = a == a # E: Unsupported operand types for == ("A" and "A") -bo = a != a # E: Argument 1 to "__cmp__" of "A" has incompatible type "A"; expected "B" +bo = a != a # E: Unsupported operand types for comparison ("A" and "A") bo = a < b bo = a > b bo = b <= b bo = b <= c -bo = b >= c # E: Argument 1 to "__cmp__" of "B" has incompatible type "C"; expected "B" +bo = b >= c # E: Unsupported operand types for comparison ("C" and "B") bo = a >= b bo = c >= b -bo = c <= b # E: Argument 1 to "__cmp__" of "C" has incompatible type "B"; expected "A" +bo = c <= b # E: Unsupported operand types for comparison ("B" and "C") bo = a == c bo = b == c # E: Unsupported operand types for == ("C" and "B") @@ -510,6 +510,11 @@ class C: [builtins_py2 fixtures/bool_py2.pyi] +[case testDiv_python2] +10 / 'no' # E: Unsupported operand types for / ("int" and "str") +'no' / 10 # E: Unsupported operand types for / ("str" and "int") +[builtins_py2 fixtures/ops.pyi] + [case cmpIgnoredPy3] a, b, bo = None, None, None # type: (A, B, bool)