Skip to content

Commit 98d4fa3

Browse files
authored
pyflakes: python3.8+ (#752)
1 parent 37f203e commit 98d4fa3

File tree

10 files changed

+31
-144
lines changed

10 files changed

+31
-144
lines changed

.github/workflows/test.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,12 @@ jobs:
1212
strategy:
1313
fail-fast: false
1414
matrix:
15-
python-version: ["3.6", "3.7", "3.8", "3.9", "3.10", "3.11.0-beta - 3.11.999", "pypy-3.9"]
15+
python-version: ["3.8", "3.9", "3.10", "3.11", "pypy-3.9"]
1616
os: [ubuntu-latest]
1717
# Include minimum py3 + maximum py3 + pypy3 on Windows
1818
include:
19-
- { os: "windows-latest" , python-version: "3.6" }
20-
- { os: "windows-latest" , python-version: "3.10" }
19+
- { os: "windows-latest" , python-version: "3.8" }
20+
- { os: "windows-latest" , python-version: "3.11" }
2121
- { os: "windows-latest" , python-version: "pypy-3.9" }
2222

2323
steps:

pyflakes/checker.py

Lines changed: 16 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818

1919
from pyflakes import messages
2020

21-
PY38_PLUS = sys.version_info >= (3, 8)
2221
PYPY = hasattr(sys, 'pypy_version_info')
2322

2423
builtin_vars = dir(builtins)
@@ -35,15 +34,12 @@ def getAlternatives(n):
3534

3635
FOR_TYPES = (ast.For, ast.AsyncFor)
3736

38-
if PY38_PLUS:
39-
def _is_singleton(node): # type: (ast.AST) -> bool
40-
return (
41-
isinstance(node, ast.Constant) and
42-
isinstance(node.value, (bool, type(Ellipsis), type(None)))
43-
)
44-
else:
45-
def _is_singleton(node): # type: (ast.AST) -> bool
46-
return isinstance(node, (ast.NameConstant, ast.Ellipsis))
37+
38+
def _is_singleton(node): # type: (ast.AST) -> bool
39+
return (
40+
isinstance(node, ast.Constant) and
41+
isinstance(node.value, (bool, type(Ellipsis), type(None)))
42+
)
4743

4844

4945
def _is_tuple_constant(node): # type: (ast.AST) -> bool
@@ -53,16 +49,8 @@ def _is_tuple_constant(node): # type: (ast.AST) -> bool
5349
)
5450

5551

56-
if PY38_PLUS:
57-
def _is_constant(node):
58-
return isinstance(node, ast.Constant) or _is_tuple_constant(node)
59-
else:
60-
def _is_constant(node):
61-
return (
62-
isinstance(node, (ast.Str, ast.Num, ast.Bytes)) or
63-
_is_singleton(node) or
64-
_is_tuple_constant(node)
65-
)
52+
def _is_constant(node):
53+
return isinstance(node, ast.Constant) or _is_tuple_constant(node)
6654

6755

6856
def _is_const_non_singleton(node): # type: (ast.AST) -> bool
@@ -1176,7 +1164,7 @@ def handleNodeStore(self, node):
11761164
)
11771165
):
11781166
binding = ExportBinding(name, node._pyflakes_parent, self.scope)
1179-
elif PY38_PLUS and isinstance(parent_stmt, ast.NamedExpr):
1167+
elif isinstance(parent_stmt, ast.NamedExpr):
11801168
binding = NamedExprAssignment(name, node)
11811169
else:
11821170
binding = Assignment(name, node)
@@ -1252,13 +1240,7 @@ def getDocstring(self, node):
12521240
if not isinstance(node, ast.Str):
12531241
return (None, None)
12541242

1255-
if PYPY or PY38_PLUS:
1256-
doctest_lineno = node.lineno - 1
1257-
else:
1258-
# Computed incorrectly if the docstring has backslash
1259-
doctest_lineno = node.lineno - node.s.count('\n') - 1
1260-
1261-
return (node.s, doctest_lineno)
1243+
return (node.s, node.lineno - 1)
12621244

12631245
def handleNode(self, node, parent):
12641246
if node is None:
@@ -1729,12 +1711,9 @@ def STR(self, node):
17291711
else:
17301712
self.deferFunction(fn)
17311713

