使用python3编码问题并单击包

时间:2015-08-26 18:46:36

标签: python-3.x encoding command-line-interface python-click

当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.

在我的情况下,我发现了这个问题的原因,当我从Mac连接到Linux主机时,Terminal.app将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'

编辑:要获得更好的补丁,请参阅我接受的答案。

我所有的linux主机都安装了'en_US.utf-8'作为语言环境(Fedora默认使用它)。

我的问题是:在python3脚本中选择/强制语言环境是否有更好(更强大)的方法?例如,在系统中设置一个可用的语言环境。

也许有一种不同的方法来解决这个问题,但我没有找到它。

3 个答案:

答案 0 :(得分:2)

好吧,我最初的解决方法有很多缺陷,我必须通过public void openDataBase(){ //Abre la base de datos try { createDataBase(); } catch (IOException e) { Log.e("SQLiteError","Error al abrir base de datos: \n"+e.getMessage()); } String myPatch = DB_PATH + DB_NAME; categoryDB = SQLiteDatabase.openDatabase(myPatch, null, SQLiteDatabase.OPEN_READWRITE); } 库检查编码,但编码本身并没有修复,所以当输入参数或输出有非ascii时我得到异常字符。

我必须实现一个更复杂的方法,包括3个步骤:设置区域设置,在std输入/输出中纠正编码并重新编码命令行参数,除非我添加了“友好”退出,如果第一次尝试设置语言环境不能按预期工作:

click

此补丁解决了几乎所有问题,但有一点需要注意,方法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__ lib使用该方法打印帮助,修复它我必须在click lib

上应用猴子补丁
click

通过此更改,当环境配置了错误的语言环境但系统支持en_US.utf-8(它是Fedora默认语言环境)时,我的所有脚本都可以正常工作。

如果您发现此方法存在任何问题或有更好的解决方案,请添加新答案。

编辑:有一个已打开的问题(增强版)http://bugs.python.org/issue15216,可以轻松更改已创建(未使用)的流中的编码(sys.std *) 。但是针对python 3.7所以,我们必须等待一段时间。

编辑(2017-12-08):我已经看到py3.7有一个PEP 538,它会在启动时改变python3编码管理的整个行为,我认为新方法将解决原始问题:https://www.python.org/dev/peps/pep-0538/

恕我直言,针对编码问题瞄准python 3.7的更改,应该是多年前制定的,但我认为迟到总比没有好。

答案 1 :(得分:2)

这是一个老化的话题,但是这个答案可能会对将来或我自己有所帮助。如果它是*nux

env | grep LC_ALL

如果已设置,请执行以下操作。这就是全部。

unset LC_ALL

答案 2 :(得分:0)

我还没有找到这个简单的方法(在执行任何操作之前在适当的环境下重新执行脚本),因此出于某种原因,我将其添加给使用旧Python版本的将来的旅行者。首先将其添加到下面:

if os.environ["LC_ALL"] != "C.UTF-8" or os.environ["LANG"] != "C.UTF-8":
    os.execve(sys.executable,
              [os.path.realpath(__file__)] + sys.argv,
              {"LC_ALL": "C.UTF-8", "LANG": "C.UTF-8"})