2011-01-27 10 views
73

He estado leyendo la documentación de Python sobre el módulo de subproceso (consulte here) y se trata de un comando subprocess.check_output() que parece ser exactamente lo que necesitar.subprocess.check_output() no parece existir (Python 2.6.5)

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

Me postulo Python 2.6.5, y el código que he utilizado es el siguiente:

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

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

Respuesta

110

Se introdujo en 2.7 Consulte el docs.

Uso subprocess.Popen si desea que la salida:

>>> import subprocess 
>>> output = subprocess.Popen(['ls', '-l'], stdout=subprocess.PIPE).communicate()[0] 
+14

diferencia check_output, esto no aumenta 'CalledProcessError' cuando el proceso devuelve un código de retorno distinto de cero. –

+1

@SridharRatnakumar: por supuesto, porque hay una gran diferencia entre ellos, a saber: bloqueo y no bloqueo. ¡Son para diferentes casos de uso! – lpapp

+0

Lo empujé en una 'lambda' como 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 para escribir defs de función multilínea en esos. Utilicé 'del subproceso importan Popen, PIPE' anteriormente en la sesión. – ArtOfWarfare

54

SI se utiliza en gran medida en el código que desee ejecutar, sino que el código no tiene que ser mantenida a largo plazo (o necesita un solución rápida, independientemente de los posibles problemas de mantenimiento en el futuro), entonces usted podría golpe de pato (también conocido como parche mono) en donde ha sido importada subproceso ...

Sólo levanta el código de 2,7 e insertarlo thusly ...

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 una inquietud menor.

Tenga en cuenta que la responsabilidad recae sobre usted para mantener los pequeños backports sucios como este. Si se descubren y corrigen errores en la última versión de python, entonces a) tiene que darse cuenta de eso yb) actualizar su versión si desea permanecer seguro. Además, anular & definir las funciones internas es la peor pesadilla del siguiente tipo, especialmente cuando el siguiente tipo es USTED varios años después y ¡se olvidó de los hackers que hizo la última vez! En resumen: rara vez es una buena idea.

+1

Estoy de acuerdo con este método. Probablemente incluiría la ubicación de la fuente. Puede encontrarlo en http://hg.python.org/cpython/file/d37f963394aa/Lib/subprocess.py#l544 –

+1

Nota: CalledProcessError no acepta un resultado en python 2.6. (Me picaron inmediatamente después de usar este truco! :() –

3

Gracias a la sugerencia de parches mono (y mis intentos fallan - pero estábamos consumiendo salida CalledProcessError, así que era necesario parche mono que)

encontró un 2,6 parche de trabajo 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 
Cuestiones relacionadas