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

Merge master into features (about to prepare 4.0)
This commit is contained in:
Bruno Oliveira 2018-11-13 18:57:41 -02:00 committed by GitHub
commit fea09cda6c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 197 additions and 59 deletions

View File

@ -1,5 +1,6 @@
sudo: false sudo: false
language: python language: python
dist: xenial
stages: stages:
- baseline - baseline
- name: test - name: test
@ -7,7 +8,7 @@ stages:
- name: deploy - name: deploy
if: repo = pytest-dev/pytest AND tag IS present if: repo = pytest-dev/pytest AND tag IS present
python: python:
- '3.6' - '3.7'
install: install:
- pip install --upgrade --pre tox - pip install --upgrade --pre tox
env: env:
@ -17,24 +18,21 @@ env:
- TOXENV=py27-nobyte - TOXENV=py27-nobyte
- TOXENV=py27-xdist - TOXENV=py27-xdist
- TOXENV=py27-pluggymaster PYTEST_NO_COVERAGE=1 - TOXENV=py27-pluggymaster PYTEST_NO_COVERAGE=1
# Specialized factors for py36. # Specialized factors for py37.
- TOXENV=py36-pexpect,py36-trial,py36-numpy - TOXENV=py37-pexpect,py37-trial,py37-numpy
- TOXENV=py36-xdist - TOXENV=py37-xdist
- TOXENV=py36-pluggymaster PYTEST_NO_COVERAGE=1 - TOXENV=py37-pluggymaster PYTEST_NO_COVERAGE=1
- TOXENV=py37-freeze PYTEST_NO_COVERAGE=1
jobs: jobs:
include: include:
# Coverage tracking is slow with pypy, skip it. # Coverage tracking is slow with pypy, skip it.
- env: TOXENV=pypy PYTEST_NO_COVERAGE=1 - env: TOXENV=pypy PYTEST_NO_COVERAGE=1
python: 'pypy-5.4' python: 'pypy-5.4'
dist: trusty
- env: TOXENV=py35 - env: TOXENV=py35
python: '3.5' python: '3.5'
- env: TOXENV=py36-freeze PYTEST_NO_COVERAGE=1
python: '3.6'
- env: TOXENV=py37 - env: TOXENV=py37
python: '3.7'
sudo: required
dist: xenial
- &test-macos - &test-macos
language: generic language: generic
os: osx os: osx
@ -54,8 +52,11 @@ jobs:
- stage: baseline - stage: baseline
env: TOXENV=py27 env: TOXENV=py27
- env: TOXENV=py34 - env: TOXENV=py34
python: '3.4'
- env: TOXENV=py36 - env: TOXENV=py36
- env: TOXENV=linting,docs,doctesting PYTEST_NO_COVERAGE=1 python: '3.6'
- env: TOXENV=linting,docs,doctesting
python: '3.7'
- stage: deploy - stage: deploy
python: '3.6' python: '3.6'
@ -88,7 +89,8 @@ after_success:
- | - |
if [[ "$PYTEST_NO_COVERAGE" != 1 ]]; then if [[ "$PYTEST_NO_COVERAGE" != 1 ]]; then
set -e set -e
pip install coverage # Add last TOXENV to $PATH.
PATH="$PWD/.tox/${TOXENV##*,}/bin:$PATH"
coverage combine coverage combine
coverage xml --ignore-errors coverage xml --ignore-errors
coverage report -m --ignore-errors coverage report -m --ignore-errors

View File

