J'aimerais enregistrer toute la sortie d'un script Python. J'ai essayé:
import sys
log = []
class writer(object):
def write(self, data):
log.append(data)
sys.stdout = writer()
sys.stderr = writer()
Maintenant, si je "imprime" quelque chose "", il est enregistré. Mais si je fais par exemple une erreur de syntaxe, dites "print 'quelque chose #", il ne sera pas enregistré - il ira à la place dans la console.
Comment capturer également les erreurs de l'interpréteur Python?
J'ai vu une solution possible ici:
http://www.velocityreviews.com/forums/showpost.php?p=1868822&postcount=3
mais le deuxième exemple se connecte à/dev/null - ce n'est pas ce que je veux. Je voudrais le connecter dans une liste comme mon exemple ci-dessus ou StringIO ou tel ...
Aussi, de préférence, je ne veux pas créer de sous-processus (et lire ses stdout et stderr dans un thread séparé).
Vous ne pouvez rien faire dans le code Python qui puisse capturer des erreurs lors de la compilation de ce même code. Comment pourrait-il? Si le compilateur ne peut pas terminer la compilation du code, il ne l'exécutera pas. Votre redirection n'a même pas encore pris effet.
C'est là qu'intervient votre sous-processus (non désiré). Vous pouvez écrire du code Python qui redirige la sortie standard, puis appeler l'interpréteur Python pour compiler un autre morceau de code.
J'ai un logiciel que j'ai écrit pour le travail et qui capture stderr dans un fichier comme suit:
import sys
sys.stderr = open('C:\\err.txt', 'w')
donc c'est certainement possible.
Je crois que votre problème est que vous créez deux instances de writer.
Peut-être quelque chose de plus semblable à:
import sys
class writer(object):
log = []
def write(self, data):
self.log.append(data)
logger = writer()
sys.stdout = logger
sys.stderr = logger
Je ne peux pas penser à un moyen facile. L'erreur standard du processus python réside à un niveau inférieur à celui d'un objet de fichier python (C vs. python).
Vous pouvez envelopper le script python dans un second script python et utiliser subprocess.Popen. Il est également possible de tirer un sort magique comme celui-ci dans un seul script:
import os
import subprocess
import sys
cat = subprocess.Popen("/bin/cat", stdin=subprocess.PIPE, stdout=subprocess.PIPE)
os.close(sys.stderr.fileno())
os.dup2(cat.stdin.fileno(), sys.stderr.fileno())
Et utilisez ensuite select.poll () pour vérifier régulièrement cat.stdout afin de trouver la sortie.
Oui, cela semble fonctionner.
Le problème que je prévois est que la plupart du temps, quelque chose imprimé sur stderr en python indique qu'il est sur le point de quitter. La manière la plus habituelle de gérer cela serait via des exceptions.
---------Modifier
Quelque part, j'ai raté la fonction os.pipe ().
import os, sys
r, w = os.pipe()
os.close(sys.stderr.fileno())
os.dup2(w, sys.stderr.fileno())
Puis lisez de r
En fait, si vous utilisez linux/mac os, vous pouvez simplement utiliser la redirection de fichier pour le faire. Par exemple, si vous exécutez "a.py" et enregistrez tous les messages qu'il générera dans le fichier "a.out", ce sera simplement
python a.py 2>&1 > a.out
La première partie redirige stderr vers stdout, et la seconde le redirige vers un fichier appelé a.out.
Pour une liste plus longue des opérateurs de redirection sous Linux/Unix, voir https://askubuntu.com/questions/420981/how-do-i-save-terminal-output-to-a-file
Python n'exécutera pas votre code en cas d'erreur. Mais vous pouvez importer votre script dans un autre script et capturer des exceptions. Exemple:
print 'something#
from importlib.machinery import SourceFileLoader
try:
SourceFileLoader("main", "<SCRIPT PATH>").load_module()
except Exception as e:
# Handle the exception here
import sys
import tkinter
# ********************************************
def mklistenconsswitch(*printf: callable) -> callable:
def wrapper(*fcs: callable) -> callable:
def newf(data):
[prf(data) for prf in fcs]
return newf
stdoutw, stderrw = sys.stdout.write, sys.stderr.write
funcs = [(wrapper(sys.stdout.write, *printf), wrapper(sys.stderr.write, *printf)), (stdoutw, stderrw)]
def switch():
sys.stdout.write, sys.stderr.write = dummy = funcs[0]
funcs[0] = funcs[1]
funcs[1] = dummy
return switch
# ********************************************
def datasupplier():
i = 5.5
while i > 0:
yield i
i -= .5
def testloop():
print(supplier.__next__())
svvitch()
root.after(500, testloop)
root = tkinter.Tk()
cons = tkinter.Text(root)
cons.pack(fill='both', expand=True)
supplier = datasupplier()
svvitch = mklistenconsswitch(lambda text: cons.insert('end', text))
testloop()
root.mainloop()
Depuis Python 3.5, vous pouvez utiliser contextlib.redirect_stderr
with open('help.txt', 'w') as f:
with redirect_stdout(f):
help(pow)
Pour ajouter à la réponse de Ned, il est difficile de capturer les erreurs à la volée lors de la compilation.
Vous pouvez écrire plusieurs instructions d'impression dans votre script et vous pouvez stdout dans un fichier, il cessera d'écrire dans le fichier lorsque l'erreur se produit. Pour déboguer le code, vous pouvez vérifier la dernière sortie enregistrée et vérifier votre script après ce moment.
Quelque chose comme ceci:
# Add to the beginning of the script execution(eg: if __== "__main__":).
from datetime import datetime
dt = datetime.now()
script_dir = os.path.dirname(os.path.abspath(__file__)) # gets the path of the script
stdout_file = script_dir+r'\logs\log'+('').join(str(dt.date()).split("-"))+r'.log'
sys.stdout = open(stdout_file, 'w')
Cela créera un fichier journal et transmettra les instructions d'impression dans le fichier.
Remarque: Attention aux caractères d'échappement dans votre chemin de fichier lors de la concaténation avec script_dir dans la deuxième ligne à partir de la dernière dans le code. Vous voudrez peut-être quelque chose de similaire à une chaîne brute. Vous pouvez vérifier ce fil pour cela.