Add register_teardown, Rename session -> prompt_session, Add sets, tuples to SelectionAction
This commit is contained in:
parent
53729f089f
commit
ad803e01be
|
@ -448,6 +448,8 @@ class ChainedAction(BaseAction, ActionListMixin):
|
||||||
if self.actions and self.auto_inject and not action.inject_last_result:
|
if self.actions and self.auto_inject and not action.inject_last_result:
|
||||||
action.inject_last_result = True
|
action.inject_last_result = True
|
||||||
super().add_action(action)
|
super().add_action(action)
|
||||||
|
if hasattr(action, "register_teardown") and callable(action.register_teardown):
|
||||||
|
action.register_teardown(self.hooks)
|
||||||
|
|
||||||
async def _run(self, *args, **kwargs) -> list[Any]:
|
async def _run(self, *args, **kwargs) -> list[Any]:
|
||||||
if not self.actions:
|
if not self.actions:
|
||||||
|
@ -617,6 +619,22 @@ class ActionGroup(BaseAction, ActionListMixin):
|
||||||
if actions:
|
if actions:
|
||||||
self.set_actions(actions)
|
self.set_actions(actions)
|
||||||
|
|
||||||
|
def _wrap_if_needed(self, action: BaseAction | Any) -> BaseAction:
|
||||||
|
if isinstance(action, BaseAction):
|
||||||
|
return action
|
||||||
|
elif callable(action):
|
||||||
|
return Action(name=action.__name__, action=action)
|
||||||
|
else:
|
||||||
|
raise TypeError(
|
||||||
|
f"ActionGroup only accepts BaseAction or callable, got {type(action).__name__}"
|
||||||
|
)
|
||||||
|
|
||||||
|
def add_action(self, action: BaseAction | Any) -> None:
|
||||||
|
action = self._wrap_if_needed(action)
|
||||||
|
super().add_action(action)
|
||||||
|
if hasattr(action, "register_teardown") and callable(action.register_teardown):
|
||||||
|
action.register_teardown(self.hooks)
|
||||||
|
|
||||||
async def _run(self, *args, **kwargs) -> list[tuple[str, Any]]:
|
async def _run(self, *args, **kwargs) -> list[tuple[str, Any]]:
|
||||||
shared_context = SharedContext(name=self.name, is_parallel=True)
|
shared_context = SharedContext(name=self.name, is_parallel=True)
|
||||||
if self.shared_context:
|
if self.shared_context:
|
||||||
|
|
|
@ -148,7 +148,7 @@ class Falyx:
|
||||||
self.render_menu: Callable[["Falyx"], None] | None = render_menu
|
self.render_menu: Callable[["Falyx"], None] | None = render_menu
|
||||||
self.custom_table: Callable[["Falyx"], Table] | Table | None = custom_table
|
self.custom_table: Callable[["Falyx"], Table] | Table | None = custom_table
|
||||||
self.validate_options(cli_args, options)
|
self.validate_options(cli_args, options)
|
||||||
self._session: PromptSession | None = None
|
self._prompt_session: PromptSession | None = None
|
||||||
|
|
||||||
def validate_options(
|
def validate_options(
|
||||||
self,
|
self,
|
||||||
|
@ -337,11 +337,11 @@ class Falyx:
|
||||||
move_cursor_to_end=True,
|
move_cursor_to_end=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
def _invalidate_session_cache(self):
|
def _invalidate_prompt_session_cache(self):
|
||||||
"""Forces the session to be recreated on the next access."""
|
"""Forces the prompt session to be recreated on the next access."""
|
||||||
if hasattr(self, "session"):
|
if hasattr(self, "prompt_session"):
|
||||||
del self.session
|
del self.prompt_session
|
||||||
self._session = None
|
self._prompt_session = None
|
||||||
|
|
||||||
def add_help_command(self):
|
def add_help_command(self):
|
||||||
"""Adds a help command to the menu if it doesn't already exist."""
|
"""Adds a help command to the menu if it doesn't already exist."""
|
||||||
|
@ -375,7 +375,7 @@ class Falyx:
|
||||||
raise FalyxError(
|
raise FalyxError(
|
||||||
"Bottom bar must be a string, callable, or BottomBar instance."
|
"Bottom bar must be a string, callable, or BottomBar instance."
|
||||||
)
|
)
|
||||||
self._invalidate_session_cache()
|
self._invalidate_prompt_session_cache()
|
||||||
|
|
||||||
def _get_bottom_bar_render(self) -> Callable[[], Any] | str | None:
|
def _get_bottom_bar_render(self) -> Callable[[], Any] | str | None:
|
||||||
"""Returns the bottom bar for the menu."""
|
"""Returns the bottom bar for the menu."""
|
||||||
|
@ -390,10 +390,10 @@ class Falyx:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
@cached_property
|
@cached_property
|
||||||
def session(self) -> PromptSession:
|
def prompt_session(self) -> PromptSession:
|
||||||
"""Returns the prompt session for the menu."""
|
"""Returns the prompt session for the menu."""
|
||||||
if self._session is None:
|
if self._prompt_session is None:
|
||||||
self._session = PromptSession(
|
self._prompt_session = PromptSession(
|
||||||
message=self.prompt,
|
message=self.prompt,
|
||||||
multiline=False,
|
multiline=False,
|
||||||
completer=self._get_completer(),
|
completer=self._get_completer(),
|
||||||
|
@ -402,7 +402,7 @@ class Falyx:
|
||||||
bottom_toolbar=self._get_bottom_bar_render(),
|
bottom_toolbar=self._get_bottom_bar_render(),
|
||||||
key_bindings=self.key_bindings,
|
key_bindings=self.key_bindings,
|
||||||
)
|
)
|
||||||
return self._session
|
return self._prompt_session
|
||||||
|
|
||||||
def register_all_hooks(self, hook_type: HookType, hooks: Hook | list[Hook]) -> None:
|
def register_all_hooks(self, hook_type: HookType, hooks: Hook | list[Hook]) -> None:
|
||||||
"""Registers hooks for all commands in the menu and actions recursively."""
|
"""Registers hooks for all commands in the menu and actions recursively."""
|
||||||
|
@ -717,7 +717,7 @@ class Falyx:
|
||||||
|
|
||||||
async def process_command(self) -> bool:
|
async def process_command(self) -> bool:
|
||||||
"""Processes the action of the selected command."""
|
"""Processes the action of the selected command."""
|
||||||
choice = await self.session.prompt_async()
|
choice = await self.prompt_session.prompt_async()
|
||||||
selected_command = self.get_command(choice)
|
selected_command = self.get_command(choice)
|
||||||
if not selected_command:
|
if not selected_command:
|
||||||
logger.info(f"Invalid command '{choice}'.")
|
logger.info(f"Invalid command '{choice}'.")
|
||||||
|
|
|
@ -15,6 +15,7 @@ from rich.tree import Tree
|
||||||
|
|
||||||
from falyx.action import Action
|
from falyx.action import Action
|
||||||
from falyx.context import ExecutionContext, SharedContext
|
from falyx.context import ExecutionContext, SharedContext
|
||||||
|
from falyx.hook_manager import HookManager, HookType
|
||||||
from falyx.themes.colors import OneColors
|
from falyx.themes.colors import OneColors
|
||||||
from falyx.utils import logger
|
from falyx.utils import logger
|
||||||
|
|
||||||
|
@ -97,7 +98,6 @@ class HTTPAction(Action):
|
||||||
)
|
)
|
||||||
|
|
||||||
async def _request(self, *args, **kwargs) -> dict[str, Any]:
|
async def _request(self, *args, **kwargs) -> dict[str, Any]:
|
||||||
# TODO: Add check for HOOK registration
|
|
||||||
if self.shared_context:
|
if self.shared_context:
|
||||||
context: SharedContext = self.shared_context
|
context: SharedContext = self.shared_context
|
||||||
session = context.get("http_session")
|
session = context.get("http_session")
|
||||||
|
@ -128,6 +128,9 @@ class HTTPAction(Action):
|
||||||
if not self.shared_context:
|
if not self.shared_context:
|
||||||
await session.close()
|
await session.close()
|
||||||
|
|
||||||
|
def register_teardown(self, hooks: HookManager):
|
||||||
|
hooks.register(HookType.ON_TEARDOWN, close_shared_http_session)
|
||||||
|
|
||||||
async def preview(self, parent: Tree | None = None):
|
async def preview(self, parent: Tree | None = None):
|
||||||
label = [
|
label = [
|
||||||
f"[{OneColors.CYAN_b}]🌐 HTTPAction[/] '{self.name}'",
|
f"[{OneColors.CYAN_b}]🌐 HTTPAction[/] '{self.name}'",
|
||||||
|
|
|
@ -33,8 +33,10 @@ async def cleanup():
|
||||||
"""
|
"""
|
||||||
|
|
||||||
GLOBAL_CONFIG = """\
|
GLOBAL_CONFIG = """\
|
||||||
async def cleanup():
|
- key: C
|
||||||
print("🧹 Cleaning temp files...")
|
description: Cleanup temp files
|
||||||
|
action: tasks.cleanup
|
||||||
|
aliases: [clean, cleanup]
|
||||||
"""
|
"""
|
||||||
|
|
||||||
console = Console(color_system="auto")
|
console = Console(color_system="auto")
|
||||||
|
|
|
@ -168,15 +168,13 @@ class MenuAction(BaseAction):
|
||||||
await self.hooks.trigger(HookType.BEFORE, context)
|
await self.hooks.trigger(HookType.BEFORE, context)
|
||||||
key = effective_default
|
key = effective_default
|
||||||
if not self.never_prompt:
|
if not self.never_prompt:
|
||||||
console = self.console
|
|
||||||
session = self.prompt_session
|
|
||||||
table = self._build_table()
|
table = self._build_table()
|
||||||
key = await prompt_for_selection(
|
key = await prompt_for_selection(
|
||||||
self.menu_options.keys(),
|
self.menu_options.keys(),
|
||||||
table,
|
table,
|
||||||
default_selection=self.default_selection,
|
default_selection=self.default_selection,
|
||||||
console=console,
|
console=self.console,
|
||||||
session=session,
|
prompt_session=self.prompt_session,
|
||||||
prompt_message=self.prompt_message,
|
prompt_message=self.prompt_message,
|
||||||
show_table=self.show_table,
|
show_table=self.show_table,
|
||||||
)
|
)
|
||||||
|
|
|
@ -203,17 +203,17 @@ async def prompt_for_index(
|
||||||
min_index: int = 0,
|
min_index: int = 0,
|
||||||
default_selection: str = "",
|
default_selection: str = "",
|
||||||
console: Console | None = None,
|
console: Console | None = None,
|
||||||
session: PromptSession | None = None,
|
prompt_session: PromptSession | None = None,
|
||||||
prompt_message: str = "Select an option > ",
|
prompt_message: str = "Select an option > ",
|
||||||
show_table: bool = True,
|
show_table: bool = True,
|
||||||
):
|
):
|
||||||
session = session or PromptSession()
|
prompt_session = prompt_session or PromptSession()
|
||||||
console = console or Console(color_system="auto")
|
console = console or Console(color_system="auto")
|
||||||
|
|
||||||
if show_table:
|
if show_table:
|
||||||
console.print(table)
|
console.print(table)
|
||||||
|
|
||||||
selection = await session.prompt_async(
|
selection = await prompt_session.prompt_async(
|
||||||
message=prompt_message,
|
message=prompt_message,
|
||||||
validator=int_range_validator(min_index, max_index),
|
validator=int_range_validator(min_index, max_index),
|
||||||
default=default_selection,
|
default=default_selection,
|
||||||
|
@ -226,18 +226,18 @@ async def prompt_for_selection(
|
||||||
table: Table,
|
table: Table,
|
||||||
default_selection: str = "",
|
default_selection: str = "",
|
||||||
console: Console | None = None,
|
console: Console | None = None,
|
||||||
session: PromptSession | None = None,
|
prompt_session: PromptSession | None = None,
|
||||||
prompt_message: str = "Select an option > ",
|
prompt_message: str = "Select an option > ",
|
||||||
show_table: bool = True,
|
show_table: bool = True,
|
||||||
) -> str:
|
) -> str:
|
||||||
"""Prompt the user to select a key from a set of options. Return the selected key."""
|
"""Prompt the user to select a key from a set of options. Return the selected key."""
|
||||||
session = session or PromptSession()
|
prompt_session = prompt_session or PromptSession()
|
||||||
console = console or Console(color_system="auto")
|
console = console or Console(color_system="auto")
|
||||||
|
|
||||||
if show_table:
|
if show_table:
|
||||||
console.print(table, justify="center")
|
console.print(table, justify="center")
|
||||||
|
|
||||||
selected = await session.prompt_async(
|
selected = await prompt_session.prompt_async(
|
||||||
message=prompt_message,
|
message=prompt_message,
|
||||||
validator=key_validator(keys),
|
validator=key_validator(keys),
|
||||||
default=default_selection,
|
default=default_selection,
|
||||||
|
@ -250,7 +250,7 @@ async def select_value_from_list(
|
||||||
title: str,
|
title: str,
|
||||||
selections: Sequence[str],
|
selections: Sequence[str],
|
||||||
console: Console | None = None,
|
console: Console | None = None,
|
||||||
session: PromptSession | None = None,
|
prompt_session: PromptSession | None = None,
|
||||||
prompt_message: str = "Select an option > ",
|
prompt_message: str = "Select an option > ",
|
||||||
default_selection: str = "",
|
default_selection: str = "",
|
||||||
columns: int = 4,
|
columns: int = 4,
|
||||||
|
@ -283,7 +283,7 @@ async def select_value_from_list(
|
||||||
caption_style,
|
caption_style,
|
||||||
highlight,
|
highlight,
|
||||||
)
|
)
|
||||||
session = session or PromptSession()
|
prompt_session = prompt_session or PromptSession()
|
||||||
console = console or Console(color_system="auto")
|
console = console or Console(color_system="auto")
|
||||||
|
|
||||||
selection_index = await prompt_for_index(
|
selection_index = await prompt_for_index(
|
||||||
|
@ -291,7 +291,7 @@ async def select_value_from_list(
|
||||||
table,
|
table,
|
||||||
default_selection=default_selection,
|
default_selection=default_selection,
|
||||||
console=console,
|
console=console,
|
||||||
session=session,
|
prompt_session=prompt_session,
|
||||||
prompt_message=prompt_message,
|
prompt_message=prompt_message,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -302,12 +302,12 @@ 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,
|
||||||
session: PromptSession | None = None,
|
prompt_session: PromptSession | None = None,
|
||||||
prompt_message: str = "Select an option > ",
|
prompt_message: str = "Select an option > ",
|
||||||
default_selection: str = "",
|
default_selection: str = "",
|
||||||
) -> Any:
|
) -> Any:
|
||||||
"""Prompt for a key from a dict, returns the key."""
|
"""Prompt for a key from a dict, returns the key."""
|
||||||
session = session or PromptSession()
|
prompt_session = prompt_session or PromptSession()
|
||||||
console = console or Console(color_system="auto")
|
console = console or Console(color_system="auto")
|
||||||
|
|
||||||
console.print(table)
|
console.print(table)
|
||||||
|
@ -317,7 +317,7 @@ async def select_key_from_dict(
|
||||||
table,
|
table,
|
||||||
default_selection=default_selection,
|
default_selection=default_selection,
|
||||||
console=console,
|
console=console,
|
||||||
session=session,
|
prompt_session=prompt_session,
|
||||||
prompt_message=prompt_message,
|
prompt_message=prompt_message,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -326,12 +326,12 @@ 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,
|
||||||
session: PromptSession | None = None,
|
prompt_session: PromptSession | None = None,
|
||||||
prompt_message: str = "Select an option > ",
|
prompt_message: str = "Select an option > ",
|
||||||
default_selection: str = "",
|
default_selection: str = "",
|
||||||
) -> Any:
|
) -> Any:
|
||||||
"""Prompt for a key from a dict, but return the value."""
|
"""Prompt for a key from a dict, but return the value."""
|
||||||
session = session or PromptSession()
|
prompt_session = prompt_session or PromptSession()
|
||||||
console = console or Console(color_system="auto")
|
console = console or Console(color_system="auto")
|
||||||
|
|
||||||
console.print(table)
|
console.print(table)
|
||||||
|
@ -341,7 +341,7 @@ async def select_value_from_dict(
|
||||||
table,
|
table,
|
||||||
default_selection=default_selection,
|
default_selection=default_selection,
|
||||||
console=console,
|
console=console,
|
||||||
session=session,
|
prompt_session=prompt_session,
|
||||||
prompt_message=prompt_message,
|
prompt_message=prompt_message,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -352,7 +352,7 @@ 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,
|
||||||
session: PromptSession | None = None,
|
prompt_session: PromptSession | None = None,
|
||||||
prompt_message: str = "Select an option > ",
|
prompt_message: str = "Select an option > ",
|
||||||
default_selection: str = "",
|
default_selection: str = "",
|
||||||
):
|
):
|
||||||
|
@ -366,7 +366,7 @@ async def get_selection_from_dict_menu(
|
||||||
selections,
|
selections,
|
||||||
table,
|
table,
|
||||||
console,
|
console,
|
||||||
session,
|
prompt_session,
|
||||||
prompt_message,
|
prompt_message,
|
||||||
default_selection,
|
default_selection,
|
||||||
)
|
)
|
||||||
|
|
|
@ -26,7 +26,7 @@ class SelectionAction(BaseAction):
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
name: str,
|
name: str,
|
||||||
selections: list[str] | dict[str, SelectionOption],
|
selections: list[str] | set[str] | tuple[str, ...] | dict[str, SelectionOption],
|
||||||
*,
|
*,
|
||||||
title: str = "Select an option",
|
title: str = "Select an option",
|
||||||
columns: int = 2,
|
columns: int = 2,
|
||||||
|
@ -36,7 +36,7 @@ class SelectionAction(BaseAction):
|
||||||
inject_last_result_as: str = "last_result",
|
inject_last_result_as: str = "last_result",
|
||||||
return_key: bool = False,
|
return_key: bool = False,
|
||||||
console: Console | None = None,
|
console: Console | None = None,
|
||||||
session: PromptSession | None = None,
|
prompt_session: PromptSession | None = None,
|
||||||
never_prompt: bool = False,
|
never_prompt: bool = False,
|
||||||
show_table: bool = True,
|
show_table: bool = True,
|
||||||
):
|
):
|
||||||
|
@ -51,7 +51,7 @@ class SelectionAction(BaseAction):
|
||||||
self.title = title
|
self.title = title
|
||||||
self.columns = columns
|
self.columns = columns
|
||||||
self.console = console or Console(color_system="auto")
|
self.console = console or Console(color_system="auto")
|
||||||
self.session = session or PromptSession()
|
self.prompt_session = prompt_session or PromptSession()
|
||||||
self.default_selection = default_selection
|
self.default_selection = default_selection
|
||||||
self.prompt_message = prompt_message
|
self.prompt_message = prompt_message
|
||||||
self.show_table = show_table
|
self.show_table = show_table
|
||||||
|
@ -61,9 +61,11 @@ class SelectionAction(BaseAction):
|
||||||
return self._selections
|
return self._selections
|
||||||
|
|
||||||
@selections.setter
|
@selections.setter
|
||||||
def selections(self, value: list[str] | dict[str, SelectionOption]):
|
def selections(
|
||||||
if isinstance(value, list):
|
self, value: list[str] | set[str] | tuple[str, ...] | dict[str, SelectionOption]
|
||||||
self._selections: list[str] | CaseInsensitiveDict = value
|
):
|
||||||
|
if isinstance(value, (list, tuple, set)):
|
||||||
|
self._selections: list[str] | CaseInsensitiveDict = list(value)
|
||||||
elif isinstance(value, dict):
|
elif isinstance(value, dict):
|
||||||
cid = CaseInsensitiveDict()
|
cid = CaseInsensitiveDict()
|
||||||
cid.update(value)
|
cid.update(value)
|
||||||
|
@ -123,7 +125,7 @@ class SelectionAction(BaseAction):
|
||||||
table,
|
table,
|
||||||
default_selection=effective_default,
|
default_selection=effective_default,
|
||||||
console=self.console,
|
console=self.console,
|
||||||
session=self.session,
|
prompt_session=self.prompt_session,
|
||||||
prompt_message=self.prompt_message,
|
prompt_message=self.prompt_message,
|
||||||
show_table=self.show_table,
|
show_table=self.show_table,
|
||||||
)
|
)
|
||||||
|
@ -140,7 +142,7 @@ class SelectionAction(BaseAction):
|
||||||
table,
|
table,
|
||||||
default_selection=effective_default,
|
default_selection=effective_default,
|
||||||
console=self.console,
|
console=self.console,
|
||||||
session=self.session,
|
prompt_session=self.prompt_session,
|
||||||
prompt_message=self.prompt_message,
|
prompt_message=self.prompt_message,
|
||||||
show_table=self.show_table,
|
show_table=self.show_table,
|
||||||
)
|
)
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
__version__ = "0.1.18"
|
__version__ = "0.1.19"
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
[tool.poetry]
|
[tool.poetry]
|
||||||
name = "falyx"
|
name = "falyx"
|
||||||
version = "0.1.18"
|
version = "0.1.19"
|
||||||
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