@ -18,6 +18,40 @@ with advance notice in the **Deprecations** section of releases.
.. towncrier release notes start .. towncrier release notes start
pytest 3.10.1 (2018-11-11)
==========================
Bug Fixes
---------
- `#4287 <https://github.com/pytest-dev/pytest/issues/4287>`_: Fix nested usage of debugging plugin (pdb), e.g. with pytester's ``testdir.runpytest``.
- `#4304 <https://github.com/pytest-dev/pytest/issues/4304>`_: Block the ``stepwise`` plugin if ``cacheprovider`` is also blocked, as one depends on the other.
- `#4306 <https://github.com/pytest-dev/pytest/issues/4306>`_: Parse ``minversion`` as an actual version and not as dot-separated strings.
- `#4310 <https://github.com/pytest-dev/pytest/issues/4310>`_: Fix duplicate collection due to multiple args matching the same packages.
- `#4321 <https://github.com/pytest-dev/pytest/issues/4321>`_: Fix ``item.nodeid`` with resolved symlinks.
- `#4325 <https://github.com/pytest-dev/pytest/issues/4325>`_: Fix collection of direct symlinked files, where the target does not match ``python_files``.
- `#4329 <https://github.com/pytest-dev/pytest/issues/4329>`_: Fix TypeError in report_collect with _collect_report_last_write.
Trivial/Internal Changes
------------------------
- `#4305 <https://github.com/pytest-dev/pytest/issues/4305>`_: Replace byte/unicode helpers in test_capture with python level syntax.
pytest 3.10.0 (2018-11-03) pytest 3.10.0 (2018-11-03)
========================== ==========================

View File

@ -169,7 +169,7 @@ Short version
#. Follow **PEP-8** for naming and `black <https://github.com/ambv/black>`_ for formatting. #. Follow **PEP-8** for naming and `black <https://github.com/ambv/black>`_ for formatting.
#. Tests are run using ``tox``:: #. Tests are run using ``tox``::
tox -e linting,py27,py36 tox -e linting,py27,py37
The test environments above are usually enough to cover most cases locally. The test environments above are usually enough to cover most cases locally.
@ -237,12 +237,12 @@ Here is a simple overview, with pytest-specific bits:
#. Run all the tests #. Run all the tests
You need to have Python 2.7 and 3.6 available in your system. Now You need to have Python 2.7 and 3.7 available in your system. Now
running tests is as simple as issuing this command:: running tests is as simple as issuing this command::
$ tox -e linting,py27,py36 $ tox -e linting,py27,py37
This command will run tests via the "tox" tool against Python 2.7 and 3.6 This command will run tests via the "tox" tool against Python 2.7 and 3.7
and also perform "lint" coding-style checks. and also perform "lint" coding-style checks.
#. You can now edit your local working copy and run the tests again as necessary. Please follow PEP-8 for naming. #. You can now edit your local working copy and run the tests again as necessary. Please follow PEP-8 for naming.
@ -252,9 +252,9 @@ Here is a simple overview, with pytest-specific bits:
$ tox -e py27 -- --pdb $ tox -e py27 -- --pdb
Or to only run tests in a particular test module on Python 3.6:: Or to only run tests in a particular test module on Python 3.7::
$ tox -e py36 -- testing/test_config.py $ tox -e py37 -- testing/test_config.py
When committing, ``pre-commit`` will re-format the files if necessary. When committing, ``pre-commit`` will re-format the files if necessary.

View File

@ -2,7 +2,6 @@ environment:
matrix: matrix:
- TOXENV: "py27" - TOXENV: "py27"
- TOXENV: "py37" - TOXENV: "py37"
PYTEST_NO_COVERAGE: "1"
- TOXENV: "linting,docs,doctesting" - TOXENV: "linting,docs,doctesting"
- TOXENV: "py36" - TOXENV: "py36"
- TOXENV: "py35" - TOXENV: "py35"
@ -14,13 +13,13 @@ environment:
- TOXENV: "py27-pluggymaster" - TOXENV: "py27-pluggymaster"
PYTEST_NO_COVERAGE: "1" PYTEST_NO_COVERAGE: "1"
- TOXENV: "py27-xdist" - TOXENV: "py27-xdist"
# Specialized factors for py36. # Specialized factors for py37.
- TOXENV: "py36-trial,py36-numpy" - TOXENV: "py37-trial,py37-numpy"
- TOXENV: "py36-pluggymaster" - TOXENV: "py37-pluggymaster"
PYTEST_NO_COVERAGE: "1" PYTEST_NO_COVERAGE: "1"
- TOXENV: "py36-freeze" - TOXENV: "py37-freeze"
PYTEST_NO_COVERAGE: "1" PYTEST_NO_COVERAGE: "1"
- TOXENV: "py36-xdist" - TOXENV: "py37-xdist"
matrix: matrix:
fast_finish: true fast_finish: true

View File

