Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Move options for verbosity and tracebacks to main plugin #408

Open
wants to merge 5 commits into
base: my-master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/_pytest/config/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -857,7 +857,7 @@ def pytest_cmdline_parse(self, args: "List[str]") -> "Config":
return self

def notify_exception(self, excinfo, option=None):
if option and getattr(option, "fulltrace", False):
if getattr(option, "fulltrace", False):
style = "long"
else:
style = "native"
Expand Down
81 changes: 81 additions & 0 deletions src/_pytest/main.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
""" core implementation of testing process: init, session, runtest loop. """
import argparse
import fnmatch
import functools
import importlib
Expand Down Expand Up @@ -41,6 +42,24 @@
from _pytest.python import Package


class MoreQuietAction(argparse._CountAction):
"""Count down and update the legacy `quiet` attribute.

Used to unify verbosity handling."""

def __call__(
self,
parser: argparse.ArgumentParser,
namespace: argparse.Namespace,
values: Union[str, Sequence[object], None],
option_string: Optional[str] = None,
) -> None:
new_count = getattr(namespace, self.dest, 0) - 1
setattr(namespace, self.dest, new_count)
# TODO(Ronny Pfannschmidt): Deprecate config.quiet.
namespace.quiet = getattr(namespace, "quiet", 0) + 1


def pytest_addoption(parser):
parser.addini(
"norecursedirs",
Expand All @@ -55,7 +74,31 @@ def pytest_addoption(parser):
type="args",
default=[],
)

group = parser.getgroup("general", "running and selection options")
group._addoption(
"-v",
"--verbose",
action="count",
default=0,
dest="verbose",
help="increase verbosity.",
)
group._addoption(
"-q",
"--quiet",
action=MoreQuietAction,
default=0,
dest="verbose",
help="decrease verbosity.",
)
group._addoption(
"--verbosity",
dest="verbose",
type=int,
default=0,
help="set verbosity. Default is 0.",
)
group._addoption(
"-x",
"--exitfirst",
Expand Down Expand Up @@ -166,6 +209,44 @@ def pytest_addoption(parser):
help="Don't ignore tests in a local virtualenv directory",
)

group = parser.getgroup("tracebacks", "Traceback formatting")
group._addoption(
"--tb",
metavar="style",
action="store",
dest="tbstyle",
default="auto",
choices=["auto", "long", "short", "no", "line", "native"],
help=(
"traceback print mode (auto/long/short/line/native/no):\n"
" - auto (default): 'long' tracebacks for the first and last entry,"
" but 'short' style for the other entries\n"
" - long: exhaustive, informative traceback formatting\n"
" - short: shorter traceback format\n"
" - line: only one line per failure\n"
" - native: Python standard library formatting\n"
" - no: no traceback at all\n"
),
)
group._addoption(
"--fulltrace",
"--full-trace",
action="store_true",
default=False,
help=(
"don't cut any tracebacks (default is to cut). "
"When used `-tb` defaults to 'long'."
),
)
group._addoption(
"-l",
"--showlocals",
action="store_true",
dest="showlocals",
default=False,
help="show locals in tracebacks (disabled by default).",
)

