falyx 0.1.34__tar.gz → 0.1.36__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.
Files changed (53) hide show
  1. {falyx-0.1.34 → falyx-0.1.36}/PKG-INFO +1 -1
  2. {falyx-0.1.34 → falyx-0.1.36}/falyx/action/action.py +7 -7
  3. {falyx-0.1.34 → falyx-0.1.36}/falyx/action/http_action.py +1 -1
  4. {falyx-0.1.34 → falyx-0.1.36}/falyx/action/select_file_action.py +1 -1
  5. {falyx-0.1.34 → falyx-0.1.36}/falyx/command.py +1 -1
  6. {falyx-0.1.34 → falyx-0.1.36}/falyx/context.py +2 -2
  7. {falyx-0.1.34 → falyx-0.1.36}/falyx/debug.py +4 -4
  8. {falyx-0.1.34 → falyx-0.1.36}/falyx/falyx.py +6 -6
  9. {falyx-0.1.34 → falyx-0.1.36}/falyx/hook_manager.py +1 -1
  10. {falyx-0.1.34 → falyx-0.1.36}/falyx/hooks.py +5 -5
  11. {falyx-0.1.34 → falyx-0.1.36}/falyx/parsers/utils.py +1 -1
  12. {falyx-0.1.34 → falyx-0.1.36}/falyx/retry.py +9 -9
  13. falyx-0.1.36/falyx/version.py +1 -0
  14. {falyx-0.1.34 → falyx-0.1.36}/pyproject.toml +1 -1
  15. falyx-0.1.34/falyx/version.py +0 -1
  16. {falyx-0.1.34 → falyx-0.1.36}/LICENSE +0 -0
  17. {falyx-0.1.34 → falyx-0.1.36}/README.md +0 -0
  18. {falyx-0.1.34 → falyx-0.1.36}/falyx/.pytyped +0 -0
  19. {falyx-0.1.34 → falyx-0.1.36}/falyx/__init__.py +0 -0
  20. {falyx-0.1.34 → falyx-0.1.36}/falyx/__main__.py +0 -0
  21. {falyx-0.1.34 → falyx-0.1.36}/falyx/action/.pytyped +0 -0
  22. {falyx-0.1.34 → falyx-0.1.36}/falyx/action/__init__.py +0 -0
  23. {falyx-0.1.34 → falyx-0.1.36}/falyx/action/action_factory.py +0 -0
  24. {falyx-0.1.34 → falyx-0.1.36}/falyx/action/io_action.py +0 -0
  25. {falyx-0.1.34 → falyx-0.1.36}/falyx/action/menu_action.py +0 -0
  26. {falyx-0.1.34 → falyx-0.1.36}/falyx/action/prompt_menu_action.py +0 -0
  27. {falyx-0.1.34 → falyx-0.1.36}/falyx/action/selection_action.py +0 -0
  28. {falyx-0.1.34 → falyx-0.1.36}/falyx/action/signal_action.py +0 -0
  29. {falyx-0.1.34 → falyx-0.1.36}/falyx/action/types.py +0 -0
  30. {falyx-0.1.34 → falyx-0.1.36}/falyx/action/user_input_action.py +0 -0
  31. {falyx-0.1.34 → falyx-0.1.36}/falyx/bottom_bar.py +0 -0
  32. {falyx-0.1.34 → falyx-0.1.36}/falyx/config.py +0 -0
  33. {falyx-0.1.34 → falyx-0.1.36}/falyx/exceptions.py +0 -0
  34. {falyx-0.1.34 → falyx-0.1.36}/falyx/execution_registry.py +0 -0
  35. {falyx-0.1.34 → falyx-0.1.36}/falyx/init.py +0 -0
  36. {falyx-0.1.34 → falyx-0.1.36}/falyx/logger.py +0 -0
  37. {falyx-0.1.34 → falyx-0.1.36}/falyx/menu.py +0 -0
  38. {falyx-0.1.34 → falyx-0.1.36}/falyx/options_manager.py +0 -0
  39. {falyx-0.1.34 → falyx-0.1.36}/falyx/parsers/.pytyped +0 -0
  40. {falyx-0.1.34 → falyx-0.1.36}/falyx/parsers/__init__.py +0 -0
  41. {falyx-0.1.34 → falyx-0.1.36}/falyx/parsers/argparse.py +0 -0
  42. {falyx-0.1.34 → falyx-0.1.36}/falyx/parsers/parsers.py +0 -0
  43. {falyx-0.1.34 → falyx-0.1.36}/falyx/parsers/signature.py +0 -0
  44. {falyx-0.1.34 → falyx-0.1.36}/falyx/prompt_utils.py +0 -0
  45. {falyx-0.1.34 → falyx-0.1.36}/falyx/protocols.py +0 -0
  46. {falyx-0.1.34 → falyx-0.1.36}/falyx/retry_utils.py +0 -0
  47. {falyx-0.1.34 → falyx-0.1.36}/falyx/selection.py +0 -0
  48. {falyx-0.1.34 → falyx-0.1.36}/falyx/signals.py +0 -0
  49. {falyx-0.1.34 → falyx-0.1.36}/falyx/tagged_table.py +0 -0
  50. {falyx-0.1.34 → falyx-0.1.36}/falyx/themes/__init__.py +0 -0
  51. {falyx-0.1.34 → falyx-0.1.36}/falyx/themes/colors.py +0 -0
  52. {falyx-0.1.34 → falyx-0.1.36}/falyx/utils.py +0 -0
  53. {falyx-0.1.34 → falyx-0.1.36}/falyx/validators.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: falyx
3
- Version: 0.1.34
3
+ Version: 0.1.36
4
4
  Summary: Reliable and introspectable async CLI action framework.
5
5
  License: MIT
6
6
  Author: Roland Thomas Jr
@@ -149,7 +149,7 @@ class BaseAction(ABC):
149
149
  if self.inject_last_result and self.shared_context:
150
150
  key = self.inject_into
151
151
  if key in kwargs:
152
- logger.warning("[%s] ⚠️ Overriding '%s' with last_result", self.name, key)
152
+ logger.warning("[%s] Overriding '%s' with last_result", self.name, key)
153
153
  kwargs = dict(kwargs)
154
154
  kwargs[key] = self.shared_context.last_result()
155
155
  return kwargs
@@ -278,7 +278,7 @@ class Action(BaseAction):
278
278
  context.exception = error
279
279
  await self.hooks.trigger(HookType.ON_ERROR, context)
280
280
  if context.result is not None:
281
- logger.info("[%s] Recovered: %s", self.name, self.name)
281
+ logger.info("[%s] Recovered: %s", self.name, self.name)
282
282
  return context.result
283
283
  raise
284
284
  finally:
@@ -518,7 +518,7 @@ class ChainedAction(BaseAction, ActionListMixin):
518
518
  for index, action in enumerate(self.actions):
519
519
  if action._skip_in_chain:
520
520
  logger.debug(
521
- "[%s] ⚠️ Skipping consumed action '%s'", self.name, action.name
521
+ "[%s] Skipping consumed action '%s'", self.name, action.name
522
522
  )
523
523
  continue
524
524
  shared_context.current_index = index
@@ -530,7 +530,7 @@ class ChainedAction(BaseAction, ActionListMixin):
530
530
  self.actions[index + 1], FallbackAction
531
531
  ):
