implementação python unicode (usando programas externos: cygnative plink ssh rsync)
Pergunta
Eu tenho um aplicativos de backup em python que precisa trabalhar no Windows. Ele precisa de compatibilidade UTF (para ser capaz de diretórios de backup que contêm caracteres UTF como acentos italiano). O problema é que ele usa programas externos (plink, cygwin, ssh e rsync) e eu não posso levá-los a trabalhar. O protótipo é de 32 linhas longas, por favor, dê uma olhada:
# -*- 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/κόσμε" vaidab@192.168.1.86:/volatile/backup/vaidab/2010-03-03.15_41_56/ --link-dest=../2010-03-03.15_00_57'.encode('utf-8')
execute(command)
ainda não funciona com a versão de nosklo, verificar o resultado:
prototype_unicode_new.py python 'Rsync.exe --stats -az --numeric-ids --delete --blocking-io --modify-janela = 2 - não-grupo --chmod = u = RWX, g =, o = -e "cygnative Plink -ssh -2 -batch -pw teste" / cygdr ive / c / \ XCE \ Xba \ xcf \ x8c \ xcf \ x83 \ XCE \ XBC \ XCE \ XB5 vaidab@192.168.1.86: / volátil / bac kup / väidab / 2010-03-03.15_41_56 / '
OUT: '\ nNúmero de arquivos: 0 \ nNúmero de arquivos transferidos: tamanho do arquivo 0 \ nTotal: 0 b ytes \ nTotal transferido tamanho: 0 bytes \ data nLiteral: 0 bytes \ data nMatched: 0 bytes \ o tamanho da lista nArquivar: 9 \ nArquivar tempo lista geração: 0,001 segundos \ lista nArquivar tempo de transferência: 0,000 segundos \ nTotal bytes enviado: 22 \ nTotal bytes recebidos: 12 \ n \ nsent 22 bytes recebidos bytes 12 68.00 bytes / seg \ tamanho Ntotal é 0 aumento de velocidade é 0.00 \ n' Erra: '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" Falha: Nenhum tal lima ou diretório (2) \ nrs erro YNC: alguns arquivos / attrs não foram transferidos (ver erros anteriores) (código 23) em /home/lapo/packaging/rsync-3.0.6-1/src/rsync-3.0.6/main.c(1039) [remetente = 3,0. 6] \ n' RET: 23
Solução
- Não use
shell=True
. sempre . Ele needlessy invoca um shell para chamar seu programa. - Passe os parâmetros como uma lista em vez de uma string.
Este exemplo deve funcionar, desde que os parâmetros são direito eo rsync.exe está na pasta atual (ou 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'),
'vaidab@192.168.1.86:/volatile/backup/vaidab/2010-03-03.15_41_56/',
'--link-dest=../2010-03-03.15_00_57']
execute(command)
Outras dicas
Um pedaço de código que excede todo o entendimento:
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)
O que é o ponto de doctests se você não executá-los?