Skip to content

Fix "pragma: no mutate" being ignored inside multi-line statements - #614

Merged
boxed merged 1 commit into
boxed:mainfrom
musharna:fix-pragma-multiline-statements
Oct 26, 2026
Merged

boxed merged 1 commit into
boxed:mainfrom
musharna:fix-pragma-multiline-statements

Conversation

@musharna

Copy link
Copy Markdown
Contributor

A # pragma: no mutate at the end of a line inside brackets is ignored, so that line is still mutated:

def inner(a, b):
    return max(
        a + 1,  # pragma: no mutate
        b - 1,
    )

visit_SimpleStatementLine only reads node.trailing_whitespace.comment. A comment that ends a line inside a call, a literal or a parenthesized condition belongs to a ParenthesizedWhitespace node instead, so no visitor sees it. README:375 says the bare pragma disables mutation "on this single line".

This adds visit_ParenthesizedWhitespace, which records that line for a bare pragma. Only that line is skipped; the other lines of the statement are still mutated.

Real run (mutmut run on a small package with the function above, a dict-literal version, and a single-line return a + 1 # pragma: no mutate as a control):

  • main: 16 mutants; 4 of 8 in inner and 4 of 8 in the dict function change the pragma line; the single-line control has 0
  • this branch: 8 mutants, none on a pragma line

Tests: three PragmaVisitor cases (call argument, dict entry, parenthesized if condition), a control showing that other comments inside brackets are ignored, and two end-to-end cases in test_mutation.py. With pragma_handling.py reverted to main, exactly the 5 new cases fail and the control passes. uv run pytest: 472 passed, 4 skipped; one tests/workers/test_timeout.py case failed under heavy load (on main, a different timeout case failed the same way), and that file passes 8/8 when run alone. pre-commit run --all-files is clean.

Not changed:

  • A pragma on the closing ) line still maps to the statement's first line (return max(), so the arguments are mutated. It's unclear whether that pragma should cover the whole statement, so I left it alone.
  • block/start/end inside brackets are not handled; only the bare pragma is.

AI assistance: this change and its tests were drafted with Claude Opus 5.5 (claude-opus-5-5). I ran the commands and numbers above locally.

@boxed
boxed merged commit c37062f into boxed:main Oct 26, 2026
7 checks passed
@boxed

boxed commented Oct 26, 2026

Copy link
Copy Markdown
Owner

Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants