summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnthony Sottile <asottile@umich.edu>2019-03-01 04:37:20 -0800
committerIan Stapleton Cordasco <graffatcolmingov@gmail.com>2019-03-01 07:37:20 -0500
commit232cb1d27ee134bf96adc8f37e53589dc259b159 (patch)
tree9d1fb9bd3dc89ee02f0819a25349a66d5d35ad93
parent6ba3f8e0b59b8fe880345be7ae594ccd76661f6d (diff)
downloadpyflakes-232cb1d27ee134bf96adc8f37e53589dc259b159.tar.gz
Improve @overload detection (#435)
* Support @overload mixed with other decorators * Detect @overload not just at module scope
-rw-r--r--pyflakes/checker.py25
-rw-r--r--pyflakes/test/test_type_annotations.py35
2 files changed, 52 insertions, 8 deletions
diff --git a/pyflakes/checker.py b/pyflakes/checker.py
index 4c88af2..0e636c1 100644
--- a/pyflakes/checker.py
+++ b/pyflakes/checker.py
@@ -530,14 +530,21 @@ def getNodeName(node):
return node.name
-def is_typing_overload(value, scope):
+def is_typing_overload(value, scope_stack):
+ def name_is_typing_overload(name): # type: (str) -> bool
+ for scope in reversed(scope_stack):
+ if name in scope:
+ return (
+ isinstance(scope[name], ImportationFrom) and
+ scope[name].fullName == 'typing.overload'
+ )
+ else:
+ return False
+
def is_typing_overload_decorator(node):
return (
(
- isinstance(node, ast.Name) and
- node.id in scope and
- isinstance(scope[node.id], ImportationFrom) and
- scope[node.id].fullName == 'typing.overload'
+ isinstance(node, ast.Name) and name_is_typing_overload(node.id)
) or (
isinstance(node, ast.Attribute) and
isinstance(node.value, ast.Name) and
@@ -548,8 +555,10 @@ def is_typing_overload(value, scope):
return (
isinstance(value.source, ast.FunctionDef) and
- len(value.source.decorator_list) == 1 and
- is_typing_overload_decorator(value.source.decorator_list[0])
+ any(
+ is_typing_overload_decorator(dec)
+ for dec in value.source.decorator_list
+ )
)
@@ -888,7 +897,7 @@ class Checker(object):
node, value.name, existing.source)
elif not existing.used and value.redefines(existing):
if value.name != '_' or isinstance(existing, Importation):
- if not is_typing_overload(existing, self.scope):
+ if not is_typing_overload(existing, self.scopeStack):
self.report(messages.RedefinedWhileUnused,
node, value.name, existing.source)
diff --git a/pyflakes/test/test_type_annotations.py b/pyflakes/test/test_type_annotations.py
index 48635bb..b8876cb 100644
--- a/pyflakes/test/test_type_annotations.py
+++ b/pyflakes/test/test_type_annotations.py
@@ -39,6 +39,41 @@ class TestTypeAnnotations(TestCase):
return s
""")
+ def test_overload_with_multiple_decorators(self):
+ self.flakes("""
+ from typing import overload
+ dec = lambda f: f
+
+ @dec
+ @overload
+ def f(x): # type: (int) -> int
+ pass
+
+ @dec
+ @overload
+ def f(x): # type: (str) -> str
+ pass
+
+ @dec
+ def f(x): return x
+ """)
+
+ def test_overload_in_class(self):
+ self.flakes("""
+ from typing import overload
+
+ class C:
+ @overload
+ def f(self, x): # type: (int) -> int
+ pass
+
+ @overload
+ def f(self, x): # type: (str) -> str
+ pass
+
+ def f(self, x): return x
+ """)
+
def test_not_a_typing_overload(self):
"""regression test for @typing.overload detection bug in 2.1.0"""
self.flakes("""