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

Tweak progress bar docs. #3286

Merged
merged 5 commits into from
Sep 20, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
- Breaking change: Widget.notify and App.notify now return None https://github.com/Textualize/textual/pull/3275
- App.unnotify is now private (renamed to App._unnotify) https://github.com/Textualize/textual/pull/3275
- `Markdown.load` will now attempt to scroll to a related heading if an anchor is provided https://github.com/Textualize/textual/pull/3244
- `ProgressBar` explicitly supports being set back to its indeterminate state https://github.com/Textualize/textual/pull/3286

## [0.36.0] - 2023-09-05

Expand Down
4 changes: 4 additions & 0 deletions src/textual/_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ def post_message(self, message: "Message") -> bool:
...


class UnusedParameter:
"""Helper type for a parameter that isn't specified in a method call."""


SegmentLines = List[List["Segment"]]
CallbackType = Union[Callable[[], Awaitable[None]], Callable[[], None]]
"""Type used for arbitrary callables used in callbacks."""
Expand Down
2 changes: 2 additions & 0 deletions src/textual/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
CallbackType,
IgnoreReturnCallbackType,
MessageTarget,
UnusedParameter,
WatchCallbackType,
)
from .actions import ActionParseResult
Expand All @@ -29,5 +30,6 @@
"MessageTarget",
"NoActiveAppError",
"RenderStyles",
"UnusedParameter",
"WatchCallbackType",
]
31 changes: 16 additions & 15 deletions src/textual/widgets/_progress_bar.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,19 @@

from rich.style import Style

from textual.geometry import clamp

from .._types import UnusedParameter
from ..app import ComposeResult, RenderResult
from ..containers import Horizontal
from ..geometry import clamp
from ..reactive import reactive
from ..renderables.bar import Bar as BarRenderable
from ..timer import Timer
from ..widget import Widget
from ..widgets import Label

UNUSED = UnusedParameter()
"""Sentinel for method signatures."""


class Bar(Widget, can_focus=False):
"""The bar portion of the progress bar."""
Expand Down Expand Up @@ -276,7 +279,6 @@ class ProgressBar(Widget, can_focus=False):
"""The total number of steps associated with this progress bar, when known.

The value `None` will render an indeterminate progress bar.
Once `total` is set to a numerical value, it cannot be set back to `None`.
"""
percentage: reactive[float | None] = reactive[Optional[float]](None)
"""The percentage of progress that has been completed.
Expand Down Expand Up @@ -398,6 +400,7 @@ def advance(self, advance: float = 1) -> None:
```py
progress_bar.advance(10) # Advance 10 steps.
```

Args:
advance: Number of steps to advance progress by.
"""
Expand All @@ -406,30 +409,28 @@ def advance(self, advance: float = 1) -> None:
def update(
self,
*,
total: float | None = None,
progress: float | None = None,
advance: float | None = None,
total: None | float | UnusedParameter = UNUSED,
progress: float | UnusedParameter = UNUSED,
advance: float | UnusedParameter = UNUSED,
) -> None:
"""Update the progress bar with the given options.

Options only affect the progress bar if they are not `None`.

Example:
```py
progress_bar.update(
total=200, # Set new total to 200 steps.
progress=None, # This has no effect.
progress=50, # Set the progress to 50 (out of 200).
)
```

Args:
total: New total number of steps (if not `None`).
progress: Set the progress to the given number of steps (if not `None`).
advance: Advance the progress by this number of steps (if not `None`).
total: New total number of steps.
progress: Set the progress to the given number of steps.
advance: Advance the progress by this number of steps.
"""
if total is not None:
if not isinstance(total, UnusedParameter):
self.total = total
if progress is not None:
if not isinstance(progress, UnusedParameter):
self.progress = progress
if advance is not None:
if not isinstance(advance, UnusedParameter):
self.progress += advance
11 changes: 10 additions & 1 deletion tests/test_progress_bar.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ def test_update_total():
assert pb.total == 1000

pb.update(total=None)
assert pb.total == 1000
assert pb.total is None

pb.update(total=100)
assert pb.total == 100
Expand Down Expand Up @@ -119,6 +119,15 @@ def test_update():
assert pb.progress == 50


def test_go_back_to_indeterminate():
pb = ProgressBar()

pb.total = 100
assert pb.percentage == 0
pb.total = None
assert pb.percentage is None


@pytest.mark.parametrize(
["show_bar", "show_percentage", "show_eta"],
[
Expand Down
Loading