pyflakes 3.3.0__tar.gz → 3.3.2__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.0 → pyflakes-3.3.2}/NEWS.rst +8 -0
  2. {pyflakes-3.3.0 → pyflakes-3.3.2}/PKG-INFO +1 -1
  3. pyflakes-3.3.2/pyflakes/__init__.py +1 -0
  4. {pyflakes-3.3.0 → pyflakes-3.3.2}/pyflakes/checker.py +16 -10
  5. {pyflakes-3.3.0 → pyflakes-3.3.2}/pyflakes/test/test_other.py +37 -0
  6. {pyflakes-3.3.0 → pyflakes-3.3.2}/pyflakes.egg-info/PKG-INFO +1 -1
  7. pyflakes-3.3.0/pyflakes/__init__.py +0 -1
  8. {pyflakes-3.3.0 → pyflakes-3.3.2}/AUTHORS +0 -0
  9. {pyflakes-3.3.0 → pyflakes-3.3.2}/LICENSE +0 -0
  10. {pyflakes-3.3.0 → pyflakes-3.3.2}/MANIFEST.in +0 -0
  11. {pyflakes-3.3.0 → pyflakes-3.3.2}/README.rst +0 -0
  12. {pyflakes-3.3.0 → pyflakes-3.3.2}/bin/pyflakes +0 -0
  13. {pyflakes-3.3.0 → pyflakes-3.3.2}/pyflakes/__main__.py +0 -0
  14. {pyflakes-3.3.0 → pyflakes-3.3.2}/pyflakes/api.py +0 -0
  15. {pyflakes-3.3.0 → pyflakes-3.3.2}/pyflakes/messages.py +0 -0
  16. {pyflakes-3.3.0 → pyflakes-3.3.2}/pyflakes/reporter.py +0 -0
  17. {pyflakes-3.3.0 → pyflakes-3.3.2}/pyflakes/scripts/__init__.py +0 -0
  18. {pyflakes-3.3.0 → pyflakes-3.3.2}/pyflakes/scripts/pyflakes.py +0 -0
  19. {pyflakes-3.3.0 → pyflakes-3.3.2}/pyflakes/test/__init__.py +0 -0
  20. {pyflakes-3.3.0 → pyflakes-3.3.2}/pyflakes/test/harness.py +0 -0
  21. {pyflakes-3.3.0 → pyflakes-3.3.2}/pyflakes/test/test_api.py +0 -0
  22. {pyflakes-3.3.0 → pyflakes-3.3.2}/pyflakes/test/test_builtin.py +0 -0
  23. {pyflakes-3.3.0 → pyflakes-3.3.2}/pyflakes/test/test_code_segment.py +0 -0
  24. {pyflakes-3.3.0 → pyflakes-3.3.2}/pyflakes/test/test_dict.py +0 -0
  25. {pyflakes-3.3.0 → pyflakes-3.3.2}/pyflakes/test/test_doctests.py +0 -0
  26. {pyflakes-3.3.0 → pyflakes-3.3.2}/pyflakes/test/test_imports.py +0 -0
  27. {pyflakes-3.3.0 → pyflakes-3.3.2}/pyflakes/test/test_is_literal.py +0 -0
  28. {pyflakes-3.3.0 → pyflakes-3.3.2}/pyflakes/test/test_match.py +0 -0
  29. {pyflakes-3.3.0 → pyflakes-3.3.2}/pyflakes/test/test_type_annotations.py +0 -0
  30. {pyflakes-3.3.0 → pyflakes-3.3.2}/pyflakes/test/test_undefined_names.py +0 -0
  31. {pyflakes-3.3.0 → pyflakes-3.3.2}/pyflakes.egg-info/SOURCES.txt +0 -0
  32. {pyflakes-3.3.0 → pyflakes-3.3.2}/pyflakes.egg-info/dependency_links.txt +0 -0
  33. {pyflakes-3.3.0 → pyflakes-3.3.2}/pyflakes.egg-info/entry_points.txt +0 -0
  34. {pyflakes-3.3.0 → pyflakes-3.3.2}/pyflakes.egg-info/top_level.txt +0 -0
  35. {pyflakes-3.3.0 → pyflakes-3.3.2}/setup.cfg +0 -0
  36. {pyflakes-3.3.0 → pyflakes-3.3.2}/setup.py +0 -0
@@ -1,3 +1,11 @@
1
+ 3.3.2 (2025-03-31)
2
+
3
+ - Fix crash with ``global`` / ``nonlocal`` in class bodies (regressed in 3.3.0)
4
+
5
+ 3.3.1 (2025-03-30)
6
+
7
+ - Allow assignment expressions to redefine annotations (regressed in 3.3.0)
8
+
1
9
  3.3.0 (2025-03-29)
2
10
 
3
11
  - Add ``__debuggerskip__`` as a special local
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: pyflakes
3
- Version: 3.3.0
3
+ Version: 3.3.2
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.3.2'
@@ -526,7 +526,10 @@ class Scope(dict):
526
526
 
527
527
 
528
528
  class ClassScope(Scope):
