47 votes

Utilisation d'un sous-processus pour exécuter un script Python sous Windows

Existe-t-il un moyen simple d'exécuter un script Python sur Windows/Linux/OS X ?

Sur les deux derniers, subprocess.Popen("/the/script.py") fonctionne, mais sous Windows, j'obtiens l'erreur suivante :

Traceback (most recent call last):
  File "test_functional.py", line 91, in test_functional
    log = tvnamerifiy(tmp)
  File "test_functional.py", line 49, in tvnamerifiy
    stdout = PIPE
  File "C:\Python26\lib\subprocess.py", line 595, in __init__
    errread, errwrite)
  File "C:\Python26\lib\subprocess.py", line 804, in _execute_child
    startupinfo)
WindowsError: [Error 193] %1 is not a valid Win32 application

de monkut commentaire : Le cas d'utilisation n'est pas clair. Pourquoi utiliser un sous-processus pour exécuter un script en python ? Y a-t-il quelque chose qui vous empêche d'importer le script et d'appeler la fonction nécessaire ?

J'étais en train d'écrire un script rapide pour tester la fonctionnalité globale d'un outil en ligne de commande Python (pour le tester sur différentes plateformes). En gros, il fallait créer un tas de fichiers dans un dossier temporaire, exécuter le script sur celui-ci et vérifier que les fichiers étaient renommés correctement.

J'aurais pu importer le script et appeler la fonction, mais comme elle s'appuie sur sys.argv et utilise sys.exit() j'aurais eu besoin de faire quelque chose comme

import sys
import tvnamer
sys.argv.append("-b", "/the/folder")
try:
    tvnamer.main()
except BaseException, errormsg:
    print type(errormsg)

De plus, je voulais capturer le stdout et le stderr pour le débogage au cas où quelque chose ne fonctionnerait pas.

Bien sûr, un meilleur moyen serait d'écrire le script d'une manière plus testable à l'unité, mais le script est essentiellement "fait" et je fais un dernier lot de tests avant de faire une version "1.0" (après quoi je vais faire une réécriture/restructuration, qui sera beaucoup plus propre et plus testable)

Fondamentalement, il était beaucoup plus facile de simplement exécuter le script en tant que processus, après avoir trouvé le fichier sys.executable variable. Je l'aurais bien écrit comme un shell-script, mais cela n'aurait pas été multiplateforme. La version finale du script peut être trouvée aquí

2 votes

Le cas d'utilisation n'est pas clair. Pourquoi utiliser subprocess pour exécuter un script en python ? Y a-t-il quelque chose qui vous empêche d'importer le script et d'appeler la fonction nécessaire ?

0 votes

J'ai eu le même problème en exécutant des modules nodejs depuis python. subprocess.call([r' \nodejs\npm '], shell=True) a résolu le problème.

68voto

dbr Points 66401

Je viens de trouver sys.executable - le chemin complet vers l'exécutable Python actuel, qui peut être utilisé pour exécuter le script (au lieu de s'appuyer sur le shbang, qui ne fonctionne évidemment pas sous Windows).

import sys
import subprocess

theproc = subprocess.Popen([sys.executable, "myscript.py"])
theproc.communicate()

4 votes

Vous pourriez utiliser subprocess.check_call([sys.executable, "myscript.py"]) à la place.

1 votes

Ou mieux encore, en Python 3.5+, utilisez subprocess.run : subprocess.run([sys.executable, 'myscript.py'], check=True)

25voto

romkyns Points 17295

Que dites-vous de ça ?

import sys
import subprocess

theproc = subprocess.Popen("myscript.py", shell = True)
theproc.communicate()                   # ^^^^^^^^^^^^

Cela dit subprocess pour utiliser le shell du système d'exploitation pour ouvrir votre script, et fonctionne sur tout ce que vous pouvez simplement exécuter dans cmd.exe.

De plus, cela recherchera dans le PATH "myscript.py" - ce qui pourrait être souhaitable.

0 votes

Je pense que cela fonctionnera de la même manière, si je me souviens bien shell=True empêche simplement le sous-processus d'échapper à tout caractère spécial (donc "mycmd > fichier.txt" redirige le texte vers fichier.txt, plutôt que d'essayer d'exécuter un fichier appelé "mycmd > fichier.txt").

2 votes

Voici une situation dans laquelle les deux sont sensiblement différents. Supposons que "myscript.py" se trouve dans le PATH du système, et non dans le répertoire courant. Si vous utilisez "shell = True", le script sera trouvé sur le PATH, mais si vous utilisez "sys.executable", il ne le sera pas.

0 votes

Ahh je vois ce que vous voulez dire (bien que le script que j'essayais d'exécuter allait toujours être dans le répertoire courant).

7voto

hmc Points 21

Oui subprocess.Popen(cmd, ..., shell=True) fonctionne comme un charme. Sous Windows, le .py L'extension de fichier est reconnue, et Python est invoqué pour le traiter (sous *NIX, juste le shebang habituel). L'environnement path contrôle si les choses sont vues. Ainsi, le premier argument de Popen es juste le nom du script .

subprocess.Popen(['myscript.py', 'arg1', ...], ..., shell=True)

0 votes

shell=True # do not show the command prompt then true, if false show it

5voto

viksit Points 1837

Il semble que Windows essaie d'exécuter le script en utilisant son propre cadre EXE plutôt que de l'appeler comme suit

python /the/script.py

Essayez,

subprocess.Popen(["python", "/the/script.py"])

Edit : "python" doit être sur votre chemin.

0 votes

L'installateur Windows de python.org ne semble pas mettre la commande "python" dans PATH, et je pense qu'elle aurait le suffixe .exe (ce qui casserait les autres plateformes).

0 votes

Hm, il semble que vous pouvez exclure le .exe sous Windows tant qu'il est dans PATH, mais vous devez ajouter manuellement Python à celui-ci

1 votes

Utilisez donc "cmd /S /C" au lieu de "python" - il est toujours sur le chemin et exécutera le script tant que l'extension est enregistrée.

2voto

Amit Points 5760

Vous utilisez un séparateur de nom de chemin qui dépend de la plate-forme. Windows utilise "\" et Unix utilise "/".

0 votes

Bon point, bien que dans le script qui a causé l'erreur, j'ai utilisé os.path.join() (bien que j'aurais dû le mentionner).

5 votes

Bien sûr, la barre oblique est valable sous Windows depuis la préhistoire et l'est toujours, donc ce n'est pas un problème.

1 votes

@romkyns pas vraiment : subprocess.call([r' \nodejs\npm '], shell=True) fonctionne, alors que subprocess.call(['../nodejs/npm'], shell=True) donne '..' n'est pas reconnu comme une commande interne ou externe.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X