falyx 0.1.61__py3-none-any.whl → 0.1.62__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.
@@ -112,7 +112,16 @@ class ActionFactory(BaseAction):
112
112
  tree = parent.add(label) if parent else Tree(label)
113
113
 
114
114
  try:
115
- generated = await self.factory(*self.preview_args, **self.preview_kwargs)
115
+ generated = None
116
+ if self.args or self.kwargs:
117
+ try:
118
+ generated = await self.factory(*self.args, **self.kwargs)
119
+ except TypeError:
120
+ ...
121
+
122
+ if not generated:
123
+ generated = await self.factory(*self.preview_args, **self.preview_kwargs)
124
+
116
125
  if isinstance(generated, BaseAction):
117
126
  await generated.preview(parent=tree)
118
127
  else:
@@ -60,6 +60,8 @@ class ActionGroup(BaseAction, ActionListMixin):
60
60
  Sequence[BaseAction | Callable[..., Any] | Callable[..., Awaitable]] | None
61
61
  ) = None,
62
62
  *,
63
+ args: tuple[Any, ...] = (),
64
+ kwargs: dict[str, Any] | None = None,
63
65
  hooks: HookManager | None = None,
64
66
  inject_last_result: bool = False,
65
67
  inject_into: str = "last_result",
@@ -71,6 +73,8 @@ class ActionGroup(BaseAction, ActionListMixin):
71
73
  inject_into=inject_into,
72
74
  )
73
75
  ActionListMixin.__init__(self)
76
+ self.args = args
77
+ self.kwargs = kwargs or {}
74
78
  if actions:
75
79
  self.set_actions(actions)
76
80
 
@@ -115,13 +119,17 @@ class ActionGroup(BaseAction, ActionListMixin):
115
119
  async def _run(self, *args, **kwargs) -> list[tuple[str, Any]]:
116
120
  if not self.actions:
117
121
  raise EmptyGroupError(f"[{self.name}] No actions to execute.")
122
+
123
+ combined_args = args + self.args
124
+ combined_kwargs = {**self.kwargs, **kwargs}
125
+
118
126
  shared_context = SharedContext(name=self.name, action=self, is_parallel=True)
119
127
  if self.shared_context:
120
128
  shared_context.set_shared_result(self.shared_context.last_result())
121
- updated_kwargs = self._maybe_inject_last_result(kwargs)
129
+ updated_kwargs = self._maybe_inject_last_result(combined_kwargs)
122
130
  context = ExecutionContext(
123
131
  name=self.name,
124
- args=args,
132
+ args=combined_args,
125
133
  kwargs=updated_kwargs,
126
134
  action=self,
127
135
  extra={"results": [], "errors": []},
@@ -131,7 +139,7 @@ class ActionGroup(BaseAction, ActionListMixin):
131
139
  async def run_one(action: BaseAction):
132
140
  try:
133
141
  prepared = action.prepare(shared_context, self.options_manager)
134
- result = await prepared(*args, **updated_kwargs)
142
+ result = await prepared(*combined_args, **updated_kwargs)
135
143
  shared_context.add_result((action.name, result))
136
144
  context.extra["results"].append((action.name, result))
137
145
  except Exception as error:
@@ -61,7 +61,9 @@ class ConfirmType(Enum):
61
61
  YES_CANCEL = "yes_cancel"
62
62
  YES_NO_CANCEL = "yes_no_cancel"
63
63
  TYPE_WORD = "type_word"
64
+ TYPE_WORD_CANCEL = "type_word_cancel"
64
65
  OK_CANCEL = "ok_cancel"
66
+ ACKNOWLEDGE = "acknowledge"
65
67
 
66
68
  @classmethod
67
69
  def choices(cls) -> list[ConfirmType]:
@@ -54,6 +54,8 @@ class ChainedAction(BaseAction, ActionListMixin):
54
54
  | None
55
55
  ) = None,
56
56
  *,
57
+ args: tuple[Any, ...] = (),
58
+ kwargs: dict[str, Any] | None = None,
57
59
  hooks: HookManager | None = None,
58
60
  inject_last_result: bool = False,
59
61
  inject_into: str = "last_result",
@@ -67,6 +69,8 @@ class ChainedAction(BaseAction, ActionListMixin):
67
69
  inject_into=inject_into,
68
70
  )
69
71
  ActionListMixin.__init__(self)
72
+ self.args = args
73
+ self.kwargs = kwargs or {}
70
74
  self.auto_inject = auto_inject
71
75
  self.return_list = return_list
72
76
  if actions:
@@ -111,13 +115,16 @@ class ChainedAction(BaseAction, ActionListMixin):
111
115
  if not self.actions:
112
116
  raise EmptyChainError(f"[{self.name}] No actions to execute.")
113
117
 
