web-dev-qa-db-fra.com

Comment écrire sur un stdin de sous-processus Python?

J'essaie d'écrire un script Python qui démarre un sous-processus et écrit dans le sous-processus stdin. J'aimerais également pouvoir déterminer une action à entreprendre si le sous-processus plante.

Le processus que j'essaie de démarrer est un programme appelé nuke qui a sa propre version intégrée de Python auquel j'aimerais pouvoir soumettre des commandes, et puis dites-lui de se fermer après l'exécution des commandes. Jusqu'à présent, je me suis rendu compte que si je démarre Python sur l'invite de commande comme, puis démarre nuke en tant que sous-processus, puis Je peux taper des commandes dans nuke, mais j'aimerais pouvoir tout mettre dans un script pour que le programme maître Python puisse démarrer nuke et ensuite écrire dans son entrée standard (et donc dans sa version intégrée de Python) et lui dire de faire des choses incroyables, alors j'ai écrit un script qui démarre nuke comme ça :

subprocess.call(["C:/Program Files/Nuke6.3v5/Nuke6.3", "-t", "E:/NukeTest/test.nk"])

Ensuite, rien ne se passe car nuke attend l'entrée utilisateur. Comment pourrais-je maintenant écrire sur une entrée standard?

Je fais cela parce que j'exécute un plugin avec nuke qui le fait planter par intermittence lors du rendu de plusieurs images. Je voudrais donc que ce script puisse démarrer nuke, lui dire de faire quelque chose et puis s'il se bloque, réessayer. Donc, s'il y a un moyen d'attraper un crash et d'être toujours OK, ce serait génial.

52
jonathan topf

Il serait peut-être préférable d'utiliser communicate :

from subprocess import Popen, PIPE, STDOUT
p = Popen(['myapp'], stdout=PIPE, stdin=PIPE, stderr=PIPE)
stdout_data = p.communicate(input='data_to_write')[0]

"Mieux", à cause de cet avertissement:

Utilisez Communiquer () plutôt que .stdin.write, .stdout.read ou .stderr.read pour éviter les blocages dus à l'un des autres tampons de tuyau du système d'exploitation remplissant et bloquant le processus enfant.

72
jro

Vous pouvez fournir un objet de type fichier à l'argument stdin de subprocess.call().

La documentation pour l'objet Popen s'applique ici.

Pour capturer la sortie, vous devez plutôt utiliser subprocess.check_output(), qui prend des arguments similaires. De la documentation:

>>> subprocess.check_output(
...     "ls non_existent_file; exit 0",
...     stderr=subprocess.STDOUT,
...     Shell=True)
'ls: non_existent_file: No such file or directory\n'
0
user626998

Voici à quoi ça ressemble - pour la version commerciale de NUKE 11.3v4 sur Windows 10:

import subprocess

# Run NUKE's script in Terminal mode on Windows machine...
subprocess.Popen(['C:/Program Files/Nuke11.3v4/Nuke11.3.exe', '-t', 'E:/NukeTest/test.nk'], stdin=PIPE, stdout=PIPE)

Voici comment cela fonctionne pour la version non commerciale de NUKE 11.3v4 sur macOS 10.14:

import subprocess
from subprocess import Popen, PIPE
import time

# Run NUKE's script in Terminal mode on MacOS machine...
np = subprocess.Popen(['/Applications/Nuke11.3v4/NukeX11.3v4 Non-commercial.app/NukeX11.3v4 Non-commercial', '-t', '/Users/<username>/Desktop/test.nknc'], stdin=PIPE, stdout=PIPE)

# Choose a method to wait for the subprocess to finish...
np.wait() 
time.sleep(5)        

data = np.communicate(input='data')[0]

print(data)

Le résultat est le suivant:

'''
NukeX 11.3v4, 64 bit, built May  1 2019.
Copyright (c) 2019 The Foundry Visionmongers Ltd.  All Rights Reserved.
Non-commercial mode active.
Licence expires on: 2019/7/27
(11, 3, 4)
('darwin', 'posix')
/Applications/Nuke11.3v4/Nuke11.3v4.app/Contents/MacOS/../Frameworks/Python.framework/Versions/Current/
Disk cache /var/tmp/nuke-u501/ViewerCache/??: 424MB (5% of 10240MB) used in 81 files.

'''

En outre, vous pouvez exécuter un sous-processus dans l'interface graphique en utilisant -v drapeau pour les images:

subprocess.Popen(['C:/Program Files/Nuke11.3v4/Nuke11.3.exe', '-v', 'E:/NukeTestImages/image.exr'], stdin=PIPE, stdout=PIPE)

J'espère que cela t'aides.

0
ARGeo