How to use mocked_doctest_runner method in Pytest

Best Python code snippet using pytest

Run Pytest automation tests on LambdaTest cloud grid

Perform automation testing on 3000+ real desktop and mobile devices online.

approx.py

Source: approx.py Github

copy
1import operator
2from decimal import Decimal
3from fractions import Fraction
4from operator import eq
5from operator import ne
6from typing import Optional
7
8import pytest
9from pytest import approx
10
11inf, nan = float("inf"), float("nan")
12
13
14@pytest.fixture
15def mocked_doctest_runner(monkeypatch):
16    import doctest
17
18    class MockedPdb:
19        def __init__(self, out):
20            pass
21
22        def set_trace(self):
23            raise NotImplementedError("not used")
24
25        def reset(self):
26            pass
27
28        def set_continue(self):
29            pass
30
31    monkeypatch.setattr("doctest._OutputRedirectingPdb", MockedPdb)
32
33    class MyDocTestRunner(doctest.DocTestRunner):
34        def report_failure(self, out, test, example, got):
35            raise AssertionError(
36                "'{}' evaluates to '{}', not '{}'".format(
37                    example.source.strip(), got.strip(), example.want.strip()
38                )
39            )
40
41    return MyDocTestRunner()
42
43
44class TestApprox:
45    def test_repr_string(self):
46        assert repr(approx(1.0)) == "1.0 ± 1.0e-06"
47        assert repr(approx([1.0, 2.0])) == "approx([1.0 ± 1.0e-06, 2.0 ± 2.0e-06])"
48        assert repr(approx((1.0, 2.0))) == "approx((1.0 ± 1.0e-06, 2.0 ± 2.0e-06))"
49        assert repr(approx(inf)) == "inf"
50        assert repr(approx(1.0, rel=nan)) == "1.0 ± ???"
51        assert repr(approx(1.0, rel=inf)) == "1.0 ± inf"
52
53        # Dictionaries aren't ordered, so we need to check both orders.
54        assert repr(approx({"a": 1.0, "b": 2.0})) in (
55            "approx({'a': 1.0 ± 1.0e-06, 'b': 2.0 ± 2.0e-06})",
56            "approx({'b': 2.0 ± 2.0e-06, 'a': 1.0 ± 1.0e-06})",
57        )
58
59    def test_repr_complex_numbers(self):
60        assert repr(approx(inf + 1j)) == "(inf+1j)"
61        assert repr(approx(1.0j, rel=inf)) == "1j ± inf"
62
63        # can't compute a sensible tolerance
64        assert repr(approx(nan + 1j)) == "(nan+1j) ± ???"
65
66        assert repr(approx(1.0j)) == "1j ± 1.0e-06 ∠ ±180°"
67
68        # relative tolerance is scaled to |3+4j| = 5
69        assert repr(approx(3 + 4 * 1j)) == "(3+4j) ± 5.0e-06 ∠ ±180°"
70
71        # absolute tolerance is not scaled
72        assert repr(approx(3.3 + 4.4 * 1j, abs=0.02)) == "(3.3+4.4j) ± 2.0e-02 ∠ ±180°"
73
74    @pytest.mark.parametrize(
75        "value, expected_repr_string",
76        [
77            (5.0, "approx(5.0 ± 5.0e-06)"),
78            ([5.0], "approx([5.0 ± 5.0e-06])"),
79            ([[5.0]], "approx([[5.0 ± 5.0e-06]])"),
80            ([[5.0, 6.0]], "approx([[5.0 ± 5.0e-06, 6.0 ± 6.0e-06]])"),
81            ([[5.0], [6.0]], "approx([[5.0 ± 5.0e-06], [6.0 ± 6.0e-06]])"),
82        ],
83    )
84    def test_repr_nd_array(self, value, expected_repr_string):
85        """Make sure that arrays of all different dimensions are repr'd correctly."""
86        np = pytest.importorskip("numpy")
87        np_array = np.array(value)
88        assert repr(approx(np_array)) == expected_repr_string
89
90    def test_operator_overloading(self):
91        assert 1 == approx(1, rel=1e-6, abs=1e-12)
92        assert not (1 != approx(1, rel=1e-6, abs=1e-12))
93        assert 10 != approx(1, rel=1e-6, abs=1e-12)
94        assert not (10 == approx(1, rel=1e-6, abs=1e-12))
95
96    def test_exactly_equal(self):
97        examples = [
98            (2.0, 2.0),
99            (0.1e200, 0.1e200),
100            (1.123e-300, 1.123e-300),
101            (12345, 12345.0),
102            (0.0, -0.0),
103            (345678, 345678),
104            (Decimal("1.0001"), Decimal("1.0001")),
105            (Fraction(1, 3), Fraction(-1, -3)),
106        ]
107        for a, x in examples:
108            assert a == approx(x)
109
110    def test_opposite_sign(self):
111        examples = [(eq, 1e-100, -1e-100), (ne, 1e100, -1e100)]
112        for op, a, x in examples:
113            assert op(a, approx(x))
114
115    def test_zero_tolerance(self):
116        within_1e10 = [(1.1e-100, 1e-100), (-1.1e-100, -1e-100)]
117        for a, x in within_1e10:
118            assert x == approx(x, rel=0.0, abs=0.0)
119            assert a != approx(x, rel=0.0, abs=0.0)
120            assert a == approx(x, rel=0.0, abs=5e-101)
121            assert a != approx(x, rel=0.0, abs=5e-102)
122            assert a == approx(x, rel=5e-1, abs=0.0)
123            assert a != approx(x, rel=5e-2, abs=0.0)
124
125    @pytest.mark.parametrize(
126        ("rel", "abs"),
127        [
128            (-1e100, None),
129            (None, -1e100),
130            (1e100, -1e100),
131            (-1e100, 1e100),
132            (-1e100, -1e100),
133        ],
134    )
135    def test_negative_tolerance(
136        self, rel: Optional[float], abs: Optional[float]
137    ) -> None:
138        # Negative tolerances are not allowed.
139        with pytest.raises(ValueError):
140            1.1 == approx(1, rel, abs)
141
142    def test_inf_tolerance(self):
143        # Everything should be equal if the tolerance is infinite.
144        large_diffs = [(1, 1000), (1e-50, 1e50), (-1.0, -1e300), (0.0, 10)]
145        for a, x in large_diffs:
146            assert a != approx(x, rel=0.0, abs=0.0)
147            assert a == approx(x, rel=inf, abs=0.0)
148            assert a == approx(x, rel=0.0, abs=inf)
149            assert a == approx(x, rel=inf, abs=inf)
150
151    def test_inf_tolerance_expecting_zero(self) -> None:
152        # If the relative tolerance is zero but the expected value is infinite,
153        # the actual tolerance is a NaN, which should be an error.
154        with pytest.raises(ValueError):
155            1 == approx(0, rel=inf, abs=0.0)
156        with pytest.raises(ValueError):
157            1 == approx(0, rel=inf, abs=inf)
158
159    def test_nan_tolerance(self) -> None:
160        with pytest.raises(ValueError):
161            1.1 == approx(1, rel=nan)
162        with pytest.raises(ValueError):
163            1.1 == approx(1, abs=nan)
164        with pytest.raises(ValueError):
165            1.1 == approx(1, rel=nan, abs=nan)
166
167    def test_reasonable_defaults(self):
168        # Whatever the defaults are, they should work for numbers close to 1
169        # than have a small amount of floating-point error.
170        assert 0.1 + 0.2 == approx(0.3)
171
172    def test_default_tolerances(self):
173        # This tests the defaults as they are currently set.  If you change the
174        # defaults, this test will fail but you should feel free to change it.
175        # None of the other tests (except the doctests) should be affected by
176        # the choice of defaults.
177        examples = [
178            # Relative tolerance used.
179            (eq, 1e100 + 1e94, 1e100),
180            (ne, 1e100 + 2e94, 1e100),
181            (eq, 1e0 + 1e-6, 1e0),
182            (ne, 1e0 + 2e-6, 1e0),
183            # Absolute tolerance used.
184            (eq, 1e-100, +1e-106),
185            (eq, 1e-100, +2e-106),
186            (eq, 1e-100, 0),
187        ]
188        for op, a, x in examples:
189            assert op(a, approx(x))
190
191    def test_custom_tolerances(self):
192        assert 1e8 + 1e0 == approx(1e8, rel=5e-8, abs=5e0)
193        assert 1e8 + 1e0 == approx(1e8, rel=5e-9, abs=5e0)
194        assert 1e8 + 1e0 == approx(1e8, rel=5e-8, abs=5e-1)
195        assert 1e8 + 1e0 != approx(1e8, rel=5e-9, abs=5e-1)
196
197        assert 1e0 + 1e-8 == approx(1e0, rel=5e-8, abs=5e-8)
198        assert 1e0 + 1e-8 == approx(1e0, rel=5e-9, abs=5e-8)
199        assert 1e0 + 1e-8 == approx(1e0, rel=5e-8, abs=5e-9)
200        assert 1e0 + 1e-8 != approx(1e0, rel=5e-9, abs=5e-9)
201
202        assert 1e-8 + 1e-16 == approx(1e-8, rel=5e-8, abs=5e-16)
203        assert 1e-8 + 1e-16 == approx(1e-8, rel=5e-9, abs=5e-16)
204        assert 1e-8 + 1e-16 == approx(1e-8, rel=5e-8, abs=5e-17)
205        assert 1e-8 + 1e-16 != approx(1e-8, rel=5e-9, abs=5e-17)
206
207    def test_relative_tolerance(self):
208        within_1e8_rel = [(1e8 + 1e0, 1e8), (1e0 + 1e-8, 1e0), (1e-8 + 1e-16, 1e-8)]
209        for a, x in within_1e8_rel:
210            assert a == approx(x, rel=5e-8, abs=0.0)
211            assert a != approx(x, rel=5e-9, abs=0.0)
212
213    def test_absolute_tolerance(self):
214        within_1e8_abs = [(1e8 + 9e-9, 1e8), (1e0 + 9e-9, 1e0), (1e-8 + 9e-9, 1e-8)]
215        for a, x in within_1e8_abs:
216            assert a == approx(x, rel=0, abs=5e-8)
217            assert a != approx(x, rel=0, abs=5e-9)
218
219    def test_expecting_zero(self):
220        examples = [
221            (ne, 1e-6, 0.0),
222            (ne, -1e-6, 0.0),
223            (eq, 1e-12, 0.0),
224            (eq, -1e-12, 0.0),
225            (ne, 2e-12, 0.0),
226            (ne, -2e-12, 0.0),
227            (ne, inf, 0.0),
228            (ne, nan, 0.0),
229        ]
230        for op, a, x in examples:
231            assert op(a, approx(x, rel=0.0, abs=1e-12))
232            assert op(a, approx(x, rel=1e-6, abs=1e-12))
233
234    def test_expecting_inf(self):
235        examples = [
236            (eq, inf, inf),
237            (eq, -inf, -inf),
238            (ne, inf, -inf),
239            (ne, 0.0, inf),
240            (ne, nan, inf),
241        ]
242        for op, a, x in examples:
243            assert op(a, approx(x))
244
245    def test_expecting_nan(self):
246        examples = [
247            (eq, nan, nan),
248            (eq, -nan, -nan),
249            (eq, nan, -nan),
250            (ne, 0.0, nan),
251            (ne, inf, nan),
252        ]
253        for op, a, x in examples:
254            # Nothing is equal to NaN by default.
255            assert a != approx(x)
256
257            # If ``nan_ok=True``, then NaN is equal to NaN.
258            assert op(a, approx(x, nan_ok=True))
259
260    def test_int(self):
261        within_1e6 = [(1000001, 1000000), (-1000001, -1000000)]
262        for a, x in within_1e6:
263            assert a == approx(x, rel=5e-6, abs=0)
264            assert a != approx(x, rel=5e-7, abs=0)
265            assert approx(x, rel=5e-6, abs=0) == a
266            assert approx(x, rel=5e-7, abs=0) != a
267
268    def test_decimal(self):
269        within_1e6 = [
270            (Decimal("1.000001"), Decimal("1.0")),
271            (Decimal("-1.000001"), Decimal("-1.0")),
272        ]
273        for a, x in within_1e6:
274            assert a == approx(x)
275            assert a == approx(x, rel=Decimal("5e-6"), abs=0)
276            assert a != approx(x, rel=Decimal("5e-7"), abs=0)
277            assert approx(x, rel=Decimal("5e-6"), abs=0) == a
278            assert approx(x, rel=Decimal("5e-7"), abs=0) != a
279
280    def test_fraction(self):
281        within_1e6 = [
282            (1 + Fraction(1, 1000000), Fraction(1)),
283            (-1 - Fraction(-1, 1000000), Fraction(-1)),
284        ]
285        for a, x in within_1e6:
286            assert a == approx(x, rel=5e-6, abs=0)
287            assert a != approx(x, rel=5e-7, abs=0)
288            assert approx(x, rel=5e-6, abs=0) == a
289            assert approx(x, rel=5e-7, abs=0) != a
290
291    def test_complex(self):
292        within_1e6 = [
293            (1.000001 + 1.0j, 1.0 + 1.0j),
294            (1.0 + 1.000001j, 1.0 + 1.0j),
295            (-1.000001 + 1.0j, -1.0 + 1.0j),
296            (1.0 - 1.000001j, 1.0 - 1.0j),
297        ]
298        for a, x in within_1e6:
299            assert a == approx(x, rel=5e-6, abs=0)
300            assert a != approx(x, rel=5e-7, abs=0)
301            assert approx(x, rel=5e-6, abs=0) == a
302            assert approx(x, rel=5e-7, abs=0) != a
303
304    def test_list(self):
305        actual = [1 + 1e-7, 2 + 1e-8]
306        expected = [1, 2]
307
308        # Return false if any element is outside the tolerance.
309        assert actual == approx(expected, rel=5e-7, abs=0)
310        assert actual != approx(expected, rel=5e-8, abs=0)
311        assert approx(expected, rel=5e-7, abs=0) == actual
312        assert approx(expected, rel=5e-8, abs=0) != actual
313
314    def test_list_wrong_len(self):
315        assert [1, 2] != approx([1])
316        assert [1, 2] != approx([1, 2, 3])
317
318    def test_tuple(self):
319        actual = (1 + 1e-7, 2 + 1e-8)
320        expected = (1, 2)
321
322        # Return false if any element is outside the tolerance.
323        assert actual == approx(expected, rel=5e-7, abs=0)
324        assert actual != approx(expected, rel=5e-8, abs=0)
325        assert approx(expected, rel=5e-7, abs=0) == actual
326        assert approx(expected, rel=5e-8, abs=0) != actual
327
328    def test_tuple_wrong_len(self):
329        assert (1, 2) != approx((1,))
330        assert (1, 2) != approx((1, 2, 3))
331
332    def test_dict(self):
333        actual = {"a": 1 + 1e-7, "b": 2 + 1e-8}
334        # Dictionaries became ordered in python3.6, so switch up the order here
335        # to make sure it doesn't matter.
336        expected = {"b": 2, "a": 1}
337
338        # Return false if any element is outside the tolerance.
339        assert actual == approx(expected, rel=5e-7, abs=0)
340        assert actual != approx(expected, rel=5e-8, abs=0)
341        assert approx(expected, rel=5e-7, abs=0) == actual
342        assert approx(expected, rel=5e-8, abs=0) != actual
343
344    def test_dict_wrong_len(self):
345        assert {"a": 1, "b": 2} != approx({"a": 1})
346        assert {"a": 1, "b": 2} != approx({"a": 1, "c": 2})
347        assert {"a": 1, "b": 2} != approx({"a": 1, "b": 2, "c": 3})
348
349    def test_numpy_array(self):
350        np = pytest.importorskip("numpy")
351
352        actual = np.array([1 + 1e-7, 2 + 1e-8])
353        expected = np.array([1, 2])
354
355        # Return false if any element is outside the tolerance.
356        assert actual == approx(expected, rel=5e-7, abs=0)
357        assert actual != approx(expected, rel=5e-8, abs=0)
358        assert approx(expected, rel=5e-7, abs=0) == expected
359        assert approx(expected, rel=5e-8, abs=0) != actual
360
361        # Should be able to compare lists with numpy arrays.
362        assert list(actual) == approx(expected, rel=5e-7, abs=0)
363        assert list(actual) != approx(expected, rel=5e-8, abs=0)
364        assert actual == approx(list(expected), rel=5e-7, abs=0)
365        assert actual != approx(list(expected), rel=5e-8, abs=0)
366
367    def test_numpy_tolerance_args(self):
368        """
369        Check that numpy rel/abs args are handled correctly
370        for comparison against an np.array
371        Check both sides of the operator, hopefully it doesn't impact things.
372        Test all permutations of where the approx and np.array() can show up
373        """
374        np = pytest.importorskip("numpy")
375        expected = 100.0
376        actual = 99.0
377        abs_diff = expected - actual
378        rel_diff = (expected - actual) / expected
379
380        tests = [
381            (eq, abs_diff, 0),
382            (eq, 0, rel_diff),
383            (ne, 0, rel_diff / 2.0),  # rel diff fail
384            (ne, abs_diff / 2.0, 0),  # abs diff fail
385        ]
386
387        for op, _abs, _rel in tests:
388            assert op(np.array(actual), approx(expected, abs=_abs, rel=_rel))  # a, b
389            assert op(approx(expected, abs=_abs, rel=_rel), np.array(actual))  # b, a
390
391            assert op(actual, approx(np.array(expected), abs=_abs, rel=_rel))  # a, b
392            assert op(approx(np.array(expected), abs=_abs, rel=_rel), actual)  # b, a
393
394            assert op(np.array(actual), approx(np.array(expected), abs=_abs, rel=_rel))
395            assert op(approx(np.array(expected), abs=_abs, rel=_rel), np.array(actual))
396
397    def test_numpy_expecting_nan(self):
398        np = pytest.importorskip("numpy")
399        examples = [
400            (eq, nan, nan),
401            (eq, -nan, -nan),
402            (eq, nan, -nan),
403            (ne, 0.0, nan),
404            (ne, inf, nan),
405        ]
406        for op, a, x in examples:
407            # Nothing is equal to NaN by default.
408            assert np.array(a) != approx(x)
409            assert a != approx(np.array(x))
410
411            # If ``nan_ok=True``, then NaN is equal to NaN.
412            assert op(np.array(a), approx(x, nan_ok=True))
413            assert op(a, approx(np.array(x), nan_ok=True))
414
415    def test_numpy_expecting_inf(self):
416        np = pytest.importorskip("numpy")
417        examples = [
418            (eq, inf, inf),
419            (eq, -inf, -inf),
420            (ne, inf, -inf),
421            (ne, 0.0, inf),
422            (ne, nan, inf),
423        ]
424        for op, a, x in examples:
425            assert op(np.array(a), approx(x))
426            assert op(a, approx(np.array(x)))
427            assert op(np.array(a), approx(np.array(x)))
428
429    def test_numpy_array_wrong_shape(self):
430        np = pytest.importorskip("numpy")
431
432        a12 = np.array([[1, 2]])
433        a21 = np.array([[1], [2]])
434
435        assert a12 != approx(a21)
436        assert a21 != approx(a12)
437
438    def test_doctests(self, mocked_doctest_runner) -> None:
439        import doctest
440
441        parser = doctest.DocTestParser()
442        assert approx.__doc__ is not None
443        test = parser.get_doctest(
444            approx.__doc__, {"approx": approx}, approx.__name__, None, None
445        )
446        mocked_doctest_runner.run(test)
447
448    def test_unicode_plus_minus(self, testdir):
449        """
450        Comparing approx instances inside lists should not produce an error in the detailed diff.
451        Integration test for issue #2111.
452        """
453        testdir.makepyfile(
454            """
455            import pytest
456            def test_foo():
457                assert [3] == [pytest.approx(4)]
458        """
459        )
460        expected = "4.0e-06"
461        result = testdir.runpytest()
462        result.stdout.fnmatch_lines(
463            ["*At index 0 diff: 3 != 4 ± {}".format(expected), "=* 1 failed in *="]
464        )
465
466    @pytest.mark.parametrize(
467        "x",
468        [
469            pytest.param(None),
470            pytest.param("string"),
471            pytest.param(["string"], id="nested-str"),
472            pytest.param([[1]], id="nested-list"),
473            pytest.param({"key": "string"}, id="dict-with-string"),
474            pytest.param({"key": {"key": 1}}, id="nested-dict"),
475        ],
476    )
477    def test_expected_value_type_error(self, x):
478        with pytest.raises(TypeError):
479            approx(x)
480
481    @pytest.mark.parametrize(
482        "op",
483        [
484            pytest.param(operator.le, id="<="),
485            pytest.param(operator.lt, id="<"),
486            pytest.param(operator.ge, id=">="),
487            pytest.param(operator.gt, id=">"),
488        ],
489    )
490    def test_comparison_operator_type_error(self, op):
491        """pytest.approx should raise TypeError for operators other than == and != (#2003)."""
492        with pytest.raises(TypeError):
493            op(1, approx(1, rel=1e-6, abs=1e-12))
494
495    def test_numpy_array_with_scalar(self):
496        np = pytest.importorskip("numpy")
497
498        actual = np.array([1 + 1e-7, 1 - 1e-8])
499        expected = 1.0
500
501        assert actual == approx(expected, rel=5e-7, abs=0)
502        assert actual != approx(expected, rel=5e-8, abs=0)
503        assert approx(expected, rel=5e-7, abs=0) == actual
504        assert approx(expected, rel=5e-8, abs=0) != actual
505
506    def test_numpy_scalar_with_array(self):
507        np = pytest.importorskip("numpy")
508
509        actual = 1.0
510        expected = np.array([1 + 1e-7, 1 - 1e-8])
511
512        assert actual == approx(expected, rel=5e-7, abs=0)
513        assert actual != approx(expected, rel=5e-8, abs=0)
514        assert approx(expected, rel=5e-7, abs=0) == actual
515        assert approx(expected, rel=5e-8, abs=0) != actual
516
517    def test_generic_sized_iterable_object(self):
518        class MySizedIterable:
519            def __iter__(self):
520                return iter([1, 2, 3, 4])
521
522            def __len__(self):
523                return 4
524
525        expected = MySizedIterable()
526        assert [1, 2, 3, 4] == approx(expected)
527
Full Screen

Accelerate Your Automation Test Cycles With LambdaTest

Leverage LambdaTest’s cloud-based platform to execute your automation tests in parallel and trim down your test execution time significantly. Your first 100 automation testing minutes are on us.

Try LambdaTest

Run Python Tests on LambdaTest Cloud Grid

Execute automation tests with Pytest on a cloud-based Grid of 3000+ real browsers and operating systems for both web and mobile applications.

Test now for Free
LambdaTestX

We use cookies to give you the best experience. Cookies help to provide a more personalized experience and relevant advertising for you, and web analytics for us. Learn More in our Cookies policy, Privacy & Terms of service

Allow Cookie
Sarah

I hope you find the best code examples for your project.

If you want to accelerate automated browser testing, try LambdaTest. Your first 100 automation testing minutes are FREE.

Sarah Elson (Product & Growth Lead)