Skip to content

Commit

Permalink
Merge pull request #156 from dwreeves/use-typeddicts
Browse files Browse the repository at this point in the history
TypedDicts for option and command groups
  • Loading branch information
dwreeves authored Feb 4, 2024
2 parents cfd2731 + 2276c42 commit 8cb5c8e
Show file tree
Hide file tree
Showing 6 changed files with 42 additions and 19 deletions.
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@

## Version 1.8.0dev

- Lazy load Rich to reduce overhead when not rendering help text.
- Better typing for option groups and command groups with `TypedDict` [[#156](https://github.com/ewels/rich-click/pull/156)]
- Lazy load Rich to reduce overhead when not rendering help text. [[#154](https://github.com/ewels/rich-click/pull/154)]
- Some internal refactors. These refactors are aimed at making the abstractions more maintainable over time, more consistent, and more adept for advanced used cases.
- `rich_click.py` is exclusively the global config; all formatting has been moved to `rich_help_rendering.py`.
- `RichCommand` now makes use of methods in the super class: `format_usage`, `format_help_text`, `format_options`, and `format_epilog`.
Expand Down
5 changes: 3 additions & 2 deletions src/rich_click/rich_click.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from typing_extensions import Literal

from rich_click.rich_help_configuration import force_terminal_default, terminal_width_default
from rich_click.utils import CommandGroupDict, OptionGroupDict


if TYPE_CHECKING:
Expand Down Expand Up @@ -91,9 +92,9 @@
USE_MARKDOWN_EMOJI: bool = True # Parse emoji codes in markdown :smile:
USE_RICH_MARKUP: bool = False # Parse help strings for rich markup (eg. [red]my text[/])
# Define sorted groups of panels to display subcommands
COMMAND_GROUPS: Dict[str, List[Dict[str, Union[str, List[str]]]]] = {}
COMMAND_GROUPS: Dict[str, List[CommandGroupDict]] = {}
# Define sorted groups of panels to display options and arguments
OPTION_GROUPS: Dict[str, List[Dict[str, Union[str, List[str], Dict[str, List[str]]]]]] = {}
OPTION_GROUPS: Dict[str, List[OptionGroupDict]] = {}
USE_CLICK_SHORT_HELP: bool = False # Use click's default function to truncate help text


Expand Down
11 changes: 6 additions & 5 deletions src/rich_click/rich_context.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
from typing import TYPE_CHECKING, Any, Mapping, Optional, Type, Union

import click
from rich.console import Console

from rich_click.rich_help_configuration import RichHelpConfiguration
from rich_click.rich_help_formatter import RichHelpFormatter
Expand All @@ -10,17 +9,19 @@
if TYPE_CHECKING:
from types import TracebackType

from rich.console import Console


class RichContext(click.Context):
"""Click Context class endowed with Rich superpowers."""

formatter_class: Type[RichHelpFormatter] = RichHelpFormatter
_console: Optional[Console] = None
_console: Optional["Console"] = None

def __init__(
self,
*args: Any,
rich_console: Optional[Console] = None,
rich_console: Optional["Console"] = None,
rich_help_config: Optional[Union[Mapping[str, Any], RichHelpConfiguration]] = None,
**kwargs: Any,
) -> None:
Expand Down Expand Up @@ -61,13 +62,13 @@ def __init__(
self.help_config = rich_help_config

@property
def console(self) -> Console:
def console(self) -> "Console":
if self._console is None:
return self.make_formatter().console
return self._console

@console.setter
def console(self, val: Console) -> None:
def console(self, val: "Console") -> None:
self._console = val

def make_formatter(self) -> RichHelpFormatter:
Expand Down
6 changes: 3 additions & 3 deletions src/rich_click/rich_help_configuration.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

from typing_extensions import Literal

from rich_click.utils import truthy
from rich_click.utils import CommandGroupDict, OptionGroupDict, truthy


if TYPE_CHECKING:
Expand Down Expand Up @@ -144,9 +144,9 @@ class RichHelpConfiguration:
"""Parse emoji codes in markdown :smile:"""
use_rich_markup: bool = field(default=False)
"""Parse help strings for rich markup (eg. [red]my text[/])"""
command_groups: Dict[str, List[Dict[str, Union[str, Any]]]] = field(default_factory=lambda: {})
command_groups: Dict[str, List[CommandGroupDict]] = field(default_factory=lambda: {})
"""Define sorted groups of panels to display subcommands"""
option_groups: Dict[str, List[Dict[str, Union[str, Any]]]] = field(default_factory=lambda: {})
option_groups: Dict[str, List[OptionGroupDict]] = field(default_factory=lambda: {})
"""Define sorted groups of panels to display options and arguments"""
use_click_short_help: bool = field(default=False)
"""Use click's default function to truncate help text"""
Expand Down
16 changes: 9 additions & 7 deletions src/rich_click/rich_help_rendering.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@

from rich_click._compat_click import CLICK_IS_BEFORE_VERSION_8X, CLICK_IS_BEFORE_VERSION_9X, CLICK_IS_VERSION_80
from rich_click.rich_help_formatter import RichHelpFormatter
from rich_click.utils import OptionGroupDict


# Support rich <= 10.6.0
Expand Down Expand Up @@ -369,16 +370,17 @@ def get_rich_options(
if isinstance(param, click.core.Argument) and not formatter.config.group_arguments_options:
argument_group_options.append(param.opts[0])
else:
list_of_option_groups: List[str] = option_groups[-1]["options"] # type: ignore[assignment]
list_of_option_groups = option_groups[-1]["options"]
list_of_option_groups.append(param.opts[0])

# If we're not grouping arguments and we got some, prepend before default options
if len(argument_group_options) > 0:
extra_option_group = {"name": formatter.config.arguments_panel_title, "options": argument_group_options}
extra_option_group: OptionGroupDict = {
"name": formatter.config.arguments_panel_title,
"options": argument_group_options,
}
option_groups.insert(len(option_groups) - 1, extra_option_group)

# print("!", option_groups)

# Print each option group panel
for option_group in option_groups:
options_rows = []
Expand Down Expand Up @@ -479,7 +481,7 @@ class MetavarHighlighter(RegexHighlighter):
"pad_edge": formatter.config.style_options_table_pad_edge,
"padding": formatter.config.style_options_table_padding,
}
t_styles.update(option_group.get("table_styles", {})) # type: ignore[arg-type]
t_styles.update(option_group.get("table_styles", {}))
box_style = getattr(box, t_styles.pop("box"), None) # type: ignore[arg-type]

options_table = Table(
Expand Down Expand Up @@ -518,7 +520,7 @@ class MetavarHighlighter(RegexHighlighter):
if command in cmd_group.get("commands", []):
break
else:
commands: List[str] = cmd_groups[-1]["commands"] # type: ignore[assignment]
commands = cmd_groups[-1]["commands"]
commands.append(command)

# Print each command group panel
Expand All @@ -532,7 +534,7 @@ class MetavarHighlighter(RegexHighlighter):
"pad_edge": formatter.config.style_commands_table_pad_edge,
"padding": formatter.config.style_commands_table_padding,
}
t_styles.update(cmd_group.get("table_styles", {})) # type: ignore[arg-type]
t_styles.update(cmd_group.get("table_styles", {}))
box_style = getattr(box, t_styles.pop("box"), None) # type: ignore[arg-type]

commands_table = Table(
Expand Down
20 changes: 19 additions & 1 deletion src/rich_click/utils.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
from typing import Any, Optional
from typing import Any, Dict, List, Optional

from typing_extensions import NotRequired, TypedDict


def truthy(o: Any) -> Optional[bool]:
Expand All @@ -14,3 +16,19 @@ def truthy(o: Any) -> Optional[bool]:
return None
else:
return bool(o)


class CommandGroupDict(TypedDict):
"""Specification for command groups."""

name: NotRequired[str]
commands: List[str]
table_styles: NotRequired[Dict[str, Any]]


class OptionGroupDict(TypedDict):
"""Specification for option groups."""

name: NotRequired[str]
options: List[str]
table_styles: NotRequired[Dict[str, Any]]

0 comments on commit 8cb5c8e

Please sign in to comment.