One place for hosting & domains

      subprocess

      Cómo usar subprocess para ejecutar programas externos en Python


      El autor seleccionó el COVID-19 Relief Fund para que reciba una donación como parte del programa Write for DOnations.

      Introducción

      Python 3 incluye el módulo subprocess para ejecutar programas externos y leer sus resultados en su código Python.

      Encontrará subprocess útil si desea usar otro programa en su computadora desde su código Python. Por ejemplo, es posible que desee invocar git desde su código Python para recuperar archivos en su proyecto que tienen un seguimiento por parte del control de versiones de git. Ya que cualquier programa al que acceda en su computadora puede estar controlado por subprocess, los ejemplos mostrados aquí serán aplicables a cualquier programa externo que desee invocar desde su código Python.

      subprocess incluye varias clases y funciones, pero en este tutorial cubriremos una de las funciones más útiles de subprocess: subprocess.run. Revisaremos sus diferentes usos y principales argumentos de palabras clave.

      Requisitos previos

      Para sacar el máximo provecho de este tutorial, se recomienda tener cierta familiaridad con la programación en Python 3. Puede consultar estos tutoriales para obtener la información de fondo necesaria:

      Ejecutar un programa externo

      Puede usar la función subprocess.run para ejecutar un programa externo desde su código Python. Primero, sin embargo, necesitará importar los módulos subprocess y sys a su programa:

      import subprocess
      import sys
      
      result = subprocess.run([sys.executable, "-c", "print('ocean')"])
      

      Si ejecuta esto, recibirá un resultado similar al siguiente:

      Output

      ocean

      Vamos a revisar este ejemplo:

      • sys.executable es la ruta absoluta al ejecutable de Python con el que se invocó su programa en un principio. Por ejemplo, sys.executable podría ser una ruta como /usr/local/bin/python.
      • subprocess.run obtiene una lista de cadenas que consisten en los componentes del comando que estamos intentando ejecutar. Ya que la primera cadena que pasamos es sys.executable, indicamos a subprocess.run que ejecute un nuevo programa Python.
      • El componente -c es una opción de línea de comandos python que le permite pasar una cadena con un programa completo Python para ejecutar. En nuestro caso, pasamos un programa que imprime la cadena ocean.

      Puede pensar en cada entrada de la lista que pasamos a subprocess.run como si estuviese separada por un espacio. Por ejemplo, [sys.executable, "-c", "print('ocean')"] se traduce aproximadamente como /usr/local/bin/python -c "print('ocean')". Observe que subprocess automáticamente pone entre comillas los componentes del comando antes de intentar ejecutarlos sobre el sistema operativo subyacente de forma que, por ejemplo, puede pasar un nombre de archivo que tenga espacios.

      Advertencia: Nunca pase una entrada no confiable a subprocess.run. Ya que subprocess.run tiene la capacidad de realizar comandos arbitrarios en su computadora, los agentes maliciosos pueden usarlo para manipular su computadora de formas inesperadas.

      Capturar resultados desde un programa externo

      Ahora que podemos invocar un programa externo usando subprocess.run, vamos a ver cómo podemos capturar el resultado desde ese programa. Por ejemplo, este proceso podría ser útil si quisiéramos usar git ls-files para crear todos sus archivos guardados actualmente bajo control de versiones.

      Nota: Los ejemplos que se muestran en esta sección requieren Python 3.7 o posterior. En particular, los argumentos de palabra clave capture_output y text fueron añadidos en Python 3.7 cuando se lanzó en junio del 2018.

      Vamos a añadir nuestro ejemplo anterior:

      import subprocess
      import sys
      
      result = subprocess.run(
          [sys.executable, "-c", "print('ocean')"], capture_output=True, text=True
      )
      print("stdout:", result.stdout)
      print("stderr:", result.stderr)
      

      Si ejecutamos este código, obtendremos un resultado como el siguiente:

      Output

      stdout: ocean stderr:

      Este ejemplo es, en gran medida, el mismo que presentamos en la primera sección: aún estamos ejecutando un subproceso para imprimir ocean. Es sobre todo importante que pasemos los argumentos de palabra clave capture_output=True y text=True a subproecss.run.

      subprocess-run devuelve un objeto subprocess.CompletedProcess que está vinculado a result. El objeto subprocess.CompletedProcess incluye detalles sobre el código de salida del programa externo y su resultado. capture_output=True garantiza que result-stdout y result-stderr se completan con el resultado correspondiente del programa externo. De forma predeterminada, result.stdout y result.stderr están vinculados como bytes, pero el argumento de palabra clave text=True indica a Python que decodifique los bytes en cadenas.

      En la sección de resultado, stdout es ocean (además de la nueva línea final que print añade de forma implícita) y no tenemos stderr.

      Vamos a probar un ejemplo que produce un valor no vacío para stderr:

      import subprocess
      import sys
      
      result = subprocess.run(
          [sys.executable, "-c", "raise ValueError('oops')"], capture_output=True, text=True
      )
      print("stdout:", result.stdout)
      print("stderr:", result.stderr)
      

      Si ejecutamos este código, obtendremos un resultado similar al siguiente:

      Output

      stdout: stderr: Traceback (most recent call last): File "<string>", line 1, in <module> ValueError: oops

      Este código ejecuta un subproceso de Python que crea de inmediato un ValueError. Cuando inspeccionamos el resultado final, no vemos nada en stdout y un Traceback de nuestro ValueError en stderr. Esto es porque, por defecto, Python escribe el Traceback de la excepción sin administrar a stderr.

      Generar una excepción en un código de salida erróneo

      A veces, es útil generar una excepción si un programa que ejecutamos sale con un código de salida erróneo. Los programas que salen con un código cero se consideran correctos, pero se considera que los programas que salen con un código no cero encontraron un error. Como ejemplo, este patrón podría ser útil si quisiéramos generar una excepción en el caso de que ejecutemos git ls-files es un directorio que realmente no era un repositorio git.

      Podemos usar el argumento de palabra clave check=True para que subprocess.run genere una excepción si el programa externo devuelve un código de salida no cero:

      import subprocess
      import sys
      
      result = subprocess.run([sys.executable, "-c", "raise ValueError('oops')"], check=True)
      

      Si ejecutamos este código, obtendremos un resultado similar al siguiente:

      Output

      Traceback (most recent call last): File "<string>", line 1, in <module> ValueError: oops Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/usr/local/lib/python3.8/subprocess.py", line 512, in run raise CalledProcessError(retcode, process.args, subprocess.CalledProcessError: Command '['/usr/local/bin/python', '-c', "raise ValueError('oops')"]' returned non-zero exit status 1.

      Este resultado muestra que ejecutamos un subproceso que generó un error, que se imprime en stderr en nuestro terminal. A continuación, subprocess.run planteó generó un subprocess.CalledProcessError en nuestro nombre en nuestro programa Python principal.

      Alternativamente, el módulo subprocess también incluye el método subprocess.CompletedProcess.check_returncode, que podemos invocar a efectos similares:

      import subprocess
      import sys
      
      result = subprocess.run([sys.executable, "-c", "raise ValueError('oops')"])
      result.check_returncode()
      

      Si ejecutamos este código, recibiremos:

      Output

      Traceback (most recent call last): File "<string>", line 1, in <module> ValueError: oops Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/usr/local/lib/python3.8/subprocess.py", line 444, in check_returncode raise CalledProcessError(self.returncode, self.args, self.stdout, subprocess.CalledProcessError: Command '['/usr/local/bin/python', '-c', "raise ValueError('oops')"]' returned non-zero exit status 1.

      Ya que no pasamos check=True a subprocess.run, vinculamos correctamente una instancia subprocess.CompletedProcess a result, a pesar de que nuestro programa salió con un código no cero. Al invocar result.check_returncode(), sin embargo, se genera un subprocess.CalledProcessError porque detecta que el proceso completado salió con un código erróneo.

      Usar timeout para salir de los programas de forma anticipada

      subprocess.run incluye el argumento timeout para permitirle detener un programa externo si tarda demasiado en ejecutarse:

      import subprocess
      import sys
      
      result = subprocess.run([sys.executable, "-c", "import time; time.sleep(2)"], timeout=1)
      

      Si ejecutamos este código, obtendremos un resultado como el siguiente:

      Output

      Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/usr/local/lib/python3.8/subprocess.py", line 491, in run stdout, stderr = process.communicate(input, timeout=timeout) File "/usr/local/lib/python3.8/subprocess.py", line 1024, in communicate stdout, stderr = self._communicate(input, endtime, timeout) File "/usr/local/lib/python3.8/subprocess.py", line 1892, in _communicate self.wait(timeout=self._remaining_time(endtime)) File "/usr/local/lib/python3.8/subprocess.py", line 1079, in wait return self._wait(timeout=timeout) File "/usr/local/lib/python3.8/subprocess.py", line 1796, in _wait raise TimeoutExpired(self.args, timeout) subprocess.TimeoutExpired: Command '['/usr/local/bin/python', '-c', 'import time; time.sleep(2)']' timed out after 0.9997982999999522 seconds

      El subproceso que intentamos ejecutar usó la función time.sleep para hibernar durante 2 segundos. Sin embargo, pasamos el argumento de palabra clave timeout=1 a subprocess.run para desconectar nuestro subproceso tras 1 segundo. Esto explica por qué nuestra invocación a subprocess.run finalmente generó una excepción subprocess.TimeoutExpired.

      Tenga en cuenta que el argumento de palabra clave timeout para subprocess.run es aproximado. Python hará todo lo posible para anular el subproceso tras el número de segundos de timeout, pero no será necesariamente exacto.

      Pasar input a programas

      A veces, los programas esperan que se pase una entrada a través de stdin.

      El argumento de palabra clave input a subprocess.run le permite pasar datos al stdin del subproceso. Por ejemplo:

      import subprocess
      import sys
      
      result = subprocess.run(
          [sys.executable, "-c", "import sys; print(sys.stdin.read())"], input=b"underwater"
      )
      

      Obtendremos un resultado similar al siguiente tras ejecutar este código:

      Output

      underwater

      En este caso, pasamos los bytes underwater a input. Nuestro subproceso objetivo utilizó sys.stdin para leer lo pasado en stdin (underwater) e imprimió nuestro resultado.

      El argumento de palabra clave input puede ser útil si desea encadenar múltiples invocaciones subprocess.run juntas pasando el resultado de un programa como la entrada de otro.

      Conclusión

      El módulo subprocess es una parte potente de la biblioteca estándar de Python que le permite ejecutar programas externos e inspeccionar sus resultados fácilmente. En este tutorial, aprendió a usar subprocess.run para controlar programas externos, pasar entrada a ellos, analizar sus resultados y comprobar sus códigos de retorno.

      El módulo subprocess expone clases y utilidades adicionales que no abarcamos en este tutorial. Ahora que tiene una base, puede usar la documentación del módulo subprocess para obtener más información sobre otras clases y utilidades disponibles.



      Source link

      Comment utiliser le module subprocess pour exécuter des programmes externes en Python 3


      L’auteur a choisi le COVID-19 Relief Fund pour recevoir un don dans le cadre du programme Write for DOnations.

      Introduction

      Python 3 comprend le module subprocess permettant d’exécuter des programmes externes et de lire leurs sorties dans votre code Python.

      Il se peut que vous trouviez subprocess utile si vous voulez utiliser un autre programme sur votre ordinateur à partir de votre code Python. Par exemple, vous pouvez invoquer git depuis votre code Python pour récupérer les fichiers de votre projet qui sont suivis dans le contrôle de version de git. Comme tout programme auquel vous pouvez accéder sur votre ordinateur par subprocess, les exemples présentés ici s’appliquent à tout programme externe que vous pourriez vouloir invoquer à partir de votre code Python.

      subprocess comprend plusieurs classes et fonctions, mais dans ce tutoriel, nous couvrirons l’une des fonctions les plus utiles de subprocess : subprocess.run. Nous passerons en revue ses différentes utilisations et les principaux arguments des mots-clés.

      Conditions préalables

      Pour tirer le meilleur parti de ce tutoriel, il est recommandé d’être familiarisé avec la  programmation en Python 3. Vous pouvez consulter ces tutoriels pour obtenir les informations de base nécessaires :

      Exécution d’un programme externe

      Vous pouvez utiliser la fonction subprocess.run pour exécuter un programme externe à partir de votre code Python. Mais d’abord, vous devez importer les modules subprocess et sys dans votre programme :

      import subprocess
      import sys
      
      result = subprocess.run([sys.executable, "-c", "print('ocean')"])
      

      Si vous l’exécutez, vous obtiendrez une sortie comme ci-dessous :

      Output

      ocean

      Passons en revue cet exemple :

      • sys.executable est le chemin absolu vers l’exécutable Python avec lequel votre programme a été invoqué à l’origine. Par exemple, sys.executable pourrait être un chemin tel que /usr/local/bin/python.
      • subprocess.run reçoit une liste de chaînes de caractères comprenant les composants de la commande que nous essayons d’exécuter. Comme la première chaîne que nous passons est sys.executable, nous ordonnons à subprocess.run d’exécuter un nouveau programme Python.
      • Le composant -c est une option de ligne de commande python qui vous permet de passer une chaîne avec un programme Python entier à exécuter. Dans notre cas, nous passons un programme qui imprime la chaîne ocean.

      Vous pouvez penser que chaque entrée de la liste que nous passons à subprocess.run est séparée par un espace. Par exemple, [sys.executable, "-c", "print('ocean')"] se traduit approximativement par /usr/local/bin/python -c "print('ocean')". Notez que subprocess cite automatiquement les composants de la commande avant d’essayer de les exécuter sur le système d’exploitation sous-jacent de sorte que, par exemple, vous pouvez passer un nom de fichier qui contient des espaces.

      Warning : ne jamais transmettre une entrée non fiable à subprocess.run. Comme subprocess.run a la capacité d’exécuter des commandes arbitraires sur votre ordinateur, des acteurs malveillants peuvent l’utiliser pour manipuler votre ordinateur de manière inattendue.

      Capturer output d’un programme externe

      Maintenant que nous pouvons invoquer un programme externe en utilisant subprocess.run, voyons comment nous pouvons récupérer la sortie de ce programme. Par exemple, ce processus pourrait être utile si nous voulions utiliser git ls-files pour produire tous vos fichiers actuellement stockés sous contrôle de version.

      Note : Les exemples présentés dans cette section nécessitent Python 3.7 ou version supérieure. En particulier, les arguments capture_output et le mot-clé text ont été ajoutés à Python 3.7 lors de sa sortie en juin 2018.

      Ajoutons à notre exemple précédent :

      import subprocess
      import sys
      
      result = subprocess.run(
          [sys.executable, "-c", "print('ocean')"], capture_output=True, text=True
      )
      print("stdout:", result.stdout)
      print("stderr:", result.stderr)
      

      Si nous exécutons ce code, nous obtiendrons le résultat suivant :

      Output

      stdout: ocean stderr:

      Cet exemple est en grande partie le même que celui présenté dans la première section : nous sommes toujours en train d’exécuter un sous-processus pour imprimer ocean. Il est toutefois important de noter que nous passons les arguments des mots-clés capture_output=True et text=True à subprocess.run.

      subprocess.run renvoie un objet subprocess.CompletedProcess qui est lié à result. L’objet subprocess.CompletedProcess comprend des détails sur le code de sortie du programme externe et sa sortie. capture_output=True garantit que result.stdout et result.stderr sont remplis avec la sortie correspondante du programme externe. Par défaut, result.stdout et result.stderr sont liés en tant qu’octets, mais l’argument du mot-clé text=True indique à Python de décoder plutôt les octets en chaînes de caractères.

      Dans la section de sortie, stdout est ocean (plus la nouvelle ligne de fin que print ajoute implicitement), et nous n’avons pas de stderr.

      Essayons un exemple qui produit une valeur non vide pour stderr :

      import subprocess
      import sys
      
      result = subprocess.run(
          [sys.executable, "-c", "raise ValueError('oops')"], capture_output=True, text=True
      )
      print("stdout:", result.stdout)
      print("stderr:", result.stderr)
      

      Si nous exécutons ce code, nous obtenons une sortie comme celle qui suit :

      Output

      stdout: stderr: Traceback (most recent call last): File "<string>", line 1, in <module> ValueError: oops

      Ce code exécute un sous-processus Python qui génère immédiatement une ValueError. Lorsque nous inspectons le result final, nous ne voyons rien dans stdout et un Traceback de notre ValueError dans stderr. C’est parce que par défaut Python écrit le Traceback de l’exception non gérée à stderr .

      Lever une exception sur un code de sortie incorrect

      Il est parfois utile de lever une exception si un programme que nous exécutons sort avec un code de sortie incorrect. Les programmes qui sortent avec un code nul sont considérés comme réussis, mais les programmes qui sortent avec un code non-nul sont considérés comme ayant rencontré une erreur. Par exemple, ce modèle pourrait être utile si nous voulions lever une exception dans le cas où nous exécutons des fichiers git ls-files dans un répertoire qui n’est pas réellement un référentiel git.

      Nous pouvons utiliser l’argument check=True du mot-clé subprocess.run pour qu’une exception soit levée si le programme externe renvoie un code de sortie non-nul :

      import subprocess
      import sys
      
      result = subprocess.run([sys.executable, "-c", "raise ValueError('oops')"], check=True)
      

      Si nous exécutons ce code, nous obtenons une sortie comme celle qui suit :

      Output

      Traceback (most recent call last): File "<string>", line 1, in <module> ValueError: oops Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/usr/local/lib/python3.8/subprocess.py", line 512, in run raise CalledProcessError(retcode, process.args, subprocess.CalledProcessError: Command '['/usr/local/bin/python', '-c', "raise ValueError('oops')"]' returned non-zero exit status 1.

      Cette sortie montre que nous avons exécuté un sous-processus qui a généré une erreur imprimée en stderr dans notre terminal. Ensuite, subprocess.run a consciencieusement levé un subprocess.CalledProcessError en notre nom dans notre programme Python principal.

      Alternativement, le module de sous-processus comprend également la méthode subprocess.CompletedProcess.check_returncode que nous pouvons invoquer pour un effet similaire :

      import subprocess
      import sys
      
      result = subprocess.run([sys.executable, "-c", "raise ValueError('oops')"])
      result.check_returncode()
      

      Si nous exécutons ce code, nous recevrons :

      Output

      Traceback (most recent call last): File "<string>", line 1, in <module> ValueError: oops Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/usr/local/lib/python3.8/subprocess.py", line 444, in check_returncode raise CalledProcessError(self.returncode, self.args, self.stdout, subprocess.CalledProcessError: Command '['/usr/local/bin/python', '-c', "raise ValueError('oops')"]' returned non-zero exit status 1.

      Comme nous n’avons pas passé check=True à subprocess.run, nous avons lié avec succès une instance de subprocess.CompletedProcess à result, même si notre programme s’est terminé avec un code non nul. L’appel de result.check_returncode() fait cependant apparaître un sous-processus appelé CalledProcessError parce qu’il détecte le processus terminé sorti avec un code incorrect.

      Utilisation du délai d’attente pour quitter prématurément les programmes

      subprocess.run inclut l’argument timeout pour vous permettre d’arrêter un programme externe si son exécution est trop longue :

      import subprocess
      import sys
      
      result = subprocess.run([sys.executable, "-c", "import time; time.sleep(2)"], timeout=1)
      

      Si nous exécutons ce code, nous obtiendrons le résultat suivant :

      Output

      Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/usr/local/lib/python3.8/subprocess.py", line 491, in run stdout, stderr = process.communicate(input, timeout=timeout) File "/usr/local/lib/python3.8/subprocess.py", line 1024, in communicate stdout, stderr = self._communicate(input, endtime, timeout) File "/usr/local/lib/python3.8/subprocess.py", line 1892, in _communicate self.wait(timeout=self._remaining_time(endtime)) File "/usr/local/lib/python3.8/subprocess.py", line 1079, in wait return self._wait(timeout=timeout) File "/usr/local/lib/python3.8/subprocess.py", line 1796, in _wait raise TimeoutExpired(self.args, timeout) subprocess.TimeoutExpired: Command '['/usr/local/bin/python', '-c', 'import time; time.sleep(2)']' timed out after 0.9997982999999522 seconds

      Le sous-processus que nous avons essayé d’exécuter utilisait la fonction time.sleep pour se mettre en veille pendant 2 secondes. Cependant, nous avons passé l’argument du mot-clé timeout=1 à subprocess.run pour que notre sous-processus soit temporisé après 1 seconde. Cela explique pourquoi notre appel à subprocess.run a finalement soulevé une exception de subprocess.TimeoutExpired.

      Notez que l’argument du mot-clé timeout à subprocess.run est approximatif. Python fera tout son possible pour arrêter le sous-processus après le nombre de secondes stipulé dans timeout, mais ce ne sera pas nécessairement exact.

      Transmission d’Input aux programmes

      Parfois, les programmes s’attendent à ce que les données leur soient transmises via stdin.

      L’argument du mot-clé input à subprocess.run vous permet de passer des données au stdin du sous-processus. Par exemple :

      import subprocess
      import sys
      
      result = subprocess.run(
          [sys.executable, "-c", "import sys; print(sys.stdin.read())"], input=b"underwater"
      )
      

      Après l’exécution de ce code, nous recevrons une sortie comme celle qui suit :

      Output

      underwater

      Dans ce cas, nous avons passé les octets underwater à input. Notre sous-processus cible a utilisé sys.stdin pour lire le passage dans stdin ( underwater ) et l’a imprimé dans notre sortie.

      L’argument du mot-clé input peut être utile si vous voulez enchaîner plusieurs appels subprocess.run ensemble en passant la sortie d’un programme comme entrée à un autre.

      Conclusion

      Le module subprocess est une partie puissante de la bibliothèque standard Python, qui vous permet d’exécuter des programmes externes et d’inspecter leurs sorties facilement. Dans ce tutoriel, vous avez appris à utiliser subprocess.run pour contrôler des programmes externes, leur transmettre des entrées, analyser leurs sorties et vérifier leurs codes de retour.

      Le module subprocess propose des classes et des utilitaires supplémentaires que nous n’avons pas abordés dans ce tutoriel. Maintenant que vous disposez d’une base de référence, vous pouvez utiliser la documentation du module subprocess pour en savoir plus sur d’autres classes et utilitaires disponibles.



      Source link

      Como usar o subprocess para executar programas externos em Python 3


      O autor selecionou a COVID-19 Relief Fund​​​​​ para receber uma doação como parte do programa Write for DOnations.

      Introdução

      O Python 3 inclui o módulo subprocess para executar programas externos e ler suas saídas em seu código Python.

      Você pode achar o subprocess útil se quiser usar outro programa em seu computador dentro do seu código Python. Por exemplo, você pode querer invocar o git dentro do seu código Python para recuperar arquivos em seu projeto que são rastreados no controle de versão git. Como qualquer programa que você possa acessar em seu computador pode ser controlado pelo subprocess, os exemplos mostrados aqui serão aplicáveis a qualquer programa externo que você queira invocar a partir do seu código Python.

      O subprocess inclui várias classes e funções, mas neste tutorial, vamos cobrir uma das funções mais úteis do subprocess: subprocess.run. Vamos revisar seus diferentes usos e principais argumentos de palavra-chave.

      Pré-requisitos

      Para tirar o máximo proveito deste tutorial, recomenda-se ter alguma familiaridade com programação em Python 3. Você pode revisar esses tutoriais para as informações básicas necessárias:

      Executando um programa externo

      Você pode usar a função subprocess.run para executar um programa externo a partir do seu código Python. Primeiro, porém, você precisa importar os módulos subprocess e sys para seu programa:

      import subprocess
      import sys
      
      result = subprocess.run([sys.executable, "-c", "print('ocean')"])
      

      Se você executar isso, receberá uma saída como a seguinte:

      Output

      ocean

      Vamos revisar este exemplo:

      • sys.executable é o caminho absoluto para o executável Python com o qual seu programa foi originalmente invocado. Por exemplo, sys.executable pode ser um caminho como /usr/local/bin/python.
      • subprocess.run recebe uma lista de strings que consistem nos componentes do comando que estamos tentando executar. Como a primeira string que passamos é sys.executable, estamos instruindo subprocess.run a executar um novo programa Python.
      • O componente -c é uma opção de linha de comando python que lhe permite passar uma string com um programa Python inteiro para executar. Em nosso caso, passamos um programa que imprime a string ocean.

      Você pode pensar em cada entrada na lista que passamos para subprocess.run como sendo separadas por um espaço. Por exemplo, [sys.executable, "-c", "print('ocean')"] traduz aproximadamente para /usr/local/bin/python -c "print('ocean')". Observe que o subprocess automaticamente coloca aspas nos componentes do comando antes de tentar executá-los no sistema operacional subjacente para que, por exemplo, você possa passar um nome de arquivo que tenha espaços nele.

      Atenção: nunca passe entrada não confiável para subprocess.run. Como o subprocess.run tem a capacidade de executar comandos arbitrários em seu computador, indivíduos maliciosos podem usá-lo para manipular seu computador de maneiras inesperadas.

      Capturando a saída de um programa externo

      Agora que podemos invocar um programa externo usando subprocess.run, vamos ver como podemos capturar a saída desse programa. Por exemplo, este processo poderia ser útil se quiséssemos usar git ls-files para exibir todos os seus arquivos atualmente armazenados sob o controle de versão.

      Nota: os exemplos mostrados nesta seção exigem Python 3.7 ou superior. Em particular, os argumentos de palavra-chave capture_output e text foram adicionados ao Python 3.7 quando ele foi lançado em junho de 2018.

      Vamos adicionar ao nosso exemplo anterior:

      import subprocess
      import sys
      
      result = subprocess.run(
          [sys.executable, "-c", "print('ocean')"], capture_output=True, text=True
      )
      print("stdout:", result.stdout)
      print("stderr:", result.stderr)
      

      Se executarmos esse código, receberemos um resultado como o seguinte:

      Output

      stdout: ocean stderr:

      Este exemplo é em grande parte o mesmo que o introduzido na primeira seção: ainda estamos executando um subprocesso para imprimir ocean. É importante ressaltar, no entanto, que passamos os argumentos de palavra-chave capture_output=True e text=True para subprocess.run.

      subprocess.run retorna um objeto subprocess.CompletedProcess que está vinculado a result. O objeto subprocess.CompletedProcess inclui detalhes sobre o código de saída do programa externo e sua saída. capture_output=True garante que result.stdout e result.stderr estejam preenchidos com a saída correspondente do programa externo. Por padrão, result.stdout e result.stderr são vinculados como bytes, mas o argumento de palavra-chave text=True instrui o Python a, em vez disso, decodificar os bytes em strings.

      Na seção output stdout é ocean (mais uma nova linha final que print adiciona implicitamente), e não temos nenhum stderr.

      Vamos tentar um exemplo que produz um valor não vazio para stderr:

      import subprocess
      import sys
      
      result = subprocess.run(
          [sys.executable, "-c", "raise ValueError('oops')"], capture_output=True, text=True
      )
      print("stdout:", result.stdout)
      print("stderr:", result.stderr)
      

      Se executarmos esse código, receberemos uma saída como a seguinte:

      Output

      stdout: stderr: Traceback (most recent call last): File "<string>", line 1, in <module> ValueError: oops

      Este código executa um subprocesso Python que imediatamente gera um erro de ValueError. Quando inspecionamos o result final, não vemos nada em stdout e um Traceback de nosso ValueError em stderr. Isso ocorre porque, por padrão, o Python escreve o Traceback da exceção não tratada em stderr.

      Gerando uma exceção em um código de saída ruim

      Às vezes, é útil gerar uma exceção se um programa que executamos termine com um código de saída ruim. Os programas que terminam com um código zero são considerados bem sucedidos, mas programas que terminam com um código não zero são considerados como tendo encontrado um erro. Como um exemplo, esse padrão poderia ser útil se quiséssemos gerar uma exceção no caso em que executamos git ls-files em um diretório que não fosse realmente um repositório git.

      Podemos usar o argumento de palavra-chave check=True para subprocess.run para ter uma exceção gerada se o programa externo retornar um código de saída não zero:

      import subprocess
      import sys
      
      result = subprocess.run([sys.executable, "-c", "raise ValueError('oops')"], check=True)
      

      Se executarmos esse código, receberemos uma saída como a seguinte:

      Output

      Traceback (most recent call last): File "<string>", line 1, in <module> ValueError: oops Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/usr/local/lib/python3.8/subprocess.py", line 512, in run raise CalledProcessError(retcode, process.args, subprocess.CalledProcessError: Command '['/usr/local/bin/python', '-c', "raise ValueError('oops')"]' returned non-zero exit status 1.

      Esta saída mostra que executamos um subprocesso que gerou um erro, que é impresso em stderr em nosso terminal. Em seguida, subprocess.run criou devidamente um subprocess.CalledProcessError por nós em nosso programa Python principal.

      Alternativamente, o módulo subprocess também inclui o método subprocess.CompletedProcess.check_returncode, que podemos invocar para um efeito semelhante:

      import subprocess
      import sys
      
      result = subprocess.run([sys.executable, "-c", "raise ValueError('oops')"])
      result.check_returncode()
      

      Se executarmos este código, receberemos:

      Output

      Traceback (most recent call last): File "<string>", line 1, in <module> ValueError: oops Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/usr/local/lib/python3.8/subprocess.py", line 444, in check_returncode raise CalledProcessError(self.returncode, self.args, self.stdout, subprocess.CalledProcessError: Command '['/usr/local/bin/python', '-c', "raise ValueError('oops')"]' returned non-zero exit status 1.

      Como não passamos check=True para subprocess.run, vinculamos com sucesso uma instância de subprocess.CompletedProcess a result, mesmo que nosso programa seja encerrado com um código diferente de zero. Chamar result.check_returncode(), no entanto, gera um subprocess.CalledProcessError porque ele detecta que o processo finalizado foi encerrado com um código ruim.

      Usando o timeout para sair de programas mais cedo

      subprocess.run inclui o argumento timeout para permitir que você pare um programa externo se estiver levando muito tempo para executar:

      import subprocess
      import sys
      
      result = subprocess.run([sys.executable, "-c", "import time; time.sleep(2)"], timeout=1)
      

      Se executarmos esse código, receberemos um resultado como o seguinte:

      Output

      Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/usr/local/lib/python3.8/subprocess.py", line 491, in run stdout, stderr = process.communicate(input, timeout=timeout) File "/usr/local/lib/python3.8/subprocess.py", line 1024, in communicate stdout, stderr = self._communicate(input, endtime, timeout) File "/usr/local/lib/python3.8/subprocess.py", line 1892, in _communicate self.wait(timeout=self._remaining_time(endtime)) File "/usr/local/lib/python3.8/subprocess.py", line 1079, in wait return self._wait(timeout=timeout) File "/usr/local/lib/python3.8/subprocess.py", line 1796, in _wait raise TimeoutExpired(self.args, timeout) subprocess.TimeoutExpired: Command '['/usr/local/bin/python', '-c', 'import time; time.sleep(2)']' timed out after 0.9997982999999522 seconds

      O subprocesso que tentamos executar usou a função time.sleep para colocá-lo em repouso por 2 segundos. No entanto, passamos o argumento de palavra-chave timeout=1 para subprocess.run para expirar nosso subprocesso após 1 segundo. Isso explica por que nossa chamada para subprocess.run finalmente gerou uma exceção subprocess.TimeoutExpired.

      Observe que o argumento de palavra-chave timeout para subprocess.run é aproximado. Python fará um melhor esforço para matar o subprocesso após o número de segundos de timeout, mas ele não será necessariamente exato.

      Passando a entrada para programas

      Às vezes, os programas esperam que a entrada seja passada para eles via stdin.

      O argumento de palavra-chave input para subprocess.run permite que você passe dados para o stdin do subprocesso. Por exemplo:

      import subprocess
      import sys
      
      result = subprocess.run(
          [sys.executable, "-c", "import sys; print(sys.stdin.read())"], input=b"underwater"
      )
      

      Receberemos uma saída como a seguinte depois de executar este código:

      Output

      underwater

      Neste caso, passamos os bytes underwater para input. Nosso subprocesso alvo usou sys.stdin para ler o que foi passado em stdin (underwater) e o imprimiu em nossa saída.

      O argumento de palavra-chave input pode ser útil se você quiser encadear várias chamadas subprocess.run juntas passando a saída de um programa como a entrada para outro.

      Conclusão

      O módulo subprocess é uma parte poderosa da biblioteca padrão Python que permite que você execute programas externos e inspecione suas saídas com facilidade. Neste tutorial, você aprendeu a usar subprocess.run para controlar programas externos, passar a entrada para eles, analisar sua saída e verificar seus códigos de retorno.

      O módulo subprocess expõe classes e utilitários adicionais que não abordamos neste tutorial. Agora que você tem um conhecimento básico, você pode usar a documentação do módulo subprocess para aprender mais sobre outras classes e utilitários disponíveis.



      Source link