Skip to content

Retrieve class or static info from node instead of type #5261

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 2 commits into from
Jun 21, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
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
25 changes: 19 additions & 6 deletions mypy/checker.py
Original file line number Diff line number Diff line change
Expand Up @@ -1221,22 +1221,32 @@ def check_method_override_for_base_with_name(
# Construct the type of the overriding method.
if isinstance(defn, FuncBase):
typ = self.function_type(defn) # type: Type
override_class_or_static = defn.is_class or defn.is_static
else:
assert defn.var.is_ready
assert defn.var.type is not None
typ = defn.var.type
override_class_or_static = defn.func.is_class or defn.func.is_static
if isinstance(typ, FunctionLike) and not is_static(context):
typ = bind_self(typ, self.scope.active_self_type())
# Map the overridden method type to subtype context so that
# it can be checked for compatibility.
original_type = base_attr.type
original_node = base_attr.node
if original_type is None:
if isinstance(base_attr.node, FuncDef):
original_type = self.function_type(base_attr.node)
elif isinstance(base_attr.node, Decorator):
original_type = self.function_type(base_attr.node.func)
if isinstance(original_node, FuncBase):
original_type = self.function_type(original_node)
elif isinstance(original_node, Decorator):
original_type = self.function_type(original_node.func)
else:
assert False, str(base_attr.node)
if isinstance(original_node, FuncBase):
original_class_or_static = original_node.is_class or original_node.is_static
elif isinstance(original_node, Decorator):
fdef = original_node.func
original_class_or_static = fdef.is_class or fdef.is_static
else:
original_class_or_static = False # a variable can't be class or static
if isinstance(original_type, AnyType) or isinstance(typ, AnyType):
pass
elif isinstance(original_type, FunctionLike) and isinstance(typ, FunctionLike):
Expand All @@ -1253,6 +1263,8 @@ def check_method_override_for_base_with_name(
defn.name(),
name,
base.name(),
original_class_or_static,
override_class_or_static,
context)
elif is_equivalent(original_type, typ):
# Assume invariance for a non-callable attribute here. Note
Expand All @@ -1267,6 +1279,8 @@ def check_method_override_for_base_with_name(

def check_override(self, override: FunctionLike, original: FunctionLike,
name: str, name_in_super: str, supertype: str,
original_class_or_static: bool,
override_class_or_static: bool,
node: Context) -> None:
"""Check a method override with given signatures.

Expand All @@ -1289,8 +1303,7 @@ def check_override(self, override: FunctionLike, original: FunctionLike,
fail = True

if isinstance(original, FunctionLike) and isinstance(override, FunctionLike):
if ((original.is_classmethod() or original.is_staticmethod()) and
not (override.is_classmethod() or override.is_staticmethod())):
if original_class_or_static and not override_class_or_static:
fail = True

if fail:
Expand Down
18 changes: 0 additions & 18 deletions mypy/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -645,12 +645,6 @@ def with_name(self, name: str) -> 'FunctionLike': pass
@abstractmethod
def get_name(self) -> Optional[str]: pass

@abstractmethod
def is_classmethod(self) -> bool: pass

@abstractmethod
def is_staticmethod(self) -> bool: pass


FormalArgument = NamedTuple('FormalArgument', [
('name', Optional[str]),
Expand Down Expand Up @@ -834,12 +828,6 @@ def with_name(self, name: str) -> 'CallableType':
def get_name(self) -> Optional[str]:
return self.name

def is_classmethod(self) -> bool:
return isinstance(self.definition, FuncBase) and self.definition.is_class

def is_staticmethod(self) -> bool:
return isinstance(self.definition, FuncBase) and self.definition.is_static

def max_fixed_args(self) -> int:
n = len(self.arg_types)
if self.is_var_arg:
Expand Down Expand Up @@ -1058,12 +1046,6 @@ def with_name(self, name: str) -> 'Overloaded':
def get_name(self) -> Optional[str]:
return self._items[0].name

def is_classmethod(self) -> bool:
return self._items[0].is_classmethod()

def is_staticmethod(self) -> bool:
return self._items[0].is_staticmethod()

def accept(self, visitor: 'TypeVisitor[T]') -> T:
return visitor.visit_overloaded(self)

Expand Down
16 changes: 16 additions & 0 deletions test-data/unit/check-classes.test
Original file line number Diff line number Diff line change
Expand Up @@ -4376,3 +4376,19 @@ class C1(object):
main:4: error: Revealed local types are:
main:4: error: t: builtins.str
main:4: error: y: builtins.float

[case testClassMethodOverride]
from typing import Callable, Any

def deco(f: Callable[..., Any]) -> Callable[..., Any]: ...

class B:
@classmethod
def meth(cls, x: int) -> int: ...

class C(B):
@classmethod
@deco
def meth(cls, x: int) -> int: ...
[builtins fixtures/classmethod.pyi]
[out]