Repository: pypa/pipenv

Issue:
Is there a way to disable / suppress pipenv's "Courtesy Notice" about virtual environments?
Each time I invoke `pipenv` I see:

> Courtesy Notice: Pipenv found itself running within a virtual environment, so it will automatically use that environment, instead of creating its own for any project. You can set PIPENV_IGNORE_VIRTUALENVS=1 to force pipenv to ignore that environment and create its own instead.

Can this be globally suppressed?
Fix #2527: Add ability to suppress nested venv courtesy notice
This will add an environment variable, PIPENV_SUPPRESS_NESTED_WARNING, to be used to suppress the courtesy notice from warn_in_virtualenv (produced when pipenv finds itself running inside another virtual environment). 
It will also add a sentence to the end of the courtesy notice to tell users how to suppress the notice.

I ended up putting the test in its own file - if there's a more logical place to put it, let me know!

**Fixes #2527.**
Is there a way to disable / suppress pipenv's "Courtesy Notice" about virtual environments?
Each time I invoke `pipenv` I see:

> Courtesy Notice: Pipenv found itself running within a virtual environment, so it will automatically use that environment, instead of creating its own for any project. You can set PIPENV_IGNORE_VIRTUALENVS=1 to force pipenv to ignore that environment and create its own instead.

Can this be globally suppressed?


Discussion:
No, there is not.
That said, maybe we can treat an empty `PIPENV_IGNORE_VIRTUALENVS` as the suppressor.

* `PIPENV_IGNORE_VIRTUALENVS` absent—show the message.
* `PIPENV_IGNORE_VIRTUALENVS` set to empty string—suppress the message, but use the environment.
* `PIPENV_IGNORE_VIRTUALENVS` is not empty—create a nested virtualenv.
Does `PIPENV_IGNORE_VIRTUALENVS=0` have any significance? If pipenv was told to not ignore virtual envs, then that should mean I want to use my existing virtual env, and the courtesy notice should be suppressed.
We have an environment variable to suppress output but we don't use it much. We can add this to the refactor
My current workaround:

`pipenv lock --requirements 2> >(grep -v "Courtesy Notice" >&2) > requirements.txt`
@max-arnold You found a bug! `lock -r` should output to stdout (it does when you’re not in a virtualenv), but for some reason outputs to stderr when you are inside. You shouldn’t need more than `pipenv lock --requirements > requirements.txt`. We will fix that. Sorry for the annoyance.

----

Edit: After some testing, you should be able to run `pipenv lock --requirements 2>/dev/null` on Linux or Mac. No need for fancy `grep`-ing.

No, there is not.
That said, maybe we can treat an empty `PIPENV_IGNORE_VIRTUALENVS` as the suppressor.

* `PIPENV_IGNORE_VIRTUALENVS` absent—show the message.
* `PIPENV_IGNORE_VIRTUALENVS` set to empty string—suppress the message, but use the environment.
* `PIPENV_IGNORE_VIRTUALENVS` is not empty—create a nested virtualenv.
Does `PIPENV_IGNORE_VIRTUALENVS=0` have any significance? If pipenv was told to not ignore virtual envs, then that should mean I want to use my existing virtual env, and the courtesy notice should be suppressed.
We have an environment variable to suppress output but we don't use it much. We can add this to the refactor
My current workaround:

`pipenv lock --requirements 2> >(grep -v "Courtesy Notice" >&2) > requirements.txt`
@max-arnold You found a bug! `lock -r` should output to stdout (it does when you’re not in a virtualenv), but for some reason outputs to stderr when you are inside. You shouldn’t need more than `pipenv lock --requirements > requirements.txt`. We will fix that. Sorry for the annoyance.

----

Edit: After some testing, you should be able to run `pipenv lock --requirements 2>/dev/null` on Linux or Mac. No need for fancy `grep`-ing.

Resolving patch:
diff --git a/pipenv/core.py b/pipenv/core.py
--- a/pipenv/core.py
+++ b/pipenv/core.py
@@ -1612,19 +1612,28 @@ def gen(out):
 
 
 def warn_in_virtualenv():
-    from .environments import PIPENV_USE_SYSTEM, PIPENV_VIRTUALENV
+    from .environments import (
+        PIPENV_USE_SYSTEM,
+        PIPENV_VIRTUALENV,
+        PIPENV_VERBOSITY,
+    )
 
     # Only warn if pipenv isn't already active.
     pipenv_active = os.environ.get("PIPENV_ACTIVE")
-    if (PIPENV_USE_SYSTEM or PIPENV_VIRTUALENV) and not pipenv_active:
+    if (
+        (PIPENV_USE_SYSTEM or PIPENV_VIRTUALENV)
+        and not (pipenv_active or PIPENV_VERBOSITY < 0)
+    ):
         click.echo(
             "{0}: Pipenv found itself running within a virtual environment, "
             "so it will automatically use that environment, instead of "
             "creating its own for any project. You can set "
             "{1} to force pipenv to ignore that environment and create "
-            "its own instead.".format(
+            "its own instead. You can set {2} to suppress this "
+            "warning.".format(
                 crayons.green("Courtesy Notice"),
                 crayons.normal("PIPENV_IGNORE_VIRTUALENVS=1", bold=True),
+                crayons.normal("PIPENV_VERBOSITY=-1", bold=True),
             ),
             err=True,
         )
diff --git a/pipenv/environments.py b/pipenv/environments.py
--- a/pipenv/environments.py
+++ b/pipenv/environments.py
@@ -174,6 +174,13 @@
 Default is to create new virtual environments in a global location.
 """
 
+PIPENV_VERBOSITY = int(os.environ.get("PIPENV_VERBOSITY", 0))
+"""Verbosity setting for pipenv.
+
+Higher values make pipenv more verbose, lower values less so. Default is 0,
+for normal verbosity.
+"""
+
 PIPENV_YES = bool(os.environ.get("PIPENV_YES"))
 """If set, Pipenv automatically assumes "yes" at all prompts.
 


Test patch:
diff --git a/tests/unit/test_core.py b/tests/unit/test_core.py
new file mode 100644
--- /dev/null
+++ b/tests/unit/test_core.py
@@ -0,0 +1,15 @@
+import pytest
+import mock
+
+from pipenv.core import warn_in_virtualenv
+
+
+@mock.patch('pipenv.environments.PIPENV_VIRTUALENV', 'totallyrealenv')
+@mock.patch('pipenv.environments.PIPENV_VERBOSITY', -1)
+@pytest.mark.core
+def test_suppress_nested_venv_warning(capsys):
+    # Capture the stderr of warn_in_virtualenv to test for the presence of the
+    # courtesy notice.
+    warn_in_virtualenv()
+    output, err = capsys.readouterr()
+    assert 'Courtesy Notice' not in err