subproc.py
import osimport 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, вызывая программа по умолчанию использует кодировку Windows cp1252, что затем приводит к тому, что cc.decode(encoding) вызывает "UnicodeDecodeError: кодек 'charmap' не может декодировать байт 0x81 в позиции 62: символ сопоставляется с ".
Вот как я запускаю подпроцесс:
call_subprocess.py
import subprocesssubprocess.Popen(
[
"python",
"C:/path/to/subproc.py",
],
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
)
Насколько я понимаю, os.device_encoding(sys.stdout.fileno()) не может найти кодировку, поскольку подпроцесс выполняется в фоновом режиме без терминала. Кроме того, Windows всегда будет предоставлять cp1252 при запросе с помощью 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
- Ошибка кодирования, выполняемая в подпроцессе с захваченным вывод
- Изменение предпочтительной кодировки локали для самого компьютера: Панель управления > Часы и регион > Регион > Администрирование > Изменить языковой стандарт системы > Проверить бета-версию: использовать Unicode UTF-8 > Перезагрузка -> Работает , но это нежелательно, так как код должен быть исполняемым на разных машинах без индивидуальной настройки каждый раз.
- Поскольку в моем случае подпроцесс был достаточно изолирован от другого кода и имел собственную функцию запуска, я использовал следующие строки перед первый импорт локали для переопределения возвращаемого значения locale.getdefaultlocale() (Источник):
# This is necessary to avoid issues with the default locale on Windows.
# It might cause issues on computers not in western countries, that do not use cp850.
import _locale
_locale._getdefaultlocale = lambda *args: ["en_US", "cp850"]
Подробнее здесь: https://stackoverflow.com/questions/793 ... ding-error
Мобильная версия