Найти - Пользователи
Полная версия: subprocess и non-ASCII символы
Начало » Python для новичков » subprocess и non-ASCII символы
1 2
_alexs_
Для запуска стороннего консольного приложения из своей программы использую модуль subprocess. Код, отвечающий за запуск сейчас выглядит так (commands — список, содержащий команду и её аргументы):
cmd = ''.join(['%s ' % c for c in commands])
proc = subprocess.Popen(
    cmd,
    shell=True,
    stdout=subprocess.PIPE,
    stdin=subprocess.PIPE,
    stderr=subprocess.STDOUT,
    universal_newlines=False,
    ).stdout
Но если аргументы содержат non-ASCII символы (кириллицу, умляуты или вообще иероглифы), то Popen аварийно завершается с ошибкой «UnicodeEncodeError: ‘ascii’ codec can't encode character u'\xf3' in position 237: ordinal not in range(128)». Причем только в Windows, в Linux проблем нет.

Гугл подсказал, что модуль subprocess в Python 2.7.х не умеет работать с юникодными строками. В качестве workaround (например тут и тут) предлагают использовать перекодирование в кодировку файловой системы:
fse = sys.getfilesystemencoding()
cmd = ''.join(['%s ' % c.encode(fse) if isinstance(c, unicode) else c for c in commands])
proc = subprocess.Popen(
    cmd,
    shell=True,
    stdout=subprocess.PIPE,
    stdin=subprocess.PIPE,
    stderr=subprocess.STDOUT,
    universal_newlines=False,
    ).stdout

К сожалению, у меня этот трюк не сработал, точнее сработал как-то не так. Ошибка UnicodeEncodeError ушла, но пути стали «испорченными»: например было «D:\проба\relief.dat» стало «D:\i?iaa\relief.dat». При этом getfilesystemencoding() возвращает «mbcs». Чувствую, что упускаю какую-то мелочь из виду, но не могу сообразить какую именно.

Да, нужно кроссплатформенное и независимое от кодировок решение, которое будет работать и в Linux, и в Windows с любыми символами (кириллица, умляуты и т.д.). Python 2.7.х, перейти на тройку пока нет возможности.
py.user.next
#!/usr/bin/env python
# coding: utf-8
  
import subprocess as subp
  
p = subp.Popen([u'echo', u'x', u'б'], stdout=subp.PIPE)
p.wait()
print (p.stdout.read(), p.returncode)

Такой попробуй запустить.
_alexs_
В Linux работает, вывод ниже
('x \xd0\xb1\n', 0)
В Windows падает с UnicodeEncodeError
Traceback (most recent call last):
File "d:\test.py", line 6, in <module>
p = subp.Popen([u'echo', u'x', u'¦-'], stdout=subp.PIPE)
File "C:\OSGEO4~1\apps\Python27\lib\subprocess.py", line 711, in __init__ errread, errwrite)
File "C:\OSGEO4~1\apps\Python27\lib\subprocess.py", line 948, in _execute_child startupinfo)
UnicodeEncodeError: 'ascii' codec can't encode character u'\u0431' in position 7: ordinal not in range(128)
py.user.next
Поковырялся - дохлый номер. Винда.

import os
 
with os.popen('echo x б') as p:
    print p.read()
Kasta_neda
import os
 
with os.popen('echo x б') as p:
    print p.read().decode('cp866')
Если кроссплатформенное, то возможно придется делать проверку на ось, и запускать участок кода под эту ось, потому как с кодировкой в винде под 2 питон вечные затыки
Kasta_neda
#!/usr/bin/env python
# coding: utf-8
  
import subprocess
 
 
proc = subprocess.Popen(['echo', 'д'], shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
out = ' '
while out:
    out = proc.stdout.readline()
    print(out.rstrip().decode('cp866'))
py.user.next
Код Kasta_neda выводит не то, если у файла кодировка utf-8. Если файл в кодировке cp1251 (даже если декларирует utf-8), нормально выводит. Если же файл в utf-8 и декларируется utf-8, то символы правильно распознаются (в обычных строках), а subprocess выдаёт proc.stdout с вопросами.
Kasta_neda
Да, файл в кодировке cp1251 должен быть сохранен, или сохранен в utf-8 а декларирован в cp1251.
py.user.next
Kasta_neda
или сохранен в utf-8 а декларирован в cp1251

Не, в чём он записан, в том он и должен быть декларирован. Она (декларация) для того и придумана, чтобы питон мог раскодировать правильно.
_alexs_
py.user.next
Если файл в кодировке cp1251 (даже если декларирует utf-8), нормально выводит. Если же файл в utf-8 и декларируется utf-8, т
У меня все файлы имеют кодировку utf-8, менять её на cp1251 не вариант.

Похоже решения таки нет, жаль. Спасибо за помощь.
This is a "lo-fi" version of our main content. To view the full version with more information, formatting and images, please click here.
Powered by DjangoBB