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

Widget documentation sweep #1909

Merged
merged 95 commits into from
Mar 1, 2023
Merged
Show file tree
Hide file tree
Changes from 87 commits
Commits
Show all changes
95 commits
Select commit Hold shift + click to select a range
fb02fde
Add a docstring for HeaderIcon.icon
davep Mar 1, 2023
597b46f
Add missing return type to HeaderIcon.render
davep Mar 1, 2023
3602dab
Flesh out the HeaderIcon.render docstring
davep Mar 1, 2023
ac18b00
Improve the return type of HeaderClockSpace.render
davep Mar 1, 2023
cfb21d0
Flesh out the HeaderClockSpace.render docstring
davep Mar 1, 2023
f96eb93
Add missing return type to HeaderClock.render
davep Mar 1, 2023
27e1311
Flesh out the HeaderClock.render docstring
davep Mar 1, 2023
318e129
Add a docsrtring for HeaderTitle.text
davep Mar 1, 2023
d0dedc0
Add a docsrtring for HeaderTitle.sub_text
davep Mar 1, 2023
4a505e8
Add a docstring to HeaderTitle.render
davep Mar 1, 2023
b071121
Migrate the HeaderTitle.render return type hint to RenderResult
davep Mar 1, 2023
766cae2
Make Header.show_clock private
davep Mar 1, 2023
4258698
Document all of the Header __init__ arguments
davep Mar 1, 2023
61aa558
Document Header.tall
davep Mar 1, 2023
287ef15
Add a module docstring for Header
davep Mar 1, 2023
ed2d547
Add docstrings to the Welcome widget
davep Mar 1, 2023
87f2169
Add the Welcome widget to the documentation
davep Mar 1, 2023
74526c1
Add a module docstring to _text_log
davep Mar 1, 2023
c619984
Add a docstring to TextLog
davep Mar 1, 2023
c0cc080
Be explicit about the type of TextLog.max_lines
davep Mar 1, 2023
8b22875
Fix TextLog.__init__ copy/paste-os
davep Mar 1, 2023
4271886
Tidy up the TextLog.write docstring
davep Mar 1, 2023
11e16b4
Remove unused import in _text_log.py
davep Mar 1, 2023
43cc67d
Add a module docstring to _list_item.py
davep Mar 1, 2023
3478615
Add a class docstring to ListItem
davep Mar 1, 2023
a326169
Add a docstring to ListItem.highlighted
davep Mar 1, 2023
d4ef173
Remove unnecessary pass
davep Mar 1, 2023
a4f22d0
Add a module docstring to _placeholder.py
davep Mar 1, 2023
5a61459
Remove unused import
davep Mar 1, 2023
bba5017
Type TextLog.max_lines in a way that works in all Pythons
davep Mar 1, 2023
d50fcc7
Add a docstring to PlaceholderVariant
davep Mar 1, 2023
46bf558
Add a docstring to Placeholder.variant
davep Mar 1, 2023
8f9cf74
Add a docstring to Placeholder.render
davep Mar 1, 2023
4971e0e
Remove defaults from the Placeholder.__init__ docstring args
davep Mar 1, 2023
9c45c7d
Add a module docstring for _pretty.py
davep Mar 1, 2023
75625ef
Add a class docstring for the Pretty widget.
davep Mar 1, 2023
52adf3f
Add a docstring to Pretty.__init__
davep Mar 1, 2023
7ca3357
Add a docstring for Pretty.render
davep Mar 1, 2023
865a8e5
Add a docstring to Pretty.update
davep Mar 1, 2023
662c1d8
Add a missing
davep Mar 1, 2023
e21e552
Add a module docstring to _tree.py
davep Mar 1, 2023
a837cd1
Ensure PlaceholderVariant gets included in the docs
davep Mar 1, 2023
ac35c1d
Document TreeNode via Tree itself
davep Mar 1, 2023
dbb5263
Document NodeID
davep Mar 1, 2023
3192ee7
Add a docstring for TreeNode.__init__
davep Mar 1, 2023
3658610
Add a docstring for TreeNode.data
davep Mar 1, 2023
6e836de
Reword the documentation for TreeNode.line
davep Mar 1, 2023
3f90812
Reword the documentation for TreeNode.id
davep Mar 1, 2023
e8d0f7a
Reword the documentation for TreeNode.is_expanded
davep Mar 1, 2023
65ba559
Reword the documentation for TreeNode.is_last
davep Mar 1, 2023
2e060c0
Reword the documentation for TreeNode.allow_expand
davep Mar 1, 2023
acb1cc6
Improve the docstring for TreeNode.set_label
davep Mar 1, 2023
6d03829
Remove default information from TreeNode.add_leaf's docstring
davep Mar 1, 2023
106c5aa
Add a class docstring to Tree
davep Mar 1, 2023
fa1f699
Reorder the declaration of the Tree COMPONENT_CLASSES
davep Mar 1, 2023
80fd76f
Document TreeDataType
davep Mar 1, 2023
40b41a1
Add a docstring to Tree.__init__
davep Mar 1, 2023
8917bb6
Document Tree.root
davep Mar 1, 2023
3850070
Improve the docstring of Tree.process_label
davep Mar 1, 2023
fb5a10a
Improve the docstring of Tree.validate_cursor_line
davep Mar 1, 2023
b73cd78
Improve the docstring of Tree.validate_guide_depth
davep Mar 1, 2023
abdcf2f
Add a docstring for EventTreeDataType
davep Mar 1, 2023
21e7cfb
Tidy up the docstring of Widget.scroll_to
davep Mar 1, 2023
22b0b5b
Tidy up the docstring of Widget.scroll_relative
davep Mar 1, 2023
48dd54c
Tidy up the docstring of Widget.scroll_home
davep Mar 1, 2023
af6d56c
Tidy up the docstring of Widget.scroll_end
davep Mar 1, 2023
cf34e5e
Merge branch 'main' into widget-doc-sweep
davep Mar 1, 2023
2fce894
Tidy up the docstring of Widget._scroll_to
davep Mar 1, 2023
52b69d5
Tidy up the docstring of Widget.scroll_to
davep Mar 1, 2023
88f771b
Tidy the wording of a docstring
davep Mar 1, 2023
ee126a9
Tidy up the docstring of Widget.scroll_left
davep Mar 1, 2023
30d8943
Tidy up the docstring of Widget._scroll_left_for_pointer
davep Mar 1, 2023
ef29a77
Remove another default value from Widget.scroll_left
davep Mar 1, 2023
acaec34
Tidy up the docstring of Widget.scroll_right
davep Mar 1, 2023
e8537c6
Tidy up the docstring of Widget._scroll_right_for_pointer
davep Mar 1, 2023
2deb90e
Tidy up the docstring of Widget.scroll_down
davep Mar 1, 2023
0992b36
Tidy up the docstring of Widget._scroll_down_for_pointer
davep Mar 1, 2023
f8167ac
Add some missing markup
davep Mar 1, 2023
ca1abcf
Tidy up the docstring of Widget.scroll_up
davep Mar 1, 2023
b617d67
Tidy up the docstring of Widget._scroll_up_for_pointer
davep Mar 1, 2023
3122748
Tidy up the docstring of Widget.scroll_page_up
davep Mar 1, 2023
ab963d2
Tidy up the docstring of Widget.scroll_page_down
davep Mar 1, 2023
ce016d5
Tidy up the docstring of Widget.scroll_page_left
davep Mar 1, 2023
5afbf48
Tidy up the docstring of Widget.scroll_page_right
davep Mar 1, 2023
53b0e54
Tidy up the docstring of Widget.scroll_to_widget
davep Mar 1, 2023
24fa963
Tidy up the docstring of Widget.scroll_to_region
davep Mar 1, 2023
aa96b54
Final back-read, typo squishing and markup-fixing
davep Mar 1, 2023
847e2cc
Merge branch 'main' into widget-doc-sweep
davep Mar 1, 2023
768d4ae
Code tidy
davep Mar 1, 2023
348fbe2
Improved wording
davep Mar 1, 2023
b1c6da2
Improved wording
davep Mar 1, 2023
b3fe97e
Improved wording
davep Mar 1, 2023
88fcf4f
Improved wording
davep Mar 1, 2023
5cfa998
Improved wording
davep Mar 1, 2023
d9ab2ac
Remove omit a unnecessary word
davep Mar 1, 2023
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 docs/api/placeholder.md
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
::: textual.widgets.Placeholder
::: textual.widgets._placeholder.PlaceholderVariant
3 changes: 3 additions & 0 deletions docs/api/tree.md
Original file line number Diff line number Diff line change
@@ -1 +1,4 @@
::: textual.widgets.Tree
::: textual.widgets._tree.TreeNode
::: textual.widgets._tree.NodeID
::: textual.widgets._tree.TreeDataType
1 change: 0 additions & 1 deletion docs/api/tree_node.md

This file was deleted.

1 change: 1 addition & 0 deletions docs/api/welcome.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
::: textual.widgets.Welcome
2 changes: 1 addition & 1 deletion mkdocs-nav.yml
Original file line number Diff line number Diff line change
Expand Up @@ -179,9 +179,9 @@ nav:
- "api/text_log.md"
- "api/toggle_button.md"
- "api/timer.md"
- "api/tree_node.md"
- "api/tree.md"
- "api/walk.md"
- "api/welcome.md"
- "api/widget.md"
- "Blog":
- blog/index.md
252 changes: 116 additions & 136 deletions src/textual/widget.py

Large diffs are not rendered by default.

55 changes: 44 additions & 11 deletions src/textual/widgets/_header.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
"""Provides a Textual application header widget."""

from __future__ import annotations

from datetime import datetime

from rich.text import Text

from ..app import RenderResult
from ..reactive import Reactive
from ..widget import Widget

Expand All @@ -19,9 +22,16 @@ class HeaderIcon(Widget):
content-align: left middle;
}
"""

icon = Reactive("⭘")
"""The character to use as the icon within the header."""

def render(self) -> RenderResult:
"""Render the header icon.

def render(self):
Returns:
The value to render.
davep marked this conversation as resolved.
Show resolved Hide resolved
"""
return self.icon


Expand All @@ -36,7 +46,12 @@ class HeaderClockSpace(Widget):
}
"""

