falyx 0.1.19__tar.gz → 0.1.20__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.19 → falyx-0.1.20}/PKG-INFO +1 -1
- {falyx-0.1.19 → falyx-0.1.20}/falyx/action.py +22 -24
- falyx-0.1.20/falyx/action_factory.py +95 -0
- {falyx-0.1.19 → falyx-0.1.20}/falyx/falyx.py +40 -9
- {falyx-0.1.19 → falyx-0.1.20}/falyx/http_action.py +4 -4
- {falyx-0.1.19 → falyx-0.1.20}/falyx/io_action.py +3 -3
- {falyx-0.1.19 → falyx-0.1.20}/falyx/menu_action.py +2 -2
- falyx-0.1.20/falyx/protocols.py +9 -0
- {falyx-0.1.19 → falyx-0.1.20}/falyx/selection_action.py +2 -2
- falyx-0.1.20/falyx/version.py +1 -0
- {falyx-0.1.19 → falyx-0.1.20}/pyproject.toml +1 -1
- falyx-0.1.19/falyx/action_factory.py +0 -23
- falyx-0.1.19/falyx/version.py +0 -1
- {falyx-0.1.19 → falyx-0.1.20}/LICENSE +0 -0
- {falyx-0.1.19 → falyx-0.1.20}/README.md +0 -0
- {falyx-0.1.19 → falyx-0.1.20}/falyx/.pytyped +0 -0
- {falyx-0.1.19 → falyx-0.1.20}/falyx/__init__.py +0 -0
- {falyx-0.1.19 → falyx-0.1.20}/falyx/__main__.py +0 -0
- {falyx-0.1.19 → falyx-0.1.20}/falyx/bottom_bar.py +0 -0
- {falyx-0.1.19 → falyx-0.1.20}/falyx/command.py +0 -0
- {falyx-0.1.19 → falyx-0.1.20}/falyx/config.py +0 -0
- {falyx-0.1.19 → falyx-0.1.20}/falyx/context.py +0 -0
- {falyx-0.1.19 → falyx-0.1.20}/falyx/debug.py +0 -0
- {falyx-0.1.19 → falyx-0.1.20}/falyx/exceptions.py +0 -0
- {falyx-0.1.19 → falyx-0.1.20}/falyx/execution_registry.py +0 -0
- {falyx-0.1.19 → falyx-0.1.20}/falyx/hook_manager.py +0 -0
- {falyx-0.1.19 → falyx-0.1.20}/falyx/hooks.py +0 -0
- {falyx-0.1.19 → falyx-0.1.20}/falyx/init.py +0 -0
- {falyx-0.1.19 → falyx-0.1.20}/falyx/options_manager.py +0 -0
- {falyx-0.1.19 → falyx-0.1.20}/falyx/parsers.py +0 -0
- {falyx-0.1.19 → falyx-0.1.20}/falyx/prompt_utils.py +0 -0
- {falyx-0.1.19 → falyx-0.1.20}/falyx/retry.py +0 -0
- {falyx-0.1.19 → falyx-0.1.20}/falyx/retry_utils.py +0 -0
- {falyx-0.1.19 → falyx-0.1.20}/falyx/select_files_action.py +0 -0
- {falyx-0.1.19 → falyx-0.1.20}/falyx/selection.py +0 -0
- {falyx-0.1.19 → falyx-0.1.20}/falyx/signal_action.py +0 -0
- {falyx-0.1.19 → falyx-0.1.20}/falyx/signals.py +0 -0
- {falyx-0.1.19 → falyx-0.1.20}/falyx/tagged_table.py +0 -0
- {falyx-0.1.19 → falyx-0.1.20}/falyx/themes/colors.py +0 -0
- {falyx-0.1.19 → falyx-0.1.20}/falyx/utils.py +0 -0
- {falyx-0.1.19 → falyx-0.1.20}/falyx/validators.py +0 -0
@@ -56,7 +56,7 @@ class BaseAction(ABC):
|
|
56
56
|
be run independently or as part of Falyx.
|
57
57
|
|
58
58
|
inject_last_result (bool): Whether to inject the previous action's result into kwargs.
|
59
|
-
|
59
|
+
inject_into (str): The name of the kwarg key to inject the result as
|
60
60
|
(default: 'last_result').
|
61
61
|
_requires_injection (bool): Whether the action requires input injection.
|
62
62
|
"""
|
@@ -66,7 +66,7 @@ class BaseAction(ABC):
|
|
66
66
|
name: str,
|
67
67
|
hooks: HookManager | None = None,
|
68
68
|
inject_last_result: bool = False,
|
69
|
-
|
69
|
+
inject_into: str = "last_result",
|
70
70
|
never_prompt: bool = False,
|
71
71
|
logging_hooks: bool = False,
|
72
72
|
) -> None:
|
@@ -75,7 +75,7 @@ class BaseAction(ABC):
|
|
75
75
|
self.is_retryable: bool = False
|
76
76
|
self.shared_context: SharedContext | None = None
|
77
77
|
self.inject_last_result: bool = inject_last_result
|
78
|
-
self.
|
78
|
+
self.inject_into: str = inject_into
|
79
79
|
self._never_prompt: bool = never_prompt
|
80
80
|
self._requires_injection: bool = False
|
81
81
|
self._skip_in_chain: bool = False
|
@@ -133,7 +133,7 @@ class BaseAction(ABC):
|
|
133
133
|
|
134
134
|
def _maybe_inject_last_result(self, kwargs: dict[str, Any]) -> dict[str, Any]:
|
135
135
|
if self.inject_last_result and self.shared_context:
|
136
|
-
key = self.
|
136
|
+
key = self.inject_into
|
137
137
|
if key in kwargs:
|
138
138
|
logger.warning("[%s] ⚠️ Overriding '%s' with last_result", self.name, key)
|
139
139
|
kwargs = dict(kwargs)
|
@@ -173,7 +173,7 @@ class Action(BaseAction):
|
|
173
173
|
kwargs (dict, optional): Static keyword arguments.
|
174
174
|
hooks (HookManager, optional): Hook manager for lifecycle events.
|
175
175
|
inject_last_result (bool, optional): Enable last_result injection.
|
176
|
-
|
176
|
+
inject_into (str, optional): Name of injected key.
|
177
177
|
retry (bool, optional): Enable retry logic.
|
178
178
|
retry_policy (RetryPolicy, optional): Retry settings.
|
179
179
|
"""
|
@@ -187,11 +187,11 @@ class Action(BaseAction):
|
|
187
187
|
kwargs: dict[str, Any] | None = None,
|
188
188
|
hooks: HookManager | None = None,
|
189
189
|
inject_last_result: bool = False,
|
190
|
-
|
190
|
+
inject_into: str = "last_result",
|
191
191
|
retry: bool = False,
|
192
192
|
retry_policy: RetryPolicy | None = None,
|
193
193
|
) -> None:
|
194
|
-
super().__init__(name, hooks, inject_last_result,
|
194
|
+
super().__init__(name, hooks, inject_last_result, inject_into)
|
195
195
|
self.action = action
|
196
196
|
self.rollback = rollback
|
197
197
|
self.args = args
|
@@ -257,7 +257,7 @@ class Action(BaseAction):
|
|
257
257
|
if context.result is not None:
|
258
258
|
logger.info("[%s] ✅ Recovered: %s", self.name, self.name)
|
259
259
|
return context.result
|
260
|
-
raise
|
260
|
+
raise
|
261
261
|
finally:
|
262
262
|
context.stop_timer()
|
263
263
|
await self.hooks.trigger(HookType.AFTER, context)
|
@@ -267,7 +267,7 @@ class Action(BaseAction):
|
|
267
267
|
async def preview(self, parent: Tree | None = None):
|
268
268
|
label = [f"[{OneColors.GREEN_b}]⚙ Action[/] '{self.name}'"]
|
269
269
|
if self.inject_last_result:
|
270
|
-
label.append(f" [dim](injects '{self.
|
270
|
+
label.append(f" [dim](injects '{self.inject_into}')[/dim]")
|
271
271
|
if self.retry_policy.enabled:
|
272
272
|
label.append(
|
273
273
|
f"\n[dim]↻ Retries:[/] {self.retry_policy.max_retries}x, "
|
@@ -413,7 +413,7 @@ class ChainedAction(BaseAction, ActionListMixin):
|
|
413
413
|
actions (list): List of actions or literals to execute.
|
414
414
|
hooks (HookManager, optional): Hooks for lifecycle events.
|
415
415
|
inject_last_result (bool, optional): Whether to inject last results into kwargs by default.
|
416
|
-
|
416
|
+
inject_into (str, optional): Key name for injection.
|
417
417
|
auto_inject (bool, optional): Auto-enable injection for subsequent actions.
|
418
418
|
return_list (bool, optional): Whether to return a list of all results. False returns the last result.
|
419
419
|
"""
|
@@ -424,11 +424,11 @@ class ChainedAction(BaseAction, ActionListMixin):
|
|
424
424
|
actions: list[BaseAction | Any] | None = None,
|
425
425
|
hooks: HookManager | None = None,
|
426
426
|
inject_last_result: bool = False,
|
427
|
-
|
427
|
+
inject_into: str = "last_result",
|
428
428
|
auto_inject: bool = False,
|
429
429
|
return_list: bool = False,
|
430
430
|
) -> None:
|
431
|
-
super().__init__(name, hooks, inject_last_result,
|
431
|
+
super().__init__(name, hooks, inject_last_result, inject_into)
|
432
432
|
ActionListMixin.__init__(self)
|
433
433
|
self.auto_inject = auto_inject
|
434
434
|
self.return_list = return_list
|
@@ -482,9 +482,7 @@ class ChainedAction(BaseAction, ActionListMixin):
|
|
482
482
|
last_result = shared_context.last_result()
|
483
483
|
try:
|
484
484
|
if self.requires_io_injection() and last_result is not None:
|
485
|
-
result = await prepared(
|
486
|
-
**{prepared.inject_last_result_as: last_result}
|
487
|
-
)
|
485
|
+
result = await prepared(**{prepared.inject_into: last_result})
|
488
486
|
else:
|
489
487
|
result = await prepared(*args, **updated_kwargs)
|
490
488
|
except Exception as error:
|
@@ -559,7 +557,7 @@ class ChainedAction(BaseAction, ActionListMixin):
|
|
559
557
|
async def preview(self, parent: Tree | None = None):
|
560
558
|
label = [f"[{OneColors.CYAN_b}]⛓ ChainedAction[/] '{self.name}'"]
|
561
559
|
if self.inject_last_result:
|
562
|
-
label.append(f" [dim](injects '{self.
|
560
|
+
label.append(f" [dim](injects '{self.inject_into}')[/dim]")
|
563
561
|
tree = parent.add("".join(label)) if parent else Tree("".join(label))
|
564
562
|
for action in self.actions:
|
565
563
|
await action.preview(parent=tree)
|
@@ -603,7 +601,7 @@ class ActionGroup(BaseAction, ActionListMixin):
|
|
603
601
|
actions (list): List of actions or literals to execute.
|
604
602
|
hooks (HookManager, optional): Hooks for lifecycle events.
|
605
603
|
inject_last_result (bool, optional): Whether to inject last results into kwargs by default.
|
606
|
-
|
604
|
+
inject_into (str, optional): Key name for injection.
|
607
605
|
"""
|
608
606
|
|
609
607
|
def __init__(
|
@@ -612,9 +610,9 @@ class ActionGroup(BaseAction, ActionListMixin):
|
|
612
610
|
actions: list[BaseAction] | None = None,
|
613
611
|
hooks: HookManager | None = None,
|
614
612
|
inject_last_result: bool = False,
|
615
|
-
|
613
|
+
inject_into: str = "last_result",
|
616
614
|
):
|
617
|
-
super().__init__(name, hooks, inject_last_result,
|
615
|
+
super().__init__(name, hooks, inject_last_result, inject_into)
|
618
616
|
ActionListMixin.__init__(self)
|
619
617
|
if actions:
|
620
618
|
self.set_actions(actions)
|
@@ -694,7 +692,7 @@ class ActionGroup(BaseAction, ActionListMixin):
|
|
694
692
|
async def preview(self, parent: Tree | None = None):
|
695
693
|
label = [f"[{OneColors.MAGENTA_b}]⏩ ActionGroup (parallel)[/] '{self.name}'"]
|
696
694
|
if self.inject_last_result:
|
697
|
-
label.append(f" [dim](receives '{self.
|
695
|
+
label.append(f" [dim](receives '{self.inject_into}')[/dim]")
|
698
696
|
tree = parent.add("".join(label)) if parent else Tree("".join(label))
|
699
697
|
actions = self.actions.copy()
|
700
698
|
random.shuffle(actions)
|
@@ -726,7 +724,7 @@ class ProcessAction(BaseAction):
|
|
726
724
|
hooks (HookManager, optional): Hook manager for lifecycle events.
|
727
725
|
executor (ProcessPoolExecutor, optional): Custom executor if desired.
|
728
726
|
inject_last_result (bool, optional): Inject last result into the function.
|
729
|
-
|
727
|
+
inject_into (str, optional): Name of the injected key.
|
730
728
|
"""
|
731
729
|
|
732
730
|
def __init__(
|
@@ -738,9 +736,9 @@ class ProcessAction(BaseAction):
|
|
738
736
|
hooks: HookManager | None = None,
|
739
737
|
executor: ProcessPoolExecutor | None = None,
|
740
738
|
inject_last_result: bool = False,
|
741
|
-
|
739
|
+
inject_into: str = "last_result",
|
742
740
|
):
|
743
|
-
super().__init__(name, hooks, inject_last_result,
|
741
|
+
super().__init__(name, hooks, inject_last_result, inject_into)
|
744
742
|
self.func = func
|
745
743
|
self.args = args
|
746
744
|
self.kwargs = kwargs or {}
|
@@ -800,7 +798,7 @@ class ProcessAction(BaseAction):
|
|
800
798
|
f"[{OneColors.DARK_YELLOW_b}]🧠 ProcessAction (new process)[/] '{self.name}'"
|
801
799
|
]
|
802
800
|
if self.inject_last_result:
|
803
|
-
label.append(f" [dim](injects '{self.
|
801
|
+
label.append(f" [dim](injects '{self.inject_into}')[/dim]")
|
804
802
|
if parent:
|
805
803
|
parent.add("".join(label))
|
806
804
|
else:
|
@@ -0,0 +1,95 @@
|
|
1
|
+
from typing import Any
|
2
|
+
|
3
|
+
from rich.tree import Tree
|
4
|
+
|
5
|
+
from falyx.action import BaseAction
|
6
|
+
from falyx.context import ExecutionContext
|
7
|
+
from falyx.execution_registry import ExecutionRegistry as er
|
8
|
+
from falyx.hook_manager import HookType
|
9
|
+
from falyx.protocols import ActionFactoryProtocol
|
10
|
+
from falyx.themes.colors import OneColors
|
11
|
+
|
12
|
+
|
13
|
+
class ActionFactoryAction(BaseAction):
|
14
|
+
"""
|
15
|
+
Dynamically creates and runs another Action at runtime using a factory function.
|
16
|
+
|
17
|
+
This is useful for generating context-specific behavior (e.g., dynamic HTTPActions)
|
18
|
+
where the structure of the next action depends on runtime values.
|
19
|
+
|
20
|
+
Args:
|
21
|
+
name (str): Name of the action.
|
22
|
+
factory (Callable): A function that returns a BaseAction given args/kwargs.
|
23
|
+
inject_last_result (bool): Whether to inject last_result into the factory.
|
24
|
+
inject_into (str): The name of the kwarg to inject last_result as.
|
25
|
+
"""
|
26
|
+
|
27
|
+
def __init__(
|
28
|
+
self,
|
29
|
+
name: str,
|
30
|
+
factory: ActionFactoryProtocol,
|
31
|
+
*,
|
32
|
+
inject_last_result: bool = False,
|
33
|
+
inject_into: str = "last_result",
|
34
|
+
preview_args: tuple[Any, ...] = (),
|
35
|
+
preview_kwargs: dict[str, Any] = {},
|
36
|
+
):
|
37
|
+
super().__init__(
|
38
|
+
name=name,
|
39
|
+
inject_last_result=inject_last_result,
|
40
|
+
inject_into=inject_into,
|
41
|
+
)
|
42
|
+
self.factory = factory
|
43
|
+
self.preview_args = preview_args
|
44
|
+
self.preview_kwargs = preview_kwargs
|
45
|
+
|
46
|
+
async def _run(self, *args, **kwargs) -> Any:
|
47
|
+
updated_kwargs = self._maybe_inject_last_result(kwargs)
|
48
|
+
context = ExecutionContext(
|
49
|
+
name=f"{self.name} (factory)",
|
50
|
+
args=args,
|
51
|
+
kwargs=updated_kwargs,
|
52
|
+
action=self,
|
53
|
+
)
|
54
|
+
context.start_timer()
|
55
|
+
try:
|
56
|
+
await self.hooks.trigger(HookType.BEFORE, context)
|
57
|
+
generated_action = self.factory(*args, **updated_kwargs)
|
58
|
+
if not isinstance(generated_action, BaseAction):
|
59
|
+
raise TypeError(
|
60
|
+
f"[{self.name}] Factory must return a BaseAction, got {type(generated_action).__name__}"
|
61
|
+
)
|
62
|
+
if self.shared_context:
|
63
|
+
generated_action.set_shared_context(self.shared_context)
|
64
|
+
if self.options_manager:
|
65
|
+
generated_action.set_options_manager(self.options_manager)
|
66
|
+
context.result = await generated_action(*args, **kwargs)
|
67
|
+
await self.hooks.trigger(HookType.ON_SUCCESS, context)
|
68
|
+
return context.result
|
69
|
+
except Exception as error:
|
70
|
+
context.exception = error
|
71
|
+
await self.hooks.trigger(HookType.ON_ERROR, context)
|
72
|
+
raise
|
73
|
+
finally:
|
74
|
+
context.stop_timer()
|
75
|
+
await self.hooks.trigger(HookType.AFTER, context)
|
76
|
+
await self.hooks.trigger(HookType.ON_TEARDOWN, context)
|
77
|
+
er.record(context)
|
78
|
+
|
79
|
+
async def preview(self, parent: Tree | None = None):
|
80
|
+
label = f"[{OneColors.CYAN_b}]🏗️ ActionFactory[/] '{self.name}'"
|
81
|
+
tree = parent.add(label) if parent else Tree(label)
|
82
|
+
|
83
|
+
try:
|
84
|
+
generated = self.factory(*self.preview_args, **self.preview_kwargs)
|
85
|
+
if isinstance(generated, BaseAction):
|
86
|
+
await generated.preview(parent=tree)
|
87
|
+
else:
|
88
|
+
tree.add(
|
89
|
+
f"[{OneColors.DARK_RED}]⚠️ Factory did not return a BaseAction[/]"
|
90
|
+
)
|
91
|
+
except Exception as error:
|
92
|
+
tree.add(f"[{OneColors.DARK_RED}]⚠️ Preview failed: {error}[/]")
|
93
|
+
|
94
|
+
if not parent:
|
95
|
+
self.console.print(tree)
|
@@ -24,6 +24,7 @@ import logging
|
|
24
24
|
import sys
|
25
25
|
from argparse import Namespace
|
26
26
|
from difflib import get_close_matches
|
27
|
+
from enum import Enum
|
27
28
|
from functools import cached_property
|
28
29
|
from typing import Any, Callable
|
29
30
|
|
@@ -59,6 +60,13 @@ from falyx.utils import CaseInsensitiveDict, chunks, get_program_invocation, log
|
|
59
60
|
from falyx.version import __version__
|
60
61
|
|
61
62
|
|
63
|
+
class FalyxMode(str, Enum):
|
64
|
+
MENU = "menu"
|
65
|
+
RUN = "run"
|
66
|
+
PREVIEW = "preview"
|
67
|
+
RUN_ALL = "run-all"
|
68
|
+
|
69
|
+
|
62
70
|
class Falyx:
|
63
71
|
"""
|
64
72
|
Main menu controller for Falyx CLI applications.
|
@@ -149,6 +157,7 @@ class Falyx:
|
|
149
157
|
self.custom_table: Callable[["Falyx"], Table] | Table | None = custom_table
|
150
158
|
self.validate_options(cli_args, options)
|
151
159
|
self._prompt_session: PromptSession | None = None
|
160
|
+
self.mode = FalyxMode.MENU
|
152
161
|
|
153
162
|
def validate_options(
|
154
163
|
self,
|
@@ -272,6 +281,11 @@ class Falyx:
|
|
272
281
|
)
|
273
282
|
|
274
283
|
self.console.print(table, justify="center")
|
284
|
+
if self.mode == FalyxMode.MENU:
|
285
|
+
self.console.print(
|
286
|
+
f"📦 Tip: Type '[{OneColors.LIGHT_YELLOW}]?[KEY][/]' to preview a command before running it.\n",
|
287
|
+
justify="center",
|
288
|
+
)
|
275
289
|
|
276
290
|
def _get_help_command(self) -> Command:
|
277
291
|
"""Returns the help command for the menu."""
|
@@ -329,7 +343,8 @@ class Falyx:
|
|
329
343
|
error_message = " ".join(message_lines)
|
330
344
|
|
331
345
|
def validator(text):
|
332
|
-
|
346
|
+
_, choice = self.get_command(text, from_validate=True)
|
347
|
+
return True if choice else False
|
333
348
|
|
334
349
|
return Validator.from_callable(
|
335
350
|
validator,
|
@@ -668,17 +683,25 @@ class Falyx:
|
|
668
683
|
else:
|
669
684
|
return self.build_default_table()
|
670
685
|
|
671
|
-
def
|
686
|
+
def parse_preview_command(self, input_str: str) -> tuple[bool, str]:
|
687
|
+
if input_str.startswith("?"):
|
688
|
+
return True, input_str[1:].strip()
|
689
|
+
return False, input_str.strip()
|
690
|
+
|
691
|
+
def get_command(
|
692
|
+
self, choice: str, from_validate=False
|
693
|
+
) -> tuple[bool, Command | None]:
|
672
694
|
"""Returns the selected command based on user input. Supports keys, aliases, and abbreviations."""
|
695
|
+
is_preview, choice = self.parse_preview_command(choice)
|
673
696
|
choice = choice.upper()
|
674
697
|
name_map = self._name_map
|
675
698
|
|
676
699
|
if choice in name_map:
|
677
|
-
return name_map[choice]
|
700
|
+
return is_preview, name_map[choice]
|
678
701
|
|
679
702
|
prefix_matches = [cmd for key, cmd in name_map.items() if key.startswith(choice)]
|
680
703
|
if len(prefix_matches) == 1:
|
681
|
-
return prefix_matches[0]
|
704
|
+
return is_preview, prefix_matches[0]
|
682
705
|
|
683
706
|
fuzzy_matches = get_close_matches(choice, list(name_map.keys()), n=3, cutoff=0.7)
|
684
707
|
if fuzzy_matches:
|
@@ -694,7 +717,7 @@ class Falyx:
|
|
694
717
|
self.console.print(
|
695
718
|
f"[{OneColors.LIGHT_YELLOW}]⚠️ Unknown command '{choice}'[/]"
|
696
719
|
)
|
697
|
-
return None
|
720
|
+
return is_preview, None
|
698
721
|
|
699
722
|
def _create_context(self, selected_command: Command) -> ExecutionContext:
|
700
723
|
"""Creates a context dictionary for the selected command."""
|
@@ -718,11 +741,16 @@ class Falyx:
|
|
718
741
|
async def process_command(self) -> bool:
|
719
742
|
"""Processes the action of the selected command."""
|
720
743
|
choice = await self.prompt_session.prompt_async()
|
721
|
-
selected_command = self.get_command(choice)
|
744
|
+
is_preview, selected_command = self.get_command(choice)
|
722
745
|
if not selected_command:
|
723
746
|
logger.info(f"Invalid command '{choice}'.")
|
724
747
|
return True
|
725
748
|
|
749
|
+
if is_preview:
|
750
|
+
logger.info(f"Preview command '{selected_command.key}' selected.")
|
751
|
+
await selected_command.preview()
|
752
|
+
return True
|
753
|
+
|
726
754
|
if selected_command.requires_input:
|
727
755
|
program = get_program_invocation()
|
728
756
|
self.console.print(
|
@@ -759,7 +787,7 @@ class Falyx:
|
|
759
787
|
async def run_key(self, command_key: str, return_context: bool = False) -> Any:
|
760
788
|
"""Run a command by key without displaying the menu (non-interactive mode)."""
|
761
789
|
self.debug_hooks()
|
762
|
-
selected_command = self.get_command(command_key)
|
790
|
+
_, selected_command = self.get_command(command_key)
|
763
791
|
self.last_run_command = selected_command
|
764
792
|
|
765
793
|
if not selected_command:
|
@@ -899,7 +927,8 @@ class Falyx:
|
|
899
927
|
sys.exit(0)
|
900
928
|
|
901
929
|
if self.cli_args.command == "preview":
|
902
|
-
|
930
|
+
self.mode = FalyxMode.PREVIEW
|
931
|
+
_, command = self.get_command(self.cli_args.name)
|
903
932
|
if not command:
|
904
933
|
self.console.print(
|
905
934
|
f"[{OneColors.DARK_RED}]❌ Command '{self.cli_args.name}' not found.[/]"
|
@@ -912,7 +941,8 @@ class Falyx:
|
|
912
941
|
sys.exit(0)
|
913
942
|
|
914
943
|
if self.cli_args.command == "run":
|
915
|
-
|
944
|
+
self.mode = FalyxMode.RUN
|
945
|
+
_, command = self.get_command(self.cli_args.name)
|
916
946
|
if not command:
|
917
947
|
self.console.print(
|
918
948
|
f"[{OneColors.DARK_RED}]❌ Command '{self.cli_args.name}' not found.[/]"
|
@@ -927,6 +957,7 @@ class Falyx:
|
|
927
957
|
sys.exit(0)
|
928
958
|
|
929
959
|
if self.cli_args.command == "run-all":
|
960
|
+
self.mode = FalyxMode.RUN_ALL
|
930
961
|
matching = [
|
931
962
|
cmd
|
932
963
|
for cmd in self.commands.values()
|
@@ -56,7 +56,7 @@ class HTTPAction(Action):
|
|
56
56
|
data (Any, optional): Raw data or form-encoded body.
|
57
57
|
hooks (HookManager, optional): Hook manager for lifecycle events.
|
58
58
|
inject_last_result (bool): Enable last_result injection.
|
59
|
-
|
59
|
+
inject_into (str): Name of injected key.
|
60
60
|
retry (bool): Enable retry logic.
|
61
61
|
retry_policy (RetryPolicy): Retry settings.
|
62
62
|
"""
|
@@ -74,7 +74,7 @@ class HTTPAction(Action):
|
|
74
74
|
data: Any = None,
|
75
75
|
hooks=None,
|
76
76
|
inject_last_result: bool = False,
|
77
|
-
|
77
|
+
inject_into: str = "last_result",
|
78
78
|
retry: bool = False,
|
79
79
|
retry_policy=None,
|
80
80
|
):
|
@@ -92,7 +92,7 @@ class HTTPAction(Action):
|
|
92
92
|
kwargs={},
|
93
93
|
hooks=hooks,
|
94
94
|
inject_last_result=inject_last_result,
|
95
|
-
|
95
|
+
inject_into=inject_into,
|
96
96
|
retry=retry,
|
97
97
|
retry_policy=retry_policy,
|
98
98
|
)
|
@@ -138,7 +138,7 @@ class HTTPAction(Action):
|
|
138
138
|
f"\n[dim]URL:[/] {self.url}",
|
139
139
|
]
|
140
140
|
if self.inject_last_result:
|
141
|
-
label.append(f"\n[dim]Injects:[/] '{self.
|
141
|
+
label.append(f"\n[dim]Injects:[/] '{self.inject_into}'")
|
142
142
|
if self.retry_policy and self.retry_policy.enabled:
|
143
143
|
label.append(
|
144
144
|
f"\n[dim]↻ Retries:[/] {self.retry_policy.max_retries}x, "
|
@@ -83,7 +83,7 @@ class BaseIOAction(BaseAction):
|
|
83
83
|
raise NotImplementedError
|
84
84
|
|
85
85
|
async def _resolve_input(self, kwargs: dict[str, Any]) -> str | bytes:
|
86
|
-
last_result = kwargs.pop(self.
|
86
|
+
last_result = kwargs.pop(self.inject_into, None)
|
87
87
|
|
88
88
|
data = await self._read_stdin()
|
89
89
|
if data:
|
@@ -168,7 +168,7 @@ class BaseIOAction(BaseAction):
|
|
168
168
|
async def preview(self, parent: Tree | None = None):
|
169
169
|
label = [f"[{OneColors.GREEN_b}]⚙ IOAction[/] '{self.name}'"]
|
170
170
|
if self.inject_last_result:
|
171
|
-
label.append(f" [dim](injects '{self.
|
171
|
+
label.append(f" [dim](injects '{self.inject_into}')[/dim]")
|
172
172
|
if parent:
|
173
173
|
parent.add("".join(label))
|
174
174
|
else:
|
@@ -243,7 +243,7 @@ class ShellAction(BaseIOAction):
|
|
243
243
|
async def preview(self, parent: Tree | None = None):
|
244
244
|
label = [f"[{OneColors.GREEN_b}]⚙ ShellAction[/] '{self.name}'"]
|
245
245
|
if self.inject_last_result:
|
246
|
-
label.append(f" [dim](injects '{self.
|
246
|
+
label.append(f" [dim](injects '{self.inject_into}')[/dim]")
|
247
247
|
if parent:
|
248
248
|
parent.add("".join(label))
|
249
249
|
else:
|
@@ -101,7 +101,7 @@ class MenuAction(BaseAction):
|
|
101
101
|
prompt_message: str = "Select > ",
|
102
102
|
default_selection: str = "",
|
103
103
|
inject_last_result: bool = False,
|
104
|
-
|
104
|
+
inject_into: str = "last_result",
|
105
105
|
console: Console | None = None,
|
106
106
|
prompt_session: PromptSession | None = None,
|
107
107
|
never_prompt: bool = False,
|
@@ -111,7 +111,7 @@ class MenuAction(BaseAction):
|
|
111
111
|
super().__init__(
|
112
112
|
name,
|
113
113
|
inject_last_result=inject_last_result,
|
114
|
-
|
114
|
+
inject_into=inject_into,
|
115
115
|
never_prompt=never_prompt,
|
116
116
|
)
|
117
117
|
self.menu_options = menu_options
|
@@ -33,7 +33,7 @@ class SelectionAction(BaseAction):
|
|
33
33
|
prompt_message: str = "Select > ",
|
34
34
|
default_selection: str = "",
|
35
35
|
inject_last_result: bool = False,
|
36
|
-
|
36
|
+
inject_into: str = "last_result",
|
37
37
|
return_key: bool = False,
|
38
38
|
console: Console | None = None,
|
39
39
|
prompt_session: PromptSession | None = None,
|
@@ -43,7 +43,7 @@ class SelectionAction(BaseAction):
|
|
43
43
|
super().__init__(
|
44
44
|
name,
|
45
45
|
inject_last_result=inject_last_result,
|
46
|
-
|
46
|
+
inject_into=inject_into,
|
47
47
|
never_prompt=never_prompt,
|
48
48
|
)
|
49
49
|
self.selections: list[str] | CaseInsensitiveDict = selections
|
@@ -0,0 +1 @@
|
|
1
|
+
__version__ = "0.1.20"
|
@@ -1,23 +0,0 @@
|
|
1
|
-
from typing import Callable
|
2
|
-
|
3
|
-
from falyx.action import BaseAction
|
4
|
-
|
5
|
-
|
6
|
-
class ActionFactoryAction(BaseAction):
|
7
|
-
def __init__(
|
8
|
-
self,
|
9
|
-
name: str,
|
10
|
-
factory: Callable[[dict], BaseAction],
|
11
|
-
*,
|
12
|
-
inject_last_result: bool = False,
|
13
|
-
inject_last_result_as: str = "last_result",
|
14
|
-
):
|
15
|
-
super().__init__(name, inject_last_result=inject_last_result, inject_last_result_as=inject_last_result_as)
|
16
|
-
self.factory = factory
|
17
|
-
|
18
|
-
async def _run(self, *args, **kwargs) -> BaseAction:
|
19
|
-
kwargs = self._maybe_inject_last_result(kwargs)
|
20
|
-
action = self.factory(kwargs)
|
21
|
-
if not isinstance(action, BaseAction):
|
22
|
-
raise TypeError(f"[{self.name}] Factory did not return a valid BaseAction.")
|
23
|
-
return action
|
falyx-0.1.19/falyx/version.py
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
__version__ = "0.1.19"
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|