118
+ combined_args = args + self.args
119
+ combined_kwargs = {**self.kwargs, **kwargs}
120
+
114
121
  shared_context = SharedContext(name=self.name, action=self)
115
122
  if self.shared_context:
116
123
  shared_context.add_result(self.shared_context.last_result())
117
- updated_kwargs = self._maybe_inject_last_result(kwargs)
124
+ updated_kwargs = self._maybe_inject_last_result(combined_kwargs)
118
125
  context = ExecutionContext(
119
126
  name=self.name,
120
- args=args,
127
+ args=combined_args,
121
128
  kwargs=updated_kwargs,
122
129
  action=self,
123
130
  extra={"results": [], "rollback_stack": []},
@@ -136,7 +143,7 @@ class ChainedAction(BaseAction, ActionListMixin):
136
143
  shared_context.current_index = index
137
144
  prepared = action.prepare(shared_context, self.options_manager)
138
145
  try:
139
- result = await prepared(*args, **updated_kwargs)
146
+ result = await prepared(*combined_args, **updated_kwargs)
140
147
  except Exception as error:
141
148
  if index + 1 < len(self.actions) and isinstance(
142
149
  self.actions[index + 1], FallbackAction
@@ -155,10 +162,12 @@ class ChainedAction(BaseAction, ActionListMixin):
155
162
  fallback._skip_in_chain = True
156
163
  else:
157
164
  raise
158
- args, updated_kwargs = self._clear_args()
159
165
  shared_context.add_result(result)
160
166
  context.extra["results"].append(result)
161
- context.extra["rollback_stack"].append(prepared)
167
+ context.extra["rollback_stack"].append(
168
+ (prepared, combined_args, updated_kwargs)
169
+ )
170
+ combined_args, updated_kwargs = self._clear_args()
162
171
 
163
172
  all_results = context.extra["results"]
164
173
  assert (
@@ -171,11 +180,11 @@ class ChainedAction(BaseAction, ActionListMixin):
171
180
  logger.info("[%s] Chain broken: %s", self.name, error)
172
181
  context.exception = error
173
182
  shared_context.add_error(shared_context.current_index, error)
174
- await self._rollback(context.extra["rollback_stack"], *args, **kwargs)
183
+ await self._rollback(context.extra["rollback_stack"])
175
184
  except Exception as error:
176
185
  context.exception = error
177
186
  shared_context.add_error(shared_context.current_index, error)
178
- await self._rollback(context.extra["rollback_stack"], *args, **kwargs)
187
+ await self._rollback(context.extra["rollback_stack"])
179
188
  await self.hooks.trigger(HookType.ON_ERROR, context)
180
189
  raise
181
190
  finally:
@@ -184,7 +193,9 @@ class ChainedAction(BaseAction, ActionListMixin):
184
193
  await self.hooks.trigger(HookType.ON_TEARDOWN, context)
185
194
  er.record(context)
186
195
 
187
- async def _rollback(self, rollback_stack, *args, **kwargs):
196
+ async def _rollback(
197
+ self, rollback_stack: list[tuple[Action, tuple[Any, ...], dict[str, Any]]]
198
+ ):
188
199
  """
189
200
  Roll back all executed actions in reverse order.
190
201
 
@@ -197,12 +208,12 @@ class ChainedAction(BaseAction, ActionListMixin):
197
208
  rollback_stack (list): Actions to roll back.
198
209
  *args, **kwargs: Passed to rollback handlers.
199
210
  """
200
- for action in reversed(rollback_stack):
211
+ for action, args, kwargs in reversed(rollback_stack):
201
212
  rollback = getattr(action, "rollback", None)
202
213
  if rollback:
203
214
  try:
204
215
  logger.warning("[%s] Rolling back...", action.name)
205
- await action.rollback(*args, **kwargs)
216
+ await rollback(*args, **kwargs)
206
217
  except Exception as error:
207
218
  logger.error("[%s] Rollback failed: %s", action.name, error)
208
219
 
@@ -112,6 +112,14 @@ class ConfirmAction(BaseAction):
112
112
  validator=word_validator(self.word),
113
113
  )
114
114
  return answer.upper().strip() != "N"
115
+ case ConfirmType.TYPE_WORD_CANCEL:
116
+ answer = await self.prompt_session.prompt_async(
117
+ f"❓ {self.message} [{self.word}] to confirm or [N/n] > ",
118
+ validator=word_validator(self.word),
119
+ )
120
+ if answer.upper().strip() == "N":
121
+ raise CancelSignal(f"Action '{self.name}' was cancelled by the user.")
122
+ return answer.upper().strip() == self.word.upper().strip()
115
123
  case ConfirmType.YES_CANCEL:
116
124
  answer = await confirm_async(
117
125
  self.message,
@@ -131,6 +139,12 @@ class ConfirmAction(BaseAction):
131
139
  if answer.upper() == "C":
132
140
  raise CancelSignal(f"Action '{self.name}' was cancelled by the user.")
133
141
  return answer.upper() == "O"
142
+ case ConfirmType.ACKNOWLEDGE:
143
+ answer = await self.prompt_session.prompt_async(
144
+ f"❓ {self.message} [A]cknowledge > ",
145
+ validator=word_validator("A"),
146
+ )
147
+ return answer.upper().strip() == "A"
134
148
  case _:
135
149
  raise ValueError(f"Unknown confirm_type: {self.confirm_type}")
136
150
 
@@ -151,7 +165,7 @@ class ConfirmAction(BaseAction):
151
165
  and not should_prompt_user(confirm=True, options=self.options_manager)
152
166
  ):
153
167
  logger.debug(
154
- "Skipping confirmation for action '%s' as 'confirm' is False or options manager indicates no prompt.",
168
+ "Skipping confirmation for '%s' due to never_prompt or options_manager settings.",
155
169
  self.name,
156
170
  )
157
171
  if self.return_last_result:
@@ -189,7 +203,7 @@ class ConfirmAction(BaseAction):
189
203
  tree.add(f"[bold]Message:[/] {self.message}")
190
204
  tree.add(f"[bold]Type:[/] {self.confirm_type.value}")
191
205
  tree.add(f"[bold]Prompt Required:[/] {'No' if self.never_prompt else 'Yes'}")
192
- if self.confirm_type == ConfirmType.TYPE_WORD:
206
+ if self.confirm_type in (ConfirmType.TYPE_WORD, ConfirmType.TYPE_WORD_CANCEL):
193
207
  tree.add(f"[bold]Confirmation Word:[/] {self.word}")
194
208
  if parent is None:
195
209
  self.console.print(tree)
@@ -91,9 +91,7 @@ class ProcessPoolAction(BaseAction):
91
91
  f"Cannot inject last result into {self.name}: "
92
92
  f"last result is not pickleable."
93
93
  )
94
- print(kwargs)
95
94
  updated_kwargs = self._maybe_inject_last_result(kwargs)
96
- print(updated_kwargs)
97
95
  context = ExecutionContext(
98
96
  name=self.name,
99
97
  args=args,
falyx/version.py CHANGED
@@ -1 +1 @@
1
- __version__ = "0.1.61"
1
+ __version__ = "0.1.62"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: falyx
3
- Version: 0.1.61
3
+ Version: 0.1.62
4
4
  Summary: Reliable and introspectable async CLI action framework.
5
5
  License: MIT
6
6
  Author: Roland Thomas Jr
@@ -4,13 +4,13 @@ falyx/__main__.py,sha256=xHO4pB45rccixo-ougF84QJeB36ef8mEZXWVK_CJL9M,3420
4
4
  falyx/action/.pytyped,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
5
  falyx/action/__init__.py,sha256=_DfOQkNOCTmtC8DmS4rD4h5Vv9tmf0dab6VVyvvdQWU,1464
6
6
  falyx/action/action.py,sha256=Pm9lnxKhJoI1vs-fadAJrXkcDGYcBCMwvQ81HHxd0HA,5879
7
- falyx/action/action_factory.py,sha256=WosLeaYf79e83XHAAkxKi62zi8jJEiVlzvgOC84Z7t0,4840
8
- falyx/action/action_group.py,sha256=RQdHOWCa8XRUme3S5YGJTICLozIApAlIpRUgEeFaiyw,7728
7
+ falyx/action/action_factory.py,sha256=hxSN1PVVnsZ7mYhO0CqbFjcNBPkPRCHZ9JZ0vvwly38,5103
8
+ falyx/action/action_group.py,sha256=TBovifJ-HIBTBt_uBcoGXmj3MYpG8NdH37bIB5Q0e6Y,7992
9
9
  falyx/action/action_mixins.py,sha256=oUrjbweCeateshg3tqtbQiGuV8u4GvlioIZCUr9D1m4,1244
10
- falyx/action/action_types.py,sha256=TjUdwbnWVNzp5B5pFjgwRdA-P-MiY4bwe1dRSz-Ur3s,2318
10
+ falyx/action/action_types.py,sha256=3dT3k4c4aYcuuqcxPXPYO-YLuOqwNTApRAS9alnljoA,2392
11
11
  falyx/action/base_action.py,sha256=o9Nml70-SEVTXnu9J0-VYnO-t5wZZM0o59lYDth24Po,5829
12
- falyx/action/chained_action.py,sha256=TNJz25jnzQQAIwXM6uaK8mzhq4bgRks5n7IZ2nDQM6Q,9614
13
- falyx/action/confirm_action.py,sha256=rBtkaMuMYJEXcLu5VeWA0YPO6Yvj0gJBiGDAfoAkCEI,8601
12
+ falyx/action/chained_action.py,sha256=hAFjdUUXhPBIR8AEPV4G3tJq_tjZPrxc6Xk8we2KZNw,9981
13
+ falyx/action/confirm_action.py,sha256=deyqeO_dYLdumkQD1Io2BajtZ9LkM6MLqTB_9UlEP-o,9385
14
14
  falyx/action/fallback_action.py,sha256=3FGWfoR1MIgY0ZkDNOpKu8p3JqPWzh5ON3943mfgDGs,1708
15
15
  falyx/action/http_action.py,sha256=DNeSBWh58UTFGlfFyTk2GnhS54hpLAJLC0QNbq2cYic,5799
16
16
  falyx/action/io_action.py,sha256=V888tQgAynqsVvkhICnEeE4wRs2vvdTcdlEpDSEbHqo,6128
@@ -18,7 +18,7 @@ falyx/action/literal_input_action.py,sha256=ShXXiUYKg01BMZRChlxEWlNcaLXV1B1LW-w5
18
18
  falyx/action/load_file_action.py,sha256=HcwSVWI8-4_dp3VC4iHR3ARaTpY0Y1rChMqpyqQjIGg,8091
19
19
  falyx/action/menu_action.py,sha256=UwMF3Y3v8AWXGCkVpzj_k3pCge5BlJvKhqGYXh_dNCc,5775
20
20
  falyx/action/process_action.py,sha256=nUNcJD6Ms34vmj8njWzv1R1P9xJTyJmelnyJksHcp7M,4666
21
- falyx/action/process_pool_action.py,sha256=XeL6e7vsy4OkOWGQHD0ET14CzuyJ0TL-c1W5VIgdCP8,6204
21
+ falyx/action/process_pool_action.py,sha256=bBemgzB_shJfPytjbn1n6g9ScrpqrxMCujZU-I-UFf0,6152
22
22
  falyx/action/prompt_menu_action.py,sha256=PTn6US8ql5SU7ilEMVCeoGqKTc31be3AbdCfcrZ6ujU,5034
23
23
  falyx/action/save_file_action.py,sha256=Pe_j0hZjDNsO14bykzVYM0gkWB3zmpB1cExSN01IQOI,9899
24
24
  falyx/action/select_file_action.py,sha256=PcV22_wiPeDoJLIhHRiEUmW8N3pYeqQZMVTscQKXuas,9867
@@ -63,9 +63,9 @@ falyx/themes/__init__.py,sha256=1CZhEUCin9cUk8IGYBUFkVvdHRNNJBEFXccHwpUKZCA,284
63
63
  falyx/themes/colors.py,sha256=4aaeAHJetmeNInI0Zytg4E3YqKfPFelpf04vtjSvsS8,19776
64
64
  falyx/utils.py,sha256=U45xnZFUdoFC4xiji_9S1jHS5V7MvxSDtufP8EgB0SM,6732
65
65
  falyx/validators.py,sha256=AXpMGnk1_7J7MAbbol6pkMAiSIdNHoF5pwtA2-xS6H8,6029
66
- falyx/version.py,sha256=CjOPJsj7rCFM2zpom_253GmmHGb2RQ8NuZwsEg0ZmF0,23
67
- falyx-0.1.61.dist-info/LICENSE,sha256=B0yqgaHuSdhN7T3OBmgQSiDTy8HqT5Oe_dLypRe4Ra4,1073
68
- falyx-0.1.61.dist-info/METADATA,sha256=JdPjGhW2VQKmq-EPF5IfR5m7lRVx8Xlq6Yb4hb11WR4,5561
69
- falyx-0.1.61.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
70
- falyx-0.1.61.dist-info/entry_points.txt,sha256=j8owOSl2j1Ss8DtGMnKfgehKaolqnIPhVFHaUBLUnMs,45
71
- falyx-0.1.61.dist-info/RECORD,,
66
+ falyx/version.py,sha256=cwSKWX9cG1qs0I6C99TSkty5QpTa10uiqSeiXnsoOg0,23
67
+ falyx-0.1.62.dist-info/LICENSE,sha256=B0yqgaHuSdhN7T3OBmgQSiDTy8HqT5Oe_dLypRe4Ra4,1073
68
+ falyx-0.1.62.dist-info/METADATA,sha256=iCnf7bzp09iDj8wsg4Lif4ef4yazOELApWRN_ZNZZqM,5561
69
+ falyx-0.1.62.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
70
+ falyx-0.1.62.dist-info/entry_points.txt,sha256=j8owOSl2j1Ss8DtGMnKfgehKaolqnIPhVFHaUBLUnMs,45
71
+ falyx-0.1.62.dist-info/RECORD,,
File without changes