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.
Files changed (36) hide show
  1. {pyflakes-3.3.2 → pyflakes-3.4.0}/NEWS.rst +8 -0
  2. {pyflakes-3.3.2 → pyflakes-3.4.0}/PKG-INFO +1 -1
  3. pyflakes-3.4.0/pyflakes/__init__.py +1 -0
  4. {pyflakes-3.3.2 → pyflakes-3.4.0}/pyflakes/checker.py +19 -2
  5. {pyflakes-3.3.2 → pyflakes-3.4.0}/pyflakes/messages.py +4 -0
  6. {pyflakes-3.3.2 → pyflakes-3.4.0}/pyflakes/test/test_imports.py +5 -1
  7. {pyflakes-3.3.2 → pyflakes-3.4.0}/pyflakes/test/test_other.py +16 -0
  8. {pyflakes-3.3.2 → pyflakes-3.4.0}/pyflakes/test/test_type_annotations.py +22 -3
  9. {pyflakes-3.3.2 → pyflakes-3.4.0}/pyflakes.egg-info/PKG-INFO +1 -1
  10. pyflakes-3.3.2/pyflakes/__init__.py +0 -1
  11. {pyflakes-3.3.2 → pyflakes-3.4.0}/AUTHORS +0 -0
  12. {pyflakes-3.3.2 → pyflakes-3.4.0}/LICENSE +0 -0
  13. {pyflakes-3.3.2 → pyflakes-3.4.0}/MANIFEST.in +0 -0
  14. {pyflakes-3.3.2 → pyflakes-3.4.0}/README.rst +0 -0
  15. {pyflakes-3.3.2 → pyflakes-3.4.0}/bin/pyflakes +0 -0
  16. {pyflakes-3.3.2 → pyflakes-3.4.0}/pyflakes/__main__.py +0 -0
  17. {pyflakes-3.3.2 → pyflakes-3.4.0}/pyflakes/api.py +0 -0
  18. {pyflakes-3.3.2 → pyflakes-3.4.0}/pyflakes/reporter.py +0 -0
  19. {pyflakes-3.3.2 → pyflakes-3.4.0}/pyflakes/scripts/__init__.py +0 -0
  20. {pyflakes-3.3.2 → pyflakes-3.4.0}/pyflakes/scripts/pyflakes.py +0 -0
  21. {pyflakes-3.3.2 → pyflakes-3.4.0}/pyflakes/test/__init__.py +0 -0
  22. {pyflakes-3.3.2 → pyflakes-3.4.0}/pyflakes/test/harness.py +0 -0
  23. {pyflakes-3.3.2 → pyflakes-3.4.0}/pyflakes/test/test_api.py +0 -0
  24. {pyflakes-3.3.2 → pyflakes-3.4.0}/pyflakes/test/test_builtin.py +0 -0
  25. {pyflakes-3.3.2 → pyflakes-3.4.0}/pyflakes/test/test_code_segment.py +0 -0
  26. {pyflakes-3.3.2 → pyflakes-3.4.0}/pyflakes/test/test_dict.py +0 -0
  27. {pyflakes-3.3.2 → pyflakes-3.4.0}/pyflakes/test/test_doctests.py +0 -0
  28. {pyflakes-3.3.2 → pyflakes-3.4.0}/pyflakes/test/test_is_literal.py +0 -0
  29. {pyflakes-3.3.2 → pyflakes-3.4.0}/pyflakes/test/test_match.py +0 -0
  30. {pyflakes-3.3.2 → pyflakes-3.4.0}/pyflakes/test/test_undefined_names.py +0 -0
  31. {pyflakes-3.3.2 → pyflakes-3.4.0}/pyflakes.egg-info/SOURCES.txt +0 -0
  32. {pyflakes-3.3.2 → pyflakes-3.4.0}/pyflakes.egg-info/dependency_links.txt +0 -0
  33. {pyflakes-3.3.2 → pyflakes-3.4.0}/pyflakes.egg-info/entry_points.txt +0 -0
  34. {pyflakes-3.3.2 → pyflakes-3.4.0}/pyflakes.egg-info/top_level.txt +0 -0
  35. {pyflakes-3.3.2 → pyflakes-3.4.0}/setup.cfg +0 -0
  36. {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)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: pyflakes
3
- Version: 3.3.2
3
+ Version: 3.4.0
4
4
  Summary: passive checker of Python programs
5
5
  Home-page: https://github.com/PyCQA/pyflakes
6
6
  Author: A lot of people
@@ -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
- self.annotationsFutureEnabled
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
- ''', m.UndefinedName, m.UndefinedName)
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
- ''', m.UndefinedName)
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
- ''', m.UndefinedName)
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,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: pyflakes
3
- Version: 3.3.2
3
+ Version: 3.4.0
4
4
  Summary: passive checker of Python programs
5
5
  Home-page: https://github.com/PyCQA/pyflakes
6
6
  Author: A lot of people
@@ -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