Created
August 4, 2025 08:18
-
-
Save riziles/32967ce7c2c0c2288f51384ef4b42c98 to your computer and use it in GitHub Desktop.
Convert Python function to Textual app
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| """Stuff.""" | |
| from collections.abc import Callable | |
| from inspect import BoundArguments | |
| import cyclopts | |
| from cyclopts.exceptions import CycloptsError | |
| from cyclopts.help import format_doc, resolve_help_format | |
| from textual.app import App, ComposeResult | |
| from textual.widgets import Button, Input, Label, RichLog | |
| def make_textual(func: Callable) -> None: | |
| """Make it Textual.""" | |
| app = cyclopts.App(default_command=func) | |
| args = app.assemble_argument_collection(parse_docstring=True) | |
| help_format = resolve_help_format([app]) | |
| help_panels = app._assemble_help_panels(None, help_format) # noqa: SLF001 | |
| class UI(App): | |
| """Textual wrapper.""" | |
| CSS_PATH = "dom4.tcss" | |
| def compose(self) -> ComposeResult: | |
| rl = RichLog(id="help") | |
| yield rl | |
| rl.write(format_doc(app, help_format)) | |
| for help_panel in help_panels: | |
| rl.write(help_panel) | |
| for k in args: | |
| if k.index is not None: | |
| yield Label(k.name) | |
| yield Input( | |
| value=str(k.field_info.default) if not k.required else None, | |
| name=k.name, | |
| placeholder="Required", | |
| ) | |
| yield Button("Run") | |
| def validate_inputs(self) -> tuple[Callable, BoundArguments | None]: | |
| """Validate inputs.""" | |
| inputs = self.query(Input) | |
| rl = self.query_one(RichLog) | |
| rl.clear() | |
| args = [] | |
| for k in inputs: | |
| if k.value: | |
| args.append(k.name) | |
| args.append(k.value) | |
| try: | |
| cmd, parsed, _ = app.parse_args( | |
| args, | |
| exit_on_error=False, | |
| print_error=False, | |
| ) | |
| except CycloptsError as e: | |
| rl.write(str(e)) | |
| return (lambda: None), None | |
| else: | |
| return cmd, parsed | |
| def on_button_pressed(self, event: Button.Pressed) -> None: | |
| """Run the app.""" | |
| if event: | |
| cmd, parsed = self.validate_inputs() | |
| if parsed: | |
| self.cmd = cmd | |
| self.args = parsed.arguments | |
| self.exit() | |
| ui = UI() | |
| ui.run() | |
| ui.cmd(**ui.args) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment