rsalmei / alive-progress

A new kind of Progress Bar, with real-time throughput, ETA, and very cool animations!
MIT License
5.53k stars 206 forks source link

support writing to stderr #177

Closed aerickson closed 1 year ago

aerickson commented 2 years ago

I think that stderr is the preferred destination for progress bars (and errors in command line tools). When the bar is written to stderr, users can still see the progress bar for commands that are redirecting or piping output and can avoid getting the bar in the captured output.

I'm happy to work on this if you can provide some guidance on how you'd like it implemented. As a proof of concept, changing alive_progress/utils/terminal/tty.py to sys.stderr had the desired effect.

I'm replacing a simple spinner with alive_progress and writing to stderr is one thing that alive_progress is missing.

tqdm writes to stderr by default. See 'file' at https://github.com/tqdm/tqdm#parameters.

TheTechRobo commented 2 years ago

When the bar is written to stderr, users can still see the progress bar for commands that are redirecting or piping output and can avoid getting the bar in the captured output.

If I remember correctly, the bar always uses stdout even if it's redirected. Cf. #171

aerickson commented 2 years ago

Correct. Yeah, that statement was regarding other progress bars that write to stderr.

I've got a branch that writes to stderr by default (https://github.com/rsalmei/alive-progress/compare/main...aerickson:alive-progress:write_to_stderr).

rsalmei commented 2 years ago

Hey @aerickson, you're right, perhaps the stderr would be a better default. I wonder how no one has ever asked about this... I have a new version almost ready, I'll try to take a look at this before releasing it.

aerickson commented 2 years ago

It is interesting that it hasn't been brought up. I guess it's a bit of an obscure feature... most apps with progress bars aren't used as input to other commands (they're end-user UIs)?

Awesome. :) Thank you.

rsalmei commented 2 years ago

You're welcome. Perhaps you've nailed it, that's because they're end-user UIs... Although my alive-progress do work when used as input to other commands, since I disable the refresh, and only output the final receipt.

rsalmei commented 2 years ago

Hey @aerickson, it's done!!

It was hard work to accomplish it, but the refactoring was worth it.

Look how cool the effect is: Untitled

The code:

import sys
import time

from alive_progress import alive_bar

def run(f):
    with alive_bar(100, file=f) as bar:
        for _ in range(100):
            time.sleep(.02)
            bar()

run(sys.stdout)
run(sys.stderr)

Next release man! 👍

aerickson commented 2 years ago

When will this be released? Thanks! :)

jacobian91 commented 2 years ago

This does not seem to be working on this branch: https://github.com/aerickson/alive-progress/tree/file_as_argument

import time

from alive_progress import alive_bar

def run():
    text_object = "foo"
    with alive_bar(100, file=text_object) as bar:
        for _ in range(100):
            time.sleep(0.02)
            bar()
            # print(text_object)

run()

I would expect that when the line print(text_object) is commented, no bar will show, but the bar is still showing up when I run it.

Instead of using a string literal as the file argument, I also tried a file object and nothing was written there either.

aerickson commented 2 years ago

Sorry, I was wrong. I never finished the feature. :(

I'm not sure how @rsalmei is doing it in his implementation.

rsalmei commented 2 years ago

Hey yeah, I have to try and find time to commit this... It's done for four months now, and still only on my machine. Since I work with Rust now, all my free time lately goes to studying Rust...

I'll try to get to it next weekend.