1732-
if PY38_PLUS:
1733-
def CONSTANT(self, node):
1734-
if isinstance(node.value, str):
1735-
return self.STR(node)
1736-
else:
1737-
NUM = BYTES = ELLIPSIS = CONSTANT = ignore
1714+
def CONSTANT(self, node):
1715+
if isinstance(node.value, str):
1716+
return self.STR(node)
17381717

17391718
# "slice" type nodes
17401719
SLICE = EXTSLICE = INDEX = handleChildren
@@ -1900,11 +1879,6 @@ def CONTINUE(self, node):
19001879
return
19011880
if isinstance(n, (ast.FunctionDef, ast.ClassDef)):
19021881
break
1903-
# Handle Try/TryFinally difference in Python < and >= 3.3
1904-
if hasattr(n, 'finalbody') and isinstance(node, ast.Continue):
1905-
if n_child in n.finalbody and not PY38_PLUS:
1906-
self.report(messages.ContinueInFinally, node)
1907-
return
19081882
if isinstance(node, ast.Continue):
19091883
self.report(messages.ContinueOutsideLoop, node)
19101884
else: # ast.Break
@@ -1952,10 +1926,9 @@ def LAMBDA(self, node):
19521926
args = []
19531927
annotations = []
19541928

1955-
if PY38_PLUS:
1956-
for arg in node.args.posonlyargs:
1957-
args.append(arg.arg)
1958-
annotations.append(arg.annotation)
1929+
for arg in node.args.posonlyargs:
1930+
args.append(arg.arg)
1931+
annotations.append(arg.annotation)
19591932
for arg in node.args.args + node.args.kwonlyargs:
19601933
args.append(arg.arg)
19611934
annotations.append(arg.annotation)

pyflakes/messages.py

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -198,13 +198,6 @@ class BreakOutsideLoop(Message):
198198
message = '\'break\' outside loop'
199199

200200

