Уведомления

Группа в Telegram: @pythonsu

#1 Сен. 27, 2011 11:53:08

Dwarf
От:
Зарегистрирован: 2011-05-09
Сообщения: 34
Репутация: +  0  -
Профиль   Отправить e-mail  

Запуск внешнего приложения. Убогая консоль Windows. Русские символы.

Python 2.7
Windows 7

Необходимо запустить внешнюю программу из Python.
Проблема 1. В пути к программе присутствуют русские символы.
Проблема 2. Программе нужно передать параметр-строку, которая представляет собой путь к другой папке (тоже с русскими символами).

Отчаянно гуглил по проблеме, накопал много инфы, пробовал по-всякому. Прошу, помогите её систематизировать и упорядочить, дабы решить проблему.

Что я понял.

1. Исходный код программы следует держать в UTF-8.
Для этого я вначале кода указал

# -*- coding: utf-8 -*-
А также все строки в программе (пути к файлам) указываю как
ur"C:\Директория1\Директория2"
2. Меня интересует самый простой запуск внешнего приложения, без премудростей (вроде отдельных питоньих потоков, процессов и прочего). Для этого, я так понял, подходит os.system
os.system(ur"C:\Директория1\Директория2\Приложение.exe")
Однако если я использую такой вариант, он ругается нечитаемыми символами в консоль питона (я запускаю скрипт из IDE PyCharm).

Поэтому я много гуглил, использовал различные советы и в конечном счёте у меня получилась такая программа:

Вот весь код программы
# -*- coding: utf-8 -*-
import subprocess
import sys
import codecs
import os

# эту функцию я нагуглил на сайте хабрахабр, вроде она должна решать проблемы с кодировкой
def setup_console(sys_enc="utf-8"):
reload(sys)
try:
# для win32 вызываем системную библиотечную функцию
if sys.platform.startswith("win"):
import ctypes
enc = "cp%d" % ctypes.windll.kernel32.GetOEMCP() #TODO: проверить на win64/python64
else:
# для Linux всё, кажется, есть и так
enc = (sys.stdout.encoding if sys.stdout.isatty() else
sys.stderr.encoding if sys.stderr.isatty() else
sys.getfilesystemencoding() or sys_enc)

# кодировка для sys
sys.setdefaultencoding(sys_enc)

# переопределяем стандартные потоки вывода, если они не перенаправлены
if sys.stdout.isatty() and sys.stdout.encoding != enc:
sys.stdout = codecs.getwriter(enc)(sys.stdout, 'replace')

if sys.stderr.isatty() and sys.stderr.encoding != enc:
sys.stderr = codecs.getwriter(enc)(sys.stderr, 'replace')

except:
pass # Ошибка? Всё равно какая - работаем по-старому...

setup_console()
path = ur"C:\Директория1\Директория2\Приложение.exe"
path = os.path.normpath(path)
os.system("chcp 65001")
os.system(path)
(для отладки я пока не использую передачу вызываемой программе параметров, просто вызываю её саму по себе)

Что получается в итоге: я получаю подобное сообщение в консоли (к счастью в корректной кодировке):
Active code page: 65001
The filename, directory name, or volume label syntax is incorrect.

Process finished with exit code 0
Также, если немного поэксперементировать с командой, меняя её, то выводится другое, но похожее сообщение:
The system cannot find the path specified
При этом сама команда на 100% верная. Если я её просто копирую из кода и вставляю в консоль она нормально выполняется.
Из чего я делаю вывод, что из вышеприведенного кода консоль винды не может понять как раз таки русские символы в путях и это всё портит.

Подскажите, как добиться того, чтобы консоль понимала и русские символы тоже.



Отредактировано (Сен. 27, 2011 11:54:40)

Офлайн

#2 Сен. 27, 2011 13:56:37

doza_and
От:
Зарегистрирован: 2010-08-15
Сообщения: 4138
Репутация: +  253  -
Профиль   Отправить e-mail  

Запуск внешнего приложения. Убогая консоль Windows. Русские символы.

1 :) Я оч злобный, поэтому указываю - вы пропустили самый главный совет: не делать путей с русскими символами и пробелами. Если есть - переименовать. В питоне это легко побороть, а в других языках проблемы почти непреодолимы.



