Comment reproduire tee comportement en Python lors de l'utilisation de sous-processus?

Je suis à la recherche d'un Python solution qui me permettra d'enregistrer la sortie d'une commande dans un fichier sans le cacher à partir de la console.

FYI: je veux parler d' tee (comme Unix utilitaire de ligne de commande) et non pas la fonction avec le même nom de Python intertools module.

Détails

  • Python solution (pas d'appel tee, il n'est pas disponible sous Windows)
  • Je n'ai pas besoin de fournir d'informations sur stdin pour les appelés du processus de
  • Je n'ai pas de contrôle sur le programme. Tout ce que je sais, c'est qu'il va afficher quelque chose sur la sortie standard stdout et stderr et de retour avec un code de sortie.
  • De travail lors de l'appel de programmes externes (sous-processus)
  • De travail pour les deux stderr et stdout
  • Être capable de différencier entre stdout et stderr parce que je peut demander l'affichage d'un seul de la à la console ou je pourrais essayer de la sortie stderr à l'aide d'une couleur différente, ce qui signifie que stderr = subprocess.STDOUT ne fonctionnera pas.
  • Vivre de sortie (progressif) - le processus peut s'exécuter pendant une longue période, et je ne suis pas en mesure d'attendre qu'elle se termine.
  • Python 3 du code compatible (important)

Références

Voici quelques incomplète des solutions que j'ai trouvé jusqu'à présent:

Diagramme http://blog.i18n.ro/wp-content/uploads/2010/06/Drawing_tee_py.png

Code actuel (deuxième essai)

#!/usr/bin/python
from __future__ import print_function

import sys, os, time, subprocess, io, threading
cmd = "python -E test_output.py"

from threading import Thread
class StreamThread ( Thread ):
    def __init__(self, buffer):
        Thread.__init__(self)
        self.buffer = buffer
    def run ( self ):
        while 1:
            line = self.buffer.readline()
            print(line,end="")
            sys.stdout.flush()
            if line == '':
                break

proc = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
stdoutThread = StreamThread(io.TextIOWrapper(proc.stdout))
stderrThread = StreamThread(io.TextIOWrapper(proc.stderr))
stdoutThread.start()
stderrThread.start()
proc.communicate()
stdoutThread.join()
stderrThread.join()

print("--done--")

#### test_output.py ####

#!/usr/bin/python
from __future__ import print_function
import sys, os, time

for i in range(0, 10):
    if i%2:
        print("stderr %s" % i, file=sys.stderr)
    else:
        print("stdout %s" % i, file=sys.stdout)
    time.sleep(0.1)

La production réelle

stderr 1
stdout 0
stderr 3
stdout 2
stderr 5
stdout 4
stderr 7
stdout 6
stderr 9
stdout 8
--done--

Résultat attendu est que les lignes commandées. Remarque, la modification de la Popen à l'utilisation d'un seul TUYAU n'est pas autorisé parce que dans la vraie vie je veux faire des choses différentes avec stderr et stdout.

Également la même dans le second cas, je n'ai pas été en mesure d'obtenir en temps réel comme, en fait, tous les résultats ont été reçus lorsque le processus est terminé. Par défaut, Popen devrait utilisez pas de tampons (bufsize=0).