ConfirmAction message formatting
This commit is contained in:
@ -71,7 +71,7 @@ async def build_chain(dogs: list[Dog]) -> ChainedAction:
|
||||
ConfirmAction(
|
||||
name="test_confirm",
|
||||
message="Do you want to process the dogs?",
|
||||
confirm_type="yes_no",
|
||||
confirm_type="yes_no_cancel",
|
||||
return_last_result=True,
|
||||
inject_into="dogs",
|
||||
),
|
||||
@ -88,6 +88,7 @@ async def build_chain(dogs: list[Dog]) -> ChainedAction:
|
||||
factory = ActionFactory(
|
||||
name="Dog Post Factory",
|
||||
factory=build_chain,
|
||||
preview_kwargs={"dogs": ["Buddy", "Max"]},
|
||||
)
|
||||
|
||||
|
||||
|
@ -56,13 +56,14 @@ class ConfirmAction(BaseAction):
|
||||
prompt_session (PromptSession | None): The session to use for input.
|
||||
confirm (bool): Whether to prompt the user for confirmation.
|
||||
word (str): The word to type for TYPE_WORD confirmation.
|
||||
return_last_result (bool): Whether to return the last result of the action.
|
||||
return_last_result (bool): Whether to return the last result of the action
|
||||
instead of a boolean.
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
name: str,
|
||||
message: str = "Continue",
|
||||
message: str = "Confirm?",
|
||||
confirm_type: ConfirmType | str = ConfirmType.YES_NO,
|
||||
prompt_session: PromptSession | None = None,
|
||||
confirm: bool = True,
|
||||
@ -114,16 +115,19 @@ class ConfirmAction(BaseAction):
|
||||
session=self.prompt_session,
|
||||
)
|
||||
case ConfirmType.YES_NO_CANCEL:
|
||||
error_message = "Enter 'Y', 'y' to confirm, 'N', 'n' to decline, or 'C', 'c' to abort."
|
||||
answer = await self.prompt_session.prompt_async(
|
||||
f"❓ {self.message} ([Y]es, [N]o, or [C]ancel to abort): ",
|
||||
validator=words_validator(["Y", "N", "C"]),
|
||||
f"❓ {self.message} [Y]es, [N]o, or [C]ancel to abort > ",
|
||||
validator=words_validator(
|
||||
["Y", "N", "C"], error_message=error_message
|
||||
),
|
||||
)
|
||||
if answer.upper() == "C":
|
||||
raise CancelSignal(f"Action '{self.name}' was cancelled by the user.")
|
||||
return answer.upper() == "Y"
|
||||
case ConfirmType.TYPE_WORD:
|
||||
answer = await self.prompt_session.prompt_async(
|
||||
f"❓ {self.message} (type '{self.word}' to confirm or N/n): ",
|
||||
f"❓ {self.message} [{self.word}] to confirm or [N/n] > ",
|
||||
validator=word_validator(self.word),
|
||||
)
|
||||
return answer.upper().strip() != "N"
|
||||
@ -138,9 +142,10 @@ class ConfirmAction(BaseAction):
|
||||
raise CancelSignal(f"Action '{self.name}' was cancelled by the user.")
|
||||
return answer
|
||||
case ConfirmType.OK_CANCEL:
|
||||
error_message = "Enter 'O', 'o' to confirm or 'C', 'c' to abort."
|
||||
answer = await self.prompt_session.prompt_async(
|
||||
f"❓ {self.message} ([O]k to continue, [C]ancel to abort): ",
|
||||
validator=words_validator(["O", "C"]),
|
||||
f"❓ {self.message} [O]k to confirm, [C]ancel to abort > ",
|
||||
validator=words_validator(["O", "C"], error_message=error_message),
|
||||
)
|
||||
if answer.upper() == "C":
|
||||
raise CancelSignal(f"Action '{self.name}' was cancelled by the user.")
|
||||
@ -213,5 +218,5 @@ class ConfirmAction(BaseAction):
|
||||
def __str__(self) -> str:
|
||||
return (
|
||||
f"ConfirmAction(name={self.name}, message={self.message}, "
|
||||
f"confirm_type={self.confirm_type})"
|
||||
f"confirm_type={self.confirm_type}, return_last_result={self.return_last_result})"
|
||||
)
|
||||
|
@ -14,7 +14,7 @@ class SignalAction(Action):
|
||||
Useful for exiting a menu, going back, or halting execution gracefully.
|
||||
"""
|
||||
|
||||
def __init__(self, name: str, signal: Exception):
|
||||
def __init__(self, name: str, signal: FlowSignal):
|
||||
self.signal = signal
|
||||
super().__init__(name, action=self.raise_signal)
|
||||
|
||||
|
@ -5,6 +5,7 @@ from typing import Any, Callable
|
||||
|
||||
from prompt_toolkit.formatted_text import HTML, merge_formatted_text
|
||||
from prompt_toolkit.key_binding import KeyBindings
|
||||
from rich.console import Console
|
||||
|
||||
from falyx.console import console
|
||||
from falyx.options_manager import OptionsManager
|
||||
|
@ -1,7 +1,5 @@
|
||||
# Falyx CLI Framework — (c) 2025 rtj.dev LLC — MIT Licensed
|
||||
"""falyx.py
|
||||
|
||||
Main class for constructing and running Falyx CLI menus.
|
||||
"""Main class for constructing and running Falyx CLI menus.
|
||||
|
||||
Falyx provides a structured, customizable interactive menu system
|
||||
for running commands, actions, and workflows. It supports:
|
||||
|
@ -56,6 +56,39 @@ def get_root_parser(
|
||||
allow_abbrev: bool = True,
|
||||
exit_on_error: bool = True,
|
||||
) -> ArgumentParser:
|
||||
"""
|
||||
Construct the root-level ArgumentParser for the Falyx CLI.
|
||||
|
||||
This parser handles global arguments shared across subcommands and can serve
|
||||
as the base parser for the Falyx CLI or standalone applications. It includes
|
||||
options for verbosity, debug logging, and version output.
|
||||
|
||||
Args:
|
||||
prog (str | None): Name of the program (e.g., 'falyx').
|
||||
usage (str | None): Optional custom usage string.
|
||||
description (str | None): Description shown in the CLI help.
|
||||
epilog (str | None): Message displayed at the end of help output.
|
||||
parents (Sequence[ArgumentParser] | None): Optional parent parsers.
|
||||
prefix_chars (str): Characters to denote optional arguments (default: "-").
|
||||
fromfile_prefix_chars (str | None): Prefix to indicate argument file input.
|
||||
argument_default (Any): Global default value for arguments.
|
||||
conflict_handler (str): Strategy to resolve conflicting argument names.
|
||||
add_help (bool): Whether to include help (`-h/--help`) in this parser.
|
||||
allow_abbrev (bool): Allow abbreviated long options.
|
||||
exit_on_error (bool): Exit immediately on error or raise an exception.
|
||||
|
||||
Returns:
|
||||
ArgumentParser: The root parser with global options attached.
|
||||
|
||||
Notes:
|
||||
```
|
||||
Includes the following arguments:
|
||||
--never-prompt : Run in non-interactive mode.
|
||||
-v / --verbose : Enable debug logging.
|
||||
--debug-hooks : Enable hook lifecycle debug logs.
|
||||
--version : Print the Falyx version.
|
||||
```
|
||||
"""
|
||||
parser = ArgumentParser(
|
||||
prog=prog,
|
||||
usage=usage,
|
||||
@ -92,7 +125,30 @@ def get_subparsers(
|
||||
title: str = "Falyx Commands",
|
||||
description: str | None = "Available commands for the Falyx CLI.",
|
||||
) -> _SubParsersAction:
|
||||
"""Create and return a subparsers action for the given parser."""
|
||||
"""
|
||||
Create and return a subparsers object for registering Falyx CLI subcommands.
|
||||
|
||||
This function adds a `subparsers` block to the given root parser, enabling
|
||||
structured subcommands such as `run`, `run-all`, `preview`, etc.
|
||||
|
||||
Args:
|
||||
parser (ArgumentParser): The root parser to attach the subparsers to.
|
||||
title (str): Title used in help output to group subcommands.
|
||||
description (str | None): Optional text describing the group of subcommands.
|
||||
|
||||
Returns:
|
||||
_SubParsersAction: The subparsers object that can be used to add new CLI subcommands.
|
||||
|
||||
Raises:
|
||||
TypeError: If `parser` is not an instance of `ArgumentParser`.
|
||||
|
||||
Example:
|
||||
```python
|
||||
>>> parser = get_root_parser()
|
||||
>>> subparsers = get_subparsers(parser, title="Available Commands")
|
||||
>>> subparsers.add_parser("run", help="Run a Falyx command")
|
||||
```
|
||||
"""
|
||||
if not isinstance(parser, ArgumentParser):
|
||||
raise TypeError("parser must be an instance of ArgumentParser")
|
||||
subparsers = parser.add_subparsers(
|
||||
@ -122,7 +178,54 @@ def get_arg_parsers(
|
||||
root_parser: ArgumentParser | None = None,
|
||||
subparsers: _SubParsersAction | None = None,
|
||||
) -> FalyxParsers:
|
||||
"""Returns the argument parser for the CLI."""
|
||||
"""
|
||||
Create and return the full suite of argument parsers used by the Falyx CLI.
|
||||
|
||||
This function builds the root parser and all subcommand parsers used for structured
|
||||
CLI workflows in Falyx. It supports standard subcommands including `run`, `run-all`,
|
||||
`preview`, `list`, and `version`, and integrates with registered `Command` objects
|
||||
to populate dynamic help and usage documentation.
|
||||
|
||||
Args:
|
||||
prog (str | None): Program name to display in help and usage messages.
|
||||
usage (str | None): Optional usage message to override the default.
|
||||
description (str | None): Description for the CLI root parser.
|
||||
epilog (str | None): Epilog message shown after the help text.
|
||||
parents (Sequence[ArgumentParser] | None): Optional parent parsers.
|
||||
prefix_chars (str): Characters that prefix optional arguments.
|
||||
fromfile_prefix_chars (str | None): Prefix character for reading args from file.
|
||||
argument_default (Any): Default value for arguments if not specified.
|
||||
conflict_handler (str): Strategy for resolving conflicting arguments.
|
||||
add_help (bool): Whether to add the `-h/--help` option to the root parser.
|
||||
allow_abbrev (bool): Whether to allow abbreviated long options.
|
||||
exit_on_error (bool): Whether the parser exits on error or raises.
|
||||
commands (dict[str, Command] | None): Optional dictionary of registered commands
|
||||
to populate help and subcommand descriptions dynamically.
|
||||
root_parser (ArgumentParser | None): Custom root parser to use instead of building one.
|
||||
subparsers (_SubParsersAction | None): Optional existing subparser object to extend.
|
||||
|
||||
Returns:
|
||||
FalyxParsers: A structured container of all parsers, including `run`, `run-all`,
|
||||
`preview`, `list`, `version`, and the root parser.
|
||||
|
||||
Raises:
|
||||
TypeError: If `root_parser` is not an instance of ArgumentParser or
|
||||
`subparsers` is not an instance of _SubParsersAction.
|
||||
|
||||
Example:
|
||||
```python
|
||||
>>> parsers = get_arg_parsers(commands=my_command_dict)
|
||||
>>> args = parsers.root.parse_args()
|
||||
```
|
||||
|
||||
Notes:
|
||||
- This function integrates dynamic command usage and descriptions if the
|
||||
`commands` argument is provided.
|
||||
- The `run` parser supports additional options for retry logic and confirmation
|
||||
prompts.
|
||||
- The `run-all` parser executes all commands matching a tag.
|
||||
- Use `falyx run ?[COMMAND]` from the CLI to preview a command.
|
||||
"""
|
||||
if epilog is None:
|
||||
epilog = f"Tip: Use '{prog} run ?[COMMAND]' to preview any command from the CLI."
|
||||
if root_parser is None:
|
||||
|
@ -44,10 +44,12 @@ def yes_no_validator() -> Validator:
|
||||
return False
|
||||
return True
|
||||
|
||||
return Validator.from_callable(validate, error_message="Enter 'Y' or 'n'.")
|
||||
return Validator.from_callable(validate, error_message="Enter 'Y', 'y' or 'N', 'n'.")
|
||||
|
||||
|
||||
def words_validator(keys: Sequence[str] | KeysView[str]) -> Validator:
|
||||
def words_validator(
|
||||
keys: Sequence[str] | KeysView[str], error_message: str | None = None
|
||||
) -> Validator:
|
||||
"""Validator for specific word inputs."""
|
||||
|
||||
def validate(text: str) -> bool:
|
||||
@ -55,9 +57,10 @@ def words_validator(keys: Sequence[str] | KeysView[str]) -> Validator:
|
||||
return False
|
||||
return True
|
||||
|
||||
return Validator.from_callable(
|
||||
validate, error_message=f"Invalid input. Choices: {{{', '.join(keys)}}}."
|
||||
)
|
||||
if error_message is None:
|
||||
error_message = f"Invalid input. Choices: {{{', '.join(keys)}}}."
|
||||
|
||||
return Validator.from_callable(validate, error_message=error_message)
|
||||
|
||||
|
||||
def word_validator(word: str) -> Validator:
|
||||
@ -68,7 +71,7 @@ def word_validator(word: str) -> Validator:
|
||||
return True
|
||||
return text.upper().strip() == word.upper()
|
||||
|
||||
return Validator.from_callable(validate, error_message=f"Enter '{word}' or 'N'.")
|
||||
return Validator.from_callable(validate, error_message=f"Enter '{word}' or 'N', 'n'.")
|
||||
|
||||
|
||||
class MultiIndexValidator(Validator):
|
||||
|
@ -1 +1 @@
|
||||
__version__ = "0.1.58"
|
||||
__version__ = "0.1.59"
|
||||
|
@ -1,6 +1,6 @@
|
||||
[tool.poetry]
|
||||
name = "falyx"
|
||||
version = "0.1.58"
|
||||
version = "0.1.59"
|
||||
description = "Reliable and introspectable async CLI action framework."
|
||||
authors = ["Roland Thomas Jr <roland@rtj.dev>"]
|
||||
license = "MIT"
|
||||
|
Reference in New Issue
Block a user