Merge pull request #6614 from blueyed/release-5.3.5

Preparing release version 5.3.5
This commit is contained in:
Daniel Hahler 2020-01-29 17:57:05 +01:00 committed by GitHub
commit 1b3eb4184d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 67 additions and 34 deletions

View File

@ -6,6 +6,7 @@ Release announcements
:maxdepth: 2 :maxdepth: 2
release-5.3.5
release-5.3.4 release-5.3.4
release-5.3.3 release-5.3.3
release-5.3.2 release-5.3.2

View File

@ -0,0 +1,19 @@
pytest-5.3.5
=======================================
pytest 5.3.5 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 https://docs.pytest.org/en/latest/changelog.html.
Thanks to all who contributed to this release, among them:
* Daniel Hahler
* Ran Benita
Happy testing,
The pytest Development Team

View File

@ -28,6 +28,15 @@ with advance notice in the **Deprecations** section of releases.
.. towncrier release notes start .. towncrier release notes start
pytest 5.3.5 (2020-01-29)
=========================
Bug Fixes
---------
- `#6517 <https://github.com/pytest-dev/pytest/issues/6517>`_: Fix regression in pytest 5.3.4 causing an INTERNALERROR due to a wrong assertion.
pytest 5.3.4 (2020-01-20) pytest 5.3.4 (2020-01-20)
========================= =========================

View File

@ -475,11 +475,8 @@ Running it results in some skips if we don't have all the python interpreters in
.. code-block:: pytest .. code-block:: pytest
. $ pytest -rs -q multipython.py . $ pytest -rs -q multipython.py
ssssssssssss...ssssssssssss [100%] ........................... [100%]
========================= short test summary info ========================== 27 passed in 0.12s
SKIPPED [12] $REGENDOC_TMPDIR/CWD/multipython.py:29: 'python3.5' not found
SKIPPED [12] $REGENDOC_TMPDIR/CWD/multipython.py:29: 'python3.7' not found
3 passed, 24 skipped in 0.12s
Indirect parametrization of optional implementations/imports Indirect parametrization of optional implementations/imports
-------------------------------------------------------------------- --------------------------------------------------------------------

View File

@ -436,7 +436,7 @@ Here is a nice run of several failures and how ``pytest`` presents things:
items = [1, 2, 3] items = [1, 2, 3]
print("items is {!r}".format(items)) print("items is {!r}".format(items))
> a, b = items.pop() > a, b = items.pop()
E TypeError: 'int' object is not iterable E TypeError: cannot unpack non-iterable int object
failure_demo.py:181: TypeError failure_demo.py:181: TypeError
--------------------------- Captured stdout call --------------------------- --------------------------- Captured stdout call ---------------------------
@ -516,7 +516,7 @@ Here is a nice run of several failures and how ``pytest`` presents things:
def test_z2_type_error(self): def test_z2_type_error(self):
items = 3 items = 3
> a, b = items > a, b = items
E TypeError: 'int' object is not iterable E TypeError: cannot unpack non-iterable int object
failure_demo.py:222: TypeError failure_demo.py:222: TypeError
______________________ TestMoreErrors.test_startswith ______________________ ______________________ TestMoreErrors.test_startswith ______________________

View File

@ -443,7 +443,7 @@ Now we can profile which test functions execute the slowest:
========================= slowest 3 test durations ========================= ========================= slowest 3 test durations =========================
0.30s call test_some_are_slow.py::test_funcslow2 0.30s call test_some_are_slow.py::test_funcslow2
0.20s call test_some_are_slow.py::test_funcslow1 0.20s call test_some_are_slow.py::test_funcslow1
0.11s call test_some_are_slow.py::test_funcfast 0.10s call test_some_are_slow.py::test_funcfast
============================ 3 passed in 0.12s ============================= ============================ 3 passed in 0.12s =============================
incremental testing - test steps incremental testing - test steps

View File

@ -28,7 +28,7 @@ Install ``pytest``
.. code-block:: bash .. code-block:: bash
$ pytest --version $ pytest --version
This is pytest version 5.x.y, imported from $PYTHON_PREFIX/lib/python3.6/site-packages/pytest/__init__.py This is pytest version 5.x.y, imported from $PYTHON_PREFIX/lib/python3.8/site-packages/pytest/__init__.py
.. _`simpletest`: .. _`simpletest`:

View File

