2011-01-27 15 views
73

Czytałem dokumentację Pythona na temat modułu podprocesowego (zobacz here) i mówi o poleceniu subprocess.check_output(), które wydaje się być dokładnie tym, co ja potrzeba.subprocess.check_output() wydaje się nie istnieć (Python 2.6.5)

Jednak gdy próbuję go użyć, pojawia się błąd, który nie istnieje, a po uruchomieniu dir(subprocess) nie ma go na liście.

Używam Python 2.6.5, a kod użyłem jest poniżej:

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

Czy ktoś ma jakiś pomysł, dlaczego tak się dzieje?

Odpowiedz

110

Został wprowadzony w wersji 2.7. Patrz: docs.

Zastosowanie subprocess.Popen jeśli chcesz wyjście:

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

przeciwieństwie check_output, to nie wywołuje 'CalledProcessError', gdy proces zwraca niezerowy kod powrotu. –

+1

@SridharRatnakumar: oczywiście, ponieważ istnieje między nimi duża różnica, a mianowicie: blokowanie i nie blokowanie. Są one przeznaczone do różnych zastosowań! – lpapp

+0

Wepchnąłem to w 'lambda' w ten sposób:' check_output = Argumenty lambda: Popen (args, stdout = PIPE) .communicate() [0] '. Tylko dlatego, że jestem w interakcyjnym tłumaczu i to jest rodzaj PITA do wypisywania w tych funkcjach funkcji multilinii. Użyłem 'z podprocesowego importu Popen, PIPE' wcześniej w sesji. – ArtOfWarfare

54

IF jest używany intensywnie w kodzie, który chcesz uruchomić, ale że kod nie musi być utrzymywana długoterminowy (lub potrzebują szybkie ustalenie niezależnie od potencjalnych bóle głowy konserwacji w przyszłości), a następnie można kaczka stempel (aka małpa Patch) to w gdziekolwiek podproces jest importowany ...

Wystarczy podnieść kod z 2,7 i włóż go 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 

Może być wymagane drobne wiercenie.

Pamiętaj jednak, że ponosisz odpowiedzialność za utrzymywanie brudnych, niewielkich backportów w ten sposób. Jeśli błędy zostaną wykryte i poprawione w najnowszym pythonie, musisz a) to zauważyć i b) zaktualizować wersję, jeśli chcesz zachować bezpieczeństwo. Nadpisywanie & samemu określając wewnętrzne funkcje jest najgorszym koszmarem następnego faceta, szczególnie, gdy następny facet jest TY kilka lat w dół i zapomniałeś o grach hakerskich, które zrobiłeś ostatnio! Podsumowując: bardzo rzadko jest to dobry pomysł.

+1

Zgadzam się z tą metodą. Prawdopodobnie uwzględniłbym lokalizację źródła. Można go znaleźć pod adresem http://hg.python.org/cpython/file/d37f963394aa/Lib/subprocess.py#l544 –

+1

Uwaga: CalledProcessError nie akceptuje danych wyjściowych w pythonie 2.6. (Jestem natychmiast ukąszony po użyciu tego hacka! :() –

3

Dzięki sugestii małpa plastra (i moje próby powstrzymanie się - ale byliśmy zużywa wyjście CalledProcessError, tak potrzebną do małpiej patcha to)

założenia pracuje 2,6 łatkę tutaj: 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 
Powiązane problemy