Script 'mail_helper' called by obssrc
Hello community,
here is the log from the commit of package python-pyflakes for openSUSE:Factory
checked in at 2025-05-20 09:30:53
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-pyflakes (Old)
and /work/SRC/openSUSE:Factory/.python-pyflakes.new.30101 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-pyflakes"
Tue May 20 09:30:53 2025 rev:40 rq:1269465 version:3.3.2
Changes:
--------
--- /work/SRC/openSUSE:Factory/python-pyflakes/python-pyflakes.changes
2024-08-06 09:08:00.312903383 +0200
+++
/work/SRC/openSUSE:Factory/.python-pyflakes.new.30101/python-pyflakes.changes
2025-05-20 09:30:55.079272571 +0200
@@ -1,0 +2,13 @@
+Tue Apr 15 07:53:16 UTC 2025 - Dirk Müller <[email protected]>
+
+- update to 3.3.2:
+ * Fix crash with global / nonlocal in class bodies (regressed
+ in 3.3.0)
+ * Allow assignment expressions to redefine annotations
+ (regressed in 3.3.0)
+ * Add __debuggerskip__ as a special local
+ * Allow assignment expressions to redefine outer names
+ * Drop support for EOL python 3.8
+ * Add new error for unused global / nonlocal names
+
+-------------------------------------------------------------------
Old:
----
pyflakes-3.2.0.tar.gz
New:
----
pyflakes-3.3.2.tar.gz
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ python-pyflakes.spec ++++++
--- /var/tmp/diff_new_pack.OR85pE/_old 2025-05-20 09:30:55.747300406 +0200
+++ /var/tmp/diff_new_pack.OR85pE/_new 2025-05-20 09:30:55.747300406 +0200
@@ -1,7 +1,7 @@
#
# spec file for package python-pyflakes
#
-# Copyright (c) 2024 SUSE LLC
+# Copyright (c) 2025 SUSE LLC
#
# All modifications and additions to the file contributed by third parties
# remain the property of their copyright owners, unless otherwise agreed
@@ -18,7 +18,7 @@
%{?sle15_python_module_pythons}
Name: python-pyflakes
-Version: 3.2.0
+Version: 3.3.2
Release: 0
Summary: Passive checker of Python programs
License: MIT
++++++ pyflakes-3.2.0.tar.gz -> pyflakes-3.3.2.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pyflakes-3.2.0/NEWS.rst new/pyflakes-3.3.2/NEWS.rst
--- old/pyflakes-3.2.0/NEWS.rst 2024-01-05 01:26:21.000000000 +0100
+++ new/pyflakes-3.3.2/NEWS.rst 2025-03-31 15:19:39.000000000 +0200
@@ -1,3 +1,18 @@
+3.3.2 (2025-03-31)
+
+- Fix crash with ``global`` / ``nonlocal`` in class bodies (regressed in 3.3.0)
+
+3.3.1 (2025-03-30)
+
+- Allow assignment expressions to redefine annotations (regressed in 3.3.0)
+
+3.3.0 (2025-03-29)
+
+- Add ``__debuggerskip__`` as a special local
+- Allow assignment expressions to redefine outer names
+- Drop support for EOL python 3.8
+- Add new error for unused ``global`` / ``nonlocal`` names
+
3.2.0 (2024-01-04)
- Add support for ``*T`` (TypeVarTuple) and ``**P`` (ParamSpec) in PEP 695
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pyflakes-3.2.0/PKG-INFO new/pyflakes-3.3.2/PKG-INFO
--- old/pyflakes-3.2.0/PKG-INFO 2024-01-05 01:28:32.802719800 +0100
+++ new/pyflakes-3.3.2/PKG-INFO 2025-03-31 15:20:31.019775600 +0200
@@ -1,6 +1,6 @@
Metadata-Version: 2.1
Name: pyflakes
-Version: 3.2.0
+Version: 3.3.2
Summary: passive checker of Python programs
Home-page: https://github.com/PyCQA/pyflakes
Author: A lot of people
@@ -17,7 +17,7 @@
Classifier: Programming Language :: Python :: Implementation :: PyPy
Classifier: Topic :: Software Development
Classifier: Topic :: Utilities
-Requires-Python: >=3.8
+Requires-Python: >=3.9
License-File: LICENSE
========
@@ -31,7 +31,7 @@
modules with side effects. It's also much faster.
It is `available on PyPI <https://pypi.org/project/pyflakes/>`_
-and it supports all active versions of Python: 3.6+.
+and it supports all active versions of Python: 3.9+.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pyflakes-3.2.0/README.rst
new/pyflakes-3.3.2/README.rst
--- old/pyflakes-3.2.0/README.rst 2023-01-31 19:28:24.000000000 +0100
+++ new/pyflakes-3.3.2/README.rst 2025-03-31 15:04:03.000000000 +0200
@@ -9,7 +9,7 @@
modules with side effects. It's also much faster.
It is `available on PyPI <https://pypi.org/project/pyflakes/>`_
-and it supports all active versions of Python: 3.6+.
+and it supports all active versions of Python: 3.9+.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pyflakes-3.2.0/pyflakes/__init__.py
new/pyflakes-3.3.2/pyflakes/__init__.py
--- old/pyflakes-3.2.0/pyflakes/__init__.py 2024-01-05 01:25:40.000000000
+0100
+++ new/pyflakes-3.3.2/pyflakes/__init__.py 2025-03-31 15:19:44.000000000
+0200
@@ -1 +1 @@
-__version__ = '3.2.0'
+__version__ = '3.3.2'
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pyflakes-3.2.0/pyflakes/checker.py
new/pyflakes-3.3.2/pyflakes/checker.py
--- old/pyflakes-3.2.0/pyflakes/checker.py 2024-01-05 01:24:56.000000000
+0100
+++ new/pyflakes-3.3.2/pyflakes/checker.py 2025-03-31 15:19:04.000000000
+0200
@@ -165,17 +165,6 @@
return fields
-def counter(items):
- """
- Simplest required implementation of collections.Counter. Required as 2.6
- does not have Counter in collections.
- """
- results = {}
- for item in items:
- results[item] = results.get(item, 0) + 1
- return results
-
-
def iter_child_nodes(node, omit=None, _fields_order=_FieldsOrder()):
"""
Yield all direct child nodes of *node*, that is, all fields that
@@ -537,7 +526,10 @@
class ClassScope(Scope):
- pass
+ def __init__(self):
+ super().__init__()
+ # {name: node}
+ self.indirect_assignments = {}
class FunctionScope(Scope):
@@ -548,13 +540,14 @@
"""
usesLocals = False
alwaysUsed = {'__tracebackhide__', '__traceback_info__',
- '__traceback_supplement__'}
+ '__traceback_supplement__', '__debuggerskip__'}
def __init__(self):
super().__init__()
# Simplify: manage the special locals as globals
self.globals = self.alwaysUsed.copy()
- self.returnValue = None # First non-empty return
+ # {name: node}
+ self.indirect_assignments = {}
def unused_assignments(self):
"""
@@ -842,6 +835,10 @@
which were imported but unused.
"""
for scope in self.deadScopes:
+ if isinstance(scope, (ClassScope, FunctionScope)):
+ for name, node in scope.indirect_assignments.items():
+ self.report(messages.UnusedIndirectAssignment, node, name)
+
# imports in classes are public members
if isinstance(scope, ClassScope):
continue
@@ -993,6 +990,9 @@
self.report(messages.RedefinedWhileUnused,
node, value.name, existing.source)
+ if isinstance(scope, (ClassScope, FunctionScope)):
+ scope.indirect_assignments.pop(value.name, None)
+
elif isinstance(existing, Importation) and
value.redefines(existing):
existing.redefined.append(node)
@@ -1003,14 +1003,21 @@
# don't treat annotations as assignments if there is an existing value
# in scope
if value.name not in self.scope or not isinstance(value, Annotation):
- cur_scope_pos = -1
- # As per PEP 572, use scope in which outermost generator is defined
- while (
- isinstance(value, NamedExprAssignment) and
- isinstance(self.scopeStack[cur_scope_pos], GeneratorScope)
- ):
- cur_scope_pos -= 1
- self.scopeStack[cur_scope_pos][value.name] = value
+ if isinstance(value, NamedExprAssignment):
+ # PEP 572: use scope in which outermost generator is defined
+ scope = next(
+ scope
+ for scope in reversed(self.scopeStack)
+ if not isinstance(scope, GeneratorScope)
+ )
+ if value.name in scope and isinstance(scope[value.name],
Annotation):
+ # re-assignment to name that was previously only an
annotation
+ scope[value.name] = value
+ else:
+ # it may be a re-assignment to an already existing name
+ scope.setdefault(value.name, value)
+ else:
+ self.scope[value.name] = value
def _unknown_handler(self, node):
# this environment variable configures whether to error on unknown
@@ -1186,6 +1193,9 @@
# be executed.
return
+ if isinstance(self.scope, (ClassScope, FunctionScope)):
+ self.scope.indirect_assignments.pop(name, None)
+
if isinstance(self.scope, FunctionScope) and name in
self.scope.globals:
self.scope.globals.remove(name)
else:
@@ -1774,7 +1784,7 @@
convert_to_value(key) for key in node.keys
]
- key_counts = counter(keys)
+ key_counts = collections.Counter(keys)
duplicate_keys = [
key for key, count in key_counts.items()
if count > 1
@@ -1783,7 +1793,7 @@
for key in duplicate_keys:
key_indices = [i for i, i_key in enumerate(keys) if i_key == key]
- values = counter(
+ values = collections.Counter(
convert_to_value(node.values[index])
for index in key_indices
)
@@ -1844,6 +1854,8 @@
for scope in self.scopeStack[global_scope_index + 1:]:
scope[node_name] = node_value
+ self.scope.indirect_assignments[node_name] = node
+
NONLOCAL = GLOBAL
def GENERATOREXP(self, node):
@@ -1896,12 +1908,6 @@
self.report(messages.ReturnOutsideFunction, node)
return
- if (
- node.value and
- hasattr(self.scope, 'returnValue') and
- not self.scope.returnValue
- ):
- self.scope.returnValue = node.value
self.handleNode(node.value, node)
def YIELD(self, node):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pyflakes-3.2.0/pyflakes/messages.py
new/pyflakes-3.3.2/pyflakes/messages.py
--- old/pyflakes-3.2.0/pyflakes/messages.py 2023-01-31 19:28:24.000000000
+0100
+++ new/pyflakes-3.3.2/pyflakes/messages.py 2025-03-31 15:04:03.000000000
+0200
@@ -168,6 +168,15 @@
self.message_args = (names,)
+class UnusedIndirectAssignment(Message):
+ """A `global` or `nonlocal` statement where the name is never reassigned"""
+ message = '`%s %s` is unused: name is never assigned in scope'
+
+ def __init__(self, filename, loc, name):
+ Message.__init__(self, filename, loc)
+ self.message_args = (type(loc).__name__.lower(), name)
+
+
class ReturnOutsideFunction(Message):
"""
Indicates a return statement outside of a function/method.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pyflakes-3.2.0/pyflakes/test/test_api.py
new/pyflakes-3.3.2/pyflakes/test/test_api.py
--- old/pyflakes-3.2.0/pyflakes/test/test_api.py 2023-06-13
03:50:05.000000000 +0200
+++ new/pyflakes-3.3.2/pyflakes/test/test_api.py 2025-03-31
15:04:03.000000000 +0200
@@ -479,16 +479,12 @@
else:
msg = 'non-default argument follows default argument'
- if PYPY and sys.version_info >= (3, 9):
+ if PYPY:
column = 18
- elif PYPY:
- column = 8
elif sys.version_info >= (3, 10):
column = 18
- elif sys.version_info >= (3, 9):
- column = 21
else:
- column = 9
+ column = 21
last_line = ' ' * (column - 1) + '^\n'
self.assertHasErrors(
sourcePath,
@@ -508,23 +504,13 @@
foo(bar=baz, bax)
"""
with self.makeTempFile(source) as sourcePath:
- if sys.version_info >= (3, 9):
- column = 17
- elif not PYPY:
- column = 14
- else:
- column = 13
- last_line = ' ' * (column - 1) + '^\n'
- columnstr = '%d:' % column
-
- message = 'positional argument follows keyword argument'
-
+ last_line = ' ' * 16 + '^\n'
self.assertHasErrors(
sourcePath,
- ["""\
-{}:1:{} {}
+ [f"""\
+{sourcePath}:1:17: positional argument follows keyword argument
foo(bar=baz, bax)
-{}""".format(sourcePath, columnstr, message, last_line)])
+{last_line}"""])
def test_invalidEscape(self):
"""
@@ -533,11 +519,9 @@
# ValueError: invalid \x escape
with self.makeTempFile(r"foo = '\xyz'") as sourcePath:
position_end = 1
- if PYPY and sys.version_info >= (3, 9):
+ if PYPY:
column = 7
- elif PYPY:
- column = 6
- elif (3, 9) <= sys.version_info < (3, 12):
+ elif sys.version_info < (3, 12):
column = 13
else:
column = 7
@@ -669,23 +653,11 @@
self.assertEqual(count, 1)
errlines = err.getvalue().split("\n")[:-1]
- if sys.version_info >= (3, 9):
- expected_error = [
- "<stdin>:1:5: Generator expression must be parenthesized",
- "max(1 for i in range(10), key=lambda x: x+1)",
- " ^",
- ]
- elif PYPY:
- expected_error = [
- "<stdin>:1:4: Generator expression must be parenthesized if
not sole argument", # noqa: E501
- "max(1 for i in range(10), key=lambda x: x+1)",
- " ^",
- ]
- else:
- expected_error = [
- "<stdin>:1:5: Generator expression must be parenthesized",
- ]
-
+ expected_error = [
+ "<stdin>:1:5: Generator expression must be parenthesized",
+ "max(1 for i in range(10), key=lambda x: x+1)",
+ " ^",
+ ]
self.assertEqual(errlines, expected_error)
@@ -774,8 +746,14 @@
with open(self.tempfilepath, 'wb') as fd:
fd.write(b"import")
d = self.runPyflakes([self.tempfilepath])
- error_msg = '{0}:1:7: invalid syntax{1}import{1} ^{1}'.format(
- self.tempfilepath, os.linesep)
+
+ if sys.version_info >= (3, 13):
+ message = "Expected one or more names after 'import'"
+ else:
+ message = 'invalid syntax'
+
+ error_msg = '{0}:1:7: {1}{2}import{2} ^{2}'.format(
+ self.tempfilepath, message, os.linesep)
self.assertEqual(d, ('', error_msg, 1))
def test_readFromStdin(self):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pyflakes-3.2.0/pyflakes/test/test_imports.py
new/pyflakes-3.3.2/pyflakes/test/test_imports.py
--- old/pyflakes-3.2.0/pyflakes/test/test_imports.py 2022-11-23
19:37:38.000000000 +0100
+++ new/pyflakes-3.3.2/pyflakes/test/test_imports.py 2025-03-31
15:04:03.000000000 +0200
@@ -654,7 +654,7 @@
self.flakes('''
import fu
def f(): global fu
- ''', m.UnusedImport)
+ ''', m.UnusedImport, m.UnusedIndirectAssignment)
def test_usedAndGlobal(self):
"""
@@ -665,7 +665,7 @@
import foo
def f(): global foo
def g(): foo.is_used()
- ''')
+ ''', m.UnusedIndirectAssignment)
def test_assignedToGlobal(self):
"""
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pyflakes-3.2.0/pyflakes/test/test_other.py
new/pyflakes-3.3.2/pyflakes/test/test_other.py
--- old/pyflakes-3.2.0/pyflakes/test/test_other.py 2023-01-31
19:28:24.000000000 +0100
+++ new/pyflakes-3.3.2/pyflakes/test/test_other.py 2025-03-31
15:19:04.000000000 +0200
@@ -1085,8 +1085,72 @@
self.flakes('''
def f(): global foo
def g(): foo = 'anything'; foo.is_used()
+ ''', m.UnusedIndirectAssignment)
+
+ def test_unused_global_statement(self):
+ self.flakes('''
+ g = 0
+ def f1():
+ global g
+ g = 1
+ def f2():
+ global g # this is unused!
+ return g
+ ''', m.UnusedIndirectAssignment)
+
+ def test_unused_nonlocal_statement(self):
+ self.flakes('''
+ def f():
+ x = 1
+ def set_x():
+ nonlocal x
+ x = 2
+ def get_x():
+ nonlocal x
+ return x
+ set_x()
+ return get_x()
+ ''', m.UnusedIndirectAssignment)
+
+ def test_unused_global_statement_not_marked_as_used_by_nested_scope(self):
+ self.flakes('''
+ g = 0
+ def f():
+ global g
+ def f2():
+ g = 2
+ ''', m.UnusedIndirectAssignment, m.UnusedVariable)
+
+ def test_global_nonlocal_in_class_bodies(self):
+ self.flakes('''
+ g = 0
+ class C:
+ global g
+ g = 1
+ def f():
+ nl = 0
+ class C:
+ nonlocal nl
+ nl = 1
''')
+ def test_unused_global_in_class(self):
+ self.flakes('''
+ g = 0
+ class C:
+ global g
+ u = g
+ ''', m.UnusedIndirectAssignment)
+
+ def test_unused_nonlocal_in_clas(self):
+ self.flakes('''
+ def f():
+ nl = 1
+ class C:
+ nonlocal nl
+ u = nl
+ ''', m.UnusedIndirectAssignment)
+
def test_function_arguments(self):
"""
Test to traverse ARG and ARGUMENT handler
@@ -1349,6 +1413,16 @@
__tracebackhide__ = True
""")
+ def test_debuggerskipSpecialVariable(self):
+ """
+ Do not warn about unused local variable __debuggerskip__, which is
+ a special variable for IPython.
+ """
+ self.flakes("""
+ def helper():
+ __debuggerskip__ = True
+ """)
+
def test_ifexp(self):
"""
Test C{foo if bar else baz} statements.
@@ -1700,6 +1774,13 @@
print(x)
''')
+ def test_assign_expr_after_annotation(self):
+ self.flakes("""
+ a: int
+ print(a := 3)
+ print(a)
+ """)
+
def test_assign_expr_generator_scope(self):
"""Test assignment expressions in generator expressions."""
self.flakes('''
@@ -1707,6 +1788,13 @@
print(y)
''')
+ def test_assign_expr_generator_scope_reassigns_parameter(self):
+ self.flakes('''
+ def foo(x):
+ fns = [lambda x: x + 1, lambda x: x + 2, lambda x: x + 3]
+ return [(x := fn(x)) for fn in fns]
+ ''')
+
def test_assign_expr_nested(self):
"""Test assignment expressions in nested expressions."""
self.flakes('''
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/pyflakes-3.2.0/pyflakes/test/test_type_annotations.py
new/pyflakes-3.3.2/pyflakes/test/test_type_annotations.py
--- old/pyflakes-3.2.0/pyflakes/test/test_type_annotations.py 2024-01-05
01:24:56.000000000 +0100
+++ new/pyflakes-3.3.2/pyflakes/test/test_type_annotations.py 2025-03-31
15:04:03.000000000 +0200
@@ -797,3 +797,10 @@
return f(*args, **kwargs)
return g
""")
+
+ @skipIf(version_info < (3, 13), 'new in Python 3.13')
+ def test_type_parameter_defaults(self):
+ self.flakes("""
+ def f[T = int](u: T) -> T:
+ return u
+ """)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pyflakes-3.2.0/pyflakes/test/test_undefined_names.py
new/pyflakes-3.3.2/pyflakes/test/test_undefined_names.py
--- old/pyflakes-3.2.0/pyflakes/test/test_undefined_names.py 2022-11-23
19:37:38.000000000 +0100
+++ new/pyflakes-3.3.2/pyflakes/test/test_undefined_names.py 2025-03-31
15:04:03.000000000 +0200
@@ -327,7 +327,7 @@
def f2():
global m
- ''', m.UndefinedName)
+ ''', m.UndefinedName, m.UnusedIndirectAssignment)
@skip("todo")
def test_unused_global(self):
@@ -462,7 +462,7 @@
a
a = 2
return a
- ''', m.UndefinedLocal)
+ ''', m.UndefinedLocal, m.UnusedIndirectAssignment)
def test_intermediateClassScopeIgnored(self):
"""
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pyflakes-3.2.0/pyflakes.egg-info/PKG-INFO
new/pyflakes-3.3.2/pyflakes.egg-info/PKG-INFO
--- old/pyflakes-3.2.0/pyflakes.egg-info/PKG-INFO 2024-01-05
01:28:32.000000000 +0100
+++ new/pyflakes-3.3.2/pyflakes.egg-info/PKG-INFO 2025-03-31
15:20:30.000000000 +0200
@@ -1,6 +1,6 @@
Metadata-Version: 2.1
Name: pyflakes
-Version: 3.2.0
+Version: 3.3.2
Summary: passive checker of Python programs
Home-page: https://github.com/PyCQA/pyflakes
Author: A lot of people
@@ -17,7 +17,7 @@
Classifier: Programming Language :: Python :: Implementation :: PyPy
Classifier: Topic :: Software Development
Classifier: Topic :: Utilities
-Requires-Python: >=3.8
+Requires-Python: >=3.9
License-File: LICENSE
========
@@ -31,7 +31,7 @@
modules with side effects. It's also much faster.
It is `available on PyPI <https://pypi.org/project/pyflakes/>`_
-and it supports all active versions of Python: 3.6+.
+and it supports all active versions of Python: 3.9+.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/pyflakes-3.2.0/setup.py new/pyflakes-3.3.2/setup.py
--- old/pyflakes-3.2.0/setup.py 2023-01-31 19:28:24.000000000 +0100
+++ new/pyflakes-3.3.2/setup.py 2025-03-31 15:04:03.000000000 +0200
@@ -42,7 +42,7 @@
author_email="[email protected]",
url="https://github.com/PyCQA/pyflakes",
packages=["pyflakes", "pyflakes.scripts", "pyflakes.test"],
- python_requires='>=3.8',
+ python_requires='>=3.9',
classifiers=[
"Development Status :: 6 - Mature",
"Environment :: Console",