@ -1 +0,0 @@
Fix nested usage of debugging plugin (pdb), e.g. with pytester's ``testdir.runpytest``.

View File

@ -1 +0,0 @@
Block the ``stepwise`` plugin if ``cacheprovider`` is also blocked, as one depends on the other.

View File

@ -1 +0,0 @@
Replace byte/unicode helpers in test_capture with python level syntax.

View File

@ -1 +0,0 @@
Parse ``minversion`` as an actual version and not as dot-separated strings.

View File

@ -1 +0,0 @@
Fix duplicate collection due to multiple args matching the same packages.

View File

@ -1 +0,0 @@
Fix TypeError in report_collect with _collect_report_last_write.

View File

@ -6,6 +6,7 @@ Release announcements
:maxdepth: 2 :maxdepth: 2
release-3.10.1
release-3.10.0 release-3.10.0
release-3.9.3 release-3.9.3
release-3.9.2 release-3.9.2

View File

@ -0,0 +1,24 @@
pytest-3.10.1
=======================================
pytest 3.10.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 https://docs.pytest.org/en/latest/changelog.html.
Thanks to all who contributed to this release, among them:
* Anthony Sottile
* Boris Feld
* Bruno Oliveira
* Daniel Hahler
* Fabien ZARIFIAN
* Jon Dufresne
* Ronny Pfannschmidt
Happy testing,
The pytest Development Team

View File

@ -85,9 +85,8 @@ interesting to just look at the collection tree::
rootdir: $REGENDOC_TMPDIR/nonpython, inifile: rootdir: $REGENDOC_TMPDIR/nonpython, inifile:
collected 2 items collected 2 items
<Package '$REGENDOC_TMPDIR/nonpython'> <Package '$REGENDOC_TMPDIR/nonpython'>
<Package '$REGENDOC_TMPDIR/nonpython'> <YamlFile 'test_simple.yml'>
<YamlFile 'test_simple.yml'> <YamlItem 'hello'>
<YamlItem 'hello'> <YamlItem 'ok'>
<YamlItem 'ok'>
======================= no tests ran in 0.12 seconds ======================= ======================= no tests ran in 0.12 seconds =======================

View File

@ -398,6 +398,7 @@ class Session(nodes.FSCollector):
# Keep track of any collected nodes in here, so we don't duplicate fixtures # Keep track of any collected nodes in here, so we don't duplicate fixtures
self._node_cache = {} self._node_cache = {}
self._bestrelpathcache = _bestrelpath_cache(config.rootdir) self._bestrelpathcache = _bestrelpath_cache(config.rootdir)
# Dirnames of pkgs with dunder-init files.
self._pkg_roots = {} self._pkg_roots = {}
self.config.pluginmanager.register(self, name="session") self.config.pluginmanager.register(self, name="session")
@ -504,7 +505,7 @@ class Session(nodes.FSCollector):
from _pytest.python import Package from _pytest.python import Package
names = self._parsearg(arg) names = self._parsearg(arg)
argpath = names.pop(0).realpath() argpath = names.pop(0)
# Start with a Session root, and delve to argpath item (dir or file) # Start with a Session root, and delve to argpath item (dir or file)
# and stack all Packages found on the way. # and stack all Packages found on the way.
@ -551,8 +552,7 @@ class Session(nodes.FSCollector):
seen_dirs.add(dirpath) seen_dirs.add(dirpath)
pkginit = dirpath.join("__init__.py") pkginit = dirpath.join("__init__.py")
if pkginit.exists(): if pkginit.exists():
collect_root = self._pkg_roots.get(dirpath, self) for x in self._collectfile(pkginit):
for x in collect_root._collectfile(pkginit):
yield x yield x
if isinstance(x, Package): if isinstance(x, Package):
self._pkg_roots[dirpath] = x self._pkg_roots[dirpath] = x
@ -652,7 +652,7 @@ class Session(nodes.FSCollector):
"file or package not found: " + arg + " (missing __init__.py?)" "file or package not found: " + arg + " (missing __init__.py?)"
) )
raise UsageError("file not found: " + arg) raise UsageError("file not found: " + arg)
parts[0] = path parts[0] = path.realpath()
return parts return parts
def matchnodes(self, matching, names): def matchnodes(self, matching, names):

