pyflakes 3.3.2__tar.gz → 3.4.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {pyflakes-3.3.2 → pyflakes-3.4.0}/NEWS.rst +8 -0
- {pyflakes-3.3.2 → pyflakes-3.4.0}/PKG-INFO +1 -1
- pyflakes-3.4.0/pyflakes/__init__.py +1 -0
- {pyflakes-3.3.2 → pyflakes-3.4.0}/pyflakes/checker.py +19 -2
- {pyflakes-3.3.2 → pyflakes-3.4.0}/pyflakes/messages.py +4 -0
- {pyflakes-3.3.2 → pyflakes-3.4.0}/pyflakes/test/test_imports.py +5 -1
- {pyflakes-3.3.2 → pyflakes-3.4.0}/pyflakes/test/test_other.py +16 -0
- {pyflakes-3.3.2 → pyflakes-3.4.0}/pyflakes/test/test_type_annotations.py +22 -3
- {pyflakes-3.3.2 → pyflakes-3.4.0}/pyflakes.egg-info/PKG-INFO +1 -1
- pyflakes-3.3.2/pyflakes/__init__.py +0 -1
- {pyflakes-3.3.2 → pyflakes-3.4.0}/AUTHORS +0 -0
- {pyflakes-3.3.2 → pyflakes-3.4.0}/LICENSE +0 -0
- {pyflakes-3.3.2 → pyflakes-3.4.0}/MANIFEST.in +0 -0
- {pyflakes-3.3.2 → pyflakes-3.4.0}/README.rst +0 -0
- {pyflakes-3.3.2 → pyflakes-3.4.0}/bin/pyflakes +0 -0
- {pyflakes-3.3.2 → pyflakes-3.4.0}/pyflakes/__main__.py +0 -0
- {pyflakes-3.3.2 → pyflakes-3.4.0}/pyflakes/api.py +0 -0
- {pyflakes-3.3.2 → pyflakes-3.4.0}/pyflakes/reporter.py +0 -0
- {pyflakes-3.3.2 → pyflakes-3.4.0}/pyflakes/scripts/__init__.py +0 -0
- {pyflakes-3.3.2 → pyflakes-3.4.0}/pyflakes/scripts/pyflakes.py +0 -0
- {pyflakes-3.3.2 → pyflakes-3.4.0}/pyflakes/test/__init__.py +0 -0
- {pyflakes-3.3.2 → pyflakes-3.4.0}/pyflakes/test/harness.py +0 -0
- {pyflakes-3.3.2 → pyflakes-3.4.0}/pyflakes/test/test_api.py +0 -0
- {pyflakes-3.3.2 → pyflakes-3.4.0}/pyflakes/test/test_builtin.py +0 -0
- {pyflakes-3.3.2 → pyflakes-3.4.0}/pyflakes/test/test_code_segment.py +0 -0
- {pyflakes-3.3.2 → pyflakes-3.4.0}/pyflakes/test/test_dict.py +0 -0
- {pyflakes-3.3.2 → pyflakes-3.4.0}/pyflakes/test/test_doctests.py +0 -0
- {pyflakes-3.3.2 → pyflakes-3.4.0}/pyflakes/test/test_is_literal.py +0 -0
- {pyflakes-3.3.2 → pyflakes-3.4.0}/pyflakes/test/test_match.py +0 -0
- {pyflakes-3.3.2 → pyflakes-3.4.0}/pyflakes/test/test_undefined_names.py +0 -0
- {pyflakes-3.3.2 → pyflakes-3.4.0}/pyflakes.egg-info/SOURCES.txt +0 -0
- {pyflakes-3.3.2 → pyflakes-3.4.0}/pyflakes.egg-info/dependency_links.txt +0 -0
- {pyflakes-3.3.2 → pyflakes-3.4.0}/pyflakes.egg-info/entry_points.txt +0 -0
- {pyflakes-3.3.2 → pyflakes-3.4.0}/pyflakes.egg-info/top_level.txt +0 -0
- {pyflakes-3.3.2 → pyflakes-3.4.0}/setup.cfg +0 -0
- {pyflakes-3.3.2 → pyflakes-3.4.0}/setup.py +0 -0
|
@@ -1,3 +1,11 @@
|
|
|
1
|
+
3.4.0 (2025-06-20)
|
|
2
|
+
|
|
3
|
+
- Add support for python 3.14
|
|
4
|
+
- Add "t-string is missing placeholders" error
|
|
5
|
+
- Fix annotation erroneously causing a name to be defined with
|
|
6
|
+
``from __future__ import annotations``
|
|
7
|
+
- Add support for always-deferred annotations (PEP 749)
|
|
8
|
+
|
|
1
9
|
3.3.2 (2025-03-31)
|
|
2
10
|
|
|
3
11
|
- Fix crash with ``global`` / ``nonlocal`` in class bodies (regressed in 3.3.0)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = '3.4.0'
|
|
@@ -1216,7 +1216,10 @@ class Checker:
|
|
|
1216
1216
|
def _in_postponed_annotation(self):
|
|
1217
1217
|
return (
|
|
1218
1218
|
self._in_annotation == AnnotationState.STRING or
|
|
1219
|
-
|
|
1219
|
+
(
|
|
1220
|
+
self._in_annotation == AnnotationState.BARE and
|
|
1221
|
+
(self.annotationsFutureEnabled or sys.version_info >= (3, 14))
|
|
1222
|
+
)
|
|
1220
1223
|
)
|
|
1221
1224
|
|
|
1222
1225
|
def handleChildren(self, tree, omit=None):
|
|
@@ -1350,7 +1353,7 @@ class Checker:
|
|
|
1350
1353
|
annotation.col_offset,
|
|
1351
1354
|
messages.ForwardAnnotationSyntaxError,
|
|
1352
1355
|
))
|
|
1353
|
-
elif self.annotationsFutureEnabled:
|
|
1356
|
+
elif self.annotationsFutureEnabled or sys.version_info >= (3, 14):
|
|
1354
1357
|
self.handle_annotation_always_deferred(annotation, node)
|
|
1355
1358
|
else:
|
|
1356
1359
|
self.handleNode(annotation, node)
|
|
@@ -1776,6 +1779,20 @@ class Checker:
|
|
|
1776
1779
|
finally:
|
|
1777
1780
|
self._in_fstring = orig
|
|
1778
1781
|
|
|
1782
|
+
def TEMPLATESTR(self, node):
|
|
1783
|
+
if not any(isinstance(x, ast.Interpolation) for x in node.values):
|
|
1784
|
+
self.report(messages.TStringMissingPlaceholders, node)
|
|
1785
|
+
|
|
1786
|
+
# similar to f-strings, conversion / etc. flags are parsed as f-strings
|
|
1787
|
+
# without placeholders
|
|
1788
|
+
self._in_fstring, orig = True, self._in_fstring
|
|
1789
|
+
try:
|
|
1790
|
+
self.handleChildren(node)
|
|
1791
|
+
finally:
|
|
1792
|
+
self._in_fstring = orig
|
|
1793
|
+
|
|
1794
|
+
INTERPOLATION = handleChildren
|
|
1795
|
+
|
|
1779
1796
|
def DICT(self, node):
|
|
1780
1797
|
# Complain if there are duplicate keys with different values
|
|
1781
1798
|
# If they have the same value it's not going to cause potentially
|
|
@@ -266,6 +266,10 @@ class FStringMissingPlaceholders(Message):
|
|
|
266
266
|
message = 'f-string is missing placeholders'
|
|
267
267
|
|
|
268
268
|
|
|
269
|
+
class TStringMissingPlaceholders(Message):
|
|
270
|
+
message = 't-string is missing placeholders'
|
|
271
|
+
|
|
272
|
+
|
|
269
273
|
class StringDotFormatExtraPositionalArguments(Message):
|
|
270
274
|
message = "'...'.format(...) has unused arguments at position(s): %s"
|
|
271
275
|
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
from sys import version_info
|
|
2
|
+
|
|
1
3
|
from pyflakes import messages as m
|
|
2
4
|
from pyflakes.checker import (
|
|
3
5
|
FutureImportation,
|
|
@@ -6,7 +8,7 @@ from pyflakes.checker import (
|
|
|
6
8
|
StarImportation,
|
|
7
9
|
SubmoduleImportation,
|
|
8
10
|
)
|
|
9
|
-
from pyflakes.test.harness import TestCase, skip
|
|
11
|
+
from pyflakes.test.harness import TestCase, skip, skipIf
|
|
10
12
|
|
|
11
13
|
|
|
12
14
|
class TestImportationObject(TestCase):
|
|
@@ -990,12 +992,14 @@ class Test(TestCase):
|
|
|
990
992
|
assert print_function is not division
|
|
991
993
|
''')
|
|
992
994
|
|
|
995
|
+
@skipIf(version_info >= (3, 14), 'in 3.14+ this is a SyntaxError')
|
|
993
996
|
def test_futureImportUndefined(self):
|
|
994
997
|
"""Importing undefined names from __future__ fails."""
|
|
995
998
|
self.flakes('''
|
|
996
999
|
from __future__ import print_statement
|
|
997
1000
|
''', m.FutureFeatureNotDefined)
|
|
998
1001
|
|
|
1002
|
+
@skipIf(version_info >= (3, 14), 'in 3.14+ this is a SyntaxError')
|
|
999
1003
|
def test_futureImportStar(self):
|
|
1000
1004
|
"""Importing '*' from __future__ fails."""
|
|
1001
1005
|
self.flakes('''
|
|
@@ -1766,6 +1766,13 @@ class TestUnusedAssignment(TestCase):
|
|
|
1766
1766
|
print(f'\x7b4*baz\N{RIGHT CURLY BRACKET}')
|
|
1767
1767
|
''')
|
|
1768
1768
|
|
|
1769
|
+
@skipIf(version_info < (3, 14), 'new in Python 3.14')
|
|
1770
|
+
def test_t_string(self):
|
|
1771
|
+
self.flakes('''
|
|
1772
|
+
baz = 0
|
|
1773
|
+
tmpl = t'hello {baz}'
|
|
1774
|
+
''')
|
|
1775
|
+
|
|
1769
1776
|
def test_assign_expr(self):
|
|
1770
1777
|
"""Test PEP 572 assignment expressions are treated as usage / write."""
|
|
1771
1778
|
self.flakes('''
|
|
@@ -1837,6 +1844,15 @@ class TestStringFormatting(TestCase):
|
|
|
1837
1844
|
print(f'{x:>2} {y:>2}')
|
|
1838
1845
|
''')
|
|
1839
1846
|
|
|
1847
|
+
@skipIf(version_info < (3, 14), 'new in Python 3.14')
|
|
1848
|
+
def test_t_string_missing_placeholders(self):
|
|
1849
|
+
self.flakes("t'foo'", m.TStringMissingPlaceholders)
|
|
1850
|
+
# make sure this does not trigger the f-string placeholder error
|
|
1851
|
+
self.flakes('''
|
|
1852
|
+
x = y = 5
|
|
1853
|
+
tmpl = t'{x:0{y}}'
|
|
1854
|
+
''')
|
|
1855
|
+
|
|
1840
1856
|
def test_invalid_dot_format_calls(self):
|
|
1841
1857
|
self.flakes('''
|
|
1842
1858
|
'{'.format(1)
|
|
@@ -152,6 +152,9 @@ class TestTypeAnnotations(TestCase):
|
|
|
152
152
|
""", m.RedefinedWhileUnused)
|
|
153
153
|
|
|
154
154
|
def test_variable_annotations(self):
|
|
155
|
+
def undefined_names_before_py314(*, n: int):
|
|
156
|
+
return (m.UndefinedName,) * n if version_info < (3, 14) else ()
|
|
157
|
+
|
|
155
158
|
self.flakes('''
|
|
156
159
|
name: str
|
|
157
160
|
age: int
|
|
@@ -264,7 +267,8 @@ class TestTypeAnnotations(TestCase):
|
|
|
264
267
|
self.flakes('''
|
|
265
268
|
def f(a: A) -> A: pass
|
|
266
269
|
class A: pass
|
|
267
|
-
''',
|
|
270
|
+
''', *undefined_names_before_py314(n=2))
|
|
271
|
+
|
|
268
272
|
self.flakes('''
|
|
269
273
|
def f(a: 'A') -> 'A': return a
|
|
270
274
|
class A: pass
|
|
@@ -272,7 +276,7 @@ class TestTypeAnnotations(TestCase):
|
|
|
272
276
|
self.flakes('''
|
|
273
277
|
a: A
|
|
274
278
|
class A: pass
|
|
275
|
-
''',
|
|
279
|
+
''', *undefined_names_before_py314(n=1))
|
|
276
280
|
self.flakes('''
|
|
277
281
|
a: 'A'
|
|
278
282
|
class A: pass
|
|
@@ -280,7 +284,7 @@ class TestTypeAnnotations(TestCase):
|
|
|
280
284
|
self.flakes('''
|
|
281
285
|
T: object
|
|
282
286
|
def f(t: T): pass
|
|
283
|
-
''',
|
|
287
|
+
''', *undefined_names_before_py314(n=1))
|
|
284
288
|
self.flakes('''
|
|
285
289
|
T: object
|
|
286
290
|
def g(t: 'T'): pass
|
|
@@ -410,6 +414,21 @@ class TestTypeAnnotations(TestCase):
|
|
|
410
414
|
def g(t: 'T'): pass
|
|
411
415
|
''')
|
|
412
416
|
|
|
417
|
+
def test_annotations_do_not_define_names_with_future_annotations(self):
|
|
418
|
+
self.flakes('''
|
|
419
|
+
from __future__ import annotations
|
|
420
|
+
def f():
|
|
421
|
+
x: str
|
|
422
|
+
print(x)
|
|
423
|
+
''', m.UndefinedName)
|
|
424
|
+
|
|
425
|
+
@skipIf(version_info < (3, 14), 'new in Python 3.14')
|
|
426
|
+
def test_postponed_annotations_py314(self):
|
|
427
|
+
self.flakes('''
|
|
428
|
+
def f(x: C) -> None: pass
|
|
429
|
+
class C: pass
|
|
430
|
+
''')
|
|
431
|
+
|
|
413
432
|
def test_type_annotation_clobbers_all(self):
|
|
414
433
|
self.flakes('''\
|
|
415
434
|
from typing import TYPE_CHECKING, List
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = '3.3.2'
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|