falyx 0.1.42__tar.gz → 0.1.44__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 (61) hide show
  1. {falyx-0.1.42 → falyx-0.1.44}/PKG-INFO +1 -1
  2. {falyx-0.1.42 → falyx-0.1.44}/falyx/__main__.py +45 -2
  3. {falyx-0.1.42 → falyx-0.1.44}/falyx/command.py +17 -0
  4. {falyx-0.1.42 → falyx-0.1.44}/falyx/falyx.py +73 -51
  5. {falyx-0.1.42 → falyx-0.1.44}/falyx/parsers/__init__.py +3 -1
  6. {falyx-0.1.42 → falyx-0.1.44}/falyx/parsers/parsers.py +74 -6
  7. {falyx-0.1.42 → falyx-0.1.44}/falyx/parsers/signature.py +2 -1
  8. falyx-0.1.44/falyx/version.py +1 -0
  9. {falyx-0.1.42 → falyx-0.1.44}/pyproject.toml +1 -1
  10. falyx-0.1.42/falyx/version.py +0 -1
  11. {falyx-0.1.42 → falyx-0.1.44}/LICENSE +0 -0
  12. {falyx-0.1.42 → falyx-0.1.44}/README.md +0 -0
  13. {falyx-0.1.42 → falyx-0.1.44}/falyx/.pytyped +0 -0
  14. {falyx-0.1.42 → falyx-0.1.44}/falyx/__init__.py +0 -0
  15. {falyx-0.1.42 → falyx-0.1.44}/falyx/action/.pytyped +0 -0
  16. {falyx-0.1.42 → falyx-0.1.44}/falyx/action/__init__.py +0 -0
  17. {falyx-0.1.42 → falyx-0.1.44}/falyx/action/action.py +0 -0
  18. {falyx-0.1.42 → falyx-0.1.44}/falyx/action/action_factory.py +0 -0
  19. {falyx-0.1.42 → falyx-0.1.44}/falyx/action/action_group.py +0 -0
  20. {falyx-0.1.42 → falyx-0.1.44}/falyx/action/base.py +0 -0
  21. {falyx-0.1.42 → falyx-0.1.44}/falyx/action/chained_action.py +0 -0
  22. {falyx-0.1.42 → falyx-0.1.44}/falyx/action/fallback_action.py +0 -0
  23. {falyx-0.1.42 → falyx-0.1.44}/falyx/action/http_action.py +0 -0
  24. {falyx-0.1.42 → falyx-0.1.44}/falyx/action/io_action.py +0 -0
  25. {falyx-0.1.42 → falyx-0.1.44}/falyx/action/literal_input_action.py +0 -0
  26. {falyx-0.1.42 → falyx-0.1.44}/falyx/action/menu_action.py +0 -0
  27. {falyx-0.1.42 → falyx-0.1.44}/falyx/action/mixins.py +0 -0
  28. {falyx-0.1.42 → falyx-0.1.44}/falyx/action/process_action.py +0 -0
  29. {falyx-0.1.42 → falyx-0.1.44}/falyx/action/process_pool_action.py +0 -0
  30. {falyx-0.1.42 → falyx-0.1.44}/falyx/action/prompt_menu_action.py +0 -0
  31. {falyx-0.1.42 → falyx-0.1.44}/falyx/action/select_file_action.py +0 -0
  32. {falyx-0.1.42 → falyx-0.1.44}/falyx/action/selection_action.py +0 -0
  33. {falyx-0.1.42 → falyx-0.1.44}/falyx/action/signal_action.py +0 -0
  34. {falyx-0.1.42 → falyx-0.1.44}/falyx/action/types.py +0 -0
  35. {falyx-0.1.42 → falyx-0.1.44}/falyx/action/user_input_action.py +0 -0
  36. {falyx-0.1.42 → falyx-0.1.44}/falyx/bottom_bar.py +0 -0
  37. {falyx-0.1.42 → falyx-0.1.44}/falyx/config.py +0 -0
  38. {falyx-0.1.42 → falyx-0.1.44}/falyx/context.py +0 -0
  39. {falyx-0.1.42 → falyx-0.1.44}/falyx/debug.py +0 -0
  40. {falyx-0.1.42 → falyx-0.1.44}/falyx/exceptions.py +0 -0
  41. {falyx-0.1.42 → falyx-0.1.44}/falyx/execution_registry.py +0 -0
  42. {falyx-0.1.42 → falyx-0.1.44}/falyx/hook_manager.py +0 -0
  43. {falyx-0.1.42 → falyx-0.1.44}/falyx/hooks.py +0 -0
  44. {falyx-0.1.42 → falyx-0.1.44}/falyx/init.py +0 -0
  45. {falyx-0.1.42 → falyx-0.1.44}/falyx/logger.py +0 -0
  46. {falyx-0.1.42 → falyx-0.1.44}/falyx/menu.py +0 -0
  47. {falyx-0.1.42 → falyx-0.1.44}/falyx/options_manager.py +0 -0
  48. {falyx-0.1.42 → falyx-0.1.44}/falyx/parsers/.pytyped +0 -0
  49. {falyx-0.1.42 → falyx-0.1.44}/falyx/parsers/argparse.py +0 -0
  50. {falyx-0.1.42 → falyx-0.1.44}/falyx/parsers/utils.py +0 -0
  51. {falyx-0.1.42 → falyx-0.1.44}/falyx/prompt_utils.py +0 -0
  52. {falyx-0.1.42 → falyx-0.1.44}/falyx/protocols.py +0 -0
  53. {falyx-0.1.42 → falyx-0.1.44}/falyx/retry.py +0 -0
  54. {falyx-0.1.42 → falyx-0.1.44}/falyx/retry_utils.py +0 -0
  55. {falyx-0.1.42 → falyx-0.1.44}/falyx/selection.py +0 -0
  56. {falyx-0.1.42 → falyx-0.1.44}/falyx/signals.py +0 -0
  57. {falyx-0.1.42 → falyx-0.1.44}/falyx/tagged_table.py +0 -0
  58. {falyx-0.1.42 → falyx-0.1.44}/falyx/themes/__init__.py +0 -0
  59. {falyx-0.1.42 → falyx-0.1.44}/falyx/themes/colors.py +0 -0
  60. {falyx-0.1.42 → falyx-0.1.44}/falyx/utils.py +0 -0
  61. {falyx-0.1.42 → falyx-0.1.44}/falyx/validators.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: falyx
