vbauerster / mpb

multi progress bar for Go cli applications
The Unlicense
2.29k stars 123 forks source link

Add Printf() method to the Progress class #89

Closed KerkDovan closed 3 years ago

KerkDovan commented 3 years ago

Hello!

Could you please add Printf(format string, a ...interface{}) method to the Progress class? Thus it would be possible to print messages, not related to the progress bars, as using simple fmt.Println() corrupts the output. Something similar to Python tqdm's write() method.

Oh, it also should be safe to use after p.Wait() is called and returned.

For now I've found this workaround, but I suppose the inner implementation would be much more optimized, as it could avoid extra progress bar creation and panic-recovers. Code below is based on the poplog example, however, bars are not popped in this situation. ```Golang package main import ( "fmt" "math/rand" "time" "github.com/vbauerster/mpb/v6" "github.com/vbauerster/mpb/v6/decor" ) func main() { p := mpb.New(mpb.PopCompletedMode()) // This is the function, that prints the message printf := func(format string, a ...interface{}) { msg := fmt.Sprintf(format, a...) // As p.Add() panics after p.Wait() is returned, we should // use reserve method to guarantee the output defer func() { if r := recover(); r != nil { fmt.Println("fmt.Println():", msg) } }() p.Add(0, nil, mpb.PrependDecorators(decor.Name("printf(): "+msg))).SetTotal(0, true) } // Simulating some output, not related to the progress bars ticker := time.NewTicker(200 * time.Millisecond) go func() { defer ticker.Stop() for n := 0; ; n++ { <-ticker.C printf("%v", n) } }() total, numBars := 100, 4 for i := 0; i < numBars; i++ { name := fmt.Sprintf("Bar#%d:", i) bar := p.AddBar(int64(total), mpb.BarFillerOnComplete(fmt.Sprintf("%s has been completed", name)), mpb.BarFillerTrim(), mpb.PrependDecorators( decor.OnComplete(decor.Name(name), ""), decor.OnComplete(decor.NewPercentage(" % d "), ""), ), mpb.AppendDecorators( decor.OnComplete(decor.Name(" "), ""), decor.OnComplete(decor.EwmaETA(decor.ET_STYLE_GO, 60), ""), ), mpb.BarNoPop(), ) // simulating some work rng := rand.New(rand.NewSource(time.Now().UnixNano())) max := 10 * time.Millisecond for i := 0; i < total; i++ { // start variable is solely for EWMA calculation // EWMA's unit of measure is an iteration's duration start := time.Now() time.Sleep(time.Duration(rng.Intn(10)+1) * max / 10) bar.Increment() // we need to call DecoratorEwmaUpdate to fulfill ewma decorator's contract bar.DecoratorEwmaUpdate(time.Since(start)) } } p.Wait() // After p.Wait() printf() will panic and recover time.Sleep(500 * time.Millisecond) } ```
Output: ``` printf(): 0 printf(): 1 printf(): 2 printf(): 3 printf(): 4 printf(): 5 printf(): 6 printf(): 7 printf(): 8 printf(): 9 printf(): 10 printf(): 11 printf(): 12 printf(): 13 printf(): 14 printf(): 15 printf(): 16 printf(): 17 printf(): 18 printf(): 19 printf(): 20 printf(): 21 printf(): 22 printf(): 23 printf(): 24 printf(): 25 printf(): 26 printf(): 27 printf(): 28 printf(): 29 printf(): 30 Bar#0: has been completed Bar#1: has been completed Bar#2: has been completed Bar#3: has been completed fmt.Println(): 31 fmt.Println(): 32 ```
vbauerster commented 3 years ago

Sorry, I'm not going to implement such Printf method.