|
import codecs |
|
import os |
|
import sys |
|
|
|
from ._compat import PY2 |
|
|
|
|
|
def _find_unicode_literals_frame(): |
|
import __future__ |
|
|
|
if not hasattr(sys, "_getframe"): |
|
return 0 |
|
frm = sys._getframe(1) |
|
idx = 1 |
|
while frm is not None: |
|
if frm.f_globals.get("__name__", "").startswith("click."): |
|
frm = frm.f_back |
|
idx += 1 |
|
elif frm.f_code.co_flags & __future__.unicode_literals.compiler_flag: |
|
return idx |
|
else: |
|
break |
|
return 0 |
|
|
|
|
|
def _check_for_unicode_literals(): |
|
if not __debug__: |
|
return |
|
|
|
from . import disable_unicode_literals_warning |
|
|
|
if not PY2 or disable_unicode_literals_warning: |
|
return |
|
bad_frame = _find_unicode_literals_frame() |
|
if bad_frame <= 0: |
|
return |
|
from warnings import warn |
|
|
|
warn( |
|
Warning( |
|
"Click detected the use of the unicode_literals __future__" |
|
" import. This is heavily discouraged because it can" |
|
" introduce subtle bugs in your code. You should instead" |
|
' use explicit u"" literals for your unicode strings. For' |
|
" more information see" |
|
" https://click.palletsprojects.com/python3/" |
|
), |
|
stacklevel=bad_frame, |
|
) |
|
|
|
|
|
def _verify_python3_env(): |
|
"""Ensures that the environment is good for unicode on Python 3.""" |
|
if PY2: |
|
return |
|
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 |
|
|
|
|
|
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 a couple of UTF-8 supporting locales" |
|
" that you can pick from. The following suitable" |
|
" locales were discovered: {}".format(", ".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" |
|
" '{}' but it is not supported".format(bad_locale) |
|
) |
|
|
|
raise RuntimeError( |
|
"Click will abort further execution because Python 3 was" |
|
" configured to use ASCII as encoding for the environment." |
|
" Consult https://click.palletsprojects.com/python3/ for" |
|
" mitigation steps.{}".format(extra) |
|
) |
|
|