diff --git a/docs/reference/pip.rst b/docs/reference/pip.rst index 84e95dab26a..c5a1201f581 100644 --- a/docs/reference/pip.rst +++ b/docs/reference/pip.rst @@ -24,7 +24,9 @@ Console logging ~~~~~~~~~~~~~~~ pip offers :ref:`-v, --verbose <--verbose>` and :ref:`-q, --quiet <--quiet>` -to control the console log level. +to control the console log level. By default, some messages (error and warnings) +are colored in the terminal. If you want to suppress the colored output use +:ref:`--no-color <--no-color>`. .. _`FileLogging`: diff --git a/news/2449.feature b/news/2449.feature new file mode 100644 index 00000000000..62410a67ac2 --- /dev/null +++ b/news/2449.feature @@ -0,0 +1,2 @@ +Add `--no-color` to `pip`. All colored output is disabled +if this flag is detected. diff --git a/src/pip/_internal/basecommand.py b/src/pip/_internal/basecommand.py index 21aa8d950f9..d7c643b70d3 100644 --- a/src/pip/_internal/basecommand.py +++ b/src/pip/_internal/basecommand.py @@ -132,6 +132,11 @@ def main(self, args): if options.log: root_level = "DEBUG" + if options.no_color: + logger_class = "logging.StreamHandler" + else: + logger_class = "pip._internal.utils.logging.ColorizedStreamHandler" + logging.config.dictConfig({ "version": 1, "disable_existing_loggers": False, @@ -150,16 +155,14 @@ def main(self, args): "handlers": { "console": { "level": level, - "class": - "pip._internal.utils.logging.ColorizedStreamHandler", + "class": logger_class, "stream": self.log_streams[0], "filters": ["exclude_warnings"], "formatter": "indent", }, "console_errors": { "level": "WARNING", - "class": - "pip._internal.utils.logging.ColorizedStreamHandler", + "class": logger_class, "stream": self.log_streams[1], "formatter": "indent", }, diff --git a/src/pip/_internal/cmdoptions.py b/src/pip/_internal/cmdoptions.py index acf73ed66ed..cdba7acb1a6 100644 --- a/src/pip/_internal/cmdoptions.py +++ b/src/pip/_internal/cmdoptions.py @@ -102,6 +102,15 @@ def getname(n): help='Give more output. Option is additive, and can be used up to 3 times.' ) +no_color = partial( + Option, + '--no-color', + dest='no_color', + action='store_true', + default=False, + help="Suppress colored output", +) + version = partial( Option, '-V', '--version', @@ -566,6 +575,7 @@ def _merge_hash(option, opt_str, value, parser): cache_dir, no_cache, disable_pip_version_check, + no_color, ] } diff --git a/tests/functional/test_no_color.py b/tests/functional/test_no_color.py new file mode 100644 index 00000000000..e2fbcc9efb5 --- /dev/null +++ b/tests/functional/test_no_color.py @@ -0,0 +1,41 @@ +""" +Test specific for the --no-color option +""" +import os +import platform +import subprocess as sp +import sys + +import pytest + + +@pytest.mark.skipif(sys.platform == 'win32', + reason="does not run on windows") +def test_no_color(script): + + """ + Test uninstalling an existing package - should out put red error + + We must use subprocess with the script command, since redirection + in unix platform causes text coloring to disapper. Thus, we can't + use the testing infrastructure that other options has. + """ + + sp.Popen("script --flush --quiet --return /tmp/colored-output.txt" + " --command \"pip uninstall noSuchPackage\"", shell=True, + stdout=sp.PIPE, stderr=sp.PIPE).communicate() + + with open("/tmp/colored-output.txt", "r") as result: + assert "\x1b[31m" in result.read() + + os.unlink("/tmp/colored-output.txt") + + sp.Popen("script --flush --quiet --return /tmp/no-color-output.txt" + " --command \"pip --no-color uninstall noSuchPackage\"", + shell=True, + stdout=sp.PIPE, stderr=sp.PIPE).communicate() + + with open("/tmp/no-color-output.txt", "r") as result: + assert "\x1b[31m" not in result.read() + + os.unlink("/tmp/no-color-output.txt")