Merge remote-tracking branch 'upstream/master' into release-4.3.0
This commit is contained in:
commit
0395996756
20
.travis.yml
20
.travis.yml
|
@ -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
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
Fix ``AssertionError`` with collection of broken symlinks with packages.
|
|
@ -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`:
|
||||
|
||||
|
|
|
@ -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>`_.
|
||||
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)))
|
||||
)
|
||||
)
|
||||
|
|
|
@ -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
|
||||
""",
|
||||
|
|
|
@ -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*",
|
||||
]
|
||||
)
|
||||
|
|
Loading…
Reference in New Issue