Add help_text to preview, preview to menu, error handling for imports, summary printing for run and run-all, mandatory kwargs for most arguments
This commit is contained in:
parent
9351ae658c
commit
5c09f86b9b
|
@ -14,6 +14,7 @@ from typing import Any
|
||||||
from falyx.config import loader
|
from falyx.config import loader
|
||||||
from falyx.falyx import Falyx
|
from falyx.falyx import Falyx
|
||||||
from falyx.parsers import FalyxParsers, get_arg_parsers
|
from falyx.parsers import FalyxParsers, get_arg_parsers
|
||||||
|
from falyx.themes.colors import OneColors
|
||||||
|
|
||||||
|
|
||||||
def find_falyx_config() -> Path | None:
|
def find_falyx_config() -> Path | None:
|
||||||
|
@ -71,6 +72,7 @@ def run(args: Namespace) -> Any:
|
||||||
title="🛠️ Config-Driven CLI",
|
title="🛠️ Config-Driven CLI",
|
||||||
cli_args=args,
|
cli_args=args,
|
||||||
columns=4,
|
columns=4,
|
||||||
|
prompt=[(OneColors.BLUE_b, "FALYX > ")],
|
||||||
)
|
)
|
||||||
flx.add_commands(loader(bootstrap_path))
|
flx.add_commands(loader(bootstrap_path))
|
||||||
return asyncio.run(flx.run())
|
return asyncio.run(flx.run())
|
||||||
|
|
|
@ -272,15 +272,21 @@ class Command(BaseModel):
|
||||||
if hasattr(self.action, "preview") and callable(self.action.preview):
|
if hasattr(self.action, "preview") and callable(self.action.preview):
|
||||||
tree = Tree(label)
|
tree = Tree(label)
|
||||||
await self.action.preview(parent=tree)
|
await self.action.preview(parent=tree)
|
||||||
|
if self.help_text:
|
||||||
|
tree.add(f"[dim]💡 {self.help_text}[/dim]")
|
||||||
console.print(tree)
|
console.print(tree)
|
||||||
elif callable(self.action) and not isinstance(self.action, BaseAction):
|
elif callable(self.action) and not isinstance(self.action, BaseAction):
|
||||||
console.print(f"{label}")
|
console.print(f"{label}")
|
||||||
|
if self.help_text:
|
||||||
|
console.print(f"[dim]💡 {self.help_text}[/dim]")
|
||||||
console.print(
|
console.print(
|
||||||
f"[{OneColors.LIGHT_RED_b}]→ Would call:[/] {self.action.__name__}"
|
f"[{OneColors.LIGHT_RED_b}]→ Would call:[/] {self.action.__name__}"
|
||||||
f"[dim](args={self.args}, kwargs={self.kwargs})[/dim]"
|
f"[dim](args={self.args}, kwargs={self.kwargs})[/dim]"
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
console.print(f"{label}")
|
console.print(f"{label}")
|
||||||
|
if self.help_text:
|
||||||
|
console.print(f"[dim]💡 {self.help_text}[/dim]")
|
||||||
console.print(
|
console.print(
|
||||||
f"[{OneColors.DARK_RED}]⚠️ Action is not callable or lacks a preview method.[/]"
|
f"[{OneColors.DARK_RED}]⚠️ Action is not callable or lacks a preview method.[/]"
|
||||||
)
|
)
|
||||||
|
|
|
@ -3,15 +3,21 @@
|
||||||
Configuration loader for Falyx CLI commands."""
|
Configuration loader for Falyx CLI commands."""
|
||||||
|
|
||||||
import importlib
|
import importlib
|
||||||
|
import sys
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
import toml
|
import toml
|
||||||
import yaml
|
import yaml
|
||||||
|
from rich.console import Console
|
||||||
|
|
||||||
from falyx.action import Action, BaseAction
|
from falyx.action import Action, BaseAction
|
||||||
from falyx.command import Command
|
from falyx.command import Command
|
||||||
from falyx.retry import RetryPolicy
|
from falyx.retry import RetryPolicy
|
||||||
|
from falyx.themes.colors import OneColors
|
||||||
|
from falyx.utils import logger
|
||||||
|
|
||||||
|
console = Console(color_system="auto")
|
||||||
|
|
||||||
|
|
||||||
def wrap_if_needed(obj: Any, name=None) -> BaseAction | Command:
|
def wrap_if_needed(obj: Any, name=None) -> BaseAction | Command:
|
||||||
|
@ -30,9 +36,28 @@ def import_action(dotted_path: str) -> Any:
|
||||||
"""Dynamically imports a callable from a dotted path like 'my.module.func'."""
|
"""Dynamically imports a callable from a dotted path like 'my.module.func'."""
|
||||||
module_path, _, attr = dotted_path.rpartition(".")
|
module_path, _, attr = dotted_path.rpartition(".")
|
||||||
if not module_path:
|
if not module_path:
|
||||||
raise ValueError(f"Invalid action path: {dotted_path}")
|
console.print(f"[{OneColors.DARK_RED}]❌ Invalid action path:[/] {dotted_path}")
|
||||||
module = importlib.import_module(module_path)
|
sys.exit(1)
|
||||||
return getattr(module, attr)
|
try:
|
||||||
|
module = importlib.import_module(module_path)
|
||||||
|
except ModuleNotFoundError as error:
|
||||||
|
logger.error("Failed to import module '%s': %s", module_path, error)
|
||||||
|
console.print(
|
||||||
|
f"[{OneColors.DARK_RED}]❌ Could not import '{dotted_path}': {error}[/]\n"
|
||||||
|
f"[{OneColors.COMMENT_GREY}]Ensure the module is installed and discoverable via PYTHONPATH."
|
||||||
|
)
|
||||||
|
sys.exit(1)
|
||||||
|
try:
|
||||||
|
action = getattr(module, attr)
|
||||||
|
except AttributeError as error:
|
||||||
|
logger.error(
|
||||||
|
"Module '%s' does not have attribute '%s': %s", module_path, attr, error
|
||||||
|
)
|
||||||
|
console.print(
|
||||||
|
f"[{OneColors.DARK_RED}]❌ Module '{module_path}' has no attribute '{attr}': {error}[/]"
|
||||||
|
)
|
||||||
|
sys.exit(1)
|
||||||
|
return action
|
||||||
|
|
||||||
|
|
||||||
def loader(file_path: Path | str) -> list[dict[str, Any]]:
|
def loader(file_path: Path | str) -> list[dict[str, Any]]:
|
||||||
|
|
|
@ -283,7 +283,7 @@ class Falyx:
|
||||||
self.console.print(table, justify="center")
|
self.console.print(table, justify="center")
|
||||||
if self.mode == FalyxMode.MENU:
|
if self.mode == FalyxMode.MENU:
|
||||||
self.console.print(
|
self.console.print(
|
||||||
f"📦 Tip: Type '[{OneColors.LIGHT_YELLOW}]?[KEY][/]' to preview a command before running it.\n",
|
f"📦 Tip: '[{OneColors.LIGHT_YELLOW}]?[KEY][/]' to preview a command before running it.\n",
|
||||||
justify="center",
|
justify="center",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -343,7 +343,9 @@ class Falyx:
|
||||||
error_message = " ".join(message_lines)
|
error_message = " ".join(message_lines)
|
||||||
|
|
||||||
def validator(text):
|
def validator(text):
|
||||||
_, choice = self.get_command(text, from_validate=True)
|
is_preview, choice = self.get_command(text, from_validate=True)
|
||||||
|
if is_preview and choice is None:
|
||||||
|
return True
|
||||||
return True if choice else False
|
return True if choice else False
|
||||||
|
|
||||||
return Validator.from_callable(
|
return Validator.from_callable(
|
||||||
|
@ -694,6 +696,13 @@ class Falyx:
|
||||||
) -> tuple[bool, Command | None]:
|
) -> tuple[bool, Command | None]:
|
||||||
"""Returns the selected command based on user input. Supports keys, aliases, and abbreviations."""
|
"""Returns the selected command based on user input. Supports keys, aliases, and abbreviations."""
|
||||||
is_preview, choice = self.parse_preview_command(choice)
|
is_preview, choice = self.parse_preview_command(choice)
|
||||||
|
if is_preview and not choice:
|
||||||
|
if not from_validate:
|
||||||
|
self.console.print(
|
||||||
|
f"[{OneColors.DARK_RED}]❌ You must enter a command for preview mode.[/]"
|
||||||
|
)
|
||||||
|
return is_preview, None
|
||||||
|
|
||||||
choice = choice.upper()
|
choice = choice.upper()
|
||||||
name_map = self._name_map
|
name_map = self._name_map
|
||||||
|
|
||||||
|
@ -788,12 +797,17 @@ class Falyx:
|
||||||
async def run_key(self, command_key: str, return_context: bool = False) -> Any:
|
async def run_key(self, command_key: str, return_context: bool = False) -> Any:
|
||||||
"""Run a command by key without displaying the menu (non-interactive mode)."""
|
"""Run a command by key without displaying the menu (non-interactive mode)."""
|
||||||
self.debug_hooks()
|
self.debug_hooks()
|
||||||
_, selected_command = self.get_command(command_key)
|
is_preview, selected_command = self.get_command(command_key)
|
||||||
self.last_run_command = selected_command
|
self.last_run_command = selected_command
|
||||||
|
|
||||||
if not selected_command:
|
if not selected_command:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
if is_preview:
|
||||||
|
logger.info(f"Preview command '{selected_command.key}' selected.")
|
||||||
|
await selected_command.preview()
|
||||||
|
return None
|
||||||
|
|
||||||
logger.info(
|
logger.info(
|
||||||
"[run_key] 🚀 Executing: %s — %s",
|
"[run_key] 🚀 Executing: %s — %s",
|
||||||
selected_command.key,
|
selected_command.key,
|
||||||
|
@ -943,11 +957,14 @@ class Falyx:
|
||||||
|
|
||||||
if self.cli_args.command == "run":
|
if self.cli_args.command == "run":
|
||||||
self.mode = FalyxMode.RUN
|
self.mode = FalyxMode.RUN
|
||||||
_, command = self.get_command(self.cli_args.name)
|
is_preview, command = self.get_command(self.cli_args.name)
|
||||||
|
if is_preview:
|
||||||
|
if command is None:
|
||||||
|
sys.exit(1)
|
||||||
|
logger.info(f"Preview command '{command.key}' selected.")
|
||||||
|
await command.preview()
|
||||||
|
sys.exit(0)
|
||||||
if not command:
|
if not command:
|
||||||
self.console.print(
|
|
||||||
f"[{OneColors.DARK_RED}]❌ Command '{self.cli_args.name}' not found.[/]"
|
|
||||||
)
|
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
self._set_retry_policy(command)
|
self._set_retry_policy(command)
|
||||||
try:
|
try:
|
||||||
|
@ -955,6 +972,9 @@ class Falyx:
|
||||||
except FalyxError as error:
|
except FalyxError as error:
|
||||||
self.console.print(f"[{OneColors.DARK_RED}]❌ Error: {error}[/]")
|
self.console.print(f"[{OneColors.DARK_RED}]❌ Error: {error}[/]")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
|
if self.cli_args.summary:
|
||||||
|
er.summary()
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
|
|
||||||
if self.cli_args.command == "run-all":
|
if self.cli_args.command == "run-all":
|
||||||
|
@ -976,6 +996,10 @@ class Falyx:
|
||||||
for cmd in matching:
|
for cmd in matching:
|
||||||
self._set_retry_policy(cmd)
|
self._set_retry_policy(cmd)
|
||||||
await self.run_key(cmd.key)
|
await self.run_key(cmd.key)
|
||||||
|
|
||||||
|
if self.cli_args.summary:
|
||||||
|
er.summary()
|
||||||
|
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
|
|
||||||
await self.menu()
|
await self.menu()
|
||||||
|
|
|
@ -59,6 +59,7 @@ class BaseIOAction(BaseAction):
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
name: str,
|
name: str,
|
||||||
|
*,
|
||||||
hooks: HookManager | None = None,
|
hooks: HookManager | None = None,
|
||||||
mode: str = "buffered",
|
mode: str = "buffered",
|
||||||
logging_hooks: bool = True,
|
logging_hooks: bool = True,
|
||||||
|
|
|
@ -36,7 +36,9 @@ def get_arg_parsers(
|
||||||
prog: str | None = "falyx",
|
prog: str | None = "falyx",
|
||||||
usage: str | None = None,
|
usage: str | None = None,
|
||||||
description: str | None = "Falyx CLI - Run structured async command workflows.",
|
description: str | None = "Falyx CLI - Run structured async command workflows.",
|
||||||
epilog: str | None = None,
|
epilog: (
|
||||||
|
str | None
|
||||||
|
) = "Tip: Use 'falyx run ?[COMMAND]' to preview any command from the CLI.",
|
||||||
parents: Sequence[ArgumentParser] = [],
|
parents: Sequence[ArgumentParser] = [],
|
||||||
prefix_chars: str = "-",
|
prefix_chars: str = "-",
|
||||||
fromfile_prefix_chars: str | None = None,
|
fromfile_prefix_chars: str | None = None,
|
||||||
|
@ -79,6 +81,11 @@ def get_arg_parsers(
|
||||||
|
|
||||||
run_parser = subparsers.add_parser("run", help="Run a specific command")
|
run_parser = subparsers.add_parser("run", help="Run a specific command")
|
||||||
run_parser.add_argument("name", help="Key, alias, or description of the command")
|
run_parser.add_argument("name", help="Key, alias, or description of the command")
|
||||||
|
run_parser.add_argument(
|
||||||
|
"--summary",
|
||||||
|
action="store_true",
|
||||||
|
help="Print an execution summary after command completes",
|
||||||
|
)
|
||||||
run_parser.add_argument(
|
run_parser.add_argument(
|
||||||
"--retries", type=int, help="Number of retries on failure", default=0
|
"--retries", type=int, help="Number of retries on failure", default=0
|
||||||
)
|
)
|
||||||
|
@ -111,6 +118,11 @@ def get_arg_parsers(
|
||||||
"run-all", help="Run all commands with a given tag"
|
"run-all", help="Run all commands with a given tag"
|
||||||
)
|
)
|
||||||
run_all_parser.add_argument("-t", "--tag", required=True, help="Tag to match")
|
run_all_parser.add_argument("-t", "--tag", required=True, help="Tag to match")
|
||||||
|
run_all_parser.add_argument(
|
||||||
|
"--summary",
|
||||||
|
action="store_true",
|
||||||
|
help="Print a summary after all tagged commands run",
|
||||||
|
)
|
||||||
run_all_parser.add_argument(
|
run_all_parser.add_argument(
|
||||||
"--retries", type=int, help="Number of retries on failure", default=0
|
"--retries", type=int, help="Number of retries on failure", default=0
|
||||||
)
|
)
|
||||||
|
|
|
@ -137,7 +137,9 @@ class SelectFileAction(BaseAction):
|
||||||
|
|
||||||
options = self.get_options(files)
|
options = self.get_options(files)
|
||||||
|
|
||||||
table = render_selection_dict_table(self.title, options, self.columns)
|
table = render_selection_dict_table(
|
||||||
|
title=self.title, selections=options, columns=self.columns
|
||||||
|
)
|
||||||
|
|
||||||
key = await prompt_for_selection(
|
key = await prompt_for_selection(
|
||||||
options.keys(),
|
options.keys(),
|
||||||
|
|
|
@ -31,6 +31,7 @@ class SelectionOption:
|
||||||
|
|
||||||
def render_table_base(
|
def render_table_base(
|
||||||
title: str,
|
title: str,
|
||||||
|
*,
|
||||||
caption: str = "",
|
caption: str = "",
|
||||||
columns: int = 4,
|
columns: int = 4,
|
||||||
box_style: box.Box = box.SIMPLE,
|
box_style: box.Box = box.SIMPLE,
|
||||||
|
@ -71,6 +72,7 @@ def render_table_base(
|
||||||
def render_selection_grid(
|
def render_selection_grid(
|
||||||
title: str,
|
title: str,
|
||||||
selections: Sequence[str],
|
selections: Sequence[str],
|
||||||
|
*,
|
||||||
columns: int = 4,
|
columns: int = 4,
|
||||||
caption: str = "",
|
caption: str = "",
|
||||||
box_style: box.Box = box.SIMPLE,
|
box_style: box.Box = box.SIMPLE,
|
||||||
|
@ -86,19 +88,19 @@ def render_selection_grid(
|
||||||
) -> Table:
|
) -> Table:
|
||||||
"""Create a selection table with the given parameters."""
|
"""Create a selection table with the given parameters."""
|
||||||
table = render_table_base(
|
table = render_table_base(
|
||||||
title,
|
title=title,
|
||||||
caption,
|
caption=caption,
|
||||||
columns,
|
columns=columns,
|
||||||
box_style,
|
box_style=box_style,
|
||||||
show_lines,
|
show_lines=show_lines,
|
||||||
show_header,
|
show_header=show_header,
|
||||||
show_footer,
|
show_footer=show_footer,
|
||||||
style,
|
style=style,
|
||||||
header_style,
|
header_style=header_style,
|
||||||
footer_style,
|
footer_style=footer_style,
|
||||||
title_style,
|
title_style=title_style,
|
||||||
caption_style,
|
caption_style=caption_style,
|
||||||
highlight,
|
highlight=highlight,
|
||||||
)
|
)
|
||||||
|
|
||||||
for chunk in chunks(selections, columns):
|
for chunk in chunks(selections, columns):
|
||||||
|
@ -110,6 +112,7 @@ def render_selection_grid(
|
||||||
def render_selection_indexed_table(
|
def render_selection_indexed_table(
|
||||||
title: str,
|
title: str,
|
||||||
selections: Sequence[str],
|
selections: Sequence[str],
|
||||||
|
*,
|
||||||
columns: int = 4,
|
columns: int = 4,
|
||||||
caption: str = "",
|
caption: str = "",
|
||||||
box_style: box.Box = box.SIMPLE,
|
box_style: box.Box = box.SIMPLE,
|
||||||
|
@ -126,19 +129,19 @@ def render_selection_indexed_table(
|
||||||
) -> Table:
|
) -> Table:
|
||||||
"""Create a selection table with the given parameters."""
|
"""Create a selection table with the given parameters."""
|
||||||
table = render_table_base(
|
table = render_table_base(
|
||||||
title,
|
title=title,
|
||||||
caption,
|
caption=caption,
|
||||||
columns,
|
columns=columns,
|
||||||
box_style,
|
box_style=box_style,
|
||||||
show_lines,
|
show_lines=show_lines,
|
||||||
show_header,
|
show_header=show_header,
|
||||||
show_footer,
|
show_footer=show_footer,
|
||||||
style,
|
style=style,
|
||||||
header_style,
|
header_style=header_style,
|
||||||
footer_style,
|
footer_style=footer_style,
|
||||||
title_style,
|
title_style=title_style,
|
||||||
caption_style,
|
caption_style=caption_style,
|
||||||
highlight,
|
highlight=highlight,
|
||||||
)
|
)
|
||||||
|
|
||||||
for indexes, chunk in zip(
|
for indexes, chunk in zip(
|
||||||
|
@ -156,6 +159,7 @@ def render_selection_indexed_table(
|
||||||
def render_selection_dict_table(
|
def render_selection_dict_table(
|
||||||
title: str,
|
title: str,
|
||||||
selections: dict[str, SelectionOption],
|
selections: dict[str, SelectionOption],
|
||||||
|
*,
|
||||||
columns: int = 2,
|
columns: int = 2,
|
||||||
caption: str = "",
|
caption: str = "",
|
||||||
box_style: box.Box = box.SIMPLE,
|
box_style: box.Box = box.SIMPLE,
|
||||||
|
@ -171,19 +175,19 @@ def render_selection_dict_table(
|
||||||
) -> Table:
|
) -> Table:
|
||||||
"""Create a selection table with the given parameters."""
|
"""Create a selection table with the given parameters."""
|
||||||
table = render_table_base(
|
table = render_table_base(
|
||||||
title,
|
title=title,
|
||||||
caption,
|
caption=caption,
|
||||||
columns,
|
columns=columns,
|
||||||
box_style,
|
box_style=box_style,
|
||||||
show_lines,
|
show_lines=show_lines,
|
||||||
show_header,
|
show_header=show_header,
|
||||||
show_footer,
|
show_footer=show_footer,
|
||||||
style,
|
style=style,
|
||||||
header_style,
|
header_style=header_style,
|
||||||
footer_style,
|
footer_style=footer_style,
|
||||||
title_style,
|
title_style=title_style,
|
||||||
caption_style,
|
caption_style=caption_style,
|
||||||
highlight,
|
highlight=highlight,
|
||||||
)
|
)
|
||||||
|
|
||||||
for chunk in chunks(selections.items(), columns):
|
for chunk in chunks(selections.items(), columns):
|
||||||
|
@ -200,6 +204,7 @@ def render_selection_dict_table(
|
||||||
async def prompt_for_index(
|
async def prompt_for_index(
|
||||||
max_index: int,
|
max_index: int,
|
||||||
table: Table,
|
table: Table,
|
||||||
|
*,
|
||||||
min_index: int = 0,
|
min_index: int = 0,
|
||||||
default_selection: str = "",
|
default_selection: str = "",
|
||||||
console: Console | None = None,
|
console: Console | None = None,
|
||||||
|
@ -224,6 +229,7 @@ async def prompt_for_index(
|
||||||
async def prompt_for_selection(
|
async def prompt_for_selection(
|
||||||
keys: Sequence[str] | KeysView[str],
|
keys: Sequence[str] | KeysView[str],
|
||||||
table: Table,
|
table: Table,
|
||||||
|
*,
|
||||||
default_selection: str = "",
|
default_selection: str = "",
|
||||||
console: Console | None = None,
|
console: Console | None = None,
|
||||||
prompt_session: PromptSession | None = None,
|
prompt_session: PromptSession | None = None,
|
||||||
|
@ -249,6 +255,7 @@ async def prompt_for_selection(
|
||||||
async def select_value_from_list(
|
async def select_value_from_list(
|
||||||
title: str,
|
title: str,
|
||||||
selections: Sequence[str],
|
selections: Sequence[str],
|
||||||
|
*,
|
||||||
console: Console | None = None,
|
console: Console | None = None,
|
||||||
prompt_session: PromptSession | None = None,
|
prompt_session: PromptSession | None = None,
|
||||||
prompt_message: str = "Select an option > ",
|
prompt_message: str = "Select an option > ",
|
||||||
|
@ -268,20 +275,20 @@ async def select_value_from_list(
|
||||||
):
|
):
|
||||||
"""Prompt for a selection. Return the selected item."""
|
"""Prompt for a selection. Return the selected item."""
|
||||||
table = render_selection_indexed_table(
|
table = render_selection_indexed_table(
|
||||||
title,
|
title=title,
|
||||||
selections,
|
selections=selections,
|
||||||
columns,
|
columns=columns,
|
||||||
caption,
|
caption=caption,
|
||||||
box_style,
|
box_style=box_style,
|
||||||
show_lines,
|
show_lines=show_lines,
|
||||||
show_header,
|
show_header=show_header,
|
||||||
show_footer,
|
show_footer=show_footer,
|
||||||
style,
|
style=style,
|
||||||
header_style,
|
header_style=header_style,
|
||||||
footer_style,
|
footer_style=footer_style,
|
||||||
title_style,
|
title_style=title_style,
|
||||||
caption_style,
|
caption_style=caption_style,
|
||||||
highlight,
|
highlight=highlight,
|
||||||
)
|
)
|
||||||
prompt_session = prompt_session or PromptSession()
|
prompt_session = prompt_session or PromptSession()
|
||||||
console = console or Console(color_system="auto")
|
console = console or Console(color_system="auto")
|
||||||
|
@ -301,6 +308,7 @@ async def select_value_from_list(
|
||||||
async def select_key_from_dict(
|
async def select_key_from_dict(
|
||||||
selections: dict[str, SelectionOption],
|
selections: dict[str, SelectionOption],
|
||||||
table: Table,
|
table: Table,
|
||||||
|
*,
|
||||||
console: Console | None = None,
|
console: Console | None = None,
|
||||||
prompt_session: PromptSession | None = None,
|
prompt_session: PromptSession | None = None,
|
||||||
prompt_message: str = "Select an option > ",
|
prompt_message: str = "Select an option > ",
|
||||||
|
@ -325,6 +333,7 @@ async def select_key_from_dict(
|
||||||
async def select_value_from_dict(
|
async def select_value_from_dict(
|
||||||
selections: dict[str, SelectionOption],
|
selections: dict[str, SelectionOption],
|
||||||
table: Table,
|
table: Table,
|
||||||
|
*,
|
||||||
console: Console | None = None,
|
console: Console | None = None,
|
||||||
prompt_session: PromptSession | None = None,
|
prompt_session: PromptSession | None = None,
|
||||||
prompt_message: str = "Select an option > ",
|
prompt_message: str = "Select an option > ",
|
||||||
|
@ -351,6 +360,7 @@ async def select_value_from_dict(
|
||||||
async def get_selection_from_dict_menu(
|
async def get_selection_from_dict_menu(
|
||||||
title: str,
|
title: str,
|
||||||
selections: dict[str, SelectionOption],
|
selections: dict[str, SelectionOption],
|
||||||
|
*,
|
||||||
console: Console | None = None,
|
console: Console | None = None,
|
||||||
prompt_session: PromptSession | None = None,
|
prompt_session: PromptSession | None = None,
|
||||||
prompt_message: str = "Select an option > ",
|
prompt_message: str = "Select an option > ",
|
||||||
|
@ -363,10 +373,10 @@ async def get_selection_from_dict_menu(
|
||||||
)
|
)
|
||||||
|
|
||||||
return await select_value_from_dict(
|
return await select_value_from_dict(
|
||||||
selections,
|
selections=selections,
|
||||||
table,
|
table=table,
|
||||||
console,
|
console=console,
|
||||||
prompt_session,
|
prompt_session=prompt_session,
|
||||||
prompt_message,
|
prompt_message=prompt_message,
|
||||||
default_selection,
|
default_selection=default_selection,
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
# Falyx CLI Framework — (c) 2025 rtj.dev LLC — MIT Licensed
|
# Falyx CLI Framework — (c) 2025 rtj.dev LLC — MIT Licensed
|
||||||
"""selection_action.py"""
|
"""selection_action.py"""
|
||||||
from pathlib import Path
|
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
from prompt_toolkit import PromptSession
|
from prompt_toolkit import PromptSession
|
||||||
|
@ -117,7 +116,9 @@ class SelectionAction(BaseAction):
|
||||||
await self.hooks.trigger(HookType.BEFORE, context)
|
await self.hooks.trigger(HookType.BEFORE, context)
|
||||||
if isinstance(self.selections, list):
|
if isinstance(self.selections, list):
|
||||||
table = render_selection_indexed_table(
|
table = render_selection_indexed_table(
|
||||||
self.title, self.selections, self.columns
|
title=self.title,
|
||||||
|
selections=self.selections,
|
||||||
|
columns=self.columns,
|
||||||
)
|
)
|
||||||
if not self.never_prompt:
|
if not self.never_prompt:
|
||||||
index = await prompt_for_index(
|
index = await prompt_for_index(
|
||||||
|
@ -134,7 +135,7 @@ class SelectionAction(BaseAction):
|
||||||
result = self.selections[int(index)]
|
result = self.selections[int(index)]
|
||||||
elif isinstance(self.selections, dict):
|
elif isinstance(self.selections, dict):
|
||||||
table = render_selection_dict_table(
|
table = render_selection_dict_table(
|
||||||
self.title, self.selections, self.columns
|
title=self.title, selections=self.selections, columns=self.columns
|
||||||
)
|
)
|
||||||
if not self.never_prompt:
|
if not self.never_prompt:
|
||||||
key = await prompt_for_selection(
|
key = await prompt_for_selection(
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
__version__ = "0.1.21"
|
__version__ = "0.1.22"
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
[tool.poetry]
|
[tool.poetry]
|
||||||
name = "falyx"
|
name = "falyx"
|
||||||
version = "0.1.21"
|
version = "0.1.22"
|
||||||
description = "Reliable and introspectable async CLI action framework."
|
description = "Reliable and introspectable async CLI action framework."
|
||||||
authors = ["Roland Thomas Jr <roland@rtj.dev>"]
|
authors = ["Roland Thomas Jr <roland@rtj.dev>"]
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
|
|
Loading…
Reference in New Issue