Skip to content

Instantly share code, notes, and snippets.

@riziles
Created August 4, 2025 08:18
Show Gist options
  • Select an option

  • Save riziles/32967ce7c2c0c2288f51384ef4b42c98 to your computer and use it in GitHub Desktop.

Select an option

Save riziles/32967ce7c2c0c2288f51384ef4b42c98 to your computer and use it in GitHub Desktop.
Convert Python function to Textual app
"""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