verigak/progress

Random Characters at start of progress bar

Closed this issue ยท 11 comments

Hello,

I ran test_progress.py on Windows

The terminal prints some strange characters at the start of the line and I don't know why:

image

Thanks

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.

Would be very pleased for a fix to this, will use the monkey patch in the meantime

image

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.)

This should be fixed with 12e46ed

@an0ndev solution works ! Actually im using Progress on Windows and im having the same issue of getting some random characters on the progress bar :(