group = parser.getgroup("debugconfig", "test session debugging and configuration")
group.addoption(
"--basetemp",
Expand Down
14 changes: 5 additions & 9 deletions src/_pytest/nodes.py
Original file line number Diff line number Diff line change
Expand Up @@ -324,7 +324,7 @@ def _repr_failure_py(
excinfo: ExceptionInfo[Union[Failed, FixtureLookupError]],
default_style: "_TracebackStyle" = None,
) -> Union[str, ReprExceptionInfo, ExceptionChainRepr, FixtureLookupErrorRepr]:
fulltrace = self.config.getoption("fulltrace", False)
fulltrace = self.config.option.fulltrace
if (
not fulltrace
and isinstance(excinfo.value, fail.Exception)
Expand All @@ -336,7 +336,8 @@ def _repr_failure_py(

# XXX should excinfo.getrepr record all data and toterminal() process it?
# XXX: does not distinguish between default/unset and --tb=auto.
tbstyle = self.config.getoption("tbstyle", "auto")
tbstyle = self.config.option.tbstyle
verbosity = self.config.option.verbose
if fulltrace:
style = "long" if tbstyle == "auto" else tbstyle # type: _TracebackStyle
else:
Expand All @@ -349,11 +350,6 @@ def _repr_failure_py(
style = tbstyle
self._prunetraceback(excinfo)

if self.config.getoption("verbose", 0) > 1:
truncate_locals = False
else:
truncate_locals = True

try:
os.getcwd()
abspath = False
Expand All @@ -363,10 +359,10 @@ def _repr_failure_py(
return excinfo.getrepr(
funcargs=True,
abspath=abspath,
showlocals=self.config.getoption("showlocals", False),
showlocals=self.config.option.showlocals,
style=style,
tbfilter=False, # pruned already, or in --fulltrace mode.
truncate_locals=truncate_locals,
truncate_locals=verbosity < 2,
)

def repr_failure(
Expand Down
39 changes: 19 additions & 20 deletions src/_pytest/python.py
Original file line number Diff line number Diff line change
Expand Up @@ -1501,27 +1501,26 @@ def setup(self) -> None:
fixtures.fillfixtures(self)

def _prunetraceback(self, excinfo: ExceptionInfo) -> None:
if hasattr(self, "_obj") and not self.config.getoption("fulltrace", False):
code = _pytest._code.Code(get_real_func(self.obj))
path, firstlineno = code.path, code.firstlineno
traceback = excinfo.traceback
ntraceback = traceback.cut(path=path, firstlineno=firstlineno)
code = _pytest._code.Code(get_real_func(self.obj))
path, firstlineno = code.path, code.firstlineno
traceback = excinfo.traceback
ntraceback = traceback.cut(path=path, firstlineno=firstlineno)
if ntraceback == traceback:
ntraceback = ntraceback.cut(path=path)
if ntraceback == traceback:
ntraceback = ntraceback.cut(path=path)
if ntraceback == traceback:
ntraceback = ntraceback.filter(filter_traceback)
if not ntraceback:
ntraceback = traceback

ntraceback = ntraceback.filter()
if ntraceback:
excinfo.traceback = ntraceback
# issue364: mark all but first and last frames to
# only show a single-line message for each frame
if self.config.getoption("tbstyle", "auto") == "auto":
if len(excinfo.traceback) > 2:
for entry in excinfo.traceback[1:-1]:
entry.set_repr_style("short")
ntraceback = ntraceback.filter(filter_traceback)
if not ntraceback:
ntraceback = traceback

ntraceback = ntraceback.filter()
if ntraceback:
excinfo.traceback = ntraceback
# issue364: mark all but first and last frames to
# only show a single-line message for each frame
if self.config.option.tbstyle == "auto":
if len(excinfo.traceback) > 2:
for entry in excinfo.traceback[1:-1]:
entry.set_repr_style("short")

def repr_failure(self, excinfo, outerr=None):
assert outerr is None, "XXX outerr usage is deprecated"
Expand Down
87 changes: 1 addition & 86 deletions src/_pytest/terminal.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

This is a good source for looking at the various reporting hooks.
"""
import argparse
import datetime
import inspect
import linecache
Expand Down Expand Up @@ -148,56 +147,8 @@ def _clear_cache_on_sigwinch(signum: int, frame: FrameType) -> None:
return _cached_terminal_width


class MoreQuietAction(argparse.Action):
"""
a modified copy of the argparse count action which counts down and updates
the legacy quiet attribute at the same time

used to unify verbosity handling
"""

def __init__(self, option_strings, dest, default=None, required=False, help=None):
super().__init__(
option_strings=option_strings,
dest=dest,
nargs=0,
default=default,
required=required,
help=help,
)

def __call__(self, parser, namespace, values, option_string=None):
new_count = getattr(namespace, self.dest, 0) - 1
setattr(namespace, self.dest, new_count)
# todo Deprecate config.quiet
namespace.quiet = getattr(namespace, "quiet", 0) + 1


def pytest_addoption(parser):
group = parser.getgroup("terminal reporting", "reporting", after="general")
group._addoption(
"-v",
"--verbose",
action="count",
default=0,
dest="verbose",
help="increase verbosity.",
)
group._addoption(
"-q",
"--quiet",
action=MoreQuietAction,
default=0,
dest="verbose",
help="decrease verbosity.",
)
group._addoption(
"--verbosity",
dest="verbose",
type=int,
default=0,
help="set verbosity. Default is 0.",
)
group._addoption(
"-r",
action="store",
Expand All @@ -218,32 +169,6 @@ def pytest_addoption(parser):
action="store_true",
help="disable warnings summary",
)
group._addoption(
"-l",
"--showlocals",
action="store_true",
dest="showlocals",
default=False,
help="show locals in tracebacks (disabled by default).",
)
group._addoption(
"--tb",
metavar="style",
action="store",
dest="tbstyle",
default="auto",
choices=["auto", "long", "short", "no", "line", "native"],
help=(
"traceback print mode (auto/long/short/line/native/no):\n"
" - auto (default): 'long' tracebacks for the first and last entry,"
" but 'short' style for the other entries\n"
" - long: exhaustive, informative traceback formatting\n"
" - short: shorter traceback format\n"
" - line: only one line per failure\n"
" - native: Python standard library formatting\n"
" - no: no traceback at all\n"
),
)
group._addoption(
"--show-capture",
action="store",
Expand All @@ -253,16 +178,6 @@ def pytest_addoption(parser):
help="Controls how captured stdout/stderr/log is shown on failed tests. "
"Default is 'all'.",
)
group._addoption(
"--fulltrace",
"--full-trace",
action="store_true",
default=False,
help=(
"don't cut any tracebacks (default is to cut). "
"When used `-tb` defaults to 'long'."
),
)
group._addoption(
"--color",
metavar="color",
Expand Down Expand Up @@ -973,7 +888,7 @@ def pytest_terminal_summary(self):
self.summary_warnings()

def pytest_keyboard_interrupt(self, excinfo: ExceptionInfo) -> None:
tbstyle = self.config.getoption("tbstyle", "auto")
tbstyle = self.config.option.tbstyle
style = "long" if tbstyle == "auto" else tbstyle # type: _TracebackStyle
self._keyboardinterrupt_memo = excinfo.getrepr(funcargs=True, style=style)

Expand Down
15 changes: 15 additions & 0 deletions testing/test_main.py
Original file line number Diff line number Diff line change
Expand Up @@ -139,3 +139,18 @@ def test_collect_ignores_hidden_file(testdir: Testdir) -> None:
testdir.makepyfile(**{"tests/.test_hidden@meh.py": "def test(): assert 0"})
result = testdir.runpytest("-o", "python_files=tests/*.py")
assert result.ret == ExitCode.NO_TESTS_COLLECTED


def test_options_without_essential_plugins(testdir: Testdir) -> None:
testdir.makepyfile(
"""
def test_options(request):
assert request.config.option.verbose == 0

assert request.config.option.fulltrace is False
assert request.config.option.showlocals is False
assert request.config.option.tbstyle == "auto"
"""
)
result = testdir.runpytest("-p", "no:[defaults]", "-p", "python")
assert result.ret == 0