pytermgui
A simple yet powerful TUI framework for your Python (3.7+) applications.
There is a couple of parts that make up this module, all building on top of eachother to achieve the final result. Your usage depends on which part of the library you use. I will provide an example of usage for each.
1""" 2A simple yet powerful TUI framework for your Python (3.7+) applications. 3 4There is a couple of parts that make up this module, all building on top 5of eachother to achieve the final result. Your usage depends on which part 6of the library you use. I will provide an example of usage for each. 7 8.. include:: ../docs/getting_started.md 9""" 10 11# https://github.com/python/mypy/issues/4930 12# mypy: ignore-errors 13 14from __future__ import annotations 15 16import sys 17from typing import Any, Optional 18 19from .animations import * 20from .ansi_interface import * 21from .colors import * 22from .context_managers import alt_buffer, cursor_at, mouse_handler 23from .enums import * 24from .exceptions import * 25from .exporters import * 26from .fancy_repr import * 27from .file_loaders import * 28from .helpers import * 29from .highlighters import * 30from .input import getch, keys 31from .inspector import * 32from .markup import * 33from .prettifiers import * 34from .serializer import * 35from .terminal import * 36from .widgets import * 37from .window_manager import * 38 39# Silence warning if running as standalone module 40if "-m" in sys.argv: # pragma: no cover 41 import warnings 42 43 warnings.filterwarnings("ignore") 44 45__version__ = "7.0.0" 46 47 48def auto(data: Any, **widget_args: Any) -> Optional[Widget | list[Splitter]]: 49 """Creates a widget from specific data structures. 50 51 This conversion includes various widget classes, as well as some shorthands for 52 more complex objects. This method is called implicitly whenever a non-widget is 53 attempted to be added to a Widget. 54 55 56 Args: 57 data: The structure to convert. See below for formats. 58 **widget_args: Arguments passed straight to the widget constructor. 59 60 Returns: 61 The widget or list of widgets created, or None if the passed structure could 62 not be converted. 63 64 <br> 65 <details style="text-align: left"> 66 <summary style="all: revert; cursor: pointer">Data structures:</summary> 67 68 `pytermgui.widgets.base.Label`: 69 70 * Created from `str` 71 * Syntax example: `"Label value"` 72 73 `pytermgui.widgets.extra.Splitter`: 74 75 * Created from `tuple[Any]` 76 * Syntax example: `(YourWidget(), "auto_syntax", ...)` 77 78 `pytermgui.widgets.extra.Splitter` prompt: 79 80 * Created from `dict[Any, Any]` 81 * Syntax example: `{YourWidget(): "auto_syntax"}` 82 83 `pytermgui.widgets.buttons.Button`: 84 85 * Created from `list[str, pytermgui.widgets.buttons.MouseCallback]` 86 * Syntax example: `["Button label", lambda target, caller: ...]` 87 88 `pytermgui.widgets.buttons.Checkbox`: 89 90 * Created from `list[bool, Callable[[bool], Any]]` 91 * Syntax example: `[True, lambda checked: ...]` 92 93 `pytermgui.widgets.buttons.Toggle`: 94 95 * Created from `list[tuple[str, str], Callable[[str], Any]]` 96 * Syntax example: `[("On", "Off"), lambda new_value: ...]` 97 </details> 98 99 Example: 100 101 ```python3 102 from pytermgui import Container 103 form = ( 104 Container(id="form") 105 + "[157 bold]This is a title" 106 + "" 107 + {"[72 italic]Label1": "[210]Button1"} 108 + {"[72 italic]Label2": "[210]Button2"} 109 + {"[72 italic]Label3": "[210]Button3"} 110 + "" 111 + ["Submit", lambda _, button, your_submit_handler(button.parent)] 112 ) 113 ``` 114 """ 115 # In my opinion, returning immediately after construction is much more readable. 116 # pylint: disable=too-many-return-statements 117 118 # Nothing to do. 119 if isinstance(data, Widget): 120 # Set all **widget_args 121 for key, value in widget_args.items(): 122 setattr(data, key, value) 123 124 return data 125 126 # Label 127 if isinstance(data, str): 128 return Label(data, **widget_args) 129 130 # Splitter 131 if isinstance(data, tuple): 132 return Splitter(*data, **widget_args) 133 134 # buttons 135 if isinstance(data, list): 136 label = data[0] 137 onclick = None 138 if len(data) > 1: 139 onclick = data[1] 140 141 # Checkbox 142 if isinstance(label, bool): 143 return Checkbox(onclick, checked=label, **widget_args) 144 145 # Toggle 146 if isinstance(label, tuple): 147 assert len(label) == 2 148 return Toggle(label, onclick, **widget_args) 149 150 return Button(label, onclick, **widget_args) 151 152 # prompt splitter 153 if isinstance(data, dict): 154 rows: list[Splitter] = [] 155 156 for key, value in data.items(): 157 left = auto(key, parent_align=HorizontalAlignment.LEFT) 158 right = auto(value, parent_align=HorizontalAlignment.RIGHT) 159 160 rows.append(Splitter(left, right, **widget_args)) 161 162 if len(rows) == 1: 163 return rows[0] 164 165 return rows 166 167 return None 168 169 170# Alternative binding for the `auto` method 171Widget.from_data = staticmethod(auto)
49def auto(data: Any, **widget_args: Any) -> Optional[Widget | list[Splitter]]: 50 """Creates a widget from specific data structures. 51 52 This conversion includes various widget classes, as well as some shorthands for 53 more complex objects. This method is called implicitly whenever a non-widget is 54 attempted to be added to a Widget. 55 56 57 Args: 58 data: The structure to convert. See below for formats. 59 **widget_args: Arguments passed straight to the widget constructor. 60 61 Returns: 62 The widget or list of widgets created, or None if the passed structure could 63 not be converted. 64 65 <br> 66 <details style="text-align: left"> 67 <summary style="all: revert; cursor: pointer">Data structures:</summary> 68 69 `pytermgui.widgets.base.Label`: 70 71 * Created from `str` 72 * Syntax example: `"Label value"` 73 74 `pytermgui.widgets.extra.Splitter`: 75 76 * Created from `tuple[Any]` 77 * Syntax example: `(YourWidget(), "auto_syntax", ...)` 78 79 `pytermgui.widgets.extra.Splitter` prompt: 80 81 * Created from `dict[Any, Any]` 82 * Syntax example: `{YourWidget(): "auto_syntax"}` 83 84 `pytermgui.widgets.buttons.Button`: 85 86 * Created from `list[str, pytermgui.widgets.buttons.MouseCallback]` 87 * Syntax example: `["Button label", lambda target, caller: ...]` 88 89 `pytermgui.widgets.buttons.Checkbox`: 90 91 * Created from `list[bool, Callable[[bool], Any]]` 92 * Syntax example: `[True, lambda checked: ...]` 93 94 `pytermgui.widgets.buttons.Toggle`: 95 96 * Created from `list[tuple[str, str], Callable[[str], Any]]` 97 * Syntax example: `[("On", "Off"), lambda new_value: ...]` 98 </details> 99 100 Example: 101 102 ```python3 103 from pytermgui import Container 104 form = ( 105 Container(id="form") 106 + "[157 bold]This is a title" 107 + "" 108 + {"[72 italic]Label1": "[210]Button1"} 109 + {"[72 italic]Label2": "[210]Button2"} 110 + {"[72 italic]Label3": "[210]Button3"} 111 + "" 112 + ["Submit", lambda _, button, your_submit_handler(button.parent)] 113 ) 114 ``` 115 """ 116 # In my opinion, returning immediately after construction is much more readable. 117 # pylint: disable=too-many-return-statements 118 119 # Nothing to do. 120 if isinstance(data, Widget): 121 # Set all **widget_args 122 for key, value in widget_args.items(): 123 setattr(data, key, value) 124 125 return data 126 127 # Label 128 if isinstance(data, str): 129 return Label(data, **widget_args) 130 131 # Splitter 132 if isinstance(data, tuple): 133 return Splitter(*data, **widget_args) 134 135 # buttons 136 if isinstance(data, list): 137 label = data[0] 138 onclick = None 139 if len(data) > 1: 140 onclick = data[1] 141 142 # Checkbox 143 if isinstance(label, bool): 144 return Checkbox(onclick, checked=label, **widget_args) 145 146 # Toggle 147 if isinstance(label, tuple): 148 assert len(label) == 2 149 return Toggle(label, onclick, **widget_args) 150 151 return Button(label, onclick, **widget_args) 152 153 # prompt splitter 154 if isinstance(data, dict): 155 rows: list[Splitter] = [] 156 157 for key, value in data.items(): 158 left = auto(key, parent_align=HorizontalAlignment.LEFT) 159 right = auto(value, parent_align=HorizontalAlignment.RIGHT) 160 161 rows.append(Splitter(left, right, **widget_args)) 162 163 if len(rows) == 1: 164 return rows[0] 165 166 return rows 167 168 return None
Creates a widget from specific data structures.
This conversion includes various widget classes, as well as some shorthands for more complex objects. This method is called implicitly whenever a non-widget is attempted to be added to a Widget.
Args
- data: The structure to convert. See below for formats.
- **widget_args: Arguments passed straight to the widget constructor.
Returns
The widget or list of widgets created, or None if the passed structure could not be converted.
Data structures:
- Created from
str
- Syntax example:
"Label value"
pytermgui.widgets.extra.Splitter
:
- Created from
tuple[Any]
- Syntax example:
(YourWidget(), "auto_syntax", ...)
pytermgui.widgets.extra.Splitter
prompt:
- Created from
dict[Any, Any]
- Syntax example:
{YourWidget(): "auto_syntax"}
pytermgui.widgets.buttons.Button
:
- Created from
list[str, pytermgui.widgets.buttons.MouseCallback]
- Syntax example:
["Button label", lambda target, caller: ...]
pytermgui.widgets.buttons.Checkbox
:
- Created from
list[bool, Callable[[bool], Any]]
- Syntax example:
[True, lambda checked: ...]
pytermgui.widgets.buttons.Toggle
:
- Created from
list[tuple[str, str], Callable[[str], Any]]
- Syntax example:
[("On", "Off"), lambda new_value: ...]
Example:
from pytermgui import Container
form = (
Container(id="form")
+ "[157 bold]This is a title"
+ ""
+ {"[72 italic]Label1": "[210]Button1"}
+ {"[72 italic]Label2": "[210]Button2"}
+ {"[72 italic]Label3": "[210]Button3"}
+ ""
+ ["Submit", lambda _, button, your_submit_handler(button.parent)]
)