summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJörn Heissler <joernheissler@users.noreply.github.com>2018-12-22 16:57:51 +0100
committerIan Stapleton Cordasco <graffatcolmingov@gmail.com>2018-12-22 09:57:51 -0600
commit6ee966df7e1973771f578bb6d5d041785a0685ec (patch)
tree000b3a68b449fff9eb479659637dcbcf367f92a3
parentc6cc4b625b41683db8ff5287947c64744e8bae2b (diff)
downloadpyflakes-6ee966df7e1973771f578bb6d5d041785a0685ec.tar.gz
Add support for PEP 563 (#356) (#374)
* Test with py3.7; Travis should use Xenial for 3.7 and nightly. * Add support for PEP 563 (#356) If a module imports annotations from __future__, postpone the evaluation of annotations like it is done for annotation strings.
-rw-r--r--pyflakes/checker.py18
-rw-r--r--pyflakes/test/test_other.py18
2 files changed, 36 insertions, 0 deletions
diff --git a/pyflakes/checker.py b/pyflakes/checker.py
index 5c12820..e05bdf4 100644
--- a/pyflakes/checker.py
+++ b/pyflakes/checker.py
@@ -476,6 +476,7 @@ class GeneratorScope(Scope):
class ModuleScope(Scope):
"""Scope for a module."""
_futures_allowed = True
+ _annotations_future_enabled = False
class DoctestScope(ModuleScope):
@@ -629,6 +630,19 @@ class Checker(object):
self.scope._futures_allowed = False
@property
+ def annotationsFutureEnabled(self):
+ scope = self.scopeStack[0]
+ if not isinstance(scope, ModuleScope):
+ return False
+ return scope._annotations_future_enabled
+
+ @annotationsFutureEnabled.setter
+ def annotationsFutureEnabled(self, value):
+ assert value is True
+ assert isinstance(self.scope, ModuleScope)
+ self.scope._annotations_future_enabled = True
+
+ @property
def scope(self):
return self.scopeStack[-1]
@@ -1068,6 +1082,8 @@ class Checker(object):
self.handleNode(parsed_annotation, node)
self.deferFunction(handleForwardAnnotation)
+ elif self.annotationsFutureEnabled:
+ self.deferFunction(lambda: self.handleNode(annotation, node))
else:
self.handleNode(annotation, node)
@@ -1448,6 +1464,8 @@ class Checker(object):
if alias.name not in __future__.all_feature_names:
self.report(messages.FutureFeatureNotDefined,
node, alias.name)
+ if alias.name == 'annotations':
+ self.annotationsFutureEnabled = True
elif alias.name == '*':
# Only Python 2, local import * is a SyntaxWarning
if not PY2 and not isinstance(self.scope, ModuleScope):
diff --git a/pyflakes/test/test_other.py b/pyflakes/test/test_other.py
index b8301ea..d0fff0a 100644
--- a/pyflakes/test/test_other.py
+++ b/pyflakes/test/test_other.py
@@ -2055,6 +2055,24 @@ class TestAsyncStatements(TestCase):
a: 'a: "A"'
''', m.ForwardAnnotationSyntaxError)
+ @skipIf(version_info < (3, 7), 'new in Python 3.7')
+ def test_postponed_annotations(self):
+ self.flakes('''
+ from __future__ import annotations
+ def f(a: A) -> A: pass
+ class A:
+ b: B
+ class B: pass
+ ''')
+
+ self.flakes('''
+ from __future__ import annotations
+ def f(a: A) -> A: pass
+ class A:
+ b: Undefined
+ class B: pass
+ ''', m.UndefinedName)
+
def test_raise_notimplemented(self):
self.flakes('''
raise NotImplementedError("This is fine")