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.
Low level
At the base, there is pytermgui.ansi_interface
and pytermgui.input
, handling terminal APIs
for output and input respectively. This is the lowest-level layer of the
library.
import pytermgui as ptg
ptg.set_alt_buffer()
print("This terminal will be discarded on '\n' input.")
while ptg.getch() != "\n":
print("Wrong key.")
ptg.unset_alt_buffer()
Helper level
On top of that, there is the helper layer, including things like pytermgui.helpers
,
pytermgui.context_managers
and the kind. These provide no extra functionality, only
combine functions defined below them in order to make them more usable.
import pytermgui as ptg
text = "This is some \033[1mlong\033[0m and \033[38;5;141mstyled\033[0m text."
for line in ptg.break_line(text, limit=10):
print(line)
High level
Building on all that is the relatively high level pytermgui.widgets
module. This
part uses things from everything defined before it to create a visually
appealing interface system. It introduces a lot of its own APIs and
abstractions, and leaves all the parts below it free of cross-layer
dependencies.
The highest layer of the library is for pytermgui.window_manager
. This layer combines
parts from everything below. It introduces abstractions on top of the pytermgui.widget
system, and creates its own featureset.
import pytermgui as ptg
with ptg.WindowManager() as manager:
manager.add(
ptg.Window()
+ "[141 bold]Title"
+ "[grey italic]body text"
+ ""
+ ["Button"]
)
manager.run()
View Source
""" 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. ## Low level At the base, there is `pytermgui.ansi_interface` and `pytermgui.input`, handling terminal APIs for output and input respectively. This is the lowest-level layer of the library. ```python3 import pytermgui as ptg ptg.set_alt_buffer() print("This terminal will be discarded on '\\n' input.") while ptg.getch() != "\\n": print("Wrong key.") ptg.unset_alt_buffer() ``` <p style="text-align: center"> <img src=https://raw.githubusercontent.com/bczsalba/pytermgui/master/assets/docs/init_low.png style="width: 80%"> </p> ## Helper level On top of that, there is the helper layer, including things like `pytermgui.helpers`, `pytermgui.context_managers` and the kind. These provide no extra functionality, only combine functions defined below them in order to make them more usable. ```python3 import pytermgui as ptg text = "This is some \\033[1mlong\\033[0m and \\033[38;5;141mstyled\\033[0m text." for line in ptg.break_line(text, limit=10): print(line) ``` <p style="text-align: center"> <img src=https://raw.githubusercontent.com/bczsalba/pytermgui/master/assets/docs/init_helper.png style="width: 80%"> </p> ## High level Building on all that is the relatively high level `pytermgui.widgets` module. This part uses things from everything defined before it to create a visually appealing interface system. It introduces a lot of its own APIs and abstractions, and leaves all the parts below it free of cross-layer dependencies. The highest layer of the library is for `pytermgui.window_manager`. This layer combines parts from everything below. It introduces abstractions on top of the `pytermgui.widget` system, and creates its own featureset. ```python3 import pytermgui as ptg with ptg.WindowManager() as manager: manager.add( ptg.Window() + "[141 bold]Title" + "[grey italic]body text" + "" + ["Button"] ) manager.run() ``` <p style="text-align: center"> <img src=https://raw.githubusercontent.com/bczsalba/pytermgui/master/assets/docs/init_high.png style="width: 80%"> </p> """ # https://github.com/python/mypy/issues/4930 # mypy: ignore-errors from __future__ import annotations from typing import Union, Any, Optional from random import shuffle import sys from .enums import * from .parser import * from .widgets import * from .helpers import * from .inspector import * from .serializer import * from .exceptions import * from .file_loaders import * from .ansi_interface import * from .window_manager import * from .input import getch, keys from .context_managers import alt_buffer, cursor_at, mouse_handler # Silence warning if running as standalone module if "-m" in sys.argv: import warnings warnings.filterwarnings("ignore") __version__ = "1.0.0" def auto(data: Any, **widget_args: Any) -> Optional[Widget | list[Splitter]]: """ ### Create widgets from specific data patterns This conversion includes various widget classes, as well as some shorthands for more complex objects. `pytermgui.widgets.base.Label`: * 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: ...]` This method is called implicitly whenever a non-widget is attempted to be added to a Widget. It returns None in case of a failure Example: ```python3 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)] ) ``` """ # In my opinion, returning immediately after construction is much more readable. # pylint: disable=too-many-return-statements # Nothing to do. if isinstance(data, Widget): return data # Label if isinstance(data, str): return Label(data, **widget_args) # Splitter if isinstance(data, tuple): return Splitter(*data, **widget_args) # buttons if isinstance(data, list): label = data[0] onclick = None if len(data) > 1: onclick = data[1] # Checkbox if isinstance(label, bool): return Checkbox(onclick, checked=label, **widget_args) # Toggle if isinstance(label, tuple): assert len(label) == 2 return Toggle(label, onclick, **widget_args) return Button(label, onclick, **widget_args) # prompt splitter if isinstance(data, dict): rows: list[Splitter] = [] for key, value in data.items(): left = auto(key, parent_align=WidgetAlignment.LEFT) right = auto(value, parent_align=WidgetAlignment.RIGHT) rows.append(Splitter(left, right, **widget_args)) if len(rows) == 1: return rows[0] return rows return None # Alternative binding for the `auto` method Widget.from_data = staticmethod(auto)
View Source
def auto(data: Any, **widget_args: Any) -> Optional[Widget | list[Splitter]]: """ ### Create widgets from specific data patterns This conversion includes various widget classes, as well as some shorthands for more complex objects. `pytermgui.widgets.base.Label`: * 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: ...]` This method is called implicitly whenever a non-widget is attempted to be added to a Widget. It returns None in case of a failure Example: ```python3 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)] ) ``` """ # In my opinion, returning immediately after construction is much more readable. # pylint: disable=too-many-return-statements # Nothing to do. if isinstance(data, Widget): return data # Label if isinstance(data, str): return Label(data, **widget_args) # Splitter if isinstance(data, tuple): return Splitter(*data, **widget_args) # buttons if isinstance(data, list): label = data[0] onclick = None if len(data) > 1: onclick = data[1] # Checkbox if isinstance(label, bool): return Checkbox(onclick, checked=label, **widget_args) # Toggle if isinstance(label, tuple): assert len(label) == 2 return Toggle(label, onclick, **widget_args) return Button(label, onclick, **widget_args) # prompt splitter if isinstance(data, dict): rows: list[Splitter] = [] for key, value in data.items(): left = auto(key, parent_align=WidgetAlignment.LEFT) right = auto(value, parent_align=WidgetAlignment.RIGHT) rows.append(Splitter(left, right, **widget_args)) if len(rows) == 1: return rows[0] return rows return None
Create widgets from specific data patterns
This conversion includes various widget classes, as well as some shorthands for more complex objects.
- 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: ...]
This method is called implicitly whenever a non-widget is attempted to be added to a Widget. It returns None in case of a failure
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)]
)