import codecs import os import sys from ._compat import PY2 def _find_unicode_literals_frame(): import __future__ if not hasattr(sys, "_getframe"): # not all Python implementations have it 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 # 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 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) )