Add message when lazy_resolver action has no input, Change ConfirmAction.confirm -> ConfirmAction.never_prompt, Move ConfirmType to action_types.py

This commit is contained in:
2025-07-15 20:00:03 -04:00
parent 68d7d89d64
commit 2288015cf3
5 changed files with 41 additions and 30 deletions

View File

@ -52,3 +52,31 @@ class SelectionReturnType(Enum):
def _missing_(cls, value: object) -> SelectionReturnType: def _missing_(cls, value: object) -> SelectionReturnType:
valid = ", ".join(member.value for member in cls) valid = ", ".join(member.value for member in cls)
raise ValueError(f"Invalid DictReturnType: '{value}'. Must be one of: {valid}") raise ValueError(f"Invalid DictReturnType: '{value}'. Must be one of: {valid}")
class ConfirmType(Enum):
"""Enum for different confirmation types."""
YES_NO = "yes_no"
YES_CANCEL = "yes_cancel"
YES_NO_CANCEL = "yes_no_cancel"
TYPE_WORD = "type_word"
OK_CANCEL = "ok_cancel"
@classmethod
def choices(cls) -> list[ConfirmType]:
"""Return a list of all hook type choices."""
return list(cls)
def __str__(self) -> str:
"""Return the string representation of the confirm type."""
return self.value
@classmethod
def _missing_(cls, value: object) -> ConfirmType:
if isinstance(value, str):
for member in cls:
if member.value == value.lower():
return member
valid = ", ".join(member.value for member in cls)
raise ValueError(f"Invalid ConfirmType: '{value}'. Must be one of: {valid}")

View File

@ -1,11 +1,11 @@
from __future__ import annotations from __future__ import annotations
from enum import Enum
from typing import Any from typing import Any
from prompt_toolkit import PromptSession from prompt_toolkit import PromptSession
from rich.tree import Tree from rich.tree import Tree
from falyx.action.action_types import ConfirmType
from falyx.action.base_action import BaseAction from falyx.action.base_action import BaseAction
from falyx.context import ExecutionContext from falyx.context import ExecutionContext
from falyx.execution_registry import ExecutionRegistry as er from falyx.execution_registry import ExecutionRegistry as er
@ -17,25 +17,6 @@ from falyx.themes import OneColors
from falyx.validators import word_validator, words_validator from falyx.validators import word_validator, words_validator
class ConfirmType(Enum):
"""Enum for different confirmation types."""
YES_NO = "yes_no"
YES_CANCEL = "yes_cancel"
YES_NO_CANCEL = "yes_no_cancel"
TYPE_WORD = "type_word"
OK_CANCEL = "ok_cancel"
@classmethod
def choices(cls) -> list[ConfirmType]:
"""Return a list of all hook type choices."""
return list(cls)
def __str__(self) -> str:
"""Return the string representation of the confirm type."""
return self.value
class ConfirmAction(BaseAction): class ConfirmAction(BaseAction):
""" """
Action to confirm an operation with the user. Action to confirm an operation with the user.
@ -66,7 +47,7 @@ class ConfirmAction(BaseAction):
message: str = "Confirm?", message: str = "Confirm?",
confirm_type: ConfirmType | str = ConfirmType.YES_NO, confirm_type: ConfirmType | str = ConfirmType.YES_NO,
prompt_session: PromptSession | None = None, prompt_session: PromptSession | None = None,
confirm: bool = True, never_prompt: bool = False,
word: str = "CONFIRM", word: str = "CONFIRM",
return_last_result: bool = False, return_last_result: bool = False,
inject_last_result: bool = True, inject_last_result: bool = True,
@ -88,11 +69,11 @@ class ConfirmAction(BaseAction):
name=name, name=name,
inject_last_result=inject_last_result, inject_last_result=inject_last_result,
inject_into=inject_into, inject_into=inject_into,
never_prompt=never_prompt,
) )
self.message = message self.message = message
self.confirm_type = self._coerce_confirm_type(confirm_type) self.confirm_type = self._coerce_confirm_type(confirm_type)
self.prompt_session = prompt_session or PromptSession() self.prompt_session = prompt_session or PromptSession()
self.confirm = confirm
self.word = word self.word = word
self.return_last_result = return_last_result self.return_last_result = return_last_result
@ -165,11 +146,9 @@ class ConfirmAction(BaseAction):
try: try:
await self.hooks.trigger(HookType.BEFORE, context) await self.hooks.trigger(HookType.BEFORE, context)
if ( if (
not self.confirm self.never_prompt
or self.options_manager or self.options_manager
and not should_prompt_user( and not should_prompt_user(confirm=True, options=self.options_manager)
confirm=self.confirm, options=self.options_manager
)
): ):
logger.debug( logger.debug(
"Skipping confirmation for action '%s' as 'confirm' is False or options manager indicates no prompt.", "Skipping confirmation for action '%s' as 'confirm' is False or options manager indicates no prompt.",
@ -209,7 +188,7 @@ class ConfirmAction(BaseAction):
) )
tree.add(f"[bold]Message:[/] {self.message}") tree.add(f"[bold]Message:[/] {self.message}")
tree.add(f"[bold]Type:[/] {self.confirm_type.value}") tree.add(f"[bold]Type:[/] {self.confirm_type.value}")
tree.add(f"[bold]Prompt Required:[/] {'Yes' if self.confirm else 'No'}") tree.add(f"[bold]Prompt Required:[/] {'No' if self.never_prompt else 'Yes'}")
if self.confirm_type == ConfirmType.TYPE_WORD: if self.confirm_type == ConfirmType.TYPE_WORD:
tree.add(f"[bold]Confirmation Word:[/] {self.word}") tree.add(f"[bold]Confirmation Word:[/] {self.word}")
if parent is None: if parent is None:

View File

@ -395,7 +395,7 @@ class CommandArgumentParser:
help: str = "", help: str = "",
dest: str | None = None, dest: str | None = None,
resolver: BaseAction | None = None, resolver: BaseAction | None = None,
lazy_resolver: bool = False, lazy_resolver: bool = True,
) -> None: ) -> None:
"""Add an argument to the parser. """Add an argument to the parser.
For `ArgumentAction.ACTION`, `nargs` and `type` determine how many and what kind For `ArgumentAction.ACTION`, `nargs` and `type` determine how many and what kind
@ -852,6 +852,10 @@ class CommandArgumentParser:
and spec.lazy_resolver and spec.lazy_resolver
and from_validate and from_validate
): ):
if not args:
raise CommandArgumentError(
f"Missing required argument '{spec.dest}': {spec.get_choice_text()}{help_text}"
)
continue # Lazy resolvers are not validated here continue # Lazy resolvers are not validated here
raise CommandArgumentError( raise CommandArgumentError(
f"Missing required argument '{spec.dest}': {spec.get_choice_text()}{help_text}" f"Missing required argument '{spec.dest}': {spec.get_choice_text()}{help_text}"

View File

@ -1 +1 @@
__version__ = "0.1.60" __version__ = "0.1.61"

View File

@ -1,6 +1,6 @@
[tool.poetry] [tool.poetry]
name = "falyx" name = "falyx"
version = "0.1.60" version = "0.1.61"
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"