Skip to content

Commit

Permalink
Remove Python 2 logic from checkexpr (#13264)
Browse files Browse the repository at this point in the history
  • Loading branch information
hauntsaninja authored Jul 28, 2022
1 parent e67fedf commit 222ac7b
Show file tree
Hide file tree
Showing 3 changed files with 11 additions and 68 deletions.
77 changes: 11 additions & 66 deletions mypy/checkexpr.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@
)
from mypy.sametypes import is_same_type
from mypy.semanal_enum import ENUM_BASES
from mypy.subtypes import is_equivalent, is_proper_subtype, is_subtype, non_method_protocol_members
from mypy.subtypes import is_equivalent, is_subtype, non_method_protocol_members
from mypy.traverser import has_await_expression
from mypy.typeanal import (
check_for_explicit_any,
Expand Down Expand Up @@ -2561,15 +2561,7 @@ def visit_complex_expr(self, e: ComplexExpr) -> Type:

def visit_ellipsis(self, e: EllipsisExpr) -> Type:
"""Type check '...'."""
if self.chk.options.python_version[0] >= 3:
return self.named_type("builtins.ellipsis")
else:
# '...' is not valid in normal Python 2 code, but it can
# be used in stubs. The parser makes sure that we only
# get this far if we are in a stub, and we can safely
# return 'object' as ellipsis is special cased elsewhere.
# The builtins.ellipsis type does not exist in Python 2.
return self.named_type("builtins.object")
return self.named_type("builtins.ellipsis")

def visit_op_expr(self, e: OpExpr) -> Type:
"""Type check a binary operator expression."""
Expand All @@ -2596,7 +2588,7 @@ def visit_op_expr(self, e: OpExpr) -> Type:
return self.concat_tuples(proper_left_type, proper_right_type)

if e.op in operators.op_methods:
method = self.get_operator_method(e.op)
method = operators.op_methods[e.op]
result, method_type = self.check_op(method, left_type, e.right, e, allow_reverse=True)
e.method_type = method_type
return result
Expand Down Expand Up @@ -2673,7 +2665,7 @@ def visit_comparison_expr(self, e: ComparisonExpr) -> Type:
else:
self.msg.add_errors(local_errors.filtered_errors())
elif operator in operators.op_methods:
method = self.get_operator_method(operator)
method = operators.op_methods[operator]

with ErrorWatcher(self.msg.errors) as w:
sub_result, method_type = self.check_op(
Expand Down Expand Up @@ -2779,11 +2771,10 @@ def dangerous_comparison(
left = remove_optional(left)
right = remove_optional(right)
left, right = get_proper_types((left, right))
py2 = self.chk.options.python_version < (3, 0)
if (
original_container
and has_bytes_component(original_container, py2)
and has_bytes_component(left, py2)
and has_bytes_component(original_container)
and has_bytes_component(left)
):
# We need to special case bytes and bytearray, because 97 in b'abc', b'a' in b'abc',
# b'a' in bytearray(b'abc') etc. all return True (and we want to show the error only
Expand All @@ -2805,12 +2796,6 @@ def dangerous_comparison(
return False
return not is_overlapping_types(left, right, ignore_promotions=False)

def get_operator_method(self, op: str) -> str:
if op == "/" and self.chk.options.python_version[0] == 2:
return "__truediv__" if self.chk.tree.is_future_flag_set("division") else "__div__"
else:
return operators.op_methods[op]

def check_method_call_by_name(
self,
method: str,
Expand Down Expand Up @@ -2973,7 +2958,7 @@ def lookup_definer(typ: Instance, attr_name: str) -> Optional[str]:
# STEP 1:
# We start by getting the __op__ and __rop__ methods, if they exist.

rev_op_name = self.get_reverse_op_method(op_name)
rev_op_name = operators.reverse_op_methods[op_name]

left_op = lookup_operator(op_name, left_type)
right_op = lookup_operator(rev_op_name, right_type)
Expand All @@ -2986,7 +2971,6 @@ def lookup_definer(typ: Instance, attr_name: str) -> Optional[str]:
# We store the determined order inside the 'variants_raw' variable,
# which records tuples containing the method, base type, and the argument.

bias_right = is_proper_subtype(right_type, left_type)
if op_name in operators.op_methods_that_shortcut and is_same_type(left_type, right_type):
# When we do "A() + A()", for example, Python will only call the __add__ method,
# never the __radd__ method.
Expand Down Expand Up @@ -3019,22 +3003,6 @@ def lookup_definer(typ: Instance, attr_name: str) -> Optional[str]:

variants_raw = [(left_op, left_type, right_expr), (right_op, right_type, left_expr)]

# STEP 2b:
# When running Python 2, we might also try calling the __cmp__ method.

is_python_2 = self.chk.options.python_version[0] == 2
if is_python_2 and op_name in operators.ops_falling_back_to_cmp:
cmp_method = operators.comparison_fallback_method
left_cmp_op = lookup_operator(cmp_method, left_type)
right_cmp_op = lookup_operator(cmp_method, right_type)

if bias_right:
variants_raw.append((right_cmp_op, right_type, left_expr))
variants_raw.append((left_cmp_op, left_type, right_expr))
else:
variants_raw.append((left_cmp_op, left_type, right_expr))
variants_raw.append((right_cmp_op, right_type, left_expr))

# STEP 3:
# We now filter out all non-existent operators. The 'variants' list contains
# all operator methods that are actually present, in the order that Python
Expand Down Expand Up @@ -3217,12 +3185,6 @@ def check_op(
context=context,
)

def get_reverse_op_method(self, method: str) -> str:
if method == "__div__" and self.chk.options.python_version[0] == 2:
return "__rdiv__"
else:
return operators.reverse_op_methods[method]

def check_boolean_op(self, e: OpExpr, context: Context) -> Type:
"""Type check a boolean operation ('and' or 'or')."""

Expand Down Expand Up @@ -3543,8 +3505,6 @@ def visit_enum_index_expr(
self, enum_type: TypeInfo, index: Expression, context: Context
) -> Type:
string_type: Type = self.named_type("builtins.str")
if self.chk.options.python_version[0] < 3:
string_type = UnionType.make_union([string_type, self.named_type("builtins.unicode")])
self.chk.check_subtype(
self.accept(index),
string_type,
Expand Down Expand Up @@ -4176,10 +4136,7 @@ def _super_arg_types(self, e: SuperExpr) -> Union[Type, Tuple[Type, Type]]:
if not self.chk.in_checked_function():
return AnyType(TypeOfAny.unannotated)
elif len(e.call.args) == 0:
if self.chk.options.python_version[0] == 2:
self.chk.fail(message_registry.TOO_FEW_ARGS_FOR_SUPER, e)
return AnyType(TypeOfAny.from_error)
elif not e.info:
if not e.info:
# This has already been reported by the semantic analyzer.
return AnyType(TypeOfAny.from_error)
elif self.chk.scope.active_class():
Expand Down Expand Up @@ -4528,7 +4485,7 @@ def is_valid_var_arg(self, typ: Type) -> bool:

def is_valid_keyword_var_arg(self, typ: Type) -> bool:
"""Is a type valid as a **kwargs argument?"""
ret = (
return (
is_subtype(
typ,
self.chk.named_generic_type(
Expand All @@ -4544,15 +4501,6 @@ def is_valid_keyword_var_arg(self, typ: Type) -> bool:
)
or isinstance(typ, ParamSpecType)
)
if self.chk.options.python_version[0] < 3:
ret = ret or is_subtype(
typ,
self.chk.named_generic_type(
"typing.Mapping",
[self.named_type("builtins.unicode"), AnyType(TypeOfAny.special_form)],
),
)
return ret

def has_member(self, typ: Type, member: str) -> bool:
"""Does type have member with the given name?"""
Expand Down Expand Up @@ -5152,13 +5100,10 @@ def is_expr_literal_type(node: Expression) -> bool:
return False


def has_bytes_component(typ: Type, py2: bool = False) -> bool:
def has_bytes_component(typ: Type) -> bool:
"""Is this one of builtin byte types, or a union that contains it?"""
typ = get_proper_type(typ)
if py2:
byte_types = {"builtins.str", "builtins.bytearray"}
else:
byte_types = {"builtins.bytes", "builtins.bytearray"}
byte_types = {"builtins.bytes", "builtins.bytearray"}
if isinstance(typ, UnionType):
return any(has_bytes_component(t) for t in typ.items)
if isinstance(typ, Instance) and typ.type.fullname in byte_types:
Expand Down
1 change: 0 additions & 1 deletion mypy/message_registry.py
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,6 @@ def format(self, *args: object, **kwargs: object) -> "ErrorMessage":

# Super
TOO_MANY_ARGS_FOR_SUPER: Final = ErrorMessage('Too many arguments for "super"')
TOO_FEW_ARGS_FOR_SUPER: Final = ErrorMessage('Too few arguments for "super"', codes.CALL_ARG)
SUPER_WITH_SINGLE_ARG_NOT_SUPPORTED: Final = ErrorMessage(
'"super" with a single argument not supported'
)
Expand Down
1 change: 0 additions & 1 deletion mypy/operators.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@
op_methods_to_symbols: Final = {v: k for (k, v) in op_methods.items()}
op_methods_to_symbols["__div__"] = "/"

comparison_fallback_method: Final = "__cmp__"
ops_falling_back_to_cmp: Final = {"__ne__", "__eq__", "__lt__", "__le__", "__gt__", "__ge__"}


Expand Down

0 comments on commit 222ac7b

Please sign in to comment.