Printing text that updates, for example a clock, in python. Ive read some threads about this but they only worked if the program prints out one line. What i am trying to do is, i already have a sort of terminal in python that accepts commands and executes them, it runs in a while loop, now if i wanted to make a clock in the top right corner of the terminal, but preserve what the user is typing and the output of previous commands, how would i do that?
P.S.: Sorry for bad formatting, in typing this from my phone
You can easily update stdout with this:
print('foo', end='')
print('\rbar', end='', flush=True)
This example prints out foo and then changes the line to bar
Related
I'm using Windows' Power Shell. I'd like to run a Python script that will take a long time to be finished (it's a code for data acquisition, so it'll take about a few hours to conclude). So, I'd like to be able to see all the prints and results on the terminal, but I would like to save all the output (in the end) as a string, a file or whatever.
I've been trying using the redirection commands like python example_file.py > output.txt , python example_file.py | tee output.txt and similars, but the problem is that those commands run all the script in the background and just show the results when it's finished (and, again, I'd like to be able to see the progress of the acquisition).
I've looked online and found that there's a command called "script" in Linux that serves for the same purpose that I want, but I've not found any equivalent for Windows Power Shell. I'm also accepting any solution in Python, it doesn't need to be necessarily on PS.
Please, someone help me?
EDIT: I'd like to see in real time the output. I mean, the intention is to see all the results of the code normally, as it's normally executed on the PS terminal, AND THEN save all the output to a file, to a string or whatever.
Example: if I run
from time import sleep
print('banana')
sleep(3)
print('banana again')
it'll show, on the terminal, the first 'banana' and then, after three seconds, it'll show 'banana again'. The problem is that with the above codes it'll execute the script on the background and then show the results at once. And that's not what I want.
I would use the following code:
from time import sleep
outputs = []
def myprint(print):
global outputs
print(print)
outputs.append(print)
myprint('banana')
sleep(3)
myprint('banana again')
open("output.txt", "w").write("\n".join(outputs))
The code now writes into(and creates if not already there) a file named output.txt all the things printed with the myprint() function. If you want, you can also access them if as single strings in the outputs array. Also, don't wonder, but in python you can use both " and ' as the same thing.
So I'm using some libraries that (unfortunately and much to my chagrin) print to stdout for certain debug info. Okay, no problem, I just disabled it with:
import sys,os
sys.stdout = open(os.devnull,'wb')
I've recently added code for getting user input and printing output in the terminal, which of course needs stdout. But again, no problem, instead of print I can just do:
sys.__stdout__.write('text\n')
Finally, since I'm doing raw_input in a separate thread and the program's output can interrupt the user typing, I wanted to re-echo the test as described in the first part of this answer to make it more or less seamless using readline.get_line_buffer(). For example, if the user entered foobar:
> foobar
And then another thread says Interrupting text! it should look like:
Interrupting text!
> foobar
But instead I observe:
Interrupting text!
>
It turns out that readline.get_line_buffer() is always blank, and the code fails to re-echo what the user had typed. If I remove the sys.stdout override, everything works as expected (except now the debug output from libraries isn't blocked).
I'm using Python 2.7 on Linux if that matters. Perhaps what I want to do is impossible, but I'd really like to know why this is happening. In my mind, doing things with stdout shouldn't affect the stdin line buffer, but I'm admittedly not familiar with the underlying libraries or implementation.
A minimum working example is below. Just type something and wait for the interrupting text. The prompt "> " will be re-echoed, but the text you entered won't be. Simply comment out the second line to see it work correctly. When the thread prints, it logs the line buffer to 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()
I've also tried sys.stdout = sys.__stdout__ right before the get_line_buffer() call, but that doesn't work either. Any help or explanation is greatly appreciated.
Its the raw_input() that stops working when you redirect the stdout.
If you try sys.stdout = sys.__stdout__ just before the raw_input() it works again.
Both stdin and stdout need to be connected to the terminal in order for raw_input to work.
I was writing a simple program on Python 3.1 and I stumbled upon this:
If I run this on the IDLE it works as intended - prints "Initializing." and then adds two dots, one after each second, and waits for input.
from time import sleep
def initialize():
print('Initializing.', end='')
sleep(1)
print(" .", end='')
sleep(1)
print(" .", end='')
input()
initialize()
The problem is that when I double-click the .py to execute the file, it runs on python.exe instead of pythonw.exe, and strange things happen: it joins all the sleep() times i.e. makes me wait for 2 seconds, and then prints the whole string Initializing. . . at once. Why does this happen? Is there a way to avoid that happening in the terminal? It works fine if I use the IDLE in both windows and linux.
This is because the output is being buffered.
You should add a sys.stdout.flush() after each write
It sounds like the difference is that stdout is automatically being flushed in IDLE. For efficiency, programming languages often save up a bunch of print calls before writing to the screen, which is a slow process.
Here's another question that has the answer you need:
How to flush output of Python print?
I have a script that does random calculation and prints it, but now I need these results written in a text file. I edited it and now each time I execute this script, new results are appended in a text file. However, I need as many new results as I can get into the same text file, so is there a way to make it run again and again (and stop it when I want to by keyboard interrupt)?
I could do something like:
inf_loop=0
while inf_loop==0:
#code to append to text file
But the script is rather long, thus I need to have each line within the loop indented properly.
I cannot comment so I'm gonna say my opinion here.
tab is your friend here. If you're using Python IDLE, just select all the lines and hit Tab. If you wanna outdent, try shift + tab.
If indenting is a problem for you and you really want to hack this down, you could simply restart your script like this:
#!/usr/bin/env python
import os
# your script content
args=['some_name']
os.execlp('./your_script.py',*args)
Run the script from the directory it is located in. If you need to pass arguments, simply append them to args.
If your script finishes it will restart itself again and again...
If you're adamant that you don't want to change your existing script, create a new one, then keep calling the other...
while True:
execfile('/path/to/other/script.py')
Although you should really be putting the work of the other script into a function, then repeatedly calling that instead of the script...
while True:
call_your_function()
I was writing a simple program on Python 3.1 and I stumbled upon this:
If I run this on the IDLE it works as intended - prints "Initializing." and then adds two dots, one after each second, and waits for input.
from time import sleep
def initialize():
print('Initializing.', end='')
sleep(1)
print(" .", end='')
sleep(1)
print(" .", end='')
input()
initialize()
The problem is that when I double-click the .py to execute the file, it runs on python.exe instead of pythonw.exe, and strange things happen: it joins all the sleep() times i.e. makes me wait for 2 seconds, and then prints the whole string Initializing. . . at once. Why does this happen? Is there a way to avoid that happening in the terminal? It works fine if I use the IDLE in both windows and linux.
This is because the output is being buffered.
You should add a sys.stdout.flush() after each write
It sounds like the difference is that stdout is automatically being flushed in IDLE. For efficiency, programming languages often save up a bunch of print calls before writing to the screen, which is a slow process.
Here's another question that has the answer you need:
How to flush output of Python print?