3
- Version: 0.1.42
3
+ Version: 0.1.44
4
4
  Summary: Reliable and introspectable async CLI action framework.
5
5
  License: MIT
6
6
  Author: Roland Thomas Jr
@@ -8,12 +8,13 @@ Licensed under the MIT License. See LICENSE file for details.
8
8
  import asyncio
9
9
  import os
10
10
  import sys
11
+ from argparse import ArgumentParser, Namespace, _SubParsersAction
11
12
  from pathlib import Path
12
13
  from typing import Any
13
14
 
14
15
  from falyx.config import loader
15
16
  from falyx.falyx import Falyx
16
- from falyx.parsers import CommandArgumentParser
17
+ from falyx.parsers import CommandArgumentParser, get_root_parser, get_subparsers
17
18
 
18
19
 
19
20
  def find_falyx_config() -> Path | None:
@@ -48,6 +49,42 @@ def init_config(parser: CommandArgumentParser) -> None:
48
49
  )
49
50
 
50
51
 
52
+ def init_callback(args: Namespace) -> None:
53
+ """Callback for the init command."""
54
+ if args.command == "init":
55
+ from falyx.init import init_project
56
+
57
+ init_project(args.name)
58
+ elif args.command == "init_global":
59
+ from falyx.init import init_global
60
+
61
+ init_global()
62
+
63
+
64
+ def get_parsers() -> tuple[ArgumentParser, _SubParsersAction]:
65
+ root_parser: ArgumentParser = get_root_parser()
66
+ subparsers = get_subparsers(root_parser)
67
+ init_parser = subparsers.add_parser(
68
+ "init",
69
+ help="Initialize a new Falyx project",
70
+ description="Create a new Falyx project with mock configuration files.",
71
+ epilog="If no name is provided, the current directory will be used.",
72
+ )
73
+ init_parser.add_argument(
74
+ "name",
75
+ type=str,
76
+ help="Name of the new Falyx project",
77
+ default=".",
78
+ nargs="?",
79
+ )
80
+ subparsers.add_parser(
81
+ "init-global",
82
+ help="Initialize Falyx global configuration",
83
+ description="Create a global Falyx configuration at ~/.config/falyx/.",
84
+ )
85
+ return root_parser, subparsers
86
+
87
+
51
88
  def main() -> Any:
52
89
  bootstrap_path = bootstrap()
53
90
  if not bootstrap_path:
@@ -60,17 +97,23 @@ def main() -> Any:
60
97
  init_project,
61
98
  aliases=["init"],
62
99
  argument_config=init_config,
100
+ help_epilogue="If no name is provided, the current directory will be used.",
63
101
  )
64
102
  flx.add_command(
65
103
  "G",
66
104
  "Initialize Falyx global configuration",
67
105
  init_global,
68
106
  aliases=["init-global"],
107
+ help_text="Create a global Falyx configuration at ~/.config/falyx/.",
69
108
  )
70
109
  else:
71
110
  flx = loader(bootstrap_path)
72
111
 
73
- return asyncio.run(flx.run())
112
+ root_parser, subparsers = get_parsers()
113
+
114
+ return asyncio.run(
115
+ flx.run(root_parser=root_parser, subparsers=subparsers, callback=init_callback)
116
+ )
74
117
 
75
118
 
76
119
  if __name__ == "__main__":
@@ -135,6 +135,7 @@ class Command(BaseModel):
135
135
  custom_help: Callable[[], str | None] | None = None
136
136
  auto_args: bool = True
137
137
  arg_metadata: dict[str, str | dict[str, Any]] = Field(default_factory=dict)
138
+ simple_help_signature: bool = False
138
139
 
139
140
  _context: ExecutionContext | None = PrivateAttr(default=None)
140
141
 
@@ -317,6 +318,22 @@ class Command(BaseModel):
317
318
  options_text = self.arg_parser.get_options_text(plain_text=True)
318
319
  return f" {command_keys_text:<20} {options_text} "
319
320
 
321
+ @property
322
+ def help_signature(self) -> str:
323
+ """Generate a help signature for the command."""
324
+ if self.arg_parser and not self.simple_help_signature:
325
+ signature = [self.arg_parser.get_usage()]
326
+ signature.append(f" {self.help_text or self.description}")
327
+ if self.tags:
328
+ signature.append(f" [dim]Tags: {', '.join(self.tags)}[/dim]")
329
+ return "\n".join(signature).strip()
330
+
331
+ command_keys = " | ".join(
332
+ [f"[{self.style}]{self.key}[/{self.style}]"]
333
+ + [f"[{self.style}]{alias}[/{self.style}]" for alias in self.aliases]
334
+ )
335
+ return f"{command_keys} {self.description}"
336
+
320
337
  def log_summary(self) -> None:
321
338
  if self._context:
322
339
  self._context.log_summary()
@@ -25,7 +25,7 @@ import asyncio
25
25
  import logging
26
26
  import shlex
27
27
  import sys
28
- from argparse import Namespace
28
+ from argparse import ArgumentParser, Namespace, _SubParsersAction
29
29
  from difflib import get_close_matches
30
30
  from enum import Enum
31
31
  from functools import cached_property
@@ -284,6 +284,7 @@ class Falyx:
284
284
  action=Action("Exit", action=_noop),
285
285
  aliases=["EXIT", "QUIT"],
286
286
  style=OneColors.DARK_RED,
287
+ simple_help_signature=True,
287
288
  )
288
289
 