532
532
  logger.warning(
533
- "[%s] ⚠️ Fallback triggered: %s, recovering with fallback "
533
+ "[%s] Fallback triggered: %s, recovering with fallback "
534
534
  "'%s'.",
535
535
  self.name,
536
536
  error,
@@ -585,10 +585,10 @@ class ChainedAction(BaseAction, ActionListMixin):
585
585
  rollback = getattr(action, "rollback", None)
586
586
  if rollback:
587
587
  try:
588
- logger.warning("[%s] ↩️ Rolling back...", action.name)
588
+ logger.warning("[%s] Rolling back...", action.name)
589
589
  await action.rollback(*args, **kwargs)
590
590
  except Exception as error:
591
- logger.error("[%s] ⚠️ Rollback failed: %s", action.name, error)
591
+ logger.error("[%s] Rollback failed: %s", action.name, error)
592
592
 
593
593
  def register_hooks_recursively(self, hook_type: HookType, hook: Hook):
594
594
  """Register a hook for all actions and sub-actions."""
@@ -726,7 +726,7 @@ class ActionGroup(BaseAction, ActionListMixin):
726
726
  if context.extra["errors"]:
727
727
  context.exception = Exception(
728
728
  f"{len(context.extra['errors'])} action(s) failed: "
729
- f"{' ,'.join(name for name, _ in context.extra["errors"])}"
729
+ f"{' ,'.join(name for name, _ in context.extra['errors'])}"
730
730
  )
731
731
  await self.hooks.trigger(HookType.ON_ERROR, context)
732
732
  raise context.exception
@@ -28,7 +28,7 @@ async def close_shared_http_session(context: ExecutionContext) -> None:
28
28
  if session and should_close:
29
29
  await session.close()
30
30
  except Exception as error:
31
- logger.warning("⚠️ Error closing shared HTTP session: %s", error)
31
+ logger.warning("Error closing shared HTTP session: %s", error)
32
32
 
33
33
 
34
34
  class HTTPAction(Action):
@@ -119,7 +119,7 @@ class SelectFileAction(BaseAction):
119
119
  description=file.name, value=value, style=self.style
120
120
  )
121
121
  except Exception as error:
122
- logger.warning("[ERROR] Failed to parse %s: %s", file.name, error)
122
+ logger.error("Failed to parse %s: %s", file.name, error)
123
123
  return options
124
124
 
125
125
  def _find_cancel_key(self, options) -> str:
@@ -245,7 +245,7 @@ class Command(BaseModel):
245
245
  if self.preview_before_confirm:
246
246
  await self.preview()
247
247
  if not await confirm_async(self.confirmation_prompt):
248
- logger.info("[Command:%s] Cancelled by user.", self.key)
248
+ logger.info("[Command:%s] Cancelled by user.", self.key)
249
249
  raise CancelSignal(f"[Command:{self.key}] Cancelled by confirmation.")
250
250
 
251
251
  context.start_timer()
@@ -140,9 +140,9 @@ class ExecutionContext(BaseModel):
140
140
  message.append(f"Duration: {summary['duration']:.3f}s | ")
141
141
 
142
142
  if summary["exception"]:
143
- message.append(f"Exception: {summary['exception']}")
143
+ message.append(f"Exception: {summary['exception']}")
144
144
  else:
145
- message.append(f"Result: {summary['result']}")
145
+ message.append(f"Result: {summary['result']}")
146
146
  (logger or self.console.print)("".join(message))
147
147
 
148
148
  def to_log_line(self) -> str:
@@ -10,7 +10,7 @@ def log_before(context: ExecutionContext):
10
10
  args = ", ".join(map(repr, context.args))
11
11
  kwargs = ", ".join(f"{k}={v!r}" for k, v in context.kwargs.items())
12
12
  signature = ", ".join(filter(None, [args, kwargs]))
13
- logger.info("[%s] 🚀 Starting → %s(%s)", context.name, context.action, signature)
13
+ logger.info("[%s] Starting → %s(%s)", context.name, context.action, signature)
14
14
 
15
15
 
16
16
  def log_success(context: ExecutionContext):
@@ -18,18 +18,18 @@ def log_success(context: ExecutionContext):
18
18
  result_str = repr(context.result)
19
19
  if len(result_str) > 100:
20
20
  result_str = f"{result_str[:100]} ..."
21
- logger.debug("[%s] Success → Result: %s", context.name, result_str)
21
+ logger.debug("[%s] Success → Result: %s", context.name, result_str)
22
22
 
23
23
 
24
24
  def log_after(context: ExecutionContext):
25
25
  """Log the completion of an action, regardless of success or failure."""
26
- logger.debug("[%s] ⏱️ Finished in %.3fs", context.name, context.duration)
26
+ logger.debug("[%s] Finished in %.3fs", context.name, context.duration)
27
27
 
28
28
 
29
29
  def log_error(context: ExecutionContext):
30
30
  """Log an error that occurred during the action."""
