Output to the same line overwriting previous output?

PythonRefreshProgress Bar

Python Problem Overview


I am writing an FTP downloader. Part of to the code is something like this:

ftp.retrbinary("RETR " + file_name, process)

I am calling function process to handle the callback:

def process(data):
    print os.path.getsize(file_name)/1024, 'KB / ', size, 'KB downloaded!'
    file.write(data)

and output is something like this:

1784  KB / KB 1829 downloaded!
1788  KB / KB 1829 downloaded!
etc...   

but I want it to print this line and next time reprint/refresh it so it will only show it once and I will see progress of that download.

How can it be done?

Python Solutions


Solution 1 - Python

Here's code for Python 3.x:

print(os.path.getsize(file_name)/1024+'KB / '+size+' KB downloaded!', end='\r')

The end= keyword is what does the work here -- by default, print() ends in a newline (\n) character, but this can be replaced with a different string. In this case, ending the line with a carriage return instead returns the cursor to the start of the current line. Thus, there's no need to import the sys module for this sort of simple usage. print() actually has a number of keyword arguments which can be used to greatly simplify code.

To use the same code on Python 2.6+, put the following line at the top of the file:

from __future__ import print_function

Solution 2 - Python

If all you want to do is change a single line, use \r. \r means carriage return. It's effect is solely to put the caret back at the start of the current line. It does not erase anything. Similarly, \b can be used to go one character backward. (some terminals may not support all those features)

import sys

def process(data):
    size_str = os.path.getsize(file_name)/1024, 'KB / ', size, 'KB downloaded!'
    sys.stdout.write('%s\r' % size_str)
    sys.stdout.flush()
    file.write(data)

Solution 3 - Python

Have a look at the curses module documentation and the curses module HOWTO.

Really basic example:

import time
import curses

stdscr = curses.initscr()

stdscr.addstr(0, 0, "Hello")
stdscr.refresh()

time.sleep(1)

stdscr.addstr(0, 0, "World! (with curses)")
stdscr.refresh()

Solution 4 - Python

Here's my little class that can reprint blocks of text. It properly clears the previous text so you can overwrite your old text with shorter new text without creating a mess.

import re, sys

class Reprinter:
	def __init__(self):
		self.text = ''

	def moveup(self, lines):
		for _ in range(lines):
			sys.stdout.write("\x1b[A")
			
	def reprint(self, text):
		# Clear previous text by overwritig non-spaces with spaces
		self.moveup(self.text.count("\n"))
		sys.stdout.write(re.sub(r"[^\s]", " ", self.text))

		# Print new text
		lines = min(self.text.count("\n"), text.count("\n"))
		self.moveup(lines)
		sys.stdout.write(text)
		self.text = text

reprinter = Reprinter()

reprinter.reprint("Foobar\nBazbar")
reprinter.reprint("Foo\nbar")

Solution 5 - Python

I found that for a simple print statement in python 2.7, just put a comma at the end after your '\r'.

print os.path.getsize(file_name)/1024, 'KB / ', size, 'KB downloaded!\r',

This is shorter than other non-python 3 solutions, but also more difficult to maintain.

Solution 6 - Python

I am using spyder 3.3.1 - windows 7 - python 3.6 although flush may not be needed. based on this posting - https://github.com/spyder-ide/spyder/issues/3437

   #works in spyder ipython console - \r at start of string , end=""
import time
import sys
    for i in range(20):
        time.sleep(0.5)
        print(f"\rnumber{i}",end="")
        sys.stdout.flush()

Solution 7 - Python

to overwiting the previous line in python all wath you need is to add end='\r' to the print function, test this example:

import time
for j in range(1,5):
   print('waiting : '+j, end='\r')
   time.sleep(1)

Solution 8 - Python

You can just add '\r' at the end of the string plus a comma at the end of print function. For example:

print(os.path.getsize(file_name)/1024+'KB / '+size+' KB downloaded!\r'),

Solution 9 - Python

Python 3.9

   for j in range(1,5):
   print('\rwaiting : '+str(j), end='')

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionKristianView Question on Stackoverflow
Solution 1 - PythonKudzuView Answer on Stackoverflow
Solution 2 - PythonSam DolanView Answer on Stackoverflow
Solution 3 - PythonAndrea SpadacciniView Answer on Stackoverflow
Solution 4 - PythonBouke VersteeghView Answer on Stackoverflow
Solution 5 - PythonMatt EllenView Answer on Stackoverflow
Solution 6 - PythonJoePythonKingView Answer on Stackoverflow
Solution 7 - PythonAmirouche ZeggaghView Answer on Stackoverflow
Solution 8 - PythonMoustafa SalehView Answer on Stackoverflow
Solution 9 - Pythonuser18647916View Answer on Stackoverflow