Skip to content

Commit

Permalink
Merge remote-tracking branch 'upstream/master' into features
Browse files Browse the repository at this point in the history
  • Loading branch information
nicoddemus committed Jun 9, 2017
2 parents c67bf9d + b2d7c26 commit 467c526
Show file tree
Hide file tree
Showing 13 changed files with 129 additions and 22 deletions.
32 changes: 32 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,38 @@
.. towncrier release notes start
Pytest 3.1.2 (2017-06-08)
=========================

Bug Fixes
---------

- Required options added via ``pytest_addoption`` will no longer prevent using
--help without passing them. (#1999)

- Respect ``python_files`` in assertion rewriting. (#2121)

- Fix recursion error detection when frames in the traceback contain objects
that can't be compared (like ``numpy`` arrays). (#2459)

- ``UnicodeWarning`` is issued from the internal pytest warnings plugin only
when the message contains non-ascii unicode (Python 2 only). (#2463)

- Added a workaround for Python 3.6 WindowsConsoleIO breaking due to Pytests's
FDCapture. Other code using console handles might still be affected by the
very same issue and might require further workarounds/fixes, i.e. colorama.
(#2467)


Improved Documentation
----------------------

- Fix internal API links to ``pluggy`` objects. (#2331)

- Make it clear that ``pytest.xfail`` stops test execution at the calling point
and improve overall flow of the ``skipping`` docs. (#810)


Pytest 3.1.1 (2017-05-30)
=========================

Expand Down
41 changes: 34 additions & 7 deletions _pytest/_code/code.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from inspect import CO_VARARGS, CO_VARKEYWORDS
import re
from weakref import ref
from _pytest.compat import _PY2, _PY3, PY35
from _pytest.compat import _PY2, _PY3, PY35, safe_str

import py
builtin_repr = repr
Expand Down Expand Up @@ -602,21 +602,48 @@ def repr_traceback(self, excinfo):
traceback = excinfo.traceback
if self.tbfilter:
traceback = traceback.filter()
recursionindex = None

if is_recursion_error(excinfo):
recursionindex = traceback.recursionindex()
traceback, extraline = self._truncate_recursive_traceback(traceback)
else:
extraline = None

last = traceback[-1]
entries = []
extraline = None
for index, entry in enumerate(traceback):
einfo = (last == entry) and excinfo or None
reprentry = self.repr_traceback_entry(entry, einfo)
entries.append(reprentry)
if index == recursionindex:
extraline = "!!! Recursion detected (same locals & position)"
break
return ReprTraceback(entries, extraline, style=self.style)

def _truncate_recursive_traceback(self, traceback):
"""
Truncate the given recursive traceback trying to find the starting point
of the recursion.
The detection is done by going through each traceback entry and finding the
point in which the locals of the frame are equal to the locals of a previous frame (see ``recursionindex()``.
Handle the situation where the recursion process might raise an exception (for example
comparing numpy arrays using equality raises a TypeError), in which case we do our best to
warn the user of the error and show a limited traceback.
"""
try:
recursionindex = traceback.recursionindex()
except Exception as e:
max_frames = 10
extraline = (
'!!! Recursion error detected, but an error occurred locating the origin of recursion.\n'
' The following exception happened when comparing locals in the stack frame:\n'
' {exc_type}: {exc_msg}\n'
' Displaying first and last {max_frames} stack frames out of {total}.'
).format(exc_type=type(e).__name__, exc_msg=safe_str(e), max_frames=max_frames, total=len(traceback))
traceback = traceback[:max_frames] + traceback[-max_frames:]
else:
extraline = "!!! Recursion detected (same locals & position)"
traceback = traceback[:recursionindex + 1]

return traceback, extraline

def repr_excinfo(self, excinfo):
if _PY2:
Expand Down
9 changes: 5 additions & 4 deletions _pytest/warnings.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,9 @@ def catch_warnings_for_item(item):
unicode_warning = False

if compat._PY2 and any(isinstance(m, compat.UNICODE_TYPES) for m in warn_msg.args):
warn_msg.args = [compat.safe_str(m) for m in warn_msg.args]
unicode_warning = True
new_args = [compat.safe_str(m) for m in warn_msg.args]
unicode_warning = warn_msg.args != new_args
warn_msg.args = new_args

msg = warnings.formatwarning(
warn_msg, warning.category,
Expand All @@ -76,8 +77,8 @@ def catch_warnings_for_item(item):

if unicode_warning:
warnings.warn(
"This warning %s is broken as it's message is not a str instance"
"(after all this is a stdlib problem workaround)" % msg,
"Warning is using unicode non convertible to ascii, "
"converting to a safe representation:\n %s" % msg,
UnicodeWarning)


Expand Down
2 changes: 0 additions & 2 deletions changelog/1999.bugfix

This file was deleted.

1 change: 0 additions & 1 deletion changelog/2121.bugfix

This file was deleted.

1 change: 0 additions & 1 deletion changelog/2331.doc

This file was deleted.

3 changes: 0 additions & 3 deletions changelog/2467.bugfix

This file was deleted.

1 change: 0 additions & 1 deletion changelog/810.doc

This file was deleted.

1 change: 1 addition & 0 deletions doc/en/announce/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ Release announcements
:maxdepth: 2


release-3.1.2
release-3.1.1
release-3.1.0
release-3.0.7
Expand Down
23 changes: 23 additions & 0 deletions doc/en/announce/release-3.1.2.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
pytest-3.1.2
=======================================

pytest 3.1.2 has just been released to PyPI.

This is a bug-fix release, being a drop-in replacement. To upgrade::

pip install --upgrade pytest
The full changelog is available at http://doc.pytest.org/en/latest/changelog.html.

Thanks to all who contributed to this release, among them:

* Andreas Pelme
* ApaDoctor
* Bruno Oliveira
* Florian Bruhin
* Ronny Pfannschmidt
* Segev Finer


Happy testing,
The pytest Development Team
2 changes: 0 additions & 2 deletions doc/en/skipping.rst
Original file line number Diff line number Diff line change
Expand Up @@ -322,8 +322,6 @@ Running it with the report-on-xfail option gives this output::
======= 7 xfailed in 0.12 seconds ========



.. _`skip/xfail with parametrize`:

Skip/xfail with parametrize
Expand Down
33 changes: 33 additions & 0 deletions testing/code/test_excinfo.py
Original file line number Diff line number Diff line change
Expand Up @@ -1140,3 +1140,36 @@ def test(tmpdir):
result = testdir.runpytest()
result.stdout.fnmatch_lines(['* 1 failed in *'])
assert 'INTERNALERROR' not in result.stdout.str() + result.stderr.str()


def test_exception_repr_extraction_error_on_recursion():
"""
Ensure we can properly detect a recursion error even
if some locals raise error on comparision (#2459).
"""
class numpy_like(object):

def __eq__(self, other):
if type(other) is numpy_like:
raise ValueError('The truth value of an array '
'with more than one element is ambiguous.')

def a(x):
return b(numpy_like())

def b(x):
return a(numpy_like())

try:
a(numpy_like())
except:
from _pytest._code.code import ExceptionInfo
from _pytest.pytester import LineMatcher
exc_info = ExceptionInfo()

matcher = LineMatcher(str(exc_info.getrepr()).splitlines())
matcher.fnmatch_lines([
'!!! Recursion error detected, but an error occurred locating the origin of recursion.',
'*The following exception happened*',
'*ValueError: The truth value of an array*',
])
2 changes: 1 addition & 1 deletion testing/test_warnings.py
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ def test_func(fix):

'*test_py2_unicode.py:8: UserWarning: \u6d4b\u8bd5',
'*warnings.warn(u"\u6d4b\u8bd5")',
'*warnings.py:*: UnicodeWarning: This warning*\u6d4b\u8bd5',
'*warnings.py:*: UnicodeWarning: Warning is using unicode non*',
'* 1 passed, 2 warnings*',
])

Expand Down

0 comments on commit 467c526

Please sign in to comment.