feat(help): improve TLDR/help handling for help context commands
- Added `from_help` flag to `get_command()` to allow help rendering without full CLI execution flow. - Updated `_render_help()` to pass `from_help=True` when fetching commands. - Enhanced TLDR parsing: - Allow TLDR flag to be processed and retained when running inside a help command (`_is_help_command=True`). - Skip removing `"tldr"` from results in help context to preserve intended behavior. - Ensure TLDR args are still marked consumed to maintain state consistency. - Simplified required argument validation to skip both `help` and `tldr` without special action checks. - Adjusted `parse_args_split()` to include `tldr` values in help commands while skipping them for normal commands. - Expanded `infer_args_from_func()` docstring with supported features and parameter handling details. - Bumped version to 0.1.84.
This commit is contained in:
		| @@ -411,7 +411,7 @@ class Falyx: | |||||||
|                 self.console.print(f"[bold]tip:[/bold] {self.get_tip()}") |                 self.console.print(f"[bold]tip:[/bold] {self.get_tip()}") | ||||||
|                 return None |                 return None | ||||||
|         if key: |         if key: | ||||||
|             _, command, args, kwargs = await self.get_command(key) |             _, command, args, kwargs = await self.get_command(key, from_help=True) | ||||||
|             if command and tldr and command.arg_parser: |             if command and tldr and command.arg_parser: | ||||||
|                 command.arg_parser.render_tldr() |                 command.arg_parser.render_tldr() | ||||||
|                 self.console.print(f"[bold]tip:[/bold] {self.get_tip()}") |                 self.console.print(f"[bold]tip:[/bold] {self.get_tip()}") | ||||||
| @@ -941,7 +941,7 @@ class Falyx: | |||||||
|         return False, input_str.strip() |         return False, input_str.strip() | ||||||
|  |  | ||||||
|     async def get_command( |     async def get_command( | ||||||
|         self, raw_choices: str, from_validate=False |         self, raw_choices: str, from_validate=False, from_help=False | ||||||
|     ) -> tuple[bool, Command | None, tuple, dict[str, Any]]: |     ) -> tuple[bool, Command | None, tuple, dict[str, Any]]: | ||||||
|         """ |         """ | ||||||
|         Returns the selected command based on user input. |         Returns the selected command based on user input. | ||||||
| @@ -982,7 +982,7 @@ class Falyx: | |||||||
|                 logger.info("Command '%s' selected.", run_command.key) |                 logger.info("Command '%s' selected.", run_command.key) | ||||||
|             if is_preview: |             if is_preview: | ||||||
|                 return True, run_command, args, kwargs |                 return True, run_command, args, kwargs | ||||||
|             elif self.is_cli_mode: |             elif self.is_cli_mode or from_help: | ||||||
|                 return False, run_command, args, kwargs |                 return False, run_command, args, kwargs | ||||||
|             try: |             try: | ||||||
|                 args, kwargs = await run_command.parse_args(input_args, from_validate) |                 args, kwargs = await run_command.parse_args(input_args, from_validate) | ||||||
|   | |||||||
| @@ -913,10 +913,18 @@ class CommandArgumentParser: | |||||||
|                 arg_states[spec.dest].set_consumed() |                 arg_states[spec.dest].set_consumed() | ||||||
|                 raise HelpSignal() |                 raise HelpSignal() | ||||||
|             elif action == ArgumentAction.TLDR: |             elif action == ArgumentAction.TLDR: | ||||||
|                 if not from_validate: |                 if self._is_help_command: | ||||||
|  |                     result[spec.dest] = True | ||||||
|  |                     arg_states[spec.dest].set_consumed() | ||||||
|  |                     consumed_indices.add(index) | ||||||
|  |                     index += 1 | ||||||
|  |                 elif not from_validate: | ||||||
|                     self.render_tldr() |                     self.render_tldr() | ||||||
|                 arg_states[spec.dest].set_consumed() |                     arg_states[spec.dest].set_consumed() | ||||||
|                 raise HelpSignal() |                     raise HelpSignal() | ||||||
|  |                 else: | ||||||
|  |                     arg_states[spec.dest].set_consumed() | ||||||
|  |                     raise HelpSignal() | ||||||
|             elif action == ArgumentAction.ACTION: |             elif action == ArgumentAction.ACTION: | ||||||
|                 assert isinstance( |                 assert isinstance( | ||||||
|                     spec.resolver, BaseAction |                     spec.resolver, BaseAction | ||||||
| @@ -1129,11 +1137,7 @@ class CommandArgumentParser: | |||||||
|  |  | ||||||
|         # Required validation |         # Required validation | ||||||
|         for spec in self._arguments: |         for spec in self._arguments: | ||||||
|             if ( |             if spec.dest == "help" or spec.dest == "tldr": | ||||||
|                 spec.dest == "help" |  | ||||||
|                 or spec.dest == "tldr" |  | ||||||
|                 and spec.action == ArgumentAction.TLDR |  | ||||||
|             ): |  | ||||||
|                 continue |                 continue | ||||||
|             if spec.required and not result.get(spec.dest): |             if spec.required and not result.get(spec.dest): | ||||||
|                 help_text = f" help: {spec.help}" if spec.help else "" |                 help_text = f" help: {spec.help}" if spec.help else "" | ||||||
| @@ -1184,7 +1188,8 @@ class CommandArgumentParser: | |||||||
|                     ) |                     ) | ||||||
|  |  | ||||||
|         result.pop("help", None) |         result.pop("help", None) | ||||||
|         result.pop("tldr", None) |         if not self._is_help_command: | ||||||
|  |             result.pop("tldr", None) | ||||||
|         return result |         return result | ||||||
|  |  | ||||||
|     async def parse_args_split( |     async def parse_args_split( | ||||||
| @@ -1202,7 +1207,9 @@ class CommandArgumentParser: | |||||||
|         args_list = [] |         args_list = [] | ||||||
|         kwargs_dict = {} |         kwargs_dict = {} | ||||||
|         for arg in self._arguments: |         for arg in self._arguments: | ||||||
|             if arg.dest in ("help", "tldr"): |             if arg.dest == "help": | ||||||
|  |                 continue | ||||||
|  |             if arg.dest == "tldr" and not self._is_help_command: | ||||||
|                 continue |                 continue | ||||||
|             if arg.positional: |             if arg.positional: | ||||||
|                 args_list.append(parsed[arg.dest]) |                 args_list.append(parsed[arg.dest]) | ||||||
|   | |||||||
| @@ -26,6 +26,18 @@ def infer_args_from_func( | |||||||
|     This utility inspects the parameters of a function and returns a list of dictionaries, |     This utility inspects the parameters of a function and returns a list of dictionaries, | ||||||
|     each of which can be passed to `CommandArgumentParser.add_argument()`. |     each of which can be passed to `CommandArgumentParser.add_argument()`. | ||||||
|  |  | ||||||
|  |     It supports: | ||||||
|  |     - Positional and keyword arguments | ||||||
|  |     - Type hints for argument types | ||||||
|  |     - Default values | ||||||
|  |     - Required vs optional arguments | ||||||
|  |     - Custom help text, choices, and suggestions via metadata | ||||||
|  |  | ||||||
|  |     Note: | ||||||
|  |         - Only parameters with kind `POSITIONAL_ONLY`, `POSITIONAL_OR_KEYWORD`, or | ||||||
|  |           `KEYWORD_ONLY` are considered. | ||||||
|  |         - Parameters with kind `VAR_POSITIONAL` or `VAR_KEYWORD` are ignored. | ||||||
|  |  | ||||||
|     Args: |     Args: | ||||||
|         func (Callable | None): The function to inspect. |         func (Callable | None): The function to inspect. | ||||||
|         arg_metadata (dict | None): Optional metadata overrides for help text, type hints, |         arg_metadata (dict | None): Optional metadata overrides for help text, type hints, | ||||||
|   | |||||||
| @@ -1 +1 @@ | |||||||
| __version__ = "0.1.83" | __version__ = "0.1.84" | ||||||
|   | |||||||
| @@ -1,6 +1,6 @@ | |||||||
| [tool.poetry] | [tool.poetry] | ||||||
| name = "falyx" | name = "falyx" | ||||||
| version = "0.1.83" | version = "0.1.84" | ||||||
| description = "Reliable and introspectable async CLI action framework." | description = "Reliable and introspectable async CLI action framework." | ||||||
| authors = ["Roland Thomas Jr <roland@rtj.dev>"] | authors = ["Roland Thomas Jr <roland@rtj.dev>"] | ||||||
| license = "MIT" | license = "MIT" | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user