Output to the same line overwriting previous output?

Question:

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?

Asked By: Kristian

||

Answers:

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()
Answered By: Andrea Spadaccini

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('%sr' % size_str)
    sys.stdout.flush()
    file.write(data)
Answered By: Sam Dolan

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
Answered By: Kudzu

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("FoobarnBazbar")
reprinter.reprint("Foonbar")
Answered By: Bouke Versteegh

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.

Answered By: Matt Ellen

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'),
Answered By: Moustafa Saleh

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()
Answered By: JoePythonKing

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)
Answered By: Amirouche Zeggagh

Python 3.9

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

This is my asnwer. I have search for that too. I got many solution but this works for me.

 from time import sleep
 for _ in range(5):
     sleep(1)
     print(f'rWritting on same line with chaning number {_}.',end='')
 else:
     print()
  • Yes you can use else: statement with for block. That will add new line when for loop finish.
  • This will only work with loops. It will not affect other print() statements.
Answered By: Viru

Thanks to Bouke Versteegh for their answer which gives a great starting point. However I found issues with it where sys.stdout wasn’t flushed as it should be, and reprinted text moved down the screen repeatedly.

My solution here is an elaboration on that answer, reimplemented to fix those issues and with a __call__ method for more convenient reprint invocation.

Tested & working on Python 3.8

import re, sys

class Reprinter:

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

    def write(self, text):
        """Writes text to stdout."""
        sys.stdout.write(text)
        sys.stdout.flush()

    def cursor_prev_line(self):
        """Moves cursor up a line."""
        self.write("x1b[A")

    def cursor_prev_line_start(self):
        """Moves cursor to start of previous line."""
        self.write("x1b[F")

    def cursor_line_start(self):
        """Moves cursor to start of current line."""
        self.write("r")

    def cursor_text_start(self):
        """Moves cursor to start of current text."""
        num_newlines = self.text.count("n")
        if not num_newlines:
            return self.cursor_line_start()
        for _ in range(num_newlines+1):
            self.cursor_prev_line_start()

    def erase(self):
        """Erases current text by replacing non-whitespace chars with spaces."""
        self.cursor_text_start()
        self.write(re.sub(r"[^s]", " ", self.text))
        self.cursor_text_start()

    def __call__(self, text):
        """Prints `text` & overwrites all existing text."""
        self.erase()
        self.write(text)
        self.text = text

reprint = Reprinter()
reprint("How nownbrown cow")
reprint("The rainnin Spain")
Answered By: kwiknik
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.