* api docs

* more docstrings

* logs

* docs shakeup

* fix notes, added intro to all apis

* Remove defaults to

* add note to events

* note

* use fira code
This commit is contained in:
Will McGugan
2023-04-08 15:35:49 +01:00
committed by GitHub
parent 5726a20e8e
commit 2244b1161e
103 changed files with 879 additions and 557 deletions

View File

@@ -13,7 +13,9 @@
{% set show_full_path = config.show_object_full_path %} {% set show_full_path = config.show_object_full_path %}
{% endif %} {% endif %}
{% if not root or config.show_root_heading %}
{% if 1 %}
{% filter heading(heading_level, {% filter heading(heading_level,
role="class", role="class",
@@ -34,7 +36,7 @@
<code>{% if show_full_path %}{{ class.path }}{% else %}{{ class.name }}{% endif %}</code> <code>{% if show_full_path %}{{ class.path }}{% else %}{{ class.name }}{% endif %}</code>
{% endif %} {% endif %}
{% with labels = class.labels %} {% with labels = ['class'] %}
{% include "labels.html" with context %} {% include "labels.html" with context %}
{% endwith %} {% endwith %}
@@ -43,11 +45,10 @@
{% if config.separate_signature and config.merge_init_into_class %} {% if config.separate_signature and config.merge_init_into_class %}
{% if "__init__" in class.members %} {% if "__init__" in class.members %}
{% with function = class.members["__init__"] %} {% with function = class.members["__init__"] %}
{% filter highlight(language="python", inline=False) %} {% filter highlight(language="python", inline=False) -%}
class {% filter format_signature(config.line_length) %} def {% filter format_signature(config.line_length) %}
{% if show_full_path %}{{ class.path }}{% else %}{{ class.name }}{% endif %} __init__{% include "signature.html" with context %}
{% include "signature.html" with context %} {% endfilter %}:
{% endfilter %}
{% endfilter %} {% endfilter %}
{% endwith %} {% endwith %}
{% endif %} {% endif %}

View File

@@ -0,0 +1,5 @@
{{ log.debug("Rendering admonition") }}
<details class="{{ section.value.kind }}" open>
<summary>{{ section.title|convert_markdown(heading_level, html_id, strip_paragraph=True) }}</summary>
{{ section.value.contents|convert_markdown(heading_level, html_id) }}
</details>

View File

@@ -29,8 +29,7 @@
{% include "signature.html" with context %} {% include "signature.html" with context %}
{% endfilter %} {% endfilter %}
{% endif %} {% endif %}
{% with labels = function.labels or [(function.parameters._parameters_list and function.parameters._parameters_list[0].name == 'self') and 'method' or 'function'] %}
{% with labels = function.labels %}
{% include "labels.html" with context %} {% include "labels.html" with context %}
{% endwith %} {% endwith %}
@@ -41,7 +40,7 @@
def {% filter format_signature(config.line_length) %} def {% filter format_signature(config.line_length) %}
{% if show_full_path %}{{ function.path }}{% else %}{{ function.name }}{% endif %} {% if show_full_path %}{{ function.path }}{% else %}{{ function.name }}{% endif %}
{% include "signature.html" with context %} {% include "signature.html" with context %}
{% endfilter %} {% endfilter %}:
{% endfilter %} {% endfilter %}
{% endif %} {% endif %}

View File

@@ -10,7 +10,7 @@
( (
{%- for parameter in function.parameters -%} {%- for parameter in function.parameters -%}
{%- if parameter.name not in ("self", "cls") or loop.index0 > 0 or not (function.parent and function.parent.is_class) -%} {%- if 1 -%}
{%- if parameter.kind.value == "positional-only" -%} {%- if parameter.kind.value == "positional-only" -%}
{%- set ns.has_pos_only = True -%} {%- set ns.has_pos_only = True -%}

View File

@@ -1,3 +0,0 @@
::: textual.widgets.Button
::: textual.widgets._button.ButtonVariant
::: textual.widgets._button.InvalidButtonVariant

View File

@@ -1 +0,0 @@
::: textual.widgets.Checkbox

View File

@@ -1 +0,0 @@
::: textual.widgets.DataTable

View File

@@ -1 +0,0 @@
::: textual.widgets.DirectoryTree

View File

@@ -1 +0,0 @@
::: textual.widgets.Footer

View File

@@ -1 +0,0 @@
::: textual.widgets.Header

View File

@@ -1 +0,0 @@
::: textual.widgets.Input

View File

@@ -1 +0,0 @@
::: textual.widgets.Label

View File

@@ -1 +0,0 @@
::: textual.widgets.ListItem

View File

@@ -1 +0,0 @@
::: textual.widgets.ListView

View File

@@ -1 +0,0 @@
::: textual.widgets.LoadingIndicator

1
docs/api/logger.md Normal file
View File

@@ -0,0 +1 @@
::: textual.Logger

View File

@@ -1 +0,0 @@
::: textual.widgets.Markdown

View File

@@ -1 +0,0 @@
::: textual.widgets.MarkdownViewer

View File

@@ -1,5 +1 @@
A message pump is a class that processes messages.
It is a base class for the `App`, `Screen`, and `Widget` classes.
::: textual.message_pump ::: textual.message_pump

View File

@@ -1,3 +0,0 @@
::: textual.widgets.OptionList
::: textual.widgets._option_list.Option
::: textual.widgets._option_list.Separator

View File

@@ -1,2 +0,0 @@
::: textual.widgets.Placeholder
::: textual.widgets._placeholder.PlaceholderVariant

View File

@@ -1 +0,0 @@
::: textual.widgets.RadioButton

View File

@@ -1 +0,0 @@
::: textual.widgets.RadioSet

View File

@@ -1 +0,0 @@
::: textual.widgets.Static

View File

@@ -1 +0,0 @@
::: textual.widgets.Switch

View File

@@ -1,2 +0,0 @@
::: textual.widgets.TabbedContent
::: textual.widgets.TabPane

View File

@@ -1,2 +0,0 @@
::: textual.widgets.Tab
::: textual.widgets.Tabs

View File

@@ -1 +0,0 @@
::: textual.widgets.TextLog

View File

@@ -1 +0,0 @@
::: textual.widgets._toggle_button.ToggleButton

View File

@@ -1,4 +0,0 @@
::: textual.widgets.Tree
::: textual.widgets._tree.TreeNode
::: textual.widgets._tree.NodeID
::: textual.widgets._tree.TreeDataType

View File

@@ -1 +0,0 @@
::: textual.widgets.Welcome

View File

@@ -1 +1,2 @@
::: textual.work ::: textual.work

View File

@@ -38,7 +38,7 @@ Additionally there are new [update_cell][textual.widgets.DataTable.update_cell]
## Tree control ## Tree control
The [Tree](../../api/tree.md) widget has grown a few methods to programmatically expand, collapse and toggle tree nodes. The [Tree](../../widgets/tree.md) widget has grown a few methods to programmatically expand, collapse and toggle tree nodes.
## Breaking changes ## Breaking changes

View File

@@ -43,9 +43,14 @@ body[data-md-color-primary="black"] .excalidraw svg rect {
border: 0; border: 0;
} }
.doc-object code {
font-family: "Fira Code", "SFMono-Regular", Consolas, "Courier New", Courier,
monospace;
}
/* Indentation. */ /* Indentation. */
div.doc-contents:not(.first) .doc-contents { div.doc-contents:not(.first) {
padding-left: 25px; padding-left: 25px;
border-left: .05rem solid var(--md-typeset-table-color); border-left: .05rem solid var(--md-typeset-table-color);
} }

View File

@@ -61,6 +61,13 @@ The WIDGET widget provides the following component classes:
## See also ## See also
- [WIDGET](../api/WIDGET.md) code reference.
- Another related API. - Another related API.
- Something else useful. - Something else useful.
---
::: textual.widgets.WIDGET
options:
heading_level: 2

View File

@@ -39,12 +39,15 @@ Clicking any of the non-disabled buttons in the example app below will result in
## Messages ## Messages
### ::: textual.widgets.Button.Pressed - [Button.Pressed][textual.widgets.Button.Pressed]
## Additional Notes ## Additional Notes
* The spacing between the text and the edges of a button are due to border, _not_ padding. To create a button with zero visible padding, use the `border: none;` declaration. * The spacing between the text and the edges of a button are due to border, _not_ padding. To create a button with zero visible padding, use the `border: none;` declaration.
## See Also ---
* [Button](../api/button.md) code reference
::: textual.widgets.Button
options:
heading_level: 2

View File

@@ -54,8 +54,12 @@ The checkbox widget provides the following component classes:
## Messages ## Messages
### ::: textual.widgets.Checkbox.Changed - [Checkbox.Changed][textual.widgets.Checkbox.Changed]
## See Also
- [Checkbox](../api/checkbox.md) code reference ---
::: textual.widgets.Checkbox
options:
heading_level: 2

View File

@@ -47,10 +47,13 @@ When the user presses the "Markdown" button the view is switched:
## Reactive Attributes ## Reactive Attributes
| Name | Type | Default | Description | | Name | Type | Default | Description |
|-----------|-----------------|---------|----------------------------------------------------------------------| | --------- | --------------- | ------- | ----------------------------------------------------------------------- |
| `current` | `str` \| `None` | `None` | The ID of the currently-visible child. `None` means nothing is visible. | | `current` | `str` \| `None` | `None` | The ID of the currently-visible child. `None` means nothing is visible. |
## See Also ---
* [ContentSwitcher][textual.widgets.ContentSwitcher] code reference
::: textual.widgets.ContentSwitcher
options:
heading_level: 2

View File

@@ -36,19 +36,13 @@ The example below populates a table with CSV data.
## Messages ## Messages
### ::: textual.widgets.DataTable.CellHighlighted - [DataTable.CellHighlighted][textual.widgets.DataTable.CellHighlighted]
- [DataTable.CellSelected][textual.widgets.DataTable.CellSelected]
### ::: textual.widgets.DataTable.CellSelected - [DataTable.RowHighlighted][textual.widgets.DataTable.RowHighlighted]
- [DataTable.RowSelected][textual.widgets.DataTable.RowSelected]
### ::: textual.widgets.DataTable.RowHighlighted - [DataTable.ColumnHighlighted][textual.widgets.DataTable.ColumnHighlighted]
- [DataTable.ColumnSelected][textual.widgets.DataTable.ColumnSelected]
### ::: textual.widgets.DataTable.RowSelected - [DataTable.HeaderSelected][textual.widgets.DataTable.HeaderSelected]
### ::: textual.widgets.DataTable.ColumnHighlighted
### ::: textual.widgets.DataTable.ColumnSelected
### ::: textual.widgets.DataTable.HeaderSelected
## Bindings ## Bindings
@@ -68,6 +62,9 @@ The data table widget provides the following component classes:
show_root_heading: false show_root_heading: false
show_root_toc_entry: false show_root_toc_entry: false
## See Also ---
* [DataTable][textual.widgets.DataTable] code reference
::: textual.widgets.DataTable
options:
heading_level: 2

View File

@@ -36,7 +36,7 @@ and directories:
## Messages ## Messages
### ::: textual.widgets.DirectoryTree.FileSelected - [DirectoryTree.FileSelected][textual.widgets.DirectoryTree.FileSelected]
## Reactive Attributes ## Reactive Attributes
@@ -57,5 +57,13 @@ The directory tree widget provides the following component classes:
## See Also ## See Also
* [DirectoryTree][textual.widgets.DirectoryTree] code reference
* [Tree][textual.widgets.Tree] code reference * [Tree][textual.widgets.Tree] code reference
---
::: textual.widgets.DirectoryTree
options:
heading_level: 2

View File

@@ -46,6 +46,10 @@ The footer widget provides the following component classes:
* You can prevent keybindings from appearing in the footer by setting the `show` argument of the `Binding` to `False`. * You can prevent keybindings from appearing in the footer by setting the `show` argument of the `Binding` to `False`.
* You can customize the text that appears for the key itself in the footer using the `key_display` argument of `Binding`. * You can customize the text that appears for the key itself in the footer using the `key_display` argument of `Binding`.
## See Also
* [Footer](../api/footer.md) code reference ---
::: textual.widgets.Footer
options:
heading_level: 2

View File

@@ -30,6 +30,9 @@ The example below shows an app with a `Header`.
This widget sends no messages. This widget sends no messages.
## See Also ---
* [Header](../api/header.md) code reference
::: textual.widgets.Header
options:
heading_level: 2

View File

@@ -32,9 +32,8 @@ The example below shows how you might create a simple form using two `Input` wid
## Messages ## Messages
### ::: textual.widgets.Input.Changed - [Input.Changed][textual.widgets.Input.Changed]
- [Input.Submitted][textual.widgets.Input.Submitted]
### ::: textual.widgets.Input.Submitted
## Bindings ## Bindings
@@ -58,6 +57,9 @@ The input widget provides the following component classes:
* The spacing around the text content is due to border. To remove it, set `border: none;` in your CSS. * The spacing around the text content is due to border. To remove it, set `border: none;` in your CSS.
## See Also ---
* [Input](../api/input.md) code reference
::: textual.widgets.Input
options:
heading_level: 2

View File

@@ -30,6 +30,9 @@ This widget has no reactive attributes.
This widget sends no messages. This widget sends no messages.
## See Also ---
* [Label](../api/label.md) code reference
::: textual.widgets.Label
options:
heading_level: 2

View File

@@ -26,16 +26,19 @@ of multiple `ListItem`s. The arrow keys can be used to navigate the list.
## Reactive Attributes ## Reactive Attributes
| Name | Type | Default | Description | | Name | Type | Default | Description |
|---------------|--------|---------|--------------------------------------| | ------------- | ------ | ------- | ------------------------------------ |
| `highlighted` | `bool` | `False` | True if this ListItem is highlighted | | `highlighted` | `bool` | `False` | True if this ListItem is highlighted |
#### Attributes #### Attributes
| attribute | type | purpose | | attribute | type | purpose |
|-----------|------------|-----------------------------| | --------- | ---------- | --------------------------- |
| `item` | `ListItem` | The item that was selected. | | `item` | `ListItem` | The item that was selected. |
## See Also ---
* [ListItem](../api/list_item.md) code reference
::: textual.widgets.ListItem
options:
heading_level: 2

View File

@@ -37,9 +37,8 @@ The example below shows an app with a simple `ListView`.
## Messages ## Messages
### ::: textual.widgets.ListView.Highlighted - [ListView.Highlighted][textual.widgets.ListView.Highlighted]
- [ListView.Selected][textual.widgets.ListView.Selected]
### ::: textual.widgets.ListView.Selected
## Bindings ## Bindings
@@ -50,6 +49,9 @@ The list view widget defines the following bindings:
show_root_heading: false show_root_heading: false
show_root_toc_entry: false show_root_toc_entry: false
## See Also ---
* [ListView](../api/list_view.md) code reference
::: textual.widgets.ListView
options:
heading_level: 2

View File

@@ -28,7 +28,9 @@ LoadingIndicator {
```python ```python
--8<-- "docs/examples/widgets/loading_indicator.py" --8<-- "docs/examples/widgets/loading_indicator.py"
``` ```
---
## See Also
* [LoadingIndicator](../api/loading_indicator.md) code reference ::: textual.widgets.LoadingIndicator
options:
heading_level: 2

View File

@@ -29,14 +29,20 @@ The following example displays Markdown from a string.
## Messages ## Messages
### ::: textual.widgets.Markdown.TableOfContentsUpdated - [Markdown.TableOfContentsUpdated][textual.widgets.Markdown.TableOfContentsUpdated]
- [Markdown.TableOfContentsSelected][textual.widgets.Markdown.TableOfContentsSelected]
### ::: textual.widgets.Markdown.TableOfContentsSelected - [Markdown.LinkClicked][textual.widgets.Markdown.LinkClicked]
### ::: textual.widgets.Markdown.LinkClicked
## See Also ## See Also
* [Markdown][textual.widgets.Markdown] code reference
* [MarkdownViewer][textual.widgets.MarkdownViewer] code reference * [MarkdownViewer][textual.widgets.MarkdownViewer] code reference
---
::: textual.widgets.Markdown
options:
heading_level: 2

View File

@@ -35,5 +35,13 @@ The following example displays Markdown from a string and a Table of Contents.
## See Also ## See Also
* [MarkdownViewer][textual.widgets.MarkdownViewer] code reference
* [Markdown][textual.widgets.Markdown] code reference * [Markdown][textual.widgets.Markdown] code reference
---
::: textual.widgets.MarkdownViewer
options:
heading_level: 2

View File

@@ -82,14 +82,13 @@ tables](https://rich.readthedocs.io/en/latest/tables.html):
## Reactive Attributes ## Reactive Attributes
| Name | Type | Default | Description | | Name | Type | Default | Description |
|---------------|-----------------|---------|---------------------------------------------------------------------------| | ------------- | --------------- | ------- | ------------------------------------------------------------------------- |
| `highlighted` | `int` \| `None` | `None` | The index of the highlighted option. `None` means nothing is highlighted. | | `highlighted` | `int` \| `None` | `None` | The index of the highlighted option. `None` means nothing is highlighted. |
## Messages ## Messages
### ::: textual.widgets.OptionList.OptionHighlighted - [OptionList.OptionHighlight][textual.widgets.OptionList.OptionHighlighted]
- [OptionList.OptionSelected][textual.widgets.OptionList.OptionSelected]
### ::: textual.widgets.OptionList.OptionSelected
Both of the messages above inherit from this common base, which makes Both of the messages above inherit from this common base, which makes
available the following properties relating to the `OptionList` and the available the following properties relating to the `OptionList` and the
@@ -122,6 +121,8 @@ The option list provides the following component classes:
show_root_heading: false show_root_heading: false
show_root_toc_entry: false show_root_toc_entry: false
## See Also
* [OptionList][textual.widgets.OptionList] code reference
::: textual.widgets.OptionList
options:
heading_level: 2

View File

@@ -35,7 +35,7 @@ The example below shows each placeholder variant.
## Reactive Attributes ## Reactive Attributes
| Name | Type | Default | Description | | Name | Type | Default | Description |
| ---------- | ------ | ----------- | -------------------------------------------------- | | --------- | ----- | ----------- | -------------------------------------------------- |
| `variant` | `str` | `"default"` | Styling variant. One of `default`, `size`, `text`. | | `variant` | `str` | `"default"` | Styling variant. One of `default`, `size`, `text`. |
@@ -43,6 +43,9 @@ The example below shows each placeholder variant.
This widget sends no messages. This widget sends no messages.
## See Also ---
* [Placeholder](../api/placeholder.md) code reference
::: textual.widgets.Placeholder
options:
heading_level: 2

View File

@@ -56,9 +56,15 @@ The radio button widget provides the following component classes:
## Messages ## Messages
### ::: textual.widgets.RadioButton.Changed - [RadioButton.Changed][textual.widgets.RadioButton.Changed]
## See Also ## See Also
- [RadioButton](../api/radiobutton.md) code reference
- [RadioSet](./radioset.md) - [RadioSet](./radioset.md)
---
::: textual.widgets.RadioButton
options:
heading_level: 2

View File

@@ -31,7 +31,7 @@ The example below shows two radio sets, one built using a collection of
## Messages ## Messages
### ::: textual.widgets.RadioSet.Changed - [RadioSet.Changed][textual.widgets.RadioSet.Changed]
#### Example #### Example
@@ -56,5 +56,12 @@ Here is an example of using the message to react to changes in a `RadioSet`:
## See Also ## See Also
- [RadioSet](../api/radioset.md) code reference
- [RadioButton](./radiobutton.md) - [RadioButton](./radiobutton.md)
---
::: textual.widgets.RadioSet
options:
heading_level: 2

View File

@@ -31,5 +31,12 @@ This widget sends no messages.
## See Also ## See Also
* [Static](../api/static.md) code reference
* [Label](./label.md) * [Label](./label.md)
---
::: textual.widgets.Static
options:
heading_level: 2

View File

@@ -52,12 +52,15 @@ The switch widget provides the following component classes:
## Messages ## Messages
### ::: textual.widgets.Switch.Changed - [Switch.Changed][textual.widgets.Switch.Changed]
## Additional Notes ## Additional Notes
- To remove the spacing around a `Switch`, set `border: none;` and `padding: 0;`. - To remove the spacing around a `Switch`, set `border: none;` and `padding: 0;`.
## See Also ---
- [Switch](../api/switch.md) code reference
::: textual.widgets.Switch
options:
heading_level: 2

View File

@@ -103,6 +103,22 @@ The following example contains a `TabbedContent` with three tabs.
## See also ## See also
- [TabbedContent](../api/tabbed_content.md) code reference.
- [Tabs](../api/tabs.md) code reference. - [Tabs](tabs.md)
- [ContentSwitcher](../api/content_switcher.md) code reference. - [ContentSwitcher](content_switcher.md)
---
::: textual.widgets.TabbedContent
options:
heading_level: 2
---
::: textual.widgets.TabPane
options:
heading_level: 2

View File

@@ -61,8 +61,8 @@ The following example adds a `Tabs` widget above a text label. Press ++a++ to ad
## Messages ## Messages
### ::: textual.widgets.Tabs.TabActivated - [Tabs.TabActivate][textual.widgets.Tabs.TabActivated]
### ::: textual.widgets.Tabs.Cleared - [Tabs.Cleared][textual.widgets.Tabs.Cleared]
## Bindings ## Bindings
@@ -73,6 +73,17 @@ The Tabs widget defines the following bindings:
show_root_heading: false show_root_heading: false
show_root_toc_entry: false show_root_toc_entry: false
## See Also
- [Tabs](../api/tabs.md) code reference ---
::: textual.widgets.Tabs
options:
heading_level: 2
---
::: textual.widgets.Tab
options:
heading_level: 2

View File

@@ -39,6 +39,9 @@ The example below shows an application showing a `TextLog` with different kinds
This widget sends no messages. This widget sends no messages.
## See Also ---
* [TextLog](../api/text_log.md) code reference
::: textual.widgets.TextLog
options:
heading_level: 2

View File

@@ -62,7 +62,16 @@ The tree widget provides the following component classes:
show_root_heading: false show_root_heading: false
show_root_toc_entry: false show_root_toc_entry: false
## See Also
* [Tree][textual.widgets.Tree] code reference ---
* [TreeNode][textual.widgets.tree.TreeNode] code reference
::: textual.widgets.Tree
options:
heading_level: 2
---
::: textual.widgets.tree.TreeNode
options:
heading_level: 2

View File

@@ -152,50 +152,25 @@ nav:
- "api/app.md" - "api/app.md"
- "api/await_remove.md" - "api/await_remove.md"
- "api/binding.md" - "api/binding.md"
- "api/button.md"
- "api/checkbox.md"
- "api/color.md" - "api/color.md"
- "api/containers.md" - "api/containers.md"
- "api/content_switcher.md"
- "api/coordinate.md" - "api/coordinate.md"
- "api/data_table.md"
- "api/directory_tree.md"
- "api/dom_node.md" - "api/dom_node.md"
- "api/events.md" - "api/events.md"
- "api/footer.md"
- "api/geometry.md" - "api/geometry.md"
- "api/header.md"
- "api/index.md" - "api/index.md"
- "api/input.md" - "api/logger.md"
- "api/label.md"
- "api/list_item.md"
- "api/list_view.md"
- "api/loading_indicator.md"
- "api/logging.md" - "api/logging.md"
- "api/markdown_viewer.md"
- "api/markdown.md"
- "api/message_pump.md" - "api/message_pump.md"
- "api/message.md" - "api/message.md"
- "api/option_list.md"
- "api/pilot.md" - "api/pilot.md"
- "api/placeholder.md"
- "api/query.md" - "api/query.md"
- "api/radiobutton.md"
- "api/radioset.md"
- "api/reactive.md" - "api/reactive.md"
- "api/screen.md" - "api/screen.md"
- "api/scroll_view.md" - "api/scroll_view.md"
- "api/static.md"
- "api/strip.md" - "api/strip.md"
- "api/switch.md"
- "api/tabbed_content.md"
- "api/tabs.md"
- "api/text_log.md"
- "api/timer.md" - "api/timer.md"
- "api/toggle_button.md"
- "api/tree.md"
- "api/walk.md" - "api/walk.md"
- "api/welcome.md"
- "api/widget.md" - "api/widget.md"
- "api/work.md" - "api/work.md"
- "api/worker.md" - "api/worker.md"

View File

@@ -1,7 +1,6 @@
from __future__ import annotations from __future__ import annotations
import inspect import inspect
from functools import partial, wraps
from typing import TYPE_CHECKING, Callable from typing import TYPE_CHECKING, Callable
import rich.repr import rich.repr

View File

@@ -139,11 +139,11 @@ class BoundAnimator:
attribute: Name of the attribute to animate. attribute: Name of the attribute to animate.
value: The value to animate to. value: The value to animate to.
final_value: The final value of the animation. Defaults to `value` if not set. final_value: The final value of the animation. Defaults to `value` if not set.
duration: The duration of the animate. Defaults to None. duration: The duration of the animate.
speed: The speed of the animation. Defaults to None. speed: The speed of the animation.
delay: A delay (in seconds) before the animation starts. Defaults to 0.0. delay: A delay (in seconds) before the animation starts.
easing: An easing method. Defaults to "in_out_cubic". easing: An easing method.
on_complete: A callable to invoke when the animation is finished. Defaults to None. on_complete: A callable to invoke when the animation is finished.
""" """
start_value = getattr(self._obj, attribute) start_value = getattr(self._obj, attribute)
@@ -237,11 +237,11 @@ class Animator:
obj: The object containing the attribute. obj: The object containing the attribute.
attribute: The name of the attribute. attribute: The name of the attribute.
value: The destination value of the attribute. value: The destination value of the attribute.
final_value: The final value, or ellipsis if it is the same as ``value``. Defaults to Ellipsis/ final_value: The final value, or ellipsis if it is the same as ``value``.
duration: The duration of the animation, or ``None`` to use speed. Defaults to ``None``. duration: The duration of the animation, or ``None`` to use speed.
speed: The speed of the animation. Defaults to None. speed: The speed of the animation.
easing: An easing function. Defaults to DEFAULT_EASING. easing: An easing function.
delay: Number of seconds to delay the start of the animation by. Defaults to 0. delay: Number of seconds to delay the start of the animation by.
on_complete: Callback to run after the animation completes. on_complete: Callback to run after the animation completes.
""" """
animate_callback = partial( animate_callback = partial(
@@ -280,10 +280,10 @@ class Animator:
obj: The object containing the attribute. obj: The object containing the attribute.
attribute: The name of the attribute. attribute: The name of the attribute.
value: The destination value of the attribute. value: The destination value of the attribute.
final_value: The final value, or ellipsis if it is the same as ``value``. Defaults to .... final_value: The final value, or ellipsis if it is the same as ``value``.
duration: The duration of the animation, or ``None`` to use speed. Defaults to ``None``. duration: The duration of the animation, or ``None`` to use speed.
speed: The speed of the animation. Defaults to None. speed: The speed of the animation.
easing: An easing function. Defaults to DEFAULT_EASING. easing: An easing function.
on_complete: Callback to run after the animation completes. on_complete: Callback to run after the animation completes.
""" """
if not hasattr(obj, attribute): if not hasattr(obj, attribute):

View File

@@ -142,7 +142,7 @@ class LRUCache(Generic[CacheKey, CacheValue]):
Args: Args:
key: Key key: Key
default: Default to return if key is not present. Defaults to None. default: Default to return if key is not present.
Returns: Returns:
Either the value or a default. Either the value or a default.
@@ -256,7 +256,7 @@ class FIFOCache(Generic[CacheKey, CacheValue]):
Args: Args:
key: Key key: Key
default: Default to return if key is not present. Defaults to None. default: Default to return if key is not present.
Returns: Returns:
Either the value or a default. Either the value or a default.

View File

@@ -1,3 +1,10 @@
"""
A decorator used to create [workers](/guide/workers).
"""
from __future__ import annotations from __future__ import annotations
from functools import partial, wraps from functools import partial, wraps
@@ -53,7 +60,7 @@ def work(
exit_on_error: bool = True, exit_on_error: bool = True,
exclusive: bool = False, exclusive: bool = False,
) -> Callable[FactoryParamSpec, Worker[ReturnType]] | Decorator: ) -> Callable[FactoryParamSpec, Worker[ReturnType]] | Decorator:
"""Worker decorator factory. """A decorator used to create [workers](/guide/workers).
Args: Args:
method: A function or coroutine. method: A function or coroutine.

View File

@@ -1,3 +1,11 @@
"""
A class to manage [workers](/guide/workers) for an app.
You access this object via [App.workers][textual.app.App.workers] or [Widget.workers][textual.dom.DOMNode.workers].
"""
from __future__ import annotations from __future__ import annotations
import asyncio import asyncio

View File

@@ -66,7 +66,7 @@ from ._wait import wait_for_idle
from ._worker_manager import WorkerManager from ._worker_manager import WorkerManager
from .actions import ActionParseResult, SkipAction from .actions import ActionParseResult, SkipAction
from .await_remove import AwaitRemove from .await_remove import AwaitRemove
from .binding import Binding, Bindings from .binding import Binding, _Bindings
from .css.query import NoMatches from .css.query import NoMatches
from .css.stylesheet import Stylesheet from .css.stylesheet import Stylesheet
from .design import ColorSystem from .design import ColorSystem
@@ -242,10 +242,10 @@ CallThreadReturnType = TypeVar("CallThreadReturnType")
class App(Generic[ReturnType], DOMNode): class App(Generic[ReturnType], DOMNode):
"""The base class for Textual Applications. """The base class for Textual Applications.
Args: Args:
driver_class: Driver class or ``None`` to auto-detect. Defaults to None. driver_class: Driver class or ``None`` to auto-detect.
css_path: Path to CSS or ``None`` for no CSS file. css_path: Path to CSS or ``None`` for no CSS file.
Defaults to None. To load multiple CSS files, pass a list of strings or paths which will be loaded in order. To load multiple CSS files, pass a list of strings or paths which will be loaded in order.
watch_css: Watch CSS for changes. Defaults to False. watch_css: Watch CSS for changes.
Raises: Raises:
CssPathError: When the supplied CSS path(s) are an unexpected type. CssPathError: When the supplied CSS path(s) are an unexpected type.
@@ -436,7 +436,12 @@ class App(Generic[ReturnType], DOMNode):
@property @property
def workers(self) -> WorkerManager: def workers(self) -> WorkerManager:
"""A worker manager.""" """The worker manager.
Returns:
An object to manage workers.
"""
return self._workers return self._workers
@property @property
@@ -446,7 +451,12 @@ class App(Generic[ReturnType], DOMNode):
@property @property
def children(self) -> Sequence["Widget"]: def children(self) -> Sequence["Widget"]:
"""A view on to the children which contains just the screen.""" """A view on to the App's children (just the screen).
Returns:
A sequence of widgets.
"""
try: try:
return (self.screen,) return (self.screen,)
except ScreenError: except ScreenError:
@@ -489,12 +499,12 @@ class App(Generic[ReturnType], DOMNode):
Args: Args:
attribute: Name of the attribute to animate. attribute: Name of the attribute to animate.
value: The value to animate to. value: The value to animate to.
final_value: The final value of the animation. Defaults to `value` if not set. final_value: The final value of the animation.
duration: The duration of the animate. Defaults to None. duration: The duration of the animate.
speed: The speed of the animation. Defaults to None. speed: The speed of the animation.
delay: A delay (in seconds) before the animation starts. Defaults to 0.0. delay: A delay (in seconds) before the animation starts.
easing: An easing method. Defaults to "in_out_cubic". easing: An easing method.
on_complete: A callable to invoke when the animation is finished. Defaults to None. on_complete: A callable to invoke when the animation is finished.
""" """
self._animate( self._animate(
@@ -520,7 +530,12 @@ class App(Generic[ReturnType], DOMNode):
@property @property
def screen_stack(self) -> list[Screen]: def screen_stack(self) -> list[Screen]:
"""A *copy* of the screen stack.""" """A *copy* of the screen stack.
Returns:
A snapshot of the current state of the screen stack.
"""
return self._screen_stack.copy() return self._screen_stack.copy()
def exit( def exit(
@@ -529,7 +544,7 @@ class App(Generic[ReturnType], DOMNode):
"""Exit the app, and return the supplied result. """Exit the app, and return the supplied result.
Args: Args:
result: Return value. Defaults to None. result: Return value.
message: Optional message to display on exit. message: Optional message to display on exit.
""" """
self._exit = True self._exit = True
@@ -540,7 +555,12 @@ class App(Generic[ReturnType], DOMNode):
@property @property
def focused(self) -> Widget | None: def focused(self) -> Widget | None:
"""The widget that is focused on the currently active screen.""" """The widget that is focused on the currently active screen.
Returns:
The currently focused widget, or `None` if nothing is focused.
"""
return self.screen.focused return self.screen.focused
@property @property
@@ -666,7 +686,12 @@ class App(Generic[ReturnType], DOMNode):
@property @property
def size(self) -> Size: def size(self) -> Size:
"""The size of the terminal.""" """The size of the terminal.
Returns:
Size of the terminal.
"""
if self._driver is not None and self._driver._size is not None: if self._driver is not None and self._driver._size is not None:
width, height = self._driver._size width, height = self._driver._size
else: else:
@@ -675,7 +700,12 @@ class App(Generic[ReturnType], DOMNode):
@property @property
def log(self) -> Logger: def log(self) -> Logger:
"""The logger object.""" """Textual log interface.
Returns:
A Textual logger.
"""
return self._logger return self._logger
def _log( def _log(
@@ -699,7 +729,7 @@ class App(Generic[ReturnType], DOMNode):
``` ```
Args: Args:
verbosity: Verbosity level 0-3. Defaults to 1. verbosity: Verbosity level 0-3.
""" """
devtools = self.devtools devtools = self.devtools
@@ -786,7 +816,7 @@ class App(Generic[ReturnType], DOMNode):
"""Save an SVG "screenshot". This action will save an SVG file containing the current contents of the screen. """Save an SVG "screenshot". This action will save an SVG file containing the current contents of the screen.
Args: Args:
filename: Filename of screenshot, or None to auto-generate. Defaults to None. filename: Filename of screenshot, or None to auto-generate.
path: Path to directory. Defaults to current working directory. path: Path to directory. Defaults to current working directory.
""" """
self.save_screenshot(filename, path) self.save_screenshot(filename, path)
@@ -796,7 +826,7 @@ class App(Generic[ReturnType], DOMNode):
Args: Args:
title: The title of the exported screenshot or None title: The title of the exported screenshot or None
to use app title. Defaults to None. to use app title.
""" """
assert self._driver is not None, "App must be running" assert self._driver is not None, "App must be running"
@@ -826,7 +856,7 @@ class App(Generic[ReturnType], DOMNode):
Args: Args:
filename: Filename of SVG screenshot, or None to auto-generate filename: Filename of SVG screenshot, or None to auto-generate
a filename with the date and time. Defaults to None. a filename with the date and time.
path: Path to directory for output. Defaults to current working directory. path: Path to directory for output. Defaults to current working directory.
time_format: Date and time format to use if filename is None. time_format: Date and time format to use if filename is None.
Defaults to a format like ISO 8601 with some reserved characters replaced with underscores. Defaults to a format like ISO 8601 with some reserved characters replaced with underscores.
@@ -865,9 +895,9 @@ class App(Generic[ReturnType], DOMNode):
Args: Args:
keys: A comma separated list of keys, i.e. keys: A comma separated list of keys, i.e.
action: Action to bind to. action: Action to bind to.
description: Short description of action. Defaults to "". description: Short description of action.
show: Show key in UI. Defaults to True. show: Show key in UI.
key_display: Replacement text for key, or None to use default. Defaults to None. key_display: Replacement text for key, or None to use default.
""" """
self._bindings.bind( self._bindings.bind(
keys, action, description, show=show, key_display=key_display keys, action, description, show=show, key_display=key_display
@@ -930,9 +960,9 @@ class App(Generic[ReturnType], DOMNode):
"""An asynchronous context manager for testing app. """An asynchronous context manager for testing app.
Args: Args:
headless: Run in headless mode (no output or input). Defaults to True. headless: Run in headless mode (no output or input).
size: Force terminal size to `(WIDTH, HEIGHT)`, size: Force terminal size to `(WIDTH, HEIGHT)`,
or None to auto-detect. Defaults to None. or None to auto-detect.
""" """
from .pilot import Pilot from .pilot import Pilot
@@ -981,9 +1011,9 @@ class App(Generic[ReturnType], DOMNode):
"""Run the app asynchronously. """Run the app asynchronously.
Args: Args:
headless: Run in headless mode (no output). Defaults to False. headless: Run in headless mode (no output).
size: Force terminal size to `(WIDTH, HEIGHT)`, size: Force terminal size to `(WIDTH, HEIGHT)`,
or None to auto-detect. Defaults to None. or None to auto-detect.
auto_pilot: An auto pilot coroutine. auto_pilot: An auto pilot coroutine.
Returns: Returns:
@@ -1042,9 +1072,9 @@ class App(Generic[ReturnType], DOMNode):
"""Run the app. """Run the app.
Args: Args:
headless: Run in headless mode (no output). Defaults to False. headless: Run in headless mode (no output).
size: Force terminal size to `(WIDTH, HEIGHT)`, size: Force terminal size to `(WIDTH, HEIGHT)`,
or None to auto-detect. Defaults to None. or None to auto-detect.
auto_pilot: An auto pilot coroutine. auto_pilot: An auto pilot coroutine.
Returns: Returns:
@@ -1119,7 +1149,6 @@ class App(Generic[ReturnType], DOMNode):
Args: Args:
id: The ID of the node to search for. id: The ID of the node to search for.
expect_type: Require the object be of the supplied type, or None for any type. expect_type: Require the object be of the supplied type, or None for any type.
Defaults to None.
Returns: Returns:
The first child of this node with the specified ID. The first child of this node with the specified ID.
@@ -1918,7 +1947,7 @@ class App(Generic[ReturnType], DOMNode):
"""Refresh CSS. """Refresh CSS.
Args: Args:
animate: Also execute CSS animations. Defaults to True. animate: Also execute CSS animations.
""" """
stylesheet = self.app.stylesheet stylesheet = self.app.stylesheet
stylesheet.set_variables(self.get_css_variables()) stylesheet.set_variables(self.get_css_variables())
@@ -1973,14 +2002,14 @@ class App(Generic[ReturnType], DOMNode):
self.console.bell() self.console.bell()
@property @property
def _binding_chain(self) -> list[tuple[DOMNode, Bindings]]: def _binding_chain(self) -> list[tuple[DOMNode, _Bindings]]:
"""Get a chain of nodes and bindings to consider. """Get a chain of nodes and bindings to consider.
If no widget is focused, returns the bindings from both the screen and the app level bindings. If no widget is focused, returns the bindings from both the screen and the app level bindings.
Otherwise, combines all the bindings from the currently focused node up the DOM to the root App. Otherwise, combines all the bindings from the currently focused node up the DOM to the root App.
""" """
focused = self.focused focused = self.focused
namespace_bindings: list[tuple[DOMNode, Bindings]] namespace_bindings: list[tuple[DOMNode, _Bindings]]
if focused is None: if focused is None:
namespace_bindings = [ namespace_bindings = [
@@ -1995,7 +2024,7 @@ class App(Generic[ReturnType], DOMNode):
return namespace_bindings return namespace_bindings
@property @property
def _modal_binding_chain(self) -> list[tuple[DOMNode, Bindings]]: def _modal_binding_chain(self) -> list[tuple[DOMNode, _Bindings]]:
"""The binding chain, ignoring everything before the last modal.""" """The binding chain, ignoring everything before the last modal."""
binding_chain = self._binding_chain binding_chain = self._binding_chain
for index, (node, _bindings) in enumerate(binding_chain, 1): for index, (node, _bindings) in enumerate(binding_chain, 1):
@@ -2061,7 +2090,7 @@ class App(Generic[ReturnType], DOMNode):
Args: Args:
action: Action encoded in a string. action: Action encoded in a string.
default_namespace: Namespace to use if not provided in the action, default_namespace: Namespace to use if not provided in the action,
or None to use app. Defaults to None. or None to use app.
Returns: Returns:
True if the event has handled. True if the event has handled.

View File

@@ -1,4 +1,9 @@
"""Provides the type of an awaitable remove.""" """
An *optionally* awaitable object returned by methods that remove widgets.
"""
from asyncio import Event, Task from asyncio import Event, Task
from typing import Generator from typing import Generator

View File

@@ -1,3 +1,12 @@
"""
A binding maps a key press on to an action.
See [bindings](/guide/input#bindings) in the guide for details.
"""
from __future__ import annotations from __future__ import annotations
from dataclasses import dataclass from dataclasses import dataclass
@@ -44,7 +53,7 @@ class Binding:
@rich.repr.auto @rich.repr.auto
class Bindings: class _Bindings:
"""Manage a set of bindings.""" """Manage a set of bindings."""
def __init__( def __init__(
@@ -98,13 +107,13 @@ class Bindings:
else {} else {}
) )
def copy(self) -> Bindings: def copy(self) -> _Bindings:
"""Return a copy of this instance. """Return a copy of this instance.
Return: Return:
New bindings object. New bindings object.
""" """
copy = Bindings() copy = _Bindings()
copy.keys = self.keys.copy() copy.keys = self.keys.copy()
return copy return copy
@@ -112,7 +121,7 @@ class Bindings:
yield self.keys yield self.keys
@classmethod @classmethod
def merge(cls, bindings: Iterable[Bindings]) -> Bindings: def merge(cls, bindings: Iterable[_Bindings]) -> _Bindings:
"""Merge a bindings. Subsequent bound keys override initial keys. """Merge a bindings. Subsequent bound keys override initial keys.
Args: Args:
@@ -124,7 +133,7 @@ class Bindings:
keys: dict[str, Binding] = {} keys: dict[str, Binding] = {}
for _bindings in bindings: for _bindings in bindings:
keys.update(_bindings.keys) keys.update(_bindings.keys)
return Bindings(keys.values()) return _Bindings(keys.values())
@property @property
def shown_keys(self) -> list[Binding]: def shown_keys(self) -> list[Binding]:

View File

@@ -1,9 +1,6 @@
""" """
This module contains a powerful Color class which Textual uses to expose colors. This module contains a powerful Color class which Textual uses to expose colors.
The only exception would be for Rich renderables, which require a rich.color.Color instance.
You can convert from a Textual color to a Rich color with the [rich_color][textual.color.Color.rich_color] property.
## Named colors ## Named colors
The following named colors are used by the [parse][textual.color.Color.parse] method. The following named colors are used by the [parse][textual.color.Color.parse] method.
@@ -46,6 +43,7 @@ from rich.color import ColorType
from rich.color_triplet import ColorTriplet from rich.color_triplet import ColorTriplet
from rich.style import Style from rich.style import Style
from rich.text import Text from rich.text import Text
from typing_extensions import Final
from textual.css.scalar import percentage_string_to_float from textual.css.scalar import percentage_string_to_float
from textual.css.tokenize import CLOSE_BRACE, COMMA, DECIMAL, OPEN_BRACE, PERCENT from textual.css.tokenize import CLOSE_BRACE, COMMA, DECIMAL, OPEN_BRACE, PERCENT
@@ -58,14 +56,14 @@ _TRUECOLOR = ColorType.TRUECOLOR
class HSL(NamedTuple): class HSL(NamedTuple):
"""A color in HLS format.""" """A color in HLS (Hue, Saturation, Lightness) format."""
h: float h: float
"""Hue""" """Hue in range 0 to 1."""
s: float s: float
"""Saturation""" """Saturation in range 0 to 1."""
l: float l: float
"""Lightness""" """Lightness in range 0 to 1."""
@property @property
def css(self) -> str: def css(self) -> str:
@@ -73,28 +71,32 @@ class HSL(NamedTuple):
h, s, l = self h, s, l = self
def as_str(number: float) -> str: def as_str(number: float) -> str:
"""Format a float."""
return f"{number:.1f}".rstrip("0").rstrip(".") return f"{number:.1f}".rstrip("0").rstrip(".")
return f"hsl({as_str(h*360)},{as_str(s*100)}%,{as_str(l*100)}%)" return f"hsl({as_str(h*360)},{as_str(s*100)}%,{as_str(l*100)}%)"
class HSV(NamedTuple): class HSV(NamedTuple):
"""A color in HSV format.""" """A color in HSV (Hue, Saturation, Value) format."""
h: float h: float
"""Hue""" """Hue in range 0 to 1."""
s: float s: float
"""Saturation""" """Saturation in range 0 to 1"""
v: float v: float
"""Value""" """Value un range 0 to 1."""
class Lab(NamedTuple): class Lab(NamedTuple):
"""A color in CIE-L*ab format.""" """A color in CIE-L*ab format."""
L: float L: float
"""Lightness in range 0 to 100."""
a: float a: float
"""A axis in range -127 to 128."""
b: float b: float
"""B axis in range -127 to 128."""
RE_COLOR = re.compile( RE_COLOR = re.compile(
@@ -126,7 +128,7 @@ class ColorParseError(Exception):
Args: Args:
message: The error message message: The error message
suggested_color: A close color we can suggest. Defaults to None. suggested_color: A close color we can suggest.
""" """
def __init__(self, message: str, suggested_color: str | None = None): def __init__(self, message: str, suggested_color: str | None = None):
@@ -136,26 +138,32 @@ class ColorParseError(Exception):
@rich.repr.auto @rich.repr.auto
class Color(NamedTuple): class Color(NamedTuple):
"""A class to represent a RGB color with an alpha component.""" """A class to represent a color.
Colors are stored as three values representing the degree of red, green, and blue in a color, and a
fourth "alpha" value which defines where the color lies on a gradient of opaque to transparent.
"""
r: int r: int
"""Red component (0-255)""" """Red component in range 0 to 255."""
g: int g: int
"""Green component (0-255)""" """Green component in range 0 to 255."""
b: int b: int
"""Blue component (0-255)""" """Blue component in range 0 to 255."""
a: float = 1.0 a: float = 1.0
"""Alpha component (0-1)""" """Alpha component in range 0 to 1."""
@classmethod @classmethod
def from_rich_color(cls, rich_color: RichColor) -> Color: def from_rich_color(cls, rich_color: RichColor) -> Color:
"""Create a new color from Rich's Color class. """Create a new color from Rich's Color class.
Args: Args:
rich_color: An instance of rich.color.Color. rich_color: An instance of [Rich color][rich.color.Color].
Returns: Returns:
A new Color. A new Color instance.
""" """
r, g, b = rich_color.get_truecolor() r, g, b = rich_color.get_truecolor()
return cls(r, g, b) return cls(r, g, b)
@@ -192,22 +200,12 @@ class Color(NamedTuple):
@property @property
def is_transparent(self) -> bool: def is_transparent(self) -> bool:
"""Check if the color is transparent, i.e. has 0 alpha. """Is the color transparent (i.e. has 0 alpha)?"""
Returns:
True if transparent, otherwise False.
"""
return self.a == 0 return self.a == 0
@property @property
def clamped(self) -> Color: def clamped(self) -> Color:
"""Get a color with all components saturated to maximum and minimum values. """A clamped color (this color with all values in expected range)."""
Returns:
A color object.
"""
r, g, b, a = self r, g, b, a = self
_clamp = clamp _clamp = clamp
color = Color( color = Color(
@@ -243,20 +241,16 @@ class Color(NamedTuple):
@property @property
def rgb(self) -> tuple[int, int, int]: def rgb(self) -> tuple[int, int, int]:
"""Get just the red, green, and blue components. """A tuple of the red, gree, and blue color components."""
Returns:
Color components
"""
r, g, b, _ = self r, g, b, _ = self
return (r, g, b) return (r, g, b)
@property @property
def hsl(self) -> HSL: def hsl(self) -> HSL:
"""Get the color as HSL. """This color in HSL format.
HSL color is an alternative way of representing a color, which can be used in certain color calculations.
Returns:
Color in HSL format.
""" """
r, g, b = self.normalized r, g, b = self.normalized
h, l, s = rgb_to_hls(r, g, b) h, l, s = rgb_to_hls(r, g, b)
@@ -264,10 +258,10 @@ class Color(NamedTuple):
@property @property
def brightness(self) -> float: def brightness(self) -> float:
"""Get the human perceptual brightness. """The human perceptual brightness.
Returns: A value of 1 is returned for pure white, and 0 for pure black.
Brightness value (0-1). Other colors lie on a gradient between the two extremes.
""" """
r, g, b = self.normalized r, g, b = self.normalized
@@ -278,8 +272,7 @@ class Color(NamedTuple):
def hex(self) -> str: def hex(self) -> str:
"""The color in CSS hex form, with 6 digits for RGB, and 8 digits for RGBA. """The color in CSS hex form, with 6 digits for RGB, and 8 digits for RGBA.
Returns: For example, `"#46b3de"` for an RGB color, or `"#3342457f"` for a color with alpha.
A CSS hex-style color, e.g. `"#46b3de"` or `"#3342457f"`
""" """
r, g, b, a = self.clamped r, g, b, a = self.clamped
@@ -293,8 +286,7 @@ class Color(NamedTuple):
def hex6(self) -> str: def hex6(self) -> str:
"""The color in CSS hex form, with 6 digits for RGB. Alpha is ignored. """The color in CSS hex form, with 6 digits for RGB. Alpha is ignored.
Returns: For example, `"#46b3de"`.
A CSS hex-style color, e.g. "#46b3de"
""" """
r, g, b, _a = self.clamped r, g, b, _a = self.clamped
@@ -302,10 +294,9 @@ class Color(NamedTuple):
@property @property
def css(self) -> str: def css(self) -> str:
"""The color in CSS rgb or rgba form. """The color in CSS RGB or RGBA form.
Returns: For example, `"rgb(10,20,30)"` for an RGB color, or `"rgb(50,70,80,0.5)"` for an RGBA color.
A CSS style color, e.g. `"rgb(10,20,30)"` or `"rgb(50,70,80,0.5)"`
""" """
r, g, b, a = self r, g, b, a = self
@@ -313,11 +304,7 @@ class Color(NamedTuple):
@property @property
def monochrome(self) -> Color: def monochrome(self) -> Color:
"""Get a monochrome version of this color. """A monochrome version of this color."""
Returns:
A new monochrome color.
"""
r, g, b, a = self r, g, b, a = self
gray = round(r * 0.2126 + g * 0.7152 + b * 0.0722) gray = round(r * 0.2126 + g * 0.7152 + b * 0.0722)
return Color(gray, gray, gray, a) return Color(gray, gray, gray, a)
@@ -358,10 +345,14 @@ class Color(NamedTuple):
) -> Color: ) -> Color:
"""Generate a new color between two colors. """Generate a new color between two colors.
This method calculates a new color on a gradient.
The position on the gradient is given by `factor`, which is a float between 0 and 1, where 0 is the original color, and 1 is the `destination` color.
A value of `gradient` between the two extremes produces a color somewhere between the two end points.
Args: Args:
destination: Another color. destination: Another color.
factor: A blend factor, 0 -> 1. factor: A blend factor, 0 -> 1.
alpha: New alpha for result. Defaults to None. alpha: New alpha for result.
Returns: Returns:
A new color. A new color.
@@ -515,7 +506,7 @@ class Color(NamedTuple):
Args: Args:
amount: Value between 0-1 to reduce luminance by. amount: Value between 0-1 to reduce luminance by.
alpha: Alpha component for new color or None to copy alpha. Defaults to None. alpha: Alpha component for new color or None to copy alpha.
Returns: Returns:
New color. New color.
@@ -529,7 +520,7 @@ class Color(NamedTuple):
Args: Args:
amount: Value between 0-1 to increase luminance by. amount: Value between 0-1 to increase luminance by.
alpha: Alpha component for new color or None to copy alpha. Defaults to None. alpha: Alpha component for new color or None to copy alpha.
Returns: Returns:
New color. New color.
@@ -541,8 +532,7 @@ class Color(NamedTuple):
"""Get a light or dark color that best contrasts this color, for use with text. """Get a light or dark color that best contrasts this color, for use with text.
Args: Args:
alpha: An alpha value to adjust the pure white / black by. alpha: An alpha value to apply to the result.
Defaults to 0.95.
Returns: Returns:
A new color, either an off-white or off-black A new color, either an off-white or off-black
@@ -597,8 +587,10 @@ class Gradient:
# Color constants # Color constants
WHITE = Color(255, 255, 255) WHITE: Final = Color(255, 255, 255)
BLACK = Color(0, 0, 0) """A constant for pure white."""
BLACK: Final = Color(0, 0, 0)
"""A constant for pure black."""
def rgb_to_lab(rgb: Color) -> Lab: def rgb_to_lab(rgb: Color) -> Lab:

View File

@@ -1,3 +1,9 @@
"""
Container widgets for quick styling.
"""
from .widget import Widget from .widget import Widget

View File

@@ -1,3 +1,8 @@
"""
A class to store a coordinate, used by the [DataTable][textual.widgets.DataTable].
"""
from __future__ import annotations from __future__ import annotations
from typing import NamedTuple from typing import NamedTuple

View File

@@ -13,7 +13,7 @@ def friendly_list(
Args: Args:
words: A list of words. words: A list of words.
joiner: The last joiner word. Defaults to "or". joiner: The last joiner word.
Returns: Returns:
List as prose. List as prose.

View File

@@ -74,7 +74,7 @@ class HelpText:
Attributes: Attributes:
summary: A succinct summary of the issue. summary: A succinct summary of the issue.
bullets: Bullet points which provide additional bullets: Bullet points which provide additional
context around the issue. These are rendered below the summary. Defaults to None. context around the issue. These are rendered below the summary.
""" """
def __init__( def __init__(

View File

@@ -68,7 +68,7 @@ def _join_tokens(tokens: Iterable[Token], joiner: str = "") -> str:
Args: Args:
tokens: Tokens to join tokens: Tokens to join
joiner: String to join on, defaults to "" joiner: String to join on.
Returns: Returns:
The tokens, joined together to form a string. The tokens, joined together to form a string.

View File

@@ -72,6 +72,21 @@ class DOMQuery(Generic[QueryType]):
exclude: str | None = None, exclude: str | None = None,
parent: DOMQuery | None = None, parent: DOMQuery | None = None,
) -> None: ) -> None:
"""Initialize a query object.
!!! warning
You won't need to construct this manually, as `DOMQuery` objects are returned by [query][textual.dom.DOMNode.query].
Args:
node: A DOM node.
filter: Query to filter children in the node.
exclude: Query to exclude children in the node.
parent: The parent query, if this is the result of filtering another query.
Raises:
InvalidQueryFormat: If the format of the query is invalid.
"""
self._node = node self._node = node
self._nodes: list[QueryType] | None = None self._nodes: list[QueryType] | None = None
self._filters: list[tuple[SelectorSet, ...]] = ( self._filters: list[tuple[SelectorSet, ...]] = (
@@ -95,6 +110,7 @@ class DOMQuery(Generic[QueryType]):
@property @property
def node(self) -> DOMNode: def node(self) -> DOMNode:
"""The node being queried."""
return self._node return self._node
@property @property
@@ -193,7 +209,7 @@ class DOMQuery(Generic[QueryType]):
Args: Args:
expect_type: Require matched node is of this type, expect_type: Require matched node is of this type,
or None for any type. Defaults to None. or None for any type.
Raises: Raises:
WrongType: If the wrong type was found. WrongType: If the wrong type was found.
@@ -228,7 +244,7 @@ class DOMQuery(Generic[QueryType]):
Args: Args:
expect_type: Require matched node is of this type, expect_type: Require matched node is of this type,
or None for any type. Defaults to None. or None for any type.
Raises: Raises:
WrongType: If the wrong type was found. WrongType: If the wrong type was found.
@@ -272,7 +288,7 @@ class DOMQuery(Generic[QueryType]):
Args: Args:
expect_type: Require matched node is of this type, expect_type: Require matched node is of this type,
or None for any type. Defaults to None. or None for any type.
Raises: Raises:
WrongType: If the wrong type was found. WrongType: If the wrong type was found.
@@ -305,7 +321,7 @@ class DOMQuery(Generic[QueryType]):
Args: Args:
filter_type: A Widget class to filter results, filter_type: A Widget class to filter results,
or None for no filter. Defaults to None. or None for no filter.
Yields: Yields:
Iterator[Widget | ExpectType]: An iterator of Widget instances. Iterator[Widget | ExpectType]: An iterator of Widget instances.
@@ -383,7 +399,7 @@ class DOMQuery(Generic[QueryType]):
"""Set styles on matched nodes. """Set styles on matched nodes.
Args: Args:
css: CSS declarations to parser, or None. Defaults to None. css: CSS declarations to parser, or None.
""" """
_rich_traceback_omit = True _rich_traceback_omit = True
@@ -405,8 +421,8 @@ class DOMQuery(Generic[QueryType]):
"""Refresh matched nodes. """Refresh matched nodes.
Args: Args:
repaint: Repaint node(s). defaults to True. repaint: Repaint node(s).
layout: Layout node(s). Defaults to False. layout: Layout node(s).
Returns: Returns:
Query for chaining. Query for chaining.

View File

@@ -447,7 +447,7 @@ class StylesBase(ABC):
Args: Args:
rule: Name of rule. rule: Name of rule.
default: Default if rule does not exists. Defaults to None. default: Default if rule does not exists.
Returns: Returns:
Rule value or default. Rule value or default.
@@ -511,7 +511,7 @@ class StylesBase(ABC):
Args: Args:
css: Textual CSS. css: Textual CSS.
path: Path or string indicating source of CSS. path: Path or string indicating source of CSS.
node: Node to associate with the Styles. Defaults to None. node: Node to associate with the Styles.
Returns: Returns:
A Styles instance containing result of parsing CSS. A Styles instance containing result of parsing CSS.
@@ -1078,11 +1078,11 @@ class RenderStyles(StylesBase):
attribute: Name of the attribute to animate. attribute: Name of the attribute to animate.
value: The value to animate to. value: The value to animate to.
final_value: The final value of the animation. Defaults to `value` if not set. final_value: The final value of the animation. Defaults to `value` if not set.
duration: The duration of the animate. Defaults to None. duration: The duration of the animate.
speed: The speed of the animation. Defaults to None. speed: The speed of the animation.
delay: A delay (in seconds) before the animation starts. Defaults to 0.0. delay: A delay (in seconds) before the animation starts.
easing: An easing method. Defaults to "in_out_cubic". easing: An easing method.
on_complete: A callable to invoke when the animation is finished. Defaults to None. on_complete: A callable to invoke when the animation is finished.
""" """
if self._animate is None: if self._animate is None:

View File

@@ -275,7 +275,6 @@ class Stylesheet:
Args: Args:
css: String with CSS source. css: String with CSS source.
path: The path of the source if a file, or some other identifier. path: The path of the source if a file, or some other identifier.
Defaults to None.
is_default_css: True if the CSS is defined in the Widget, False if the CSS is defined is_default_css: True if the CSS is defined in the Widget, False if the CSS is defined
in a user stylesheet. in a user stylesheet.
tie_breaker: Integer representing the priority of this source. tie_breaker: Integer representing the priority of this source.
@@ -365,12 +364,12 @@ class Stylesheet:
"""Apply the stylesheet to a DOM node. """Apply the stylesheet to a DOM node.
Args: Args:
node: The ``DOMNode`` to apply the stylesheet to. node: The `DOMNode` to apply the stylesheet to.
Applies the styles defined in this ``Stylesheet`` to the node. Applies the styles defined in this `Stylesheet` to the node.
If the same rule is defined multiple times for the node (e.g. multiple If the same rule is defined multiple times for the node (e.g. multiple
classes modifying the same CSS property), then only the most specific classes modifying the same CSS property), then only the most specific
rule will be applied. rule will be applied.
animate: Animate changed rules. Defaults to ``False``. animate: Animate changed rules.
""" """
# Dictionary of rule attribute names e.g. "text_background" to list of tuples. # Dictionary of rule attribute names e.g. "text_background" to list of tuples.
# The tuples contain the rule specificity, and the value for that rule. # The tuples contain the rule specificity, and the value for that rule.
@@ -447,7 +446,7 @@ class Stylesheet:
Args: Args:
node: A DOM node. node: A DOM node.
rules: Mapping of rules. rules: Mapping of rules.
animate: Enable animation. Defaults to False. animate: Enable animation.
""" """
# Alias styles and base styles # Alias styles and base styles
@@ -519,7 +518,7 @@ class Stylesheet:
Args: Args:
root: Root note to update. root: Root note to update.
animate: Enable CSS animation. Defaults to False. animate: Enable CSS animation.
""" """
self.update_nodes(root.walk_children(with_self=True), animate=animate) self.update_nodes(root.walk_children(with_self=True), animate=animate)
@@ -529,7 +528,7 @@ class Stylesheet:
Args: Args:
nodes: Nodes to update. nodes: Nodes to update.
animate: Enable CSS animation. Defaults to False. animate: Enable CSS animation.
""" """
rules_map = self.rules_map rules_map = self.rules_map

View File

@@ -32,7 +32,7 @@ class TokenError(Exception):
code: The code being parsed. code: The code being parsed.
start: Line number of the error. start: Line number of the error.
message: A message associated with the error. message: A message associated with the error.
end: End location of token, or None if not known. Defaults to None. end: End location of token, or None if not known.
""" """
self.path = path self.path = path

View File

@@ -410,8 +410,8 @@ class DemoApp(App[None]):
"""Save an SVG "screenshot". This action will save an SVG file containing the current contents of the screen. """Save an SVG "screenshot". This action will save an SVG file containing the current contents of the screen.
Args: Args:
filename: Filename of screenshot, or None to auto-generate. Defaults to None. filename: Filename of screenshot, or None to auto-generate.
path: Path to directory. Defaults to "./". path: Path to directory.
""" """
self.bell() self.bell()
path = self.save_screenshot(filename, path) path = self.save_screenshot(filename, path)

View File

@@ -94,12 +94,6 @@ class ColorSystem:
def generate(self) -> dict[str, str]: def generate(self) -> dict[str, str]:
"""Generate a mapping of color name on to a CSS color. """Generate a mapping of color name on to a CSS color.
Args:
dark: Enable dark mode. Defaults to False.
luminosity_spread: Amount of luminosity to subtract and add to generate
shades. Defaults to 0.2.
text_alpha: Alpha value for text. Defaults to 0.9.
Returns: Returns:
A mapping of color name on to a CSS-style encoded color A mapping of color name on to a CSS-style encoded color

View File

@@ -1,3 +1,12 @@
"""
A DOMNode is a base class for any object within the Textual Document Object Model,
which includes all Widgets, Screens, and Apps.
"""
from __future__ import annotations from __future__ import annotations
import re import re
@@ -25,7 +34,7 @@ from ._context import NoActiveAppError
from ._node_list import NodeList from ._node_list import NodeList
from ._types import WatchCallbackType from ._types import WatchCallbackType
from ._worker_manager import WorkerManager from ._worker_manager import WorkerManager
from .binding import Binding, Bindings, BindingType from .binding import Binding, BindingType, _Bindings
from .color import BLACK, WHITE, Color from .color import BLACK, WHITE, Color
from .css._error_tools import friendly_list from .css._error_tools import friendly_list
from .css.constants import VALID_DISPLAY, VALID_VISIBILITY from .css.constants import VALID_DISPLAY, VALID_VISIBILITY
@@ -134,7 +143,7 @@ class DOMNode(MessagePump):
_css_type_names: ClassVar[frozenset[str]] = frozenset() _css_type_names: ClassVar[frozenset[str]] = frozenset()
# Generated list of bindings # Generated list of bindings
_merged_bindings: ClassVar[Bindings | None] = None _merged_bindings: ClassVar[_Bindings | None] = None
_reactives: ClassVar[dict[str, Reactive]] _reactives: ClassVar[dict[str, Reactive]]
@@ -168,7 +177,7 @@ class DOMNode(MessagePump):
self._auto_refresh_timer: Timer | None = None self._auto_refresh_timer: Timer | None = None
self._css_types = {cls.__name__ for cls in self._css_bases(self.__class__)} self._css_types = {cls.__name__ for cls in self._css_bases(self.__class__)}
self._bindings = ( self._bindings = (
Bindings() _Bindings()
if self._merged_bindings is None if self._merged_bindings is None
else self._merged_bindings.copy() else self._merged_bindings.copy()
) )
@@ -191,7 +200,12 @@ class DOMNode(MessagePump):
@property @property
def children(self) -> Sequence["Widget"]: def children(self) -> Sequence["Widget"]:
"""A view on to the children.""" """A view on to the children.
Returns:
The node's children.
"""
return self._nodes return self._nodes
@property @property
@@ -212,7 +226,7 @@ class DOMNode(MessagePump):
@property @property
def workers(self) -> WorkerManager: def workers(self) -> WorkerManager:
"""A worker manager.""" """The app's worker manager. Shortcut for `self.app.workers`."""
return self.app.workers return self.app.workers
def run_worker( def run_worker(
@@ -346,27 +360,27 @@ class DOMNode(MessagePump):
return classes return classes
@classmethod @classmethod
def _merge_bindings(cls) -> Bindings: def _merge_bindings(cls) -> _Bindings:
"""Merge bindings from base classes. """Merge bindings from base classes.
Returns: Returns:
Merged bindings. Merged bindings.
""" """
bindings: list[Bindings] = [] bindings: list[_Bindings] = []
for base in reversed(cls.__mro__): for base in reversed(cls.__mro__):
if issubclass(base, DOMNode): if issubclass(base, DOMNode):
if not base._inherit_bindings: if not base._inherit_bindings:
bindings.clear() bindings.clear()
bindings.append( bindings.append(
Bindings( _Bindings(
base.__dict__.get("BINDINGS", []), base.__dict__.get("BINDINGS", []),
) )
) )
keys: dict[str, Binding] = {} keys: dict[str, Binding] = {}
for bindings_ in bindings: for bindings_ in bindings:
keys.update(bindings_.keys) keys.update(bindings_.keys)
return Bindings(keys.values()) return _Bindings(keys.values())
def _post_register(self, app: App) -> None: def _post_register(self, app: App) -> None:
"""Called when the widget is registered """Called when the widget is registered
@@ -503,6 +517,7 @@ class DOMNode(MessagePump):
return tokens return tokens
classes = _ClassesDescriptor() classes = _ClassesDescriptor()
"""CSS class names for this node."""
@property @property
def pseudo_classes(self) -> frozenset[str]: def pseudo_classes(self) -> frozenset[str]:
@@ -584,9 +599,15 @@ class DOMNode(MessagePump):
@property @property
def tree(self) -> Tree: def tree(self) -> Tree:
"""Get a Rich tree object which will recursively render the structure of the node tree.""" """Get a Rich tree object which will recursively render the structure of the node tree.
Returns:
A Rich Tree renderable.
"""
def render_info(node: DOMNode) -> Pretty: def render_info(node: DOMNode) -> Pretty:
"""Render a node for the tree."""
return Pretty(node) return Pretty(node)
tree = Tree(render_info(self)) tree = Tree(render_info(self))
@@ -605,6 +626,9 @@ class DOMNode(MessagePump):
def css_tree(self) -> Tree: def css_tree(self) -> Tree:
"""Get a Rich tree object which will recursively render the structure of the node tree, """Get a Rich tree object which will recursively render the structure of the node tree,
which also displays CSS and size information. which also displays CSS and size information.
Returns:
A Rich Tree renderable.
""" """
from rich.columns import Columns from rich.columns import Columns
from rich.console import Group from rich.console import Group
@@ -613,6 +637,7 @@ class DOMNode(MessagePump):
from .widget import Widget from .widget import Widget
def render_info(node: DOMNode) -> Columns: def render_info(node: DOMNode) -> Columns:
"""Render a node for the tree."""
if isinstance(node, Widget): if isinstance(node, Widget):
info = Columns( info = Columns(
[ [
@@ -659,7 +684,7 @@ class DOMNode(MessagePump):
the child will also be bold. the child will also be bold.
Returns: Returns:
Rich Style object. A Rich Style.
""" """
return Style.combine( return Style.combine(
node.styles.text_style for node in reversed(self.ancestors_with_self) node.styles.text_style for node in reversed(self.ancestors_with_self)
@@ -667,7 +692,12 @@ class DOMNode(MessagePump):
@property @property
def rich_style(self) -> Style: def rich_style(self) -> Style:
"""Get a Rich Style object for this DOMNode.""" """Get a Rich Style object for this DOMNode.
Returns:
A Rich style.
"""
background = Color(0, 0, 0, 0) background = Color(0, 0, 0, 0)
color = Color(255, 255, 255, 0) color = Color(255, 255, 255, 0)
style = Style() style = Style()
@@ -720,6 +750,9 @@ class DOMNode(MessagePump):
Note: Note:
This is inclusive of ``self``. This is inclusive of ``self``.
Returns:
A list of nodes.
""" """
nodes: list[MessagePump | None] = [] nodes: list[MessagePump | None] = []
add_node = nodes.append add_node = nodes.append
@@ -731,12 +764,22 @@ class DOMNode(MessagePump):
@property @property
def ancestors(self) -> list[DOMNode]: def ancestors(self) -> list[DOMNode]:
"""A list of ancestor nodes Nodes by tracing ancestors all the way back to App.""" """A list of ancestor nodes Nodes by tracing ancestors all the way back to App.
Returns:
A list of nodes.
"""
return self.ancestors_with_self[1:] return self.ancestors_with_self[1:]
@property @property
def displayed_children(self) -> list[Widget]: def displayed_children(self) -> list[Widget]:
"""The children which don't have display: none set.""" """The children which don't have display: none set.
Returns:
A list of nodes.
"""
return [child for child in self._nodes if child.display] return [child for child in self._nodes if child.display]
def watch( def watch(
@@ -829,10 +872,9 @@ class DOMNode(MessagePump):
Args: Args:
filter_type: Filter only this type, or None for no filter. filter_type: Filter only this type, or None for no filter.
Defaults to None. with_self: Also yield self in addition to descendants.
with_self: Also yield self in addition to descendants. Defaults to False. method: One of "depth" or "breadth".
method: One of "depth" or "breadth". Defaults to "depth". reverse: Reverse the order (bottom up).
reverse: Reverse the order (bottom up). Defaults to False.
Returns: Returns:
A list of nodes. A list of nodes.
@@ -867,7 +909,7 @@ class DOMNode(MessagePump):
"""Get a DOM query matching a selector. """Get a DOM query matching a selector.
Args: Args:
selector: A CSS selector or `None` for all nodes. Defaults to None. selector: A CSS selector or `None` for all nodes.
Returns: Returns:
A query object. A query object.
@@ -902,7 +944,6 @@ class DOMNode(MessagePump):
Args: Args:
selector: A selector. selector: A selector.
expect_type: Require the object be of the supplied type, or None for any type. expect_type: Require the object be of the supplied type, or None for any type.
Defaults to None.
Raises: Raises:
WrongType: If the wrong type was found. WrongType: If the wrong type was found.

View File

@@ -1,3 +1,17 @@
"""
Builtin events sent by Textual.
Events may be marked as "Bubbles" and "Verbose".
See the [events guide](/guide/events/#bubbling) for an explanation of bubbling.
Verbose events are excluded from the textual console, unless you explicit request them with the `-v` switch as follows:
```
textual console -v
```
"""
from __future__ import annotations from __future__ import annotations
from typing import TYPE_CHECKING, Type, TypeVar from typing import TYPE_CHECKING, Type, TypeVar
@@ -37,7 +51,12 @@ class Callback(Event, bubble=False, verbose=True):
class InvokeCallbacks(Event, bubble=False, verbose=True): class InvokeCallbacks(Event, bubble=False, verbose=True):
"""Sent after the Screen is updated""" """An internal event, sent to the screen to run callbacks.
- [ ] Bubbles
- [X] Verbose
"""
class ShutdownRequest(Event): class ShutdownRequest(Event):
@@ -55,6 +74,8 @@ class Load(Event, bubble=False):
Use this event to run any set up that doesn't require any visuals such as loading Use this event to run any set up that doesn't require any visuals such as loading
configuration and binding keys. configuration and binding keys.
- [ ] Bubbles
- [ ] Verbose
""" """
@@ -65,6 +86,9 @@ class Idle(Event, bubble=False):
This is a pseudo-event in that it is created by the Textual system and doesn't go This is a pseudo-event in that it is created by the Textual system and doesn't go
through the usual message queue. through the usual message queue.
- [ ] Bubbles
- [ ] Verbose
""" """
@@ -81,10 +105,14 @@ class Action(Event):
class Resize(Event, bubble=False): class Resize(Event, bubble=False):
"""Sent when the app or widget has been resized. """Sent when the app or widget has been resized.
- [ ] Bubbles
- [ ] Verbose
Args: Args:
size: The new size of the Widget. size: The new size of the Widget.
virtual_size: The virtual size (scrollable size) of the Widget. virtual_size: The virtual size (scrollable size) of the Widget.
container_size: The size of the Widget's container widget. Defaults to None. container_size: The size of the Widget's container widget.
""" """
@@ -111,24 +139,47 @@ class Resize(Event, bubble=False):
class Compose(Event, bubble=False, verbose=True): class Compose(Event, bubble=False, verbose=True):
"""Sent to a widget to request it to compose and mount children.""" """Sent to a widget to request it to compose and mount children.
- [ ] Bubbles
- [X] Verbose
"""
class Mount(Event, bubble=False, verbose=False): class Mount(Event, bubble=False, verbose=False):
"""Sent when a widget is *mounted* and may receive messages.""" """Sent when a widget is *mounted* and may receive messages.
- [ ] Bubbles
- [ ] Verbose
"""
class Unmount(Mount, bubble=False, verbose=False): class Unmount(Mount, bubble=False, verbose=False):
"""Sent when a widget is unmounted and may not longer receive messages.""" """Sent when a widget is unmounted and may not longer receive messages.
- [ ] Bubbles
- [ ] Verbose
"""
class Show(Event, bubble=False): class Show(Event, bubble=False):
"""Sent when a widget has become visible.""" """Sent when a widget has become visible.
- [ ] Bubbles
- [ ] Verbose
"""
class Hide(Event, bubble=False): class Hide(Event, bubble=False):
"""Sent when a widget has been hidden. """Sent when a widget has been hidden.
- [ ] Bubbles
- [ ] Verbose
A widget may be hidden by setting its `visible` flag to `False`, if it is no longer in a layout, A widget may be hidden by setting its `visible` flag to `False`, if it is no longer in a layout,
or if it has been offset beyond the edges of the terminal. or if it has been offset beyond the edges of the terminal.
@@ -136,15 +187,22 @@ class Hide(Event, bubble=False):
class Ready(Event, bubble=False): class Ready(Event, bubble=False):
"""Sent to the app when the DOM is ready.""" """Sent to the app when the DOM is ready.
- [ ] Bubbles
- [ ] Verbose
"""
@rich.repr.auto @rich.repr.auto
class MouseCapture(Event, bubble=False): class MouseCapture(Event, bubble=False):
"""Sent when the mouse has been captured. """Sent when the mouse has been captured.
When a mouse has been captured, all further mouse events will be sent to the capturing widget. - [ ] Bubbles
- [ ] Verbose
When a mouse has been captured, all further mouse events will be sent to the capturing widget.
Args: Args:
mouse_position: The position of the mouse when captured. mouse_position: The position of the mouse when captured.
@@ -163,6 +221,9 @@ class MouseCapture(Event, bubble=False):
class MouseRelease(Event, bubble=False): class MouseRelease(Event, bubble=False):
"""Mouse has been released. """Mouse has been released.
- [ ] Bubbles
- [ ] Verbose
Args: Args:
mouse_position: The position of the mouse when released. mouse_position: The position of the mouse when released.
""" """
@@ -183,6 +244,9 @@ class InputEvent(Event):
class Key(InputEvent): class Key(InputEvent):
"""Sent when the user hits a key on the keyboard. """Sent when the user hits a key on the keyboard.
- [X] Bubbles
- [ ] Verbose
Args: Args:
key: The key that was pressed. key: The key that was pressed.
character: A printable character or ``None`` if it is not printable. character: A printable character or ``None`` if it is not printable.
@@ -239,6 +303,9 @@ def _key_to_identifier(key: str) -> str:
class MouseEvent(InputEvent, bubble=True): class MouseEvent(InputEvent, bubble=True):
"""Sent in response to a mouse event. """Sent in response to a mouse event.
- [X] Bubbles
- [ ] Verbose
Args: Args:
x: The relative x coordinate. x: The relative x coordinate.
y: The relative y coordinate. y: The relative y coordinate.
@@ -395,35 +462,73 @@ class MouseEvent(InputEvent, bubble=True):
@rich.repr.auto @rich.repr.auto
class MouseMove(MouseEvent, bubble=False, verbose=True): class MouseMove(MouseEvent, bubble=False, verbose=True):
"""Sent when the mouse cursor moves.""" """Sent when the mouse cursor moves.
- [ ] Bubbles
- [X] Verbose
"""
@rich.repr.auto @rich.repr.auto
class MouseDown(MouseEvent, bubble=True, verbose=True): class MouseDown(MouseEvent, bubble=True, verbose=True):
pass """Sent when a mouse button is pressed.
- [X] Bubbles
- [X] Verbose
"""
@rich.repr.auto @rich.repr.auto
class MouseUp(MouseEvent, bubble=True, verbose=True): class MouseUp(MouseEvent, bubble=True, verbose=True):
pass """Sent when a mouse button is released.
- [X] Bubbles
- [X] Verbose
"""
@rich.repr.auto @rich.repr.auto
class MouseScrollDown(MouseEvent, bubble=True): class MouseScrollDown(MouseEvent, bubble=True):
pass """Sent when the mouse wheel is scrolled *down*.
- [X] Bubbles
- [ ] Verbose
"""
@rich.repr.auto @rich.repr.auto
class MouseScrollUp(MouseEvent, bubble=True): class MouseScrollUp(MouseEvent, bubble=True):
pass """Sent when the mouse wheel is scrolled *up*.
- [X] Bubbles
- [ ] Verbose
"""
class Click(MouseEvent, bubble=True): class Click(MouseEvent, bubble=True):
pass """Sent when a widget is clicked.
- [X] Bubbles
- [ ] Verbose
"""
@rich.repr.auto @rich.repr.auto
class Timer(Event, bubble=False, verbose=True): class Timer(Event, bubble=False, verbose=True):
"""Sent in response to a timer.
- [ ] Bubbles
- [X] Verbose
"""
__slots__ = ["time", "count", "callback"] __slots__ = ["time", "count", "callback"]
def __init__( def __init__(
@@ -445,27 +550,57 @@ class Timer(Event, bubble=False, verbose=True):
class Enter(Event, bubble=False, verbose=True): class Enter(Event, bubble=False, verbose=True):
pass """Sent when the mouse is moved over a widget.
- [ ] Bubbles
- [X] Verbose
"""
class Leave(Event, bubble=False, verbose=True): class Leave(Event, bubble=False, verbose=True):
pass """Sent when the mouse is moved away from a widget.
- [ ] Bubbles
- [X] Verbose
"""
class Focus(Event, bubble=False): class Focus(Event, bubble=False):
pass """Sent when a widget is focussed.
- [X] Bubbles
- [ ] Verbose
"""
class Blur(Event, bubble=False): class Blur(Event, bubble=False):
pass """Sent when a widget is blurred (un-focussed).
- [X] Bubbles
- [ ] Verbose
"""
class DescendantFocus(Event, bubble=True, verbose=True): class DescendantFocus(Event, bubble=True, verbose=True):
pass """Sent when a child widget is focussed.
- [X] Bubbles
- [X] Verbose
"""
class DescendantBlur(Event, bubble=True, verbose=True): class DescendantBlur(Event, bubble=True, verbose=True):
pass """Sent when a child widget is blurred.
- [X] Bubbles
- [X] Verbose
"""
@rich.repr.auto @rich.repr.auto
@@ -475,6 +610,10 @@ class Paste(Event, bubble=True):
bracketed paste mode. Textual will enable bracketed pastes when an app starts, bracketed paste mode. Textual will enable bracketed pastes when an app starts,
and disable it when the app shuts down. and disable it when the app shuts down.
- [X] Bubbles
- [ ] Verbose
Args: Args:
text: The text that has been pasted. text: The text that has been pasted.
""" """
@@ -488,8 +627,18 @@ class Paste(Event, bubble=True):
class ScreenResume(Event, bubble=False): class ScreenResume(Event, bubble=False):
pass """Sent to screen that has been made active.
- [ ] Bubbles
- [ ] Verbose
"""
class ScreenSuspend(Event, bubble=False): class ScreenSuspend(Event, bubble=False):
pass """Sent to screen when it is no longer active.
- [ ] Bubbles
- [ ] Verbose
"""

View File

@@ -19,6 +19,8 @@ from typing import (
cast, cast,
) )
from typing_extensions import Final
if TYPE_CHECKING: if TYPE_CHECKING:
from typing_extensions import TypeAlias from typing_extensions import TypeAlias
@@ -31,7 +33,7 @@ T = TypeVar("T", int, float)
def clamp(value: T, minimum: T, maximum: T) -> T: def clamp(value: T, minimum: T, maximum: T) -> T:
"""Adjust a value to it is not less than a minimum and not greater """Adjust a value so it is not less than a minimum and not greater
than a maximum value. than a maximum value.
Args: Args:
@@ -53,8 +55,9 @@ def clamp(value: T, minimum: T, maximum: T) -> T:
class Offset(NamedTuple): class Offset(NamedTuple):
"""A cell offset defined by x and y coordinates. Offsets are typically relative to the """A cell offset defined by x and y coordinates.
top left of the terminal or other container.
Offsets are typically relative to the top left of the terminal or other container.
Textual prefers the names `x` and `y`, but you could consider `x` to be the _column_ and `y` to be the _row_. Textual prefers the names `x` and `y`, but you could consider `x` to be the _column_ and `y` to be the _row_.
@@ -67,21 +70,12 @@ class Offset(NamedTuple):
@property @property
def is_origin(self) -> bool: def is_origin(self) -> bool:
"""Check if the point is at the origin (0, 0). """Is the offset at (0, 0)?"""
Returns:
True if the offset is the origin.
"""
return self == (0, 0) return self == (0, 0)
@property @property
def clamped(self) -> Offset: def clamped(self) -> Offset:
"""Ensure x and y are above zero. """This offset with `x` and `y` restricted to values above zero."""
Returns:
New offset.
"""
x, y = self x, y = self
return Offset(0 if x < 0 else x, 0 if y < 0 else y) return Offset(0 if x < 0 else x, 0 if y < 0 else y)
@@ -113,7 +107,7 @@ class Offset(NamedTuple):
return Offset(-x, -y) return Offset(-x, -y)
def blend(self, destination: Offset, factor: float) -> Offset: def blend(self, destination: Offset, factor: float) -> Offset:
"""Blend (interpolate) to a new point. """Calculate a new offset on a line between this offset and a destination offset.
Args: Args:
destination: Point where factor would be 1.0. destination: Point where factor would be 1.0.
@@ -159,31 +153,18 @@ class Size(NamedTuple):
@property @property
def area(self) -> int: def area(self) -> int:
"""Get the area of the size. """The area occupied by a region of this size."""
Returns:
Area in cells.
"""
return self.width * self.height return self.width * self.height
@property @property
def region(self) -> Region: def region(self) -> Region:
"""Get a region of the same size. """A region of the same size, at the origin."""
Returns:
A region with the same size at (0, 0).
"""
width, height = self width, height = self
return Region(0, 0, width, height) return Region(0, 0, width, height)
@property @property
def line_range(self) -> range: def line_range(self) -> range:
"""Get a range covering lines. """A range object that covers values between 0 and `height`."""
Returns:
A builtin range object.
"""
return range(self.height) return range(self.height)
def __add__(self, other: object) -> Size: def __add__(self, other: object) -> Size:
@@ -327,7 +308,7 @@ class Region(NamedTuple):
Args: Args:
window_region: The window region. window_region: The window region.
region: The region to move inside the window. region: The region to move inside the window.
top: Get offset to top of window. Defaults to False top: Get offset to top of window.
Returns: Returns:
An offset required to add to region to move it inside window_region. An offset required to add to region to move it inside window_region.
@@ -376,64 +357,43 @@ class Region(NamedTuple):
@property @property
def column_span(self) -> tuple[int, int]: def column_span(self) -> tuple[int, int]:
"""Get the start and end columns (x coord). """A pair of integers for the start and end columns (x coordinates) in this region.
The end value is exclusive. The end value is *exclusive*.
Returns:
Pair of x coordinates (column numbers).
""" """
return (self.x, self.x + self.width) return (self.x, self.x + self.width)
@property @property
def line_span(self) -> tuple[int, int]: def line_span(self) -> tuple[int, int]:
"""Get the start and end line number (y coord). """A pair of integers for the start and end lines (y coordinates) in this region.
The end value is exclusive. The end value is *exclusive*.
Returns:
Pair of y coordinates (line numbers).
""" """
return (self.y, self.y + self.height) return (self.y, self.y + self.height)
@property @property
def right(self) -> int: def right(self) -> int:
"""Maximum X value (non inclusive). """Maximum X value (non inclusive)."""
Returns:
x coordinate.
"""
return self.x + self.width return self.x + self.width
@property @property
def bottom(self) -> int: def bottom(self) -> int:
"""Maximum Y value (non inclusive). """Maximum Y value (non inclusive)."""
Returns:
y coordinate.
"""
return self.y + self.height return self.y + self.height
@property @property
def area(self) -> int: def area(self) -> int:
"""Get the area within the region. """The are under the region."""
Returns:
Area covered by this region.
"""
return self.width * self.height return self.width * self.height
@property @property
def offset(self) -> Offset: def offset(self) -> Offset:
"""Get the start point of the region. """The top left corner of the region.
Returns: Returns:
Top left offset. An offset.
""" """
return Offset(*self[:2]) return Offset(*self[:2])
@@ -443,8 +403,7 @@ class Region(NamedTuple):
"""Bottom left offset of the region. """Bottom left offset of the region.
Returns: Returns:
Bottom left offset. An offset.
""" """
x, y, _width, height = self x, y, _width, height = self
return Offset(x, y + height) return Offset(x, y + height)
@@ -454,7 +413,7 @@ class Region(NamedTuple):
"""Top right offset of the region. """Top right offset of the region.
Returns: Returns:
Top right. An offset.
""" """
x, y, width, _height = self x, y, width, _height = self
@@ -462,10 +421,10 @@ class Region(NamedTuple):
@property @property
def bottom_right(self) -> Offset: def bottom_right(self) -> Offset:
"""Bottom right of the region. """Bottom right offset of the region.
Returns: Returns:
Bottom right. An offset.
""" """
x, y, width, height = self x, y, width, height = self
@@ -473,21 +432,12 @@ class Region(NamedTuple):
@property @property
def size(self) -> Size: def size(self) -> Size:
"""Get the size of the region. """Get the size of the region."""
Returns:
Size of the region.
"""
return Size(*self[2:]) return Size(*self[2:])
@property @property
def corners(self) -> tuple[int, int, int, int]: def corners(self) -> tuple[int, int, int, int]:
"""Get the top left and bottom right coordinates as a tuple of integers. """The top left and bottom right coordinates as a tuple of four integers."""
Returns:
A tuple of `(<left>, <top>, <right>, <bottom>)`.
"""
x, y, width, height = self x, y, width, height = self
return x, y, x + width, y + height return x, y, x + width, y + height
@@ -506,7 +456,7 @@ class Region(NamedTuple):
"""An region of the same size at (0, 0). """An region of the same size at (0, 0).
Returns: Returns:
Reset region. A region at the origin.
""" """
_, _, width, height = self _, _, width, height = self
@@ -897,63 +847,35 @@ class Spacing(NamedTuple):
@property @property
def width(self) -> int: def width(self) -> int:
"""Total space in width. """Total space in the x axis."""
Returns:
Width.
"""
return self.left + self.right return self.left + self.right
@property @property
def height(self) -> int: def height(self) -> int:
"""Total space in height. """Total space in the y axis."""
Returns:
Height.
"""
return self.top + self.bottom return self.top + self.bottom
@property @property
def top_left(self) -> tuple[int, int]: def top_left(self) -> tuple[int, int]:
"""Top left space. """A pair of integers for the left, and top space."""
Returns:
`(<left>, <top>)`
"""
return (self.left, self.top) return (self.left, self.top)
@property @property
def bottom_right(self) -> tuple[int, int]: def bottom_right(self) -> tuple[int, int]:
"""Bottom right space. """A pair of integers for the right, and bottom space."""
Returns:
`(<right>, <bottom>)`
"""
return (self.right, self.bottom) return (self.right, self.bottom)
@property @property
def totals(self) -> tuple[int, int]: def totals(self) -> tuple[int, int]:
"""Get total horizontal and vertical space. """A pair of integers for the total horizontal and vertical space."""
Returns:
`(<horizontal>, <vertical>)`
"""
top, right, bottom, left = self top, right, bottom, left = self
return (left + right, top + bottom) return (left + right, top + bottom)
@property @property
def css(self) -> str: def css(self) -> str:
"""Gets a string containing the spacing in CSS format. """A string containing the spacing in CSS format.
Returns:
Spacing in CSS format.
For example: "1" or "2 4" or "4 2 8 2".
""" """
top, right, bottom, left = self top, right, bottom, left = self
if top == right == bottom == left: if top == right == bottom == left:
@@ -1067,4 +989,5 @@ class Spacing(NamedTuple):
) )
NULL_OFFSET = Offset(0, 0) NULL_OFFSET: Final = Offset(0, 0)
"""An Offset constant for (0, 0)."""

View File

@@ -1,3 +1,13 @@
"""
A Textual Logging handler.
If there is an active Textual app, then log messages will go via the app (and logged via textual console).
If there is *no* active app, then log messages will go to stderr or stdout, depending on configuration.
"""
import sys import sys
from logging import Handler, LogRecord from logging import Handler, LogRecord

View File

@@ -1,3 +1,10 @@
"""
The base class for all messages (including events).
"""
from __future__ import annotations from __future__ import annotations
from typing import TYPE_CHECKING, ClassVar from typing import TYPE_CHECKING, ClassVar
@@ -99,7 +106,7 @@ class Message:
Args: Args:
prevent: True if the default action should be suppressed, prevent: True if the default action should be suppressed,
or False if the default actions should be performed. Defaults to True. or False if the default actions should be performed.
""" """
self._no_default_action = prevent self._no_default_action = prevent
return self return self
@@ -108,7 +115,7 @@ class Message:
"""Stop propagation of the message to parent. """Stop propagation of the message to parent.
Args: Args:
stop: The stop flag. Defaults to True. stop: The stop flag.
""" """
self._stop_propagation = stop self._stop_propagation = stop
return self return self

View File

@@ -1,8 +1,6 @@
""" """
A message pump is a class that processes messages. A message pump is a base class for any object which processes messages, which includes Widget, Screen, and App.
It is a base class for the App, Screen, and Widgets.
""" """
from __future__ import annotations from __future__ import annotations
@@ -46,7 +44,7 @@ class MessagePumpClosed(Exception):
pass pass
class MessagePumpMeta(type): class _MessagePumpMeta(type):
"""Metaclass for message pump. This exists to populate a Message inner class of a Widget with the """Metaclass for message pump. This exists to populate a Message inner class of a Widget with the
parent classes' name. parent classes' name.
@@ -69,7 +67,7 @@ class MessagePumpMeta(type):
return class_obj return class_obj
class MessagePump(metaclass=MessagePumpMeta): class MessagePump(metaclass=_MessagePumpMeta):
"""Base class which supplies a message pump.""" """Base class which supplies a message pump."""
def __init__(self, parent: MessagePump | None = None) -> None: def __init__(self, parent: MessagePump | None = None) -> None:
@@ -143,6 +141,7 @@ class MessagePump(metaclass=MessagePumpMeta):
@property @property
def has_parent(self) -> bool: def has_parent(self) -> bool:
"""Does this object have a parent?"""
return self._parent is not None return self._parent is not None
@property @property
@@ -178,7 +177,7 @@ class MessagePump(metaclass=MessagePumpMeta):
@property @property
def is_running(self) -> bool: def is_running(self) -> bool:
"""Is the message pump running (potentially processing messages).""" """Is the message pump running (potentially processing messages)?"""
return self._running return self._running
@property @property
@@ -192,7 +191,7 @@ class MessagePump(metaclass=MessagePumpMeta):
@property @property
def is_attached(self) -> bool: def is_attached(self) -> bool:
"""Is the node is attached to the app via the DOM.""" """Is the node is attached to the app via the DOM?"""
from .app import App from .app import App
node = self node = self
@@ -289,9 +288,9 @@ class MessagePump(metaclass=MessagePumpMeta):
Args: Args:
delay: Time to wait before invoking callback. delay: Time to wait before invoking callback.
callback: Callback to call after time has expired. Defaults to None. callback: Callback to call after time has expired.
name: Name of the timer (for debug). Defaults to None. name: Name of the timer (for debug).
pause: Start timer paused. Defaults to False. pause: Start timer paused.
Returns: Returns:
A timer object. A timer object.
@@ -321,10 +320,10 @@ class MessagePump(metaclass=MessagePumpMeta):
Args: Args:
interval: Time between calls. interval: Time between calls.
callback: Function to call. Defaults to None. callback: Function to call.
name: Name of the timer object. Defaults to None. name: Name of the timer object.
repeat: Number of times to repeat the call or 0 for continuous. Defaults to 0. repeat: Number of times to repeat the call or 0 for continuous.
pause: Start the timer paused. Defaults to False. pause: Start the timer paused.
Returns: Returns:
A timer object. A timer object.

View File

@@ -1,3 +1,9 @@
"""
The pilot object is used by [App.run_test][textual.app.App.run_test] to programmatically operate an app.
"""
from __future__ import annotations from __future__ import annotations
import asyncio import asyncio

View File

@@ -1,3 +1,9 @@
"""
The `Reactive` class implements [reactivity](/guide/reactivity/).
"""
from __future__ import annotations from __future__ import annotations
from functools import partial from functools import partial
@@ -33,11 +39,11 @@ class Reactive(Generic[ReactiveType]):
Args: Args:
default: A default value or callable that returns a default. default: A default value or callable that returns a default.
layout: Perform a layout on change. Defaults to False. layout: Perform a layout on change.
repaint: Perform a repaint on change. Defaults to True. repaint: Perform a repaint on change.
init: Call watchers on initialize (post mount). Defaults to False. init: Call watchers on initialize (post mount).
always_update: Call watchers even when the new value equals the old value. Defaults to False. always_update: Call watchers even when the new value equals the old value.
compute: Run compute methods when attribute is changed. Defaults to True. compute: Run compute methods when attribute is changed.
""" """
_reactives: ClassVar[dict[str, object]] = {} _reactives: ClassVar[dict[str, object]] = {}
@@ -280,10 +286,10 @@ class reactive(Reactive[ReactiveType]):
Args: Args:
default: A default value or callable that returns a default. default: A default value or callable that returns a default.
layout: Perform a layout on change. Defaults to False. layout: Perform a layout on change.
repaint: Perform a repaint on change. Defaults to True. repaint: Perform a repaint on change.
init: Call watchers on initialize (post mount). Defaults to True. init: Call watchers on initialize (post mount).
always_update: Call watchers even when the new value equals the old value. Defaults to False. always_update: Call watchers even when the new value equals the old value.
""" """
def __init__( def __init__(
@@ -309,7 +315,7 @@ class var(Reactive[ReactiveType]):
Args: Args:
default: A default value or callable that returns a default. default: A default value or callable that returns a default.
init: Call watchers on initialize (post mount). Defaults to True. init: Call watchers on initialize (post mount).
""" """
def __init__( def __init__(
@@ -339,7 +345,7 @@ def _watch(
obj: The parent object. obj: The parent object.
attribute_name: The attribute to watch. attribute_name: The attribute to watch.
callback: A callable to call when the attribute changes. callback: A callable to call when the attribute changes.
init: True to call watcher initialization. Defaults to True. init: True to call watcher initialization.
""" """
if not hasattr(obj, "__watchers"): if not hasattr(obj, "__watchers"):
setattr(obj, "__watchers", {}) setattr(obj, "__watchers", {})

View File

@@ -9,7 +9,7 @@ class UnderlineBar:
"""Thin horizontal bar with a portion highlighted. """Thin horizontal bar with a portion highlighted.
Args: Args:
highlight_range: The range to highlight. Defaults to ``(0, 0)`` (no highlight) highlight_range: The range to highlight.
highlight_style: The style of the highlighted range of the bar. highlight_style: The style of the highlighted range of the bar.
background_style: The style of the non-highlighted range(s) of the bar. background_style: The style of the non-highlighted range(s) of the bar.
width: The width of the bar, or ``None`` to fill available width. width: The width of the bar, or ``None`` to fill available width.

View File

@@ -1,3 +1,9 @@
"""
The `Screen` class is a special widget which represents the content in the terminal. See [Screens](/guide/screens/) for details.
"""
from __future__ import annotations from __future__ import annotations
from typing import TYPE_CHECKING, Iterable, Iterator from typing import TYPE_CHECKING, Iterable, Iterator

View File

@@ -1,3 +1,8 @@
"""
`ScrollView` is a base class for [line api](/guide/widgets#line-api) widgets.
"""
from __future__ import annotations from __future__ import annotations
from rich.console import RenderableType from rich.console import RenderableType

View File

@@ -1,3 +1,9 @@
"""
A Strip contains the result of rendering a widget.
See [line API](/guide/widgets#line-api) for how to use Strips.
"""
from __future__ import annotations from __future__ import annotations
from itertools import chain from itertools import chain
@@ -51,7 +57,7 @@ class Strip:
Args: Args:
segments: An iterable of segments. segments: An iterable of segments.
cell_length: The cell length if known, or None to calculate on demand. Defaults to None. cell_length: The cell length if known, or None to calculate on demand.
""" """
__slots__ = [ __slots__ = [
@@ -117,7 +123,7 @@ class Strip:
Args: Args:
lines: List of lines, where a line is a list of segments. lines: List of lines, where a line is a list of segments.
cell_length: Cell length of lines (must be same) or None if not known. Defaults to None. cell_length: Cell length of lines (must be same) or None if not known.
Returns: Returns:
List of strips. List of strips.
@@ -205,7 +211,7 @@ class Strip:
Args: Args:
cell_length: New desired cell length. cell_length: New desired cell length.
style: Style when extending, or `None`. Defaults to `None`. style: Style when extending, or `None`.
Returns: Returns:
A new strip with the supplied cell length. A new strip with the supplied cell length.

View File

@@ -34,11 +34,11 @@ class Timer:
Args: Args:
event_target: The object which will receive the timer events. event_target: The object which will receive the timer events.
interval: The time between timer events, in seconds. interval: The time between timer events, in seconds.
name: A name to assign the event (for debugging). Defaults to None. name: A name to assign the event (for debugging).
callback: A optional callback to invoke when the event is handled. Defaults to None. callback: A optional callback to invoke when the event is handled.
repeat: The number of times to repeat the timer, or None to repeat forever. Defaults to None. repeat: The number of times to repeat the timer, or None to repeat forever.
skip: Enable skipping of scheduled events that couldn't be sent in time. Defaults to True. skip: Enable skipping of scheduled events that couldn't be sent in time.
pause: Start the timer paused. Defaults to False. pause: Start the timer paused.
""" """
_timer_count: int = 1 _timer_count: int = 1

View File

@@ -1,3 +1,12 @@
"""
Functions for *walking* the DOM.
!!! note
For most purposes you would be better off using [query][textual.dom.DOMNode.query], which uses these functions internally.
"""
from __future__ import annotations from __future__ import annotations
from collections import deque from collections import deque
@@ -44,8 +53,7 @@ def walk_depth_first(
Args: Args:
root: The root note (starting point). root: The root note (starting point).
filter_type: Optional DOMNode subclass to filter by, or ``None`` for no filter. filter_type: Optional DOMNode subclass to filter by, or ``None`` for no filter.
Defaults to None. with_root: Include the root in the walk.
with_root: Include the root in the walk. Defaults to True.
Returns: Returns:
An iterable of DOMNodes, or the type specified in ``filter_type``. An iterable of DOMNodes, or the type specified in ``filter_type``.
@@ -106,8 +114,7 @@ def walk_breadth_first(
Args: Args:
root: The root note (starting point). root: The root note (starting point).
filter_type: Optional DOMNode subclass to filter by, or ``None`` for no filter. filter_type: Optional DOMNode subclass to filter by, or ``None`` for no filter.
Defaults to None. with_root: Include the root in the walk.
with_root: Include the root in the walk. Defaults to True.
Returns: Returns:
An iterable of DOMNodes, or the type specified in ``filter_type``. An iterable of DOMNodes, or the type specified in ``filter_type``.

View File

@@ -1,3 +1,8 @@
"""
The base class for widgets.
"""
from __future__ import annotations from __future__ import annotations
from asyncio import Lock, wait from asyncio import Lock, wait
@@ -84,10 +89,12 @@ _JUSTIFY_MAP: dict[str, JustifyMethod] = {
class AwaitMount: class AwaitMount:
"""An awaitable returned by mount() and mount_all(). """An *optional* awaitable returned by [mount][textual.widget.Widget.mount] and [mount_all][textual.widget.Widget.mount_all].
Example: Example:
```python
await self.mount(Static("foo")) await self.mount(Static("foo"))
```
""" """
@@ -164,7 +171,7 @@ class _Styled:
return Measurement.get(console, options, self.renderable) return Measurement.get(console, options, self.renderable)
class RenderCache(NamedTuple): class _RenderCache(NamedTuple):
"""Stores results of a previous render.""" """Stores results of a previous render."""
size: Size size: Size
@@ -286,6 +293,15 @@ class Widget(DOMNode):
classes: str | None = None, classes: str | None = None,
disabled: bool = False, disabled: bool = False,
) -> None: ) -> None:
"""Initialize a Widget.
Args:
*children: Child widgets.
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.
"""
self._size = Size(0, 0) self._size = Size(0, 0)
self._container_size = Size(0, 0) self._container_size = Size(0, 0)
self._layout_required = False self._layout_required = False
@@ -302,7 +318,7 @@ class Widget(DOMNode):
self._border_title: Text | None = None self._border_title: Text | None = None
self._border_subtitle: Text | None = None self._border_subtitle: Text | None = None
self._render_cache = RenderCache(Size(0, 0), []) self._render_cache = _RenderCache(Size(0, 0), [])
# Regions which need to be updated (in Widget) # Regions which need to be updated (in Widget)
self._dirty_regions: set[Region] = set() self._dirty_regions: set[Region] = set()
# Regions which need to be transferred from cache to screen # Regions which need to be transferred from cache to screen
@@ -469,7 +485,6 @@ class Widget(DOMNode):
Args: Args:
id: The ID of the child. id: The ID of the child.
expect_type: Require the object be of the supplied type, or None for any type. expect_type: Require the object be of the supplied type, or None for any type.
Defaults to None.
Returns: Returns:
The first child of this node with the ID. The first child of this node with the ID.
@@ -1498,11 +1513,11 @@ class Widget(DOMNode):
attribute: Name of the attribute to animate. attribute: Name of the attribute to animate.
value: The value to animate to. value: The value to animate to.
final_value: The final value of the animation. Defaults to `value` if not set. final_value: The final value of the animation. Defaults to `value` if not set.
duration: The duration of the animate. Defaults to None. duration: The duration of the animate.
speed: The speed of the animation. Defaults to None. speed: The speed of the animation.
delay: A delay (in seconds) before the animation starts. Defaults to 0.0. delay: A delay (in seconds) before the animation starts.
easing: An easing method. Defaults to "in_out_cubic". easing: An easing method.
on_complete: A callable to invoke when the animation is finished. Defaults to None. on_complete: A callable to invoke when the animation is finished.
""" """
if self._animate is None: if self._animate is None:
@@ -2663,7 +2678,7 @@ class Widget(DOMNode):
) )
) )
strips = [Strip(line, width) for line in lines] strips = [Strip(line, width) for line in lines]
self._render_cache = RenderCache(self.size, strips) self._render_cache = _RenderCache(self.size, strips)
self._dirty_regions.clear() self._dirty_regions.clear()
def render_line(self, y: int) -> Strip: def render_line(self, y: int) -> Strip:
@@ -2886,7 +2901,7 @@ class Widget(DOMNode):
When captured, mouse events will go to this widget even when the pointer is not directly over the widget. When captured, mouse events will go to this widget even when the pointer is not directly over the widget.
Args: Args:
capture: True to capture or False to release. Defaults to True. capture: True to capture or False to release.
""" """
self.app.capture_mouse(self if capture else None) self.app.capture_mouse(self if capture else None)

View File

@@ -553,7 +553,7 @@ class Markdown(Widget):
"""A Markdown widget. """A Markdown widget.
Args: Args:
markdown: String containing Markdown or None to leave blank for now. Defaults to None. markdown: String containing Markdown or None to leave blank for now.
name: The name of the widget. name: The name of the widget.
id: The ID of the widget in the DOM. id: The ID of the widget in the DOM.
classes: The CSS classes of the widget. classes: The CSS classes of the widget.
@@ -850,8 +850,8 @@ class MarkdownViewer(VerticalScroll, can_focus=True, can_focus_children=True):
"""Create a Markdown Viewer object. """Create a Markdown Viewer object.
Args: Args:
markdown: String containing Markdown, or None to leave blank. Defaults to None. markdown: String containing Markdown, or None to leave blank.
show_table_of_contents: Show a table of contents in a sidebar. Defaults to True. show_table_of_contents: Show a table of contents in a sidebar.
name: The name of the widget. name: The name of the widget.
id: The ID of the widget in the DOM. id: The ID of the widget in the DOM.
classes: The CSS classes of the widget. classes: The CSS classes of the widget.

View File

@@ -100,7 +100,7 @@ class Placeholder(Widget):
label: The label to identify the placeholder. label: The label to identify the placeholder.
If no label is present, uses the placeholder ID instead. If no label is present, uses the placeholder ID instead.
variant: The variant of the placeholder. variant: The variant of the placeholder.
name: The name of the placeholder. Defaults to None. name: The name of the placeholder.
id: The ID of the placeholder in the DOM. id: The ID of the placeholder in the DOM.
classes: A space separated string with the CSS classes classes: A space separated string with the CSS classes
of the placeholder, if any. of the placeholder, if any.

View File

@@ -29,13 +29,12 @@ class Static(Widget, inherit_bindings=False):
Args: Args:
renderable: A Rich renderable, or string containing console markup. renderable: A Rich renderable, or string containing console markup.
Defaults to "". expand: Expand content if required to fill container.
expand: Expand content if required to fill container. Defaults to False. shrink: Shrink content if required to fill container.
shrink: Shrink content if required to fill container. Defaults to False. markup: True if markup should be parsed and rendered.
markup: True if markup should be parsed and rendered. Defaults to True. name: Name of widget.
name: Name of widget. Defaults to None. id: ID of Widget.
id: ID of Widget. Defaults to None. classes: Space separated list of class names.
classes: Space separated list of class names. Defaults to None.
disabled: Whether the static is disabled or not. disabled: Whether the static is disabled or not.
""" """

View File

@@ -113,8 +113,8 @@ class Switch(Widget, can_focus=True):
"""Initialise the switch. """Initialise the switch.
Args: Args:
value: The initial value of the switch. Defaults to False. value: The initial value of the switch.
animate: True if the switch should animate when toggled. Defaults to True. animate: True if the switch should animate when toggled.
name: The name of the switch. name: The name of the switch.
id: The ID of the switch in the DOM. id: The ID of the switch in the DOM.
classes: The CSS classes of the switch. classes: The CSS classes of the switch.

View File

@@ -127,7 +127,7 @@ class ToggleButton(Static, can_focus=True):
Args: Args:
label: The label for the toggle. label: The label for the toggle.
value: The initial value of the toggle. Defaults to `False`. value: The initial value of the toggle.
button_first: Should the button come before the label, or after? button_first: Should the button come before the label, or after?
name: The name of the toggle. name: The name of the toggle.
id: The ID of the toggle in the DOM. id: The ID of the toggle in the DOM.

Some files were not shown because too many files have changed in this diff Show More