falyx 0.1.26__tar.gz → 0.1.28__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {falyx-0.1.26 → falyx-0.1.28}/PKG-INFO +1 -1
- {falyx-0.1.26 → falyx-0.1.28}/falyx/action/__init__.py +2 -0
- {falyx-0.1.26 → falyx-0.1.28}/falyx/action/action_factory.py +11 -2
- {falyx-0.1.26 → falyx-0.1.28}/falyx/action/menu_action.py +4 -0
- falyx-0.1.28/falyx/action/user_input_action.py +94 -0
- falyx-0.1.28/falyx/argparse.py +596 -0
- {falyx-0.1.26 → falyx-0.1.28}/falyx/command.py +35 -4
- {falyx-0.1.26 → falyx-0.1.28}/falyx/exceptions.py +4 -0
- {falyx-0.1.26 → falyx-0.1.28}/falyx/execution_registry.py +1 -1
- {falyx-0.1.26 → falyx-0.1.28}/falyx/falyx.py +95 -43
- {falyx-0.1.26 → falyx-0.1.28}/falyx/parsers.py +7 -1
- falyx-0.1.28/falyx/protocols.py +17 -0
- {falyx-0.1.26 → falyx-0.1.28}/falyx/signals.py +14 -0
- {falyx-0.1.26 → falyx-0.1.28}/falyx/utils.py +1 -0
- falyx-0.1.28/falyx/version.py +1 -0
- {falyx-0.1.26 → falyx-0.1.28}/pyproject.toml +1 -1
- falyx-0.1.26/falyx/protocols.py +0 -11
- falyx-0.1.26/falyx/version.py +0 -1
- {falyx-0.1.26 → falyx-0.1.28}/LICENSE +0 -0
- {falyx-0.1.26 → falyx-0.1.28}/README.md +0 -0
- {falyx-0.1.26 → falyx-0.1.28}/falyx/.pytyped +0 -0
- {falyx-0.1.26 → falyx-0.1.28}/falyx/__init__.py +0 -0
- {falyx-0.1.26 → falyx-0.1.28}/falyx/__main__.py +0 -0
- {falyx-0.1.26 → falyx-0.1.28}/falyx/action/action.py +0 -0
- {falyx-0.1.26 → falyx-0.1.28}/falyx/action/http_action.py +0 -0
- {falyx-0.1.26 → falyx-0.1.28}/falyx/action/io_action.py +0 -0
- {falyx-0.1.26 → falyx-0.1.28}/falyx/action/select_file_action.py +0 -0
- {falyx-0.1.26 → falyx-0.1.28}/falyx/action/selection_action.py +0 -0
- {falyx-0.1.26 → falyx-0.1.28}/falyx/action/signal_action.py +0 -0
- {falyx-0.1.26 → falyx-0.1.28}/falyx/action/types.py +0 -0
- {falyx-0.1.26 → falyx-0.1.28}/falyx/bottom_bar.py +0 -0
- {falyx-0.1.26 → falyx-0.1.28}/falyx/config.py +0 -0
- {falyx-0.1.26 → falyx-0.1.28}/falyx/config_schema.py +0 -0
- {falyx-0.1.26 → falyx-0.1.28}/falyx/context.py +0 -0
- {falyx-0.1.26 → falyx-0.1.28}/falyx/debug.py +0 -0
- {falyx-0.1.26 → falyx-0.1.28}/falyx/hook_manager.py +0 -0
- {falyx-0.1.26 → falyx-0.1.28}/falyx/hooks.py +0 -0
- {falyx-0.1.26 → falyx-0.1.28}/falyx/init.py +0 -0
- {falyx-0.1.26 → falyx-0.1.28}/falyx/logger.py +0 -0
- {falyx-0.1.26 → falyx-0.1.28}/falyx/menu.py +0 -0
- {falyx-0.1.26 → falyx-0.1.28}/falyx/options_manager.py +0 -0
- {falyx-0.1.26 → falyx-0.1.28}/falyx/prompt_utils.py +0 -0
- {falyx-0.1.26 → falyx-0.1.28}/falyx/retry.py +0 -0
- {falyx-0.1.26 → falyx-0.1.28}/falyx/retry_utils.py +0 -0
- {falyx-0.1.26 → falyx-0.1.28}/falyx/selection.py +0 -0
- {falyx-0.1.26 → falyx-0.1.28}/falyx/tagged_table.py +0 -0
- {falyx-0.1.26 → falyx-0.1.28}/falyx/themes/__init__.py +0 -0
- {falyx-0.1.26 → falyx-0.1.28}/falyx/themes/colors.py +0 -0
- {falyx-0.1.26 → falyx-0.1.28}/falyx/validators.py +0 -0
@@ -21,6 +21,7 @@ from .menu_action import MenuAction
|
|
21
21
|
from .select_file_action import SelectFileAction
|
22
22
|
from .selection_action import SelectionAction
|
23
23
|
from .signal_action import SignalAction
|
24
|
+
from .user_input_action import UserInputAction
|
24
25
|
|
25
26
|
__all__ = [
|
26
27
|
"Action",
|
@@ -38,4 +39,5 @@ __all__ = [
|
|
38
39
|
"SignalAction",
|
39
40
|
"FallbackAction",
|
40
41
|
"LiteralInputAction",
|
42
|
+
"UserInputAction",
|
41
43
|
]
|
@@ -11,6 +11,7 @@ from falyx.hook_manager import HookType
|
|
11
11
|
from falyx.logger import logger
|
12
12
|
from falyx.protocols import ActionFactoryProtocol
|
13
13
|
from falyx.themes import OneColors
|
14
|
+
from falyx.utils import ensure_async
|
14
15
|
|
15
16
|
|
16
17
|
class ActionFactoryAction(BaseAction):
|
@@ -46,6 +47,14 @@ class ActionFactoryAction(BaseAction):
|
|
46
47
|
self.preview_args = preview_args
|
47
48
|
self.preview_kwargs = preview_kwargs or {}
|
48
49
|
|
50
|
+
@property
|
51
|
+
def factory(self) -> ActionFactoryProtocol:
|
52
|
+
return self._factory # type: ignore[return-value]
|
53
|
+
|
54
|
+
@factory.setter
|
55
|
+
def factory(self, value: ActionFactoryProtocol):
|
56
|
+
self._factory = ensure_async(value)
|
57
|
+
|
49
58
|
async def _run(self, *args, **kwargs) -> Any:
|
50
59
|
updated_kwargs = self._maybe_inject_last_result(kwargs)
|
51
60
|
context = ExecutionContext(
|
@@ -57,7 +66,7 @@ class ActionFactoryAction(BaseAction):
|
|
57
66
|
context.start_timer()
|
58
67
|
try:
|
59
68
|
await self.hooks.trigger(HookType.BEFORE, context)
|
60
|
-
generated_action = self.factory(*args, **updated_kwargs)
|
69
|
+
generated_action = await self.factory(*args, **updated_kwargs)
|
61
70
|
if not isinstance(generated_action, BaseAction):
|
62
71
|
raise TypeError(
|
63
72
|
f"[{self.name}] Factory must return a BaseAction, got "
|
@@ -94,7 +103,7 @@ class ActionFactoryAction(BaseAction):
|
|
94
103
|
tree = parent.add(label) if parent else Tree(label)
|
95
104
|
|
96
105
|
try:
|
97
|
-
generated = self.factory(*self.preview_args, **self.preview_kwargs)
|
106
|
+
generated = await self.factory(*self.preview_args, **self.preview_kwargs)
|
98
107
|
if isinstance(generated, BaseAction):
|
99
108
|
await generated.preview(parent=tree)
|
100
109
|
else:
|
@@ -38,6 +38,7 @@ class MenuAction(BaseAction):
|
|
38
38
|
never_prompt: bool = False,
|
39
39
|
include_reserved: bool = True,
|
40
40
|
show_table: bool = True,
|
41
|
+
custom_table: Table | None = None,
|
41
42
|
):
|
42
43
|
super().__init__(
|
43
44
|
name,
|
@@ -54,8 +55,11 @@ class MenuAction(BaseAction):
|
|
54
55
|
self.prompt_session = prompt_session or PromptSession()
|
55
56
|
self.include_reserved = include_reserved
|
56
57
|
self.show_table = show_table
|
58
|
+
self.custom_table = custom_table
|
57
59
|
|
58
60
|
def _build_table(self) -> Table:
|
61
|
+
if self.custom_table:
|
62
|
+
return self.custom_table
|
59
63
|
table = render_table_base(
|
60
64
|
title=self.title,
|
61
65
|
columns=self.columns,
|
@@ -0,0 +1,94 @@
|
|
1
|
+
from prompt_toolkit import PromptSession
|
2
|
+
from prompt_toolkit.validation import Validator
|
3
|
+
from rich.console import Console
|
4
|
+
from rich.tree import Tree
|
5
|
+
|
6
|
+
from falyx.action import BaseAction
|
7
|
+
from falyx.context import ExecutionContext
|
8
|
+
from falyx.execution_registry import ExecutionRegistry as er
|
9
|
+
from falyx.hook_manager import HookType
|
10
|
+
from falyx.themes.colors import OneColors
|
11
|
+
|
12
|
+
|
13
|
+
class UserInputAction(BaseAction):
|
14
|
+
"""
|
15
|
+
Prompts the user for input via PromptSession and returns the result.
|
16
|
+
|
17
|
+
Args:
|
18
|
+
name (str): Action name.
|
19
|
+
prompt_text (str): Prompt text (can include '{last_result}' for interpolation).
|
20
|
+
validator (Validator, optional): Prompt Toolkit validator.
|
21
|
+
console (Console, optional): Rich console for rendering.
|
22
|
+
prompt_session (PromptSession, optional): Reusable prompt session.
|
23
|
+
inject_last_result (bool): Whether to inject last_result into prompt.
|
24
|
+
inject_into (str): Key to use for injection (default: 'last_result').
|
25
|
+
"""
|
26
|
+
|
27
|
+
def __init__(
|
28
|
+
self,
|
29
|
+
name: str,
|
30
|
+
*,
|
31
|
+
prompt_text: str = "Input > ",
|
32
|
+
validator: Validator | None = None,
|
33
|
+
console: Console | None = None,
|
34
|
+
prompt_session: PromptSession | None = None,
|
35
|
+
inject_last_result: bool = False,
|
36
|
+
):
|
37
|
+
super().__init__(
|
38
|
+
name=name,
|
39
|
+
inject_last_result=inject_last_result,
|
40
|
+
)
|
41
|
+
self.prompt_text = prompt_text
|
42
|
+
self.validator = validator
|
43
|
+
self.console = console or Console(color_system="auto")
|
44
|
+
self.prompt_session = prompt_session or PromptSession()
|
45
|
+
|
46
|
+
async def _run(self, *args, **kwargs) -> str:
|
47
|
+
context = ExecutionContext(
|
48
|
+
name=self.name,
|
49
|
+
args=args,
|
50
|
+
kwargs=kwargs,
|
51
|
+
action=self,
|
52
|
+
)
|
53
|
+
context.start_timer()
|
54
|
+
try:
|
55
|
+
await self.hooks.trigger(HookType.BEFORE, context)
|
56
|
+
|
57
|
+
prompt_text = self.prompt_text
|
58
|
+
if self.inject_last_result and self.last_result:
|
59
|
+
prompt_text = prompt_text.format(last_result=self.last_result)
|
60
|
+
|
61
|
+
answer = await self.prompt_session.prompt_async(
|
62
|
+
prompt_text,
|
63
|
+
validator=self.validator,
|
64
|
+
)
|
65
|
+
context.result = answer
|
66
|
+
await self.hooks.trigger(HookType.ON_SUCCESS, context)
|
67
|
+
return answer
|
68
|
+
except Exception as error:
|
69
|
+
context.exception = error
|
70
|
+
await self.hooks.trigger(HookType.ON_ERROR, context)
|
71
|
+
raise
|
72
|
+
finally:
|
73
|
+
context.stop_timer()
|
74
|
+
await self.hooks.trigger(HookType.AFTER, context)
|
75
|
+
await self.hooks.trigger(HookType.ON_TEARDOWN, context)
|
76
|
+
er.record(context)
|
77
|
+
|
78
|
+
async def preview(self, parent: Tree | None = None):
|
79
|
+
label = f"[{OneColors.MAGENTA}]⌨ UserInputAction[/] '{self.name}'"
|
80
|
+
tree = parent.add(label) if parent else Tree(label)
|
81
|
+
|
82
|
+
prompt_text = (
|
83
|
+
self.prompt_text.replace("{last_result}", "<last_result>")
|
84
|
+
if "{last_result}" in self.prompt_text
|
85
|
+
else self.prompt_text
|
86
|
+
)
|
87
|
+
tree.add(f"[dim]Prompt:[/] {prompt_text}")
|
88
|
+
if self.validator:
|
89
|
+
tree.add("[dim]Validator:[/] Yes")
|
90
|
+
if not parent:
|
91
|
+
self.console.print(tree)
|
92
|
+
|
93
|
+
def __str__(self):
|
94
|
+
return f"UserInputAction(name={self.name!r}, prompt={self.prompt!r})"
|