falyx 0.1.19__py3-none-any.whl → 0.1.20__py3-none-any.whl

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/action.py CHANGED
@@ -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
- inject_last_result_as (str): The name of the kwarg key to inject the result as
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
- inject_last_result_as: str = "last_result",
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.inject_last_result_as: str = inject_last_result_as
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.inject_last_result_as
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
- inject_last_result_as (str, optional): Name of injected key.
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
- inject_last_result_as: str = "last_result",
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, inject_last_result_as)
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 error
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.inject_last_result_as}')[/dim]")
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
- inject_last_result_as (str, optional): Key name for injection.
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
- inject_last_result_as: str = "last_result",
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, inject_last_result_as)
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.inject_last_result_as}')[/dim]")
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
- inject_last_result_as (str, optional): Key name for injection.
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
- inject_last_result_as: str = "last_result",
613
+ inject_into: str = "last_result",
616
614
  ):
617
- super().__init__(name, hooks, inject_last_result, inject_last_result_as)
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.inject_last_result_as}')[/dim]")
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
- inject_last_result_as (str, optional): Name of the injected key.
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
- inject_last_result_as: str = "last_result",
739
+ inject_into: str = "last_result",
742
740
  ):
743
- super().__init__(name, hooks, inject_last_result, inject_last_result_as)
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.inject_last_result_as}')[/dim]")
801
+ label.append(f" [dim](injects '{self.inject_into}')[/dim]")
804
802
  if parent:
805
803
  parent.add("".join(label))
806
804
  else:
falyx/action_factory.py CHANGED
@@ -1,23 +1,95 @@
1
- from typing import Callable
1
+ from typing import Any
2
+
3
+ from rich.tree import Tree
2
4
 
3
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
4
11
 
5
12
 
6
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
+
7
27
  def __init__(
8
28
  self,
9
29
  name: str,
10
- factory: Callable[[dict], BaseAction],
30
+ factory: ActionFactoryProtocol,
11
31
  *,
12
32
  inject_last_result: bool = False,
13
- inject_last_result_as: str = "last_result",
33
+ inject_into: str = "last_result",
34
+ preview_args: tuple[Any, ...] = (),
35
+ preview_kwargs: dict[str, Any] = {},
14
36
  ):
15
- super().__init__(name, inject_last_result=inject_last_result, inject_last_result_as=inject_last_result_as)
37
+ super().__init__(
38
+ name=name,
39
+ inject_last_result=inject_last_result,
40
+ inject_into=inject_into,
41
+ )
16
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}[/]")
17
93
 
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
94
+ if not parent:
95
+ self.console.print(tree)
falyx/falyx.py CHANGED
@@ -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
- return True if self.get_command(text, from_validate=True) else False
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 get_command(self, choice: str, from_validate=False) -> Command | None:
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
- command = self.get_command(self.cli_args.name)
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
- command = self.get_command(self.cli_args.name)
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()
falyx/http_action.py CHANGED
@@ -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
- inject_last_result_as (str): Name of injected key.
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
- inject_last_result_as: str = "last_result",
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
- inject_last_result_as=inject_last_result_as,
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.inject_last_result_as}'")
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, "
falyx/io_action.py CHANGED
@@ -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.inject_last_result_as, None)
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.inject_last_result_as}')[/dim]")
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.inject_last_result_as}')[/dim]")
246
+ label.append(f" [dim](injects '{self.inject_into}')[/dim]")
247
247
  if parent:
248
248
  parent.add("".join(label))
249
249
  else:
falyx/menu_action.py CHANGED
@@ -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
- inject_last_result_as: str = "last_result",
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
- inject_last_result_as=inject_last_result_as,
114
+ inject_into=inject_into,
115
115
  never_prompt=never_prompt,
116
116
  )
117
117
  self.menu_options = menu_options
falyx/protocols.py ADDED
@@ -0,0 +1,9 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import Any, Protocol
4
+
5
+ from falyx.action import BaseAction
6
+
7
+
8
+ class ActionFactoryProtocol(Protocol):
9
+ def __call__(self, *args: Any, **kwargs: Any) -> BaseAction: ...
falyx/selection_action.py CHANGED
@@ -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
- inject_last_result_as: str = "last_result",
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
- inject_last_result_as=inject_last_result_as,
46
+ inject_into=inject_into,
47
47
  never_prompt=never_prompt,
48
48
  )
49
49
  self.selections: list[str] | CaseInsensitiveDict = selections
falyx/version.py CHANGED
@@ -1 +1 @@
1
- __version__ = "0.1.19"
1
+ __version__ = "0.1.20"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: falyx
3
- Version: 0.1.19
3
+ Version: 0.1.20
4
4
  Summary: Reliable and introspectable async CLI action framework.
5
5
  License: MIT
6
6
  Author: Roland Thomas Jr
@@ -1,8 +1,8 @@
1
1
  falyx/.pytyped,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
2
  falyx/__init__.py,sha256=dYRamQJlT1Zoy5Uu1uG4NCV05Xk98nN1LAQrSR1CT2A,643
3
3
  falyx/__main__.py,sha256=pXxXLlDot33dc4mR11Njpr4M_xbSTdKEqKWMS2aUqfk,2195
4
- falyx/action.py,sha256=E5sRroj-itmpZTzfo7zKqGe9VFnDZpB7ftMX2gI6Ieg,31974
5
- falyx/action_factory.py,sha256=z3oTtHNKc-FQI4niIElBO2iB0v7OGZgYntXPmskwL6E,772
4
+ falyx/action.py,sha256=vqWJfdywTQZyWgplbm1ilMtEh3DpOGlx2-pawe-hl7U,31694
5
+ falyx/action_factory.py,sha256=SMucCBuigKk3rlKXCEN69Sew4dVaBUxQqxyUUAHMZeo,3629
6
6
  falyx/bottom_bar.py,sha256=83KSElBU7sFJqUhKyfef6gYfPnNDM8V7bph60cY5ARQ,7384
7
7
  falyx/command.py,sha256=8Db_A3WDxmFNuZUb4_PO0UlpnfZFAUUEFkgC7B8v1Jk,11891
8
8
  falyx/config.py,sha256=czt_EjOCT0lzWcoRE2F-oS2k1AVBFdiNuTcQXHlUVD0,4534
@@ -10,30 +10,31 @@ falyx/context.py,sha256=Dm7HV-eigU-aTv5ERah6Ow9fIRdrOsB1G6ETPIu42Gw,10070
10
10
  falyx/debug.py,sha256=-jbTti29UC5zP9qQlWs3TbkOQR2f3zKSuNluh-r56wY,1551
11
11
  falyx/exceptions.py,sha256=YVbhPp2BNvZoO_xqeGSRKHVQ2rdLOLf1HCjH4JTj9w8,776
12
12
  falyx/execution_registry.py,sha256=xB2SJuEoDxxfwUmKXLAZQSrVoNPXwnVML98sTgwBqRI,2869
13
- falyx/falyx.py,sha256=1ULLG-E_9thbQl8HHXESRsPP91fhHTt9OqPw7cv5DSU,38606
13
+ falyx/falyx.py,sha256=xXRvl3TzfmtRIEdDj-xesmu0Y5Txf57pUAYpq40UYRo,39682
14
14
  falyx/hook_manager.py,sha256=E9Vk4bdoUTeXPQ_BQEvY2Jt-jUAusc40LI8JDy3NLUw,2381
15
15
  falyx/hooks.py,sha256=9zXk62DsJLJrmwTdyeNy5s-rVRvl8feuYRrfMmz6cVQ,2802
16
- falyx/http_action.py,sha256=oRqHjVx8ggZtMR9ssv3VmXRgvYhUBpv4fq6357mMU4c,5846
16
+ falyx/http_action.py,sha256=JfopEleXJ0goVHi0VCn983c22GrmJhobnPIP7sTRqzU,5796
17
17
  falyx/init.py,sha256=jP4ZNw7ycDMKw4n1HDifxWSa0NYHaGLq7_LiFt85NpA,1832
18
- falyx/io_action.py,sha256=MsvKj63VmABqdtDURgfGOpiudpTPOL0N_hlmTbYVtcA,10662
19
- falyx/menu_action.py,sha256=2i5eEH1B6-o8Ac2pS_HaXnv6ro2FZBySHSnaJa1UyTw,7999
18
+ falyx/io_action.py,sha256=IT7jDbucZbMxqcIotb1X4GmYXt6uXGMszy1hxAK_e90,10632
19
+ falyx/menu_action.py,sha256=UfJStuOM8LMauTRFcZfKLvornfYBuZZza-EK9CQ0edE,7969
20
20
  falyx/options_manager.py,sha256=yYpn-moYN-bRYgMLccmi_de4mUzhTT7cv_bR2FFWZ8c,2798
