【问题标题】:Python Popen failing to use proper encoding in Windows PowerShellPython Popen 未能在 Windows PowerShell 中使用正确的编码
【发布时间】:2012-04-17 01:19:11
【问题描述】:

我在 Windows PowerShell 中运行我的 Python 脚本,该脚本应该使用 Popen 运行另一个程序,然后通过管道输出该程序的输出(实际上是 Mercurial)以在我的脚本中使用。当我尝试在 PowerShell 中执行脚本时遇到编码错误。

我很确定它正在发生,因为在获取 Popen 调用的输出时,Python 没有使用 PowerShell 使用的正确编码。 问题是我不知道如何告诉 Python 使用正确的编码。


我的脚本看起来像

# -*- coding: utf-8 -*-
#... some imports
proc = Popen(["hg", "--cwd", self.path, "--encoding", "UTF-8"] + list(args), stdout=PIPE, stderr=PIPE)
#... other code

当我在 Linux 上运行这个脚本时,我没有任何问题。我还可以使用 PowerShell 在 Windows 7 Home Premium 64 位中运行脚本,没有任何问题。这个Windows 7中的PowerShell使用的是代码页850,即chcp的输出是850("ibm850")。

然而,当我使用默认编码为 cp437 (chcp = 437 的 PowerShell 在 Windows 7 Starter 32 位 中运行脚本时),我从 Python(2.7.2 版)收到以下错误:

File "D:\Path\to\myscript.py", line 55, in hg_command
    proc = Popen(["hg", "--cwd", self.path, "--encoding", "UTF-8"] + list(args), stdout=PIPE, stderr=PIPE)
File "C:\Program files\Python27\lib\subprocess.py", line 679, in __init__
    errread, errwrite)
File "C:\Program files\Python27\lib\subprocess.py", line 852, in _execute_child
    args = list2cmdline(args)
File "C:\Program files\Python27\lib\subprocess.py", line 615, in list2cmdline
    return ''.join(result)
UnicodeDecodeError: 'utf8' codec cant decode byte 0xe3 in position 0: unexpected end of data

我尝试了以下方法,但没有成功(即上述错误报告保持不变):

  • 从我的脚本中删除 # -*- coding: utf-8 -*- 行。
  • 删除在我的脚本中通过 Popen 运行 Mercurial 的 -- encoding UTF-8 选项。
  • 在执行我的脚本之前,在 PowerShell 中将编码更改为 chcp 850
  • 我在其他 Stack Overflow 答案中发现了许多其他杂项 Python hack。

关于我的具体细节,我的完整源代码可在here in BitBucket 获得。 hgapi.py 是给出错误的脚本。


更新: 这个other script正在调用脚本,它正在设置这样的编码

sys.setdefaultencoding("utf-8")

这一行看起来很重要,因为如果我把它注释掉,我会得到一个不同的错误:

UnicodeDecoreError: 'ascii' codec cant decode byte 0xe3 in position 0: ordinal not in range(128)

【问题讨论】:

  • 您在使用mercurial api时是否有同样的问题?由于您使用的是 python,所以它看起来很自然。
  • 项目之前使用的是mercurial的内部api,但是因为是官方稳定的,所以我切换到了命令行api。除扩展外,不应使用内部 api。
  • 这看起来更像是args 数组的问题,因为在list2cmdline 中引发了异常。也许argsself.path 是字节字符串而不是Unicode 字符串?
  • 在 Windows 上,您通常希望尽可能使用 Unicode 字符串。 hgapi.py 将所有字符串文字转换为 Unicode 文字 (from __future__ import unicode_literals),hypergrasscore.py 可能也应该这样做。
  • @Philipp,这是有道理的。但是,我添加了from __future__ import unicode_literals,但仍然出现同样的错误。事实上,我什至在调用 hgapi.py 的 hypergrasscore.py 脚本中包含 u 之前的字符串 (u'string'),但没有成功。 =/

标签: python powershell unicode mercurial


【解决方案1】:

尝试将编码更改为cp1252。 Windows 中的 Popen 需要编码为 cp1252 的 shell 命令。这似乎是一个错误,它似乎也通过subprocess 模块在 Python 3.X 中修复:http://docs.python.org/library/subprocess.html

import subprocess
subprocess.Popen(["hg", "--cwd", self.path, "--encoding", "UTF-8"] + list(args), stdout=PIPE, stderr=PIPE)

更新:

您的问题或许可以通过Django模块的smart_str功能解决。

使用此代码:

from django.utils.encoding import smart_str, smart_unicode
# the cmd should contain sthe string with the commsnd that you want to execute
smart_cmd = smart_str(cmd)
subprocess.Popen(smart_cmd)

您可以找到有关如何在 Windows here 上安装 Django 的信息。 可以先安装pip,然后启动安装Django 具有管理员权限的命令外壳并运行以下命令:

pip install Django

这会将 Django 安装到 Python 安装的 site-packages 目录中。

【讨论】:

  • 通过什么把编码改成cp1252? PowerShell 中的 chcp 1252 没有帮助。
  • @STALTZ 试试$OutputEncoding = [Console]::OutputEncoding
  • @STALTZ 很抱歉,也许我更新的答案可以帮助你,但你必须安装一个新模块,django。 smart_str 是一个非常有用的功能。您可以在这里找到更多信息:saltycrane.com/blog/2008/11/…
  • 我还没有尝试过你的 Django 解决方案,@ThanasisPetsas,因为我认为应该有一些基本的 Python 解决方案。无论如何,谢谢,如果我找不到其他解决方案,我最终可以使用 Django。
【解决方案2】:

使用from __future__ import unicode_literals 后,我开始遇到同样的错误,但在代码的不同部分:

out, err = [x.decode("utf-8") for x in  proc.communicate()]

报错

UnicodeDecodeError: 'utf8' codec cant decode byte 0xe3 in position 33 ....

确实,x 是一个 字节字符串,其中包含 \xe3(在 cp1252 中是 ã)。所以我没有使用x.decode('utf-8'),而是使用了x.decode('windows-1252'),这没有给我带来任何错误。为了支持任何类型的编码,我最终改用x.decode(sys.stdout.encoding)问题已解决。

那是在 Python 3.2.2 和 Windows 7 Starter 计算机上,但同一台计算机上的 Python 2.7 也可以正常工作。

【讨论】:

猜你喜欢
  • 2021-03-17
  • 1970-01-01
  • 2015-03-20
  • 2023-03-11
  • 1970-01-01
  • 2020-04-10
  • 1970-01-01
  • 1970-01-01
  • 2019-02-22
相关资源
最近更新 更多