Skip to content

Commit 57c4489

Browse files
committed
Use a simple +- ASCII string in the string representation of pytest.approx In Python 2
Fix #2111
1 parent 5365f7c commit 57c4489

File tree

3 files changed

+49
-23
lines changed

3 files changed

+49
-23
lines changed

CHANGELOG.rst

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,11 @@
1515
* Provide ``:ref:`` targets for ``recwarn.rst`` so we can use intersphinx referencing.
1616
Thanks to `@dupuy`_ for the report and `@lwm`_ for the PR.
1717

18+
* In Python 2, use a simple ``+-`` ASCII string in the string representation of ``pytest.approx`` (for example ``"4 +- 4.0e-06"``)
19+
because it is brittle to handle that in different contexts and representations internally in pytest
20+
which can result in bugs such as `#2111`_. In Python 3, the representation still uses ``±`` (for example ``4 ± 4.0e-06``).
21+
Thanks `@kerrick-lyft`_ for the report and `@nicoddemus`_ for the PR.
22+
1823
* Using ``item.Function``, ``item.Module``, etc., is now issuing deprecation warnings, prefer
1924
``pytest.Function``, ``pytest.Module``, etc., instead (`#2034`_).
2025
Thanks `@nmundar`_ for the PR.
@@ -42,25 +47,27 @@
4247

4348
*
4449

45-
.. _@mbukatov: https://github.com/mbukatov
46-
.. _@dupuy: https://bitbucket.org/dupuy/
47-
.. _@d-b-w: https://bitbucket.org/d-b-w/
48-
.. _@lwm: https://github.com/lwm
4950
.. _@adler-j: https://github.com/adler-j
51+
.. _@d-b-w: https://bitbucket.org/d-b-w/
5052
.. _@DuncanBetts: https://github.com/DuncanBetts
53+
.. _@dupuy: https://bitbucket.org/dupuy/
54+
.. _@kerrick-lyft: https://github.com/kerrick-lyft
55+
.. _@lwm: https://github.com/lwm
56+
.. _@mbukatov: https://github.com/mbukatov
5157
.. _@nedbat: https://github.com/nedbat
5258
.. _@nmundar: https://github.com/nmundar
5359

54-
.. _#2089: https://github.com/pytest-dev/pytest/issues/2089
55-
.. _#478: https://github.com/pytest-dev/pytest/issues/478
56-
.. _#687: https://github.com/pytest-dev/pytest/issues/687
5760
.. _#2016: https://github.com/pytest-dev/pytest/issues/2016
5861
.. _#2034: https://github.com/pytest-dev/pytest/issues/2034
5962
.. _#2038: https://github.com/pytest-dev/pytest/issues/2038
6063
.. _#2078: https://github.com/pytest-dev/pytest/issues/2078
6164
.. _#2082: https://github.com/pytest-dev/pytest/issues/2082
65+
.. _#2089: https://github.com/pytest-dev/pytest/issues/2089
6266
.. _#2103: https://github.com/pytest-dev/pytest/issues/2103
6367
.. _#2105: https://github.com/pytest-dev/pytest/issues/2105
68+
.. _#2111: https://github.com/pytest-dev/pytest/issues/2111
69+
.. _#478: https://github.com/pytest-dev/pytest/issues/478
70+
.. _#687: https://github.com/pytest-dev/pytest/issues/687
6471

6572

6673
3.0.4

_pytest/python.py

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1434,16 +1434,10 @@ def __repr__(self):
14341434
except ValueError:
14351435
vetted_tolerance = '???'
14361436

1437-
plus_minus = u'{0} \u00b1 {1}'.format(self.expected, vetted_tolerance)
1438-
1439-
# In python2, __repr__() must return a string (i.e. not a unicode
1440-
# object). In python3, __repr__() must return a unicode object
1441-
# (although now strings are unicode objects and bytes are what
1442-
# strings were).
14431437
if sys.version_info[0] == 2:
1444-
return plus_minus.encode('utf-8')
1438+
return '{0} +- {1}'.format(self.expected, vetted_tolerance)
14451439
else:
1446-
return plus_minus
1440+
return u'{0} \u00b1 {1}'.format(self.expected, vetted_tolerance)
14471441

14481442
def __eq__(self, actual):
14491443
# Short-circuit exact equality.

testing/python/approx.py

Lines changed: 33 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# encoding: utf-8
2-
2+
import sys
33
import pytest
44
import doctest
55

@@ -9,6 +9,7 @@
99
from fractions import Fraction
1010
inf, nan = float('inf'), float('nan')
1111

12+
1213
class MyDocTestRunner(doctest.DocTestRunner):
1314

1415
def __init__(self):
@@ -22,13 +23,17 @@ def report_failure(self, out, test, example, got):
2223
class TestApprox:
2324

2425
def test_repr_string(self):
25-
# Just make sure the Unicode handling doesn't raise any exceptions.
26-
print(approx(1.0))
27-
print(approx([1.0, 2.0, 3.0]))
28-
print(approx(inf))
29-
print(approx(1.0, rel=nan))
30-
print(approx(1.0, rel=inf))
31-
print(approx(1.0j, rel=inf))
26+
# for some reason in Python 2.6 it is not displaying the tolerance representation correctly
27+
plus_minus = u'\u00b1' if sys.version_info[0] > 2 else u'+-'
28+
tol1, tol2, infr = '1.0e-06', '2.0e-06', 'inf'
29+
if sys.version_info[:2] == (2, 6):
30+
tol1, tol2, infr = '???', '???', '???'
31+
assert repr(approx(1.0)) == '1.0 {pm} {tol1}'.format(pm=plus_minus, tol1=tol1)
32+
assert repr(approx([1.0, 2.0])) == '1.0 {pm} {tol1}, 2.0 {pm} {tol2}'.format(pm=plus_minus, tol1=tol1, tol2=tol2)
33+
assert repr(approx(inf)) == 'inf'
34+
assert repr(approx(1.0, rel=nan)) == '1.0 {pm} ???'.format(pm=plus_minus)
35+
assert repr(approx(1.0, rel=inf)) == '1.0 {pm} {infr}'.format(pm=plus_minus, infr=infr)
36+
assert repr(approx(1.0j, rel=inf)) == '1j'
3237

3338
def test_operator_overloading(self):
3439
assert 1 == approx(1, rel=1e-6, abs=1e-12)
@@ -285,3 +290,23 @@ def test_doctests(self):
285290
runner = MyDocTestRunner()
286291
runner.run(test)
287292

293+
def test_unicode_plus_minus(self, testdir):
294+
"""
295+
Comparing approx instances inside lists should not produce an error in the detailed diff.
296+
Integration test for issue #2111.
297+
"""
298+
testdir.makepyfile("""
299+
import pytest
300+
def test_foo():
301+
assert [3] == [pytest.approx(4)]
302+
""")
303+
expected = '4.0e-06'
304+
# for some reason in Python 2.6 it is not displaying the tolerance representation correctly
305+
if sys.version_info[:2] == (2, 6):
306+
expected = '???'
307+
result = testdir.runpytest()
308+
result.stdout.fnmatch_lines([
309+
'*At index 0 diff: 3 != 4 * {0}'.format(expected),
310+
'=* 1 failed in *=',
311+
])
312+

0 commit comments

Comments
 (0)