289
290
  def _get_history_command(self) -> Command:
@@ -294,60 +295,71 @@ class Falyx:
294
295
  aliases=["HISTORY"],
295
296
  action=Action(name="View Execution History", action=er.summary),
296
297
  style=OneColors.DARK_YELLOW,
298
+ simple_help_signature=True,
297
299
  )
298
300
 
299
- async def _show_help(self):
300
- table = Table(title="[bold cyan]Help Menu[/]", box=box.SIMPLE)
301
- table.add_column("Key", style="bold", no_wrap=True)
302
- table.add_column("Aliases", style="dim", no_wrap=True)
303
- table.add_column("Description", style="dim", overflow="fold")
304
- table.add_column("Tags", style="dim", no_wrap=True)
305
-
306
- for command in self.commands.values():
307
- help_text = command.help_text or command.description
308
- table.add_row(
309
- f"[{command.style}]{command.key}[/]",
310
- ", ".join(command.aliases) if command.aliases else "",
311
- help_text,
312
- ", ".join(command.tags) if command.tags else "",
301
+ async def _show_help(self, tag: str = "") -> None:
302
+ if tag:
303
+ table = Table(
304
+ title=tag.upper(),
305
+ title_justify="left",
306
+ show_header=False,
307
+ box=box.SIMPLE,
308
+ show_footer=False,
313
309
  )
314
-
315
- table.add_row(
316
- f"[{self.exit_command.style}]{self.exit_command.key}[/]",
317
- ", ".join(self.exit_command.aliases),
318
- "Exit this menu or program",
319
- )
320
-
321
- if self.history_command:
322
- table.add_row(
323
- f"[{self.history_command.style}]{self.history_command.key}[/]",
324
- ", ".join(self.history_command.aliases),
325
- "History of executed actions",
310
+ tag_lower = tag.lower()
311
+ commands = [
312
+ command
313
+ for command in self.commands.values()
314
+ if any(tag_lower == tag.lower() for tag in command.tags)
315
+ ]
316
+ for command in commands:
317
+ table.add_row(command.help_signature)
318
+ self.console.print(table)
319
+ return
320
+ else:
321
+ table = Table(
322
+ title="Help",
323
+ title_justify="left",
324
+ title_style=OneColors.LIGHT_YELLOW_b,
325
+ show_header=False,
326
+ show_footer=False,
327
+ box=box.SIMPLE,
326
328
  )
327
-
329
+ for command in self.commands.values():
330
+ table.add_row(command.help_signature)
328
331
  if self.help_command:
329
- table.add_row(
330
- f"[{self.help_command.style}]{self.help_command.key}[/]",
331
- ", ".join(self.help_command.aliases),
332
- "Show this help menu",
333
- )
334
-
335
- self.console.print(table, justify="center")
336
- if self.mode == FalyxMode.MENU:
337
- self.console.print(
338
- f"📦 Tip: '[{OneColors.LIGHT_YELLOW}]?[KEY][/]' to preview a command "
339
- "before running it.\n",
340
- justify="center",
341
- )
332
+ table.add_row(self.help_command.help_signature)
333
+ if self.history_command:
334
+ table.add_row(self.history_command.help_signature)
335
+ table.add_row(self.exit_command.help_signature)
336
+ table.add_row(f"Tip: '[{OneColors.LIGHT_YELLOW}]?[KEY][/]' to preview a command ")
337
+ self.console.print(table)
342
338
 
343
339
  def _get_help_command(self) -> Command:
344
340
  """Returns the help command for the menu."""
341
+ parser = CommandArgumentParser(
342
+ command_key="H",
343
+ command_description="Help",
344
+ command_style=OneColors.LIGHT_YELLOW,
345
+ aliases=["?", "HELP", "LIST"],
346
+ )
347
+ parser.add_argument(
348
+ "-t",
349
+ "--tag",
350
+ nargs="?",
351
+ default="",
352
+ help="Optional tag to filter commands by.",
353
+ )
345
354
  return Command(
346
355
  key="H",
347
- aliases=["HELP", "?"],
356
+ aliases=["?", "HELP", "LIST"],
348
357
  description="Help",
358
+ help_text="Show this help menu",
349
359
  action=Action("Help", self._show_help),
350
360
  style=OneColors.LIGHT_YELLOW,
361
+ arg_parser=parser,
362
+ auto_args=False,
351
363
  )
352
364
 
353
365
  def _get_completer(self) -> WordCompleter:
@@ -568,7 +580,9 @@ class Falyx:
568
580
  if not isinstance(submenu, Falyx):
569
581
  raise NotAFalyxError("submenu must be an instance of Falyx.")
570
582
  self._validate_command_key(key)
571
- self.add_command(key, description, submenu.menu, style=style)
583
+ self.add_command(
584
+ key, description, submenu.menu, style=style, simple_help_signature=True
585
+ )
572
586
  if submenu.exit_command.key == "X":
573
587
  submenu.update_exit_command(key="B", description="Back", aliases=["BACK"])
574
588
 
@@ -630,6 +644,7 @@ class Falyx:
630
644
  custom_help: Callable[[], str | None] | None = None,
631
645
  auto_args: bool = True,
632
646
  arg_metadata: dict[str, str | dict[str, Any]] | None = None,
647
+ simple_help_signature: bool = False,
633
648
  ) -> Command:
634
649
  """Adds an command to the menu, preventing duplicates."""
635
650
  self._validate_command_key(key)
@@ -682,6 +697,7 @@ class Falyx:
682
697
  custom_help=custom_help,
683
698
  auto_args=auto_args,
684
699
  arg_metadata=arg_metadata or {},
700
+ simple_help_signature=simple_help_signature,
685
701
  )
686
702
 
687
703
  if hooks:
@@ -706,16 +722,16 @@ class Falyx:
706
722
  def get_bottom_row(self) -> list[str]:
707
723
  """Returns the bottom row of the table for displaying additional commands."""
708
724
  bottom_row = []
709
- if self.history_command:
710
- bottom_row.append(
711
- f"[{self.history_command.key}] [{self.history_command.style}]"
712
- f"{self.history_command.description}"
713
- )
714
725
  if self.help_command:
715
726
  bottom_row.append(
716
727
  f"[{self.help_command.key}] [{self.help_command.style}]"
717
728
  f"{self.help_command.description}"
718
729
  )
730
+ if self.history_command:
731
+ bottom_row.append(
732
+ f"[{self.history_command.key}] [{self.history_command.style}]"
733
+ f"{self.history_command.description}"
734
+ )
719
735
  bottom_row.append(
720
736
  f"[{self.exit_command.key}] [{self.exit_command.style}]"
721
737
  f"{self.exit_command.description}"
@@ -727,12 +743,14 @@ class Falyx:
727
743
  Build the standard table layout. Developers can subclass or call this
728
744
  in custom tables.
729
745
  """
730
- table = Table(title=self.title, show_header=False, box=box.SIMPLE, expand=True) # type: ignore[arg-type]
746
+ table = Table(title=self.title, show_header=False, box=box.SIMPLE) # type: ignore[arg-type]
731
747
  visible_commands = [item for item in self.commands.items() if not item[1].hidden]
748
+ space = self.console.width // self.columns
732
749
  for chunk in chunks(visible_commands, self.columns):
733
750
  row = []
734
751
  for key, command in chunk:
735
- row.append(f"[{key}] [{command.style}]{command.description}")
752
+ cell = f"[{key}] [{command.style}]{command.description}"
753
+ row.append(f"{cell:<{space}}")
736
754
  table.add_row(*row)
737
755
  bottom_row = self.get_bottom_row()
738
756
  for row in chunks(bottom_row, self.columns):
@@ -1029,6 +1047,8 @@ class Falyx:
1029
1047
  async def run(
1030
1048
  self,
1031
1049
  falyx_parsers: FalyxParsers | None = None,
1050
+ root_parser: ArgumentParser | None = None,
1051
+ subparsers: _SubParsersAction | None = None,
1032
1052
  callback: Callable[..., Any] | None = None,
1033
1053
  ) -> None:
1034
1054
  """Run Falyx CLI with structured subcommands."""
@@ -1046,6 +1066,8 @@ class Falyx:
1046
1066
  self.description,
1047
1067
  self.epilog,
1048
1068
  commands=self.commands,
1069
+ root_parser=root_parser,
1070
+ subparsers=subparsers,
1049
1071
  )
1050
1072
  self.cli_args = falyx_parsers.parse_args()
1051
1073
  self.options.from_namespace(self.cli_args, "cli_args")
@@ -1072,7 +1094,7 @@ class Falyx:
1072
1094
  self.register_all_with_debug_hooks()
1073
1095
 
1074
1096
  if self.cli_args.command == "list":
1075
- await self._show_help()
1097
+ await self._show_help(tag=self.cli_args.tag)
1076
1098
  sys.exit(0)
1077
1099
 
1078
1100
  if self.cli_args.command == "version" or self.cli_args.version:
@@ -6,12 +6,14 @@ Licensed under the MIT License. See LICENSE file for details.
6
6
  """
7
7
 
8
8
  from .argparse import Argument, ArgumentAction, CommandArgumentParser
9
- from .parsers import FalyxParsers, get_arg_parsers
9
+ from .parsers import FalyxParsers, get_arg_parsers, get_root_parser, get_subparsers
10
10
 
11
11
  __all__ = [
12
12
  "Argument",
13
13
  "ArgumentAction",
14
14
  "CommandArgumentParser",
15
15
  "get_arg_parsers",
16
+ "get_root_parser",
17
+ "get_subparsers",
16
18
  "FalyxParsers",
17
19
  ]
@@ -40,7 +40,7 @@ class FalyxParsers:
40
40
  return self.as_dict().get(name)
41
41
 
42
42
 
43
- def get_arg_parsers(
43
+ def get_root_parser(
44
44
  prog: str | None = "falyx",
45
45
  usage: str | None = None,
46
46
  description: str | None = "Falyx CLI - Run structured async command workflows.",
@@ -55,9 +55,7 @@ def get_arg_parsers(
55
55
  add_help: bool = True,
56
56
  allow_abbrev: bool = True,
57
57
  exit_on_error: bool = True,
58
- commands: dict[str, Command] | None = None,
59
- ) -> FalyxParsers:
60
- """Returns the argument parser for the CLI."""
58
+ ) -> ArgumentParser:
61
59
  parser = ArgumentParser(
62
60
  prog=prog,
63
61
  usage=usage,
@@ -86,7 +84,70 @@ def get_arg_parsers(
86
84
  help="Enable default lifecycle debug logging",
87
85
  )
88
86
  parser.add_argument("--version", action="store_true", help="Show Falyx version")
89
- subparsers = parser.add_subparsers(dest="command")
87
+ return parser
88
+
89
+
90
+ def get_subparsers(
91
+ parser: ArgumentParser,
92
+ title: str = "Falyx Commands",
93
+ description: str | None = "Available commands for the Falyx CLI.",
94
+ ) -> _SubParsersAction:
95
+ """Create and return a subparsers action for the given parser."""
96
+ if not isinstance(parser, ArgumentParser):
97
+ raise TypeError("parser must be an instance of ArgumentParser")
98
+ subparsers = parser.add_subparsers(
99
+ title=title,
100
+ description=description,
101
+ metavar="COMMAND",
102
+ dest="command",
103
+ )
104
+ return subparsers
105
+
106
+
107
+ def get_arg_parsers(
108
+ prog: str | None = "falyx",
109
+ usage: str | None = None,
110
+ description: str | None = "Falyx CLI - Run structured async command workflows.",
111
+ epilog: (
112
+ str | None
113
+ ) = "Tip: Use 'falyx run ?[COMMAND]' to preview any command from the CLI.",
114
+ parents: Sequence[ArgumentParser] | None = None,
115
+ prefix_chars: str = "-",
116
+ fromfile_prefix_chars: str | None = None,
117
+ argument_default: Any = None,
118
+ conflict_handler: str = "error",
119
+ add_help: bool = True,
120
+ allow_abbrev: bool = True,
121
+ exit_on_error: bool = True,
122
+ commands: dict[str, Command] | None = None,
123
+ root_parser: ArgumentParser | None = None,
124
+ subparsers: _SubParsersAction | None = None,
125
+ ) -> FalyxParsers:
126
+ """Returns the argument parser for the CLI."""
127
+ if root_parser is None:
128
+ parser = get_root_parser(
129
+ prog=prog,
130
+ usage=usage,
131
+ description=description,
132
+ epilog=epilog,
133
+ parents=parents,
134
+ prefix_chars=prefix_chars,
135
+ fromfile_prefix_chars=fromfile_prefix_chars,
136
+ argument_default=argument_default,
137
+ conflict_handler=conflict_handler,
138
+ add_help=add_help,
139
+ allow_abbrev=allow_abbrev,
140
+ exit_on_error=exit_on_error,
141
+ )
142
+ else:
143
+ if not isinstance(root_parser, ArgumentParser):
144
+ raise TypeError("root_parser must be an instance of ArgumentParser")
145
+ parser = root_parser
146
+
147
+ if subparsers is None:
148
+ subparsers = get_subparsers(parser)
149
+ if not isinstance(subparsers, _SubParsersAction):
150
+ raise TypeError("subparsers must be an instance of _SubParsersAction")
90
151
 
91
152
  run_description = ["Run a command by its key or alias.\n"]
92
153
  run_description.append("commands:")
@@ -105,7 +166,9 @@ def get_arg_parsers(
105
166
  epilog=run_epilog,
106
167
  formatter_class=RawDescriptionHelpFormatter,
107
168
  )
108
- run_parser.add_argument("name", help="Run a command by its key or alias")
169
+ run_parser.add_argument(
170
+ "name", help="Run a command by its key or alias", metavar="COMMAND"
171
+ )
109
172
  run_parser.add_argument(
110
173
  "--summary",
111
174
  action="store_true",
@@ -143,6 +206,7 @@ def get_arg_parsers(
143
206
  "command_args",
144
207
  nargs=REMAINDER,
145
208
  help="Arguments to pass to the command (if applicable)",
209
+ metavar="ARGS",
146
210
  )
147
211
 
148
212
  run_all_parser = subparsers.add_parser(
@@ -191,6 +255,10 @@ def get_arg_parsers(
191
255
  "list", help="List all available commands with tags"
192
256
  )
193
257
 
258
+ list_parser.add_argument(
259
+ "-t", "--tag", help="Filter commands by tag (case-insensitive)", default=None
260
+ )
261
+
194
262
  version_parser = subparsers.add_parser("version", help="Show the Falyx version")
195
263
 
196
264
  return FalyxParsers(
@@ -24,7 +24,6 @@ def infer_args_from_func(
24
24
  metadata = (
25
25
  {"help": raw_metadata} if isinstance(raw_metadata, str) else raw_metadata
26
26
  )
27
-
28
27
  if param.kind not in (
29
28
  inspect.Parameter.POSITIONAL_ONLY,
30
29
  inspect.Parameter.POSITIONAL_OR_KEYWORD,
@@ -35,6 +34,8 @@ def infer_args_from_func(
35
34
  arg_type = (
36
35
  param.annotation if param.annotation is not inspect.Parameter.empty else str
37
36
  )
37
+ if isinstance(arg_type, str):
38
+ arg_type = str
38
39
  default = param.default if param.default is not inspect.Parameter.empty else None
39
40
  is_required = param.default is inspect.Parameter.empty
40
41
  if is_required:
@@ -0,0 +1 @@
1
+ __version__ = "0.1.44"
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "falyx"
3
- version = "0.1.42"
3
+ version = "0.1.44"
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.42"
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
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes