Skip to content

Commit

Permalink
fix: better understanding of constant conditions
Browse files Browse the repository at this point in the history
  • Loading branch information
nedbat committed Feb 15, 2025
1 parent 1bf0db2 commit 0eb3222
Show file tree
Hide file tree
Showing 13 changed files with 147 additions and 121 deletions.
5 changes: 4 additions & 1 deletion CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,10 @@ upgrading your version of coverage.py.
Unreleased
----------

Nothing yet.
- Many constant tests in if statements are now recognized as being optimized
away. For example, previously ``if 13:`` would have been considered a branch
with one path not taken. Now it is understood as always true and no coverage
is missing.


.. start-releases
Expand Down
31 changes: 20 additions & 11 deletions coverage/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -654,23 +654,28 @@ def __init__(self, body: Sequence[ast.AST]) -> None:
# TODO: Shouldn't the cause messages join with "and" instead of "or"?


def is_constant_test_expr(node: ast.AST) -> bool:
def is_constant_test_expr(node: ast.AST) -> tuple[bool, bool]:
"""Is this a compile-time constant test expression?
We don't try to mimic all of CPython's optimizations. We just have to
handle the kinds of constant expressions people might actually use.
"""
if isinstance(node, ast.Constant):
return True
return True, bool(node.value)
elif isinstance(node, ast.Name):
if node.id in ["True", "False", "None", "__debug__"]:
return True
return True, eval(node.id)
elif isinstance(node, ast.UnaryOp) and isinstance(node.op, ast.Not):
return is_constant_test_expr(node.operand)
is_constant, val = is_constant_test_expr(node.operand)
return is_constant, not val
elif isinstance(node, ast.BoolOp):
return all(is_constant_test_expr(v) for v in node.values)
return False
rets = [is_constant_test_expr(v) for v in node.values]
is_constant = all(is_const for is_const, _ in rets)
if is_constant:
op = any if isinstance(node.op, ast.Or) else all
return True, op(v for _, v in rets)
return False, False


class AstArcAnalyzer:
Expand Down Expand Up @@ -1156,10 +1161,14 @@ def _handle__For(self, node: ast.For) -> set[ArcStart]:

def _handle__If(self, node: ast.If) -> set[ArcStart]:
start = self.line_for_node(node.test)
from_start = ArcStart(start, cause="the condition on line {lineno} was never true")
exits = self.process_body(node.body, from_start=from_start)
from_start = ArcStart(start, cause="the condition on line {lineno} was always true")
exits |= self.process_body(node.orelse, from_start=from_start)
constant_test, val = is_constant_test_expr(node.test)
exits = set()
if not constant_test or val:
from_start = ArcStart(start, cause="the condition on line {lineno} was never true")
exits |= self.process_body(node.body, from_start=from_start)
if not constant_test or not val:
from_start = ArcStart(start, cause="the condition on line {lineno} was always true")
exits |= self.process_body(node.orelse, from_start=from_start)
return exits

if sys.version_info >= (3, 10):
Expand Down Expand Up @@ -1271,7 +1280,7 @@ def _handle__Try(self, node: ast.Try) -> set[ArcStart]:

