Replies: 8 comments 2 replies
-
In my own code, I use an @unique
class HelpPanel(str, Enum):
Creation = "Creation"
Configuration = "Configuration"
Startup = "Startup" I wonder if the API used an I use an |
Beta Was this translation helpful? Give feedback.
-
@mike0sv (and others looking to achieve something similar) this might help for the time being: from click import Context
import typer
from typer.core import TyperGroup
class OrderCommands(TyperGroup):
def list_commands(self, ctx: Context):
"""Return list of commands in the order appear."""
return list(self.commands) # get commands using self.commands
app = typer.Typer(
cls=OrderCommands,
)
... |
Beta Was this translation helpful? Give feedback.
-
@iameskild Thanks for the suggestion. I tried this out, but The panel grouping must be applied after this step? |
Beta Was this translation helpful? Give feedback.
-
As I mentioned, the actual order of panels in help text is the order of keys in some dict inside formatting function. So probably there is no way to influence it unless you monkey-patch that function |
Beta Was this translation helpful? Give feedback.
-
I would suspect, then, that the order that the panels appears should, in later versions of Python or at least CPython (where Dict key order is guaranteed), this would then be influenced directly by the order in which you declare your commands... Or at least, by the order in which the decorators are parsed. You can cheat this in a few ways, but the one I came up with on the spot is as follows: from typer import Typer
from typer.models import CommandFunctionType
from typing import Optional, List, Callable
from collections import defaultdict
class PanelOrderedTyper(Typer):
def init(self, *, rich_help_panel_order: Optional[List[str]] = None, **kwargs: Any):
super().__init__(**kwargs)
self.rich_help_panel_order = rich_help_panel_order
self._rich_help_panels_commands = defaultdict(list)
def command(self, *, rich_help_panel: Optional[str] = None, **kwargs: Any) -> Callable[[CommandFunctionType], CommandFunctionType]:
def decorator(f: CommandFunctionType) -> CommandFunctionType:
if rich_help_panel is not None:
# Defer original decorator's functionality for later
self._rich_help_panels_commands[rich_help_panel].append((f,kwargs))
else:
# But we don't care to defer those that don't have a named panel
return super().command(**kwargs)(f)
return f
return decorator
def __call__(self, *args: Any, **kwargs: Any) -> Any:
for _panel in self.rich_help_panel_order: # All known in order
for _panel_command in self._rich_help_panels_commands[_panel]:
_f, _kwargs = _panel_command
super().command(rich_help_panel=_panel, **_kwargs)(_f)
for _panel in self._rich_help_panels_commands.keys(): # Handle any not in order list
if _panel not in self.rich_help_panel_order:
for _panel_command in self._rich_help_panels_commands[_panel]:
_f, _kwargs = _panel_command
super().command(rich_help_panel=_panel, **_kwargs)(_f)
return super().__call__(*args, **kwargs)
app = PanelOrderedTyper(rich_help_panel_order=['first', 'second'])
[...] (Untested, ymmv, sorry) ... But I sort of suspect that might be more work (and certainly more jank) than implementing it in the core 😅 |
Beta Was this translation helpful? Give feedback.
-
In case of a mix of app = typer.Typer(
cls=OrderCommands,
add_completion=False,
add_help_option=True,
rich_markup_mode="rich",
)
app.command(
name='command-1',
)(some_function)
app.add_typer(
some_typer_app,
name="group-of-commands-1",
) this helped me : class OrderCommands(TyperGroup):
def list_commands(self, ctx: Context):
"""Return list of commands in the order they appear.
See: https://github.com/tiangolo/typer/issues/428#issuecomment-1238866548
"""
order = ["command-1", "group-of-commands-1", "command-2", "group-of-commands-2", "some-other-command"]
ordered_commands = [command for command in order if command in self.commands]
additional_commands = [
command for command in self.commands if command not in ordered_commands
]
return ordered_commands + additional_commands |
Beta Was this translation helpful? Give feedback.
-
[Maintenance note]: moving this to the discussion forum as it's a feature request - we can continue the discussion there! 🙏 |
Beta Was this translation helpful? Give feedback.
-
Here's my solution, it uses the order the enum values are defined to set the order of the groups in help: class Panel(str, Enum):
Creation = "Creation"
Configuration = "Configuration"
Startup = "Startup"
class OrderCommands(TyperGroup):
def list_commands(self, _ctx: Context) -> list[str]:
order = list(Panel)
grouped_commands = {
name: getattr(command, "rich_help_panel")
for name, command in sorted(self.commands.items())
if getattr(command, "rich_help_panel") in order
}
ungrouped_command_names = [
command.name
for command in self.commands.values()
if command.name not in grouped_commands
]
return [
name
for name, command in sorted(
grouped_commands.items(),
key=lambda item: order.index(item[1]),
)
] + sorted(ungrouped_command_names)
app = typer.Typer(
cls=OrderCommands,
…
)
@app.command(name="create", rich_help_panel=Panel.Creation)
def cli_create() -> None:
pass |
Beta Was this translation helpful? Give feedback.
-
First Check
Commit to Help
Example Code
Description
New typer version introduced
rich_help_panel
option for commands and groups, which groups together different commands for multi-command help message. However there is no way to set the order of different panels (it's semi-random depending on the order ofpanel_to_commands
dict insiderich_format_text
function). It would be nice to have an option to configure this orderWanted Solution
see code example above
Wanted Code
Alternatives
No response
Operating System
Other
Operating System Details
No response
Typer Version
0.6.1
Python Version
3.9.4
Additional Context
No response
Beta Was this translation helpful? Give feedback.
All reactions