@ -82,8 +82,8 @@ class Parser:
self.optparser = self._getparser() self.optparser = self._getparser()
try_argcomplete(self.optparser) try_argcomplete(self.optparser)
strargs = [str(x) if isinstance(x, py.path.local) else x for x in args] args = [str(x) if isinstance(x, py.path.local) else x for x in args]
return self.optparser.parse_args(strargs, namespace=namespace) return self.optparser.parse_args(args, namespace=namespace)
def _getparser(self) -> "MyOptionParser": def _getparser(self) -> "MyOptionParser":
from _pytest._argcomplete import filescompleter from _pytest._argcomplete import filescompleter
@ -124,8 +124,8 @@ class Parser:
the remaining arguments unknown at this point. the remaining arguments unknown at this point.
""" """
optparser = self._getparser() optparser = self._getparser()
strargs = [str(x) if isinstance(x, py.path.local) else x for x in args] args = [str(x) if isinstance(x, py.path.local) else x for x in args]
return optparser.parse_known_args(strargs, namespace=namespace) return optparser.parse_known_args(args, namespace=namespace)
def addini(self, name, help, type=None, default=None): def addini(self, name, help, type=None, default=None):
""" register an ini-file option. """ register an ini-file option.

View File

@ -1,9 +1,6 @@
import os import os
from typing import Any
from typing import Iterable
from typing import List from typing import List
from typing import Optional from typing import Optional
from typing import Tuple
import py import py
@ -63,7 +60,7 @@ def getcfg(args, config=None):
return None, None, None return None, None, None
def get_common_ancestor(paths: Iterable[py.path.local]) -> py.path.local: def get_common_ancestor(paths):
common_ancestor = None common_ancestor = None
for path in paths: for path in paths:
if not path.exists(): if not path.exists():
@ -116,7 +113,7 @@ def determine_setup(
args: List[str], args: List[str],
rootdir_cmd_arg: Optional[str] = None, rootdir_cmd_arg: Optional[str] = None,
config: Optional["Config"] = None, config: Optional["Config"] = None,
) -> Tuple[py.path.local, Optional[str], Any]: ):
dirs = get_dirs_from_args(args) dirs = get_dirs_from_args(args)
if inifile: if inifile:
iniconfig = py.iniconfig.IniConfig(inifile) iniconfig = py.iniconfig.IniConfig(inifile)

View File

@ -308,7 +308,7 @@ class DoctestItem(pytest.Item):
else: else:
return super().repr_failure(excinfo) return super().repr_failure(excinfo)
def reportinfo(self) -> Tuple[py.path.local, int, str]: def reportinfo(self) -> Tuple[str, int, str]:
return self.fspath, self.dtest.lineno, "[doctest] %s" % self.name return self.fspath, self.dtest.lineno, "[doctest] %s" % self.name

View File

@ -351,7 +351,7 @@ class FixtureRequest:
self.fixturename = None self.fixturename = None
#: Scope string, one of "function", "class", "module", "session" #: Scope string, one of "function", "class", "module", "session"
self.scope = "function" self.scope = "function"
self._fixture_defs = {} # type: Dict[str, FixtureDef] self._fixture_defs = {} # argname -> FixtureDef
fixtureinfo = pyfuncitem._fixtureinfo fixtureinfo = pyfuncitem._fixtureinfo
self._arg2fixturedefs = fixtureinfo.name2fixturedefs.copy() self._arg2fixturedefs = fixtureinfo.name2fixturedefs.copy()
self._arg2index = {} self._arg2index = {}
@ -426,8 +426,7 @@ class FixtureRequest:
@scopeproperty() @scopeproperty()
def fspath(self) -> py.path.local: def fspath(self) -> py.path.local:
""" the file system path of the test module which collected this test. """ """ the file system path of the test module which collected this test. """
# TODO: Remove ignore once _pyfuncitem is properly typed. return self._pyfuncitem.fspath
return self._pyfuncitem.fspath # type: ignore
@property @property
def keywords(self): def keywords(self):
@ -550,9 +549,7 @@ class FixtureRequest:
source_lineno = frameinfo.lineno source_lineno = frameinfo.lineno
source_path = py.path.local(source_path) source_path = py.path.local(source_path)
if source_path.relto(funcitem.config.rootdir): if source_path.relto(funcitem.config.rootdir):
source_path_str = source_path.relto(funcitem.config.rootdir) source_path = source_path.relto(funcitem.config.rootdir)
else:
source_path_str = str(source_path)
msg = ( msg = (
"The requested fixture has no parameter defined for test:\n" "The requested fixture has no parameter defined for test:\n"
" {}\n\n" " {}\n\n"
@ -561,7 +558,7 @@ class FixtureRequest:
funcitem.nodeid, funcitem.nodeid,
fixturedef.argname, fixturedef.argname,
getlocation(fixturedef.func, funcitem.config.rootdir), getlocation(fixturedef.func, funcitem.config.rootdir),
source_path_str, source_path,
source_lineno, source_lineno,
) )
) )

View File

@ -367,9 +367,9 @@ class Failed(Exception):
@attr.s @attr.s
class _bestrelpath_cache(dict): class _bestrelpath_cache(dict):
path = attr.ib(type=py.path.local) path = attr.ib()
def __missing__(self, path: py.path.local) -> str: def __missing__(self, path: str) -> str:
r = self.path.bestrelpath(path) # type: str r = self.path.bestrelpath(path) # type: str
self[path] = r self[path] = r
return r return r
@ -399,7 +399,7 @@ class Session(nodes.FSCollector):
self._node_cache = {} self._node_cache = {}
self._bestrelpathcache = _bestrelpath_cache( self._bestrelpathcache = _bestrelpath_cache(
config.rootdir config.rootdir
) # type: Dict[py.path.local, str] ) # type: Dict[str, str]
# Dirnames of pkgs with dunder-init files. # Dirnames of pkgs with dunder-init files.
self._pkg_roots = {} self._pkg_roots = {}
@ -414,7 +414,7 @@ class Session(nodes.FSCollector):
self.testscollected, self.testscollected,
) )
def _node_location_to_relpath(self, node_path: py.path.local) -> str: def _node_location_to_relpath(self, node_path: str) -> str:
# bestrelpath is a quite slow function # bestrelpath is a quite slow function
return self._bestrelpathcache[node_path] return self._bestrelpathcache[node_path]

View File

@ -462,7 +462,6 @@ class Item(Node):
@cached_property @cached_property
def location(self) -> Tuple[str, Optional[int], str]: def location(self) -> Tuple[str, Optional[int], str]:
location = self.reportinfo() location = self.reportinfo()
assert isinstance(location[0], py.path.local), location[0]
fspath = self.session._node_location_to_relpath(location[0]) fspath = self.session._node_location_to_relpath(location[0])
assert type(location[2]) is str assert type(location[2]) is str
return (fspath, location[1], location[2]) return (fspath, location[1], location[2])

View File

@ -1018,10 +1018,10 @@ class TestReportInfo:
def test_itemreport_reportinfo(self, testdir): def test_itemreport_reportinfo(self, testdir):
testdir.makeconftest( testdir.makeconftest(
""" """
import pytest, py import pytest
class MyFunction(pytest.Function): class MyFunction(pytest.Function):
def reportinfo(self): def reportinfo(self):
return py.path.local("foo"), 42, "custom" return "ABCDE", 42, "custom"
def pytest_pycollect_makeitem(collector, name, obj): def pytest_pycollect_makeitem(collector, name, obj):
if name == "test_func": if name == "test_func":
return MyFunction(name, parent=collector) return MyFunction(name, parent=collector)
@ -1029,7 +1029,7 @@ class TestReportInfo:
) )
item = testdir.getitem("def test_func(): pass") item = testdir.getitem("def test_func(): pass")
item.config.pluginmanager.getplugin("runner") item.config.pluginmanager.getplugin("runner")
assert item.location == ("foo", 42, "custom") assert item.location == ("ABCDE", 42, "custom")
def test_func_reportinfo(self, testdir): def test_func_reportinfo(self, testdir):
item = testdir.getitem("def test_func(): pass") item = testdir.getitem("def test_func(): pass")

View File

@ -375,3 +375,17 @@ def test_skip_test_with_unicode(testdir):
) )
result = testdir.runpytest() result = testdir.runpytest()
result.stdout.fnmatch_lines(["* 1 skipped *"]) result.stdout.fnmatch_lines(["* 1 skipped *"])
def test_issue_6517(testdir):
testdir.makepyfile(
"""
from nose.tools import raises
@raises(RuntimeError)
def test_fail_without_tcp():
raise RuntimeError
"""
)
result = testdir.runpytest()
result.stdout.fnmatch_lines(["* 1 passed *"])