python_api: let approx() take nonnumeric values (#7710)

Co-authored-by: Bruno Oliveira <nicoddemus@gmail.com>
This commit is contained in:
Jakob van Santen
2020-09-28 17:17:23 +02:00
committed by GitHub
parent f324b27d02
commit 91fa11bed0
4 changed files with 117 additions and 21 deletions

View File

@@ -1,4 +1,5 @@
import operator
import sys
from decimal import Decimal
from fractions import Fraction
from operator import eq
@@ -329,6 +330,9 @@ class TestApprox:
assert (1, 2) != approx((1,))
assert (1, 2) != approx((1, 2, 3))
def test_tuple_vs_other(self):
assert 1 != approx((1,))
def test_dict(self):
actual = {"a": 1 + 1e-7, "b": 2 + 1e-8}
# Dictionaries became ordered in python3.6, so switch up the order here
@@ -346,6 +350,13 @@ class TestApprox:
assert {"a": 1, "b": 2} != approx({"a": 1, "c": 2})
assert {"a": 1, "b": 2} != approx({"a": 1, "b": 2, "c": 3})
def test_dict_nonnumeric(self):
assert {"a": 1.0, "b": None} == pytest.approx({"a": 1.0, "b": None})
assert {"a": 1.0, "b": 1} != pytest.approx({"a": 1.0, "b": None})
def test_dict_vs_other(self):
assert 1 != approx({"a": 0})
def test_numpy_array(self):
np = pytest.importorskip("numpy")
@@ -463,20 +474,67 @@ class TestApprox:
["*At index 0 diff: 3 != 4 ± {}".format(expected), "=* 1 failed in *="]
)
@pytest.mark.parametrize(
"x, name",
[
pytest.param([[1]], "data structures", id="nested-list"),
pytest.param({"key": {"key": 1}}, "dictionaries", id="nested-dict"),
],
)
def test_expected_value_type_error(self, x, name):
with pytest.raises(
TypeError,
match=r"pytest.approx\(\) does not support nested {}:".format(name),
):
approx(x)
@pytest.mark.parametrize(
"x",
[
pytest.param(None),
pytest.param("string"),
pytest.param(["string"], id="nested-str"),
pytest.param([[1]], id="nested-list"),
pytest.param({"key": "string"}, id="dict-with-string"),
pytest.param({"key": {"key": 1}}, id="nested-dict"),
],
)
def test_expected_value_type_error(self, x):
with pytest.raises(TypeError):
approx(x)
def test_nonnumeric_okay_if_equal(self, x):
assert x == approx(x)
@pytest.mark.parametrize(
"x",
[
pytest.param("string"),
pytest.param(["string"], id="nested-str"),
pytest.param({"key": "string"}, id="dict-with-string"),
],
)
def test_nonnumeric_false_if_unequal(self, x):
"""For nonnumeric types, x != pytest.approx(y) reduces to x != y"""
assert "ab" != approx("abc")
assert ["ab"] != approx(["abc"])
# in particular, both of these should return False
assert {"a": 1.0} != approx({"a": None})
assert {"a": None} != approx({"a": 1.0})
assert 1.0 != approx(None)
assert None != approx(1.0) # noqa: E711
assert 1.0 != approx([None])
assert None != approx([1.0]) # noqa: E711
@pytest.mark.skipif(sys.version_info < (3, 7), reason="requires ordered dicts")
def test_nonnumeric_dict_repr(self):
"""Dicts with non-numerics and infinites have no tolerances"""
x1 = {"foo": 1.0000005, "bar": None, "foobar": inf}
assert (
repr(approx(x1))
== "approx({'foo': 1.0000005 ± 1.0e-06, 'bar': None, 'foobar': inf})"
)
def test_nonnumeric_list_repr(self):
"""Lists with non-numerics and infinites have no tolerances"""
x1 = [1.0000005, None, inf]
assert repr(approx(x1)) == "approx([1.0000005 ± 1.0e-06, None, inf])"
@pytest.mark.parametrize(
"op",