21
21
  falyx/parsers.py,sha256=Ki0rn2wryPDmMI9WUNBLQ5J5Y64BNten0POMZM8wPKU,5189
22
22
  falyx/prompt_utils.py,sha256=JOg3p8Juv6ZdY1srfy_HlMNYfE-ajggDWLqNsjZq87I,560
23
+ falyx/protocols.py,sha256=yNtQEugq9poN-SbOJf5LL_j6HBWdglbTNghpyopLpTs,216
23
24
  falyx/retry.py,sha256=GncBUiDDfDHUvLsWsWQw2Nq2XYL0TR0Fne3iXPzvQ48,3551
24
25
  falyx/retry_utils.py,sha256=SN5apcsg71IG2-KylysqdJd-PkPBLoCVwsgrSTF9wrQ,666
25
26
  falyx/select_files_action.py,sha256=aqh7Ezb0TVfvwskY3p_OtUjfN06KF8jRHGuNuq5RpUQ,2444
26
27
  falyx/selection.py,sha256=Hi8vfu6IuKdZ7URLiavb3uD1_Gb50D8XoKpZwAHLjmE,9859
27
- falyx/selection_action.py,sha256=Z_MuwA8RenxQuDiv3ScCI2qUzAl7F2bgENnwSMNEBF8,8288
28
+ falyx/selection_action.py,sha256=hWsfyRO0cn6Z-sBeDYNTJKZq8CCBxY2GY917U7a8Uo0,8258
28
29
  falyx/signal_action.py,sha256=wfhW9miSUj9MUoc1WOyk4tU9CtYKAXusHxQdBPYLoyQ,829
29
30
  falyx/signals.py,sha256=tlUbz3x6z3rYlUggan_Ntoy4bU5RbOd8UfR4cNcV6kQ,694
30
31
  falyx/tagged_table.py,sha256=sn2kosRRpcpeMB8vKk47c9yjpffSz_9FXH_e6kw15mA,1019
31
32
  falyx/themes/colors.py,sha256=4aaeAHJetmeNInI0Zytg4E3YqKfPFelpf04vtjSvsS8,19776
32
33
  falyx/utils.py,sha256=b1GQ3ooz4Io3zPE7MsoDm7j42AioTG-ZcWH-N2TRpbI,7710
33
34
  falyx/validators.py,sha256=NMxqCk8Fr8HQGVDYpg8B_JRk5SKR41E_G9gj1YfQnxg,1316
34
- falyx/version.py,sha256=cAJAbAh288a9AL-3yxwFzEM1L26izSJ6wma5aiml_9Y,23
35
- falyx-0.1.19.dist-info/LICENSE,sha256=B0yqgaHuSdhN7T3OBmgQSiDTy8HqT5Oe_dLypRe4Ra4,1073
36
- falyx-0.1.19.dist-info/METADATA,sha256=rYsPhQvH59KWDqxI_NOdW1adLpK243QrPqZq2XQJ_b4,5484
37
- falyx-0.1.19.dist-info/WHEEL,sha256=fGIA9gx4Qxk2KDKeNJCbOEwSrmLtjWCwzBz351GyrPQ,88
38
- falyx-0.1.19.dist-info/entry_points.txt,sha256=j8owOSl2j1Ss8DtGMnKfgehKaolqnIPhVFHaUBLUnMs,45
39
- falyx-0.1.19.dist-info/RECORD,,
35
+ falyx/version.py,sha256=8XalsVoLEfXslFvdtUEmkNOuYShzOzYOcFbgmOz1oSk,23
36
+ falyx-0.1.20.dist-info/LICENSE,sha256=B0yqgaHuSdhN7T3OBmgQSiDTy8HqT5Oe_dLypRe4Ra4,1073
37
+ falyx-0.1.20.dist-info/METADATA,sha256=zSkzjuSPukAX2JukaxG18mqDOSzQlb9vAEW-E2QH8Ds,5484
38
+ falyx-0.1.20.dist-info/WHEEL,sha256=fGIA9gx4Qxk2KDKeNJCbOEwSrmLtjWCwzBz351GyrPQ,88
39
+ falyx-0.1.20.dist-info/entry_points.txt,sha256=j8owOSl2j1Ss8DtGMnKfgehKaolqnIPhVFHaUBLUnMs,45
40
+ falyx-0.1.20.dist-info/RECORD,,
File without changes