10000 Function compatibility rewrite by sixolet · Pull Request #2521 · python/mypy · GitHub
[go: up one dir, main page]

Skip to content

Function compatibility rewrite #2521

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 18 commits into from
Dec 22, 2016
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Rename argument shorter
  • Loading branch information
sixolet committed Dec 21, 2016
commit 8b3b788ead8b0e704ae1a91a50713cf66ae1ac1e
2 changes: 1 addition & 1 deletion mypy/checker.py
Original file line number Diff line number Diff line change
Expand Up @@ -936,7 +936,7 @@ def check_override(self, override: FunctionLike, original: FunctionLike,
"""
# Use boolean variable to clarify code.
fail = False
if not is_subtype(override, original, ignore_positional_arg_names=True):
if not is_subtype(override, original, ignore_pos_arg_names=True):
fail = True
elif (not isinstance(original, Overloaded) and
isinstance(override, Overloaded) and
Expand Down
34 changes: 17 additions & 17 deletions mypy/subtypes.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ def check_type_parameter(lefta: Type, righta: Type, variance: int) -> bool:

def is_subtype(left: Type, right: Type,
type_parameter_checker: TypeParameterChecker = check_type_parameter,
*, ignore_positional_arg_names: bool = False) -> bool:
*, ignore_pos_arg_names: bool = False) -> bool:
"""Is 'left' subtype of 'right'?

Also consider Any to be a subtype of any type, and vice versa. This
Expand All @@ -50,11 +50,11 @@ def is_subtype(left: Type, right: Type,
return True
elif isinstance(right, UnionType) and not isinstance(left, UnionType):
return any(is_subtype(left, item, type_parameter_checker,
ignore_positional_arg_names = ignore_positional_arg_names)
ignore_pos_arg_names=ignore_pos_arg_names)
for item in right.items)
else:
return left.accept(SubtypeVisitor(right, type_parameter_checker,
ignore_positional_arg_names=ignore_positional_arg_names))
ignore_pos_arg_names=ignore_pos_arg_names))


def is_subtype_ignoring_tvars(left: Type, right: Type) -> bool:
Expand Down Expand Up @@ -85,10 +85,10 @@ class SubtypeVisitor(TypeVisitor[bool]):

def __init__(self, right: Type,
type_parameter_checker: TypeParameterChecker,
*, ignore_positional_arg_names: bool = False) -> None:
*, ignore_pos_arg_names: bool = False) -> None:
self.right = right
self.check_type_parameter = type_parameter_checker
self.ignore_positional_arg_names = ignore_positional_arg_names
self.ignore_pos_arg_names = ignore_pos_arg_names

# visit_x(left) means: is left (which is an instance of X) a subtype of
# right?
Expand Down Expand Up @@ -133,7 +133,7 @@ def visit_instance(self, left: Instance) -> bool:
if isinstance(right, Instance):
if left.type._promote and is_subtype(
left.type._promote, self.right, self.check_type_parameter,
ignore_positional_arg_names=self.ignore_positional_arg_names):
ignore_pos_arg_names=self.ignore_pos_arg_names):
return True
rname = right.type.fullname()
if not left.type.has_base(rname) and rname != 'builtins.object':
Expand All @@ -159,14 +159,14 @@ def visit_callable_type(self, left: CallableType) -> bool:
if isinstance(right, CallableType):
return is_callable_subtype(
left, right,
ignore_positional_arg_names=self.ignore_positional_arg_names)
ignore_pos_arg_names=self.ignore_pos_arg_names)
elif isinstance(right, Overloaded):
return all(is_subtype(left, item, self.check_type_parameter,
ignore_positional_arg_names=self.ignore_positional_arg_names)
ignore_pos_arg_names=self.ignore_pos_arg_names)
for item in right.items())
elif isinstance(right, Instance):
return is_subtype(left.fallback, right,
ignore_positional_arg_names=self.ignore_positional_arg_names)
ignore_pos_arg_names=self.ignore_pos_arg_names)
elif isinstance(right, TypeType):
# This is unsound, we don't check the __init__ signature.
return left.is_type_obj() and is_subtype(left.ret_type, right.item)
Expand Down Expand Up @@ -223,7 +223,7 @@ def visit_overloaded(self, left: Overloaded) -> bool:
right, 'builtins.type'):
for item in left.items():
if is_subtype(item, right, self.check_type_parameter,
ignore_positional_arg_names=self.ignore_positional_arg_names):
ignore_pos_arg_names=self.ignore_pos_arg_names):
return True
return False
elif isinstance(right, Overloaded):
Expand All @@ -232,7 +232,7 @@ def visit_overloaded(self, left: Overloaded) -> bool:
return False
for i in range(len(left.items())):
if not is_subtype(left.items()[i], right.items()[i], self.check_type_parameter,
ignore_positional_arg_names=self.ignore_positional_arg_names):
ignore_pos_arg_names=self.ignore_pos_arg_names):
return False
return True
elif isinstance(right, UnboundType):
Expand Down Expand Up @@ -270,7 +270,7 @@ def visit_type_type(self, left: TypeType) -> bool:

def is_callable_subtype(left: CallableType, right: CallableType,
ignore_return: bool = False,
ignore_positional_arg_names: bool = False) -> bool:
ignore_pos_arg_names: bool = False) -> bool:
"""Is left a subtype of right?"""
# Non-type cannot be a subtype of type.
if right.is_type_obj() and not left.is_type_obj():
Expand Down Expand Up @@ -337,7 +337,7 @@ def is_callable_subtype(left: CallableType, right: CallableType,
right_name, right_kind, right_type, right_required = right_by_position
if not is_left_more_general(left_name, left_pos, left_type, left_required,
right_name, right_pos, right_type, right_required,
ignore_positional_arg_names):
ignore_pos_arg_names):
return False
j += 1

Expand All @@ -363,7 +363,7 @@ def is_callable_subtype(left: CallableType, right: CallableType,
right_name, right_kind, right_type, right_required = right_by_name
if not is_left_more_general(left_name, left_pos, left_type, left_required,
right_name, right_pos, right_type, right_required,
ignore_positional_arg_names):
ignore_pos_arg_names):
return False
continue

Expand Down Expand Up @@ -405,7 +405,7 @@ def is_callable_subtype(left: CallableType, right: CallableType,

if not is_left_more_general(left_name, left_pos, left_type, left_required,
right_name, right_pos, right_type, right_required,
ignore_positional_arg_names):
ignore_pos_arg_names):
return False

for i in range(len(left.arg_types)):
Expand Down Expand Up @@ -443,12 +443,12 @@ def is_left_more_general(
right_pos: Optional[int],
right_type: Type,
right_required: bool,
ignore_positional_arg_names: bool) -> bool:
ignore_pos_arg_names: bool) -> bool:
# If right has a specific name it wants this argument to be, left must
# have the same.
if right_name is not None and left_name != right_name:
# But pay attention to whether we're ignoring positional arg names
if not ignore_positional_arg_names or right_pos is None:
if not ignore_pos_arg_names or right_pos is None:
return False
# If right is at a specific position, left must have the same:
if right_pos is not None and left_pos != right_pos:
Expand Down
4 changes: 2 additions & 2 deletions test-data/unit/check-functions.test
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,8 @@ ee_var = everywhere
ee_var = specific_1 # The difference between Callable[[...], blah] and one with a *args: Any, **kwargs: Any is that the ... goes loosely both ways.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Extra [] around ... in comment: should be Callable[..., blah].

ee_def = specific_1 # E: Incompatible types in assignment (expression has type Callable[[int, str], None], variable has type Callable[[Any, Any], None])
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The error message is confusing (missing indication of * and ** in the variable).


[builtins fixtures/dict.pyi]

[case testLackOfNames]
def f(__a: int, __b: str) -> None: pass
def g(a: int, b: str) -> None: pass
Expand All @@ -152,8 +154,6 @@ gg = g
ff = g
gg = f # E: Incompatible types in assignment (expression has type Callable[[int, str], None], variable has type Callable[[Arg('a', int, False), Arg('b', str, False)], None])

[builtins fixtures/dict.pyi]

[case testFunctionTypeCompatibilityWithOtherTypes]
from typing import Callable
f = None # type: Callable[[], None]
Expand Down
0