2015-04-03 2 views
2

Возьмите этот пример фрагмента.Каков правильный способ работы с подпроцессом unicode env в Windows?

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.path является documented быть совершенно нормально с юникода. Каков правильный способ справиться с этим (и похожим кодом), чтобы все работало так, как ожидалось? Очевидным решением является вызов .encode() по пути unicode, но я не уверен, что это приведет к неожиданному поведению.

+0

Сообщение об ошибке кажется само собой разумеющимся; предположительно, Python просто не поддерживает создание дочернего процесса с переменными среды Unicode. –

ответ

3

В Windows, прохождение среды dict до subprocess.check_call() сводится к передаче среды CreateProcess(). Фактически это может принимать строки unicode (в его воплощении CreateProcessW()).

Однако из питона 2,7-х _subprocess.c:

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

Таким образом, вы не первый думать о проблеме.

Существует также общее решение вашей проблемы, поскольку среда интерпретируется вызываемым процессом, а некоторые из них также автоматически используются системными или системными библиотеками. Таким образом, правильная кодировка зависит от ожидаемого целевого процесса.

К сожалению, в то время как Python 2 на Windows, делает обрабатывать Unicode, он фактически переходит на нулевой прерванных узких строк символов (т.е. PyString_AS_STRING() возвращает char *), к функциям системы.

Теперь, как Windows сама обрабатывает две разные версии переменных окружения, так как очевидно, что возможно передавать либо широкие, либо узкие строки окружения.

Целевой процесс имеет доступ только к GetEnvironmentStrings(), который возвращает либо широкие, либо узкие символы в зависимости от того, было ли приложение скомпилировано с поддержкой Unicode или без него.

Итак, что происходит, когда вы делаете CreateProcess() из узкого (ANSI) процесса, чтобы запустить процесс Unicode? То же самое, что происходит со всеми аргументами, они декодируются в кодовой странице вызывающего абонента и преобразуются в Windows-версию символов UCS-2.

Таким образом, правильный способ, вероятно, заключается в использовании системной кодовой страницы, поскольку только тогда строки будут корректно отображаться в целевом процессе unicode. Это, конечно, предотвращает использование символов не в этой кодовой странице ...

Так что да, среды Unicode на Python 2 более или менее разбиты.

+0

Если 'CreateProcessW' требуется в Python 2, попробуйте win32process вместо этого или даже ctypes. – eryksun

Смежные вопросы