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

View File

@@ -10,14 +10,14 @@
(
{%- 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" -%}
{%- set ns.has_pos_only = True -%}
{%- else -%}
{%- if ns.has_pos_only and ns.render_pos_only_separator -%}
{%- set ns.render_pos_only_separator = False %}/, {% endif -%}
{%- if parameter.kind.value == "keyword-only" -%}
{%- if parameter.kind.value == "keyword-only" -%}
{%- if ns.render_kw_only_separator -%}
{%- set ns.render_kw_only_separator = False %}*, {% endif -%}
{%- endif -%}

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

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

View File

@@ -38,7 +38,7 @@ Additionally there are new [update_cell][textual.widgets.DataTable.update_cell]
## 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

View File

@@ -43,9 +43,14 @@ body[data-md-color-primary="black"] .excalidraw svg rect {
border: 0;
}
.doc-object code {
font-family: "Fira Code", "SFMono-Regular", Consolas, "Courier New", Courier,
monospace;
}
/* Indentation. */
div.doc-contents:not(.first) .doc-contents {
div.doc-contents:not(.first) {
padding-left: 25px;
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
- [WIDGET](../api/WIDGET.md) code reference.
- Another related API.
- 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
### ::: textual.widgets.Button.Pressed
- [Button.Pressed][textual.widgets.Button.Pressed]
## 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.
## 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
### ::: 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

@@ -46,11 +46,14 @@ When the user presses the "Markdown" button the view is switched:
## 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. |
## 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
### ::: textual.widgets.DataTable.CellHighlighted
### ::: textual.widgets.DataTable.CellSelected
### ::: textual.widgets.DataTable.RowHighlighted
### ::: textual.widgets.DataTable.RowSelected
### ::: textual.widgets.DataTable.ColumnHighlighted
### ::: textual.widgets.DataTable.ColumnSelected
### ::: textual.widgets.DataTable.HeaderSelected
- [DataTable.CellHighlighted][textual.widgets.DataTable.CellHighlighted]
- [DataTable.CellSelected][textual.widgets.DataTable.CellSelected]
- [DataTable.RowHighlighted][textual.widgets.DataTable.RowHighlighted]
- [DataTable.RowSelected][textual.widgets.DataTable.RowSelected]
- [DataTable.ColumnHighlighted][textual.widgets.DataTable.ColumnHighlighted]
- [DataTable.ColumnSelected][textual.widgets.DataTable.ColumnSelected]
- [DataTable.HeaderSelected][textual.widgets.DataTable.HeaderSelected]
## Bindings
@@ -68,6 +62,9 @@ The data table widget provides the following component classes:
show_root_heading: 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
### ::: textual.widgets.DirectoryTree.FileSelected
- [DirectoryTree.FileSelected][textual.widgets.DirectoryTree.FileSelected]
## Reactive Attributes
@@ -57,5 +57,13 @@ The directory tree widget provides the following component classes:
## See Also
* [DirectoryTree][textual.widgets.DirectoryTree] 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 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.
## 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
### ::: textual.widgets.Input.Changed
### ::: textual.widgets.Input.Submitted
- [Input.Changed][textual.widgets.Input.Changed]
- [Input.Submitted][textual.widgets.Input.Submitted]
## 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.
## 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.
## 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
| Name | Type | Default | Description |
|---------------|--------|---------|--------------------------------------|
| ------------- | ------ | ------- | ------------------------------------ |
| `highlighted` | `bool` | `False` | True if this ListItem is highlighted |
#### Attributes
| attribute | type | purpose |
|-----------|------------|-----------------------------|
| --------- | ---------- | --------------------------- |
| `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
### ::: textual.widgets.ListView.Highlighted
### ::: textual.widgets.ListView.Selected
- [ListView.Highlighted][textual.widgets.ListView.Highlighted]
- [ListView.Selected][textual.widgets.ListView.Selected]
## Bindings
@@ -50,6 +49,9 @@ The list view widget defines the following bindings:
show_root_heading: 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
--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
### ::: textual.widgets.Markdown.TableOfContentsUpdated
### ::: textual.widgets.Markdown.TableOfContentsSelected
### ::: textual.widgets.Markdown.LinkClicked
- [Markdown.TableOfContentsUpdated][textual.widgets.Markdown.TableOfContentsUpdated]
- [Markdown.TableOfContentsSelected][textual.widgets.Markdown.TableOfContentsSelected]
- [Markdown.LinkClicked][textual.widgets.Markdown.LinkClicked]
## See Also
* [Markdown][textual.widgets.Markdown] 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
* [MarkdownViewer][textual.widgets.MarkdownViewer] 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
| Name | Type | Default | Description |
|---------------|-----------------|---------|---------------------------------------------------------------------------|
| ------------- | --------------- | ------- | ------------------------------------------------------------------------- |
| `highlighted` | `int` \| `None` | `None` | The index of the highlighted option. `None` means nothing is highlighted. |
## Messages
### ::: textual.widgets.OptionList.OptionHighlighted
### ::: textual.widgets.OptionList.OptionSelected
- [OptionList.OptionHighlight][textual.widgets.OptionList.OptionHighlighted]
- [OptionList.OptionSelected][textual.widgets.OptionList.OptionSelected]
Both of the messages above inherit from this common base, which makes
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_toc_entry: false
## See Also
* [OptionList][textual.widgets.OptionList] code reference
::: textual.widgets.OptionList
options:
heading_level: 2

View File

@@ -34,15 +34,18 @@ The example below shows each placeholder variant.
## Reactive Attributes
| Name | Type | Default | Description |
| ---------- | ------ | ----------- | -------------------------------------------------- |
| `variant` | `str` | `"default"` | Styling variant. One of `default`, `size`, `text`. |
| Name | Type | Default | Description |
| --------- | ----- | ----------- | -------------------------------------------------- |
| `variant` | `str` | `"default"` | Styling variant. One of `default`, `size`, `text`. |
## 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
### ::: textual.widgets.RadioButton.Changed
- [RadioButton.Changed][textual.widgets.RadioButton.Changed]
## See Also
- [RadioButton](../api/radiobutton.md) code reference
- [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
### ::: textual.widgets.RadioSet.Changed
- [RadioSet.Changed][textual.widgets.RadioSet.Changed]
#### Example
@@ -56,5 +56,12 @@ Here is an example of using the message to react to changes in a `RadioSet`:
## See Also
- [RadioSet](../api/radioset.md) code reference
- [RadioButton](./radiobutton.md)
---
::: textual.widgets.RadioSet
options:
heading_level: 2

View File

@@ -31,5 +31,12 @@ This widget sends no messages.
## See Also
* [Static](../api/static.md) code reference
* [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
### ::: textual.widgets.Switch.Changed
- [Switch.Changed][textual.widgets.Switch.Changed]
## Additional Notes
- 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
- [TabbedContent](../api/tabbed_content.md) code reference.
- [Tabs](../api/tabs.md) code reference.
- [ContentSwitcher](../api/content_switcher.md) code reference.
- [Tabs](tabs.md)
- [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
### ::: textual.widgets.Tabs.TabActivated
### ::: textual.widgets.Tabs.Cleared
- [Tabs.TabActivate][textual.widgets.Tabs.TabActivated]
- [Tabs.Cleared][textual.widgets.Tabs.Cleared]
## Bindings
@@ -73,6 +73,17 @@ The Tabs widget defines the following bindings:
show_root_heading: 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.
## 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_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/await_remove.md"
- "api/binding.md"
- "api/button.md"
- "api/checkbox.md"
- "api/color.md"
- "api/containers.md"
- "api/content_switcher.md"
- "api/coordinate.md"
- "api/data_table.md"
- "api/directory_tree.md"
- "api/dom_node.md"
- "api/events.md"
- "api/footer.md"
- "api/geometry.md"
- "api/header.md"
- "api/index.md"
- "api/input.md"
- "api/label.md"
- "api/list_item.md"
- "api/list_view.md"
- "api/loading_indicator.md"
- "api/logger.md"
- "api/logging.md"
- "api/markdown_viewer.md"
- "api/markdown.md"
- "api/message_pump.md"
- "api/message.md"
- "api/option_list.md"
- "api/pilot.md"
- "api/placeholder.md"
- "api/query.md"
- "api/radiobutton.md"
- "api/radioset.md"
- "api/reactive.md"
- "api/screen.md"
- "api/scroll_view.md"
- "api/static.md"
- "api/strip.md"
- "api/switch.md"
- "api/tabbed_content.md"
- "api/tabs.md"
- "api/text_log.md"
- "api/timer.md"
- "api/toggle_button.md"
- "api/tree.md"
- "api/walk.md"
- "api/welcome.md"
- "api/widget.md"
- "api/work.md"
- "api/worker.md"

View File

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

View File

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

View File

@@ -142,7 +142,7 @@ class LRUCache(Generic[CacheKey, CacheValue]):
Args:
key: Key
default: Default to return if key is not present. Defaults to None.
default: Default to return if key is not present.
Returns:
Either the value or a default.
@@ -256,7 +256,7 @@ class FIFOCache(Generic[CacheKey, CacheValue]):
Args:
key: Key
default: Default to return if key is not present. Defaults to None.
default: Default to return if key is not present.
Returns:
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 functools import partial, wraps
@@ -53,7 +60,7 @@ def work(
exit_on_error: bool = True,
exclusive: bool = False,
) -> Callable[FactoryParamSpec, Worker[ReturnType]] | Decorator:
"""Worker decorator factory.
"""A decorator used to create [workers](/guide/workers).
Args:
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
import asyncio

View File

@@ -66,7 +66,7 @@ from ._wait import wait_for_idle
from ._worker_manager import WorkerManager
from .actions import ActionParseResult, SkipAction
from .await_remove import AwaitRemove
from .binding import Binding, Bindings
from .binding import Binding, _Bindings
from .css.query import NoMatches
from .css.stylesheet import Stylesheet
from .design import ColorSystem
@@ -242,10 +242,10 @@ CallThreadReturnType = TypeVar("CallThreadReturnType")
class App(Generic[ReturnType], DOMNode):
"""The base class for Textual Applications.
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.
Defaults to None. 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.
To load multiple CSS files, pass a list of strings or paths which will be loaded in order.
watch_css: Watch CSS for changes.
Raises:
CssPathError: When the supplied CSS path(s) are an unexpected type.
@@ -436,7 +436,12 @@ class App(Generic[ReturnType], DOMNode):
@property
def workers(self) -> WorkerManager:
"""A worker manager."""
"""The worker manager.
Returns:
An object to manage workers.
"""
return self._workers
@property
@@ -446,7 +451,12 @@ class App(Generic[ReturnType], DOMNode):
@property
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:
return (self.screen,)
except ScreenError:
@@ -489,12 +499,12 @@ class App(Generic[ReturnType], DOMNode):
Args:
attribute: Name of the attribute to animate.
value: The value to animate to.
final_value: The final value of the animation. Defaults to `value` if not set.
duration: The duration of the animate. Defaults to None.
speed: The speed of the animation. Defaults to None.
delay: A delay (in seconds) before the animation starts. Defaults to 0.0.
easing: An easing method. Defaults to "in_out_cubic".
on_complete: A callable to invoke when the animation is finished. Defaults to None.
final_value: The final value of the animation.
duration: The duration of the animate.
speed: The speed of the animation.
delay: A delay (in seconds) before the animation starts.
easing: An easing method.
on_complete: A callable to invoke when the animation is finished.
"""
self._animate(
@@ -520,7 +530,12 @@ class App(Generic[ReturnType], DOMNode):
@property
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()
def exit(
@@ -529,7 +544,7 @@ class App(Generic[ReturnType], DOMNode):
"""Exit the app, and return the supplied result.
Args:
result: Return value. Defaults to None.
result: Return value.
message: Optional message to display on exit.
"""
self._exit = True
@@ -540,7 +555,12 @@ class App(Generic[ReturnType], DOMNode):
@property
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
@property
@@ -666,7 +686,12 @@ class App(Generic[ReturnType], DOMNode):
@property
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:
width, height = self._driver._size
else:
@@ -675,7 +700,12 @@ class App(Generic[ReturnType], DOMNode):
@property
def log(self) -> Logger:
"""The logger object."""
"""Textual log interface.
Returns:
A Textual logger.
"""
return self._logger
def _log(
@@ -699,7 +729,7 @@ class App(Generic[ReturnType], DOMNode):
```
Args:
verbosity: Verbosity level 0-3. Defaults to 1.
verbosity: Verbosity level 0-3.
"""
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.
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.
"""
self.save_screenshot(filename, path)
@@ -796,7 +826,7 @@ class App(Generic[ReturnType], DOMNode):
Args:
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"
@@ -826,7 +856,7 @@ class App(Generic[ReturnType], DOMNode):
Args:
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.
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.
@@ -865,9 +895,9 @@ class App(Generic[ReturnType], DOMNode):
Args:
keys: A comma separated list of keys, i.e.
action: Action to bind to.
description: Short description of action. Defaults to "".
show: Show key in UI. Defaults to True.
key_display: Replacement text for key, or None to use default. Defaults to None.
description: Short description of action.
show: Show key in UI.
key_display: Replacement text for key, or None to use default.
"""
self._bindings.bind(
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.
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)`,
or None to auto-detect. Defaults to None.
or None to auto-detect.
"""
from .pilot import Pilot
@@ -981,9 +1011,9 @@ class App(Generic[ReturnType], DOMNode):
"""Run the app asynchronously.
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)`,
or None to auto-detect. Defaults to None.
or None to auto-detect.
auto_pilot: An auto pilot coroutine.
Returns:
@@ -1042,9 +1072,9 @@ class App(Generic[ReturnType], DOMNode):
"""Run the app.
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)`,
or None to auto-detect. Defaults to None.
or None to auto-detect.
auto_pilot: An auto pilot coroutine.
Returns:
@@ -1119,7 +1149,6 @@ class App(Generic[ReturnType], DOMNode):
Args:
id: The ID of the node to search for.
expect_type: Require the object be of the supplied type, or None for any type.
Defaults to None.
Returns:
The first child of this node with the specified ID.
@@ -1918,7 +1947,7 @@ class App(Generic[ReturnType], DOMNode):
"""Refresh CSS.
Args:
animate: Also execute CSS animations. Defaults to True.
animate: Also execute CSS animations.
"""
stylesheet = self.app.stylesheet
stylesheet.set_variables(self.get_css_variables())
@@ -1973,14 +2002,14 @@ class App(Generic[ReturnType], DOMNode):
self.console.bell()
@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.
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.
"""
focused = self.focused
namespace_bindings: list[tuple[DOMNode, Bindings]]
namespace_bindings: list[tuple[DOMNode, _Bindings]]
if focused is None:
namespace_bindings = [
@@ -1995,7 +2024,7 @@ class App(Generic[ReturnType], DOMNode):
return namespace_bindings
@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."""
binding_chain = self._binding_chain
for index, (node, _bindings) in enumerate(binding_chain, 1):
@@ -2061,7 +2090,7 @@ class App(Generic[ReturnType], DOMNode):
Args:
action: Action encoded in a string.
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:
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 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 dataclasses import dataclass
@@ -44,7 +53,7 @@ class Binding:
@rich.repr.auto
class Bindings:
class _Bindings:
"""Manage a set of bindings."""
def __init__(
@@ -98,13 +107,13 @@ class Bindings:
else {}
)
def copy(self) -> Bindings:
def copy(self) -> _Bindings:
"""Return a copy of this instance.
Return:
New bindings object.
"""
copy = Bindings()
copy = _Bindings()
copy.keys = self.keys.copy()
return copy
@@ -112,7 +121,7 @@ class Bindings:
yield self.keys
@classmethod
def merge(cls, bindings: Iterable[Bindings]) -> Bindings:
def merge(cls, bindings: Iterable[_Bindings]) -> _Bindings:
"""Merge a bindings. Subsequent bound keys override initial keys.
Args:
@@ -124,7 +133,7 @@ class Bindings:
keys: dict[str, Binding] = {}
for _bindings in bindings:
keys.update(_bindings.keys)
return Bindings(keys.values())
return _Bindings(keys.values())
@property
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.
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
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.style import Style
from rich.text import Text
from typing_extensions import Final
from textual.css.scalar import percentage_string_to_float
from textual.css.tokenize import CLOSE_BRACE, COMMA, DECIMAL, OPEN_BRACE, PERCENT
@@ -58,14 +56,14 @@ _TRUECOLOR = ColorType.TRUECOLOR
class HSL(NamedTuple):
"""A color in HLS format."""
"""A color in HLS (Hue, Saturation, Lightness) format."""
h: float
"""Hue"""
"""Hue in range 0 to 1."""
s: float
"""Saturation"""
"""Saturation in range 0 to 1."""
l: float
"""Lightness"""
"""Lightness in range 0 to 1."""
@property
def css(self) -> str:
@@ -73,28 +71,32 @@ class HSL(NamedTuple):
h, s, l = self
def as_str(number: float) -> str:
"""Format a float."""
return f"{number:.1f}".rstrip("0").rstrip(".")
return f"hsl({as_str(h*360)},{as_str(s*100)}%,{as_str(l*100)}%)"
class HSV(NamedTuple):
"""A color in HSV format."""
"""A color in HSV (Hue, Saturation, Value) format."""
h: float
"""Hue"""
"""Hue in range 0 to 1."""
s: float
"""Saturation"""
"""Saturation in range 0 to 1"""
v: float
"""Value"""
"""Value un range 0 to 1."""
class Lab(NamedTuple):
"""A color in CIE-L*ab format."""
L: float
"""Lightness in range 0 to 100."""
a: float
"""A axis in range -127 to 128."""
b: float
"""B axis in range -127 to 128."""
RE_COLOR = re.compile(
@@ -126,7 +128,7 @@ class ColorParseError(Exception):
Args:
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):
@@ -136,26 +138,32 @@ class ColorParseError(Exception):
@rich.repr.auto
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
"""Red component (0-255)"""
"""Red component in range 0 to 255."""
g: int
"""Green component (0-255)"""
"""Green component in range 0 to 255."""
b: int
"""Blue component (0-255)"""
"""Blue component in range 0 to 255."""
a: float = 1.0
"""Alpha component (0-1)"""
"""Alpha component in range 0 to 1."""
@classmethod
def from_rich_color(cls, rich_color: RichColor) -> Color:
"""Create a new color from Rich's Color class.
Args:
rich_color: An instance of rich.color.Color.
rich_color: An instance of [Rich color][rich.color.Color].
Returns:
A new Color.
A new Color instance.
"""
r, g, b = rich_color.get_truecolor()
return cls(r, g, b)
@@ -192,22 +200,12 @@ class Color(NamedTuple):
@property
def is_transparent(self) -> bool:
"""Check if the color is transparent, i.e. has 0 alpha.
Returns:
True if transparent, otherwise False.
"""
"""Is the color transparent (i.e. has 0 alpha)?"""
return self.a == 0
@property
def clamped(self) -> Color:
"""Get a color with all components saturated to maximum and minimum values.
Returns:
A color object.
"""
"""A clamped color (this color with all values in expected range)."""
r, g, b, a = self
_clamp = clamp
color = Color(
@@ -243,20 +241,16 @@ class Color(NamedTuple):
@property
def rgb(self) -> tuple[int, int, int]:
"""Get just the red, green, and blue components.
Returns:
Color components
"""
"""A tuple of the red, gree, and blue color components."""
r, g, b, _ = self
return (r, g, b)
@property
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
h, l, s = rgb_to_hls(r, g, b)
@@ -264,10 +258,10 @@ class Color(NamedTuple):
@property
def brightness(self) -> float:
"""Get the human perceptual brightness.
"""The human perceptual brightness.
Returns:
Brightness value (0-1).
A value of 1 is returned for pure white, and 0 for pure black.
Other colors lie on a gradient between the two extremes.
"""
r, g, b = self.normalized
@@ -278,8 +272,7 @@ class Color(NamedTuple):
def hex(self) -> str:
"""The color in CSS hex form, with 6 digits for RGB, and 8 digits for RGBA.
Returns:
A CSS hex-style color, e.g. `"#46b3de"` or `"#3342457f"`
For example, `"#46b3de"` for an RGB color, or `"#3342457f"` for a color with alpha.
"""
r, g, b, a = self.clamped
@@ -293,8 +286,7 @@ class Color(NamedTuple):
def hex6(self) -> str:
"""The color in CSS hex form, with 6 digits for RGB. Alpha is ignored.
Returns:
A CSS hex-style color, e.g. "#46b3de"
For example, `"#46b3de"`.
"""
r, g, b, _a = self.clamped
@@ -302,10 +294,9 @@ class Color(NamedTuple):
@property
def css(self) -> str:
"""The color in CSS rgb or rgba form.
"""The color in CSS RGB or RGBA form.
Returns:
A CSS style color, e.g. `"rgb(10,20,30)"` or `"rgb(50,70,80,0.5)"`
For example, `"rgb(10,20,30)"` for an RGB color, or `"rgb(50,70,80,0.5)"` for an RGBA color.
"""
r, g, b, a = self
@@ -313,11 +304,7 @@ class Color(NamedTuple):
@property
def monochrome(self) -> Color:
"""Get a monochrome version of this color.
Returns:
A new monochrome color.
"""
"""A monochrome version of this color."""
r, g, b, a = self
gray = round(r * 0.2126 + g * 0.7152 + b * 0.0722)
return Color(gray, gray, gray, a)
@@ -358,10 +345,14 @@ class Color(NamedTuple):
) -> Color:
"""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:
destination: Another color.
factor: A blend factor, 0 -> 1.
alpha: New alpha for result. Defaults to None.
alpha: New alpha for result.
Returns:
A new color.
@@ -515,7 +506,7 @@ class Color(NamedTuple):
Args:
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:
New color.
@@ -529,7 +520,7 @@ class Color(NamedTuple):
Args:
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:
New color.
@@ -541,8 +532,7 @@ class Color(NamedTuple):
"""Get a light or dark color that best contrasts this color, for use with text.
Args:
alpha: An alpha value to adjust the pure white / black by.
Defaults to 0.95.
alpha: An alpha value to apply to the result.
Returns:
A new color, either an off-white or off-black
@@ -597,8 +587,10 @@ class Gradient:
# Color constants
WHITE = Color(255, 255, 255)
BLACK = Color(0, 0, 0)
WHITE: Final = Color(255, 255, 255)
"""A constant for pure white."""
BLACK: Final = Color(0, 0, 0)
"""A constant for pure black."""
def rgb_to_lab(rgb: Color) -> Lab:

View File

@@ -1,3 +1,9 @@
"""
Container widgets for quick styling.
"""
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 typing import NamedTuple

View File

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

View File

@@ -74,7 +74,7 @@ class HelpText:
Attributes:
summary: A succinct summary of the issue.
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__(

View File

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

View File

@@ -72,6 +72,21 @@ class DOMQuery(Generic[QueryType]):
exclude: str | None = None,
parent: DOMQuery | 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._nodes: list[QueryType] | None = None
self._filters: list[tuple[SelectorSet, ...]] = (
@@ -95,6 +110,7 @@ class DOMQuery(Generic[QueryType]):
@property
def node(self) -> DOMNode:
"""The node being queried."""
return self._node
@property
@@ -193,7 +209,7 @@ class DOMQuery(Generic[QueryType]):
Args:
expect_type: Require matched node is of this type,
or None for any type. Defaults to None.
or None for any type.
Raises:
WrongType: If the wrong type was found.
@@ -228,7 +244,7 @@ class DOMQuery(Generic[QueryType]):
Args:
expect_type: Require matched node is of this type,
or None for any type. Defaults to None.
or None for any type.
Raises:
WrongType: If the wrong type was found.
@@ -272,7 +288,7 @@ class DOMQuery(Generic[QueryType]):
Args:
expect_type: Require matched node is of this type,
or None for any type. Defaults to None.
or None for any type.
Raises:
WrongType: If the wrong type was found.
@@ -305,7 +321,7 @@ class DOMQuery(Generic[QueryType]):
Args:
filter_type: A Widget class to filter results,
or None for no filter. Defaults to None.
or None for no filter.
Yields:
Iterator[Widget | ExpectType]: An iterator of Widget instances.
@@ -383,7 +399,7 @@ class DOMQuery(Generic[QueryType]):
"""Set styles on matched nodes.
Args:
css: CSS declarations to parser, or None. Defaults to None.
css: CSS declarations to parser, or None.
"""
_rich_traceback_omit = True
@@ -405,8 +421,8 @@ class DOMQuery(Generic[QueryType]):
"""Refresh matched nodes.
Args:
repaint: Repaint node(s). defaults to True.
layout: Layout node(s). Defaults to False.
repaint: Repaint node(s).
layout: Layout node(s).
Returns:
Query for chaining.

View File

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

View File

@@ -275,7 +275,6 @@ class Stylesheet:
Args:
css: String with CSS source.
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
in a user stylesheet.
tie_breaker: Integer representing the priority of this source.
@@ -365,12 +364,12 @@ class Stylesheet:
"""Apply the stylesheet to a DOM node.
Args:
node: The ``DOMNode`` to apply the stylesheet to.
Applies the styles defined in this ``Stylesheet`` to the node.
node: The `DOMNode` to apply the stylesheet to.
Applies the styles defined in this `Stylesheet` to the node.
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
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.
# The tuples contain the rule specificity, and the value for that rule.
@@ -447,7 +446,7 @@ class Stylesheet:
Args:
node: A DOM node.
rules: Mapping of rules.
animate: Enable animation. Defaults to False.
animate: Enable animation.
"""
# Alias styles and base styles
@@ -519,7 +518,7 @@ class Stylesheet:
Args:
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)
@@ -529,7 +528,7 @@ class Stylesheet:
Args:
nodes: Nodes to update.
animate: Enable CSS animation. Defaults to False.
animate: Enable CSS animation.
"""
rules_map = self.rules_map

View File

@@ -32,7 +32,7 @@ class TokenError(Exception):
code: The code being parsed.
start: Line number of 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

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.
Args:
filename: Filename of screenshot, or None to auto-generate. Defaults to None.
path: Path to directory. Defaults to "./".
filename: Filename of screenshot, or None to auto-generate.
path: Path to directory.
"""
self.bell()
path = self.save_screenshot(filename, path)

View File

@@ -94,12 +94,6 @@ class ColorSystem:
def generate(self) -> dict[str, str]:
"""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:
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
import re
@@ -25,7 +34,7 @@ from ._context import NoActiveAppError
from ._node_list import NodeList
from ._types import WatchCallbackType
from ._worker_manager import WorkerManager
from .binding import Binding, Bindings, BindingType
from .binding import Binding, BindingType, _Bindings
from .color import BLACK, WHITE, Color
from .css._error_tools import friendly_list
from .css.constants import VALID_DISPLAY, VALID_VISIBILITY
@@ -134,7 +143,7 @@ class DOMNode(MessagePump):
_css_type_names: ClassVar[frozenset[str]] = frozenset()
# Generated list of bindings
_merged_bindings: ClassVar[Bindings | None] = None
_merged_bindings: ClassVar[_Bindings | None] = None
_reactives: ClassVar[dict[str, Reactive]]
@@ -168,7 +177,7 @@ class DOMNode(MessagePump):
self._auto_refresh_timer: Timer | None = None
self._css_types = {cls.__name__ for cls in self._css_bases(self.__class__)}
self._bindings = (
Bindings()
_Bindings()
if self._merged_bindings is None
else self._merged_bindings.copy()
)
@@ -191,7 +200,12 @@ class DOMNode(MessagePump):
@property
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
@property
@@ -212,7 +226,7 @@ class DOMNode(MessagePump):
@property
def workers(self) -> WorkerManager:
"""A worker manager."""
"""The app's worker manager. Shortcut for `self.app.workers`."""
return self.app.workers
def run_worker(
@@ -346,27 +360,27 @@ class DOMNode(MessagePump):
return classes
@classmethod
def _merge_bindings(cls) -> Bindings:
def _merge_bindings(cls) -> _Bindings:
"""Merge bindings from base classes.
Returns:
Merged bindings.
"""
bindings: list[Bindings] = []
bindings: list[_Bindings] = []
for base in reversed(cls.__mro__):
if issubclass(base, DOMNode):
if not base._inherit_bindings:
bindings.clear()
bindings.append(
Bindings(
_Bindings(
base.__dict__.get("BINDINGS", []),
)
)
keys: dict[str, Binding] = {}
for bindings_ in bindings:
keys.update(bindings_.keys)
return Bindings(keys.values())
return _Bindings(keys.values())
def _post_register(self, app: App) -> None:
"""Called when the widget is registered
@@ -503,6 +517,7 @@ class DOMNode(MessagePump):
return tokens
classes = _ClassesDescriptor()
"""CSS class names for this node."""
@property
def pseudo_classes(self) -> frozenset[str]:
@@ -584,9 +599,15 @@ class DOMNode(MessagePump):
@property
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:
"""Render a node for the tree."""
return Pretty(node)
tree = Tree(render_info(self))
@@ -605,6 +626,9 @@ class DOMNode(MessagePump):
def css_tree(self) -> Tree:
"""Get a Rich tree object which will recursively render the structure of the node tree,
which also displays CSS and size information.
Returns:
A Rich Tree renderable.
"""
from rich.columns import Columns
from rich.console import Group
@@ -613,6 +637,7 @@ class DOMNode(MessagePump):
from .widget import Widget
def render_info(node: DOMNode) -> Columns:
"""Render a node for the tree."""
if isinstance(node, Widget):
info = Columns(
[
@@ -659,7 +684,7 @@ class DOMNode(MessagePump):
the child will also be bold.
Returns:
Rich Style object.
A Rich Style.
"""
return Style.combine(
node.styles.text_style for node in reversed(self.ancestors_with_self)
@@ -667,7 +692,12 @@ class DOMNode(MessagePump):
@property
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)
color = Color(255, 255, 255, 0)
style = Style()
@@ -720,6 +750,9 @@ class DOMNode(MessagePump):
Note:
This is inclusive of ``self``.
Returns:
A list of nodes.
"""
nodes: list[MessagePump | None] = []
add_node = nodes.append
@@ -731,12 +764,22 @@ class DOMNode(MessagePump):
@property
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:]
@property
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]
def watch(
@@ -829,10 +872,9 @@ class DOMNode(MessagePump):
Args:
filter_type: Filter only this type, or None for no filter.
Defaults to None.
with_self: Also yield self in addition to descendants. Defaults to False.
method: One of "depth" or "breadth". Defaults to "depth".
reverse: Reverse the order (bottom up). Defaults to False.
with_self: Also yield self in addition to descendants.
method: One of "depth" or "breadth".
reverse: Reverse the order (bottom up).
Returns:
A list of nodes.
@@ -867,7 +909,7 @@ class DOMNode(MessagePump):
"""Get a DOM query matching a selector.
Args:
selector: A CSS selector or `None` for all nodes. Defaults to None.
selector: A CSS selector or `None` for all nodes.
Returns:
A query object.
@@ -902,7 +944,6 @@ class DOMNode(MessagePump):
Args:
selector: A selector.
expect_type: Require the object be of the supplied type, or None for any type.
Defaults to None.
Raises:
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 typing import TYPE_CHECKING, Type, TypeVar
@@ -37,7 +51,12 @@ class Callback(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):
@@ -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
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
through the usual message queue.
- [ ] Bubbles
- [ ] Verbose
"""
@@ -81,10 +105,14 @@ class Action(Event):
class Resize(Event, bubble=False):
"""Sent when the app or widget has been resized.
- [ ] Bubbles
- [ ] Verbose
Args:
size: The new 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):
"""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):
"""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):
"""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):
"""Sent when a widget has become visible."""
"""Sent when a widget has become visible.
- [ ] Bubbles
- [ ] Verbose
"""
class Hide(Event, bubble=False):
"""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,
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):
"""Sent to the app when the DOM is ready."""
"""Sent to the app when the DOM is ready.
- [ ] Bubbles
- [ ] Verbose
"""
@rich.repr.auto
class MouseCapture(Event, bubble=False):
"""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:
mouse_position: The position of the mouse when captured.
@@ -163,6 +221,9 @@ class MouseCapture(Event, bubble=False):
class MouseRelease(Event, bubble=False):
"""Mouse has been released.
- [ ] Bubbles
- [ ] Verbose
Args:
mouse_position: The position of the mouse when released.
"""
@@ -183,6 +244,9 @@ class InputEvent(Event):
class Key(InputEvent):
"""Sent when the user hits a key on the keyboard.
- [X] Bubbles
- [ ] Verbose
Args:
key: The key that was pressed.
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):
"""Sent in response to a mouse event.
- [X] Bubbles
- [ ] Verbose
Args:
x: The relative x coordinate.
y: The relative y coordinate.
@@ -395,35 +462,73 @@ class MouseEvent(InputEvent, bubble=True):
@rich.repr.auto
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
class MouseDown(MouseEvent, bubble=True, verbose=True):
pass
"""Sent when a mouse button is pressed.
- [X] Bubbles
- [X] Verbose
"""
@rich.repr.auto
class MouseUp(MouseEvent, bubble=True, verbose=True):
pass
"""Sent when a mouse button is released.
- [X] Bubbles
- [X] Verbose
"""
@rich.repr.auto
class MouseScrollDown(MouseEvent, bubble=True):
pass
"""Sent when the mouse wheel is scrolled *down*.
- [X] Bubbles
- [ ] Verbose
"""
@rich.repr.auto
class MouseScrollUp(MouseEvent, bubble=True):
pass
"""Sent when the mouse wheel is scrolled *up*.
- [X] Bubbles
- [ ] Verbose
"""
class Click(MouseEvent, bubble=True):
pass
"""Sent when a widget is clicked.
- [X] Bubbles
- [ ] Verbose
"""
@rich.repr.auto
class Timer(Event, bubble=False, verbose=True):
"""Sent in response to a timer.
- [ ] Bubbles
- [X] Verbose
"""
__slots__ = ["time", "count", "callback"]
def __init__(
@@ -445,27 +550,57 @@ class Timer(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):
pass
"""Sent when the mouse is moved away from a widget.
- [ ] Bubbles
- [X] Verbose
"""
class Focus(Event, bubble=False):
pass
"""Sent when a widget is focussed.
- [X] Bubbles
- [ ] Verbose
"""
class Blur(Event, bubble=False):
pass
"""Sent when a widget is blurred (un-focussed).
- [X] Bubbles
- [ ] Verbose
"""
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):
pass
"""Sent when a child widget is blurred.
- [X] Bubbles
- [X] Verbose
"""
@rich.repr.auto
@@ -475,6 +610,10 @@ class Paste(Event, bubble=True):
bracketed paste mode. Textual will enable bracketed pastes when an app starts,
and disable it when the app shuts down.
- [X] Bubbles
- [ ] Verbose
Args:
text: The text that has been pasted.
"""
@@ -488,8 +627,18 @@ class Paste(Event, bubble=True):
class ScreenResume(Event, bubble=False):
pass
"""Sent to screen that has been made active.
- [ ] Bubbles
- [ ] Verbose
"""
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,
)
from typing_extensions import Final
if TYPE_CHECKING:
from typing_extensions import TypeAlias
@@ -31,7 +33,7 @@ T = TypeVar("T", int, float)
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.
Args:
@@ -53,8 +55,9 @@ def clamp(value: T, minimum: T, maximum: T) -> T:
class Offset(NamedTuple):
"""A cell offset defined by x and y coordinates. Offsets are typically relative to the
top left of the terminal or other container.
"""A cell offset defined by x and y coordinates.
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_.
@@ -67,21 +70,12 @@ class Offset(NamedTuple):
@property
def is_origin(self) -> bool:
"""Check if the point is at the origin (0, 0).
Returns:
True if the offset is the origin.
"""
"""Is the offset at (0, 0)?"""
return self == (0, 0)
@property
def clamped(self) -> Offset:
"""Ensure x and y are above zero.
Returns:
New offset.
"""
"""This offset with `x` and `y` restricted to values above zero."""
x, y = self
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)
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:
destination: Point where factor would be 1.0.
@@ -159,31 +153,18 @@ class Size(NamedTuple):
@property
def area(self) -> int:
"""Get the area of the size.
Returns:
Area in cells.
"""
"""The area occupied by a region of this size."""
return self.width * self.height
@property
def region(self) -> Region:
"""Get a region of the same size.
Returns:
A region with the same size at (0, 0).
"""
"""A region of the same size, at the origin."""
width, height = self
return Region(0, 0, width, height)
@property
def line_range(self) -> range:
"""Get a range covering lines.
Returns:
A builtin range object.
"""
"""A range object that covers values between 0 and `height`."""
return range(self.height)
def __add__(self, other: object) -> Size:
@@ -327,7 +308,7 @@ class Region(NamedTuple):
Args:
window_region: The window region.
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:
An offset required to add to region to move it inside window_region.
@@ -376,64 +357,43 @@ class Region(NamedTuple):
@property
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.
Returns:
Pair of x coordinates (column numbers).
The end value is *exclusive*.
"""
return (self.x, self.x + self.width)
@property
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.
Returns:
Pair of y coordinates (line numbers).
The end value is *exclusive*.
"""
return (self.y, self.y + self.height)
@property
def right(self) -> int:
"""Maximum X value (non inclusive).
Returns:
x coordinate.
"""
"""Maximum X value (non inclusive)."""
return self.x + self.width
@property
def bottom(self) -> int:
"""Maximum Y value (non inclusive).
Returns:
y coordinate.
"""
"""Maximum Y value (non inclusive)."""
return self.y + self.height
@property
def area(self) -> int:
"""Get the area within the region.
Returns:
Area covered by this region.
"""
"""The are under the region."""
return self.width * self.height
@property
def offset(self) -> Offset:
"""Get the start point of the region.
"""The top left corner of the region.
Returns:
Top left offset.
An offset.
"""
return Offset(*self[:2])
@@ -443,8 +403,7 @@ class Region(NamedTuple):
"""Bottom left offset of the region.
Returns:
Bottom left offset.
An offset.
"""
x, y, _width, height = self
return Offset(x, y + height)
@@ -454,7 +413,7 @@ class Region(NamedTuple):
"""Top right offset of the region.
Returns:
Top right.
An offset.
"""
x, y, width, _height = self
@@ -462,10 +421,10 @@ class Region(NamedTuple):
@property
def bottom_right(self) -> Offset:
"""Bottom right of the region.
"""Bottom right offset of the region.
Returns:
Bottom right.
An offset.
"""
x, y, width, height = self
@@ -473,21 +432,12 @@ class Region(NamedTuple):
@property
def size(self) -> Size:
"""Get the size of the region.
Returns:
Size of the region.
"""
"""Get the size of the region."""
return Size(*self[2:])
@property
def corners(self) -> tuple[int, int, int, int]:
"""Get the top left and bottom right coordinates as a tuple of integers.
Returns:
A tuple of `(<left>, <top>, <right>, <bottom>)`.
"""
"""The top left and bottom right coordinates as a tuple of four integers."""
x, y, width, height = self
return x, y, x + width, y + height
@@ -506,7 +456,7 @@ class Region(NamedTuple):
"""An region of the same size at (0, 0).
Returns:
Reset region.
A region at the origin.
"""
_, _, width, height = self
@@ -897,63 +847,35 @@ class Spacing(NamedTuple):
@property
def width(self) -> int:
"""Total space in width.
Returns:
Width.
"""
"""Total space in the x axis."""
return self.left + self.right
@property
def height(self) -> int:
"""Total space in height.
Returns:
Height.
"""
"""Total space in the y axis."""
return self.top + self.bottom
@property
def top_left(self) -> tuple[int, int]:
"""Top left space.
Returns:
`(<left>, <top>)`
"""
"""A pair of integers for the left, and top space."""
return (self.left, self.top)
@property
def bottom_right(self) -> tuple[int, int]:
"""Bottom right space.
Returns:
`(<right>, <bottom>)`
"""
"""A pair of integers for the right, and bottom space."""
return (self.right, self.bottom)
@property
def totals(self) -> tuple[int, int]:
"""Get total horizontal and vertical space.
Returns:
`(<horizontal>, <vertical>)`
"""
"""A pair of integers for the total horizontal and vertical space."""
top, right, bottom, left = self
return (left + right, top + bottom)
@property
def css(self) -> str:
"""Gets a string containing the spacing in CSS format.
Returns:
Spacing in CSS format.
"""A string containing the spacing in CSS format.
For example: "1" or "2 4" or "4 2 8 2".
"""
top, right, bottom, left = self
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
from logging import Handler, LogRecord

View File

@@ -1,3 +1,10 @@
"""
The base class for all messages (including events).
"""
from __future__ import annotations
from typing import TYPE_CHECKING, ClassVar
@@ -99,7 +106,7 @@ class Message:
Args:
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
return self
@@ -108,7 +115,7 @@ class Message:
"""Stop propagation of the message to parent.
Args:
stop: The stop flag. Defaults to True.
stop: The stop flag.
"""
self._stop_propagation = stop
return self

View File

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

View File

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

View File

@@ -9,7 +9,7 @@ class UnderlineBar:
"""Thin horizontal bar with a portion highlighted.
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.
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.

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 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 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 itertools import chain
@@ -51,7 +57,7 @@ class Strip:
Args:
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__ = [
@@ -117,7 +123,7 @@ class Strip:
Args:
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:
List of strips.
@@ -205,7 +211,7 @@ class Strip:
Args:
cell_length: New desired cell length.
style: Style when extending, or `None`. Defaults to `None`.
style: Style when extending, or `None`.
Returns:
A new strip with the supplied cell length.

View File

@@ -34,11 +34,11 @@ class Timer:
Args:
event_target: The object which will receive the timer events.
interval: The time between timer events, in seconds.
name: A name to assign the event (for debugging). Defaults to None.
callback: A optional callback to invoke when the event is handled. Defaults to None.
repeat: The number of times to repeat the timer, or None to repeat forever. Defaults to None.
skip: Enable skipping of scheduled events that couldn't be sent in time. Defaults to True.
pause: Start the timer paused. Defaults to False.
name: A name to assign the event (for debugging).
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.
skip: Enable skipping of scheduled events that couldn't be sent in time.
pause: Start the timer paused.
"""
_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 collections import deque
@@ -44,8 +53,7 @@ def walk_depth_first(
Args:
root: The root note (starting point).
filter_type: Optional DOMNode subclass to filter by, or ``None`` for no filter.
Defaults to None.
with_root: Include the root in the walk. Defaults to True.
with_root: Include the root in the walk.
Returns:
An iterable of DOMNodes, or the type specified in ``filter_type``.
@@ -106,8 +114,7 @@ def walk_breadth_first(
Args:
root: The root note (starting point).
filter_type: Optional DOMNode subclass to filter by, or ``None`` for no filter.
Defaults to None.
with_root: Include the root in the walk. Defaults to True.
with_root: Include the root in the walk.
Returns:
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 asyncio import Lock, wait
@@ -84,10 +89,12 @@ _JUSTIFY_MAP: dict[str, JustifyMethod] = {
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:
```python
await self.mount(Static("foo"))
```
"""
@@ -164,7 +171,7 @@ class _Styled:
return Measurement.get(console, options, self.renderable)
class RenderCache(NamedTuple):
class _RenderCache(NamedTuple):
"""Stores results of a previous render."""
size: Size
@@ -286,6 +293,15 @@ class Widget(DOMNode):
classes: str | None = None,
disabled: bool = False,
) -> 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._container_size = Size(0, 0)
self._layout_required = False
@@ -302,7 +318,7 @@ class Widget(DOMNode):
self._border_title: 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)
self._dirty_regions: set[Region] = set()
# Regions which need to be transferred from cache to screen
@@ -469,7 +485,6 @@ class Widget(DOMNode):
Args:
id: The ID of the child.
expect_type: Require the object be of the supplied type, or None for any type.
Defaults to None.
Returns:
The first child of this node with the ID.
@@ -1498,11 +1513,11 @@ class Widget(DOMNode):
attribute: Name of the attribute to animate.
value: The value to animate to.
final_value: The final value of the animation. Defaults to `value` if not set.
duration: The duration of the animate. Defaults to None.
speed: The speed of the animation. Defaults to None.
delay: A delay (in seconds) before the animation starts. Defaults to 0.0.
easing: An easing method. Defaults to "in_out_cubic".
on_complete: A callable to invoke when the animation is finished. Defaults to None.
duration: The duration of the animate.
speed: The speed of the animation.
delay: A delay (in seconds) before the animation starts.
easing: An easing method.
on_complete: A callable to invoke when the animation is finished.
"""
if self._animate is None:
@@ -2663,7 +2678,7 @@ class Widget(DOMNode):
)
)
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()
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.
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)

View File

@@ -553,7 +553,7 @@ class Markdown(Widget):
"""A Markdown widget.
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.
id: The ID of the widget in the DOM.
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.
Args:
markdown: String containing Markdown, or None to leave blank. Defaults to None.
show_table_of_contents: Show a table of contents in a sidebar. Defaults to True.
markdown: String containing Markdown, or None to leave blank.
show_table_of_contents: Show a table of contents in a sidebar.
name: The name of the widget.
id: The ID of the widget in the DOM.
classes: The CSS classes of the widget.

View File

@@ -100,7 +100,7 @@ class Placeholder(Widget):
label: The label to identify the placeholder.
If no label is present, uses the placeholder ID instead.
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.
classes: A space separated string with the CSS classes
of the placeholder, if any.

View File

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

View File

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

View File

@@ -127,7 +127,7 @@ class ToggleButton(Static, can_focus=True):
Args:
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?
name: The name of the toggle.
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