Print over Current Line in Python Shell - python

I'm trying to make a percentage text that displays a progress amount but i'm trying to avoid the percentages printing out like this:
Progress: 10%
Progress: 11%
Progress: 12%
Progress: 13%
How can erase and write over the current line? Iv'e tried using the \r and \b characters but neither seems to work. Every single thing I found before has been for either for Python 2 or Unix so i'm not even sure which of those is the problem (if even one of them) because i'm not using either. Does anyone know how I can do this with Python 3 running Windows 7? This is the unworking code that I have currently, but I've tried plenty of other things.
print('Progress: {}%'.format(solutions//possibleSolutions),flush=True,end="\r")
EDIT:
This is not a problem if I'm executing the program from command prompt so I don't think it is a problem with windows. I tried updating Python from what i was using previously (3.4.1) to the latest v3.4.3 and the issue is the same.
Heres a screenshot of the problem:
This is the best I can do at taking a screenshot of the issue. It appears as if each time I move the cursor farther to the left (passed one of the Progress:'s) that the gray area between the text and the cursor gets larger
EDIT 2: The problem is that IDLE does not support ASCII control codes. Solution: Use a different IDE.

You can use print:
print('Progress: {}%'.format(solutions),flush=True,end="\r")

You can't use '\r' and '\b' in IDLE. If you want to use it, try adding these lines at the start of your program:
import sys
sys.stdout = sys.__stdout__
and running idle with this batch script:
#echo off
echo Running IDLE...
py -m idlelib
then, you see output in cmd window and there are '\r' and '\b'.

Use the character '\r' for the print function. Default is '\n'.
'\r' stands for carriage return, '\n' means new line.

You can create a new class called Printer like this:
class Printer():
def __init__(self, data):
sys.stdout.write("\r\x1b[K"+data.__str__())
sys.stdout.flush()
Then, let's say you want to print the progress of a for loop:
for i in range(0, 100):
p = i * 100
output = "%d%% of the for loop completed" % p
Printer(output)

Related

Python 3.6 on linux: Problem with flushing what i want to write to the stdout

I'm pretty new to python and linux and I'm running into a problem...
So I'm trying to run the following code
(It is supposed to inform the person in front of the terminal, that the program is still running and then delete that line after 1 second):
import sys
while True:
# do something
sys.stdout.write("Still going...")
time.sleep(1)
sys.stdout.write("\r")
sys.stdout.flush()
This works perfectly fine on windows on python 3.8, but when i run it on my linux vps with python 3.6.9 via the "python3" command it doesn't flush the "\r", so the "Still going..." line only gets deleted and immediately reprinted the next time it reaches sys.stdout.write("Still going...").
If anyone has an idea what's going on here - please tell me
Any help is appreciated!
Windows, Mac OS and UNIXes code new lines with differents chars.
Windows uses \r\n
Mac OS uses \r
UNIXes use \n
if you want your program to be cross-platform, you should use os.linesep instead of an OS-specific linebreak
answering the comment:
Indeed on Windows, \r just return at the start of the line while \n actually starts a new line (see this StackExchange anwser for a nice explanation).
I assume that, on windows, it allows you to simply write on the same line until the program exits.
Sadly it could work at least with some terminals on UNIXes but not necessarily on every terminals...
As a work around, you could probably use the \b character which deletes the last caracter of the line, like the [backspace] key.

How can I redirect terminal output that "refreshes" using '\r'?

I am attempting to write a (Bash) shell script that wraps around a third-party python script and captures all output (errors and stdout) into a log file, and also restarts the script with a new batch of data each time it completes successfully. I'm doing this on a standard Linux distribution, but hopefully this solution can be platform-independent.
So here's a simplified version of the shell script, omitting everything except the logging:
#!/bin/bash
/home/me/script.py &>> /home/me/logfile
The problem is the third-party python script's output is mostly on a single line, which is being refreshed periodically (~every 90 seconds) by use of a carriage return ("\r"). Here's an example of the type of output I mean:
#!/usr/bin/env python3
import time
tracker = 1
print("This line is captured in the logfile because it ends with a newline")
while tracker < 5:
print(" This output isn't captured in the log file. Tracker = " + str(tracker),end="\r")
tracker += 1
time.sleep(1)
print("This line does get captured. Script is done. ")
How can I write a simple shell script to capture the output each time it is refreshed, or at least to periodically capture the current output as it would appear on the screen if I were running the script in the terminal?
Obviously I could try to modify the python script to change its output behavior, but the actual script I'm using is very complex and I think beyond my abilities to do that easily.
The program should have disabled this behavior when output is not a tty.
The output is already captured completely, it's just that you see all the updates at once when you cat the file. Open it in a text editor and see for yourself.
To make the file easier to work with, you can just replace the carriage returns with line feeds:
/home/me/script.py | tr '\r' '\n'
If the process normally produces output right away, but not with this command, you can disable Python's output buffering.

How to do partial carriage return

I want to replace the cmd output of my Python script, without overwriting the first three characters of the line. Here is what I mean:
How I want it:
>>>ID1 downloading
>>>ID1 converting
>>>ID1 finished
With /r:
>>>ID0 downloading
>>>converting
>>>finished
This isn't fundamentally a Python question; it's a standard output question.
The standard output doesn't work that way. The simplest thing is to just rewrite "ID1".
Otherwise you will need to move to something more advanced: either console-specific formatting commands (like ANSI), or a library like curses.
Try this. But this may not work in IDLE.
from time import sleep
from sys import stdout
stdout.write("\r%s" % "ID1 downloading")
stdout.flush()
sleep(1)
stdout.write("\r%s" % "ID1 converting ")
stdout.flush()
sleep(1)
stdout.write("\r%s" % "ID1 done ")
stdout.write("\r \r\n") # clean up

Print \r correctly in console

When I write a script that updates a printed line, for example like this:
for i in range(101):
print(str(i) + "% \r", end="")
and run this script using the terminal (Ubuntu), I get the correct output, that updated the line:
100%
However, using Pydev in Eclipse, the Eclipse console does this:
0%
1%
2%
...
100%
Anyone know how to fix this? Thanks in advance!
This is because 'print' always generates a new line whenever you use \r or not, try sys.stdout instead:
import time, sys
for i in range(101):
sys.stdout.write(str(i) + "% \r")
sys.stdout.flush()
time.sleep(.3)
This seems to be the old CR LF problem. Depending on the OS and the console you are using, CR and LF as a line termination will be interpreted differently.
Some systems require a CRLF as an end of line.
Some systems only require LF but do the CR implicitly.
Some systems (like yours) do a LF before each CR implicitly, although this is the first time I see this.
Maybe there is a way to edit the newline settings for your PyDev console.
EDIT: Or you might use ANSI escape codes for moving the cursor around. Like CSInD for n characters to the left or CSInC for n characters to the right.

How to remove lines from stdout in python?

I have a program that grabs some data through ssh using paramiko:
ssh = paramiko.SSHClient()
ssh.connect(main.Server_IP, username=main.Username, password=main.Password)
ssh_stdin_host, ssh_stdout_host, ssh_stderr_host =ssh_session.exec_command(setting.GetHostData)
I would like to remove the first 4 lines from ssh_stdout_host. I've tried using StringIO to use readlines like this:
output = StringIO("".join(ssh_stdout_host))
data_all = output.readlines()
But I'm lost after this. What would be a good approach? Im using python 2.6.5. Thanks.
How to remove lines from stdout in python?
(this is a general answer for removing lines from the stdout Python console window, and has nothing to do with specific question involving paramiko, ssh etc)
see also: here and here
Instead of using the print command or print() function, use sys.stdout.write("...") combined with sys.stdout.flush(). To erase the written line, go 'back to the previous line' and overwrite all characters by spaces using sys.stdout.write('\r'+' '*n), where n is the number of characters in the line.
a nice example says it all:
import sys, time
print ('And now for something completely different ...')
time.sleep(0.5)
msg = 'I am going to erase this line from the console window.'
sys.stdout.write(msg); sys.stdout.flush()
time.sleep(1)
sys.stdout.write('\r' + ' '*len(msg))
sys.stdout.flush()
time.sleep(0.5)
print('\rdid I succeed?')
time.sleep(1)
edit
instead of sys.stdout.write(msg); sys.stdout.flush(), you could also use
print(msg, end='')
For Python versions below 3.0, put from __future__ import print_function at the top of your script/module for this to work.
Note that this solution works for the stdout Python console window, e.g. run the script by right-clicking and choosing 'open with -> python'. It does not work for SciTe, Idle, Eclipse or other editors with incorporated console windows. I am waiting myself for a solution for that here.
readlines provides all the data
allLines = [line for line in stdout.readlines()]
data_no_firstfour = "\n".join(allLines[4:])

Categories