Skip to content

Commit

Permalink
add option to view failure stacktraces
Browse files Browse the repository at this point in the history
Signed-off-by: Bernat Gabor <bgabor8@bloomberg.net>
  • Loading branch information
gaborbernat committed Feb 11, 2020
1 parent f8afe88 commit 6efd327
Show file tree
Hide file tree
Showing 6 changed files with 33 additions and 18 deletions.
2 changes: 2 additions & 0 deletions docs/changelog/1572.feature.rst
@@ -0,0 +1,2 @@
Add a CLI flag :option:`with-traceback` that allows displaying the stacktrace of the virtualenv when a failure occurs
- by :user:`gaborbernat`.
16 changes: 11 additions & 5 deletions src/virtualenv/__main__.py
@@ -1,19 +1,20 @@
from __future__ import absolute_import, print_function, unicode_literals

import argparse
import logging
import sys
from datetime import datetime


def run(args=None):
def run(args=None, options=None):
start = datetime.now()
from virtualenv.error import ProcessCallFailed
from virtualenv.run import run_via_cli

if args is None:
args = sys.argv[1:]
try:
run_via_cli(args)
run_via_cli(args, options)
except ProcessCallFailed as exception:
print("subprocess call failed for {}".format(exception.cmd))
print(exception.out, file=sys.stdout, end="")
Expand All @@ -24,11 +25,16 @@ def run(args=None):


def run_with_catch(args=None):
options = argparse.Namespace()
try:
run(args)
run(args, options)
except (KeyboardInterrupt, Exception) as exception:
logging.error("%s: %s", type(exception).__name__, exception)
sys.exit(1)
if options.with_traceback:
logging.shutdown() # force flush of log messages before the trace is printed
raise
else:
logging.error("%s: %s", type(exception).__name__, exception)
sys.exit(1)


if __name__ == "__main__":
Expand Down
4 changes: 2 additions & 2 deletions src/virtualenv/config/cli/parser.py
Expand Up @@ -11,7 +11,7 @@ class VirtualEnvConfigParser(ArgumentParser):
Custom option parser which updates its defaults by checking the configuration files and environmental variables
"""

def __init__(self, *args, **kwargs):
def __init__(self, options=None, *args, **kwargs):
self.file_config = IniConfig()
self.epilog_list = []
kwargs["epilog"] = self.file_config.epilog
Expand All @@ -22,7 +22,7 @@ def __init__(self, *args, **kwargs):
self._fixed = set()
self._elements = None
self._verbosity = None
self._options = None
self._options = options
self._interpreter = None

def _fix_defaults(self):
Expand Down
21 changes: 14 additions & 7 deletions src/virtualenv/run/__init__.py
Expand Up @@ -12,30 +12,37 @@
from .plugin.seeders import SeederSelector


def run_via_cli(args):
def run_via_cli(args, options=None):
"""Run the virtual environment creation via CLI arguments
:param args: the command line arguments
:return: the creator used
"""
session = session_via_cli(args)
session = session_via_cli(args, options)
session.run()
return session


# noinspection PyProtectedMember
def session_via_cli(args):
parser = build_parser(args)
def session_via_cli(args, options=None):
parser = build_parser(args, options)
parser.parse_args(args, namespace=parser._options)
creator, seeder, activators = tuple(e.create(parser._options) for e in parser._elements) # create types
session = Session(parser._verbosity, parser._interpreter, creator, seeder, activators)
return session


# noinspection PyProtectedMember
def build_parser(args=None):
parser = VirtualEnvConfigParser()
def build_parser(args=None, options=None):
parser = VirtualEnvConfigParser(options)
add_version_flag(parser)
parser.add_argument(
"--with-traceback",
dest="with_traceback",
action="store_true",
default=False,
help="on failure also display the stacktrace internals of virtualenv",
)
parser._options, parser._verbosity = _do_report_setup(parser, args)
discover = get_discover(parser, args, parser._options)
parser._interpreter = interpreter = discover.interpreter
Expand Down Expand Up @@ -73,6 +80,6 @@ def _do_report_setup(parser, args):
verbosity = verbosity_group.add_mutually_exclusive_group()
verbosity.add_argument("-v", "--verbose", action="count", dest="verbose", help="increase verbosity", default=2)
verbosity.add_argument("-q", "--quiet", action="count", dest="quiet", help="decrease verbosity", default=0)
options, _ = parser.parse_known_args(args)
options, _ = parser.parse_known_args(args, namespace=parser._options)
verbosity_value = setup_report(options.verbose, options.quiet)
return options, verbosity_value
4 changes: 2 additions & 2 deletions tests/conftest.py
Expand Up @@ -182,8 +182,8 @@ def coverage_env(monkeypatch, link):
# we inject right after creation, we cannot collect coverage on site.py - used for helper scripts, such as debug
from virtualenv import run

def via_cli(args):
session = prev_run(args)
def via_cli(args, options=None):
session = prev_run(args, options)
old_run = session.creator.run

def create_run():
Expand Down
4 changes: 2 additions & 2 deletions tests/unit/create/test_creator.py
Expand Up @@ -174,8 +174,8 @@ def list_to_str(iterable):

@pytest.mark.skipif(not CURRENT.has_venv, reason="requires interpreter with venv")
def test_venv_fails_not_inline(tmp_path, capsys, mocker):
def _session_via_cli(args):
session = session_via_cli(args)
def _session_via_cli(args, options=None):
session = session_via_cli(args, options)
assert session.creator.can_be_inline is False
return session

Expand Down

0 comments on commit 6efd327

Please sign in to comment.