Skip to content

fix: correct NumPy integer differences in approx failures - #15312

Open
L-zeus wants to merge 3 commits into
pytest-dev:mainfrom
L-zeus:publish/numpy-integer-approx-diagnostics-20261030
Open

L-zeus wants to merge 3 commits into
pytest-dev:mainfrom
L-zeus:publish/numpy-integer-approx-diagnostics-20261030

Conversation

@L-zeus

@L-zeus L-zeus commented Nov 1, 2026 •

Copy link
Copy Markdown

Problem

When comparing NumPy integer arrays with pytest.approx(), the failure message can show incorrect differences or fail to render because of integer overflow.

For example, comparing np.uint8(255) with 0 should report an absolute difference of 255. However, the failure-reporting path performs arithmetic on a fixed-width NumPy scalar, which can overflow.

The comparison result itself is correct. The problem is limited to how the failure details are calculated.

Change

The existing comparison path already converts NumPy scalars to Python values using _unbox_numpy_scalar().

This change reuses that helper in ApproxNumpy._repr_compare() before calculating the differences.

It fixes the reported values without changing the equality comparison or tolerance calculations.

Tests

Added regression tests covering:

  • uint8, int8, uint64, and int64 boundary values.
  • The actual pytest assertion output with -Werror.

I reproduced the issue on the original code and checked the result after applying the fix. The failure message now reports the correct absolute difference of 255 and relative difference of 1.0.

Codex ran the automated checks on the submission branch:

  • testing/python/approx.py: 187 passed.
  • Applicable pre-commit checks passed.

AI assistance and review

I used OpenAI Codex to assist with the implementation and automated testing.

I reviewed the source changes and regression tests, checked why the comparison path was already correct while the failure-reporting path could overflow, and reproduced the before-and-after behavior locally.

I understand the change and will handle review feedback and any necessary follow-up changes myself. Codex is also credited in a follow-up commit

L-zeus and others added 3 commits October 30, 2026 20:32
Unbox the actual array scalar before mismatch and difference calculations, matching the existing equality path.

Implementation and local verification performed with OpenAI Codex assistance; pending human review.
Codex assisted the implementation and verification of the NumPy integer
failure-diagnostics fix. L-zeus reviewed the changes and reproduced the bug.

Co-authored-by: Codex <noreply@openai.com>
@pyba-chronographer pyba-chronographer Bot added the bot:chronographer:provided (automation) changelog entry is part of PR label Nov 1, 2026
@ege-arhan

Copy link
Copy Markdown

The unboxing fix only reaches ApproxNumpy._repr_compare. ApproxSequenceLike._repr_compare (src/_pytest/approx.py:434-440) still subtracts the raw numpy scalar from the Python float, so approx(<python list>) compared against a numpy integer array keeps the old behaviour.

Repro on head 3c373ef44 (numpy 2.x, pytest 10.0.0.dev13):

import warnings
import numpy as np
import pytest

warnings.simplefilter("error")

print(pytest.approx([0])._repr_compare(np.array([255], dtype=np.uint8)))
print(pytest.approx([127])._repr_compare(np.array([-128], dtype=np.int8)))

Obtained:

Max absolute difference: 1
Max relative difference: 0.00392156862745098
...
Max absolute difference: 1
Max relative difference: -0.0078125

Expected (same values as your new test_numpy_integer_failure_details, which only exercises approx(np.array(...))):

Max absolute difference: 255
Max relative difference: 1.0

Under -Werror line 440 also raises RuntimeWarning: overflow encountered in scalar subtract, so the failure report degrades to "representation of details failed" — the case the changelog entry claims is fixed. The same repro as a test:

def test_sequence_expected_numpy_actual():
    actual = np.array([255], dtype=np.uint8)
    assert actual == pytest.approx([0])

python -m pytest -Werror test_seq_overflow.py fails with RuntimeWarning: overflow encountered in scalar subtract in ApproxScalar.__eq__.

One-line fix in the sequence-like loop, mirroring the numpy path:

            other_value = _unbox_numpy_scalar(other_value)
            if approx_value != other_value:

It is a no-op for plain Python values (_unbox_numpy_scalar only calls .item() when the attribute exists). With that applied testing/python/approx.py stays green (187 passed) and both cases above report 255 / 1.0.

Suggest also adding a list-expected case to test_numpy_integer_failure_details so both _repr_compare implementations are covered.

@doubledare704

Copy link
Copy Markdown

Thanks for working on this. One heads-up: this PR fixes ApproxNumpy._repr_compare, but the same overflow also exists in ApproxSequenceLike._repr_compare and ApproxMapping._repr_compare (see #15314).

More importantly, ApproxScalar.__eq__ does self.expected - actual on the raw numpy scalar, so equality is wrong too for non-array expected values, e.g. np.uint8(255) == approx(254, abs=2) returns False. The array path is the one case that was already correct for equality.

I have a fix for #15314 that unboxes in ApproxScalar.__eq__ and in the sequence and mapping report paths: https://github.com/doubledare704/pytest/tree/fix-approx-numpy-int-overflow. It does not touch ApproxNumpy._repr_compare, so the two should merge cleanly. Would you be OK with that, or would you rather extend this PR to cover the other paths?

@L-zeus

L-zeus commented Nov 1, 2026

Copy link
Copy Markdown
Author

Thanks @ege-arhan and @doubledare704 for the detailed reports and suggestions. I have a local follow-up covering scalar comparisons and sequence/mapping diagnostics, but haven’t pushed it yet

I also noticed #15318 now covers the sequence path, so there’s some overlap. Before pushing, I’d like to coordinate the scope. Would the maintainers prefer keeping this PR focused on NumPy-array diagnostics and addressing the remaining cases separately, or extending it here?

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

bot:chronographer:provided (automation) changelog entry is part of PR

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants