Repository: pipxproject/pipx (python)

Issue:
Remove emojis by default
They don't really have any benefit, support is platform, specific, and they look unprofessional. Also half the time I get broken characters because I don't have the right emoji fonts installed. I don't really need any cutesy icons in my tooling.

I recognize that this is a very subjective thing, and having emojis doesn't really hurt anything, I just don't like them.

I'm not expecting any action to be taken here, just wanted to mention that I think they look bad. Maybe people can vote on this issue to give a better idea of how many people also think they look bad/good?

If you like the emoji please give this comment a thumbs down.

----

The environment variable `USE_EMOJI` will allow you to opt-out of emoji usage.

Pull request description:
add env var USE_EMOJI
<!---
Thank you for your soon-to-be pull request. Before you submit this, please
double check to make sure that you've added an entry to docs/changelog.md.
-->
fixes #376

cc @traverseda 

We had some trouble with https://github.com/pipxproject/pipx/pull/377 so I just made a new PR. 

Patch:
diff --git a/docs/changelog.md b/docs/changelog.md
index cc726ef..4b4b9fe 100644
--- a/docs/changelog.md
+++ b/docs/changelog.md
@@ -6,6 +6,7 @@ dev
 - [refactor] Moved all commands to separate files within the commands module (#255).
 - [bugfix] Continue reinstalling packages after failure
 - [bugfix] Hide cursor while pipx runs
+- [feature] Add environment variable `USE_EMOJI` to allow enabling/disabling emojies (#376)
 
 0.15.1.3
 
diff --git a/src/pipx/commands/uninstall.py b/src/pipx/commands/uninstall.py
index c59a0a9..e76a2ff 100644
--- a/src/pipx/commands/uninstall.py
+++ b/src/pipx/commands/uninstall.py
@@ -6,7 +6,7 @@ from pipx.util import WINDOWS, rmdir
 
 
 from pipx import constants
-from pipx.emojies import hazard, stars
+from pipx.emojies import hazard, stars, sleep
 from pipx.venv import Venv, VenvContainer
 
 
@@ -15,7 +15,7 @@ def uninstall(venv_dir: Path, package: str, local_bin_dir: Path, verbose: bool):
     packages.
     """
     if not venv_dir.exists():
-        print(f"Nothing to uninstall for {package} 😴")
+        print(f"Nothing to uninstall for {package} {sleep}")
         app = which(package)
         if app:
             print(
diff --git a/src/pipx/constants.py b/src/pipx/constants.py
index 861090d..90fc652 100644
--- a/src/pipx/constants.py
+++ b/src/pipx/constants.py
@@ -16,14 +16,36 @@ PIPX_SHARED_PTH = "pipx_shared.pth"
 LOCAL_BIN_DIR = Path(os.environ.get("PIPX_BIN_DIR", DEFAULT_PIPX_BIN_DIR)).resolve()
 PIPX_VENV_CACHEDIR = PIPX_HOME / ".cache"
 TEMP_VENV_EXPIRATION_THRESHOLD_DAYS = 14
-try:
-    WindowsError
-except NameError:
-    WINDOWS = False
-else:
-    WINDOWS = True
-
-emoji_support = not WINDOWS and sys.getdefaultencoding() == "utf-8"
+
+
+def is_windows() -> bool:
+    try:
+        WindowsError  # noqa
+    except NameError:
+        return False
+    else:
+        return True
+
+
+WINDOWS: bool = is_windows()
+
+
+def strtobool(val: str) -> bool:
+    val = val.lower()
+    if val in ("y", "yes", "t", "true", "on", "1"):
+        return True
+    elif val in ("n", "no", "f", "false", "off", "0"):
+        return False
+    else:
+        return False
+
+
+def use_emjois():
+    platform_emoji_support = not is_windows() and sys.getdefaultencoding() == "utf-8"
+    return strtobool(str(os.getenv("USE_EMOJI", platform_emoji_support)))
+
+
+emoji_support = use_emjois()
 
 completion_instructions = dedent(
     """
diff --git a/src/pipx/main.py b/src/pipx/main.py
index 95989f1..a7a97de 100644
--- a/src/pipx/main.py
+++ b/src/pipx/main.py
@@ -42,9 +42,13 @@ or run directly in an temporary Virtual Environment.
 
 Virtual Environment location is {str(constants.PIPX_LOCAL_VENVS)}.
 Symlinks to apps are placed in {str(constants.LOCAL_BIN_DIR)}.
-These locations can be overridden with the environment variables
-PIPX_HOME and PIPX_BIN_DIR, respectively. (Virtual Environments will
-be installed to $PIPX_HOME/venvs)
+
+Optional Environment Variables:
+PIPX_HOME: Overrides default pipx location. Virtual Environments
+will be installed to $PIPX_HOME/venvs.
+PIPX_BIN_DIR: Overrides location of app installations. Apps are symlinked
+or copied here.
+USE_EMOJI: Override emoji behavior. Default value varies based on platform.
 """
 )
 


Test patch:
diff --git a/tests/test_constants.py b/tests/test_constants.py
new file mode 100644
index 0000000..d6bdb1c
--- /dev/null
+++ b/tests/test_constants.py
@@ -0,0 +1,42 @@
+from pipx.constants import use_emjois
+from pipx import constants
+from unittest import mock
+import sys
+import pytest  # type: ignore
+
+
+@pytest.mark.parametrize(
+    "windows, USE_EMOJI, encoding, expected",
+    [
+        # windows
+        (True, None, "utf-8", False),
+        (True, "", "utf-8", False),
+        (True, "0", "utf-8", False),
+        (True, "1", "utf-8", True),
+        (True, "true", "utf-8", True),
+        (True, "tru", "utf-8", False),
+        (True, "True", "utf-8", True),
+        (True, "false", "utf-8", False),
+        # unix
+        (False, None, "utf-8", True),
+        (False, "", "utf-8", False),
+        (False, "0", "utf-8", False),
+        (False, "1", "utf-8", True),
+        (False, "true", "utf-8", True),
+        (False, "tru", "utf-8", False),
+        (False, "True", "utf-8", True),
+        (False, "false", "utf-8", False),
+        # encoding
+        (False, None, "utf-8", True),
+        (False, None, "", False),
+    ],
+)
+def test_use_emjois(monkeypatch, windows, USE_EMOJI, encoding, expected):
+    with mock.patch.object(
+        constants,
+        "is_windows",
+        mock.create_autospec(constants.is_windows, return_value=windows),
+    ), mock.patch.object(sys, "getdefaultencoding", return_value=encoding):
+        if USE_EMOJI is not None:
+            monkeypatch.setenv("USE_EMOJI", USE_EMOJI)
+        assert use_emjois() is expected