summaryrefslogtreecommitdiff
path: root/src/click/_unicodefun.py
blob: 53ec9d267bdc84fb0dfb3f010ac20dc146b0a14d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
import codecs
import os


def _verify_python_env():
    """Ensures that the environment is good for Unicode."""
    try:
        import locale

        fs_enc = codecs.lookup(locale.getpreferredencoding()).name
    except Exception:
        fs_enc = "ascii"
    if fs_enc != "ascii":
        return

    extra = ""
    if os.name == "posix":
        import subprocess

        try:
            rv = subprocess.Popen(
                ["locale", "-a"], stdout=subprocess.PIPE, stderr=subprocess.PIPE
            ).communicate()[0]
        except OSError:
            rv = b""
        good_locales = set()
        has_c_utf8 = False

        # Make sure we're operating on text here.
        if isinstance(rv, bytes):
            rv = rv.decode("ascii", "replace")

        for line in rv.splitlines():
            locale = line.strip()
            if locale.lower().endswith((".utf-8", ".utf8")):
                good_locales.add(locale)
                if locale.lower() in ("c.utf8", "c.utf-8"):
                    has_c_utf8 = True

        extra += "\n\n"
        if not good_locales:
            extra += (
                "Additional information: on this system no suitable"
                " UTF-8 locales were discovered. This most likely"
                " requires resolving by reconfiguring the locale"
                " system."
            )
        elif has_c_utf8:
            extra += (
                "This system supports the C.UTF-8 locale which is"
                " recommended. You might be able to resolve your issue"
                " by exporting the following environment variables:\n\n"
                "    export LC_ALL=C.UTF-8\n"
                "    export LANG=C.UTF-8"
            )
        else:
            extra += (
                "This system lists some UTF-8 supporting locales that"
                " you can pick from. The following suitable locales"
                f" were discovered: {', '.join(sorted(good_locales))}"
            )

        bad_locale = None
        for locale in os.environ.get("LC_ALL"), os.environ.get("LANG"):
            if locale and locale.lower().endswith((".utf-8", ".utf8")):
                bad_locale = locale
            if locale is not None:
                break
        if bad_locale is not None:
            extra += (
                "\n\nClick discovered that you exported a UTF-8 locale"
                " but the locale system could not pick up from it"
                " because it does not exist. The exported locale is"
                f" {bad_locale!r} but it is not supported"
            )

    raise RuntimeError(
        "Click will abort further execution because Python was"
        " configured to use ASCII as encoding for the environment."
        " Consult https://click.palletsprojects.com/unicode-support/"
        f" for mitigation steps.{extra}"
    )