From a9b721cde66fce618def4c49c014dc9ecedb96cb Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Fri, 22 Apr 2016 16:40:21 -0700 Subject: [PATCH 1/2] Don't complain about method undefined in superclass if caller is a dynamic function. --- mypy/checkexpr.py | 3 ++- mypy/checkmember.py | 12 ++++++++---- mypy/test/data/check-super.test | 9 +++++++++ 3 files changed, 19 insertions(+), 5 deletions(-) diff --git a/mypy/checkexpr.py b/mypy/checkexpr.py index fee0957fc0d0..4577413041b7 100644 --- a/mypy/checkexpr.py +++ b/mypy/checkexpr.py @@ -1325,7 +1325,8 @@ def analyze_super(self, e: SuperExpr, is_lvalue: bool) -> Type: return analyze_member_access(e.name, self_type(e.info), e, is_lvalue, True, self.named_type, self.not_ready_callback, - self.msg, base) + self.msg, base, + strict=self.chk.typing_mode_full()) else: # Invalid super. This has been reported by the semantic analyzer. return AnyType() diff --git a/mypy/checkmember.py b/mypy/checkmember.py index 152728ea6426..9e3a9902e8db 100644 --- a/mypy/checkmember.py +++ b/mypy/checkmember.py @@ -22,7 +22,8 @@ def analyze_member_access(name: str, typ: Type, node: Context, is_lvalue: bool, builtin_type: Callable[[str], Instance], not_ready_callback: Callable[[str, Context], None], msg: MessageBuilder, override_info: TypeInfo = None, - report_type: Type = None) -> Type: + report_type: Type = None, + strict: bool = True) -> Type: """Analyse attribute access. This is a general operation that supports various different variations: @@ -68,7 +69,8 @@ def analyze_member_access(name: str, typ: Type, node: Context, is_lvalue: bool, return analyze_member_var_access(name, typ, info, node, is_lvalue, is_super, builtin_type, not_ready_callback, msg, - report_type=report_type) + report_type=report_type, + strict=strict) elif isinstance(typ, AnyType): # The base object has dynamic type. return AnyType() @@ -121,7 +123,8 @@ def analyze_member_var_access(name: str, itype: Instance, info: TypeInfo, builtin_type: Callable[[str], Instance], not_ready_callback: Callable[[str, Context], None], msg: MessageBuilder, - report_type: Type = None) -> Type: + report_type: Type = None, + strict: bool = True) -> Type: """Analyse attribute access that does not target a method. This is logically part of analyze_member_access and the arguments are @@ -154,7 +157,8 @@ def analyze_member_var_access(name: str, itype: Instance, info: TypeInfo, # Could not find the member. if is_super: - msg.undefined_in_superclass(name, node) + if strict: + msg.undefined_in_superclass(name, node) return AnyType() else: return msg.has_no_attr(report_type or itype, name, node) diff --git a/mypy/test/data/check-super.test b/mypy/test/data/check-super.test index ad07d431b970..0f2d7e7af466 100644 --- a/mypy/test/data/check-super.test +++ b/mypy/test/data/check-super.test @@ -108,3 +108,12 @@ class C(B): def __init__(self, arg=0): super(C, self).__init__(arg, arg=arg) [out] + +[case testSuperSilentInDynamicFunction] +class A: + pass + +class B(A): + def foo(self): + super(B, self).foo() # Not an error +[out] From a8611850340af8119432ab7a396e11271bc11a85 Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Fri, 22 Apr 2016 17:22:31 -0700 Subject: [PATCH 2/2] Simpler. Just skip analyze_member_access() if not in full typing mode. --- mypy/checkexpr.py | 5 +++-- mypy/checkmember.py | 12 ++++-------- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/mypy/checkexpr.py b/mypy/checkexpr.py index 4577413041b7..7939e3c82cad 100644 --- a/mypy/checkexpr.py +++ b/mypy/checkexpr.py @@ -1322,11 +1322,12 @@ def analyze_super(self, e: SuperExpr, is_lvalue: bool) -> Type: # There's an undefined base class, and we're # at the end of the chain. That's not an error. return AnyType() + if not self.chk.typing_mode_full(): + return AnyType() return analyze_member_access(e.name, self_type(e.info), e, is_lvalue, True, self.named_type, self.not_ready_callback, - self.msg, base, - strict=self.chk.typing_mode_full()) + self.msg, base) else: # Invalid super. This has been reported by the semantic analyzer. return AnyType() diff --git a/mypy/checkmember.py b/mypy/checkmember.py index 9e3a9902e8db..152728ea6426 100644 --- a/mypy/checkmember.py +++ b/mypy/checkmember.py @@ -22,8 +22,7 @@ def analyze_member_access(name: str, typ: Type, node: Context, is_lvalue: bool, builtin_type: Callable[[str], Instance], not_ready_callback: Callable[[str, Context], None], msg: MessageBuilder, override_info: TypeInfo = None, - report_type: Type = None, - strict: bool = True) -> Type: + report_type: Type = None) -> Type: """Analyse attribute access. This is a general operation that supports various different variations: @@ -69,8 +68,7 @@ def analyze_member_access(name: str, typ: Type, node: Context, is_lvalue: bool, return analyze_member_var_access(name, typ, info, node, is_lvalue, is_super, builtin_type, not_ready_callback, msg, - report_type=report_type, - strict=strict) + report_type=report_type) elif isinstance(typ, AnyType): # The base object has dynamic type. return AnyType() @@ -123,8 +121,7 @@ def analyze_member_var_access(name: str, itype: Instance, info: TypeInfo, builtin_type: Callable[[str], Instance], not_ready_callback: Callable[[str, Context], None], msg: MessageBuilder, - report_type: Type = None, - strict: bool = True) -> Type: + report_type: Type = None) -> Type: """Analyse attribute access that does not target a method. This is logically part of analyze_member_access and the arguments are @@ -157,8 +154,7 @@ def analyze_member_var_access(name: str, itype: Instance, info: TypeInfo, # Could not find the member. if is_super: - if strict: - msg.undefined_in_superclass(name, node) + msg.undefined_in_superclass(name, node) return AnyType() else: return msg.has_no_attr(report_type or itype, name, node)