View File

@ -449,7 +449,7 @@ class Collector(Node):
def _check_initialpaths_for_relpath(session, fspath): def _check_initialpaths_for_relpath(session, fspath):
for initial_path in session._initialpaths: for initial_path in session._initialpaths:
if fspath.common(initial_path) == initial_path: if fspath.common(initial_path) == initial_path:
return fspath.relto(initial_path.dirname) return fspath.relto(initial_path)
class FSCollector(Collector): class FSCollector(Collector):

View File

@ -666,11 +666,11 @@ class TestInvocationVariants(object):
assert result.ret == 0 assert result.ret == 0
result.stdout.fnmatch_lines( result.stdout.fnmatch_lines(
[ [
"*test_hello.py::test_hello*PASSED*", "test_hello.py::test_hello*PASSED*",
"*test_hello.py::test_other*PASSED*", "test_hello.py::test_other*PASSED*",
"*test_world.py::test_world*PASSED*", "ns_pkg/world/test_world.py::test_world*PASSED*",
"*test_world.py::test_other*PASSED*", "ns_pkg/world/test_world.py::test_other*PASSED*",
"*4 passed*", "*4 passed in*",
] ]
) )

View File

@ -15,7 +15,7 @@ def equal_with_bash(prefix, ffc, fc, out=None):
res_bash = set(fc(prefix)) res_bash = set(fc(prefix))
retval = set(res) == res_bash retval = set(res) == res_bash
if out: if out:
out.write("equal_with_bash {} {}\n".format(retval, res)) out.write("equal_with_bash({}) {} {}\n".format(prefix, retval, res))
if not retval: if not retval:
out.write(" python - bash: %s\n" % (set(res) - res_bash)) out.write(" python - bash: %s\n" % (set(res) - res_bash))
out.write(" bash - python: %s\n" % (res_bash - set(res))) out.write(" bash - python: %s\n" % (res_bash - set(res)))
@ -91,13 +91,19 @@ class FilesCompleter(object):
class TestArgComplete(object): class TestArgComplete(object):
@pytest.mark.skipif("sys.platform in ('win32', 'darwin')") @pytest.mark.skipif("sys.platform in ('win32', 'darwin')")
def test_compare_with_compgen(self): def test_compare_with_compgen(self, tmpdir):
from _pytest._argcomplete import FastFilesCompleter from _pytest._argcomplete import FastFilesCompleter
ffc = FastFilesCompleter() ffc = FastFilesCompleter()
fc = FilesCompleter() fc = FilesCompleter()
for x in ["/", "/d", "/data", "qqq", ""]:
assert equal_with_bash(x, ffc, fc, out=sys.stdout) with tmpdir.as_cwd():
assert equal_with_bash("", ffc, fc, out=sys.stdout)
tmpdir.ensure("data")
for x in ["d", "data", "doesnotexist", ""]:
assert equal_with_bash(x, ffc, fc, out=sys.stdout)
@pytest.mark.skipif("sys.platform in ('win32', 'darwin')") @pytest.mark.skipif("sys.platform in ('win32', 'darwin')")
def test_remove_dir_prefix(self): def test_remove_dir_prefix(self):

View File

