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

Allow bypassing the logging setup via the Python API #1904

Merged
merged 1 commit into from
Jul 24, 2020
Merged
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
File renamed without changes.
2 changes: 2 additions & 0 deletions docs/changelog/1896.bugfix.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Provide ``setup_logging`` flag to python API so that users can bypass logging handling if their application already
performs this - by :user:`gaborbernat`.
3 changes: 2 additions & 1 deletion src/virtualenv/__init__.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
from __future__ import absolute_import, unicode_literals

from .run import cli_run
from .run import cli_run, session_via_cli
from .version import __version__

__all__ = (
"__version__",
"cli_run",
"session_via_cli",
)
48 changes: 32 additions & 16 deletions src/virtualenv/run/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,30 +14,39 @@
from .plugin.seeders import SeederSelector


def cli_run(args, options=None):
"""Create a virtual environment given some command line interface arguments
def cli_run(args, options=None, setup_logging=True):
"""
Create a virtual environment given some command line interface arguments.

:param args: the command line arguments
:param options: passing in a ``VirtualEnvOptions`` object allows return of the parsed options
:param setup_logging: ``True`` if setup logging handlers, ``False`` to use handlers already registered
:return: the session object of the creation (its structure for now is experimental and might change on short notice)
"""
session = session_via_cli(args, options)
with session:
session.run()
return session
of_session = session_via_cli(args, options, setup_logging)
with of_session:
of_session.run()
return of_session


def session_via_cli(args, options=None, setup_logging=True):
"""
Create a virtualenv session (same as cli_run, but this does not perform the creation). Use this if you just want to
query what the virtual environment would look like, but not actually create it.

# noinspection PyProtectedMember
def session_via_cli(args, options=None):
parser, elements = build_parser(args, options)
:param args: the command line arguments
:param options: passing in a ``VirtualEnvOptions`` object allows return of the parsed options
:param setup_logging: ``True`` if setup logging handlers, ``False`` to use handlers already registered
:return: the session object of the creation (its structure for now is experimental and might change on short notice)
"""
parser, elements = build_parser(args, options, setup_logging)
options = parser.parse_args(args)
creator, seeder, activators = tuple(e.create(options) for e in elements) # create types
session = Session(options.verbosity, options.app_data, parser._interpreter, creator, seeder, activators)
return session
of_session = Session(options.verbosity, options.app_data, parser._interpreter, creator, seeder, activators) # noqa
return of_session


# noinspection PyProtectedMember
def build_parser(args=None, options=None):
def build_parser(args=None, options=None, setup_logging=True):
parser = VirtualEnvConfigParser(options)
add_version_flag(parser)
parser.add_argument(
Expand All @@ -47,7 +56,7 @@ def build_parser(args=None, options=None):
default=False,
help="on failure also display the stacktrace internals of virtualenv",
)
_do_report_setup(parser, args)
_do_report_setup(parser, args, setup_logging)
options = load_app_data(args, parser, options)
handle_extra_commands(options)

Expand Down Expand Up @@ -121,7 +130,7 @@ def add_version_flag(parser):
)


def _do_report_setup(parser, args):
def _do_report_setup(parser, args, setup_logging):
level_map = ", ".join("{}={}".format(logging.getLevelName(l), c) for c, l in sorted(list(LEVELS.items())))
msg = "verbosity = verbose - quiet, default {}, mapping => {}"
verbosity_group = parser.add_argument_group(
Expand All @@ -131,4 +140,11 @@ def _do_report_setup(parser, args):
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)
option, _ = parser.parse_known_args(args)
setup_report(option.verbosity)
if setup_logging:
setup_report(option.verbosity)


__all__ = (
"cli_run",
"session_via_cli",
)
6 changes: 3 additions & 3 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -196,8 +196,8 @@ def coverage_env(monkeypatch, link, request):
# 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, options):
session = prev_run(args, options)
def _session_via_cli(args, options, setup_logging):
session = prev_run(args, options, setup_logging)
old_run = session.creator.run

def create_run():
Expand All @@ -211,7 +211,7 @@ def create_run():

obj = {"cov": None}
prev_run = run.session_via_cli
monkeypatch.setattr(run, "session_via_cli", via_cli)
monkeypatch.setattr(run, "session_via_cli", _session_via_cli)

def finish():
cov = obj["cov"]
Expand Down
4 changes: 2 additions & 2 deletions tests/unit/config/test___main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ def _func(exception):

prev_session = session_via_cli

def _session_via_cli(args, options=None):
prev_session(args, options)
def _session_via_cli(args, options=None, setup_logging=True):
prev_session(args, options, setup_logging)
raise exception

mocker.patch("virtualenv.run.session_via_cli", side_effect=_session_via_cli)
Expand Down
4 changes: 2 additions & 2 deletions tests/unit/create/test_creator.py
Original file line number Diff line number Diff line change
Expand Up @@ -250,8 +250,8 @@ def test_venv_fails_not_inline(tmp_path, capsys, mocker):
if os.geteuid() == 0:
pytest.skip("no way to check permission restriction when running under root")

def _session_via_cli(args, options=None):
session = session_via_cli(args, options)
def _session_via_cli(args, options=None, setup_logging=True):
session = session_via_cli(args, options, setup_logging)
assert session.creator.can_be_inline is False
return session

Expand Down
15 changes: 14 additions & 1 deletion tests/unit/test_run.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
from __future__ import absolute_import, unicode_literals

import logging

import pytest
import six

from virtualenv import __version__
from virtualenv.run import cli_run
from virtualenv.run import cli_run, session_via_cli


def test_help(capsys):
Expand All @@ -31,3 +33,14 @@ def test_version(capsys):
import virtualenv

assert virtualenv.__file__ in content


@pytest.mark.parametrize("on", [True, False])
def test_logging_setup(caplog, on):
caplog.set_level(logging.DEBUG)
session_via_cli(["env"], setup_logging=on)
# DEBUG only level output is generated during this phase, default output is WARN, so if on no records should be
if on:
assert not caplog.records
else:
assert caplog.records