Merge pull request #4785 from blueyed/merge-master-into-features

Merge master into features
This commit is contained in:
Daniel Hahler 2019-02-13 20:23:24 +01:00 committed by GitHub
commit 1dbf440194
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
29 changed files with 373 additions and 67 deletions

3
.gitignore vendored
View File

@ -45,3 +45,6 @@ coverage.xml
.project .project
.settings .settings
.vscode .vscode
# generated by pip
pip-wheel-metadata/

View File

@ -17,10 +17,10 @@ env:
# Specialized factors for py27. # Specialized factors for py27.
- TOXENV=py27-nobyte - TOXENV=py27-nobyte
- TOXENV=py27-xdist - TOXENV=py27-xdist
- TOXENV=py27-pluggymaster PYTEST_NO_COVERAGE=1 - TOXENV=py27-pluggymaster
# Specialized factors for py37. # Specialized factors for py37.
- TOXENV=py37-pexpect,py37-trial,py37-numpy - TOXENV=py37-pexpect,py37-trial,py37-numpy
- TOXENV=py37-pluggymaster PYTEST_NO_COVERAGE=1 - TOXENV=py37-pluggymaster
- TOXENV=py37-freeze PYTEST_NO_COVERAGE=1 - TOXENV=py37-freeze PYTEST_NO_COVERAGE=1
matrix: matrix:

View File

@ -18,6 +18,62 @@ with advance notice in the **Deprecations** section of releases.
.. towncrier release notes start .. towncrier release notes start
pytest 4.2.1 (2019-02-12)
=========================
Bug Fixes
---------
- `#2895 <https://github.com/pytest-dev/pytest/issues/2895>`_: The ``pytest_report_collectionfinish`` hook now is also called with ``--collect-only``.
- `#3899 <https://github.com/pytest-dev/pytest/issues/3899>`_: Do not raise ``UsageError`` when an imported package has a ``pytest_plugins.py`` child module.
- `#4347 <https://github.com/pytest-dev/pytest/issues/4347>`_: Fix output capturing when using pdb++ with recursive debugging.
- `#4592 <https://github.com/pytest-dev/pytest/issues/4592>`_: Fix handling of ``collect_ignore`` via parent ``conftest.py``.
- `#4700 <https://github.com/pytest-dev/pytest/issues/4700>`_: Fix regression where ``setUpClass`` would always be called in subclasses even if all tests
were skipped by a ``unittest.skip()`` decorator applied in the subclass.
- `#4739 <https://github.com/pytest-dev/pytest/issues/4739>`_: Fix ``parametrize(... ids=<function>)`` when the function returns non-strings.
- `#4745 <https://github.com/pytest-dev/pytest/issues/4745>`_: Fix/improve collection of args when passing in ``__init__.py`` and a test file.
- `#4770 <https://github.com/pytest-dev/pytest/issues/4770>`_: ``more_itertools`` is now constrained to <6.0.0 when required for Python 2.7 compatibility.
- `#526 <https://github.com/pytest-dev/pytest/issues/526>`_: Fix "ValueError: Plugin already registered" exceptions when running in build directories that symlink to actual source.
Improved Documentation
----------------------
- `#3899 <https://github.com/pytest-dev/pytest/issues/3899>`_: Add note to ``plugins.rst`` that ``pytest_plugins`` should not be used as a name for a user module containing plugins.
- `#4324 <https://github.com/pytest-dev/pytest/issues/4324>`_: Document how to use ``raises`` and ``does_not_raise`` to write parametrized tests with conditional raises.
- `#4709 <https://github.com/pytest-dev/pytest/issues/4709>`_: Document how to customize test failure messages when using
``pytest.warns``.
Trivial/Internal Changes
------------------------
- `#4741 <https://github.com/pytest-dev/pytest/issues/4741>`_: Some verbosity related attributes of the TerminalReporter plugin are now
read only properties.
pytest 4.2.0 (2019-01-30) pytest 4.2.0 (2019-01-30)
========================= =========================

View File

