From 06bf0e432cfd35996ef0ed18e31d7c3408cbea58 Mon Sep 17 00:00:00 2001 From: Roland Thomas Date: Mon, 11 Aug 2025 19:51:49 -0400 Subject: [PATCH] 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. --- falyx/falyx.py | 6 +++--- falyx/parser/command_argument_parser.py | 27 ++++++++++++++++--------- falyx/parser/signature.py | 12 +++++++++++ falyx/version.py | 2 +- pyproject.toml | 2 +- 5 files changed, 34 insertions(+), 15 deletions(-) diff --git a/falyx/falyx.py b/falyx/falyx.py index 96e6e76..a0a2909 100644 --- a/falyx/falyx.py +++ b/falyx/falyx.py @@ -411,7 +411,7 @@ class Falyx: self.console.print(f"[bold]tip:[/bold] {self.get_tip()}") return None 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: command.arg_parser.render_tldr() self.console.print(f"[bold]tip:[/bold] {self.get_tip()}") @@ -941,7 +941,7 @@ class Falyx: return False, input_str.strip() 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]]: """ Returns the selected command based on user input. @@ -982,7 +982,7 @@ class Falyx: logger.info("Command '%s' selected.", run_command.key) if is_preview: 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 try: args, kwargs = await run_command.parse_args(input_args, from_validate) diff --git a/falyx/parser/command_argument_parser.py b/falyx/parser/command_argument_parser.py index 4120525..07d4f76 100644 --- a/falyx/parser/command_argument_parser.py +++ b/falyx/parser/command_argument_parser.py @@ -913,10 +913,18 @@ class CommandArgumentParser: arg_states[spec.dest].set_consumed() raise HelpSignal() 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() - arg_states[spec.dest].set_consumed() - raise HelpSignal() + arg_states[spec.dest].set_consumed() + raise HelpSignal() + else: + arg_states[spec.dest].set_consumed() + raise HelpSignal() elif action == ArgumentAction.ACTION: assert isinstance( spec.resolver, BaseAction @@ -1129,11 +1137,7 @@ class CommandArgumentParser: # Required validation for spec in self._arguments: - if ( - spec.dest == "help" - or spec.dest == "tldr" - and spec.action == ArgumentAction.TLDR - ): + if spec.dest == "help" or spec.dest == "tldr": continue if spec.required and not result.get(spec.dest): help_text = f" help: {spec.help}" if spec.help else "" @@ -1184,7 +1188,8 @@ class CommandArgumentParser: ) result.pop("help", None) - result.pop("tldr", None) + if not self._is_help_command: + result.pop("tldr", None) return result async def parse_args_split( @@ -1202,7 +1207,9 @@ class CommandArgumentParser: args_list = [] kwargs_dict = {} 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 if arg.positional: args_list.append(parsed[arg.dest]) diff --git a/falyx/parser/signature.py b/falyx/parser/signature.py index 1cd6889..da1f28a 100644 --- a/falyx/parser/signature.py +++ b/falyx/parser/signature.py @@ -26,6 +26,18 @@ def infer_args_from_func( This utility inspects the parameters of a function and returns a list of dictionaries, 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: func (Callable | None): The function to inspect. arg_metadata (dict | None): Optional metadata overrides for help text, type hints, diff --git a/falyx/version.py b/falyx/version.py index 2459c36..b5a66f5 100644 --- a/falyx/version.py +++ b/falyx/version.py @@ -1 +1 @@ -__version__ = "0.1.83" +__version__ = "0.1.84" diff --git a/pyproject.toml b/pyproject.toml index 1040f13..1ed1906 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "falyx" -version = "0.1.83" +version = "0.1.84" description = "Reliable and introspectable async CLI action framework." authors = ["Roland Thomas Jr "] license = "MIT"