subprocess.check_output () no parece existir (Python 2.6.5)

79

He estado leyendo la documentación de Python sobre el módulo de subproceso (ver aquí ) y habla de unsubprocess.check_output() comando que parece ser exactamente lo que necesito.

Sin embargo, cuando intento usarlo, aparece un error que indica que no existe y cuando lo ejecuto dir(subprocess)no aparece en la lista.

Estoy ejecutando Python 2.6.5, y el código que he usado es el siguiente:

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

¿Alguien tiene alguna idea de por qué está sucediendo esto?

robintw
fuente

Respuestas:

123

Fue introducido en 2.7 Ver los documentos .

Use subprocess.Popen si desea la salida:

>>> import subprocess
>>> output = subprocess.Popen(['ls', '-l'], stdout=subprocess.PIPE).communicate()[0]
user225312
fuente
14
a diferencia de check_output, esto no surge CalledProcessErrorcuando el proceso devuelve un código de retorno distinto de cero.
Sridhar Ratnakumar
1
@SridharRatnakumar: por supuesto porque hay una gran diferencia entre ellos, a saber: bloqueo y no bloqueo. ¡Son para diferentes casos de uso!
lpapp
Me metí en una lambdacomo esta: check_output = lambda args: Popen(args, stdout = PIPE).communicate()[0]. Solo porque estoy en un intérprete interactivo y es una especie de PITA escribir defs de funciones de varias líneas en esos. Usé from subprocess import Popen, PIPEanteriormente en la sesión.
ArtOfWarfare
como hacer un ping entonces ?? ¿Puedo seguir usando Popen o?
TheCrazyProfessor
56

SI se usa mucho en el código que desea ejecutar pero ese código no tiene que mantenerse a largo plazo (o necesita una solución rápida independientemente de los posibles dolores de cabeza de mantenimiento en el futuro), entonces podría esquivar el golpe (también conocido como parche de mono) en cualquier lugar donde se importe el subproceso ...

Simplemente levante el código de 2.7 e insértelo así ...

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

Es posible que se requiera inquietud leve.

Tenga en cuenta que la responsabilidad recae en usted para mantener pequeños puertos sucios como este. Si se descubren errores y se corrigen en la última versión de Python, entonces a) debe notarlo yb) actualizar su versión si desea mantenerse seguro. Además, anular y definir las funciones internas por ti mismo es la peor pesadilla del próximo chico, especialmente cuando el próximo chico eres USTED varios años después y te has olvidado de los trucos divertidos que hiciste la última vez. En resumen: rara vez es una buena idea.

Roger Heathcote
fuente
2
Estoy de acuerdo con este método. Probablemente incluiría la ubicación de la fuente. Puede encontrarlo en hg.python.org/cpython/file/d37f963394aa/Lib/subprocess.py#l544
Ehtesh Choudhury
1
Nota: CalledProcessError no acepta una salida en Python 2.6. (¡Me muerden inmediatamente después de usar este truco! :()
Andy Hayden
cpython ahora está en GitHub - check_outputpara Python 2.7 está actualmente aquí: github.com/python/cpython/blob/2.7/Lib/subprocess.py#L194
jamesc
6

Gracias a la sugerencia del parche de mono (y mis intentos fallaron, pero estábamos consumiendo la salida de CalledProcessError, así que necesitábamos parchear eso)

Encontré un parche 2.6 que funciona aquí: 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
afilado
fuente