!!! abstract “”
How to choose your preferred progress bar backend and customise progress bars.
scinexus defaults to using the tqdm for progress bars. These
behave well across terminal and notebook environments. We also support
using rich for its progress
bars. A single API for different progress backends.
Use set_progress_backend to switch between backends. The
default is tqdm.
```python { notest } import scinexus
scinexus.set_progress_backend(“rich”) # switch to rich scinexus.set_progress_backend(“tqdm”) # switch back to tqdm scinexus.set_progress_backend(None) # reset to default (tqdm)
## Getting a progress bar
Use `get_progress` to obtain a `Progress` instance. Passing `show_progress=True` returns the current default backend.
```python { notest }
import scinexus
pbar = scinexus.get_progress(show_progress=True)
for item in pbar(range(100), msg="Processing"):
pass # your work here
You can pass keyword arguments to configure the default backend:
```python { notest } import scinexus
pbar = scinexus.get_progress(show_progress=True, colour=“blue”, leave=True)
You can also pass a `Progress` instance directly:
```python { notest }
from scinexus.progress import RichProgress
pbar = scinexus.get_progress(show_progress=RichProgress())
!!! note
If you call `get_progress(show_progress=False)`, it returns `NoProgress`, which silently passes through the iterable.
=== “Using tqdm (default)”
Create nested progress bars using `child()`. Each bar can have its own description via the `msg` keyword. Create the child once before the loop — it automatically resets to zero on each subsequent call.
```python { notest }
import scinexus
pbar = scinexus.get_progress(show_progress=True)
child = pbar.child()
for batch in pbar(range(3), msg="Outer loop"):
for item in child(range(10), msg=f"Inner batch {batch}"):
pass # your work here
```
=== “Using rich”
The same nesting pattern works with the `rich` backend:
```python { notest }
import scinexus
scinexus.set_progress_backend("rich")
pbar = scinexus.get_progress(show_progress=True)
child = pbar.child()
for batch in pbar(range(3), msg="Outer loop"):
for item in child(range(10), msg=f"Inner batch {batch}"):
pass # your work here
```
`rich` children share the same `rich.progress.Progress` display instance, so all bars render together in a single live display.
The outer bar tracks the top-level iteration. Each call to
child() creates a new Progress at the next
cursor position, so inner bars appear below the outer one. The child bar
is reused across iterations — on the second and subsequent calls, the
bar resets to zero instead of creating a new one.
When you need to report fractional progress rather than iterating,
use context():
```python { notest } import scinexus
pbar = scinexus.get_progress(show_progress=True)
child = pbar.child() for batch in pbar(range(3), msg=“Processing”): with child.context(msg=f”Batch {batch}“) as ctx: for i in range(100): ctx.update(progress=i / 100, msg=f”Step {i}“)
The context maps progress values from `[0.0, 1.0]` to the configured `[start, end]` range and is cleaned up automatically when the `with` block exits.
## Cleaning up
Both `Progress` and `ProgressContext` support the context manager protocol. Using a progress bar as a context manager ensures that `close()` is called automatically, which finalises the display and moves the cursor past the bars. Without cleanup, leftover bars can leave the terminal cursor in the wrong position.
=== "Using `tqdm` (default)"
```python
import scinexus
with scinexus.get_progress(show_progress=True) as pbar: # (1)!
child = pbar.child()
for batch in pbar(range(3), msg="Outer"):
for item in child(range(10), msg=f"Batch {batch}"):
pass
```
1. `close()` is called automatically and the cursor position is restored.
=== "Using `rich`"
```python
import scinexus
scinexus.set_progress_backend("rich")
with scinexus.get_progress(show_progress=True) as pbar: # (1)!
child = pbar.child()
for batch in pbar(range(3), msg="Outer"):
for item in child(range(10), msg=f"Batch {batch}"):
pass
```
1. `close()` is called automatically and the cursor position is restored.
???- tip "No context manager? No problem!"
```python
import scinexus
pbar = scinexus.get_progress(show_progress=True)
child = pbar.child()
for batch in pbar(range(3), msg="Outer"):
for item in child(range(10), msg=f"Batch {batch}"):
pass
pbar.close() # (1)!
```
1. Call `close()` explicitly when you are done
!!! note
Calling `close()` on a `Progress` instance also closes all of its children. For standalone `ProgressContext` objects (from `context()`), use the `with` statement as shown in the [push-based sub-contexts](#push-based-sub-contexts) section.
## Customising appearance
### Persisting bars after completion
By default, `tqdm` keeps the outermost bar visible after completion but clears nested bars. `rich` removes all bars. Use `leave` to control this:
```python { notest }
from scinexus.progress import TqdmProgress, RichProgress
# Keep all tqdm bars visible after completion
pbar = TqdmProgress(leave=True)
# Keep all rich bars visible after completion
pbar = RichProgress(leave=True)
You can also set leave independently on child bars:
```python { notest } from scinexus.progress import TqdmProgress
pbar = TqdmProgress(leave=True) child = pbar.child(leave=False) # child bars disappear, outer persists
for batch in pbar(range(3), msg=“Outer”): for item in child(range(10), msg=f”Batch {batch}“): pass
### Setting bar colour
Both backends support a `colour` parameter. For `tqdm`, this sets the bar colour directly. For `rich`, it styles the bar column when the display is auto-created.
```python { notest }
from scinexus.progress import TqdmProgress, RichProgress
pbar = TqdmProgress(colour="green")
pbar = RichProgress(colour="cyan")
Colour is inherited by child bars.