Configuration¶
There are two methods to configure rich-click:
- Decorator: Use the
@rich_config()
decorator (andRichHelpConfiguration()
). - Globals: Set the global variables in the
rich_config.rich_config
module.
Configuration using the rich_config
decorator¶
Initializing a new RichHelpConfiguration
object creates a configuration that you can then pass to your CLIs via the rich_config
decorator. For example:
import rich_click as click
@click.command()
@click.rich_config(help_config=click.RichHelpConfiguration(style_option="bold red"))
def cli():
"""Help text here."""
RichHelpConfiguration()
initializes the default configuration, and the user is able to specify any changes to that default configuration that they'd like. Note that RichHelpConfiguration()
is unaware of the global configuration.
You may also specify custom config as a dict:
import rich_click as click
from rich_click import rich_config
@click.command()
@rich_config(help_config={"style_option": "bold red"})
def cli():
"""Help text here."""
There is a subtle difference between using a dict
and using a RichHelpConfiguration
.
Initializing a RichHelpConfiguration
creates a fresh config from the defaults, whereas a dict
merges to either the parent or (if the parent config does not exist) the global config.
In the below example subcommand
's configuration would get "merged" into my_group
's configuration, meaning that subcommand
would inherit the style_option="bold red"
style from my_group
:
import rich_click as click
from rich_click import rich_config
@click.group()
@rich_config(help_config={"style_option": "bold red"})
def my_group():
"""Help text here."""
@my_group.command()
@rich_config(help_config={"style_argument": "bold yellow"})
def subcommand():
"""Help text here."""
Configuration using the global config¶
The other way to configure rich-click is to use the global configuration inside the rich_click.rich_click
module:
import rich_click as click
import rich_click.rich_click as rc
rc.STYLE_OPTION = "bold red"
@click.command()
def my_command():
"""Help text here."""
Compatibility between RichHelpConfiguration
and global config¶
You can load the global config into a RichHelpConfiguration
using the RichHelpConfiguration.load_from_globals()
classmethod:
import rich_click as click
import rich_click.rich_click as rc
rc.STYLE_OPTION = "bold red"
# The help config will have `style_option = "bold red"`.
help_config = click.RichHelpConfiguration.load_from_globals()
@click.command()
@click.rich_config(help_config=help_config)
def my_command():
"""Help text here."""
You can also dump a help config into the global config using RichHelpConfiguration().dump_to_globals()
.
You probably do not need this in most cases; this is mostly for rich-click's internal use.
import rich_click as click
import rich_click.rich_click as rc
help_config = click.RichHelpConfiguration(style_option="bold red")
help_config.dump_to_globals()
# The CLI will have `style_option = "bold red"` since it pulls from the globals.
@click.command()
def my_command():
"""Help text here."""
Configuration options¶
Below is a full list of configuration options from rich_click.py
.
Config
# Default styles
THEME: Optional[Union[str, RichClickTheme]] = None
ENABLE_THEME_ENV_VAR: bool = True
STYLE_OPTION: "StyleType" = FROM_THEME
STYLE_OPTION_NEGATIVE: Optional["StyleType"] = FROM_THEME
STYLE_ARGUMENT: "StyleType" = FROM_THEME
STYLE_COMMAND: "StyleType" = FROM_THEME
STYLE_COMMAND_ALIASES: "StyleType" = FROM_THEME
STYLE_SWITCH: "StyleType" = FROM_THEME
STYLE_SWITCH_NEGATVE: Optional["StyleType"] = FROM_THEME
STYLE_METAVAR: "StyleType" = FROM_THEME
STYLE_METAVAR_APPEND: "StyleType" = FROM_THEME
STYLE_METAVAR_SEPARATOR: "StyleType" = FROM_THEME
STYLE_RANGE_APPEND: "StyleType" = FROM_THEME
STYLE_USAGE: "StyleType" = FROM_THEME
STYLE_USAGE_COMMAND: "StyleType" = FROM_THEME
STYLE_USAGE_SEPARATOR: "StyleType" = FROM_THEME
STYLE_DEPRECATED: "StyleType" = FROM_THEME
STYLE_HELPTEXT_FIRST_LINE: "StyleType" = FROM_THEME
STYLE_HELPTEXT: "StyleType" = FROM_THEME
STYLE_OPTION_HELP: "StyleType" = FROM_THEME
STYLE_COMMAND_HELP: "StyleType" = FROM_THEME
STYLE_OPTION_DEFAULT: "StyleType" = FROM_THEME
STYLE_OPTION_ENVVAR: "StyleType" = FROM_THEME
STYLE_REQUIRED_SHORT: "StyleType" = FROM_THEME
STYLE_REQUIRED_LONG: "StyleType" = FROM_THEME
STYLE_OPTIONS_PANEL_BORDER: "StyleType" = FROM_THEME
STYLE_OPTIONS_PANEL_BOX: Optional[Union[str, "Box"]] = FROM_THEME
STYLE_OPTIONS_PANEL_HELP_STYLE: "StyleType" = FROM_THEME
STYLE_OPTIONS_PANEL_TITLE_STYLE: "StyleType" = FROM_THEME
STYLE_OPTIONS_PANEL_PADDING: "PaddingDimensions" = FROM_THEME
STYLE_OPTIONS_PANEL_STYLE: "StyleType" = FROM_THEME
ALIGN_OPTIONS_PANEL: "AlignMethod" = "left"
STYLE_OPTIONS_TABLE_SHOW_LINES: bool = False
STYLE_OPTIONS_TABLE_LEADING: int = 0
STYLE_OPTIONS_TABLE_PAD_EDGE: bool = False
STYLE_OPTIONS_TABLE_PADDING: "PaddingDimensions" = (0, 1)
STYLE_OPTIONS_TABLE_EXPAND: bool = FROM_THEME
STYLE_OPTIONS_TABLE_BOX: Optional[Union[str, "Box"]] = FROM_THEME
STYLE_OPTIONS_TABLE_ROW_STYLES: Optional[List["StyleType"]] = None
STYLE_OPTIONS_TABLE_BORDER_STYLE: Optional["StyleType"] = FROM_THEME
STYLE_COMMANDS_PANEL_BORDER: "StyleType" = FROM_THEME
PANEL_INLINE_HELP_IN_TITLE: bool = FROM_THEME
PANEL_INLINE_HELP_DELIMITER: str = FROM_THEME
STYLE_COMMANDS_PANEL_BOX: Optional[Union[str, "Box"]] = FROM_THEME
STYLE_COMMANDS_PANEL_HELP_STYLE: "StyleType" = FROM_THEME
STYLE_COMMANDS_PANEL_TITLE_STYLE: "StyleType" = FROM_THEME
STYLE_COMMANDS_PANEL_PADDING: "PaddingDimensions" = FROM_THEME
STYLE_COMMANDS_PANEL_STYLE: "StyleType" = FROM_THEME
ALIGN_COMMANDS_PANEL: "AlignMethod" = "left"
STYLE_COMMANDS_TABLE_SHOW_LINES: bool = False
STYLE_COMMANDS_TABLE_LEADING: int = 0
STYLE_COMMANDS_TABLE_PAD_EDGE: bool = False
STYLE_COMMANDS_TABLE_PADDING: "PaddingDimensions" = (0, 1)
STYLE_COMMANDS_TABLE_EXPAND: bool = FROM_THEME
STYLE_COMMANDS_TABLE_BOX: Optional[Union[str, "Box"]] = FROM_THEME
STYLE_COMMANDS_TABLE_ROW_STYLES: Optional[List["StyleType"]] = None
STYLE_COMMANDS_TABLE_BORDER_STYLE: Optional["StyleType"] = FROM_THEME
STYLE_COMMANDS_TABLE_COLUMN_WIDTH_RATIO: Optional[Union[Tuple[None, None], Tuple[int, int]]] = (None, None)
STYLE_ERRORS_PANEL_BORDER: "StyleType" = FROM_THEME
STYLE_ERRORS_PANEL_BOX: Optional[Union[str, "Box"]] = FROM_THEME
ALIGN_ERRORS_PANEL: "AlignMethod" = "left"
STYLE_ERRORS_SUGGESTION: Optional["StyleType"] = None
STYLE_ERRORS_SUGGESTION_COMMAND: Optional["StyleType"] = None
STYLE_PADDING_ERRORS: "StyleType" = FROM_THEME
STYLE_ABORTED: "StyleType" = "red"
STYLE_PADDING_USAGE: "StyleType" = FROM_THEME
STYLE_PADDING_HELPTEXT: "StyleType" = FROM_THEME
STYLE_PADDING_EPILOG: "StyleType" = FROM_THEME
STYLE_HEADER_TEXT: "StyleType" = FROM_THEME
STYLE_EPILOG_TEXT: "StyleType" = FROM_THEME
STYLE_FOOTER_TEXT: "StyleType" = FROM_THEME
PANEL_TITLE_PADDING: int = FROM_THEME
WIDTH: Optional[int] = terminal_width_default()
MAX_WIDTH: Optional[int] = terminal_width_default()
COLOR_SYSTEM: Optional[Literal["auto", "standard", "256", "truecolor", "windows"]] = (
"auto" # Set to None to disable colors
)
FORCE_TERMINAL: Optional[bool] = force_terminal_default()
OPTIONS_TABLE_COLUMN_TYPES: List[OptionColumnType] = FROM_THEME
COMMANDS_TABLE_COLUMN_TYPES: List[CommandColumnType] = FROM_THEME
OPTIONS_TABLE_HELP_SECTIONS: List[OptionHelpSectionType] = FROM_THEME
COMMANDS_TABLE_HELP_SECTIONS: List[CommandHelpSectionType] = FROM_THEME
# Fixed strings
HEADER_TEXT: Optional[Union[str, "Text"]] = None
FOOTER_TEXT: Optional[Union[str, "Text"]] = None
PANEL_TITLE_STRING: str = FROM_THEME
DEPRECATED_STRING: str = FROM_THEME
DEPRECATED_WITH_REASON_STRING: str = FROM_THEME
DEFAULT_STRING: str = FROM_THEME
ENVVAR_STRING: str = FROM_THEME
REQUIRED_SHORT_STRING: str = FROM_THEME
REQUIRED_LONG_STRING: str = FROM_THEME
RANGE_STRING: str = FROM_THEME
APPEND_METAVARS_HELP_STRING: str = FROM_THEME
APPEND_RANGE_HELP_STRING: str = FROM_THEME
ARGUMENTS_PANEL_TITLE: str = "Arguments"
OPTIONS_PANEL_TITLE: str = "Options"
COMMANDS_PANEL_TITLE: str = "Commands"
ERRORS_PANEL_TITLE: str = "Error"
DELIMITER_COMMA: str = FROM_THEME
DELIMITER_SLASH: str = FROM_THEME
ERRORS_SUGGESTION: Optional[Union[str, "Text"]] = None # Default: Try 'cmd -h' for help. Set to False to disable.
ERRORS_EPILOGUE: Optional[Union[str, "Text"]] = None
ABORTED_TEXT: str = "Aborted."
PADDING_HEADER_TEXT: "PaddingDimensions" = FROM_THEME
PADDING_USAGE: "PaddingDimensions" = FROM_THEME
PADDING_HELPTEXT: "PaddingDimensions" = FROM_THEME
PADDING_HELPTEXT_DEPRECATED: "PaddingDimensions" = 0
PADDING_HELPTEXT_FIRST_LINE: "PaddingDimensions" = 0
PADDING_EPILOG: "PaddingDimensions" = FROM_THEME
PADDING_FOOTER_TEXT: "PaddingDimensions" = FROM_THEME
PADDING_ERRORS_PANEL: "PaddingDimensions" = (0, 0, 1, 0)
PADDING_ERRORS_SUGGESTION: "PaddingDimensions" = (0, 1, 0, 1)
PADDING_ERRORS_EPILOGUE: "PaddingDimensions" = (0, 1, 1, 1)
# Behaviours
SHOW_ARGUMENTS: Optional[bool] = None # Show positional arguments
SHOW_METAVARS_COLUMN: Optional[bool] = None # Show a column with the option metavar (eg. INTEGER)
COMMANDS_BEFORE_OPTIONS: bool = False # If set, the commands panel show above the options panel.
APPEND_METAVARS_HELP: Optional[bool] = None # Append metavar (eg. [TEXT]) after the help text
GROUP_ARGUMENTS_OPTIONS: bool = False # Show arguments with options instead of in own panel
OPTION_ENVVAR_FIRST: Optional[Optional[bool]] = None # Show env vars before option help text instead of avert
TEXT_MARKUP: Literal["ansi", "rich", "markdown", None] = notset
TEXT_KWARGS: Optional[Dict[str, Any]] = None
TEXT_EMOJIS: bool = notset
TEXT_PARAGRAPH_LINEBREAKS: Optional[Literal["\n", "\n\n"]] = None
# If set, parse emoji codes and replace with actual emojis, e.g. :smiley_cat: -> 😺
USE_MARKDOWN: Optional[bool] = None # Parse help strings as markdown
USE_MARKDOWN_EMOJI: Optional[bool] = None # Parse emoji codes in markdown :smile:
USE_RICH_MARKUP: Optional[bool] = None # Parse help strings for rich markup (eg. [red]my text[/])
# Define sorted groups of panels to display subcommands
COMMAND_GROUPS: Dict[str, List[CommandGroupDict]] = {}
# Define sorted groups of panels to display options and arguments
OPTION_GROUPS: Dict[str, List[OptionGroupDict]] = {}
USE_CLICK_SHORT_HELP: bool = False # Use click's default function to truncate help text
All of these are available in the RichHelpConfiguration
object, but as lowercase.
Advanced
The rest of this document contains information that the majority of users will not need.
(Advanced) Config resolution order¶
It probably should not matter for most use cases, but just case it does matter, there is an explicitly defined order of operations for how the configuration gets resolved:
flowchart TD
A["Did you pass in a @rich_config(help_config=...)?"]
A --> |Yes| Ayes
A --> |No| Ano
Ayes["Was it a dict or a RichHelpConfiguration?"]
Ayes --> |dict| AyesBdict
Ayes --> |RichHelpConfiguration| AyesBrhc
AyesBdict["Is there a 'parent' config?"]
AyesBdict --> |Yes| AyesBdictCyes
AyesBdict --> |No| AyesBdictCno
AyesBdictCyes:::StoppingPoint
AyesBdictCyes["Merge into the parent config, and use that"]
AyesBdictCno:::StoppingPoint
AyesBdictCno["Merge into the global config, and use that"]
AyesBrhc:::Wide
AyesBrhc["<font style="font-weight: 600;">Use the RichHelpConfiguration object.</font><br>(Note: RichHelpConfiguration's defaults are independent of the global config.)"]
Ano["Is there a 'parent' config?"]
Ano --> |Yes| AnoByes
Ano --> |No| AnoBno
AnoByes:::StoppingPoint
AnoByes["Use the parent config"]
AnoBno:::StoppingPoint
AnoBno["Use the global config"]
classDef StoppingPoint font-weight: 600;
classDef Wide padding: 8.5em;
(Advanced) Themes¶
Success
This section is specifically concerned with how themes interact with configurations.
More general information about themes is described in the themes docs.
Config options controlled by themes are assigned a sentinel value.
When a RichHelpConfiguration()
object is created, if the theme
is defined, then the theme is applied to any unset config values.
Other config resolution rules still apply.
So for example, the below will not apply the "green2-nu"
theme to the CLI
because of the config resolution rule which states that config = RichHelpConfiguration()
will not pull from globals:
import rich_click as click
import rich_click.rich_click as rc
# The following line will NOT do anything because the RichHelpConfiguration() below
# completely ignores the the global config.
rc.THEME = "green2-nu"
# This will NOT have the green2-nu theme.
help_config = click.RichHelpConfiguration(style_option="magenta")
@click.command()
@click.rich_config(help_config=help_config)
def my_command():
"""Help text here."""
import rich_click as click
@click.command()
@click.rich_config({"theme": "green2-nu", "style_option": "magenta"})
def my_command():
"""Help text here."""
import rich_click as click
@click.command()
@click.rich_config(click.RichHelpConfiguration(theme="green2-nu", style_option="magenta"))
def my_command():
"""Help text here."""
import rich_click as click
import rich_click.rich_click as rc
rc.THEME = "green2-nu"
rc.STYLE_OPTION = "magenta"
@click.command()
def my_command():
"""Help text here."""
import rich_click as click
import rich_click.rich_click as rc
# This works because of the config rule that dicts get merged
# into the global config
rc.THEME = "green2-nu"
@click.command()
@click.rich_config({"style_option": "magenta"})
def my_command():
"""Help text here."""
When we go to render help text, if there is still no theme, then the default theme (default-box
) is applied.
In the event that there are multiple themes being assigned from different sources, one theme must be selected. The priority order of which theme gets selected is defined below (highest priority is #1):
- The theme defined in the
rich-click
CLI:rich-click --theme [theme]
- Environment variable:
RICH_CLICK_THEME=[theme]
- The
theme
of the command's config
Handling overrides and custom themes¶
The user can override the theme that a developer sets because all end-user settings (CLI and env var) are prioritized above things set by the developer (command config).
Note that themes never override existing config options, so explicitly set options always take precedence over a theme. This can cause potentially unintended side effects where your style settings clash with the user's theme. There are three ways around this.
The first is to do nothing. For many config options, like commands_before_options
or options_panel_title
, the theme should not make any real difference, or the config option may not even be stylistic in nature. Theme overrides only become a real issue when a user's RICH_CLICK_THEME
clashes stylistically with your custom settings.
The second way is to explicitly prevent theme overrides by setting the config option enable_theme_env_var = False
. This option prevents all overrides when enabled.
import rich_click as click
@click.group("cli")
@click.rich_config({"theme": "nord-slim", "enable_theme_env_var": False})
def cli():
"""My CLI help text"""
import rich_click as click
@click.group("cli")
@click.rich_config(click.RichHelpConfiguration(theme="nord-slim", enable_theme_env_var=False))
def cli():
"""My CLI help text"""
import rich_click as click
click.rich_click.THEME = "nord-slim"
click.rich_click.ENABLE_THEME_ENV_VAR = False
@click.group("cli")
def cli():
"""My CLI help text"""
The final way is to apply your config as a theme. Basically, since themes are applied last and can be overridden, then if you have your config applied as a theme, then it can be overridden. RichHelpConfigurations have a method called to_theme which generates a theme from your config:
import rich_click as click
config = click.RichHelpConfiguration()
theme = config.to_theme()
@click.group("cli")
# This can be overridden.
@click.rich_config({"theme": theme})
def cli():
"""My CLI help text"""
A more advanced pattern, which lets you make some options overridable by a theme, while keeping others immutable:
import rich_click as click
# All of these config options can be overridden
theme = click.RichHelpConfiguration(
style_option="bold red",
style_command="bold green"
).to_theme()
# Here, `style_metavar` will not be overridden by the RICH_CLICK_THEME env var.
config = click.RichHelpConfiguration(
theme=theme,
style_metavar="magenta",
)
@click.group("cli")
@click.rich_config(config)
def cli():
"""My CLI help text"""