Repository: pypa/pipx
Pull request #1073 (2023-10-03 17:38:03)

Print all env vars in pipx environment
* [x] I have added an entry to `docs/changelog.md`

## Summary of changes
* Add PIPX_DEFAULT_PYTHON and USE_EMOJI to pipx environment
* Print both original environment and pipx computed values
* Remove "Only PIPX_HOME and PIPX_BIN_DIR can be set by users in the above list." (not true)

## Test plan
Tested by running

```shellsession
$ pipx environment
Environment variables (set by user):

PIPX_HOME=
PIPX_BIN_DIR=
PIPX_SHARED_LIBS=
PIPX_DEFAULT_PYTHON=
USE_EMOJI=

Derived values (computed by pipx):

PIPX_HOME=/home/user/.local/share/pipx
PIPX_BIN_DIR=/home/user/.local/bin
PIPX_SHARED_LIBS=/home/user/.local/share/pipx/shared
PIPX_LOCAL_VENVS=/home/user/.local/share/pipx/venvs
PIPX_LOG_DIR=/home/user/.local/state/pipx/log
PIPX_TRASH_DIR=/home/user/.local/share/pipx/trash
PIPX_VENV_CACHEDIR=/home/user/.cache/pipx
PIPX_DEFAULT_PYTHON=/usr/bin/python3
USE_EMOJI=true
```

```shellsession
$ PIPX_HOME=~/otherhome pipx environment
Environment variables (set by user):

PIPX_HOME=/home/user/otherhome
PIPX_BIN_DIR=
PIPX_SHARED_LIBS=
PIPX_DEFAULT_PYTHON=
USE_EMOJI=

Derived values (computed by pipx):

PIPX_HOME=/home/user/otherhome
PIPX_BIN_DIR=/home/user/.local/bin
PIPX_SHARED_LIBS=/home/user/otherhome/shared
PIPX_LOCAL_VENVS=/home/user/otherhome/venvs
PIPX_LOG_DIR=/home/user/otherhome/logs
PIPX_TRASH_DIR=/home/user/otherhome/.trash
PIPX_VENV_CACHEDIR=/home/user/otherhome/.cache
PIPX_DEFAULT_PYTHON=/usr/bin/python3
USE_EMOJI=true
```

```shellsession
$ USE_EMOJI=n pipx environment
Environment variables (set by user):

PIPX_HOME=
PIPX_BIN_DIR=
PIPX_SHARED_LIBS=
PIPX_DEFAULT_PYTHON=
USE_EMOJI=n

Derived values (computed by pipx):

PIPX_HOME=/home/user/.local/share/pipx
PIPX_BIN_DIR=/home/user/.local/bin
PIPX_SHARED_LIBS=/home/user/.local/share/pipx/shared
PIPX_LOCAL_VENVS=/home/user/.local/share/pipx/venvs
PIPX_LOG_DIR=/home/user/.local/state/pipx/log
PIPX_TRASH_DIR=/home/user/.local/share/pipx/trash
PIPX_VENV_CACHEDIR=/home/user/.cache/pipx
PIPX_DEFAULT_PYTHON=/usr/bin/python3
USE_EMOJI=false
```

```shellsession
$ PIPX_DEFAULT_PYTHON=python3.11 pipx environment
Environment variables (set by user):

PIPX_HOME=
PIPX_BIN_DIR=
PIPX_SHARED_LIBS=
PIPX_DEFAULT_PYTHON=python3.11
USE_EMOJI=

Derived values (computed by pipx):

PIPX_HOME=/home/user/.local/share/pipx
PIPX_BIN_DIR=/home/user/.local/bin
PIPX_SHARED_LIBS=/home/user/.local/share/pipx/shared
PIPX_LOCAL_VENVS=/home/user/.local/share/pipx/venvs
PIPX_LOG_DIR=/home/user/.local/state/pipx/log
PIPX_TRASH_DIR=/home/user/.local/share/pipx/trash
PIPX_VENV_CACHEDIR=/home/user/.cache/pipx
PIPX_DEFAULT_PYTHON=/usr/bin/python3.11
USE_EMOJI=true
```

```shellsession
$ PIPX_DEFAULT_PYTHON=foo pipx environment
Traceback (most recent call last):
  File "/home/user/.local/bin/pipx", line 5, in <module>
    from pipx.main import cli
  File "/home/user/.local/lib/python3.11/site-packages/pipx/main.py", line 23, in <module>
    from pipx import commands, constants
  File "/home/user/.local/lib/python3.11/site-packages/pipx/commands/__init__.py", line 2, in <module>
    from pipx.commands.environment import environment
  File "/home/user/.local/lib/python3.11/site-packages/pipx/commands/environment.py", line 15, in <module>
    from pipx.interpreter import DEFAULT_PYTHON
  File "/home/user/.local/lib/python3.11/site-packages/pipx/interpreter.py", line 87, in <module>
    DEFAULT_PYTHON = _get_absolute_python_interpreter(env_default_python)
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/user/.local/lib/python3.11/site-packages/pipx/interpreter.py", line 78, in _get_absolute_python_interpreter
    raise PipxError(f"Default python interpreter '{env_python}' is invalid.")
pipx.util.PipxError: Default python interpreter 'foo' is invalid.
```



Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index fa453d2..da15e33 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -15,6 +15,7 @@
 - Add `pipx install --preinstall` to support preinstalling build requirements
 - Pass `--no-input` to pip when output is not piped to parent stdout
 - Fix program name in generated manual page