@ -11,11 +11,9 @@ environment:
# Specialized factors for py27. # Specialized factors for py27.
- TOXENV: "py27-trial,py27-numpy,py27-nobyte" - TOXENV: "py27-trial,py27-numpy,py27-nobyte"
- TOXENV: "py27-pluggymaster" - TOXENV: "py27-pluggymaster"
PYTEST_NO_COVERAGE: "1"
# Specialized factors for py37. # Specialized factors for py37.
- TOXENV: "py37-trial,py37-numpy" - TOXENV: "py37-trial,py37-numpy"
- TOXENV: "py37-pluggymaster" - TOXENV: "py37-pluggymaster"
PYTEST_NO_COVERAGE: "1"
- TOXENV: "py37-freeze" - TOXENV: "py37-freeze"
PYTEST_NO_COVERAGE: "1" PYTEST_NO_COVERAGE: "1"

45
azure-pipelines.yml Normal file
View File

@ -0,0 +1,45 @@
trigger:
- master
- features
variables:
PYTEST_ADDOPTS: "--junitxml=build/test-results/$(tox.env).xml"
jobs:
- job: 'Test'
pool:
vmImage: "vs2017-win2016"
strategy:
matrix:
py27:
python.version: '2.7'
tox.env: 'py27'
py35:
python.version: '3.5'
tox.env: 'py35'
py36:
python.version: '3.6'
tox.env: 'py36'
py37:
python.version: '3.7'
tox.env: 'py37'
maxParallel: 4
steps:
- task: UsePythonVersion@0
inputs:
versionSpec: '$(python.version)'
architecture: 'x64'
- script: python -m pip install --upgrade pip && pip install tox
displayName: 'Install tox'
- script: python -m tox -e $(tox.env)
displayName: 'Run tests'
- task: PublishTestResults@2
inputs:
testResultsFiles: 'build/test-results/$(tox.env).xml'
testRunTitle: '$(tox.env)'
condition: succeededOrFailed()

View File

@ -1 +0,0 @@
The ``pytest_report_collectionfinish`` hook now is also called with ``--collect-only``.

View File

@ -1 +0,0 @@
Do not raise ``UsageError`` when an imported package has a ``pytest_plugins.py`` child module.

View File

@ -1 +0,0 @@
Add note to ``plugins.rst`` that ``pytest_plugins`` should not be used as a name for a user module containing plugins.

View File

@ -1 +0,0 @@
Document how to use ``raises`` and ``does_not_raise`` to write parametrized tests with conditional raises.

View File

@ -1 +0,0 @@
Fix handling of ``collect_ignore`` via parent ``conftest.py``.

View File

@ -1,2 +0,0 @@
Fix regression where ``setUpClass`` would always be called in subclasses even if all tests
were skipped by a ``unittest.skip()`` decorator applied in the subclass.

View File

@ -1,2 +0,0 @@
Document how to customize test failure messages when using
``pytest.warns``.

View File

@ -1 +0,0 @@
Fix ``parametrize(... ids=<function>)`` when the function returns non-strings.

View File

@ -6,6 +6,7 @@ Release announcements
:maxdepth: 2 :maxdepth: 2
release-4.2.1
release-4.2.0 release-4.2.0
release-4.1.1 release-4.1.1
release-4.1.0 release-4.1.0

View File

@ -0,0 +1,30 @@
pytest-4.2.1
=======================================
pytest 4.2.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
* Arel Cordero
* Bruno Oliveira
* Daniel Hahler
* Holger Kohr
* Kevin J. Foley
* Nick Murphy
* Paweł Stradomski
* Raphael Pierzina
* Ronny Pfannschmidt
* Sam Brightman
* Thomas Hisch
* Zac Hatfield-Dodds
Happy testing,
The pytest Development Team

View File

@ -205,8 +205,8 @@ Special comparisons are done for a number of cases:
See the :ref:`reporting demo <tbreportdemo>` for many more examples. See the :ref:`reporting demo <tbreportdemo>` for many more examples.
Defining your own assertion comparison Defining your own explanation for failed assertions
---------------------------------------------- ---------------------------------------------------
It is possible to add your own detailed explanations by implementing It is possible to add your own detailed explanations by implementing
the ``pytest_assertrepr_compare`` hook. the ``pytest_assertrepr_compare`` hook.

View File

@ -1042,6 +1042,20 @@ passed multiple times. The expected format is ``name=value``. For example::
This tells pytest to ignore deprecation warnings and turn all other warnings This tells pytest to ignore deprecation warnings and turn all other warnings
into errors. For more information please refer to :ref:`warnings`. into errors. For more information please refer to :ref:`warnings`.
.. confval:: junit_family
.. versionadded:: 4.2
Configures the format of the generated JUnit XML file. The possible options are:
* ``xunit1`` (or ``legacy``): produces old style output, compatible with the xunit 1.0 format. **This is the default**.
* ``xunit2``: produces `xunit 2.0 style output <https://github.com/jenkinsci/xunit-plugin/blob/xunit-2.3.2/src/main/resources/org/jenkinsci/plugins/xunit/types/model/xsd/junit-10.xsd>`__,
which should be more compatible with latest Jenkins versions.
.. code-block:: ini
[pytest]
junit_family = xunit2
.. confval:: junit_suite_name .. confval:: junit_suite_name

View File

@ -10,7 +10,8 @@ INSTALL_REQUIRES = [
"six>=1.10.0", "six>=1.10.0",
"setuptools", "setuptools",
"attrs>=17.4.0", "attrs>=17.4.0",
"more-itertools>=4.0.0", 'more-itertools>=4.0.0,<6.0.0;python_version<="2.7"',
'more-itertools>=4.0.0;python_version>"2.7"',
"atomicwrites>=1.0", "atomicwrites>=1.0",
'funcsigs;python_version<"3.0"', 'funcsigs;python_version<"3.0"',
'pathlib2>=2.2.0;python_version<"3.6"', 'pathlib2>=2.2.0;python_version<"3.6"',

View File

@ -408,7 +408,10 @@ class PytestPluginManager(PluginManager):
continue continue
conftestpath = parent.join("conftest.py") conftestpath = parent.join("conftest.py")
if conftestpath.isfile(): if conftestpath.isfile():
mod = self._importconftest(conftestpath) # Use realpath to avoid loading the same conftest twice
# with build systems that create build directories containing
# symlinks to actual files.
mod = self._importconftest(conftestpath.realpath())
clist.append(mod) clist.append(mod)
self._dirpath2confmods[directory] = clist self._dirpath2confmods[directory] = clist
return clist return clist

View File

@ -75,6 +75,7 @@ class pytestPDB(object):
_config = None _config = None
_pdb_cls = pdb.Pdb _pdb_cls = pdb.Pdb
_saved = [] _saved = []
_recursive_debug = 0
@classmethod @classmethod
def _init_pdb(cls, *args, **kwargs): def _init_pdb(cls, *args, **kwargs):
@ -87,29 +88,37 @@ class pytestPDB(object):
capman.suspend_global_capture(in_=True) capman.suspend_global_capture(in_=True)
tw = _pytest.config.create_terminal_writer(cls._config) tw = _pytest.config.create_terminal_writer(cls._config)
tw.line() tw.line()
# Handle header similar to pdb.set_trace in py37+. if cls._recursive_debug == 0:
header = kwargs.pop("header", None) # Handle header similar to pdb.set_trace in py37+.
if header is not None: header = kwargs.pop("header", None)
tw.sep(">", header) if header is not None:
elif capman and capman.is_globally_capturing(): tw.sep(">", header)
tw.sep(">", "PDB set_trace (IO-capturing turned off)") elif capman and capman.is_globally_capturing():
else: tw.sep(">", "PDB set_trace (IO-capturing turned off)")
tw.sep(">", "PDB set_trace") else:
tw.sep(">", "PDB set_trace")
class _PdbWrapper(cls._pdb_cls, object): class _PdbWrapper(cls._pdb_cls, object):
_pytest_capman = capman _pytest_capman = capman
_continued = False _continued = False
def do_debug(self, arg):
cls._recursive_debug += 1
ret = super(_PdbWrapper, self).do_debug(arg)
cls._recursive_debug -= 1
return ret
def do_continue(self, arg): def do_continue(self, arg):
ret = super(_PdbWrapper, self).do_continue(arg) ret = super(_PdbWrapper, self).do_continue(arg)
if self._pytest_capman: if self._pytest_capman:
tw = _pytest.config.create_terminal_writer(cls._config) tw = _pytest.config.create_terminal_writer(cls._config)
tw.line() tw.line()
if self._pytest_capman.is_globally_capturing(): if cls._recursive_debug == 0:
tw.sep(">", "PDB continue (IO-capturing resumed)") if self._pytest_capman.is_globally_capturing():
else: tw.sep(">", "PDB continue (IO-capturing resumed)")
tw.sep(">", "PDB continue") else:
self._pytest_capman.resume_global_capture() tw.sep(">", "PDB continue")
self._pytest_capman.resume_global_capture()
cls._pluginmanager.hook.pytest_leave_pdb( cls._pluginmanager.hook.pytest_leave_pdb(
config=cls._config, pdb=self config=cls._config, pdb=self
) )

View File

@ -4,6 +4,7 @@ from __future__ import print_function
import functools import functools
import inspect import inspect
import itertools
import sys import sys
import warnings import warnings
from collections import defaultdict from collections import defaultdict
@ -13,7 +14,6 @@ from collections import OrderedDict
import attr import attr
import py import py
import six import six
from more_itertools import flatten
import _pytest import _pytest
from _pytest import nodes from _pytest import nodes
@ -1109,7 +1109,7 @@ class FixtureManager(object):
argnames = getfuncargnames(func, cls=cls) argnames = getfuncargnames(func, cls=cls)
else: else:
argnames = () argnames = ()
usefixtures = flatten( usefixtures = itertools.chain.from_iterable(
mark.args for mark in node.iter_markers(name="usefixtures") mark.args for mark in node.iter_markers(name="usefixtures")
) )
initialnames = tuple(usefixtures) + argnames initialnames = tuple(usefixtures) + argnames

View File

@ -435,13 +435,6 @@ class LoggingPlugin(object):
# terminal reporter is disabled e.g. by pytest-xdist. # terminal reporter is disabled e.g. by pytest-xdist.
return return
# FIXME don't set verbosity level and derived attributes of
# terminalwriter directly
terminal_reporter.verbosity = config.option.verbose
terminal_reporter.showheader = terminal_reporter.verbosity >= 0
terminal_reporter.showfspath = terminal_reporter.verbosity >= 0
terminal_reporter.showlongtestinfo = terminal_reporter.verbosity > 0
capture_manager = config.pluginmanager.get_plugin("capturemanager") capture_manager = config.pluginmanager.get_plugin("capturemanager")
# if capturemanager plugin is disabled, live logging still works. # if capturemanager plugin is disabled, live logging still works.
log_cli_handler = _LiveLoggingStreamHandler(terminal_reporter, capture_manager) log_cli_handler = _LiveLoggingStreamHandler(terminal_reporter, capture_manager)

View File

@ -571,19 +571,9 @@ class Session(nodes.FSCollector):
if argpath.check(dir=1): if argpath.check(dir=1):
assert not names, "invalid arg %r" % (arg,) assert not names, "invalid arg %r" % (arg,)
if six.PY2:
def filter_(f):
return f.check(file=1) and not f.strpath.endswith("*.pyc")
else:
def filter_(f):
return f.check(file=1)
seen_dirs = set() seen_dirs = set()
for path in argpath.visit( for path in argpath.visit(
fil=filter_, rec=self._recurse, bf=True, sort=True fil=self._visit_filter, rec=self._recurse, bf=True, sort=True
): ):
dirpath = path.dirpath() dirpath = path.dirpath()
if dirpath not in seen_dirs: if dirpath not in seen_dirs:
@ -613,7 +603,7 @@ class Session(nodes.FSCollector):
col = self._node_cache[argpath] col = self._node_cache[argpath]
else: else:
collect_root = self._pkg_roots.get(argpath.dirname, self) collect_root = self._pkg_roots.get(argpath.dirname, self)
col = collect_root._collectfile(argpath) col = collect_root._collectfile(argpath, handle_dupes=False)
if col: if col:
self._node_cache[argpath] = col self._node_cache[argpath] = col
m = self.matchnodes(col, names) m = self.matchnodes(col, names)
@ -658,6 +648,18 @@ class Session(nodes.FSCollector):
ihook.pytest_collect_directory(path=dirpath, parent=self) ihook.pytest_collect_directory(path=dirpath, parent=self)
return True return True
if six.PY2:
@staticmethod
def _visit_filter(f):
return f.check(file=1) and not f.strpath.endswith("*.pyc")
else:
@staticmethod
def _visit_filter(f):
return f.check(file=1)
def _tryconvertpyarg(self, x): def _tryconvertpyarg(self, x):
"""Convert a dotted module name to path.""" """Convert a dotted module name to path."""
try: try:

View File

@ -81,7 +81,11 @@ class LsofFdLeakChecker(object):
def _exec_lsof(self): def _exec_lsof(self):
pid = os.getpid() pid = os.getpid()
return subprocess.check_output(("lsof", "-Ffn0", "-p", str(pid))).decode() # py3: use subprocess.DEVNULL directly.
with open(os.devnull, "wb") as devnull:
return subprocess.check_output(
("lsof", "-Ffn0", "-p", str(pid)), stderr=devnull
).decode()
def _parse_lsof_output(self, out): def _parse_lsof_output(self, out):
def isopen(line): def isopen(line):

View File

@ -222,12 +222,9 @@ class TerminalReporter(object):
import _pytest.config import _pytest.config
self.config = config self.config = config
self.verbosity = self.config.option.verbose
self.showheader = self.verbosity >= 0
self.showfspath = self.verbosity >= 0
self.showlongtestinfo = self.verbosity > 0
self._numcollected = 0 self._numcollected = 0
self._session = None self._session = None
self._showfspath = None
self.stats = {} self.stats = {}
self.startdir = py.path.local() self.startdir = py.path.local()
@ -255,6 +252,28 @@ class TerminalReporter(object):
return False return False
return self.config.getini("console_output_style") in ("progress", "count") return self.config.getini("console_output_style") in ("progress", "count")
@property
def verbosity(self):
return self.config.option.verbose
@property
def showheader(self):
return self.verbosity >= 0
@property
def showfspath(self):
if self._showfspath is None:
return self.verbosity >= 0
return self._showfspath
@showfspath.setter
def showfspath(self, value):
self._showfspath = value
@property
def showlongtestinfo(self):
return self.verbosity > 0
def hasopt(self, char): def hasopt(self, char):
char = {"xfailed": "x", "skipped": "s"}.get(char, char) char = {"xfailed": "x", "skipped": "s"}.get(char, char)
return char in self.reportchars return char in self.reportchars

View File

@ -1177,3 +1177,32 @@ def test_collectignore_via_conftest(testdir, monkeypatch):
result = testdir.runpytest() result = testdir.runpytest()
assert result.ret == EXIT_NOTESTSCOLLECTED assert result.ret == EXIT_NOTESTSCOLLECTED
def test_collect_pkg_init_and_file_in_args(testdir):
subdir = testdir.mkdir("sub")
init = subdir.ensure("__init__.py")
init.write("def test_init(): pass")
p = subdir.ensure("test_file.py")
p.write("def test_file(): pass")
# NOTE: without "-o python_files=*.py" this collects test_file.py twice.
# This changed/broke with "Add package scoped fixtures #2283" (2b1410895)
# initially (causing a RecursionError).
result = testdir.runpytest("-v", str(init), str(p))
result.stdout.fnmatch_lines(
[
"sub/test_file.py::test_file PASSED*",
"sub/test_file.py::test_file PASSED*",
"*2 passed in*",
]
)
result = testdir.runpytest("-v", "-o", "python_files=*.py", str(init), str(p))
result.stdout.fnmatch_lines(
[
"sub/__init__.py::test_init PASSED*",
"sub/test_file.py::test_file PASSED*",
"*2 passed in*",
]
)

View File

@ -244,6 +244,42 @@ def test_conftest_symlink(testdir):
assert result.ret == EXIT_OK assert result.ret == EXIT_OK
@pytest.mark.skipif(
not hasattr(py.path.local, "mksymlinkto"),
reason="symlink not available on this platform",
)
def test_conftest_symlink_files(testdir):
"""Check conftest.py loading when running in directory with symlinks."""
real = testdir.tmpdir.mkdir("real")
source = {
"app/test_foo.py": "def test1(fixture): pass",
"app/__init__.py": "",
"app/conftest.py": textwrap.dedent(
"""
import pytest
print("conftest_loaded")
@pytest.fixture
def fixture():
print("fixture_used")
"""
),
}
testdir.makepyfile(**{"real/%s" % k: v for k, v in source.items()})
# Create a build directory that contains symlinks to actual files
# but doesn't symlink actual directories.
build = testdir.tmpdir.mkdir("build")
build.mkdir("app")
for f in source:
build.join(f).mksymlinkto(real.join(f))
build.chdir()
result = testdir.runpytest("-vs", "app/test_foo.py")
result.stdout.fnmatch_lines(["*conftest_loaded*", "PASSED"])
assert result.ret == EXIT_OK
def test_no_conftest(testdir): def test_no_conftest(testdir):
testdir.makeconftest("assert 0") testdir.makeconftest("assert 0")
result = testdir.runpytest("--noconftest") result = testdir.runpytest("--noconftest")

View File

@ -513,6 +513,76 @@ class TestPDB(object):
assert "1 failed" in rest assert "1 failed" in rest
self.flush(child) self.flush(child)
def test_pdb_interaction_continue_recursive(self, testdir):
p1 = testdir.makepyfile(
mytest="""
import pdb
import pytest
count_continue = 0
# Simulates pdbpp, which injects Pdb into do_debug, and uses
# self.__class__ in do_continue.
class CustomPdb(pdb.Pdb, object):
def do_debug(self, arg):
import sys
import types
newglobals = {
'Pdb': self.__class__, # NOTE: different with pdb.Pdb
'sys': sys,
}
if sys.version_info < (3, ):
do_debug_func = pdb.Pdb.do_debug.im_func
else:
do_debug_func = pdb.Pdb.do_debug
orig_do_debug = types.FunctionType(
do_debug_func.__code__, newglobals,
do_debug_func.__name__, do_debug_func.__defaults__,
)
return orig_do_debug(self, arg)
do_debug.__doc__ = pdb.Pdb.do_debug.__doc__
def do_continue(self, *args, **kwargs):
global count_continue
count_continue += 1
return super(CustomPdb, self).do_continue(*args, **kwargs)
def foo():
print("print_from_foo")
def test_1():
i = 0
print("hello17")
pytest.set_trace()
x = 3
print("hello18")
assert count_continue == 2, "unexpected_failure: %d != 2" % count_continue
pytest.fail("expected_failure")
"""
)
child = testdir.spawn_pytest("--pdbcls=mytest:CustomPdb %s" % str(p1))
child.expect(r"PDB set_trace \(IO-capturing turned off\)")
child.expect(r"\n\(Pdb")
child.sendline("debug foo()")
child.expect("ENTERING RECURSIVE DEBUGGER")
child.expect(r"\n\(\(Pdb")
child.sendline("c")
child.expect("LEAVING RECURSIVE DEBUGGER")
assert b"PDB continue" not in child.before
assert b"print_from_foo" in child.before
child.sendline("c")
child.expect(r"PDB continue \(IO-capturing resumed\)")
rest = child.read().decode("utf8")
assert "hello17" in rest # out is captured
assert "hello18" in rest # out is captured
assert "1 failed" in rest
assert "Failed: expected_failure" in rest
assert "AssertionError: unexpected_failure" not in rest
self.flush(child)
def test_pdb_without_capture(self, testdir): def test_pdb_without_capture(self, testdir):
p1 = testdir.makepyfile( p1 = testdir.makepyfile(
""" """

23
tox.ini
View File

@ -1,6 +1,6 @@
[tox] [tox]
isolated_build = True isolated_build = True
minversion = 3.3 minversion = 3.5.3
distshare = {homedir}/.tox/distshare distshare = {homedir}/.tox/distshare
# make sure to update environment list in travis.yml and appveyor.yml # make sure to update environment list in travis.yml and appveyor.yml
envlist = envlist =
@ -23,10 +23,11 @@ commands =
{env:_PYTEST_TOX_COVERAGE_RUN:} pytest {env:_PYTEST_TOX_ARGS:} {posargs} {env:_PYTEST_TOX_COVERAGE_RUN:} pytest {env:_PYTEST_TOX_ARGS:} {posargs}
coverage: coverage combine coverage: coverage combine
coverage: coverage report coverage: coverage report
passenv = USER USERNAME COVERAGE_* TRAVIS passenv = USER USERNAME COVERAGE_* TRAVIS PYTEST_ADDOPTS
setenv = setenv =
_PYTEST_TOX_ARGS=--lsof _PYTEST_TOX_ARGS=--lsof
# configuration if a user runs tox with a "coverage" factor, for example "tox -e py37-coverage" # Configuration to run with coverage similar to Travis/Appveyor, e.g.
# "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
@ -55,8 +56,8 @@ commands = pre-commit run --all-files --show-diff-on-failure
[testenv:py27-pexpect] [testenv:py27-pexpect]
platform = linux|darwin platform = linux|darwin
deps = deps =
{[testenv]deps}
pexpect pexpect
{env:_PYTEST_TOX_EXTRA_DEP:}
commands = commands =
{env:_PYTEST_TOX_COVERAGE_RUN:} pytest {posargs:testing/test_pdb.py testing/test_terminal.py testing/test_unittest.py} {env:_PYTEST_TOX_COVERAGE_RUN:} pytest {posargs:testing/test_pdb.py testing/test_terminal.py testing/test_unittest.py}
@ -68,8 +69,8 @@ commands = {[testenv:py27-pexpect]commands}
[testenv:py27-nobyte] [testenv:py27-nobyte]
extras = testing extras = testing
deps = deps =
{[testenv]deps}
pytest-xdist>=1.13 pytest-xdist>=1.13
{env:_PYTEST_TOX_EXTRA_DEP:}
distribute = true distribute = true
setenv = setenv =
{[testenv]setenv} {[testenv]setenv}
@ -79,8 +80,8 @@ commands =
[testenv:py27-trial] [testenv:py27-trial]
deps = deps =
{[testenv]deps}
twisted twisted
{env:_PYTEST_TOX_EXTRA_DEP:}
commands = commands =
{env:_PYTEST_TOX_COVERAGE_RUN:} pytest {posargs:testing/test_unittest.py} {env:_PYTEST_TOX_COVERAGE_RUN:} pytest {posargs:testing/test_unittest.py}
@ -90,8 +91,8 @@ commands = {[testenv:py27-trial]commands}
[testenv:py27-numpy] [testenv:py27-numpy]
deps = deps =
{[testenv]deps}
numpy numpy
{env:_PYTEST_TOX_EXTRA_DEP:}
commands= commands=
{env:_PYTEST_TOX_COVERAGE_RUN:} pytest {posargs:testing/python/approx.py} {env:_PYTEST_TOX_COVERAGE_RUN:} pytest {posargs:testing/python/approx.py}
@ -103,11 +104,13 @@ commands = {[testenv:py27-numpy]commands}
setenv= setenv=
{[testenv]setenv} {[testenv]setenv}
_PYTEST_SETUP_SKIP_PLUGGY_DEP=1 _PYTEST_SETUP_SKIP_PLUGGY_DEP=1
# NOTE: using env instead of "{[testenv]deps}", because of https://github.com/tox-dev/tox/issues/706. deps =
_PYTEST_TOX_EXTRA_DEP=git+https://github.com/pytest-dev/pluggy.git@master {[testenv]deps}
git+https://github.com/pytest-dev/pluggy.git@master
[testenv:py37-pluggymaster] [testenv:py37-pluggymaster]
setenv = {[testenv:py27-pluggymaster]setenv} setenv = {[testenv:py27-pluggymaster]setenv}
deps = {[testenv:py27-pluggymaster]deps}
[testenv:docs] [testenv:docs]
basepython = python3 basepython = python3
@ -123,8 +126,8 @@ commands =
basepython = python3 basepython = python3
skipsdist = True skipsdist = True
deps = deps =
{[testenv]deps}
PyYAML PyYAML
{env:_PYTEST_TOX_EXTRA_DEP:}
commands = commands =
{env:_PYTEST_TOX_COVERAGE_RUN:} pytest doc/en {env:_PYTEST_TOX_COVERAGE_RUN:} pytest doc/en
{env:_PYTEST_TOX_COVERAGE_RUN:} pytest --doctest-modules --pyargs _pytest {env:_PYTEST_TOX_COVERAGE_RUN:} pytest --doctest-modules --pyargs _pytest