Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 13 additions & 10 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,18 +1,21 @@
language: python
cache: pip
python:
- 2.7
- 3.4
- 3.5
- 3.6
- nightly
- pypy
- pypy-5.3
- pypy3
matrix:
include:
- python: 2.7
- python: 3.4
- python: 3.5
- python: 3.6
- python: pypy
- python: pypy-5.3
- python: pypy3
- python: 3.7
dist: xenial
- python: nightly
dist: xenial
install:
- pip install --upgrade .
- pip list
script:
- python setup.py test -q
- if [ "$TRAVIS_PYTHON_VERSION" != "nightly" ]; then pip install flake8==2.1.0 pep8==1.5.6 && flake8 --version && flake8 pyflakes setup.py; fi
sudo: false
18 changes: 18 additions & 0 deletions pyflakes/checker.py
Original file line number Diff line number Diff line change
Expand Up @@ -476,6 +476,7 @@ class GeneratorScope(Scope):
class ModuleScope(Scope):
"""Scope for a module."""
_futures_allowed = True
_annotations_future_enabled = False


class DoctestScope(ModuleScope):
Expand Down Expand Up @@ -628,6 +629,19 @@ def futuresAllowed(self, value):
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]
Expand Down Expand Up @@ -1068,6 +1082,8 @@ def handleForwardAnnotation():
self.handleNode(parsed_annotation, node)

self.deferFunction(handleForwardAnnotation)
elif self.annotationsFutureEnabled:
self.deferFunction(lambda: self.handleNode(annotation, node))
else:
self.handleNode(annotation, node)

Expand Down Expand Up @@ -1448,6 +1464,8 @@ def IMPORTFROM(self, node):
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):
Expand Down
18 changes: 18 additions & 0 deletions pyflakes/test/test_other.py
Original file line number Diff line number Diff line change
Expand Up @@ -2055,6 +2055,24 @@ class A: pass
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")
Expand Down
2 changes: 1 addition & 1 deletion tox.ini
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[tox]
skip_missing_interpreters = True
envlist =
py27,py34,py35,py36,pypy,pypy3
py27,py34,py35,py36,py37,pypy,pypy3

[testenv]
deps =
Expand Down