Random Characters at start of progress bar
Closed this issue ยท 11 comments
I had the same problem, so I looked into the code and found where the problem is coming from.
In helpers.py
on line 63, there is a print statement, which has some beginning characters to "reprint" on the same line:
print('\r\x1b[K', end='', file=self.file)
It turns out that, at least for windows for windows, the '\x1b[K'
isn't supposed to be there. For any individuals who want a quick fix, change the code to:
print('\r', end='', file=self.file)
For the repository editors, I propose the following replacement for line 63 in helpers.py
to:
if sys.platform.startswith("win"):
print('\r', end='', file=self.file)
else:
print('\r\x1b[K', end='', file=self.file)
Thanks, this is a huge help.
Just had this, due to windows not recognising the ANSI escape codes used. To fix, edit lines 29, 30 and 90 of _ init _.py (in C:\Users\USERNAME\AppData\Local\Programs\Python\Python37-32\Lib\site-packages\progress)
From:
HIDE_CURSOR = '\x1b[?25l'
SHOW_CURSOR = '\x1b[?25h'
print('\r\x1b[K', end='', file=self.file)
To:
HIDE_CURSOR = ''
SHOW_CURSOR = ''
print('\r', end='', file=self.file)
I can reproduce the same problem in windows environments
If you don't feel comfortable modifying the code of the module directly or want this patch to work in any environment, here's a monkeypatch for modifying the imported version of the module without actually modifying the module code on disk. I've included a check for the OS into both the patch code replacing the cursor strings and the patched function. Thanks to @pepsimax2k and @shadowperson for the original changes.
def getpatchedprogress():
# Import a clean version of the entire package.
import progress
# Import the wraps decorator for copying over the name, docstring, and other metadata.
from functools import wraps
# Get the current platform.
from sys import platform
# Check if we're on Windows.
if platform.startswith("win"):
# Disable HIDE_CURSOR and SHOW_CURSOR characters.
progress.HIDE_CURSOR = ''
progress.SHOW_CURSOR = ''
# Create a patched clearln function that wraps the original function.
@wraps(progress.Infinite.clearln)
def patchedclearln(self):
# Get the current platform.
from sys import platform
# Some sort of check copied from the source.
if self.file and self.is_tty():
# Check if we're on Windows.
if platform.startswith("win"):
# Don't use the character.
print('\r', end='', file=self.file)
else:
# Use the character.
print('\r\x1b[K', end='', file=self.file)
# Copy over the patched clearln function into the imported clearln function.
progress.Infinite.clearln = patchedclearln
# Return the modified version of the entire package.
return progress
This function returns a modified version of the entire package that you can then import from like so:
# import progress
progress = getpatchedprogress()
# You can now import anything from the patched version.
from progress.bar import Bar
I also found it helpful to put the entire function in a separate file, e.g. patch.py
or whatever you'd like, and then you can just monkeypatch like this:
from patch import getpatchedprogress
progress = getpatchedprogress()
# etc...
Enjoy!
I can't really test these changes on different versions of Windows. If someone wants to take responsibility can submit a PR to fix this.
A good solution for showing and hiding cursors is this one:
import sys
import os
if os.name == 'nt':
import msvcrt
import ctypes
class _CursorInfo(ctypes.Structure):
_fields_ = [("size", ctypes.c_int),
("visible", ctypes.c_byte)]
def hide_cursor():
if os.name == 'nt':
ci = _CursorInfo()
handle = ctypes.windll.kernel32.GetStdHandle(-11)
ctypes.windll.kernel32.GetConsoleCursorInfo(handle, ctypes.byref(ci))
ci.visible = False
ctypes.windll.kernel32.SetConsoleCursorInfo(handle, ctypes.byref(ci))
elif os.name == 'posix':
sys.stdout.write("\033[?25l")
sys.stdout.flush()
def show_cursor():
if os.name == 'nt':
ci = _CursorInfo()
handle = ctypes.windll.kernel32.GetStdHandle(-11)
ctypes.windll.kernel32.GetConsoleCursorInfo(handle, ctypes.byref(ci))
ci.visible = True
ctypes.windll.kernel32.SetConsoleCursorInfo(handle, ctypes.byref(ci))
elif os.name == 'posix':
sys.stdout.write("\033[?25h")
sys.stdout.flush()
I will try to create a PR in few days time.
Does the Infinite.is_tty() function reliably indicate whether the terminal supports terminal control codes? If so, perhaps it would make sense, in general, to emit the control codes in cases where is_tty() evaluates to True, but otherwise fall back to emitting a carriage return ("\r") instead of control codes in order to clear the current line.
If the Infinite.is_tty() function does not reliably indicate whether the terminal supports control codes, then maybe it would make sense to replace the is_tty() function with a function called something like terminal_supports_control_codes(), and try to construct the terminal_supports_control_codes() function so that it would reliably detect whether the terminal supports control codes. Then the terminal_supports_control_codes() function could be evaluated to decide whether to emit control codes or, alternatively, to fall back to some less-sophisticated formatting strategy (perhaps the least-sophisticated, worst-case strategy would be to emit a separate line for each progress update -- this would not be pretty, but would probably be preferable to displaying gobbledygook control codes, and would certainly be preferable to displaying no progress output whatsoever.)
@an0ndev solution works ! Actually im using Progress on Windows and im having the same issue of getting some random characters on the progress bar :(