Офлайн

#3 Сен. 27, 2011 14:18:04

Dwarf
От:
Зарегистрирован: 2011-05-09
Сообщения: 34
Репутация: +  0  -
Профиль   Отправить e-mail  

Запуск внешнего приложения. Убогая консоль Windows. Русские символы.

Моя программа это пакетный перекодировщик книг из fb2 в mobi. Алгоритм её работы заключается в рекурсивном обходе дерева папок с книгами и передаче каждой книги в качестве параметра стороннему перекодировщику fb2->mobi, который не поддерживает пакетный режим. Соответственно мой скрипт это этакая обёртка к нему.

Ладно, допустим можно легко переименовать путь к самой сторонней программе-перекодировщику.
Но вот с параметром, в котором передаётся путь к папке, уже сложнее.
Я скачал кучу книг с торрента, все книги рассортированы по папкам, названия которых представляют собой фамилии авторов, названия жанров.
Мало того, что мне неудобно будет потом работать с этой иерархией, если я всё запишу транслитом, так ещё и поддерживать торрент-раздачу после переименования не получится.

Да, можно создать отдельное дерево папок, не трогая исходное. Но это примитивный вариант, достаточно ёмкий по времени и костыльный.
Как вариант может создавать символьную ссылку с латинским названием на оригинальный файл, работать с ней, а потом питоном переименовывать полученный файл на русское название. Интересный вариант, но, сами понимаете, тоже костыльный.

В питоне это легко побороть, а в других языках проблемы почти непреодолимы.
Не понял, что именно в питоне легко побороть?



Офлайн

#4 Сен. 27, 2011 14:24:09

doza_and
От:
Зарегистрирован: 2010-08-15
Сообщения: 4138
Репутация: +  253  -
Профиль   Отправить e-mail  

Запуск внешнего приложения. Убогая консоль Windows. Русские символы.

Легко побороть русские символы в путях. Мне тут не дали закончить. Бороться с консолью не надо.
Сделайте os.system(“some command 1>1 2>2”) и ловите сообщения в файл.
ur“C:\Директория1\Директория2\Приложение.exe” можно заменить на
u“C:/Директория1/Директория2/Приложение.exe” Но это не принципиально.

По поводу юникода - вы правильно поняли. У меня Windows XP и os.system(u“ФФФ.exe”) работает без проблем.
Чего в семерке - не скажу. Поэтому если есть хоть малейшая возможность - не используйте в путях не латиницу.

Для проверки чего получается сделайте

os.system(u"python.exe tie.py ффф.txt")
а из tie.py сохраните в файл командную строку, чтобы разобраться что у вас приходит в cmd



Отредактировано (Сен. 27, 2011 14:27:22)

Офлайн

#5 Сен. 27, 2011 14:32:59

doza_and
От:
Зарегистрирован: 2010-08-15
Сообщения: 4138
Репутация: +  253  -
Профиль   Отправить e-mail  

Запуск внешнего приложения. Убогая консоль Windows. Русские символы.

ПО поводу пакетной перекодировки: Я не понял зачем эти танцы с бубном

def PathFind(pattr,root="."):
"""аналог find"""
for di,dl,fl in os.walk(root):
for f in glob.fnmatch.filter(fl,pattr):
yield os.path.join(di,f)
У меня этот генератор дает имена - пригодные для выполнения.
Может он вам поможет?
Перекодировщик можно и по русски назвать.
Мне кажется проблемы из-за того что вы консоль путаете - изменяя кодировку.
Если не получится пришлите архивчик небольшой который хотите перекодировать, я могу попробовать…



Отредактировано (Сен. 27, 2011 14:37:30)

Офлайн

#6 Сен. 27, 2011 15:49:00

Dwarf
От:
Зарегистрирован: 2011-05-09
Сообщения: 34
Репутация: +  0  -
Профиль   Отправить e-mail  

Запуск внешнего приложения. Убогая консоль Windows. Русские символы.

doza_and
Легко побороть русские символы в путях. Мне тут не дали закончить. Бороться с консолью не надо.
Сделайте os.system(“some command 1>1 2>2”) и ловите сообщения в файл.
ur“C:\Директория1\Директория2\Приложение.exe” можно заменить на
u“ChmmДиректория1/Директория2/Приложение.exe” Но это не принципиально.

