Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[BUG] Progress Display Overwrites Separate Console Output and Repeats Past Tasks #3086

Closed
2 tasks done
Johnserf-Seed opened this issue Aug 13, 2023 · 10 comments
Closed
2 tasks done

Comments

@Johnserf-Seed
Copy link

Johnserf-Seed commented Aug 13, 2023

Describe the bug

When utilizing the Progress class from the rich library to showcase progress for downloading content across different pages, I've noticed repeated task outputs on my terminal. Specifically, as my program fetches and processes data from subsequent pages, the progress display seems to refresh and reflect past tasks. I've ensured there is no repetition in my data or within the tasks themselves in rich.

this is first-page download

image
image

When I step-by-step debugged it, I found that the page-flip download redraws the terminal causing a lot of duplicate output for many tasks

image
image

The task_ids and tasks are not duplicates.

To Reproduce

Part of the code uses the example's code https://github.com/Textualize/rich/blob/master/examples/downloader.py
A brief code snippet is as follows:

import os
import asyncio
from rich.progress import (
    BarColumn,
    DownloadColumn,
    Progress,
    TaskID,
    TextColumn,
    TimeRemainingColumn,
    TransferSpeedColumn,
)
from rich.console import Console

console = Console(width=150) 
console = rich.console.Console(color_system="truecolor")


class Download:
    def __init__(self, config, progress):
        self.config = config
        self.progress = progress

    async def AwemeDownload(self, aweme_data):
        download_tasks = []
        for aweme in aweme_data:
            ctime_f = Util.time.strftime('%Y-%m-%d %H.%M.%S', Util.time.localtime((aweme['create_time'])))
            base_path = aweme['path']
            subdir_name = f'{ctime_f}_{aweme["desc"]}'
            desc_path = Util.os.path.join(base_path, subdir_name)
            os.makedirs(desc_path, exist_ok=True)
            if self.config['music'].lower() == 'yes':
                try:
                    music_url = aweme['music_play_url']['url_list'][0]
                    music_file_name = f'{ctime_f}_{aweme["desc"]}_music'
                    music_file_path = f'{music_file_name}.mp3'
                    music_full_path = os.path.join(desc_path, music_file_path)
                    music_state = os.path.exists(music_full_path)
                    if music_state:
                        task_id = self.progress.add_task(description="[  skip  ]:",
                                                        filename=self.trim_filename(music_file_path, 50),
                                                        total=1, completed=1)
                        self.progress.update(task_id, completed=1)
                    else:
                        task_id = self.progress.add_task(description="[  music  ]:",
                                                        filename=self.trim_filename(music_file_path, 50),
                                                        start=False)
                        console.print('example print')
                        download_task = asyncio.create_task(self.download_file(task_id, music_url, music_full_path))
                        download_tasks.append(download_task)
                        await asyncio.sleep(0)
                except IndexError:
                    pass
         await Util.asyncio.gather(*download_tasks)

class Profile:
    def __init__(self):
        self.process_console = Console(width=150)
        self.progress = Progress(
                Util.TextColumn("{task.description}[bold blue]{task.fields[filename]}", justify="left"),
                Util.BarColumn(bar_width=25),
                "[progress.percentage]{task.percentage:>3.1f}%",
                "•",
                Util.DownloadColumn(),
                "•",
                Util.TransferSpeedColumn(),
                console=self.process_console
        )
        self.download = Download(self.config, self.progress)

    async def get_Profile(self, count: int = 20) -> None:
       ......
        with self.download.progress:
            await self.download.AwemeDownload(aweme_data)

Another problem is that I'm using a different console object but progress still overwrites its output.

Expected behavior

  1. For the progress display, only tasks pertinent to the current page should be shown.
  2. The separate Console object's outputs should remain unaffected by the Progress display.

Actual behavior

  1. Old tasks from prior pages are redrawn atop my terminal.
  2. Console messages printed using the separate Console object are overwritten by the Progress display.

This is my project https://github.com/johnserf-seed/tiktokdownload

@github-actions
Copy link

We found the following entry in the FAQ which you may find helpful:

Feel free to close this issue if you found an answer in the FAQ. Otherwise, please give us a little time to review.

This is an automated reply, generated by FAQtory

@willmcgugan
Copy link
Collaborator

You will need to use the same console object throughout your code if you want to combine printing with scrollbars.

@Johnserf-Seed
Copy link
Author

Johnserf-Seed commented Aug 13, 2023

You will need to use the same console object throughout your code if you want to combine printing with scrollbars.

When I change console=self.process_console to console=console for progress, it still doesn't work. This is because the downloader.py that I referenced from examples at the beginning did not set the console property. When the terminal print overrides the terminal progress bar output I asked gpt3.5 and it told me that the output and the progress bar output can be separated. Of course, again they don't work.
I forgot to mention my version, py version 3.11.1 rich is up to date.

@willmcgugan
Copy link
Collaborator

I'm afraid I didn't follow that. You will need to use the same Console object. Please trust me over GPT.

@Johnserf-Seed
Copy link
Author

I'm afraid I didn't follow that. You will need to use the same Console object. Please trust me over GPT.

I didn't use 2 console objects at first, I used the downloader.py that you provided

@Johnserf-Seed
Copy link
Author

Now with the console object declaration deleted, the progress override is still there. I used python's print and console.print still. Everything works fine on the first page, when I call

with progress:
    await AwemeDownload(aweme_data)

again, the output is overwritten and repeated

@willmcgugan
Copy link
Collaborator

The issue is most likely in your code, and not Rich itself. I suspect you are writing to stdout somewhere, and not going through the Progress console object. It could also be related to the way you have fixed the console width, rather than let Rich auto-detect it.

If you need further help, please narrow down the problem to a short piece of code I can test against.

https://label.dev/articles/minimal-reproducible-example/

@github-actions
Copy link

I hope we solved your problem.

If you like using Rich, you might also enjoy Textual

@Johnserf-Seed
Copy link
Author

So do I need to use progress.console.log to control the output, but I checked my code and the list given to copy_url has no duplicate tasks

@dmdhrumilmistry
Copy link

I'm afraid I didn't follow that. You will need to use the same Console object. Please trust me over GPT.

This worked for me. It turned out that my logging config was using stderror which caused the issue. I used rich.logging.RichHandler and passed console as arg.

logging.basicConfig(
    format="%(message)s",
    datefmt="[%X]",
    handlers=[RichHandler(
        console=console, rich_tracebacks=True, tracebacks_show_locals=True)],
)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants