Skip to content

fix: point file and line at the same place - #6

Merged
othercodes merged 1 commit into
masterfrom
fix/failure-location
Aug 7, 2026
Merged

othercodes merged 1 commit into
masterfrom
fix/failure-location

Conversation

@othercodes

Copy link
Copy Markdown
Owner

file and line could point at different places, because they came from different sources: file from report.location, line from reprcrash.lineno. reprcrash points at the frame that raised, which for self.assertEqual is inside the standard library. A run of unittest tests reported this:

{"file":"test_auth.py","line":918,"type":"AssertionError","message":"401 != 200"}

in a file of twelve lines. The coordinate does not exist, and handing an agent somewhere to look is what this library is for.

Why no test caught it

Every failure in the suite used a bare assert, where the crash lands in the test file itself, so the two sources happen to agree. It shows up with unittest.TestCase, with any project that wraps its assertions in a helper, and with pyssertive.

Found by checking whether pymmary[pytest] covers unittest projects, which it does, except the line numbers were wrong.

The fix

Both fields now come from the last entry of the rendered traceback, which is what pytest prints as path:lineno:. It is already relative, already 1-based, and it is a pair by construction. It is also the frame the ecosystem points at: assertion helpers that set __tracebackhide__ drop out, so the last entry lands back in the test.

Measured against real pytest output, all five shapes, serial and -n 2:

Failure pytest before after
unittest assertEqual test_mix.py:11 case.py:918 test_mix.py:11
bare assert test_mix.py:15 test_mix.py:15 test_mix.py:15
helper in the same file test_mix.py:6 test_mix.py:6 test_mix.py:6
raise test_mix.py:23 test_mix.py:23 test_mix.py:23
fixture error test_mix.py:28 test_mix.py:28 test_mix.py:28

reprfileloc survives the xdist worker boundary, so -n 2 gives the same numbers.

Fallbacks

Two, both returning a coherent pair:

  • No file location on the traceback entries (--tb=no, --tb=line, --tb=native): falls back to reprcrash, paying an absolute path for it.
  • longrepr replaced by a plain string, which plugins are allowed to do: falls back to the test file with line 0. Losing the line is acceptable, crashing is not.

86 tests, coverage still 100%.

They came from different sources. `file` from report.location, `line` from
reprcrash.lineno, and reprcrash points at the frame that raised. For
`self.assertEqual` that frame is inside the standard library, so a run of
unittest tests reported this:

  {"file":"test_auth.py","line":918,"type":"AssertionError","message":"401 != 200"}

in a file of twelve lines. A coordinate that does not exist, and the
library exists to hand an agent somewhere to look.

Bare `assert` hid it: the crash lands in the test file, so file and line
happen to agree and every test we had passed. It shows up with unittest,
with any project that wraps its assertions in a helper, and with
pyssertive.

Both now come from the last entry of the rendered traceback, which is the
`path:lineno:` pytest itself prints, already relative and already 1-based,
and a pair by construction. Verified to match pytest exactly across bare
assert, unittest assertEqual, a helper in the same file, a raise and a
fixture error, in serial and under -n 2.

Falls back to reprcrash when there is no traceback to read (--tb=no,
--tb=line, --tb=native), and to the test file with line 0 when a plugin
has replaced longrepr with a plain string. Both tiers still return a pair.

86 tests, coverage still 100%.
@sonarqubecloud

sonarqubecloud Bot commented Aug 7, 2026

Copy link
Copy Markdown

@othercodes
othercodes merged commit 5c95f4e into master Aug 7, 2026
13 checks passed
@othercodes
othercodes deleted the fix/failure-location branch August 7, 2026 04:22
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.

1 participant