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

progressbar(hide=True) option for hiding the progress bar #2609

Open
simonw opened this issue Sep 12, 2023 · 4 comments · May be fixed by #2727
Open

progressbar(hide=True) option for hiding the progress bar #2609

simonw opened this issue Sep 12, 2023 · 4 comments · May be fixed by #2727
Milestone

Comments

@simonw
Copy link
Contributor

simonw commented Sep 12, 2023

Often when I use the Click progressbar I find myself wanting to conditionally hide it. Sometimes it's because there's another option in play which means I have output to display in place of it - others it's because I added a --silent option (as seen in curl) for disabling it entirely.

It's actually a bit tricky doing this at the moment, due to its use as a context manager.

What I'd really like to be able to do is this:

hide = True  # or False depending on various things

with click.progressbar(items, show_eta=True, hide=hide):
    for item in items:
        process_item(item)
@simonw
Copy link
Contributor Author

simonw commented Sep 12, 2023

Here's one workaround I've used for this, which feels pretty messy:

class NullProgressBar:
    def __init__(self, *args):
        self.args = args

    def __iter__(self):
        yield from self.args[0]

    def update(self, value):
        pass


@contextlib.contextmanager
def progressbar(*args, **kwargs):
    silent = kwargs.pop("silent")
    if silent:
        yield NullProgressBar(*args)
    else:
        with click.progressbar(*args, **kwargs) as bar:
            yield bar

Then:

        with progressbar(
            length=self.count, silent=not show_progress, label="1: Evaluating"
        ) as bar:

@simonw
Copy link
Contributor Author

simonw commented Sep 12, 2023

It looks like there's already a property that could be used for this:

self.is_hidden: bool = not isatty(self.file)

So the implementation may be as straight-forward as adding a hide: bool = False parameter and then doing this:

 self.is_hidden: bool = not hide and not isatty(self.file) 

@simonw
Copy link
Contributor Author

simonw commented Sep 12, 2023

I tried this:

        with click.progressbar(
            ids, label="Calculating similarities", show_percent=True
        ) as bar:
            if hide:
                bar.is_hidden = True

But it still shows the bar once at the start of the loop, because of this:

def __enter__(self) -> ProgressBar[V]:
self.entered = True
self.render_progress()
return self

Which calls render_progress() before I've had a chance to toggle is_hidden to False:

def render_progress(self) -> None:
import shutil
if self.is_hidden:
# Only output the label as it changes if the output is not a
# TTY. Use file=stderr if you expect to be piping stdout.
if self._last_line != self.label:
self._last_line = self.label
echo(self.label, file=self.file, color=self.color)

@davidism
Copy link
Member

I'm wary of changing our progress bar at this point. I generally recommend that people use tqdm or rich if they need features beyond what ours provides. Both of them have a way to hide a progress bar.

In this case, it does seem relatively straightforward to modify our existing hide behavior with a parameter, so I think I'm ok with this.

@davidism davidism added this to the 8.2.0 milestone May 22, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants