Skip to content

Preserve the tool's exit code when the notebook is unchanged - #907

Open
Eljees wants to merge 2 commits into
nbQA-dev:mainfrom
Eljees:fix/872-preserve-tool-exit-code
Open

Eljees wants to merge 2 commits into
nbQA-dev:mainfrom
Eljees:fix/872-preserve-tool-exit-code

Conversation

@Eljees

@Eljees Eljees commented Aug 14, 2026

Copy link
Copy Markdown

Closes #872.

nbQA resets output_code to 0 whenever the third-party tool rewrote the temporary Python file but the round-trip back into the notebook produced no change:

if mutated and not actually_mutated:
    output_code = 0
    mutated = False

That branch is there so a formatter which only touched the temporary file is not reported as having changed the notebook. It also swallows real failures, though: ruff check --fix can fix some violations, leave others unfixable and exit 1, and nbQA still reports success -- so a pre-commit hook goes green over genuine errors.

This keeps the mutated = False reset and only zeroes the exit code when the tool printed nothing at all. If the tool printed something, there is something left to report, so its exit code survives.

I also tried simply dropping the output_code = 0 reset. That breaks tools whose non-zero exit code means "I modified files" -- blacken-docs, which is in this repo's own requirements-dev.txt, is one of them -- so nbQA would start failing on a notebook it had successfully left unchanged. Hence the narrower condition.

Tests

Three tests in tests/test_return_code.py, covering both directions of the new condition:

  • tool exits 1 and prints a violation, notebook unchanged -> nbQA exits 1 (fails on main with assert 0 == 1)
  • tool exits 1 and prints nothing, notebook unchanged -> nbQA exits 0 (the case the branch was written for)
  • tool exits 0 after reformatting the temporary file -> nbQA exits 0

They use unittest.mock rather than a notebook fixture on purpose: I could not find an input where a real tool leaves the notebook unchanged and exits non-zero. The condition is reachable, but hard to hit from the outside -- which is probably why it had no coverage.

Test suite

3 failed, 119 passed, 3 skipped on this branch. The three failures are present on main as well (tests/tools/test_ruff_works.py -- a newer ruff prints diagnostics in a different format) and are untouched by this change.

nbQA resets output_code to 0 whenever the third-party tool rewrote the temporary Python file but the round-trip back into the notebook produced no change. That branch exists so that a formatter which only touched the temporary file is not reported as having changed the notebook, but it also swallows genuine failures: ruff check --fix can fix some violations, leave others unfixable and exit 1, and nbQA would report success. Only reset the exit code when the tool printed nothing at all. Closes nbQA-dev#872.
@Eljees
Eljees force-pushed the fix/872-preserve-tool-exit-code branch from 55f4551 to 88c2b4a Compare August 14, 2026 07:05

This branch has not been deployed

No deployments
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.

exit code is 0 on failed "ruff check --fix"

1 participant