529
- pass
529
+ def __init__(self):
530
+ super().__init__()
531
+ # {name: node}
532
+ self.indirect_assignments = {}
530
533
 
531
534
 
532
535
  class FunctionScope(Scope):
@@ -566,9 +569,6 @@ class FunctionScope(Scope):
566
569
  if not binding.used and isinstance(binding, Annotation):
567
570
  yield name, binding
568
571
 
569
- def unused_indirect_assignments(self):
570
- return self.indirect_assignments.items()
571
-
572
572
 
573
573
  class TypeScope(Scope):
574
574
  pass
@@ -835,6 +835,10 @@ class Checker:
835
835
  which were imported but unused.
836
836
  """
837
837
  for scope in self.deadScopes:
838
+ if isinstance(scope, (ClassScope, FunctionScope)):
839
+ for name, node in scope.indirect_assignments.items():
840
+ self.report(messages.UnusedIndirectAssignment, node, name)
841
+
838
842
  # imports in classes are public members
839
843
  if isinstance(scope, ClassScope):
840
844
  continue
@@ -844,8 +848,6 @@ class Checker:
844
848
  self.report(messages.UnusedVariable, binding.source, name)
845
849
  for name, binding in scope.unused_annotations():
846
850
  self.report(messages.UnusedAnnotation, binding.source, name)
847
- for name, node in scope.unused_indirect_assignments():
848
- self.report(messages.UnusedIndirectAssignment, node, name)
849
851
 
850
852
  all_binding = scope.get('__all__')
851
853
  if all_binding and not isinstance(all_binding, ExportBinding):
@@ -988,7 +990,7 @@ class Checker:
988
990
  self.report(messages.RedefinedWhileUnused,
989
991
  node, value.name, existing.source)
990
992
 
991
- if isinstance(scope, FunctionScope):
993
+ if isinstance(scope, (ClassScope, FunctionScope)):
992
994
  scope.indirect_assignments.pop(value.name, None)
993
995
 
994
996
  elif isinstance(existing, Importation) and value.redefines(existing):
@@ -1008,8 +1010,12 @@ class Checker:
1008
1010
  for scope in reversed(self.scopeStack)
1009
1011
  if not isinstance(scope, GeneratorScope)
1010
1012
  )
1011
- # it may be a re-assignment to an already existing name
1012
- scope.setdefault(value.name, value)
1013
+ if value.name in scope and isinstance(scope[value.name], Annotation):
1014
+ # re-assignment to name that was previously only an annotation
1015
+ scope[value.name] = value
1016
+ else:
1017
+ # it may be a re-assignment to an already existing name
1018
+ scope.setdefault(value.name, value)
1013
1019
  else:
1014
1020
  self.scope[value.name] = value
1015
1021
 
@@ -1187,7 +1193,7 @@ class Checker:
1187
1193
  # be executed.
1188
1194
  return
1189
1195
 
1190
- if isinstance(self.scope, FunctionScope):
1196
+ if isinstance(self.scope, (ClassScope, FunctionScope)):
1191
1197
  self.scope.indirect_assignments.pop(name, None)
1192
1198
 
1193
1199
  if isinstance(self.scope, FunctionScope) and name in self.scope.globals:
@@ -1121,6 +1121,36 @@ class Test(TestCase):
1121
1121
  g = 2
1122
1122
  ''', m.UnusedIndirectAssignment, m.UnusedVariable)
1123
1123
 
1124
+ def test_global_nonlocal_in_class_bodies(self):
1125
+ self.flakes('''
1126
+ g = 0
1127
+ class C:
1128
+ global g
1129
+ g = 1
1130
+ def f():
1131
+ nl = 0
1132
+ class C:
1133
+ nonlocal nl
1134
+ nl = 1
1135
+ ''')
1136
+
1137
+ def test_unused_global_in_class(self):
1138
+ self.flakes('''
1139
+ g = 0
1140
+ class C:
1141
+ global g
1142
+ u = g
1143
+ ''', m.UnusedIndirectAssignment)
1144
+
1145
+ def test_unused_nonlocal_in_clas(self):
1146
+ self.flakes('''
1147
+ def f():
1148
+ nl = 1
1149
+ class C:
1150
+ nonlocal nl
1151
+ u = nl
1152
+ ''', m.UnusedIndirectAssignment)
1153
+
1124
1154
  def test_function_arguments(self):
1125
1155
  """
1126
1156
  Test to traverse ARG and ARGUMENT handler
@@ -1744,6 +1774,13 @@ class TestUnusedAssignment(TestCase):
1744
1774
  print(x)
1745
1775
  ''')
1746
1776
 
1777
+ def test_assign_expr_after_annotation(self):
1778
+ self.flakes("""
1779
+ a: int
1780
+ print(a := 3)
1781
+ print(a)
1782
+ """)
1783
+
1747
1784
  def test_assign_expr_generator_scope(self):
1748
1785
  """Test assignment expressions in generator expressions."""
1749
1786
  self.flakes('''
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: pyflakes
3
- Version: 3.3.0
3
+ Version: 3.3.2
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.0'
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