Skip to content

Commit

Permalink
Fix __getattr__ and operators related infinite recursion (#6655)
Browse files Browse the repository at this point in the history
Fixes #6579.
  • Loading branch information
onlined authored and ilevkivskyi committed Apr 11, 2019
1 parent bee73a0 commit 94746d6
Show file tree
Hide file tree
Showing 3 changed files with 20 additions and 3 deletions.
4 changes: 2 additions & 2 deletions mypy/checkexpr.py
Original file line number Diff line number Diff line change
Expand Up @@ -704,8 +704,8 @@ def check_call(self,
elif isinstance(callee, UnionType):
return self.check_union_call(callee, args, arg_kinds, arg_names, context, arg_messages)
elif isinstance(callee, Instance):
call_function = analyze_member_access('__call__', callee, context,
False, False, False, self.msg,
call_function = analyze_member_access('__call__', callee, context, is_lvalue=False,
is_super=False, is_operator=True, msg=self.msg,
original_type=callee, chk=self.chk,
in_literal_context=self.is_literal_context())
callable_name = callee.type.fullname() + ".__call__"
Expand Down
3 changes: 2 additions & 1 deletion mypy/checkmember.py
Original file line number Diff line number Diff line change
Expand Up @@ -332,7 +332,8 @@ def analyze_member_var_access(name: str,
return analyze_var(name, v, itype, info, mx, implicit=implicit)
elif isinstance(v, FuncDef):
assert False, "Did not expect a function"
elif not v and name not in ['__getattr__', '__setattr__', '__getattribute__']:
elif (not v and name not in ['__getattr__', '__setattr__', '__getattribute__'] and
not mx.is_operator):
if not mx.is_lvalue:
for method_name in ('__getattribute__', '__getattr__'):
method = info.get_method(method_name)
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 @@ -2494,6 +2494,22 @@ b = a.bar
[out]
main:9: error: Incompatible types in assignment (expression has type "A", variable has type "B")

[case testGetattrWithGetitem]
class A:
def __getattr__(self, x: str) -> 'A':
return A()

a = A()
a[0] # E: Value of type "A" is not indexable

[case testGetattrWithCall]
class A:
def __getattr__(self, x: str) -> 'A':
return A()

a = A()
a.y() # E: "A" not callable

[case testNestedGetattr]
def foo() -> object:
def __getattr__() -> None: # no error because not in a class
Expand Down

0 comments on commit 94746d6

Please sign in to comment.