Merge remote-tracking branch 'upstream/master' into features
This commit is contained in:
commit
467c526307
|
@ -8,6 +8,38 @@
|
||||||
|
|
||||||
.. towncrier release notes start
|
.. 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)
|
Pytest 3.1.1 (2017-05-30)
|
||||||
=========================
|
=========================
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@ import sys
|
||||||
from inspect import CO_VARARGS, CO_VARKEYWORDS
|
from inspect import CO_VARARGS, CO_VARKEYWORDS
|
||||||
import re
|
import re
|
||||||
from weakref import ref
|
from weakref import ref
|
||||||
from _pytest.compat import _PY2, _PY3, PY35
|
from _pytest.compat import _PY2, _PY3, PY35, safe_str
|
||||||
|
|
||||||
import py
|
import py
|
||||||
builtin_repr = repr
|
builtin_repr = repr
|
||||||
|
@ -602,21 +602,48 @@ class FormattedExcinfo(object):
|
||||||
traceback = excinfo.traceback
|
traceback = excinfo.traceback
|
||||||
if self.tbfilter:
|
if self.tbfilter:
|
||||||
traceback = traceback.filter()
|
traceback = traceback.filter()
|
||||||
recursionindex = None
|
|
||||||
if is_recursion_error(excinfo):
|
if is_recursion_error(excinfo):
|
||||||
recursionindex = traceback.recursionindex()
|
traceback, extraline = self._truncate_recursive_traceback(traceback)
|
||||||
|
else:
|
||||||
|
extraline = None
|
||||||
|
|
||||||
last = traceback[-1]
|
last = traceback[-1]
|
||||||
entries = []
|
entries = []
|
||||||
extraline = None
|
|
||||||
for index, entry in enumerate(traceback):
|
for index, entry in enumerate(traceback):
|
||||||
einfo = (last == entry) and excinfo or None
|
einfo = (last == entry) and excinfo or None
|
||||||
reprentry = self.repr_traceback_entry(entry, einfo)
|
reprentry = self.repr_traceback_entry(entry, einfo)
|
||||||
entries.append(reprentry)
|
entries.append(reprentry)
|
||||||
if index == recursionindex:
|
|
||||||
extraline = "!!! Recursion detected (same locals & position)"
|
|
||||||
break
|
|
||||||
return ReprTraceback(entries, extraline, style=self.style)
|
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):
|
def repr_excinfo(self, excinfo):
|
||||||
if _PY2:
|
if _PY2:
|
||||||
|
|
|
@ -66,8 +66,9 @@ def catch_warnings_for_item(item):
|
||||||
unicode_warning = False
|
unicode_warning = False
|
||||||
|
|
||||||
if compat._PY2 and any(isinstance(m, compat.UNICODE_TYPES) for m in warn_msg.args):
|
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]
|
new_args = [compat.safe_str(m) for m in warn_msg.args]
|
||||||
unicode_warning = True
|
unicode_warning = warn_msg.args != new_args
|
||||||
|
warn_msg.args = new_args
|
||||||
|
|
||||||
msg = warnings.formatwarning(
|
msg = warnings.formatwarning(
|
||||||
warn_msg, warning.category,
|
warn_msg, warning.category,
|
||||||
|
@ -76,8 +77,8 @@ def catch_warnings_for_item(item):
|
||||||
|
|
||||||
if unicode_warning:
|
if unicode_warning:
|
||||||
warnings.warn(
|
warnings.warn(
|
||||||
"This warning %s is broken as it's message is not a str instance"
|
"Warning is using unicode non convertible to ascii, "
|
||||||
"(after all this is a stdlib problem workaround)" % msg,
|
"converting to a safe representation:\n %s" % msg,
|
||||||
UnicodeWarning)
|
UnicodeWarning)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,2 +0,0 @@
|
||||||
Required options added via ``pytest_addoption`` will no longer prevent
|
|
||||||
using --help without passing them.
|
|
|
@ -1 +0,0 @@
|
||||||
Respect ``python_files`` in assertion rewriting.
|
|
|
@ -1 +0,0 @@
|
||||||
Fix internal API links to ``pluggy`` objects.
|
|
|
@ -1,3 +0,0 @@
|
||||||
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.
|
|
|
@ -1 +0,0 @@
|
||||||
Make it clear that ``pytest.xfail`` stops test execution at the calling point and improve overall flow of the ``skipping`` docs.
|
|
|
@ -6,6 +6,7 @@ Release announcements
|
||||||
:maxdepth: 2
|
:maxdepth: 2
|
||||||
|
|
||||||
|
|
||||||
|
release-3.1.2
|
||||||
release-3.1.1
|
release-3.1.1
|
||||||
release-3.1.0
|
release-3.1.0
|
||||||
release-3.0.7
|
release-3.0.7
|
||||||
|
|
|
@ -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
|
|
@ -322,8 +322,6 @@ Running it with the report-on-xfail option gives this output::
|
||||||
|
|
||||||
======= 7 xfailed in 0.12 seconds ========
|
======= 7 xfailed in 0.12 seconds ========
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
.. _`skip/xfail with parametrize`:
|
.. _`skip/xfail with parametrize`:
|
||||||
|
|
||||||
Skip/xfail with parametrize
|
Skip/xfail with parametrize
|
||||||
|
|
|
@ -1140,3 +1140,36 @@ def test_cwd_deleted(testdir):
|
||||||
result = testdir.runpytest()
|
result = testdir.runpytest()
|
||||||
result.stdout.fnmatch_lines(['* 1 failed in *'])
|
result.stdout.fnmatch_lines(['* 1 failed in *'])
|
||||||
assert 'INTERNALERROR' not in result.stdout.str() + result.stderr.str()
|
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*',
|
||||||
|
])
|
||||||
|
|
|
@ -161,7 +161,7 @@ def test_py2_unicode(testdir, pyfile_with_warnings):
|
||||||
|
|
||||||
'*test_py2_unicode.py:8: UserWarning: \u6d4b\u8bd5',
|
'*test_py2_unicode.py:8: UserWarning: \u6d4b\u8bd5',
|
||||||
'*warnings.warn(u"\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*',
|
'* 1 passed, 2 warnings*',
|
||||||
])
|
])
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue