Merge remote-tracking branch 'upstream/master' into release-4.3.0

This commit is contained in:
Bruno Oliveira 2019-02-16 14:06:51 +00:00
commit 0395996756
11 changed files with 96 additions and 50 deletions

View File

@ -1,4 +1,3 @@
sudo: false
language: python
dist: xenial
stages:
@ -26,7 +25,7 @@ env:
matrix:
allow_failures:
- python: '3.8-dev'
env: TOXENV=py38
env: TOXENV=py38-xdist
jobs:
include:
@ -34,14 +33,12 @@ jobs:
- env: TOXENV=pypy PYTEST_NO_COVERAGE=1
python: 'pypy-5.4'
dist: trusty
- env: TOXENV=py34
- env: TOXENV=py34-xdist
python: '3.4'
- env: TOXENV=py35
- env: TOXENV=py35-xdist
python: '3.5'
- env: TOXENV=py36
- env: TOXENV=py36-xdist
python: '3.6'
- env: TOXENV=py38
python: '3.8-dev'
- env: TOXENV=py37
- &test-macos
language: generic
@ -50,15 +47,20 @@ jobs:
sudo: required
install:
- python -m pip install --pre tox
env: TOXENV=py27
env: TOXENV=py27-xdist
- <<: *test-macos
env: TOXENV=py37
env: TOXENV=py37-xdist
before_install:
- brew update
- brew upgrade python
- brew unlink python
- brew link python
# Jobs only run via Travis cron jobs (currently daily).
- env: TOXENV=py38-xdist
python: '3.8-dev'
if: type = cron
- stage: baseline
env: TOXENV=py27-pexpect,py27-trial,py27-numpy
- env: TOXENV=py37-xdist

View File

@ -0,0 +1 @@
Fix ``AssertionError`` with collection of broken symlinks with packages.

View File

@ -88,23 +88,30 @@ and if you need to have access to the actual exception info you may use::
the actual exception raised. The main attributes of interest are
``.type``, ``.value`` and ``.traceback``.
.. versionchanged:: 3.0
You can pass a ``match`` keyword parameter to the context-manager to test
that a regular expression matches on the string representation of an exception
(similar to the ``TestCase.assertRaisesRegexp`` method from ``unittest``)::
In the context manager form you may use the keyword argument
``message`` to specify a custom failure message::
import pytest
>>> with raises(ZeroDivisionError, message="Expecting ZeroDivisionError"):
... pass
... Failed: Expecting ZeroDivisionError
def myfunc():
raise ValueError("Exception 123 raised")
If you want to write test code that works on Python 2.4 as well,
you may also use two other ways to test for an expected exception::
def test_match():
with pytest.raises(ValueError, match=r'.* 123 .*'):
myfunc()
The regexp parameter of the ``match`` method is matched with the ``re.search``
function, so in the above example ``match='123'`` would have worked as
well.
There's an alternate form of the ``pytest.raises`` function where you pass
a function that will be executed with the given ``*args`` and ``**kwargs`` and
assert that the given exception is raised::
pytest.raises(ExpectedException, func, *args, **kwargs)
which will execute the specified function with args and kwargs and
assert that the given ``ExpectedException`` is raised. The reporter will
provide you with helpful output in case of failures such as *no
The reporter will provide you with helpful output in case of failures such as *no
exception* or *wrong exception*.
Note that it is also possible to specify a "raises" argument to
@ -121,23 +128,6 @@ exceptions your own code is deliberately raising, whereas using
like documenting unfixed bugs (where the test describes what "should" happen)
or bugs in dependencies.
Also, the context manager form accepts a ``match`` keyword parameter to test
that a regular expression matches on the string representation of an exception
(like the ``TestCase.assertRaisesRegexp`` method from ``unittest``)::
import pytest
def myfunc():
raise ValueError("Exception 123 raised")
def test_match():
with pytest.raises(ValueError, match=r'.* 123 .*'):
myfunc()
The regexp parameter of the ``match`` method is matched with the ``re.search``
function. So in the above example ``match='123'`` would have worked as
well.
.. _`assertwarns`:

View File

@ -25,6 +25,9 @@ Talks and blog postings
- pytest: recommendations, basic packages for testing in Python and Django, Andreu Vallbona, PyconES 2017 (`slides in english <http://talks.apsl.io/testing-pycones-2017/>`_, `video in spanish <https://www.youtube.com/watch?v=K20GeR-lXDk>`_)
- `pytest advanced, Andrew Svetlov (Russian, PyCon Russia, 2016)
<https://www.youtube.com/watch?v=7KgihdKTWY4>`_.
- `Pythonic testing, Igor Starikov (Russian, PyNsk, November 2016)
<https://www.youtube.com/watch?v=_92nfdd5nK8>`_.

View File

@ -618,7 +618,12 @@ class Session(nodes.FSCollector):
yield y
def _collectfile(self, path, handle_dupes=True):
assert path.isfile()
assert path.isfile(), "%r is not a file (isdir=%r, exists=%r, islink=%r)" % (
path,
path.isdir(),
path.exists(),
path.islink(),
)
ihook = self.gethookproxy(path)
if not self.isinitpath(path):
if ihook.pytest_ignore_collect(path=path, config=self.config):

View File

@ -113,11 +113,12 @@ class Node(object):
:raise ValueError: if ``warning`` instance is not a subclass of PytestWarning.
Example usage::
Example usage:
.. code-block:: python
node.warn(PytestWarning("some message"))
"""
from _pytest.warning_types import PytestWarning

View File

@ -599,7 +599,12 @@ class Package(Module):
return proxy
def _collectfile(self, path, handle_dupes=True):
assert path.isfile()
assert path.isfile(), "%r is not a file (isdir=%r, exists=%r, islink=%r)" % (
path,
path.isdir(),
path.exists(),
path.islink(),
)
ihook = self.gethookproxy(path)
if not self.isinitpath(path):
if ihook.pytest_ignore_collect(path=path, config=self.config):
@ -632,7 +637,8 @@ class Package(Module):
pkg_prefixes = set()
for path in this_path.visit(rec=self._recurse, bf=True, sort=True):
# We will visit our own __init__.py file, in which case we skip it.
if path.isfile():
is_file = path.isfile()
if is_file:
if path.basename == "__init__.py" and path.dirpath() == this_path:
continue
@ -643,12 +649,14 @@ class Package(Module):
):
continue
if path.isdir():
if path.join("__init__.py").check(file=1):
pkg_prefixes.add(path)
else:
if is_file:
for x in self._collectfile(path):
yield x
elif not path.isdir():
# Broken symlink or invalid/missing file.
continue
elif path.join("__init__.py").check(file=1):
pkg_prefixes.add(path)
def _get_xunit_setup_teardown(holder, attr_name, param_obj=None):

View File

@ -280,7 +280,9 @@ class TerminalReporter(object):
def write_fspath_result(self, nodeid, res, **markup):
fspath = self.config.rootdir.join(nodeid.split("::")[0])
if fspath != self.currentfspath:
# NOTE: explicitly check for None to work around py bug, and for less
# overhead in general (https://github.com/pytest-dev/py/pull/207).
if self.currentfspath is None or fspath != self.currentfspath:
if self.currentfspath is not None and self._show_progress_info:
self._write_progress_information_filling_space()
self.currentfspath = fspath

View File

@ -31,7 +31,7 @@ class TempPathFactory(object):
# using os.path.abspath() to get absolute path instead of resolve() as it
# does not work the same in all platforms (see #4427)
# Path.absolute() exists, but it is not public (see https://bugs.python.org/issue25012)
convert=attr.converters.optional(
converter=attr.converters.optional(
lambda p: Path(os.path.abspath(six.text_type(p)))
)
)

View File

@ -1308,10 +1308,17 @@ class TestEarlyRewriteBailout(object):
@pytest.mark.skipif(
sys.platform.startswith("win32"), reason="cannot remove cwd on Windows"
)
def test_cwd_changed(self, testdir):
def test_cwd_changed(self, testdir, monkeypatch):
# Setup conditions for py's fspath trying to import pathlib on py34
# always (previously triggered via xdist only).
# Ref: https://github.com/pytest-dev/py/pull/207
monkeypatch.setattr(sys, "path", [""] + sys.path)
if "pathlib" in sys.modules:
del sys.modules["pathlib"]
testdir.makepyfile(
**{
"test_bar.py": """
"test_setup_nonexisting_cwd.py": """
import os
import shutil
import tempfile
@ -1320,7 +1327,7 @@ class TestEarlyRewriteBailout(object):
os.chdir(d)
shutil.rmtree(d)
""",
"test_foo.py": """
"test_test.py": """
def test():
pass
""",

View File

@ -1206,3 +1206,30 @@ def test_collect_pkg_init_and_file_in_args(testdir):
"*2 passed in*",
]
)
@pytest.mark.skipif(
not hasattr(py.path.local, "mksymlinkto"),
reason="symlink not available on this platform",
)
@pytest.mark.parametrize("use_pkg", (True, False))
def test_collect_sub_with_symlinks(use_pkg, testdir):
sub = testdir.mkdir("sub")
if use_pkg:
sub.ensure("__init__.py")
sub.ensure("test_file.py").write("def test_file(): pass")
# Create a broken symlink.
sub.join("test_broken.py").mksymlinkto("test_doesnotexist.py")
# Symlink that gets collected.
sub.join("test_symlink.py").mksymlinkto("test_file.py")
result = testdir.runpytest("-v", str(sub))
result.stdout.fnmatch_lines(
[
"sub/test_file.py::test_file PASSED*",
"sub/test_symlink.py::test_file PASSED*",
"*2 passed in*",
]
)