subprocess.check_output () scheint nicht zu existieren (Python 2.6.5)

79

Ich habe die Python-Dokumentation über das Unterprozessmodul gelesen (siehe hier ) und es handelt sich um einen subprocess.check_output()Befehl, der genau das zu sein scheint, was ich brauche.

Wenn ich jedoch versuche, es zu verwenden, erhalte ich die Fehlermeldung, dass es nicht vorhanden ist, und wenn ich es ausführe dir(subprocess), wird es nicht aufgelistet.

Ich verwende Python 2.6.5 und der Code, den ich verwendet habe, ist unten:

import subprocess
subprocess.check_output(["ls", "-l", "/dev/null"])

Hat jemand eine Idee, warum dies geschieht?

robintw
quelle

Antworten:

123

Es wurde in 2.7 eingeführt. Siehe die Dokumente .

Verwenden Sie subprocess.Popen, wenn Sie die Ausgabe wünschen:

>>> import subprocess
>>> output = subprocess.Popen(['ls', '-l'], stdout=subprocess.PIPE).communicate()[0]
user225312
quelle
14
Im Gegensatz zu check_output wird dies nicht ausgelöst, CalledProcessErrorwenn der Prozess einen Rückkehrcode ungleich Null zurückgibt.
Sridhar Ratnakumar
1
@SridharRatnakumar: Natürlich, weil es einen großen Unterschied zwischen ihnen gibt, nämlich: Blockieren und Nicht-Blockieren. Sie sind für verschiedene Anwendungsfälle!
lpapp
Ich habe es so geschoben lambda: check_output = lambda args: Popen(args, stdout = PIPE).communicate()[0]. Nur weil ich in einem interaktiven Interpreter bin und es eine Art PITA ist, mehrzeilige Funktionsdefekte in diese zu schreiben. Ich habe from subprocess import Popen, PIPEfrüher in der Sitzung verwendet.
ArtOfWarfare
Wie mache ich dann einen Ping? kann ich noch Popen benutzen oder?
TheCrazyProfessor
56

WENN es in dem Code, den Sie ausführen möchten, häufig verwendet wird, dieser Code jedoch nicht langfristig gewartet werden muss (oder Sie eine schnelle Lösung benötigen, unabhängig von möglichen Wartungsproblemen in der Zukunft), können Sie sich ducken (auch bekannt als Affen-Patch). es überall dort, wo ein Unterprozess importiert wird ...

Heben Sie einfach den Code von 2.7 an und fügen Sie ihn so ein ...

import subprocess

if "check_output" not in dir( subprocess ): # duck punch it in!
    def f(*popenargs, **kwargs):
        if 'stdout' in kwargs:
            raise ValueError('stdout argument not allowed, it will be overridden.')
        process = subprocess.Popen(stdout=subprocess.PIPE, *popenargs, **kwargs)
        output, unused_err = process.communicate()
        retcode = process.poll()
        if retcode:
            cmd = kwargs.get("args")
            if cmd is None:
                cmd = popenargs[0]
            raise subprocess.CalledProcessError(retcode, cmd)
        return output
    subprocess.check_output = f

Möglicherweise ist ein geringfügiges Zappeln erforderlich.

Denken Sie daran, dass es Ihre Pflicht ist, schmutzige kleine Backports wie diesen zu pflegen. Wenn Fehler in der neuesten Python entdeckt und behoben werden, müssen Sie a) dies beachten und b) Ihre Version aktualisieren, wenn Sie sicher bleiben möchten. Das Überschreiben und Definieren interner Funktionen selbst ist der schlimmste Albtraum des nächsten Mannes, besonders wenn der nächste Mann mehrere Jahre später DU bist und du alles über die Grody-Hacks vergessen hast, die du das letzte Mal gemacht hast! Zusammenfassend: Es ist sehr selten eine gute Idee.

Roger Heathcote
quelle
2
Ich stimme dieser Methode zu. Ich würde wahrscheinlich den Ort der Quelle angeben. Sie finden es unter hg.python.org/cpython/file/d37f963394aa/Lib/subprocess.py#l544
Ehtesh Choudhury
1
Hinweis: CalledProcessError akzeptiert keine Ausgabe in Python 2.6. (Ich bin sofort gebissen, nachdem ich diesen Hack benutzt habe! :()
Andy Hayden
cpython ist jetzt auf GitHub - check_outputfür Python 2.7 ist derzeit hier: github.com/python/cpython/blob/2.7/Lib/subprocess.py#L194
jamesc
6

Dank des Affen-Patch-Vorschlags (und meiner fehlgeschlagenen Versuche - aber wir haben die CalledProcessError-Ausgabe verbraucht, mussten diese also mit einem Affen-Patch versehen).

Hier wurde ein funktionierender 2.6-Patch gefunden: http://pydoc.net/Python/pep8radius/0.9.0/pep8radius.shell/

"""Note: We also monkey-patch subprocess for python 2.6 to
give feature parity with later versions.
"""
try:
    from subprocess import STDOUT, check_output, CalledProcessError
except ImportError:  # pragma: no cover
    # python 2.6 doesn't include check_output
    # monkey patch it in!
    import subprocess
    STDOUT = subprocess.STDOUT

    def check_output(*popenargs, **kwargs):
        if 'stdout' in kwargs:  # pragma: no cover
            raise ValueError('stdout argument not allowed, '
                             'it will be overridden.')
        process = subprocess.Popen(stdout=subprocess.PIPE,
                                   *popenargs, **kwargs)
        output, _ = process.communicate()
        retcode = process.poll()
        if retcode:
            cmd = kwargs.get("args")
            if cmd is None:
                cmd = popenargs[0]
            raise subprocess.CalledProcessError(retcode, cmd,
                                                output=output)
        return output
    subprocess.check_output = check_output

    # overwrite CalledProcessError due to `output`
    # keyword not being available (in 2.6)
    class CalledProcessError(Exception):

        def __init__(self, returncode, cmd, output=None):
            self.returncode = returncode
            self.cmd = cmd
            self.output = output

        def __str__(self):
            return "Command '%s' returned non-zero exit status %d" % (
                self.cmd, self.returncode)
    subprocess.CalledProcessError = CalledProcessError
daran interessiert
quelle