Print \r correctly in console - python

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.

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.

Why python2 shows \r (Raw escaped) and python3 does not?

I have been having a path error: No file or directory found for hours. After hours of debugging, I realised that python2 added an invisible '\r' at the end of each line.
The input: (trainval.txt)
Images/K0KKI1.jpg Labels/K0KKI1.xml
Images/2KVW51.jpg Labels/2KVW51.xml
Images/MMCPZY.jpg Labels/MMCPZY.xml
Images/LCW6RB.jpg Labels/LCW6RB.xml
The code I used to debug the error
with open('trainval.txt', "r") as lf:
for line in lf.readlines():
print ((line),repr(line))
img_file, anno = line.strip("\n").split(" ")
print(repr(img_file), repr(anno))
Python2 output:
("'Images/K0KKI1.jpg'", "'Labels/K0KKI1.xml\\r'")
('Images/2KVW51.jpg Labels/2KVW51.xml\r\n', "'Images/2KVW51.jpg Labels/2KVW51.xml\\r\\n'")
("'Images/2KVW51.jpg'", "'Labels/2KVW51.xml\\r'")
('Images/MMCPZY.jpg Labels/MMCPZY.xml\r\n', "'Images/MMCPZY.jpg Labels/MMCPZY.xml\\r\\n'")
("'Images/MMCPZY.jpg'", "'Labels/MMCPZY.xml\\r'")
('Images/LCW6RB.jpg Labels/LCW6RB.xml\r\n', "'Images/LCW6RB.jpg Labels/LCW6RB.xml\\r\\n'")
("'Images/LCW6RB.jpg'", "'Labels/LCW6RB.xml\\r'")
Python3 output:
Images/K0KKI1.jpg Labels/K0KKI1.xml
'Images/K0KKI1.jpg Labels/K0KKI1.xml\n'
'Images/K0KKI1.jpg' 'Labels/K0KKI1.xml'
Images/2KVW51.jpg Labels/2KVW51.xml
'Images/2KVW51.jpg Labels/2KVW51.xml\n'
'Images/2KVW51.jpg' 'Labels/2KVW51.xml'
Images/MMCPZY.jpg Labels/MMCPZY.xml
'Images/MMCPZY.jpg Labels/MMCPZY.xml\n'
'Images/MMCPZY.jpg' 'Labels/MMCPZY.xml'
Images/LCW6RB.jpg Labels/LCW6RB.xml
'Images/LCW6RB.jpg Labels/LCW6RB.xml\n'
'Images/LCW6RB.jpg' 'Labels/LCW6RB.xml'
As annoying as it was, it was that small '\r' who caused the path error. I could not see it in my console until I write the script above. My question is: Why is this '\r' even there? I did not create it. Something somewhere added it there. It would be helpful if someone could tell me what is the use of this small 'r' , why did it appear in python2 and not in python3 and how to avoid getting bugs due to it.
there's probably a subtle difference of processing between Windows text file in python 2 & 3 versions.
The issue here is that your file has a Windows text format, and contains one or several carriage return chars before the linefeed. A quick & generic fix would be to change:
img_file, anno = line.strip("\n").split(" ")
by just:
img_file, anno = line.split()
Without arguments str.split is very smart:
it splits according to any kind of whitespace (linefeed, space, carriage return, tab)
it removes empty fields (no need for strip after all)
So use that cross-platform/python version agnostic form unless you need really specific split operation, and your problems will be history.
As an aside, don't do for line in lf.readlines(): but just for line in lf:, it will read & yield the lines one by one, handy when the file is big so you don't consume too much memory.

Print over Current Line in Python Shell

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)

In Python, why won't something print without a newline? [duplicate]

This question already has an answer here:
Why doesn't print output show up immediately in the terminal when there is no newline at the end?
(1 answer)
Closed last month.
import time
import sys
sys.stdout.write("1")
time.sleep(5)
print("2")
will print "12" after 5 seconds
import time
import sys
sys.stdout.write("1\n")
time.sleep(5)
print("2")
will print "1\n" right away, then "2" after 5 seconds
Why is this?
If you add "\n" then stream is flushed automaticaly, and it is not without new line at the end.
You can flush output with: sys.stdout.flush()
Because stdout is buffered. You may be able to force the output sooner with a sys.stdout.flush() call.
The sys.stdout.write command from the sys module purposefully prints out the statement without the \n character. This is how a normal call to the stdout stream works, such as in C++ or C, where the \n character must be added manually.
However the print command provided by Python automatically adds a \n character to the string, therefore simplifying the code and making it easier to read.
The reason the phenomenon in the first result happens is because the system is waiting for a flush to print out, which is provided by the \n character. You can avoid this by using this command, sys.stdout.flush(), which will flush the stdout stream which forces it to print.
Buffering. It's not really Python, but rather your operating system/terminal. Output from any program is sent to a buffer, a holding area of memory. When a whole line is collected, it's sent to the screen. There is usually a hook, a method named something like flush(), to force output of partial lines.
It's because output in Python is buffered by default - ordinarily you won't get the output until the buffer is full or something causes the buffer to be flushed. In this case the \n was sensed and caused an automatic flush.
See this question for ways around the problem: How to flush output of Python print?
Consider that when you type a command into a computer, it doesn't know you're finished until you press ENTER
Similarly, the newline tells Python you've finished that line.

How do I modify program files in Python?

In the actual window where I right code is there a way to insert part of the code into everyline that I already have. Like insert a comma into all lines at the first spot>?
You need a file editor, not python.
Install the appropriate VIM variant for your operating system
Open the file you want to modify using VIM
Type: :%s/^/,/
Type: :wq
If you are in UNIX environment, open up a terminal, cd to the directory your file is in and use the sed command. I think this may work:
sed "s/\n/\n,/" your_filename.py > new_filename.py
What this says is to replace all \n (newline character) to \n, (newline character + comma character) in your_filename.py and to output the result into new_filename.py.
UPDATE: This is much better:
sed "s/^/,/" your_filename.py > new_filename.py
This is very similar to the previous example, however we use the regular expression token ^ which matches the beginning of each line (and $ is the symbol for end).
There are chances this doesn't work or that it doesn't even apply to you because you didn't really provide that much information in your question (and I would have just commented on it, but I can't because I don't have enough reputation or something). Good luck.
Are you talking about the interactive shell? (a.k.a. opening up a prompt and typing python)? You can't go back and edit what those previous commands did (as they have been executed), but you can hit the up arrow to flip through those commands to edit and reexecute them.
If you're doing anything very long, the best bet is to write your program into your text editor of choice, save that file, then launch it.
Adding a comma to the start of every line with Python:
import sys
src = open(sys.argv[1])
dest = open('withcommas-' + sys.argv[1],'w')
for line in src:
dest.write(',' + line)
src.close()
dest.close()
Call like so: C:\Scripts>python commaz.py cc.py. This is a bizzare thing to do, but who am I to argue.
Code is data. You could do this like you would with any other text file. Open the file, read the line, stick a comma on the front of it, then write it back to file.
Also, most modern IDEs/text editors have the ability to define macros. You could post a question asking for specific help for your editor. For example, in Emacs I would use C-x ( to start defining a macro, then ',' to write a comma, then C-b C-n to go back a character and down a line, then C-x ) to end my macro. I could then run this macro with C-x e, pressing e to execute it an additional time.

Categories