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
