реализация юникода на python (с использованием внешних программ: cygnative plink ssh rsync)

У меня есть приложения для резервного копирования на python, которые должны работать в Windows. Требуется совместимость с UTF (чтобы иметь возможность создавать резервные копии каталогов, содержащих символы UTF, такие как итальянские акценты). Проблема в том, что он использует внешние программы (plink, cygwin, ssh и rsync), и я не могу заставить их работать. Прототип состоит из 32 строк, взгляните:

# -*- coding: utf-8 -*-
import subprocess

def safestr(obj, encoding='utf-8'):
    r"""Converts any given object to utf-8 encoded string.

        >>> safestr('hello')
        'hello'
        >>> safestr(u'\u1234')
        '\xe1\x88\xb4'
        >>> safestr(2)
        '2'
    """
    if isinstance(obj, unicode):
        return obj.encode("utf-8")
    elif isinstance(obj, str):
        return obj.encode
    else:
        return str(obj)

def execute(command):
    pipe = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.PIPE)
    out, errs = pipe.communicate()
    retcode = pipe.poll()

    print "OUT: " + repr(out)
    print "ERRS: " + repr(errs)
    print "RET: " + str(retcode)


command = u'rsync --stats -az --numeric-ids --delete --blocking-io --modify-window=2 --no-group --chmod=u=rwX,g=,o=  -e \'cygnative plink -ssh -2 -batch  -pw test \' "/cygdrive/c/κόσμε" [email protected]:/volatile/backup/vaidab/2010-03-03.15_41_56/ --link-dest=../2010-03-03.15_00_57'.encode('utf-8')
execute(command)

Все еще не работает с версией nosklo, проверьте результат:

python prototype_unicode_new.py 'rsync.exe --stats -az --numeric-ids --delete --blocking-io --modify-window=2 -- no-group --chmod=u=rwX,g=,o = -e "cygnative plink -ssh -2 -batch -pw test" /cygdr ive/c/\xce\xba\xcf\x8c\xcf\x83\xce\xbc\xce\xb5 [email protected]:/volatile /резервная копия/vaidab/2010-03-03.15_41_56/'

OUT: '\nКоличество файлов: 0\nКоличество переданных файлов: 0\nОбщий размер файла: 0 байт\nОбщий размер переданного файла: 0 байт\nЛитеральные данные: 0 байт\nСопоставленные данные: 0 байт\nРазмер списка файлов: 9 \nВремя создания списка файлов: 0,001 секунды\nВремя передачи списка файлов: 0,000 секунд\nВсего отправлено байтов: 22\nВсего получено байтов: 12\n\ nОтправлено 22 получено байтов 12 байтов 68,00 байт/сек\nОбщий размер равен 0, ускорение равно 0,00\ n' ОШИБКИ: 'rsync: link_stat "/cygdrive/c/\xc3\x8e\xc2\xba\xc3\x8f\xc5\x92\xc3\x8f\xc 6\x92\xc3\x8e\xc2\xbc\xc3\ x8e\xc2\xb5" не удалось: такого файла или каталога нет (2)\nrs ошибка синхронизации: некоторые файлы/атрибуты не были переданы (см. предыдущие ошибки) (код 23) в /home/lapo/packaging/rsync-3.0.6 -1/src/rsync-3.0.6/main.c(1039) [отправитель=3.0. 6]\n' РЕТ: 23


person vaidab    schedule 09.03.2010    source источник
comment
Пожалуйста, включите код в свой вопрос (для этого есть специальная разметка). Вы не можете ожидать, что мы загрузим zip-файл...   -  person ChristopheD    schedule 09.03.2010
comment
32 строки слишком мало. Пожалуйста, скопируйте источник и вставьте его в вопрос.   -  person nosklo    schedule 09.03.2010
comment
Я включил в zip-файл двоичные файлы (rsync, cygnative, plink и ssh + dll, чтобы вы могли использовать все инструменты)   -  person vaidab    schedule 09.03.2010


Ответы (2)


  • Не используйте shell=True. НИКОГДА. Он без необходимости вызывает оболочку для вызова вашей программы.
  • Передайте параметры в виде списка, а не строки.

Этот пример должен работать, если параметры правильные и rsync.exe находится в текущей папке (или PATH):

# -*- coding: utf-8 -*-
import subprocess

def execute(command):
    pipe = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    out, errs = pipe.communicate()
    retcode = pipe.poll()

    print "OUT: " + repr(out)
    print "ERRS: " + repr(errs)
    print "RET: " + str(retcode)
    return out


command = ['rsync.exe', '--stats', '-az', '--numeric-ids', '--delete', 
           '--blocking-io', '--modify-window=2', '--no-group', 
           '--chmod=u=rwX,g=,o=', '-e', 
           'cygnative plink -ssh -2 -batch -pw test', 
           u'/cygdrive/c/κόσμε'.encode('utf-8'), 
           '[email protected]:/volatile/backup/vaidab/2010-03-03.15_41_56/', 
           '--link-dest=../2010-03-03.15_00_57']

execute(command)
person nosklo    schedule 09.03.2010
comment
Ну, тогда кажется, что ваша файловая система не utf-8. Что возвращает sys.getfilesystemencoding()? Возможно, попробуйте использовать это как кодировку? - person nosklo; 09.03.2010
comment
он возвращает mbcs. Я изменил на .encode('mbcs') и: группа --chmod=u=rwX,g=,o= -e cygnative plink -ssh -2 -batch -pw test /cygdr ive/c/??s\xb5e [email protected]:/volatile/backup/vaidab /2010-03-03.15_41_56/' ... ОШИБКИ: 'rsync: link_stat /cygdrive/c/??s\xc2\xb5e не удалось: нет такого файла или каталога - person vaidab; 10.03.2010
comment
@vaidab: вы можете запустить команду в командной строке? Какую кодировку использует ваша программа терминала/консоли? - person nosklo; 10.03.2010
comment
После установки итальянского языка я получаю: sys.getdefaultencoding() ascii sys.stdout.encoding() cp437 - person vaidab; 11.03.2010
comment
@vaidab: какой редактор вы используете для редактирования исходного файла? Может ли редактор сохранить файл в utf-8? - person nosklo; 12.03.2010
comment
Я использую vim, и символы utf-8, которые я набираю в исходном файле, нормально работают в Linux (я создаю с ними каталог и проверяю его существование). - person vaidab; 19.03.2010

Кусок кода, который превосходит все понимание:

if isinstance(obj, unicode):
    return obj.encode("utf-8")
elif isinstance(obj, str):
    return obj.encode
    # the above is returning a METHOD ***************************
else:
    return str(obj)

Какой смысл в доктестах, если вы их не проводите?

person John Machin    schedule 09.03.2010
comment
правда, это был остаток, извините за это. - person vaidab; 10.03.2010