web-dev-qa-db-fra.com

Python popen () - communique (str.encode (encoding = "utf-8", errors = "ignore")) se bloque

Utilisation de Python 3.4.3 sous Windows.

Mon script exécute un petit programme Java dans la console et devrait obtenir le résultat:

import subprocess
p1 = subprocess.Popen([ ... ], stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True)
out, err = p1.communicate(str.encode("utf-8"))

Cela conduit à une normale 

'UnicodeDecodeError: le codec' charmap 'ne peut pas décoder l'octet 0x9d en position 135: les mappages de caractères sur <non défini>'.

Maintenant, je veux ignorer les erreurs:

out, err = p1.communicate(str.encode(encoding="utf-8", errors="ignore"))

Cela conduit à une erreur plus intéressante je n'ai trouvé aucune aide pour utiliser Google:

TypeError: le descripteur 'encode' de l'objet 'str' a besoin d'un argument

Il semble donc que python ne sache même plus quels sont les arguments de str.encode (...). Il en va de même lorsque vous omettez la partie erreurs.

7
user136036

universal_newlines=True active le mode texte. Combiné à stdout=PIPE, il force le décodage de la sortie du processus enfant à l'aide de locale.getpreferredencoding(False) qui n'est pas utf-8 sous Windows. C'est pourquoi vous voyez UnicodeDecodeError.

Pour lire la sortie du sous-processus en utilisant le codage utf-8, supprimez universal_newlines=True:

#!/usr/bin/env python3
from subprocess import Popen, PIPE

with Popen(r'C:\path\to\program.exe "arg 1" "arg 2"',
           stdout=PIPE, stderr=PIPE) as p:
    output, errors = p.communicate()
lines = output.decode('utf-8').splitlines()

str.encode("utf-8") est équivalent à "utf-8".encode(). Il est inutile de le transmettre à .communicate() à moins que vous ne définissiez stdin=PIPE et que le processus enfant attende b'utf-8' bytestring en tant qu'entrée.

str.encode(encoding="utf-8", errors="ignore) a la forme klass.method(**kwargs). La méthode .encode() attend self (un objet chaîne), raison pour laquelle vous voyez TypeError.

>>> str.encode("abc", encoding="utf-8", errors="ignore") #XXX don't do it
b'abc'
>>> "abc".encode(encoding="utf-8", errors="ignore")
b'abc'

N'utilisez pas klass.method(obj) au lieu de obj.method() sans une bonne raison.

10
jfs

Vous n'êtes pas censé appeler .encode() sur la classe elle-même. Ce que vous voulez probablement faire est quelque chose comme

p1.communicate("FOOBAR".encode("utf-8"))

Le message d'erreur que vous obtenez signifie que la fonction encode() n'a rien à coder, puisque vous l'avez appelée sur la classe plutôt que sur une instance (qui serait ensuite passée en tant que paramètre self à encode()).

2
cemper93