По поводу юникода - вы правильно поняли. У меня Windows XP и os.system(u“ФФФ.exe”) работает без проблем.
Чего в семерке - не скажу. Поэтому если есть хоть малейшая возможность - не используйте в путях не латиницу.

Для проверки чего получается сделайте
Код:

os.system(u“python.exe tie.py ффф.txt”)

а из tie.py сохраните в файл командную строку, чтобы разобраться что у вас приходит в cmd
Извините, не уловил, что вы имели в виду.

doza_and
ПО поводу пакетной перекодировки: Я не понял зачем эти танцы с бубном
Что именно вам не понятно?

doza_and
У меня этот генератор дает имена - пригодные для выполнения.
Боюсь я с генераторами ещё не работал и не совсем понимаю принцип их работы.

doza_and
Может он вам поможет?
Вроде проблемы с обходом дерева папок нет. На каждом шаге я получаю UTF-8 строку, которую надо скормить в качестве параметра сторонней программе.

А нельзя ли запускать стороннюю софтину в обход консоли Windows?



Офлайн

#7 Сен. 27, 2011 20:15:49

Dwarf
От:
Зарегистрирован: 2011-05-09
Сообщения: 34
Репутация: +  0  -
Профиль   Отправить e-mail  

Запуск внешнего приложения. Убогая консоль Windows. Русские символы.

Сейчас попытался сделать через костыль: сначала прокидывать симлинк с англопутём на целевой файл с русским путём.

Симлинк прокидываю с помощью функции

win32file.CreateSymbolicLink(temp_file, filename, 1)
Дык нет, тоже не хочет, ругается:
Active code page: 65001
Traceback (most recent call last):
File “D:/dev/python/books_converter/book_converter/book_converter.py”, line 77, in <module>
convert_files_from_dir(files)
File “D:/dev/python/books_converter/book_converter/book_converter.py”, line 14, in convert_files_from_dir
win32file.CreateSymbolicLink(temp_file, filename, 1)
pywintypes.error: (1314, ‘CreateSymbolicLink’, ‘\xca\xeb\xe8\xe5\xed\xf2 \xed\xe5 \xee\xe1\xeb\xe0\xe4\xe0\xe5\xf2 \xf2\xf0\xe5\xe1\xf3\xe5\xec\xfb\xec\xe8 \xef\xf0\xe0\xe2\xe0\xec\xe8.’)

Process finished with exit code 1



Офлайн

#8 Сен. 27, 2011 20:18:09

Dwarf
От:
Зарегистрирован: 2011-05-09
Сообщения: 34
Репутация: +  0  -
Профиль   Отправить e-mail  

Запуск внешнего приложения. Убогая консоль Windows. Русские символы.

Пытался декодировать строки в cp866 прежде чем скармливать их функции

win32file.CreateSymbolicLink(temp_file.encode("cp866"), filename.encode("cp866"), 1)
Дык нет, пишет что не может сконвертировать ибо символы (русские видимо) выходят за диапазон 128.



Офлайн

#9 Сен. 27, 2011 20:18:16

Андрей Светлов
От:
Зарегистрирован: 2007-05-15
Сообщения: 3137
Репутация: +  14  -
Профиль   Адрес электронной почты  

Запуск внешнего приложения. Убогая консоль Windows. Русские символы.

import subprocess



Офлайн

#10 Сен. 27, 2011 21:37:40

doza_and
От:
Зарегистрирован: 2010-08-15
Сообщения: 4138
Репутация: +  253  -
Профиль   Отправить e-mail  

Запуск внешнего приложения. Убогая консоль Windows. Русские символы.

#!/usr/bin/env python
# -*- coding: cp1251 -*-
import subprocess as sp
import os
#sp.call("фыв.exe")
os.system("фыв.exe")
работает в обоих случаях. Это не юникод конечно.
Если не получится шлите аську, Попробуем тогда оперативно понять в чем ваша проблема.



Офлайн

Board footer

Модераторировать

Powered by DjangoBB

Lo-Fi Version