Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package python-vulture for openSUSE:Factory 
checked in at 2026-03-30 18:31:11
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-vulture (Old)
 and      /work/SRC/openSUSE:Factory/.python-vulture.new.1999 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-vulture"

Mon Mar 30 18:31:11 2026 rev:15 rq:1343511 version:2.16

Changes:
--------
--- /work/SRC/openSUSE:Factory/python-vulture/python-vulture.changes    
2026-03-22 14:14:21.778673891 +0100
+++ /work/SRC/openSUSE:Factory/.python-vulture.new.1999/python-vulture.changes  
2026-03-30 18:34:13.478396257 +0200
@@ -1,0 +2,9 @@
+Sun Mar 29 18:48:32 UTC 2026 - Dirk Müller <[email protected]>
+
+- update to 2.16:
+  * Fix false positives for dead code after while loops (#412,
+    #413, Jendrik Seipp).
+  * Use `ty` instead of `pytype` for testing type annotations
+    (Jendrik Seipp).
+
+-------------------------------------------------------------------

Old:
----
  vulture-2.15.tar.gz

New:
----
  vulture-2.16.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python-vulture.spec ++++++
--- /var/tmp/diff_new_pack.mvrg1Y/_old  2026-03-30 18:34:14.142424020 +0200
+++ /var/tmp/diff_new_pack.mvrg1Y/_new  2026-03-30 18:34:14.146424186 +0200
@@ -18,7 +18,7 @@
 
 %{?sle15_python_module_pythons}
 Name:           python-vulture
-Version:        2.15
+Version:        2.16
 Release:        0
 Summary:        Python module for finding dead code
 License:        MIT

++++++ vulture-2.15.tar.gz -> vulture-2.16.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/vulture-2.15/CHANGELOG.md 
new/vulture-2.16/CHANGELOG.md
--- old/vulture-2.15/CHANGELOG.md       2026-03-04 22:41:34.000000000 +0100
+++ new/vulture-2.16/CHANGELOG.md       2026-03-25 15:41:19.000000000 +0100
@@ -1,3 +1,8 @@
+# 2.16 (2026-03-25)
+
+* Fix false positives for dead code after while loops (#412, #413, Jendrik 
Seipp).
+* Use `ty` instead of `pytype` for testing type annotations (Jendrik Seipp).
+
 # 2.15 (2026-03-04)
 
 * Handle `while True` loops without `break` statements (kreathon).
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/vulture-2.15/PKG-INFO new/vulture-2.16/PKG-INFO
--- old/vulture-2.15/PKG-INFO   2026-03-04 22:41:37.876020000 +0100
+++ new/vulture-2.16/PKG-INFO   2026-03-25 15:41:23.052682600 +0100
@@ -1,6 +1,6 @@
 Metadata-Version: 2.4
 Name: vulture
-Version: 2.15
+Version: 2.16
 Summary: Find dead code
 Author-email: Jendrik Seipp <[email protected]>
 License: The MIT License (MIT)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/vulture-2.15/tests/test_pytype.py 
new/vulture-2.16/tests/test_pytype.py
--- old/vulture-2.15/tests/test_pytype.py       2026-03-04 22:41:34.000000000 
+0100
+++ new/vulture-2.16/tests/test_pytype.py       1970-01-01 01:00:00.000000000 
+0100
@@ -1,11 +0,0 @@
-import subprocess
-import sys
-
-import pytest
-
-
[email protected](
-    sys.version_info >= (3, 13), reason="needs Python < 3.13 for pytype"
-)
-def test_pytype():
-    assert subprocess.run(["pytype", "vulture/core.py"]).returncode == 0
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/vulture-2.15/tests/test_reachability.py 
new/vulture-2.16/tests/test_reachability.py
--- old/vulture-2.15/tests/test_reachability.py 2026-03-04 22:41:34.000000000 
+0100
+++ new/vulture-2.16/tests/test_reachability.py 2026-03-25 15:41:19.000000000 
+0100
@@ -805,3 +805,41 @@
 """
     )
     assert v.unreachable_code == []
+
+
+def test_while_true_fall_through_break_before_for_loop(v):
+    """Regression: a for-loop after an if-break in a while body must not
+    suppress the break-detection, causing a false-positive unreachable report
+    for code that follows the while loop."""
+    v.scan(
+        """\
+def foo():
+    while True:
+        if condition:
+            break
+        for item in items:
+            process(item)
+    return "reachable"
+"""
+    )
+    assert v.unreachable_code == []
+
+
+def test_while_true_fall_through_for_loop_before_break(v):
+    """Regression: a for-loop before an if-break, followed by another for-loop,
+    must not suppress break-detection (GitHub issue #412).
+    Structure: while True: for→if-break→for, then code after the loop."""
+    v.scan(
+        """\
+def foo():
+    while True:
+        for i in items:
+            process(i)
+        if condition:
+            break
+        for j in others:
+            finalize(j)
+    return "reachable"
+"""
+    )
+    assert v.unreachable_code == []
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/vulture-2.15/tox.ini new/vulture-2.16/tox.ini
--- old/vulture-2.15/tox.ini    2026-03-04 22:41:34.000000000 +0100
+++ new/vulture-2.16/tox.ini    2026-03-25 15:41:19.000000000 +0100
@@ -15,7 +15,7 @@
   pint  # Use latest version to catch API changes.
   pytest
   pytest-cov
-  pytype ; python_version < '3.13'
+  ty
 commands =
   pytest {posargs}
 # Install package as wheel in all envs 
(https://hynek.me/articles/turbo-charge-tox/).
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/vulture-2.15/vulture/reachability.py 
new/vulture-2.16/vulture/reachability.py
--- old/vulture-2.15/vulture/reachability.py    2026-03-04 22:41:34.000000000 
+0100
+++ new/vulture-2.16/vulture/reachability.py    2026-03-25 15:41:19.000000000 
+0100
@@ -8,18 +8,10 @@
         self._report = report
         self._no_fall_through_nodes = set()
 
-        # Since we visit the children nodes first, we need to maintain a flag
-        # that indicates if a break statement was seen. When visiting the
-        # parent (While, For or AsyncFor), the value is checked (for While)
-        # and reset. Assumes code is valid (break statements only in loops).
-        self._current_loop_has_break_statement = False
-
     def visit(self, node):
         """When called, all children of this node have already been visited."""
         if isinstance(node, (ast.Break, ast.Continue, ast.Return, ast.Raise)):
             self._mark_as_no_fall_through(node)
-            if isinstance(node, ast.Break):
-                self._current_loop_has_break_statement = True
 
         elif isinstance(
             node,
@@ -34,10 +26,8 @@
             self._can_fall_through_statements_analysis(node.body)
         elif isinstance(node, ast.While):
             self._handle_reachability_while(node)
-            self._current_loop_has_break_statement = False
         elif isinstance(node, (ast.For, ast.AsyncFor)):
             self._can_fall_through_statements_analysis(node.body)
-            self._current_loop_has_break_statement = False
         elif isinstance(node, ast.If):
             self._handle_reachability_if(node)
         elif isinstance(node, ast.IfExp):
@@ -173,11 +163,40 @@
                     message="unreachable 'else' block",
                 )
 
-            if not self._current_loop_has_break_statement:
+            if not self._body_has_break(node.body):
                 self._mark_as_no_fall_through(node)
 
         self._can_fall_through_statements_analysis(node.body)
 
+    @staticmethod
+    def _body_has_break(stmts):
+        """Return True if stmts contain a break that exits the current loop.
+
+        Does not recurse into nested loops or new function/class scopes, since
+        break statements inside those do not affect the enclosing loop.
+        """
+        for stmt in stmts:
+            if isinstance(stmt, ast.Break):
+                return True
+            if isinstance(
+                stmt,
+                (
+                    ast.While,
+                    ast.For,
+                    ast.AsyncFor,
+                    ast.FunctionDef,
+                    ast.AsyncFunctionDef,
+                    ast.ClassDef,
+                ),
+            ):
+                continue
+            for _, value in ast.iter_fields(stmt):
+                if isinstance(value, list):
+                    ast_stmts = [s for s in value if isinstance(s, ast.AST)]
+                    if Reachability._body_has_break(ast_stmts):
+                        return True
+        return False
+
     def _handle_reachability_try(self, node):
         try_can_fall_through = self._can_fall_through_statements_analysis(
             node.body
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/vulture-2.15/vulture/version.py 
new/vulture-2.16/vulture/version.py
--- old/vulture-2.15/vulture/version.py 2026-03-04 22:41:34.000000000 +0100
+++ new/vulture-2.16/vulture/version.py 2026-03-25 15:41:19.000000000 +0100
@@ -1 +1 @@
-__version__ = "2.15"
+__version__ = "2.16"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/vulture-2.15/vulture.egg-info/PKG-INFO 
new/vulture-2.16/vulture.egg-info/PKG-INFO
--- old/vulture-2.15/vulture.egg-info/PKG-INFO  2026-03-04 22:41:37.000000000 
+0100
+++ new/vulture-2.16/vulture.egg-info/PKG-INFO  2026-03-25 15:41:23.000000000 
+0100
@@ -1,6 +1,6 @@
 Metadata-Version: 2.4
 Name: vulture
-Version: 2.15
+Version: 2.16
 Summary: Find dead code
 Author-email: Jendrik Seipp <[email protected]>
 License: The MIT License (MIT)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/vulture-2.15/vulture.egg-info/SOURCES.txt 
new/vulture-2.16/vulture.egg-info/SOURCES.txt
--- old/vulture-2.15/vulture.egg-info/SOURCES.txt       2026-03-04 
22:41:37.000000000 +0100
+++ new/vulture-2.16/vulture.egg-info/SOURCES.txt       2026-03-25 
15:41:23.000000000 +0100
@@ -21,7 +21,6 @@
 tests/test_item.py
 tests/test_make_whitelist.py
 tests/test_noqa.py
-tests/test_pytype.py
 tests/test_reachability.py
 tests/test_report.py
 tests/test_scavenging.py

Reply via email to