Skip to content

Attribute error in pytest.approx for types implicitly convertible to numpy arrays #12114

Closed
@ascended121

Description

@ascended121
  • a detailed description of the bug or problem you are having

When using pytest.approx with custom types which are implicitly convertible to numpy arrays, the following error is observed:

E       AssertionError: assert <test_matrix_...x7f9169ac4ca0> == approx([1.0 ±....0 ± 4.0e-06])
E         (pytest_assertion plugin: representation of details failed: ~/.venv/lib/python3.10/site-packages/_pytest/python_api.py:175: AttributeError: 'MyType' object has no attribute 'shape'.
E          Probably an object has a faulty __repr__.)

Note: The line number in the error message is a little off from the current head. That line is here.

Looking at the code, pytest.approx sensibly chooses the numpy implementation ApproxNumpy, because the expected value is implicitly convertible to a numpy array. However, the shape check assumes that other_side is a numpy array (rather than assuming its implicitly convertible to a numpy array, like the expected value is) and so assumes that it has a shape attribute (which is not part of how approx determines if something is a numpy array).

It seems like either:

  1. ApproxNumpy._repr_compare() needs to convert other_side to a numpy array (ie _as_numpy_array(other_side))
  2. _as_numpy_array needs to check if the object has a shape attribute, if the code is going to assume that's the case
  • output of pip list from the virtual environment you are using:
    Relevant packages:
    numpy: 1.26.1

  • pytest and operating system versions

pytest: 7.4.3
Ubuntu: 22.04

  • minimal example if possible
import numpy as np
import pytest

class MyType:
    """Type which is implicitly convertible to a numpy array."""
    def __init__(self, vals):
        self.vals = vals

    def __repr__(self):
        return f"{self.__class__.__name__}({self.vals})"

    def __array__(self, dtype=None, copy=None):
        return np.array(self.vals)

def test_approx_eq():
    vec1 = MyType([1.0, 2.0, 3.0])
    vec2 = MyType([1.0, 2.0, 4.0])
    assert vec1 == pytest.approx(vec2)

Metadata

Metadata

Assignees

No one assigned

    Labels

    topic: approxrelated to pytest.approx functiontype: bugproblem that needs to be addressed

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions