Merge pull request #3428 from nicoddemus/merge-master-into-features

Merge master into features
This commit is contained in:
Ronny Pfannschmidt 2018-04-25 14:04:41 +02:00 committed by GitHub
commit 5ba0663827
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
26 changed files with 201 additions and 61 deletions

View File

@ -8,6 +8,58 @@
.. towncrier release notes start
Pytest 3.5.1 (2018-04-23)
=========================
Bug Fixes
---------
- Reset ``sys.last_type``, ``sys.last_value`` and ``sys.last_traceback`` before
each test executes. Those attributes are added by pytest during the test run
to aid debugging, but were never reset so they would create a leaking
reference to the last failing test's frame which in turn could never be
reclaimed by the garbage collector. (`#2798
<https://github.com/pytest-dev/pytest/issues/2798>`_)
- ``pytest.raises`` now raises ``TypeError`` when receiving an unknown keyword
argument. (`#3348 <https://github.com/pytest-dev/pytest/issues/3348>`_)
- ``pytest.raises`` now works with exception classes that look like iterables.
(`#3372 <https://github.com/pytest-dev/pytest/issues/3372>`_)
Improved Documentation
----------------------
- Fix typo in ``caplog`` fixture documentation, which incorrectly identified
certain attributes as methods. (`#3406
<https://github.com/pytest-dev/pytest/issues/3406>`_)
Trivial/Internal Changes
------------------------
- Added a more indicative error message when parametrizing a function whose
argument takes a default value. (`#3221
<https://github.com/pytest-dev/pytest/issues/3221>`_)
- Remove internal ``_pytest.terminal.flatten`` function in favor of
``more_itertools.collapse``. (`#3330
<https://github.com/pytest-dev/pytest/issues/3330>`_)
- Import some modules from ``collections.abc`` instead of ``collections`` as
the former modules trigger ``DeprecationWarning`` in Python 3.7. (`#3339
<https://github.com/pytest-dev/pytest/issues/3339>`_)
- record_property is no longer experimental, removing the warnings was
forgotten. (`#3360 <https://github.com/pytest-dev/pytest/issues/3360>`_)
- Mention in documentation and CLI help that fixtures with leading ``_`` are
printed by ``pytest --fixtures`` only if the ``-v`` option is added. (`#3398
<https://github.com/pytest-dev/pytest/issues/3398>`_)
Pytest 3.5.0 (2018-03-21)
=========================

View File

@ -48,8 +48,7 @@ fix the bug itself.
Fix bugs
--------
Look through the GitHub issues for bugs. Here is a filter you can use:
https://github.com/pytest-dev/pytest/labels/type%3A%20bug
Look through the `GitHub issues for bugs <https://github.com/pytest-dev/pytest/labels/type:%20bug>`_.
:ref:`Talk <contact>` to developers to find out how you can fix specific bugs.
@ -60,8 +59,7 @@ Don't forget to check the issue trackers of your favourite plugins, too!
Implement features
------------------
Look through the GitHub issues for enhancements. Here is a filter you can use:
https://github.com/pytest-dev/pytest/labels/enhancement
Look through the `GitHub issues for enhancements <https://github.com/pytest-dev/pytest/labels/type:%20enhancement>`_.
:ref:`Talk <contact>` to developers to find out how you can implement specific
features.

View File

@ -135,6 +135,14 @@ def getfuncargnames(function, is_method=False, cls=None):
return arg_names
def get_default_arg_names(function):
# Note: this code intentionally mirrors the code at the beginning of getfuncargnames,
# to get the arguments which were excluded from its result because they had default values
return tuple(p.name for p in signature(function).parameters.values()
if p.kind in (Parameter.POSITIONAL_OR_KEYWORD, Parameter.KEYWORD_ONLY) and
p.default is not Parameter.empty)
if _PY3:
STRING_TYPES = bytes, str
UNICODE_TYPES = str,

View File

@ -138,7 +138,8 @@ def showhelp(config):
tw.line("to see available markers type: pytest --markers")
tw.line("to see available fixtures type: pytest --fixtures")
tw.line("(shown according to specified file_or_dir or current dir "
"if not specified)")
"if not specified; fixtures with leading '_' are only shown "
"with the '-v' option")
for warningreport in reporter.stats.get('warnings', []):
tw.line("warning : " + warningreport.message, red=True)

View File

@ -289,9 +289,9 @@ def caplog(request):
Captured logs are available through the following methods::
* caplog.text() -> string containing formatted log output
* caplog.records() -> list of logging.LogRecord instances
* caplog.record_tuples() -> list of (logger_name, level, message) tuples
* caplog.text -> string containing formatted log output
* caplog.records -> list of logging.LogRecord instances
* caplog.record_tuples -> list of (logger_name, level, message) tuples
* caplog.clear() -> clear captured records and formatted log output string
"""
result = LogCaptureFixture(request.node)

View File

@ -333,7 +333,7 @@ class Session(nodes.FSCollector):
def gethookproxy(self, fspath):
# check if we have the common case of running
# hooks with all conftest.py filesall conftest.py
# hooks with all conftest.py files
pm = self.config.pluginmanager
my_conftestmodules = pm._getconftestmodules(fspath)
remove_mods = pm._conftest_plugins.difference(my_conftestmodules)

View File

@ -25,7 +25,7 @@ from _pytest.compat import (
isclass, isfunction, is_generator, ascii_escaped,
REGEX_TYPE, STRING_TYPES, NoneType, NOTSET,
get_real_func, getfslineno, safe_getattr,
safe_str, getlocation, enum,
safe_str, getlocation, enum, get_default_arg_names
)
from _pytest.outcomes import fail
from _pytest.mark.structures import transfer_markers, get_unpacked_marks
@ -75,7 +75,8 @@ def pytest_addoption(parser):
group = parser.getgroup("general")
group.addoption('--fixtures', '--funcargs',
action="store_true", dest="showfixtures", default=False,
help="show available fixtures, sorted by plugin appearance")
help="show available fixtures, sorted by plugin appearance "
"(fixtures with leading '_' are only shown with '-v')")
group.addoption(
'--fixtures-per-test',
action="store_true",
@ -808,6 +809,7 @@ class Metafunc(fixtures.FuncargnamesCompatAttr):
argnames, parameters = ParameterSet._for_parametrize(
argnames, argvalues, self.function, self.config)
del argvalues
default_arg_names = set(get_default_arg_names(self.function))
if scope is None:
scope = _find_parametrized_scope(argnames, self._arg2fixturedefs, indirect)
@ -816,6 +818,9 @@ class Metafunc(fixtures.FuncargnamesCompatAttr):
valtypes = {}
for arg in argnames:
if arg not in self.fixturenames:
if arg in default_arg_names:
raise ValueError("%r already takes an argument %r with a default value" % (self.function, arg))
else:
if isinstance(indirect, (tuple, list)):
name = 'fixture' if arg in indirect else 'argument'
else:

View File

@ -105,6 +105,7 @@ def pytest_runtest_setup(item):
def pytest_runtest_call(item):
_update_current_test_var(item, 'call')
sys.last_type, sys.last_value, sys.last_traceback = (None, None, None)
try:
item.runtest()
except Exception:
@ -114,7 +115,7 @@ def pytest_runtest_call(item):
sys.last_type = type
sys.last_value = value
sys.last_traceback = tb
del tb # Get rid of it in this namespace
del type, value, tb # Get rid of these in this frame
raise

View File

@ -1 +0,0 @@
Remove internal ``_pytest.terminal.flatten`` function in favor of ``more_itertools.collapse``.

View File

@ -1 +0,0 @@
Import some modules from ``collections`` instead of ``collections.abc`` as the former modules trigger ``DeprecationWarning`` in Python 3.7.

View File

@ -1 +0,0 @@
``pytest.raises`` now raises ``TypeError`` when receiving an unknown keyword argument.

View File

@ -1,2 +0,0 @@
record_property is no longer experimental, removing the warnings was forgotten.

View File

@ -1 +0,0 @@
``pytest.raises`` now works with exception classes that look like iterables.

View File

@ -6,6 +6,7 @@ Release announcements
:maxdepth: 2
release-3.5.1
release-3.5.0
release-3.4.2
release-3.4.1

View File

@ -0,0 +1,30 @@
pytest-3.5.1
=======================================
pytest 3.5.1 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:
* Brian Maissy
* Bruno Oliveira
* Darren Burns
* David Chudzicki
* Floris Bruynooghe
* Holger Kohr
* Irmen de Jong
* Jeffrey Rackauckas
* Rachel Kogan
* Ronny Pfannschmidt
* Stefan Scherfke
* Tim Strazny
* Семён Марьясин
Happy testing,
The pytest Development Team

View File

@ -12,7 +12,7 @@ For information on plugin hooks and objects, see :ref:`plugins`.
For information on the ``pytest.mark`` mechanism, see :ref:`mark`.
For information about fixtures, see :ref:`fixtures`. To see a complete list of available fixtures, type::
For information about fixtures, see :ref:`fixtures`. To see a complete list of available fixtures (add ``-v`` to also see fixtures with leading ``_``), type ::
$ pytest -q --fixtures
cache
@ -77,9 +77,9 @@ For information about fixtures, see :ref:`fixtures`. To see a complete list of a
Captured logs are available through the following methods::
* caplog.text() -> string containing formatted log output
* caplog.records() -> list of logging.LogRecord instances
* caplog.record_tuples() -> list of (logger_name, level, message) tuples
* caplog.text -> string containing formatted log output
* caplog.records -> list of logging.LogRecord instances
* caplog.record_tuples -> list of (logger_name, level, message) tuples
* caplog.clear() -> clear captured records and formatted log output string
monkeypatch
The returned ``monkeypatch`` fixture provides these

View File

@ -358,7 +358,7 @@ get on the terminal - we are working on that)::
> int(s)
E ValueError: invalid literal for int() with base 10: 'qwe'
<0-codegen $PYTHON_PREFIX/lib/python3.5/site-packages/_pytest/python_api.py:613>:1: ValueError
<0-codegen $PYTHON_PREFIX/lib/python3.5/site-packages/_pytest/python_api.py:615>:1: ValueError
______________________ TestRaises.test_raises_doesnt _______________________
self = <failure_demo.TestRaises object at 0xdeadbeef>

View File

@ -102,7 +102,7 @@ the command line arguments before they get processed:
# content of conftest.py
import sys
def pytest_cmdline_preparse(args):
def pytest_load_initial_conftests(args):
if 'xdist' in sys.modules: # pytest-xdist plugin
import multiprocessing
num = max(multiprocessing.cpu_count() / 2, 1)

View File

@ -111,11 +111,11 @@ with a list of available function arguments.
.. note::
You can always issue::
You can always issue ::
pytest --fixtures test_simplefactory.py
to see available fixtures.
to see available fixtures (fixtures with leading ``_`` are only shown if you add the ``-v`` option).
Fixtures: a prime example of dependency injection
---------------------------------------------------

View File

@ -166,6 +166,8 @@ Find out what kind of builtin :ref:`pytest fixtures <fixtures>` exist with the c
pytest --fixtures # shows builtin and custom fixtures
Note that this command omits fixtures with leading ``_`` unless the ``-v`` option is added.
Continue reading
-------------------------------------

View File

@ -23,7 +23,7 @@ command line options
``--full-trace``
don't cut any tracebacks (default is to cut).
``--fixtures``
show available function arguments, sorted by plugin
show available fixtures, sorted by plugin appearance (fixtures with leading ``_`` are only shown with '-v')
Start improving this plugin in 30 seconds
=========================================

View File

@ -88,6 +88,10 @@ def main():
'write_to': '_pytest/_version.py',
},
url='http://pytest.org',
project_urls={
'Source': 'https://github.com/pytest-dev/pytest',
'Tracker': 'https://github.com/pytest-dev/pytest/issues',
},
license='MIT license',
platforms=['unix', 'linux', 'osx', 'cygwin', 'win32'],
author=(

View File

@ -988,3 +988,33 @@ def test_fixture_order_respects_scope(testdir):
''')
result = testdir.runpytest()
assert result.ret == 0
def test_frame_leak_on_failing_test(testdir):
"""pytest would leak garbage referencing the frames of tests that failed that could never be reclaimed (#2798)
Unfortunately it was not possible to remove the actual circles because most of them
are made of traceback objects which cannot be weakly referenced. Those objects at least
can be eventually claimed by the garbage collector.
"""
testdir.makepyfile('''
import gc
import weakref
class Obj:
pass
ref = None
def test1():
obj = Obj()
global ref
ref = weakref.ref(obj)
assert 0
def test2():
gc.collect()
assert ref() is None
''')
result = testdir.runpytest_subprocess()
result.stdout.fnmatch_lines(['*1 failed, 1 passed in*'])

View File

@ -622,6 +622,19 @@ class TestMetafunc(object):
"*uses no argument 'y'*",
])
def test_parametrize_gives_indicative_error_on_function_with_default_argument(self, testdir):
testdir.makepyfile("""
import pytest
@pytest.mark.parametrize('x, y', [('a', 'b')])
def test_simple(x, y=1):
assert len(x) == 1
""")
result = testdir.runpytest("--collect-only")
result.stdout.fnmatch_lines([
"*already takes an argument 'y' with a default value",
])
def test_addcalls_and_parametrize_indirect(self):
def func(x, y):
pass

View File

@ -719,18 +719,20 @@ def test_makereport_getsource_dynamic_code(testdir, monkeypatch):
result.stdout.fnmatch_lines(["*test_fix*", "*fixture*'missing'*not found*"])
def test_store_except_info_on_eror():
def test_store_except_info_on_error():
""" Test that upon test failure, the exception info is stored on
sys.last_traceback and friends.
"""
# Simulate item that raises a specific exception
class ItemThatRaises(object):
# Simulate item that might raise a specific exception, depending on `raise_error` class var
class ItemMightRaise(object):
nodeid = 'item_that_raises'
raise_error = True
def runtest(self):
if self.raise_error:
raise IndexError('TEST')
try:
runner.pytest_runtest_call(ItemThatRaises())
runner.pytest_runtest_call(ItemMightRaise())
except IndexError:
pass
# Check that exception info is stored on sys
@ -738,6 +740,13 @@ def test_store_except_info_on_eror():
assert sys.last_value.args[0] == 'TEST'
assert sys.last_traceback
# The next run should clear the exception info stored by the previous run
ItemMightRaise.raise_error = False
runner.pytest_runtest_call(ItemMightRaise())
assert sys.last_type is None
assert sys.last_value is None
assert sys.last_traceback is None
def test_current_test_env_var(testdir, monkeypatch):
pytest_current_test_vars = []

36
tox.ini
View File

@ -13,7 +13,7 @@ envlist =
{py27,py36}-{pexpect,xdist,trial,numpy,pluggymaster}
py27-nobyte
doctesting
py35-freeze
py36-freeze
docs
[testenv]
@ -56,12 +56,11 @@ deps =
hypothesis>=3.5.2
changedir=testing
commands =
pytest -n1 -ra {posargs:.}
pytest -n8 -ra {posargs:.}
[testenv:py36-xdist]
deps = {[testenv:py27-xdist]deps}
commands =
pytest -n3 -ra {posargs:testing}
commands = {[testenv:py27-xdist]commands}
[testenv:py27-pexpect]
changedir = testing
@ -71,11 +70,10 @@ commands =
pytest -ra test_pdb.py test_terminal.py test_unittest.py
[testenv:py36-pexpect]
changedir = testing
platform = linux|darwin
changedir = {[testenv:py27-pexpect]changedir}
platform = {[testenv:py27-pexpect]platform}
deps = {[testenv:py27-pexpect]deps}
commands =
pytest -ra test_pdb.py test_terminal.py test_unittest.py
commands = {[testenv:py27-pexpect]commands}
[testenv:py27-nobyte]
deps =
@ -95,18 +93,16 @@ commands =
[testenv:py36-trial]
deps = {[testenv:py27-trial]deps}
commands =
pytest -ra {posargs:testing/test_unittest.py}
commands = {[testenv:py27-trial]commands}
[testenv:py27-numpy]
deps=numpy
deps = numpy
commands=
pytest -ra {posargs:testing/python/approx.py}
[testenv:py36-numpy]
deps=numpy
commands=
pytest -ra {posargs:testing/python/approx.py}
deps = {[testenv:py27-numpy]deps}
commands = {[testenv:py27-numpy]commands}
[testenv:py27-pluggymaster]
setenv=
@ -115,12 +111,9 @@ deps =
{[testenv]deps}
git+https://github.com/pytest-dev/pluggy.git@master
[testenv:py35-pluggymaster]
setenv=
_PYTEST_SETUP_SKIP_PLUGGY_DEP=1
deps =
{[testenv:py27-pluggymaster]deps}
git+https://github.com/pytest-dev/pluggy.git@master
[testenv:py36-pluggymaster]
setenv = {[testenv:py27-pluggymaster]setenv}
deps = {[testenv:py27-pluggymaster]deps}
[testenv:docs]
skipsdist = True
@ -176,7 +169,7 @@ changedir = testing
commands =
{envpython} {envbindir}/py.test-jython -ra {posargs}
[testenv:py35-freeze]
[testenv:py36-freeze]
changedir = testing/freeze
deps = pyinstaller
commands =
@ -199,7 +192,6 @@ commands =
[pytest]
minversion = 2.0
plugins = pytester
#--pyargs --doctest-modules --ignore=.tox
addopts = -ra -p pytester --ignore=testing/cx_freeze
rsyncdirs = tox.ini pytest.py _pytest testing
python_files = test_*.py *_test.py testing/*/*.py