File: progressbar.md

package info (click to toggle)
typer 0.19.2-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 3,688 kB
  • sloc: python: 16,702; javascript: 280; sh: 28; makefile: 27
file content (238 lines) | stat: -rw-r--r-- 6,150 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
# Progress Bar

If you are executing an operation that can take some time, you can inform it to the user. 🤓

## Progress Bar

You can use <a href="https://rich.readthedocs.io/en/stable/progress.html" class="external-link" target="_blank">Rich's Progress Display</a> to show a progress bar, for example:

{* docs_src/progressbar/tutorial001.py hl[4,9] *}

You put the thing that you want to iterate over inside of Rich's `track()`, and then iterate over that.

Check it:

<div class="termy">

```console
$ python main.py

---> 100%

Processed 100 things.
```

</div>

...actually, it will look a lot prettier. ✨ But I can't show you the animation here in the docs. 😅

The colors and information will look something like this:

<div class="termy">

```console
$ python main.py

Processing... <font color="#F92672">━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╸</font><font color="#3A3A3A">━━━━━━━━━━</font> <font color="#AE81FF"> 74%</font> <font color="#A1EFE4">0:00:01</font>
```

</div>

## Spinner

When you don't know how long the operation will take, you can use a spinner instead.

Rich allows you to display many things in complex and advanced ways.

For example, this will show two spinners:

{* docs_src/progressbar/tutorial002.py hl[4,8:15] *}

I can't show you the beautiful animation here in the docs. 😅

But at some point in time it will look like this (imagine it's spinning). 🤓

<div class="termy">

```console
$ python main.py

<font color="#A6E22E">⠹</font> Processing...
<font color="#A6E22E">⠹</font> Preparing...
```

</div>

You can learn more about it in the <a href="https://rich.readthedocs.io/en/stable/progress.html" class="external-link" target="_blank">Rich docs for Progress Display</a>.

## Typer `progressbar`

If you can, you should use **Rich** as explained above, it has more features, it's more advanced, and can display information more beautifully. ✨

/// tip

If you can use Rich, use the information above, the Rich docs, and skip the rest of this page. 😎

///

But if you can't use Rich, Typer (actually Click) comes with a simple utility to show progress bars.

/// info

`typer.progressbar()` comes directly from Click, you can read more about it in <a href="https://click.palletsprojects.com/en/8.1.x/utils/#showing-progress-bars" class="external-link" target="_blank">Click's docs</a>.

///

### Use `typer.progressbar`

/// tip

Remember, you are much better off using <a href="https://rich.readthedocs.io/" class="external-link" target="_blank">Rich</a> for this. 😎

///

You can use `typer.progressbar()` with a `with` statement, as in:

```Python
with typer.progressbar(something) as progress:
    pass
```

And you pass as function argument to `typer.progressbar()` the thing that you would normally iterate over.

{* docs_src/progressbar/tutorial003.py hl[8] *}

So, if you have a list of users, this could be:

```Python
users = ["Camila", "Rick", "Morty"]

with typer.progressbar(users) as progress:
    pass
```

And the `with` statement using `typer.progressbar()` gives you an object that you can iterate over, just like if it was the same thing that you would iterate over normally.

But by iterating over this object **Typer** (actually Click) will know to update the progress bar:

```Python
users = ["Camila", "Rick", "Morty"]

with typer.progressbar(users) as progress:
    for user in progress:
        typer.echo(user)
```

/// tip

Notice that there are 2 levels of code blocks. One for the `with` statement and one for the `for` statement.

///

/// info

This is mostly useful for operations that take some time.

In the example above we are faking it with `time.sleep()`.

///

Check it:

<div class="termy">

```console
$ python main.py

---> 100%

Processed 100 things.
```

</div>

### Setting a Progress Bar `length`

/// tip

Remember, you are much better off using <a href="https://rich.readthedocs.io/" class="external-link" target="_blank">Rich</a> for this. 😎

///

The progress bar is generated from the length of the iterable (e.g. the list of users).

But if the length is not available (for example, with something that fetches a new user from a web API each time) you can pass an explicit `length` to `typer.progressbar()`.

{* docs_src/progressbar/tutorial004.py hl[14] *}

Check it:

<div class="termy">

```console
$ python main.py

---> 100%

Processed 100 user IDs.
```

</div>

#### About the function with `yield`

If you hadn't seen something like that `yield` above, that's a "<a href="https://docs.python.org/3/glossary.html#term-generator" class="external-link" target="_blank">generator</a>".

You can iterate over that function with a `for` and at each iteration it will give you the value at `yield`.

`yield` is like a `return` that gives values multiple times and let's you use the function in a `for` loop.

For example:

```Python
def iterate_user_ids():
    # Let's imagine this is a web API, not a range()
    for i in range(100):
        yield i

for i in iterate_user_ids():
    print(i)
```

would print each of the "user IDs" (here it's just the numbers from `0` to `99`).

### Add a `label`

/// tip

Remember, you are much better off using <a href="https://rich.readthedocs.io/" class="external-link" target="_blank">Rich</a> for this. 😎

///

You can also set a `label`:

{* docs_src/progressbar/tutorial005.py hl[8] *}

Check it:

<div class="use-termynal">
<span data-ty="input">python main.py</span>
<span data-ty="progress" data-ty-prompt="Processing"></span>
<span data-ty>Processed 100 things.</span>
</div>

## Iterate manually

If you need to manually iterate over something and update the progress bar irregularly, you can do it by not passing an iterable but just a `length` to `typer.progressbar()`.

And then calling the `.update()` method in the object from the `with` statement:

{* docs_src/progressbar/tutorial006.py hl[8,12] *}

Check it:

<div class="use-termynal">
<span data-ty="input">python main.py</span>
<span data-ty="progress" data-ty-prompt="Batches"></span>
<span data-ty>Processed 1000 things in batches.</span>
</div>