2011-01-27 10 views
73

Ho letto la documentazione Python sul modulo di sottoprocesso (vedere here) e parla di un comando subprocess.check_output() che sembra essere esattamente ciò che io bisogno.subprocess.check_output() non sembra esistere (Python 2.6.5)

Tuttavia, quando provo a utilizzarlo, ricevo un messaggio di errore che non esiste e quando eseguo dir(subprocess) non è elencato.

Sono in esecuzione Python 2.6.5, e il codice che ho usato è qui sotto:

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

Qualcuno ha qualche idea del perché questo sta accadendo?

risposta

110

È stato introdotto in 2.7 Vedere lo docs.

Usa subprocess.Popen se si desidera che l'output:

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

differenza check_output, questo non genera 'CalledProcessError' quando il processo restituisce un codice di ritorno diverso da zero. –

+1

@SridharRatnakumar: ovviamente perché c'è una grande differenza tra loro, vale a dire: blocco e non blocco. Sono per diversi casi d'uso! – lpapp

+0

L'ho inserito in un 'lambda' in questo modo:' check_output = lambda args: Popen (args, stdout = PIPE) .communicate() [0] '. Solo perché sono in un interprete interattivo ed è una specie di PITA a scrivere le funzioni di definizione multilinea in quelle. Ho usato 'dal sottoprocesso di importazione Popen, PIPE' all'inizio della sessione. – ArtOfWarfare

54

SE è usato pesantemente nel codice che si desidera eseguire, ma che il codice non deve essere mantenuta a lungo termine (o avete bisogno di un soluzione rapida indipendentemente potenziali problemi di manutenzione in futuro), allora si potrebbe anatra punzone (aka patch di scimmia) in ovunque sottoprocesso è importata ...

Basta sollevare il codice da 2.7 e inserirla questa convenzione ...

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 

Potrebbe essere necessario un minore disturbo.

Tieni a mente, anche se l'onere è su di te per mantenere sporchi piccoli backport come questo. Se i bug vengono scoperti e corretti nell'ultimo python, allora a) devi notarlo e b) aggiornare la tua versione se vuoi rimanere al sicuro. Inoltre, ignorare lo & definendo le funzioni interne da solo è il peggior incubo del ragazzo successivo, specialmente quando il prossimo ragazzo è TU diversi anni dopo la linea e hai dimenticato tutti gli hack che hai fatto l'ultima volta! In breve: raramente è una buona idea.

+1

Concordo con questo metodo. Probabilmente includerei la posizione della fonte. Puoi trovarlo su http://hg.python.org/cpython/file/d37f963394aa/Lib/subprocess.py#l544 –

+1

Nota: CalledProcessError non accetta un output in python 2.6. (Sono subito morso dopo aver usato questo trucco! :() –

3

Grazie al suggerimento di patch scimmia (e miei tentativi in ​​mancanza - ma siamo stati consumando uscita CalledProcessError, avevamo bisogno di patch di scimmia che)

trovato un lavoro 2,6 cerotto qui: 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 
Problemi correlati