+- Print all environment variables in `pipx environment`
 
 ## 1.2.0
 
diff --git a/src/pipx/commands/environment.py b/src/pipx/commands/environment.py
index 461bcb7..155311e 100644
--- a/src/pipx/commands/environment.py
+++ b/src/pipx/commands/environment.py
@@ -1,3 +1,5 @@
+import os
+
 from pipx.constants import (
     EXIT_CODE_OK,
     LOCAL_BIN_DIR,
@@ -9,12 +11,21 @@ from pipx.constants import (
     PIPX_VENV_CACHEDIR,
     ExitCode,
 )
+from pipx.emojis import EMOJI_SUPPORT
+from pipx.interpreter import DEFAULT_PYTHON
 from pipx.util import PipxError
 
 
 def environment(value: str) -> ExitCode:
-    """Print a list of variables used in `pipx.constants`"""
-    environment_variables = {
+    """Print a list of environment variables and paths used by pipx"""
+    environment_variables = [
+        "PIPX_HOME",
+        "PIPX_BIN_DIR",
+        "PIPX_SHARED_LIBS",
+        "PIPX_DEFAULT_PYTHON",
+        "USE_EMOJI",
+    ]
+    derived_values = {
         "PIPX_HOME": PIPX_HOME,
         "PIPX_BIN_DIR": LOCAL_BIN_DIR,
         "PIPX_SHARED_LIBS": PIPX_SHARED_LIBS,
@@ -22,14 +33,22 @@ def environment(value: str) -> ExitCode:
         "PIPX_LOG_DIR": PIPX_LOG_DIR,
         "PIPX_TRASH_DIR": PIPX_TRASH_DIR,
         "PIPX_VENV_CACHEDIR": PIPX_VENV_CACHEDIR,
+        "PIPX_DEFAULT_PYTHON": DEFAULT_PYTHON,
+        "USE_EMOJI": str(EMOJI_SUPPORT).lower(),
     }
     if value is None:
+        print("Environment variables (set by user):")
+        print("")
         for env_variable in environment_variables:
-            print(f"{env_variable}={environment_variables[env_variable]}")
+            env_value = os.getenv(env_variable, "")
+            print(f"{env_variable}={env_value}")
+        print("")
+        print("Derived values (computed by pipx):")
         print("")
-        print("Only PIPX_HOME and PIPX_BIN_DIR can be set by users in the above list.")
-    elif value in environment_variables:
-        print(environment_variables[value])
+        for env_variable in derived_values:
+            print(f"{env_variable}={derived_values[env_variable]}")
+    elif value in derived_values:
+        print(derived_values[value])
     else:
         raise PipxError("Variable not found.")
 
diff --git a/src/pipx/main.py b/src/pipx/main.py
index 7f12fba..bb5750d 100644
--- a/src/pipx/main.py
+++ b/src/pipx/main.py
@@ -668,15 +668,16 @@ def _add_environment(subparsers: argparse._SubParsersAction) -> None:
     p = subparsers.add_parser(
         "environment",
         formatter_class=LineWrapRawTextHelpFormatter,
-        help=("Print a list of variables used in pipx.constants."),
+        help="Print a list of environment variables and paths used by pipx.",
         description=textwrap.dedent(
             """
+            Prints the names and current values of environment variables used by pipx,
+            followed by internal pipx variables which are derived from the environment
+            variables and platform specific default values.
+
             Available variables:
             PIPX_HOME, PIPX_BIN_DIR, PIPX_SHARED_LIBS, PIPX_LOCAL_VENVS, PIPX_LOG_DIR,
-            PIPX_TRASH_DIR, PIPX_VENV_CACHEDIR
-
-            Only PIPX_HOME and PIPX_BIN_DIR can be set by users in the above list.
-
+            PIPX_TRASH_DIR, PIPX_VENV_CACHEDIR, PIPX_DEFAULT_PYTHON, USE_EMOJI
             """
         ),
     )


Test patch:
diff --git a/tests/test_environment.py b/tests/test_environment.py
index d15cabe..8c55d94 100644
--- a/tests/test_environment.py
+++ b/tests/test_environment.py
@@ -11,10 +11,9 @@ def test_cli(monkeypatch, capsys):
     assert "PIPX_LOG_DIR" in captured.out
     assert "PIPX_TRASH_DIR" in captured.out
     assert "PIPX_VENV_CACHEDIR" in captured.out
-    assert (
-        "Only PIPX_HOME and PIPX_BIN_DIR can be set by users in the above list."
-        in captured.out
-    )
+    assert "PIPX_DEFAULT_PYTHON" in captured.out
+    assert "USE_EMOJI" in captured.out
+    assert "Environment variables (set by user):" in captured.out
 
 
 def test_cli_with_args(monkeypatch, capsys):
@@ -25,6 +24,8 @@ def test_cli_with_args(monkeypatch, capsys):
     assert not run_pipx_cli(["environment", "--value", "PIPX_LOG_DIR"])
     assert not run_pipx_cli(["environment", "--value", "PIPX_TRASH_DIR"])
     assert not run_pipx_cli(["environment", "--value", "PIPX_VENV_CACHEDIR"])
+    assert not run_pipx_cli(["environment", "--value", "PIPX_DEFAULT_PYTHON"])
+    assert not run_pipx_cli(["environment", "--value", "USE_EMOJI"])
 
     assert run_pipx_cli(["environment", "--value", "SSS"])
     captured = capsys.readouterr()