31
31
  logger.error(
32
- "[%s] Error (%s): %s",
32
+ "[%s] Error (%s): %s",
33
33
  context.name,
34
34
  type(context.exception).__name__,
35
35
  context.exception,
@@ -852,7 +852,7 @@ class Falyx:
852
852
  self.last_run_command = selected_command
853
853
 
854
854
  if selected_command == self.exit_command:
855
- logger.info("🔙 Back selected: exiting %s", self.get_title())
855
+ logger.info("Back selected: exiting %s", self.get_title())
856
856
  return False
857
857
 
858
858
  context = self._create_context(selected_command)
@@ -895,7 +895,7 @@ class Falyx:
895
895
  return None
896
896
 
897
897
  logger.info(
898
- "[run_key] 🚀 Executing: %s — %s",
898
+ "[run_key] Executing: %s — %s",
899
899
  selected_command.key,
900
900
  selected_command.description,
901
901
  )
@@ -908,10 +908,10 @@ class Falyx:
908
908
  context.result = result
909
909
 
910
910
  await self.hooks.trigger(HookType.ON_SUCCESS, context)
911
- logger.info("[run_key] '%s' complete.", selected_command.description)
911
+ logger.info("[run_key] '%s' complete.", selected_command.description)
912
912
  except (KeyboardInterrupt, EOFError) as error:
913
913
  logger.warning(
914
- "[run_key] ⚠️ Interrupted by user: %s", selected_command.description
914
+ "[run_key] Interrupted by user: %s", selected_command.description
915
915
  )
916
916
  raise FalyxError(
917
917
  f"[run_key] ⚠️ '{selected_command.description}' interrupted by user."
@@ -920,7 +920,7 @@ class Falyx:
920
920
  context.exception = error
921
921
  await self.hooks.trigger(HookType.ON_ERROR, context)
922
922
  logger.error(
923
- "[run_key] Failed: %s — %s: %s",
923
+ "[run_key] Failed: %s — %s: %s",
924
924
  selected_command.description,
925
925
  type(error).__name__,
926
926
  error,
@@ -1024,7 +1024,7 @@ class Falyx:
1024
1024
  logging.getLogger("falyx").setLevel(logging.DEBUG)
1025
1025
 
1026
1026
  if self.cli_args.debug_hooks:
1027
- logger.debug("Enabling global debug hooks for all commands")
1027
+ logger.debug("Enabling global debug hooks for all commands")
1028
1028
  self.register_all_with_debug_hooks()
1029
1029
 
1030
1030
  if self.cli_args.command == "list":
@@ -65,7 +65,7 @@ class HookManager:
65
65
  hook(context)
66
66
  except Exception as hook_error:
67
67
  logger.warning(
68
- "⚠️ Hook '%s' raised an exception during '%s' for '%s': %s",
68
+ "[Hook:%s] raised an exception during '%s' for '%s': %s",
69
69
  hook.__name__,
70
70
  hook_type,
71
71
  context.name,
@@ -56,10 +56,10 @@ class CircuitBreaker:
56
56
  if self.open_until:
57
57
  if time.time() < self.open_until:
58
58
  raise CircuitBreakerOpen(
59
- f"🔴 Circuit open for '{name}' until {time.ctime(self.open_until)}."
59
+ f"Circuit open for '{name}' until {time.ctime(self.open_until)}."
60
60
  )
61
61
  else:
62
- logger.info("🟢 Circuit closed again for '%s'.")
62
+ logger.info("Circuit closed again for '%s'.")
63
63
  self.failures = 0
64
64
  self.open_until = None
65
65
 
@@ -67,7 +67,7 @@ class CircuitBreaker:
67
67
  name = context.name
68
68
  self.failures += 1
69
69
  logger.warning(
70
- "⚠️ CircuitBreaker: '%s' failure %s/%s.",
70
+ "CircuitBreaker: '%s' failure %s/%s.",
71
71
  name,
72
72
  self.failures,
73
73
  self.max_failures,
@@ -75,7 +75,7 @@ class CircuitBreaker:
75
75
  if self.failures >= self.max_failures:
76
76
  self.open_until = time.time() + self.reset_timeout
77
77
  logger.error(
78
- "🔴 Circuit opened for '%s' until %s.", name, time.ctime(self.open_until)
78
+ "Circuit opened for '%s' until %s.", name, time.ctime(self.open_until)
79
79
  )
80
80
 
81
81
  def after_hook(self, _: ExecutionContext):
@@ -87,4 +87,4 @@ class CircuitBreaker:
87
87
  def reset(self):
88
88
  self.failures = 0
89
89
  self.open_until = None
90
- logger.info("🔄 Circuit reset.")
90
+ logger.info("Circuit reset.")
@@ -1,6 +1,6 @@
1
1
  from typing import Any
2
2
 
3
- from falyx import logger
3
+ from falyx.logger import logger
4
4
  from falyx.parsers.signature import infer_args_from_func
5
5
 
6
6
 
@@ -53,7 +53,7 @@ class RetryHandler:
53
53
  self.policy.delay = delay
54
54
  self.policy.backoff = backoff
55
55
  self.policy.jitter = jitter
56
- logger.info("🔄 Retry policy enabled: %s", self.policy)
56
+ logger.info("Retry policy enabled: %s", self.policy)
57
57
 
58
58
  async def retry_on_error(self, context: ExecutionContext) -> None:
59
59
  from falyx.action import Action
@@ -67,21 +67,21 @@ class RetryHandler:
67
67
  last_error = error
68
68
 
69
69
  if not target:
70
- logger.warning("[%s] ⚠️ No action target. Cannot retry.", name)
70
+ logger.warning("[%s] No action target. Cannot retry.", name)
71
71
  return None
72
72
 
73
73
  if not isinstance(target, Action):
74
74
  logger.warning(
75
- "[%s] RetryHandler only supports only supports Action objects.", name
75
+ "[%s] RetryHandler only supports only supports Action objects.", name
76
76
  )
77
77
  return None
78
78
 
79
79
  if not getattr(target, "is_retryable", False):
80
- logger.warning("[%s] Not retryable.", name)
80
+ logger.warning("[%s] Not retryable.", name)
81
81
  return None
82
82
 
83
83
  if not self.policy.enabled:
84
- logger.warning("[%s] Retry policy is disabled.", name)
84
+ logger.warning("[%s] Retry policy is disabled.", name)
85
85
  return None
86
86
 
87
87
  while retries_done < self.policy.max_retries:
@@ -92,7 +92,7 @@ class RetryHandler:
92
92
  sleep_delay += random.uniform(-self.policy.jitter, self.policy.jitter)
93
93
 
94
94
  logger.info(
95
- "[%s] 🔄 Retrying (%s/%s) in %ss due to '%s'...",
95
+ "[%s] Retrying (%s/%s) in %ss due to '%s'...",
96
96
  name,
97
97
  retries_done,
98
98
  self.policy.max_retries,
@@ -104,13 +104,13 @@ class RetryHandler:
104
104
  result = await target.action(*context.args, **context.kwargs)
105
105
  context.result = result
106
106
  context.exception = None
107
- logger.info("[%s] Retry succeeded on attempt %s.", name, retries_done)
107
+ logger.info("[%s] Retry succeeded on attempt %s.", name, retries_done)
108
108
  return None
109
109
  except Exception as retry_error:
110
110
  last_error = retry_error
111
111
  current_delay *= self.policy.backoff
112
112
  logger.warning(
113
- "[%s] ⚠️ Retry attempt %s/%s failed due to '%s'.",
113
+ "[%s] Retry attempt %s/%s failed due to '%s'.",
114
114
  name,
115
115
  retries_done,
116
116
  self.policy.max_retries,
@@ -118,4 +118,4 @@ class RetryHandler:
118
118
  )
119
119
 
120
120
  context.exception = last_error
121
- logger.error("[%s] All %s retries failed.", name, self.policy.max_retries)
121
+ logger.error("[%s] All %s retries failed.", name, self.policy.max_retries)
@@ -0,0 +1 @@
1
+ __version__ = "0.1.36"
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "falyx"
3
- version = "0.1.34"
3
+ version = "0.1.36"
4
4
  description = "Reliable and introspectable async CLI action framework."
5
5
  authors = ["Roland Thomas Jr <roland@rtj.dev>"]
6
6
  license = "MIT"
@@ -1 +0,0 @@
1
- __version__ = "0.1.34"
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
File without changes
File without changes