def render(self) -> str:
def render(self) -> RenderResult:
"""Render the header clock space.

Returns:
The value to render.
davep marked this conversation as resolved.
Show resolved Hide resolved
"""
return ""


Expand All @@ -55,7 +70,12 @@ class HeaderClock(HeaderClockSpace):
def on_mount(self) -> None:
self.set_interval(1, callback=self.refresh, name=f"update header clock")

def render(self):
def render(self) -> RenderResult:
"""Render the header clock.

Returns:
The value to render.
davep marked this conversation as resolved.
Show resolved Hide resolved
"""
return Text(datetime.now().time().strftime("%X"))


Expand All @@ -70,9 +90,17 @@ class HeaderTitle(Widget):
"""

text: Reactive[str] = Reactive("")
"""The main title text."""

sub_text = Reactive("")
"""The sub-title text."""

def render(self) -> RenderResult:
"""Render the title and sub-title.

def render(self) -> Text:
Returns:
The value to render.
"""
text = Text(self.text, no_wrap=True, overflow="ellipsis")
if self.sub_text:
text.append(" — ")
Expand All @@ -81,11 +109,7 @@ def render(self) -> Text:


class Header(Widget):
"""A header widget with icon and clock.

Args:
show_clock: True if the clock should be shown on the right of the header.
"""
"""A header widget with icon and clock."""

DEFAULT_CSS = """
Header {
Expand All @@ -103,6 +127,7 @@ class Header(Widget):
DEFAULT_CLASSES = ""

tall = Reactive(False)
"""Track if the `Header` is in a tall state or not."""

def __init__(
self,
Expand All @@ -112,13 +137,21 @@ def __init__(
id: str | None = None,
classes: str | None = None,
):
"""Initialise the header widget.

Args:
show_clock: ``True`` if the clock should be shown on the right of the header.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a difference between surrounding True with a pair of backticks versus two pairs of backticks? I have seen both and haven't understood the difference yet.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good question; I was asking myself the same thing as I was going through the docstrings and seeing a difference. I tested it and from what I can tell there's zero difference; both have the same effect (my uninformed guess here would be it's mkdocstrings or something supporting a couple of other doc systems' styles).

name: The name of the header widget.
id: The ID of the header widget in the DOM.
classes: The CSS classes of the header widget.
"""
super().__init__(name=name, id=id, classes=classes)
self.show_clock = show_clock
self._show_clock = show_clock

def compose(self):
yield HeaderIcon()
yield HeaderTitle()
yield HeaderClock() if self.show_clock else HeaderClockSpace()
yield HeaderClock() if self._show_clock else HeaderClockSpace()

def watch_tall(self, tall: bool) -> None:
self.set_class(tall, "-tall")
Expand Down
12 changes: 10 additions & 2 deletions src/textual/widgets/_list_item.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,19 @@
"""Provides a list item widget for use with `ListView`."""

from textual import events
from textual.message import Message
from textual.reactive import reactive
from textual.widget import Widget


class ListItem(Widget, can_focus=False):
"""A widget that is an item within a `ListView`.

A `ListItem` is designed for use within a
[ListView][textual.widgets._list_view.ListView], please see `ListView`'s
documentation for more details on use.
"""

DEFAULT_CSS = """
ListItem {
color: $text;
Expand All @@ -27,12 +36,11 @@ class ListItem(Widget, can_focus=False):
"""

highlighted = reactive(False)
"""Is this item highlighted?"""

class _ChildClicked(Message):
"""For informing with the parent ListView that we were clicked"""

pass

def on_click(self, event: events.Click) -> None:
self.post_message_no_wait(self._ChildClicked(self))

Expand Down
19 changes: 14 additions & 5 deletions src/textual/widgets/_placeholder.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
"""Provides a Textual placeholder widget; useful when designing an app's layout."""

from __future__ import annotations

from itertools import cycle
Expand All @@ -8,9 +10,11 @@
from .. import events
from ..css._error_tools import friendly_list
from ..reactive import Reactive, reactive
from ..widget import RenderResult, Widget
from ..widget import Widget

PlaceholderVariant = Literal["default", "size", "text"]
"""The different variants of placeholder."""
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you think of moving the variant table from Placeholder up to here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missed this. Yeah, I was debating that too.


_VALID_PLACEHOLDER_VARIANTS_ORDERED: list[PlaceholderVariant] = [
"default",
"size",
Expand Down Expand Up @@ -94,14 +98,12 @@ def __init__(

Args:
label: The label to identify the placeholder.
If no label is present, uses the placeholder ID instead. Defaults to None.
If no label is present, uses the placeholder ID instead.
variant: The variant of the placeholder.
Defaults to "default".
name: The name of the placeholder. Defaults to None.
id: The ID of the placeholder in the DOM.
Defaults to None.
classes: A space separated string with the CSS classes
of the placeholder, if any. Defaults to None.
of the placeholder, if any.
"""
# Create and cache renderables for all the variants.
self._renderables = {
Expand All @@ -115,12 +117,19 @@ def __init__(
self.styles.background = f"{next(Placeholder._COLORS)} 50%"

self.variant = self.validate_variant(variant)
"""The current variant of the placeholder."""

# Set a cycle through the variants with the correct starting point.
self._variants_cycle = cycle(_VALID_PLACEHOLDER_VARIANTS_ORDERED)
while next(self._variants_cycle) != self.variant:
pass

def render(self) -> RenderableType:
"""Render the placeholder.

Returns:
The value to render.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
The value to render.
The rendered placeholder.

"""
return self._renderables[self.variant]

def cycle_variant(self) -> None:
Expand Down
25 changes: 25 additions & 0 deletions src/textual/widgets/_pretty.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
"""Provides a pretty-printing widget."""

from __future__ import annotations

from typing import Any
Expand All @@ -8,6 +10,11 @@


class Pretty(Widget):
"""A pretty-printing widget.

Used to pretty-print any object.
"""

DEFAULT_CSS = """
Static {
height: auto;
Expand All @@ -22,6 +29,14 @@ def __init__(
id: str | None = None,
classes: str | None = None,
) -> None:
"""Initialise the `Pretty` widget.

Args:
object: The object to pretty-print.
name: The name of the pretty widget.
id: The ID of the pretty in the DOM.
classes: The CSS classes of the pretty.
"""
super().__init__(
name=name,
id=id,
Expand All @@ -30,8 +45,18 @@ def __init__(
self._renderable = PrettyRenderable(object)

def render(self) -> PrettyRenderable:
"""Render the pretty-printed object.

Returns:
The value to render.
davep marked this conversation as resolved.
Show resolved Hide resolved
"""
return self._renderable

def update(self, object: Any) -> None:
"""Update the content of the pretty widget.

Args:
object: The object to pretty-print.
"""
self._renderable = PrettyRenderable(object)
self.refresh(layout=True)
23 changes: 13 additions & 10 deletions src/textual/widgets/_text_log.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
"""Provides a scrollable text-logging widget."""

from __future__ import annotations

from typing import cast
from typing import Optional, cast

from rich.console import RenderableType
from rich.highlighter import ReprHighlighter
from rich.measure import measure_renderables
from rich.pretty import Pretty
from rich.protocol import is_renderable
from rich.segment import Segment
from rich.style import Style
from rich.text import Text

from .._cache import LRUCache
Expand All @@ -19,6 +20,8 @@


class TextLog(ScrollView, can_focus=True):
"""A widget for logging text."""

DEFAULT_CSS = """
TextLog{
background: $surface;
Expand All @@ -27,7 +30,7 @@ class TextLog(ScrollView, can_focus=True):
}
"""

max_lines: var[int | None] = var(None)
max_lines: var[int | None] = var[Optional[int]](None)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As far as my understanding goes, var is just an "alias" for a quick way to create a reactive attribute with some parameters in pre-defined values.
Would it be worth typing max_lines as max_lines: reactive[int | None] = var[Optional[int]](None)?
(This was not a rhetoric question.)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What benefit do we get from that? A downside I can see is that it might be confusing to a reader of the code, seeing two "different" types like that.

min_width: var[int] = var(78)
wrap: var[bool] = var(False)
highlight: var[bool] = var(False)
Expand All @@ -54,10 +57,10 @@ def __init__(
wrap: Enable word wrapping (default is off).
highlight: Automatically highlight content.
markup: Apply Rich console markup.
name: The name of the button.
id: The ID of the button in the DOM.
classes: The CSS classes of the button.
disabled: Whether the button is disabled or not.
name: The name of the text log.
id: The ID of the text log in the DOM.
classes: The CSS classes of the text log.
disabled: Whether the text log is disabled or not.
davep marked this conversation as resolved.
Show resolved Hide resolved
"""
super().__init__(name=name, id=id, classes=classes, disabled=disabled)
self.max_lines = max_lines
Expand Down Expand Up @@ -91,9 +94,9 @@ def write(

Args:
content: Rich renderable (or text).
width: Width to render or None to use optimal width. Defaults to `None`.
expand: Enable expand to widget width, or False to use `width`. Defaults to `False`.
shrink: Enable shrinking of content to fit width. Defaults to `True`.
width: Width to render or ``None`` to use optimal width.
expand: Enable expand to widget width, or ``False`` to use `width`.
shrink: Enable shrinking of content to fit width.
"""

renderable: RenderableType
Expand Down
Loading