Python: os.device_encoding изменяется при вызове из подпроцесса, что приводит к ошибке декодирования в Windows. Как принPython

Программы на Python
Ответить
Anonymous
 Python: os.device_encoding изменяется при вызове из подпроцесса, что приводит к ошибке декодирования в Windows. Как прин

Сообщение Anonymous »

Описание проблемы
У меня есть следующий код Python 3.7 в импортированном пакете, который я не могу изменить, который считывает и декодирует имя системного компилятора, предоставленное disttools:

Код: Выделить всё

# subproc.py

import os
import sys
import locale
import subprocess
from distutils.ccompiler import new_compiler

ccompiler = new_compiler()
ccompiler.initialize()
cc = subprocess.check_output(f"{ccompiler.cc}", stderr=subprocess.STDOUT, shell=True)
encoding = os.device_encoding(sys.stdout.fileno()) or locale.getpreferredencoding()
print("Encoding:", encoding)
compiler_name = cc.decode(encoding).partition("\n")[0].strip()
print("Compiler name:", compiler_name)
При прямом вызове, т. е. непосредственном запуске subprocess.py, все работает нормально. Имя компилятора правильно идентифицируется как «Microsoft (R) C/C++-Optimierungscompiler Version 19.42.34433 für x64» (я думаю, причина проблемы в ü)
Однако, когда я вызываю его с помощью subprocess.Popen(), os.device_encoding возвращает None вместо cp850 (он же utf-8), в результате чего программа по умолчанию использует кодировку Windows cp1242 (aka ), что затем приводит к тому, что cc.decode(encoding) вызывает ошибку UnicodeDecodeError: кодек 'charmap' не может декодировать байт 0x81 в позиции 62: символ соответствует .
Вот как я запускаю подпроцесс:

Код: Выделить всё

# call_subprocess.py

import subprocess

subprocess.Popen(
[
"python",
"C:/path/to/subproc.py",
],
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
)
Вопрос
Насколько я понимаю, os.device_encoding(sys.stdout.fileno()) не может найти кодировку, поскольку подпроцесс выполняется в фоновом режиме, без терминала. Кроме того, Windows всегда будет предоставлять cp1242 при запросе с помощью locale.getpreferredencoding().
Поскольку я не могу редактировать код во внешнем пакете, есть ли способ вызвать подпроцесс, чтобы заставить любую из этих команд вернуть cp850?
Варианты, которые я пытался решить проблему:
  • Явно установить кодировку в Popen:

    Код: Выделить всё

    subprocess.Popen(
    ...
    text=True,
    encoding="cp850",
    )
    
  • Явно установите PYTHONIOENCODING в среде подпроцесса:

    Код: Выделить всё

    environ = os.environ.copy()
    environ['PYTHONIOENCODING'] = 'utf-8'
    ...
    subprocess.Popen(
    ...
    env=environ,
    encoding='utf-8',
    )
    
  • Используйте subprocess.run() вместо subprocess.Popen()
  • Различные комбинации приведенных выше решений.
Ресурсы, которые я уже просматривал

[*]Подпроцесс использует неверную кодировку в Windows
[*]Ошибка кодирования, выполняемая в подпроцессе с захваченным вывод
[*]Изменение предпочтительной кодировки локали для самого компьютера -> Работает, но нежелательно, поскольку код должен быть исполняемым на разных машинах без индивидуальной настройки каждый раз.


Подробнее здесь: https://stackoverflow.com/questions/793 ... ing-decodi
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «Python»