Merge master into features

Conflicts:
	tox.ini
This commit is contained in:
Daniel Hahler
2019-02-13 17:58:16 +01:00
29 changed files with 373 additions and 67 deletions

View File

@@ -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

View File

@@ -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
)

View File

@@ -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

View File

@@ -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)

View File

@@ -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:

View File

@@ -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):

View File

@@ -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