commit
7b91952645
|
@ -45,3 +45,6 @@ coverage.xml
|
|||
.project
|
||||
.settings
|
||||
.vscode
|
||||
|
||||
# generated by pip
|
||||
pip-wheel-metadata/
|
||||
|
|
|
@ -17,10 +17,10 @@ env:
|
|||
# Specialized factors for py27.
|
||||
- TOXENV=py27-nobyte
|
||||
- TOXENV=py27-xdist
|
||||
- TOXENV=py27-pluggymaster PYTEST_NO_COVERAGE=1
|
||||
- TOXENV=py27-pluggymaster
|
||||
# Specialized factors for py37.
|
||||
- TOXENV=py37-pexpect,py37-trial,py37-numpy
|
||||
- TOXENV=py37-pluggymaster PYTEST_NO_COVERAGE=1
|
||||
- TOXENV=py37-pluggymaster
|
||||
- TOXENV=py37-freeze PYTEST_NO_COVERAGE=1
|
||||
|
||||
matrix:
|
||||
|
|
|
@ -18,6 +18,62 @@ with advance notice in the **Deprecations** section of releases.
|
|||
|
||||
.. 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)
|
||||
=========================
|
||||
|
||||
|
|
|
@ -11,11 +11,9 @@ environment:
|
|||
# Specialized factors for py27.
|
||||
- TOXENV: "py27-trial,py27-numpy,py27-nobyte"
|
||||
- TOXENV: "py27-pluggymaster"
|
||||
PYTEST_NO_COVERAGE: "1"
|
||||
# Specialized factors for py37.
|
||||
- TOXENV: "py37-trial,py37-numpy"
|
||||
- TOXENV: "py37-pluggymaster"
|
||||
PYTEST_NO_COVERAGE: "1"
|
||||
- TOXENV: "py37-freeze"
|
||||
PYTEST_NO_COVERAGE: "1"
|
||||
|
||||
|
|
|
@ -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()
|
|
@ -1 +0,0 @@
|
|||
The ``pytest_report_collectionfinish`` hook now is also called with ``--collect-only``.
|
|
@ -1 +0,0 @@
|
|||
Do not raise ``UsageError`` when an imported package has a ``pytest_plugins.py`` child module.
|
|
@ -1 +0,0 @@
|
|||
Add note to ``plugins.rst`` that ``pytest_plugins`` should not be used as a name for a user module containing plugins.
|
|
@ -1 +0,0 @@
|
|||
Document how to use ``raises`` and ``does_not_raise`` to write parametrized tests with conditional raises.
|
|
@ -1 +0,0 @@
|
|||
Fix handling of ``collect_ignore`` via parent ``conftest.py``.
|
|
@ -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.
|
|
@ -1,2 +0,0 @@
|
|||
Document how to customize test failure messages when using
|
||||
``pytest.warns``.
|
|
@ -1 +0,0 @@
|
|||
Fix ``parametrize(... ids=<function>)`` when the function returns non-strings.
|
|
@ -6,6 +6,7 @@ Release announcements
|
|||
:maxdepth: 2
|
||||
|
||||
|
||||
release-4.2.1
|
||||
release-4.2.0
|
||||
release-4.1.1
|
||||
release-4.1.0
|
||||
|
|
|
@ -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
|
|
@ -205,8 +205,8 @@ Special comparisons are done for a number of cases:
|
|||
|
||||
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
|
||||
the ``pytest_assertrepr_compare`` hook.
|
||||
|
|
|
@ -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
|
||||
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
|
||||
|
||||
|
|
3
setup.py
3
setup.py
|
@ -10,7 +10,8 @@ INSTALL_REQUIRES = [
|
|||
"six>=1.10.0",
|
||||
"setuptools",
|
||||
"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",
|
||||
'funcsigs;python_version<"3.0"',
|
||||
'pathlib2>=2.2.0;python_version<"3.6"',
|
||||
|
|
|
@ -408,7 +408,10 @@ class PytestPluginManager(PluginManager):
|
|||
continue
|
||||
conftestpath = parent.join("conftest.py")
|
||||
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)
|
||||
self._dirpath2confmods[directory] = clist
|
||||
return clist
|
||||
|
|
|
@ -75,6 +75,7 @@ class pytestPDB(object):
|
|||
_config = None
|
||||
_pdb_cls = pdb.Pdb
|
||||
_saved = []
|
||||
_recursive_debug = 0
|
||||
|
||||
@classmethod
|
||||
def _init_pdb(cls, *args, **kwargs):
|
||||
|
@ -87,29 +88,37 @@ class pytestPDB(object):
|
|||
capman.suspend_global_capture(in_=True)
|
||||
tw = _pytest.config.create_terminal_writer(cls._config)
|
||||
tw.line()
|
||||
# Handle header similar to pdb.set_trace in py37+.
|
||||
header = kwargs.pop("header", None)
|
||||
if header is not None:
|
||||
tw.sep(">", header)
|
||||
elif capman and capman.is_globally_capturing():
|
||||
tw.sep(">", "PDB set_trace (IO-capturing turned off)")
|
||||
else:
|
||||
tw.sep(">", "PDB set_trace")
|
||||
if cls._recursive_debug == 0:
|
||||
# Handle header similar to pdb.set_trace in py37+.
|
||||
header = kwargs.pop("header", None)
|
||||
if header is not None:
|
||||
tw.sep(">", header)
|
||||
elif capman and capman.is_globally_capturing():
|
||||
tw.sep(">", "PDB set_trace (IO-capturing turned off)")
|
||||
else:
|
||||
tw.sep(">", "PDB set_trace")
|
||||
|
||||
class _PdbWrapper(cls._pdb_cls, object):
|
||||
_pytest_capman = capman
|
||||
_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):
|
||||
ret = super(_PdbWrapper, self).do_continue(arg)
|
||||
if self._pytest_capman:
|
||||
tw = _pytest.config.create_terminal_writer(cls._config)
|
||||
tw.line()
|
||||
if self._pytest_capman.is_globally_capturing():
|
||||
tw.sep(">", "PDB continue (IO-capturing resumed)")
|
||||
else:
|
||||
tw.sep(">", "PDB continue")
|
||||
self._pytest_capman.resume_global_capture()
|
||||
if cls._recursive_debug == 0:
|
||||
if self._pytest_capman.is_globally_capturing():
|
||||
tw.sep(">", "PDB continue (IO-capturing resumed)")
|
||||
else:
|
||||
tw.sep(">", "PDB continue")
|
||||
self._pytest_capman.resume_global_capture()
|
||||
cls._pluginmanager.hook.pytest_leave_pdb(
|
||||
config=cls._config, pdb=self
|
||||
)
|
||||
|
|
|
@ -4,6 +4,7 @@ from __future__ import print_function
|
|||
|
||||
import functools
|
||||
import inspect
|
||||
import itertools
|
||||
import sys
|
||||
import warnings
|
||||
from collections import defaultdict
|
||||
|
@ -13,7 +14,6 @@ from collections import OrderedDict
|
|||
import attr
|
||||
import py
|
||||
import six
|
||||
from more_itertools import flatten
|
||||
|
||||
import _pytest
|
||||
from _pytest import nodes
|
||||
|
@ -1109,7 +1109,7 @@ class FixtureManager(object):
|
|||
argnames = getfuncargnames(func, cls=cls)
|
||||
else:
|
||||
argnames = ()
|
||||
usefixtures = flatten(
|
||||
usefixtures = itertools.chain.from_iterable(
|
||||
mark.args for mark in node.iter_markers(name="usefixtures")
|
||||
)
|
||||
initialnames = tuple(usefixtures) + argnames
|
||||
|
|
|
@ -435,13 +435,6 @@ class LoggingPlugin(object):
|
|||
# terminal reporter is disabled e.g. by pytest-xdist.
|
||||
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")
|
||||
# if capturemanager plugin is disabled, live logging still works.
|
||||
log_cli_handler = _LiveLoggingStreamHandler(terminal_reporter, capture_manager)
|
||||
|
|
|
@ -571,19 +571,9 @@ class Session(nodes.FSCollector):
|
|||
if argpath.check(dir=1):
|
||||
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()
|
||||
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()
|
||||
if dirpath not in seen_dirs:
|
||||
|
@ -613,7 +603,7 @@ class Session(nodes.FSCollector):
|
|||
col = self._node_cache[argpath]
|
||||
else:
|
||||
collect_root = self._pkg_roots.get(argpath.dirname, self)
|
||||
col = collect_root._collectfile(argpath)
|
||||
col = collect_root._collectfile(argpath, handle_dupes=False)
|
||||
if col:
|
||||
self._node_cache[argpath] = col
|
||||
m = self.matchnodes(col, names)
|
||||
|
@ -658,6 +648,18 @@ class Session(nodes.FSCollector):
|
|||
ihook.pytest_collect_directory(path=dirpath, parent=self)
|
||||
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):
|
||||
"""Convert a dotted module name to path."""
|
||||
try:
|
||||
|
|
|
@ -81,7 +81,11 @@ class LsofFdLeakChecker(object):
|
|||
|
||||
def _exec_lsof(self):
|
||||
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 isopen(line):
|
||||
|
|
|
@ -222,12 +222,9 @@ class TerminalReporter(object):
|
|||
import _pytest.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._session = None
|
||||
self._showfspath = None
|
||||
|
||||
self.stats = {}
|
||||
self.startdir = py.path.local()
|
||||
|
@ -255,6 +252,28 @@ class TerminalReporter(object):
|
|||
return False
|
||||
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):
|
||||
char = {"xfailed": "x", "skipped": "s"}.get(char, char)
|
||||
return char in self.reportchars
|
||||
|
|
|
@ -1177,3 +1177,32 @@ def test_collectignore_via_conftest(testdir, monkeypatch):
|
|||
|
||||
result = testdir.runpytest()
|
||||
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*",
|
||||
]
|
||||
)
|
||||
|
|
|
@ -244,6 +244,42 @@ def test_conftest_symlink(testdir):
|
|||
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):
|
||||
testdir.makeconftest("assert 0")
|
||||
result = testdir.runpytest("--noconftest")
|
||||
|
|
|
@ -513,6 +513,76 @@ class TestPDB(object):
|
|||
assert "1 failed" in rest
|
||||
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):
|
||||
p1 = testdir.makepyfile(
|
||||
"""
|
||||
|
|
23
tox.ini
23
tox.ini
|
@ -1,6 +1,6 @@
|
|||
[tox]
|
||||
isolated_build = True
|
||||
minversion = 3.3
|
||||
minversion = 3.5.3
|
||||
distshare = {homedir}/.tox/distshare
|
||||
# make sure to update environment list in travis.yml and appveyor.yml
|
||||
envlist =
|
||||
|
@ -23,10 +23,11 @@ commands =
|
|||
{env:_PYTEST_TOX_COVERAGE_RUN:} pytest {env:_PYTEST_TOX_ARGS:} {posargs}
|
||||
coverage: coverage combine
|
||||
coverage: coverage report
|
||||
passenv = USER USERNAME COVERAGE_* TRAVIS
|
||||
passenv = USER USERNAME COVERAGE_* TRAVIS PYTEST_ADDOPTS
|
||||
setenv =
|
||||
_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_EXTRA_DEP=coverage-enable-subprocess
|
||||
coverage: COVERAGE_FILE={toxinidir}/.coverage
|
||||
|
@ -55,8 +56,8 @@ commands = pre-commit run --all-files --show-diff-on-failure
|
|||
[testenv:py27-pexpect]
|
||||
platform = linux|darwin
|
||||
deps =
|
||||
{[testenv]deps}
|
||||
pexpect
|
||||
{env:_PYTEST_TOX_EXTRA_DEP:}
|
||||
commands =
|
||||
{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]
|
||||
extras = testing
|
||||
deps =
|
||||
{[testenv]deps}
|
||||
pytest-xdist>=1.13
|
||||
{env:_PYTEST_TOX_EXTRA_DEP:}
|
||||
distribute = true
|
||||
setenv =
|
||||
{[testenv]setenv}
|
||||
|
@ -79,8 +80,8 @@ commands =
|
|||
|
||||
[testenv:py27-trial]
|
||||
deps =
|
||||
{[testenv]deps}
|
||||
twisted
|
||||
{env:_PYTEST_TOX_EXTRA_DEP:}
|
||||
commands =
|
||||
{env:_PYTEST_TOX_COVERAGE_RUN:} pytest {posargs:testing/test_unittest.py}
|
||||
|
||||
|
@ -90,8 +91,8 @@ commands = {[testenv:py27-trial]commands}
|
|||
|
||||
[testenv:py27-numpy]
|
||||
deps =
|
||||
{[testenv]deps}
|
||||
numpy
|
||||
{env:_PYTEST_TOX_EXTRA_DEP:}
|
||||
commands=
|
||||
{env:_PYTEST_TOX_COVERAGE_RUN:} pytest {posargs:testing/python/approx.py}
|
||||
|
||||
|
@ -103,11 +104,13 @@ commands = {[testenv:py27-numpy]commands}
|
|||
setenv=
|
||||
{[testenv]setenv}
|
||||
_PYTEST_SETUP_SKIP_PLUGGY_DEP=1
|
||||
# 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
|
||||
deps =
|
||||
{[testenv]deps}
|
||||
git+https://github.com/pytest-dev/pluggy.git@master
|
||||
|
||||
[testenv:py37-pluggymaster]
|
||||
setenv = {[testenv:py27-pluggymaster]setenv}
|
||||
deps = {[testenv:py27-pluggymaster]deps}
|
||||
|
||||
[testenv:docs]
|
||||
basepython = python3
|
||||
|
@ -123,8 +126,8 @@ commands =
|
|||
basepython = python3
|
||||
skipsdist = True
|
||||
deps =
|
||||
{[testenv]deps}
|
||||
PyYAML
|
||||
{env:_PYTEST_TOX_EXTRA_DEP:}
|
||||
commands =
|
||||
{env:_PYTEST_TOX_COVERAGE_RUN:} pytest doc/en
|
||||
{env:_PYTEST_TOX_COVERAGE_RUN:} pytest --doctest-modules --pyargs _pytest
|
||||
|
|
Loading…
Reference in New Issue