2015-04-03 149 views
2

以此示例代碼片段爲例。在Windows中處理unicode subprocess env的正確方法是什麼?

import subprocess 
import os 

env = os.environ.copy() 
env["FOO"] = u"foo" 
subprocess.check_call(["ls", "-l"], env=env) 

在Windows上,這會失敗。

C:\Python27\python.exe test.py 
Traceback (most recent call last): 
    File "test.py", line 7, in <module> 
    subprocess.check_call(["ls", "-l"], env=env) 
    File "C:\Python27\lib\subprocess.py", line 535, in check_call 
    retcode = call(*popenargs, **kwargs) 
    File "C:\Python27\lib\subprocess.py", line 522, in call 
    return Popen(*popenargs, **kwargs).wait() 
    File "C:\Python27\lib\subprocess.py", line 710, in __init__ 
    errread, errwrite) 
    File "C:\Python27\lib\subprocess.py", line 958, in _execute_child 
    startupinfo) 
TypeError: environment can only contain strings 

sys.pathdocumented是使用Unicode完全確定。處理這個(和類似的代碼)的正確方法是什麼,以便一切按預期工作?顯而易見的解決方案是在unicode路徑上調用.encode(),但我不確定這是否會導致意外行爲。

+0

錯誤消息似乎不言自明;據推測,Python根本不支持使用Unicode環境變量創建子進程。 – 2015-04-03 08:55:26

回答

3

在Windows上,傳遞環境字典到subprocess.check_call()歸結爲將環境傳遞到CreateProcess()。這實際上可以採取Unicode字符串(在其CreateProcessW()化身)。

然而,從Python 2.7版的_subprocess.c

/* TODO: handle unicode command lines? */ 
/* TODO: handle unicode environment? */ 

那麼,你是不是第一個想到的問題。

對於您的問題,也沒有通用的解決方案,因爲環境由被調用的進程解釋,其中一些也由系統或系統庫自動解釋。所以正確的編碼取決於目標進程的期望。

不幸的是,儘管Windows上的Python 2處理Unicode,但它實際上將零終止的窄字符串(即PyString_AS_STRING()返回char *)傳遞給系統函數。

現在,Windows本身如何處理兩個不同版本的環境變量,因爲顯然它似乎可以傳遞寬或窄的環境字符串。

目標進程僅GetEnvironmentStrings()返回取決於如果應用程序支持Unicode或編譯任一寬或窄字符訪問。

那麼當你從一個狹窄的(ANSI)進程啓動一個Unicode進程時,你會發生什麼呢?CreateProcess()?所有參數都會發生同樣的情況,它們會在調用者的代碼頁中解碼並轉換爲Windows版本的UCS-2寬字符。

所以正確的方法可能是使用系統代碼頁,因爲只有這樣字符串才能在unicode目標進程中正確顯示。這--oF course--防止您在使用代碼頁字符不是......

所以,是的,Python的2 Unicode的環境中都或多或少的破碎。

+0

如果在Python 2中需要'CreateProcessW',請改爲使用win32process,或者甚至使用ctypes。 – eryksun 2015-04-03 11:46:49

相關問題