2016-09-19 2 views
4

Je suis en utilisant des bibliothèques d'impression (malheureusement et beaucoup à mon grand regret) à stdout pour certaines informations de débogage. Ok, pas de problème, je viens désactivé avec:stdout Killing dans les pauses python get_line_buffer()

import sys,os 
sys.stdout = open(os.devnull,'wb') 

J'ai récemment ajouté un code pour obtenir l'entrée d'utilisateur et la sortie d'impression dans le terminal, ce qui bien sûr a besoin stdout. Mais encore une fois, pas de problème, au lieu de print je peux faire:

sys.__stdout__.write('text\n') 

Enfin, depuis que je fais raw_input dans un thread séparé et la sortie peut interrompre la saisie de l'utilisateur du programme, je voulais re-écho du tester comme décrit in the first part of this answer pour le rendre plus ou moins homogène en utilisant readline.get_line_buffer(). Par exemple, si l'utilisateur est entré foobar:

> foobar 

Et puis un autre thread dit Interrupting text! il devrait ressembler à:

Interrupting text! 
> foobar 

Mais au lieu j'observe:

Interrupting text! 
> 

Il se trouve que readline.get_line_buffer() est toujours vide et le code ne parvient pas à réécouter ce que l'utilisateur a tapé. Si je supprime le remplacement sys.stdout, tout fonctionne comme prévu (sauf maintenant la sortie de débogage des bibliothèques n'est pas bloquée).

J'utilise Python 2.7 sur Linux si cela importe. Peut-être que ce que je veux faire est impossible, mais j'aimerais vraiment savoir pourquoi cela se passe. Dans mon esprit, faire des choses avec stdout ne devrait pas affecter le tampon de ligne stdin, mais je ne suis pas familier avec les bibliothèques ou l'implémentation sous-jacentes.

Un exemple de travail minimum est ci-dessous. Tapez simplement quelque chose et attendez le texte d'interruption. L'invite "> " sera ré-écho, mais le texte que vous avez entré ne sera pas. Il suffit de commenter la deuxième ligne pour la voir fonctionner correctement. Lorsque le thread imprime, il enregistre le tampon de ligne à stdin.log.

import time,readline,thread,sys,os 
sys.stdout = open(os.devnull,'wb') # comment this line! 

def noisy_thread(): 
    while True: 
    time.sleep(5) 
    line = readline.get_line_buffer() 
    with open('stdin.log','a') as f: 
     f.write(time.asctime()+' | "'+line+'"\n') 
    sys.__stdout__.write('\r'+' '*(len(line)+2)+'\r') 
    sys.__stdout__.write('Interrupting text!\n') 
    sys.__stdout__.write('> ' + line) 
    sys.__stdout__.flush() 

thread.start_new_thread(noisy_thread,()) 
while True: 
    sys.__stdout__.write('> ') 
    s = raw_input() 

J'ai aussi essayé droit sys.stdout = sys.__stdout__ avant l'appel get_line_buffer(), mais cela ne fonctionne pas non plus. Toute aide ou explication est grandement appréciée.

+0

J'enverraient une demande de tirage à ces bibliothèques à utiliser 'logging' au lieu, parce que l'impression sur * ou * stdout stderr à partir du code bibliothèque est ridicule. Ou au moins déposer un rapport de bug. Et peut-être name and shame: P –

+0

Je viens aussi d'écrire une classe wrapper rapide et il semble que tout ce qui remplace 'stdout' rompt le comportement de readline. –

+0

Merci, je l'ai fait, mais en attendant je voudrais toujours savoir _why_ ce qui se passe :) – TheSchwa

Répondre

1

Son l'raw_input() qui cesse de fonctionner lorsque vous redirigez stdout. Si vous essayez sys.stdout = sys.__stdout__ juste avant le raw_input() cela fonctionne à nouveau. Les deux stdin et stdout doivent être connectés à la borne afin raw_input de travailler.

+0

Maintenant que vous l'avez dit, cela a tellement de sens; Je ne pouvais pas me débrouiller tout seul. Merci! – TheSchwa