201-
class ContinueInFinally(Message):
202-
"""
203-
Indicates a continue statement in a finally block in a while or for loop.
204-
"""
205-
message = '\'continue\' not supported inside \'finally\' clause'
206-
207-
208201
class DefaultExceptNotLast(Message):
209202
"""
210203
Indicates an except: block as not the last exception handler.

pyflakes/reporter.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,6 @@ def syntaxError(self, filename, msg, lineno, offset, text):
6060
lineno = max(lineno, 1)
6161

6262
if offset is not None:
63-
if sys.version_info < (3, 8) and text is not None:
64-
offset = offset - (len(text) - len(line)) + 1
6563
# some versions of python emit an offset of -1 for certain encoding errors
6664
offset = max(offset, 1)
6765
self._stderr.write('%s:%d:%d: %s\n' %

pyflakes/test/test_api.py

Lines changed: 7 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -233,9 +233,7 @@ def test_syntaxError(self):
233233
"""
234234
err = io.StringIO()
235235
reporter = Reporter(None, err)
236-
reporter.syntaxError('foo.py', 'a problem', 3,
237-
8 if sys.version_info >= (3, 8) else 7,
238-
'bad line of source')
236+
reporter.syntaxError('foo.py', 'a problem', 3, 8, 'bad line of source')
239237
self.assertEqual(
240238
("foo.py:3:8: a problem\n"
241239
"bad line of source\n"
@@ -281,11 +279,10 @@ def test_multiLineSyntaxError(self):
281279
reporter = Reporter(None, err)
282280
reporter.syntaxError('foo.py', 'a problem', 3, len(lines[0]) + 7,
283281
'\n'.join(lines))
284-
column = 25 if sys.version_info >= (3, 8) else 7
285282
self.assertEqual(
286-
("foo.py:3:%d: a problem\n" % column +
283+
("foo.py:3:25: a problem\n" +
287284
lines[-1] + "\n" +
288-
" " * (column - 1) + "^\n"),
285+
" " * 24 + "^\n"),
289286
err.getvalue())
290287

291288
def test_unexpectedError(self):
@@ -417,10 +414,8 @@ def evaluate(source):
417414

418415
if PYPY or sys.version_info >= (3, 10):
419416
column = 12
420-
elif sys.version_info >= (3, 8):
421-
column = 8
422417
else:
423-
column = 11
418+
column = 8
424419
self.assertHasErrors(
425420
sourcePath,
426421
["""\
@@ -487,10 +482,8 @@ def foo(bar=baz, bax):
487482
column = 18
488483
elif sys.version_info >= (3, 9):
489484
column = 21
490-
elif sys.version_info >= (3, 8):
491-
column = 9
492485
else:
493-
column = 8
486+
column = 9
494487
last_line = ' ' * (column - 1) + '^\n'
495488
columnstr = '%d:' % column
496489
self.assertHasErrors(
@@ -512,7 +505,7 @@ def test_nonKeywordAfterKeywordSyntaxError(self):
512505
with self.makeTempFile(source) as sourcePath:
513506
if sys.version_info >= (3, 9):
514507
column = 17
515-
elif not PYPY and sys.version_info >= (3, 8):
508+
elif not PYPY:
516509
column = 14
517510
else:
518511
column = 13
@@ -679,18 +672,10 @@ def test_stdinReportsErrors(self):
679672
"max(1 for i in range(10), key=lambda x: x+1)",
680673
" ^",
681674
]
682-
elif sys.version_info >= (3, 8):
675+
else:
683676
expected_error = [
684677
"<stdin>:1:5: Generator expression must be parenthesized",
685678
]
686-
elif sys.version_info >= (3, 7):
687-
expected_error = [
688-
"<stdin>:1:4: Generator expression must be parenthesized",
689-
]
690-
elif sys.version_info >= (3, 6):
691-
expected_error = [
692-
"<stdin>:1:4: Generator expression must be parenthesized if not sole argument", # noqa: E501
693-
]
694679

695680
self.assertEqual(errlines, expected_error)
696681

pyflakes/test/test_doctests.py

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import sys
21
import textwrap
32

43
from pyflakes import messages as m
@@ -323,7 +322,7 @@ def doctest_stuff():
323322
m.DoctestSyntaxError).messages
324323
exc = exceptions[0]
325324
self.assertEqual(exc.lineno, 4)
326-
if not PYPY and sys.version_info >= (3, 8):
325+
if not PYPY:
327326
self.assertEqual(exc.col, 18)
328327
else:
329328
self.assertEqual(exc.col, 26)
@@ -339,10 +338,7 @@ def doctest_stuff():
339338
self.assertEqual(exc.col, 16)
340339
exc = exceptions[2]
341340
self.assertEqual(exc.lineno, 6)
342-
if PYPY or sys.version_info >= (3, 8):
343-
self.assertEqual(exc.col, 13)
344-
else:
345-
self.assertEqual(exc.col, 18)
341+
self.assertEqual(exc.col, 13)
346342

347343
def test_indentationErrorInDoctest(self):
348344
exc = self.flakes('''
@@ -353,10 +349,7 @@ def doctest_stuff():
353349
"""
354350
''', m.DoctestSyntaxError).messages[0]
355351
self.assertEqual(exc.lineno, 5)
356-
if PYPY or sys.version_info >= (3, 8):
357-
self.assertEqual(exc.col, 13)
358-
else:
359-
self.assertEqual(exc.col, 16)
352+
self.assertEqual(exc.col, 13)
360353

361354
def test_offsetWithMultiLineArgs(self):
362355
(exc1, exc2) = self.flakes(

pyflakes/test/test_other.py

Lines changed: 0 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -445,36 +445,6 @@ def test_continueInsideLoop(self):
445445
continue
446446
''')
447447

448-
@skipIf(version_info > (3, 8), "Python <= 3.8 only")
449-
def test_continueInFinally(self):
450-
# 'continue' inside 'finally' is a special syntax error
451-
# that is removed in 3.8
452-
self.flakes('''
453-
while True:
454-
try:
455-
pass
456-
finally:
457-
continue
458-
''', m.ContinueInFinally)
459-
460-
self.flakes('''
461-
while True:
462-
try:
463-
pass
464-
finally:
465-
if 1:
466-
if 2:
467-
continue
468-
''', m.ContinueInFinally)
469-
470-
# Even when not in a loop, this is the error Python gives
471-
self.flakes('''
472-
try:
473-
pass
474-
finally:
475-
continue
476-
''', m.ContinueInFinally)
477-
478448
def test_breakOutsideLoop(self):
479449
self.flakes('''
480450
break
@@ -1716,7 +1686,6 @@ def test_f_string(self):
17161686
print(f'\x7b4*baz\N{RIGHT CURLY BRACKET}')
17171687
''')
17181688

1719-
@skipIf(version_info < (3, 8), 'new in Python 3.8')
17201689
def test_assign_expr(self):
17211690
"""Test PEP 572 assignment expressions are treated as usage / write."""
17221691
self.flakes('''
@@ -1725,15 +1694,13 @@ def test_assign_expr(self):
17251694
print(x)
17261695
''')
17271696

1728-
@skipIf(version_info < (3, 8), 'new in Python 3.8')
17291697
def test_assign_expr_generator_scope(self):
17301698
"""Test assignment expressions in generator expressions."""
17311699
self.flakes('''
17321700
if (any((y := x[0]) for x in [[True]])):
17331701
print(y)
17341702
''')
17351703

1736-
@skipIf(version_info < (3, 8), 'new in Python 3.8')
17371704
def test_assign_expr_nested(self):
17381705
"""Test assignment expressions in nested expressions."""
17391706
self.flakes('''
@@ -1972,19 +1939,6 @@ async def read_data(db):
19721939
return output
19731940
''', m.BreakOutsideLoop)
19741941

1975-
@skipIf(version_info > (3, 8), "Python <= 3.8 only")
1976-
def test_continueInAsyncForFinally(self):
1977-
self.flakes('''
1978-
async def read_data(db):
1979-
output = []
1980-
async for row in db.cursor():
1981-
try:
1982-
output.append(row)
1983-
finally:
1984-
continue
1985-
return output
1986-
''', m.ContinueInFinally)
1987-
19881942
def test_asyncWith(self):
19891943
self.flakes('''
19901944
async def commit(session, data):

pyflakes/test/test_type_annotations.py

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -379,7 +379,6 @@ class c: pass
379379
async def func(c: c) -> None: pass
380380
''')
381381

382-
@skipIf(version_info < (3, 7), 'new in Python 3.7')
383382
def test_postponed_annotations(self):
384383
self.flakes('''
385384
from __future__ import annotations
@@ -434,7 +433,6 @@ def t(self) -> Y:
434433
return Y
435434
""", m.UndefinedName)
436435

437-
@skipIf(version_info < (3, 8), 'new in Python 3.8')
438436
def test_positional_only_argument_annotations(self):
439437
self.flakes("""
440438
from x import C
@@ -584,7 +582,6 @@ def f() -> "Optional['Queue[str]']":
584582
return None
585583
""")
586584

587-
@skipIf(version_info < (3, 7), 'new in Python 3.7')
588585
def test_partial_string_annotations_with_future_annotations(self):
589586
self.flakes("""
590587
from __future__ import annotations

setup.py

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -42,19 +42,14 @@ def get_long_description():
4242
author_email="[email protected]",
4343
url="https://github.com/PyCQA/pyflakes",
4444
packages=["pyflakes", "pyflakes.scripts", "pyflakes.test"],
45-
python_requires='>=3.6',
45+
python_requires='>=3.8',
4646
classifiers=[
4747
"Development Status :: 6 - Mature",
4848
"Environment :: Console",
4949
"Intended Audience :: Developers",
5050
"License :: OSI Approved :: MIT License",
5151
"Programming Language :: Python",
5252
"Programming Language :: Python :: 3",
53-
"Programming Language :: Python :: 3.6",
54-
"Programming Language :: Python :: 3.7",
55-
"Programming Language :: Python :: 3.8",
56-
"Programming Language :: Python :: 3.9",
57-
"Programming Language :: Python :: 3.10",
5853
"Programming Language :: Python :: 3 :: Only",
5954
"Programming Language :: Python :: Implementation :: CPython",
6055
"Programming Language :: Python :: Implementation :: PyPy",

0 commit comments

Comments
 (0)