@ -6,6 +6,8 @@ import pprint
import sys import sys
import textwrap import textwrap
import py
import pytest import pytest
from _pytest.main import _in_venv from _pytest.main import _in_venv
from _pytest.main import EXIT_NOTESTSCOLLECTED from _pytest.main import EXIT_NOTESTSCOLLECTED
@ -1082,4 +1084,55 @@ def test_collect_with_chdir_during_import(testdir):
with testdir.tmpdir.as_cwd(): with testdir.tmpdir.as_cwd():
result = testdir.runpytest("--collect-only") result = testdir.runpytest("--collect-only")
result.stdout.fnmatch_lines(["collected 1 item"]) result.stdout.fnmatch_lines(["collected 1 item"])
@pytest.mark.skipif(
not hasattr(py.path.local, "mksymlinkto"),
reason="symlink not available on this platform",
)
def test_collect_symlink_file_arg(testdir):
"""Test that collecting a direct symlink, where the target does not match python_files works (#4325)."""
real = testdir.makepyfile(
real="""
def test_nodeid(request):
assert request.node.nodeid == "real.py::test_nodeid"
"""
)
symlink = testdir.tmpdir.join("symlink.py")
symlink.mksymlinkto(real)
result = testdir.runpytest("-v", symlink)
result.stdout.fnmatch_lines(["real.py::test_nodeid PASSED*", "*1 passed in*"])
assert result.ret == 0
@pytest.mark.skipif(
not hasattr(py.path.local, "mksymlinkto"),
reason="symlink not available on this platform",
)
def test_collect_symlink_out_of_tree(testdir):
"""Test collection of symlink via out-of-tree rootdir."""
sub = testdir.tmpdir.join("sub")
real = sub.join("test_real.py")
real.write(
textwrap.dedent(
"""
def test_nodeid(request):
# Should not contain sub/ prefix.
assert request.node.nodeid == "test_real.py::test_nodeid"
"""
),
ensure=True,
)
out_of_tree = testdir.tmpdir.join("out_of_tree").ensure(dir=True)
symlink_to_sub = out_of_tree.join("symlink_to_sub")
symlink_to_sub.mksymlinkto(sub)
sub.chdir()
result = testdir.runpytest("-vs", "--rootdir=%s" % sub, symlink_to_sub)
result.stdout.fnmatch_lines(
[
# Should not contain "sub/"!
"test_real.py::test_nodeid PASSED"
]
)
assert result.ret == 0 assert result.ret == 0

View File

@ -1,3 +1,5 @@
import py
import pytest import pytest
from _pytest import nodes from _pytest import nodes
@ -29,3 +31,23 @@ def test_std_warn_not_pytestwarning(testdir):
) )
with pytest.raises(ValueError, match=".*instance of PytestWarning.*"): with pytest.raises(ValueError, match=".*instance of PytestWarning.*"):
items[0].warn(UserWarning("some warning")) items[0].warn(UserWarning("some warning"))
def test__check_initialpaths_for_relpath():
"""Ensure that it handles dirs, and does not always use dirname."""
cwd = py.path.local()
class FakeSession:
_initialpaths = [cwd]
assert nodes._check_initialpaths_for_relpath(FakeSession, cwd) == ""
sub = cwd.join("file")
class FakeSession:
_initialpaths = [cwd]
assert nodes._check_initialpaths_for_relpath(FakeSession, sub) == "file"
outside = py.path.local("/outside")
assert nodes._check_initialpaths_for_relpath(FakeSession, outside) is None

View File

@ -333,7 +333,11 @@ def test_rootdir_option_arg(testdir, monkeypatch, path):
result = testdir.runpytest("--rootdir={}".format(path)) result = testdir.runpytest("--rootdir={}".format(path))
result.stdout.fnmatch_lines( result.stdout.fnmatch_lines(
["*rootdir: {}/root, inifile:*".format(testdir.tmpdir), "*1 passed*"] [
"*rootdir: {}/root, inifile:*".format(testdir.tmpdir),
"root/test_rootdir_option_arg.py *",
"*1 passed*",
]
) )

20
tox.ini
View File