def _handle__While(self, node: ast.While) -> set[ArcStart]:
start = to_top = self.line_for_node(node.test)
constant_test = is_constant_test_expr(node.test)
constant_test, _ = is_constant_test_expr(node.test)
top_is_body0 = False
if constant_test:
top_is_body0 = True
Expand Down
12 changes: 6 additions & 6 deletions tests/gold/html/partial/class_index.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Coverage report</title>
<link rel="icon" sizes="32x32" href="favicon_32_cb_58284776.png">
<link rel="stylesheet" href="style_cb_718ce007.css" type="text/css">
<script src="coverage_html_cb_d1c4fcc4.js" defer></script>
<link rel="stylesheet" href="style_cb_8e611ae1.css" type="text/css">
<script src="coverage_html_cb_6fb7b396.js" defer></script>
</head>
<body class="indexfile">
<header>
Expand Down Expand Up @@ -56,8 +56,8 @@ <h2>
<a class="button current">Classes</a>
</h2>
<p class="text">
<a class="nav" href="https://coverage.readthedocs.io/en/7.5.1a0.dev1">coverage.py v7.5.1a0.dev1</a>,
created at 2024-04-29 17:40 -0300
<a class="nav" href="https://coverage.readthedocs.io/en/7.6.13a0.dev1">coverage.py v7.6.13a0.dev1</a>,
created at 2025-02-15 17:25 -0500
</p>
</div>
</header>
Expand Down Expand Up @@ -107,8 +107,8 @@ <h2>
<footer>
<div class="content">
<p>
<a class="nav" href="https://coverage.readthedocs.io/en/7.5.1a0.dev1">coverage.py v7.5.1a0.dev1</a>,
created at 2024-04-29 17:40 -0300
<a class="nav" href="https://coverage.readthedocs.io/en/7.6.13a0.dev1">coverage.py v7.6.13a0.dev1</a>,
created at 2025-02-15 17:25 -0500
</p>
</div>
<aside class="hidden">
Expand Down
12 changes: 6 additions & 6 deletions tests/gold/html/partial/function_index.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Coverage report</title>
<link rel="icon" sizes="32x32" href="favicon_32_cb_58284776.png">
<link rel="stylesheet" href="style_cb_718ce007.css" type="text/css">
<script src="coverage_html_cb_d1c4fcc4.js" defer></script>
<link rel="stylesheet" href="style_cb_8e611ae1.css" type="text/css">
<script src="coverage_html_cb_6fb7b396.js" defer></script>
</head>
<body class="indexfile">
<header>
Expand Down Expand Up @@ -56,8 +56,8 @@ <h2>
<a class="button" href="class_index.html">Classes</a>
</h2>
<p class="text">
<a class="nav" href="https://coverage.readthedocs.io/en/7.5.1a0.dev1">coverage.py v7.5.1a0.dev1</a>,
created at 2024-04-29 17:40 -0300
<a class="nav" href="https://coverage.readthedocs.io/en/7.6.13a0.dev1">coverage.py v7.6.13a0.dev1</a>,
created at 2025-02-15 17:25 -0500
</p>
</div>
</header>
Expand Down Expand Up @@ -107,8 +107,8 @@ <h2>
<footer>
<div class="content">
<p>
<a class="nav" href="https://coverage.readthedocs.io/en/7.5.1a0.dev1">coverage.py v7.5.1a0.dev1</a>,
created at 2024-04-29 17:40 -0300
<a class="nav" href="https://coverage.readthedocs.io/en/7.6.13a0.dev1">coverage.py v7.6.13a0.dev1</a>,
created at 2025-02-15 17:25 -0500
</p>
</div>
<aside class="hidden">
Expand Down
12 changes: 6 additions & 6 deletions tests/gold/html/partial/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Coverage report</title>
<link rel="icon" sizes="32x32" href="favicon_32_cb_58284776.png">
<link rel="stylesheet" href="style_cb_718ce007.css" type="text/css">
<script src="coverage_html_cb_d1c4fcc4.js" defer></script>
<link rel="stylesheet" href="style_cb_8e611ae1.css" type="text/css">
<script src="coverage_html_cb_6fb7b396.js" defer></script>
</head>
<body class="indexfile">
<header>
Expand Down Expand Up @@ -55,8 +55,8 @@ <h2>
<a class="button" href="class_index.html">Classes</a>
</h2>
<p class="text">
<a class="nav" href="https://coverage.readthedocs.io/en/7.5.1a0.dev1">coverage.py v7.5.1a0.dev1</a>,
created at 2024-04-29 17:40 -0300
<a class="nav" href="https://coverage.readthedocs.io/en/7.6.13a0.dev1">coverage.py v7.6.13a0.dev1</a>,
created at 2025-02-15 17:25 -0500
</p>
</div>
</header>
Expand Down Expand Up @@ -103,8 +103,8 @@ <h2>
<footer>
<div class="content">
<p>
<a class="nav" href="https://coverage.readthedocs.io/en/7.5.1a0.dev1">coverage.py v7.5.1a0.dev1</a>,
created at 2024-04-29 17:40 -0300
<a class="nav" href="https://coverage.readthedocs.io/en/7.6.13a0.dev1">coverage.py v7.6.13a0.dev1</a>,
created at 2025-02-15 17:25 -0500
</p>
</div>
<aside class="hidden">
Expand Down
8 changes: 4 additions & 4 deletions tests/gold/html/partial/partial_py.html
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,8 @@ <h2>
<a id="indexLink" class="nav" href="index.html">&Hat; index</a> &nbsp; &nbsp;
<a id="nextFileLink" class="nav" href="index.html">&#xbb; next</a>
&nbsp; &nbsp; &nbsp;
<a class="nav" href="https://coverage.readthedocs.io/en/7.5.4a0.dev1">coverage.py v7.5.4a0.dev1</a>,
created at 2024-05-30 15:19 -0400
<a class="nav" href="https://coverage.readthedocs.io/en/7.6.13a0.dev1">coverage.py v7.6.13a0.dev1</a>,
created at 2025-02-15 17:25 -0500
</p>
<aside class="hidden">
<button type="button" class="button_next_chunk" data-shortcut="j"></button>
Expand Down Expand Up @@ -107,8 +107,8 @@ <h2>
<a class="nav" href="index.html">&Hat; index</a> &nbsp; &nbsp;
<a class="nav" href="index.html">&#xbb; next</a>
&nbsp; &nbsp; &nbsp;
<a class="nav" href="https://coverage.readthedocs.io/en/7.5.4a0.dev1">coverage.py v7.5.4a0.dev1</a>,
created at 2024-05-30 15:19 -0400
<a class="nav" href="https://coverage.readthedocs.io/en/7.6.13a0.dev1">coverage.py v7.6.13a0.dev1</a>,
created at 2025-02-15 17:25 -0500
</p>
</div>
</footer>
Expand Down
22 changes: 11 additions & 11 deletions tests/gold/html/partial_626/class_index.html
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
<header>
<div class="content">
<h1>Coverage report:
<span class="pc_cov">87%</span>
<span class="pc_cov">92%</span>
</h1>
<aside id="help_panel_wrapper">
<input id="help_panel_state" type="checkbox">
Expand Down Expand Up @@ -56,8 +56,8 @@ <h2>
<a class="button current">Classes</a>
</h2>
<p class="text">
<a class="nav" href="https://coverage.readthedocs.io/en/7.6.0a0.dev1">coverage.py v7.6.0a0.dev1</a>,
created at 2024-07-10 12:20 -0400
<a class="nav" href="https://coverage.readthedocs.io/en/7.6.13a0.dev1">coverage.py v7.6.13a0.dev1</a>,
created at 2025-02-15 12:46 -0500
</p>
</div>
</header>
Expand All @@ -82,9 +82,9 @@ <h2>
<td>9</td>
<td>0</td>
<td>1</td>
<td>6</td>
<td>2</td>
<td class="right" data-ratio="13 15">87%</td>
<td>4</td>
<td>1</td>
<td class="right" data-ratio="12 13">92%</td>
</tr>
</tbody>
<tfoot>
Expand All @@ -94,9 +94,9 @@ <h2>
<td>9</td>
<td>0</td>
<td>1</td>
<td>6</td>
<td>2</td>
<td class="right" data-ratio="13 15">87%</td>
<td>4</td>
<td>1</td>
<td class="right" data-ratio="12 13">92%</td>
</tr>
</tfoot>
</table>
Expand All @@ -107,8 +107,8 @@ <h2>
<footer>
<div class="content">
<p>
<a class="nav" href="https://coverage.readthedocs.io/en/7.6.0a0.dev1">coverage.py v7.6.0a0.dev1</a>,
created at 2024-07-10 12:20 -0400
<a class="nav" href="https://coverage.readthedocs.io/en/7.6.13a0.dev1">coverage.py v7.6.13a0.dev1</a>,
created at 2025-02-15 12:46 -0500
</p>
</div>
<aside class="hidden">
Expand Down
22 changes: 11 additions & 11 deletions tests/gold/html/partial_626/function_index.html
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
<header>
<div class="content">
<h1>Coverage report:
<span class="pc_cov">87%</span>
<span class="pc_cov">92%</span>
</h1>
<aside id="help_panel_wrapper">
<input id="help_panel_state" type="checkbox">
Expand Down Expand Up @@ -56,8 +56,8 @@ <h2>
<a class="button" href="class_index.html">Classes</a>
</h2>
<p class="text">
<a class="nav" href="https://coverage.readthedocs.io/en/7.6.0a0.dev1">coverage.py v7.6.0a0.dev1</a>,
created at 2024-07-10 12:20 -0400
<a class="nav" href="https://coverage.readthedocs.io/en/7.6.13a0.dev1">coverage.py v7.6.13a0.dev1</a>,
created at 2025-02-15 12:46 -0500
</p>
</div>
</header>
Expand All @@ -82,9 +82,9 @@ <h2>
<td>9</td>
<td>0</td>
<td>1</td>
<td>6</td>
<td>2</td>
<td class="right" data-ratio="13 15">87%</td>
<td>4</td>
<td>1</td>
<td class="right" data-ratio="12 13">92%</td>
</tr>
</tbody>
<tfoot>
Expand All @@ -94,9 +94,9 @@ <h2>
<td>9</td>
<td>0</td>
<td>1</td>
<td>6</td>
<td>2</td>
<td class="right" data-ratio="13 15">87%</td>
<td>4</td>
<td>1</td>
<td class="right" data-ratio="12 13">92%</td>
</tr>
</tfoot>
</table>
Expand All @@ -107,8 +107,8 @@ <h2>
<footer>
<div class="content">
<p>
<a class="nav" href="https://coverage.readthedocs.io/en/7.6.0a0.dev1">coverage.py v7.6.0a0.dev1</a>,
created at 2024-07-10 12:20 -0400
<a class="nav" href="https://coverage.readthedocs.io/en/7.6.13a0.dev1">coverage.py v7.6.13a0.dev1</a>,
created at 2025-02-15 12:46 -0500
</p>
</div>
<aside class="hidden">
Expand Down
22 changes: 11 additions & 11 deletions tests/gold/html/partial_626/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
<header>
<div class="content">
<h1>Coverage report:
<span class="pc_cov">87%</span>
<span class="pc_cov">92%</span>
</h1>
<aside id="help_panel_wrapper">
<input id="help_panel_state" type="checkbox">
Expand Down Expand Up @@ -55,8 +55,8 @@ <h2>
<a class="button" href="class_index.html">Classes</a>
</h2>
<p class="text">
<a class="nav" href="https://coverage.readthedocs.io/en/7.6.0a0.dev1">coverage.py v7.6.0a0.dev1</a>,
created at 2024-07-10 12:20 -0400
<a class="nav" href="https://coverage.readthedocs.io/en/7.6.13a0.dev1">coverage.py v7.6.13a0.dev1</a>,
created at 2025-02-15 12:46 -0500
</p>
</div>
</header>
Expand All @@ -79,9 +79,9 @@ <h2>
<td>9</td>
<td>0</td>
<td>1</td>
<td>6</td>
<td>2</td>
<td class="right" data-ratio="13 15">87%</td>
<td>4</td>
<td>1</td>
<td class="right" data-ratio="12 13">92%</td>
</tr>
</tbody>
<tfoot>
Expand All @@ -90,9 +90,9 @@ <h2>
<td>9</td>
<td>0</td>
<td>1</td>
<td>6</td>
<td>2</td>
<td class="right" data-ratio="13 15">87%</td>
<td>4</td>
<td>1</td>
<td class="right" data-ratio="12 13">92%</td>
</tr>
</tfoot>
</table>
Expand All @@ -103,8 +103,8 @@ <h2>
<footer>
<div class="content">
<p>
<a class="nav" href="https://coverage.readthedocs.io/en/7.6.0a0.dev1">coverage.py v7.6.0a0.dev1</a>,
created at 2024-07-10 12:20 -0400
<a class="nav" href="https://coverage.readthedocs.io/en/7.6.13a0.dev1">coverage.py v7.6.13a0.dev1</a>,
created at 2025-02-15 12:46 -0500
</p>
</div>
<aside class="hidden">
Expand Down
Loading

0 comments on commit 0eb3222

Please sign in to comment.