Merge pull request #4808 from nicoddemus/merge-master-into-features
Merge master into features
This commit is contained in:
commit
b9561e29ff
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
|
||||
|
|
|
@ -18,6 +18,48 @@ with advance notice in the **Deprecations** section of releases.
|
|||
|
||||
.. towncrier release notes start
|
||||
|
||||
pytest 4.3.0 (2019-02-16)
|
||||
=========================
|
||||
|
||||
Deprecations
|
||||
------------
|
||||
|
||||
- `#4724 <https://github.com/pytest-dev/pytest/issues/4724>`_: ``pytest.warns()`` now emits a warning when it receives unknown keyword arguments.
|
||||
|
||||
This will be changed into an error in the future.
|
||||
|
||||
|
||||
|
||||
Features
|
||||
--------
|
||||
|
||||
- `#2753 <https://github.com/pytest-dev/pytest/issues/2753>`_: Usage errors from argparse are mapped to pytest's ``UsageError``.
|
||||
|
||||
|
||||
- `#3711 <https://github.com/pytest-dev/pytest/issues/3711>`_: Add the ``--ignore-glob`` parameter to exclude test-modules with Unix shell-style wildcards.
|
||||
Add the ``collect_ignore_glob`` for ``conftest.py`` to exclude test-modules with Unix shell-style wildcards.
|
||||
|
||||
|
||||
- `#4698 <https://github.com/pytest-dev/pytest/issues/4698>`_: The warning about Python 2.7 and 3.4 not being supported in pytest 5.0 has been removed.
|
||||
|
||||
In the end it was considered to be more
|
||||
of a nuisance than actual utility and users of those Python versions shouldn't have problems as ``pip`` will not
|
||||
install pytest 5.0 on those interpreters.
|
||||
|
||||
|
||||
- `#4707 <https://github.com/pytest-dev/pytest/issues/4707>`_: With the help of new ``set_log_path()`` method there is a way to set ``log_file`` paths from hooks.
|
||||
|
||||
|
||||
|
||||
Bug Fixes
|
||||
---------
|
||||
|
||||
- `#4651 <https://github.com/pytest-dev/pytest/issues/4651>`_: ``--help`` and ``--version`` are handled with ``UsageError``.
|
||||
|
||||
|
||||
- `#4782 <https://github.com/pytest-dev/pytest/issues/4782>`_: Fix ``AssertionError`` with collection of broken symlinks with packages.
|
||||
|
||||
|
||||
pytest 4.2.1 (2019-02-12)
|
||||
=========================
|
||||
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
Usage errors from argparse are mapped to pytest's ``UsageError``.
|
|
@ -1,2 +0,0 @@
|
|||
Add the ``--ignore-glob`` parameter to exclude test-modules with Unix shell-style wildcards.
|
||||
Add the ``collect_ignore_glob`` for ``conftest.py`` to exclude test-modules with Unix shell-style wildcards.
|
|
@ -1 +0,0 @@
|
|||
``--help`` and ``--version`` are handled with ``UsageError``.
|
|
@ -1,5 +0,0 @@
|
|||
The warning about Python 2.7 and 3.4 not being supported in pytest 5.0 has been removed.
|
||||
|
||||
In the end it was considered to be more
|
||||
of a nuisance than actual utility and users of those Python versions shouldn't have problems as ``pip`` will not
|
||||
install pytest 5.0 on those interpreters.
|
|
@ -1 +0,0 @@
|
|||
With the help of new ``set_log_path()`` method there is a way to set ``log_file`` paths from hooks.
|
|
@ -1,3 +0,0 @@
|
|||
``pytest.warns()`` now emits a warning when it receives unknown keyword arguments.
|
||||
|
||||
This will be changed into an error in the future.
|
|
@ -6,6 +6,7 @@ Release announcements
|
|||
:maxdepth: 2
|
||||
|
||||
|
||||
release-4.3.0
|
||||
release-4.2.1
|
||||
release-4.2.0
|
||||
release-4.1.1
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
pytest-4.3.0
|
||||
=======================================
|
||||
|
||||
The pytest team is proud to announce the 4.3.0 release!
|
||||
|
||||
pytest is a mature Python testing tool with more than a 2000 tests
|
||||
against itself, passing on many different interpreters and platforms.
|
||||
|
||||
This release contains a number of bugs fixes and improvements, so users are encouraged
|
||||
to take a look at the CHANGELOG:
|
||||
|
||||
https://docs.pytest.org/en/latest/changelog.html
|
||||
|
||||
For complete documentation, please visit:
|
||||
|
||||
https://docs.pytest.org/en/latest/
|
||||
|
||||
As usual, you can upgrade from pypi via:
|
||||
|
||||
pip install -U pytest
|
||||
|
||||
Thanks to all who contributed to this release, among them:
|
||||
|
||||
* Andras Mitzki
|
||||
* Anthony Sottile
|
||||
* Bruno Oliveira
|
||||
* Christian Fetzer
|
||||
* Daniel Hahler
|
||||
* Grygorii Iermolenko
|
||||
* R. Alex Matevish
|
||||
* Ronny Pfannschmidt
|
||||
* cclauss
|
||||
|
||||
|
||||
Happy testing,
|
||||
The Pytest Development Team
|
|
@ -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`:
|
||||
|
||||
|
|
|
@ -436,10 +436,8 @@ Running it results in some skips if we don't have all the python interpreters in
|
|||
.. code-block:: pytest
|
||||
|
||||
. $ pytest -rs -q multipython.py
|
||||
...sss...sssssssss...sss... [100%]
|
||||
========================= short test summary info ==========================
|
||||
SKIPPED [15] $REGENDOC_TMPDIR/CWD/multipython.py:30: 'python3.4' not found
|
||||
12 passed, 15 skipped in 0.12 seconds
|
||||
........................... [100%]
|
||||
27 passed in 0.12 seconds
|
||||
|
||||
Indirect parametrization of optional implementations/imports
|
||||
--------------------------------------------------------------------
|
||||
|
|
|
@ -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)))
|
||||
)
|
||||
)
|
||||
|
|
|
@ -560,7 +560,6 @@ def test_oneline_and_comment():
|
|||
assert str(source) == "raise ValueError"
|
||||
|
||||
|
||||
@pytest.mark.xfail(hasattr(sys, "pypy_version_info"), reason="does not work on pypy")
|
||||
def test_comments():
|
||||
source = '''def test():
|
||||
"comment 1"
|
||||
|
@ -576,9 +575,15 @@ comment 4
|
|||
'''
|
||||
for line in range(2, 6):
|
||||
assert str(getstatement(line, source)) == " x = 1"
|
||||
for line in range(6, 10):
|
||||
assert str(getstatement(line, source)) == " assert False"
|
||||
if sys.version_info >= (3, 8) or hasattr(sys, "pypy_version_info"):
|
||||
tqs_start = 8
|
||||
else:
|
||||
tqs_start = 10
|
||||
assert str(getstatement(10, source)) == '"""'
|
||||
for line in range(6, tqs_start):
|
||||
assert str(getstatement(line, source)) == " assert False"
|
||||
for line in range(tqs_start, 10):
|
||||
assert str(getstatement(line, source)) == '"""\ncomment 4\n"""'
|
||||
|
||||
|
||||
def test_comment_in_statement():
|
||||
|
|
|
@ -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*",
|
||||
]
|
||||
)
|
||||
|
|
|
@ -910,7 +910,6 @@ def test_reportchars_all_error(testdir):
|
|||
result.stdout.fnmatch_lines(["ERROR*test_foo*"])
|
||||
|
||||
|
||||
@pytest.mark.xfail("hasattr(sys, 'pypy_version_info')")
|
||||
def test_errors_in_xfail_skip_expressions(testdir):
|
||||
testdir.makepyfile(
|
||||
"""
|
||||
|
@ -931,6 +930,10 @@ def test_errors_in_xfail_skip_expressions(testdir):
|
|||
if sys.platform.startswith("java"):
|
||||
# XXX report this to java
|
||||
markline = "*" + markline[8:]
|
||||
elif hasattr(sys, "pypy_version_info") and sys.pypy_version_info < (6,):
|
||||
markline = markline[5:]
|
||||
elif sys.version_info >= (3, 8) or hasattr(sys, "pypy_version_info"):
|
||||
markline = markline[4:]
|
||||
result.stdout.fnmatch_lines(
|
||||
[
|
||||
"*ERROR*test_nameerror*",
|
||||
|
|
Loading…
Reference in New Issue