Проблема кодирования с python3 и нажмите пакет
когда lib click
обнаруживает, что среда выполнения python3, но кодировка ASCII, то он резко завершает программу python:
RuntimeError: Click will abort further execution because Python 3 was configured to use ASCII as encoding for the environment. Either switch to Python 2 or consult http://click.pocoo.org/python3/ for mitigation steps.
Я нашел причину этой проблемы в моем случае, когда я подключаюсь к моему хосту Linux с моего Mac, терминала.приложение устанавливает локаль сеанса SSH в локаль моего Mac (es_ES.UTF-8) однако мой хост Linux не установил такую локаль (только en_US.utf-8).
я применил первоначальный обходной путь, чтобы исправить это (но это было многие вопросы, см. принятый ответ):
import locale, codecs
# locale.getpreferredencoding() == 'ANSI_X3.4-1968'
if codecs.lookup(locale.getpreferredencoding()).name == 'ascii':
os.environ['LANG'] = 'en_US.utf-8'
EDIT: для лучшего патча см. Мой принятый ответ.
все Мои хосты linux установили ' en_US.utf-8 ' в качестве локали (Fedora использует его по умолчанию).
мой вопрос: есть ли лучший (более надежный) способ выбрать/заставить локаль в скрипте python3 ? например, установка одного из доступных локалей в системе.
может быть, есть другой подход чтобы исправить эту проблему, но я ее не нашел.
2 ответов
Ну, мой первоначальный обходной путь имел много недостатков, я должен пройти click
проверка библиотеки о кодировке, но сама кодировка не была исправлена, поэтому я получаю исключения, когда входные параметры или выходные данные имели символы, отличные от ascii.
мне пришлось реализовать более сложный метод с 3 шагами: установить локаль, правильную кодировку в std in / out и перекодировать параметры командной строки, кроме того, я добавил "дружественный" выход, если первая попытка установить локаль не работает как ожидалось:
def prevent_ascii_env():
"""
To avoid issues reading unicode chars from stdin or writing to stdout, we need to ensure that the
python3 runtime is correctly configured, if not, we try to force to utf-8,
but It isn't possible then we exit with a more friendly message that the original one.
"""
import locale, codecs, os, sys
# locale.getpreferredencoding() == 'ANSI_X3.4-1968'
if codecs.lookup(locale.getpreferredencoding()).name == 'ascii':
os.environ['LANG'] = 'en_US.utf-8'
if codecs.lookup(locale.getpreferredencoding()).name == 'ascii':
print("The current locale is not correctly configured in your system")
print("Please set the LANG env variable to the proper value before to call this script")
sys.exit(-1)
#Once we have the proper locale.getpreferredencoding() We can change current stdin/out streams
_, encoding = locale.getdefaultlocale()
import io
sys.stderr = io.TextIOWrapper(sys.stderr.detach(), encoding=encoding, errors="replace", line_buffering=True)
sys.stdout = io.TextIOWrapper(sys.stdout.detach(), encoding=encoding, errors="replace", line_buffering=True)
sys.stdin = io.TextIOWrapper(sys.stdin.detach(), encoding=encoding, errors="replace", line_buffering=True)
# And finally we need to re-encode the input parameters
for i, p in enumerate(sys.argv):
sys.argv[i] = os.fsencode(p).decode()
этот патч решает почти все проблемы, однако он имеет оговорку, метод shutils.get_terminal_size()
поднимает ValueError
потому что sys.__stdout__
была отсоединена, click
lib использует этот метод для печати справки, чтобы исправить это, мне пришлось применить патч обезьяны на click
lib
def wrapper_get_terminal_size():
"""
Replace the original function termui.get_terminal_size (click lib) by a new one
that uses a fallback if ValueError exception has been raised
"""
from click import termui, formatting
old_get_term_size = termui.get_terminal_size
def _wrapped_get_terminal_size():
try:
return old_get_term_size()
except ValueError:
import os
sz = os.get_terminal_size()
return sz.columns, sz.lines
termui.get_terminal_size = _wrapped_get_terminal_size
formatting.get_terminal_size = _wrapped_get_terminal_size
С этими изменениями все мои скрипты теперь работают нормально, когда в среде настроена неправильная локаль, но система поддерживает en_US.utf-8 (это локаль Fedora по умолчанию).
если вы найдете любую проблему на этом подходе или имеете лучшее решение, Пожалуйста, добавьте новый ответ.
редактировать: есть открытая проблема (улучшение),http://bugs.python.org/issue15216, что позволит легко изменить кодировку в созданном (не используемом) потоке (sys.ЗППП.)* Но нацелен на python 3.7, поэтому нам придется подождать некоторое время.
редактировать (2017-12-08): я видел, что есть PEP 538 для py3.7, это изменит все поведение управления кодировкой python3 во время запуска, я думаю, что новый подход исправит исходную проблему:https://www.python.org/dev/peps/pep-0538/
IMHO изменения, направленные на python 3.7 для проблем кодирования, должны были быть спланированы много лет назад, но лучше поздно, чем никогда, я думаю.
Это старая нить, однако этот ответ может помочь другим в будущем или мне. Если это *nux
env | grep LC_ALL
если он установлен, выполните следующие действия. Вот и все.
unset LC_ALL