From 6ee966df7e1973771f578bb6d5d041785a0685ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rn=20Heissler?= Date: Sat, 22 Dec 2018 16:57:51 +0100 Subject: 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. --- pyflakes/checker.py | 18 ++++++++++++++++++ pyflakes/test/test_other.py | 18 ++++++++++++++++++ 2 files changed, 36 insertions(+) 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): @@ -628,6 +629,19 @@ class Checker(object): if isinstance(self.scope, ModuleScope): 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") -- cgit v1.2.1