@ -10,10 +10,10 @@ envlist =
py36 py36
py37 py37
pypy pypy
{py27,py36}-{pexpect,xdist,trial,numpy,pluggymaster} {py27,py37}-{pexpect,xdist,trial,numpy,pluggymaster}
py27-nobyte py27-nobyte
doctesting doctesting
py36-freeze py37-freeze
docs docs
[testenv] [testenv]
@ -23,7 +23,7 @@ commands =
coverage: coverage report coverage: coverage report
passenv = USER USERNAME COVERAGE_* TRAVIS passenv = USER USERNAME COVERAGE_* TRAVIS
setenv = setenv =
# configuration if a user runs tox with a "coverage" factor, for example "tox -e py36-coverage" # configuration if a user runs tox with a "coverage" factor, for example "tox -e py37-coverage"
coverage: _PYTEST_TOX_COVERAGE_RUN=coverage run -m coverage: _PYTEST_TOX_COVERAGE_RUN=coverage run -m
coverage: _PYTEST_TOX_EXTRA_DEP=coverage-enable-subprocess coverage: _PYTEST_TOX_EXTRA_DEP=coverage-enable-subprocess
coverage: COVERAGE_FILE={toxinidir}/.coverage coverage: COVERAGE_FILE={toxinidir}/.coverage
@ -46,7 +46,7 @@ commands =
[testenv:linting] [testenv:linting]
skip_install = True skip_install = True
basepython = python3.6 basepython = python3
deps = pre-commit>=1.11.0 deps = pre-commit>=1.11.0
commands = pre-commit run --all-files --show-diff-on-failure commands = pre-commit run --all-files --show-diff-on-failure
@ -60,7 +60,7 @@ deps =
commands = commands =
{env:_PYTEST_TOX_COVERAGE_RUN:} pytest -n auto {posargs} {env:_PYTEST_TOX_COVERAGE_RUN:} pytest -n auto {posargs}
[testenv:py36-xdist] [testenv:py37-xdist]
# NOTE: copied from above due to https://github.com/tox-dev/tox/issues/706. # NOTE: copied from above due to https://github.com/tox-dev/tox/issues/706.
deps = deps =
pytest-xdist>=1.13 pytest-xdist>=1.13
@ -78,7 +78,7 @@ deps =
commands = commands =
{env:_PYTEST_TOX_COVERAGE_RUN:} pytest testing/test_pdb.py testing/test_terminal.py testing/test_unittest.py {posargs} {env:_PYTEST_TOX_COVERAGE_RUN:} pytest testing/test_pdb.py testing/test_terminal.py testing/test_unittest.py {posargs}
[testenv:py36-pexpect] [testenv:py37-pexpect]
platform = {[testenv:py27-pexpect]platform} platform = {[testenv:py27-pexpect]platform}
deps = {[testenv:py27-pexpect]deps} deps = {[testenv:py27-pexpect]deps}
commands = {[testenv:py27-pexpect]commands} commands = {[testenv:py27-pexpect]commands}
@ -103,7 +103,7 @@ deps =
commands = commands =
{env:_PYTEST_TOX_COVERAGE_RUN:} pytest {posargs:testing/test_unittest.py} {env:_PYTEST_TOX_COVERAGE_RUN:} pytest {posargs:testing/test_unittest.py}
[testenv:py36-trial] [testenv:py37-trial]
deps = {[testenv:py27-trial]deps} deps = {[testenv:py27-trial]deps}
commands = {[testenv:py27-trial]commands} commands = {[testenv:py27-trial]commands}
@ -114,7 +114,7 @@ deps =
commands= commands=
{env:_PYTEST_TOX_COVERAGE_RUN:} pytest {posargs:testing/python/approx.py} {env:_PYTEST_TOX_COVERAGE_RUN:} pytest {posargs:testing/python/approx.py}
[testenv:py36-numpy] [testenv:py37-numpy]
deps = {[testenv:py27-numpy]deps} deps = {[testenv:py27-numpy]deps}
commands = {[testenv:py27-numpy]commands} commands = {[testenv:py27-numpy]commands}
@ -125,7 +125,7 @@ setenv=
# NOTE: using env instead of "{[testenv]deps}", because of https://github.com/tox-dev/tox/issues/706. # NOTE: using env instead of "{[testenv]deps}", because of https://github.com/tox-dev/tox/issues/706.
_PYTEST_TOX_EXTRA_DEP=git+https://github.com/pytest-dev/pluggy.git@master _PYTEST_TOX_EXTRA_DEP=git+https://github.com/pytest-dev/pluggy.git@master
[testenv:py36-pluggymaster] [testenv:py37-pluggymaster]
setenv = {[testenv:py27-pluggymaster]setenv} setenv = {[testenv:py27-pluggymaster]setenv}
[testenv:docs] [testenv:docs]
@ -170,7 +170,7 @@ changedir = testing
commands = commands =
{envpython} {envbindir}/py.test-jython {posargs} {envpython} {envbindir}/py.test-jython {posargs}
[testenv:py36-freeze] [testenv:py37-freeze]
changedir = testing/freeze changedir = testing/freeze
deps = deps =
pyinstaller pyinstaller