rich-click 1.9.0.dev2__tar.gz → 1.9.0.dev3__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {rich_click-1.9.0.dev2/src/rich_click.egg-info → rich_click-1.9.0.dev3}/PKG-INFO +5 -3
- {rich_click-1.9.0.dev2 → rich_click-1.9.0.dev3}/README.md +2 -2
- {rich_click-1.9.0.dev2 → rich_click-1.9.0.dev3}/pyproject.toml +2 -0
- {rich_click-1.9.0.dev2 → rich_click-1.9.0.dev3}/src/rich_click/__init__.py +1 -1
- rich_click-1.9.0.dev3/src/rich_click/_internal_types.py +250 -0
- {rich_click-1.9.0.dev2 → rich_click-1.9.0.dev3}/src/rich_click/cli.py +87 -132
- {rich_click-1.9.0.dev2 → rich_click-1.9.0.dev3}/src/rich_click/decorators.py +17 -1
- {rich_click-1.9.0.dev2 → rich_click-1.9.0.dev3}/src/rich_click/decorators.pyi +23 -221
- rich_click-1.9.0.dev3/src/rich_click/patch.py +270 -0
- {rich_click-1.9.0.dev2 → rich_click-1.9.0.dev3}/src/rich_click/rich_click.py +13 -4
- rich_click-1.9.0.dev3/src/rich_click/rich_click_theme.py +1098 -0
- {rich_click-1.9.0.dev2 → rich_click-1.9.0.dev3}/src/rich_click/rich_command.py +64 -13
- rich_click-1.9.0.dev3/src/rich_click/rich_command.pyi +428 -0
- {rich_click-1.9.0.dev2 → rich_click-1.9.0.dev3}/src/rich_click/rich_help_configuration.py +110 -35
- {rich_click-1.9.0.dev2 → rich_click-1.9.0.dev3}/src/rich_click/rich_help_rendering.py +144 -47
- {rich_click-1.9.0.dev2 → rich_click-1.9.0.dev3}/src/rich_click/rich_panel.py +21 -33
- {rich_click-1.9.0.dev2 → rich_click-1.9.0.dev3}/src/rich_click/utils.py +1 -1
- {rich_click-1.9.0.dev2 → rich_click-1.9.0.dev3/src/rich_click.egg-info}/PKG-INFO +5 -3
- {rich_click-1.9.0.dev2 → rich_click-1.9.0.dev3}/src/rich_click.egg-info/SOURCES.txt +5 -2
- {rich_click-1.9.0.dev2 → rich_click-1.9.0.dev3}/src/rich_click.egg-info/requires.txt +2 -0
- {rich_click-1.9.0.dev2 → rich_click-1.9.0.dev3}/tests/test_config.py +3 -59
- {rich_click-1.9.0.dev2 → rich_click-1.9.0.dev3}/tests/test_rich_click_cli.py +28 -27
- rich_click-1.9.0.dev3/tests/test_types.py +101 -0
- rich_click-1.9.0.dev2/src/rich_click/patch.py +0 -72
- rich_click-1.9.0.dev2/src/rich_click/rich_theme.py +0 -817
- {rich_click-1.9.0.dev2 → rich_click-1.9.0.dev3}/LICENSE +0 -0
- {rich_click-1.9.0.dev2 → rich_click-1.9.0.dev3}/setup.cfg +0 -0
- {rich_click-1.9.0.dev2 → rich_click-1.9.0.dev3}/src/rich_click/__main__.py +0 -0
- {rich_click-1.9.0.dev2 → rich_click-1.9.0.dev3}/src/rich_click/_compat_click.py +0 -0
- {rich_click-1.9.0.dev2 → rich_click-1.9.0.dev3}/src/rich_click/py.typed +0 -0
- {rich_click-1.9.0.dev2 → rich_click-1.9.0.dev3}/src/rich_click/rich_box.py +0 -0
- {rich_click-1.9.0.dev2 → rich_click-1.9.0.dev3}/src/rich_click/rich_context.py +0 -0
- {rich_click-1.9.0.dev2 → rich_click-1.9.0.dev3}/src/rich_click/rich_group.py +0 -0
- {rich_click-1.9.0.dev2 → rich_click-1.9.0.dev3}/src/rich_click/rich_help_formatter.py +0 -0
- {rich_click-1.9.0.dev2 → rich_click-1.9.0.dev3}/src/rich_click/rich_parameter.py +0 -0
- {rich_click-1.9.0.dev2 → rich_click-1.9.0.dev3}/src/rich_click.egg-info/dependency_links.txt +0 -0
- {rich_click-1.9.0.dev2 → rich_click-1.9.0.dev3}/src/rich_click.egg-info/entry_points.txt +0 -0
- {rich_click-1.9.0.dev2 → rich_click-1.9.0.dev3}/src/rich_click.egg-info/top_level.txt +0 -0
- {rich_click-1.9.0.dev2 → rich_click-1.9.0.dev3}/tests/test_deprecations.py +0 -0
- {rich_click-1.9.0.dev2 → rich_click-1.9.0.dev3}/tests/test_exit_code.py +0 -0
- {rich_click-1.9.0.dev2 → rich_click-1.9.0.dev3}/tests/test_misc.py +0 -0
- {rich_click-1.9.0.dev2 → rich_click-1.9.0.dev3}/tests/test_no_rich_imports.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: rich-click
|
|
3
|
-
Version: 1.9.0.
|
|
3
|
+
Version: 1.9.0.dev3
|
|
4
4
|
Summary: Format click help output nicely with rich
|
|
5
5
|
Author-email: Phil Ewels <phil@ewels.co.uk>
|
|
6
6
|
Maintainer-email: Phil Ewels <phil@ewels.co.uk>, Daniel Reeves <xdanielreeves@gmail.com>
|
|
@@ -57,6 +57,7 @@ Requires-Dist: pytest>=8.3.5; extra == "dev"
|
|
|
57
57
|
Requires-Dist: pytest-cov>=5; extra == "dev"
|
|
58
58
|
Requires-Dist: rich-codex>=1.2.11; extra == "dev"
|
|
59
59
|
Requires-Dist: ruff>=0.12.4; extra == "dev"
|
|
60
|
+
Requires-Dist: typer>=0.15; extra == "dev"
|
|
60
61
|
Requires-Dist: types-setuptools>=75.8.0.20250110; extra == "dev"
|
|
61
62
|
Provides-Extra: docs
|
|
62
63
|
Requires-Dist: markdown-include>=0.8.1; extra == "docs"
|
|
@@ -70,6 +71,7 @@ Requires-Dist: mkdocs-material-extensions>=1.3.1; extra == "docs"
|
|
|
70
71
|
Requires-Dist: mkdocs-rss-plugin>=1.15; extra == "docs"
|
|
71
72
|
Requires-Dist: mkdocstrings[python]>=0.26.1; extra == "docs"
|
|
72
73
|
Requires-Dist: rich-codex>=1.2.11; extra == "docs"
|
|
74
|
+
Requires-Dist: typer>=0.15; extra == "docs"
|
|
73
75
|
Dynamic: license-file
|
|
74
76
|
|
|
75
77
|
<p align="center">
|
|
@@ -109,12 +111,12 @@ Click, formatted with Rich, with minimal customization required.
|
|
|
109
111
|
- 🌈 Rich command-line formatting of click help and error messages
|
|
110
112
|
- 😌 Same API as Click: usage is simply `import rich_click as click`
|
|
111
113
|
- 🎨 Over 100 themes that can be set by developers and end-users (`export RICH_CLICK_THEME=...`)
|
|
112
|
-
- 💻 CLI tool to run on _other people's_
|
|
114
|
+
- 💻 CLI tool to run on _other people's_ Click and Typer CLIs (prefix the command with `rich-click`)
|
|
113
115
|
- 📦 Export help text as HTML or SVG
|
|
114
116
|
- 🎁 Group commands and options into named panels
|
|
115
117
|
- ❌ Well formatted error messages
|
|
116
118
|
- 💫 Extensive customization
|
|
117
|
-
- 🤖 IDE autocomplete of Click decorators for smooth developer experience
|
|
119
|
+
- 🤖 IDE autocomplete of Click decorators for smooth developer experience
|
|
118
120
|
|
|
119
121
|
## Installation
|
|
120
122
|
|
|
@@ -35,12 +35,12 @@ Click, formatted with Rich, with minimal customization required.
|
|
|
35
35
|
- 🌈 Rich command-line formatting of click help and error messages
|
|
36
36
|
- 😌 Same API as Click: usage is simply `import rich_click as click`
|
|
37
37
|
- 🎨 Over 100 themes that can be set by developers and end-users (`export RICH_CLICK_THEME=...`)
|
|
38
|
-
- 💻 CLI tool to run on _other people's_
|
|
38
|
+
- 💻 CLI tool to run on _other people's_ Click and Typer CLIs (prefix the command with `rich-click`)
|
|
39
39
|
- 📦 Export help text as HTML or SVG
|
|
40
40
|
- 🎁 Group commands and options into named panels
|
|
41
41
|
- ❌ Well formatted error messages
|
|
42
42
|
- 💫 Extensive customization
|
|
43
|
-
- 🤖 IDE autocomplete of Click decorators for smooth developer experience
|
|
43
|
+
- 🤖 IDE autocomplete of Click decorators for smooth developer experience
|
|
44
44
|
|
|
45
45
|
## Installation
|
|
46
46
|
|
|
@@ -46,6 +46,7 @@ optional-dependencies.dev = [
|
|
|
46
46
|
"pytest-cov>=5",
|
|
47
47
|
"rich-codex>=1.2.11",
|
|
48
48
|
"ruff>=0.12.4",
|
|
49
|
+
"typer>=0.15",
|
|
49
50
|
"types-setuptools>=75.8.0.20250110",
|
|
50
51
|
]
|
|
51
52
|
optional-dependencies.docs = [
|
|
@@ -60,6 +61,7 @@ optional-dependencies.docs = [
|
|
|
60
61
|
"mkdocs-rss-plugin>=1.15",
|
|
61
62
|
"mkdocstrings[python]>=0.26.1",
|
|
62
63
|
"rich-codex>=1.2.11",
|
|
64
|
+
"typer>=0.15",
|
|
63
65
|
]
|
|
64
66
|
urls.Documentation = "https://github.com/ewels/rich-click"
|
|
65
67
|
urls.Homepage = "https://github.com/ewels/rich-click"
|
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Contains types for .pyi files.
|
|
3
|
+
Import from this at your own risk.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from __future__ import annotations
|
|
7
|
+
|
|
8
|
+
from typing import (
|
|
9
|
+
TYPE_CHECKING,
|
|
10
|
+
Any,
|
|
11
|
+
Callable,
|
|
12
|
+
Dict,
|
|
13
|
+
Iterable,
|
|
14
|
+
List,
|
|
15
|
+
Literal,
|
|
16
|
+
Mapping,
|
|
17
|
+
MutableMapping,
|
|
18
|
+
Optional,
|
|
19
|
+
Tuple,
|
|
20
|
+
TypedDict,
|
|
21
|
+
Union,
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
from rich_click.utils import CommandGroupDict, OptionGroupDict
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
if TYPE_CHECKING:
|
|
28
|
+
import sys
|
|
29
|
+
|
|
30
|
+
from rich.align import AlignMethod
|
|
31
|
+
from rich.box import Box
|
|
32
|
+
from rich.console import Console, JustifyMethod
|
|
33
|
+
from rich.padding import PaddingDimensions
|
|
34
|
+
from rich.style import StyleType
|
|
35
|
+
from rich.text import Text, TextType
|
|
36
|
+
|
|
37
|
+
from rich_click.rich_help_configuration import (
|
|
38
|
+
CommandColumnType,
|
|
39
|
+
CommandHelpSectionType,
|
|
40
|
+
OptionColumnType,
|
|
41
|
+
OptionHelpSectionType,
|
|
42
|
+
RichHelpConfiguration,
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
if sys.version_info < (3, 11):
|
|
46
|
+
from typing_extensions import NotRequired
|
|
47
|
+
else:
|
|
48
|
+
from typing import NotRequired
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
class RichContextSettingsDict(TypedDict):
|
|
52
|
+
obj: NotRequired["Any | None"]
|
|
53
|
+
auto_envvar_prefix: NotRequired[Optional[str]]
|
|
54
|
+
default_map: NotRequired[MutableMapping[str, Any] | None]
|
|
55
|
+
terminal_width: NotRequired[Optional[int]]
|
|
56
|
+
max_content_width: NotRequired[Optional[int]]
|
|
57
|
+
resilient_parsing: NotRequired[bool]
|
|
58
|
+
allow_extra_args: NotRequired[Optional[bool]]
|
|
59
|
+
allow_interspersed_args: NotRequired[Optional[bool]]
|
|
60
|
+
ignore_unknown_options: NotRequired[Optional[bool]]
|
|
61
|
+
help_option_names: NotRequired[Optional[List[str]]]
|
|
62
|
+
token_normalize_func: NotRequired[Callable[[str], str] | None]
|
|
63
|
+
color: NotRequired[Optional[bool]]
|
|
64
|
+
show_default: NotRequired[Optional[bool]]
|
|
65
|
+
rich_console: NotRequired[Optional["Console"]]
|
|
66
|
+
rich_help_config: NotRequired[Optional[Union[Mapping[str, Any], RichHelpConfiguration]]]
|
|
67
|
+
export_console_as: NotRequired[Optional[Literal["html", "svg", "text"]]]
|
|
68
|
+
errors_in_output_format: NotRequired[Optional[bool]]
|
|
69
|
+
help_to_stderr: NotRequired[Optional[bool]]
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
class TableKwargs(TypedDict):
|
|
73
|
+
title: NotRequired[Optional["TextType"]]
|
|
74
|
+
caption: NotRequired[Optional["TextType"]]
|
|
75
|
+
width: NotRequired[Optional[int]]
|
|
76
|
+
min_width: NotRequired[Optional[int]]
|
|
77
|
+
box: NotRequired[Optional[Union[str, "Box"]]]
|
|
78
|
+
safe_box: NotRequired[Optional[bool]]
|
|
79
|
+
padding: NotRequired["PaddingDimensions"]
|
|
80
|
+
collapse_padding: NotRequired[bool]
|
|
81
|
+
pad_edge: NotRequired[bool]
|
|
82
|
+
expand: NotRequired[bool]
|
|
83
|
+
show_header: NotRequired[bool]
|
|
84
|
+
show_footer: NotRequired[bool]
|
|
85
|
+
show_edge: NotRequired[bool]
|
|
86
|
+
show_lines: NotRequired[bool]
|
|
87
|
+
leading: NotRequired[int]
|
|
88
|
+
style: NotRequired["StyleType"]
|
|
89
|
+
row_styles: NotRequired[Optional[Iterable["StyleType"]]]
|
|
90
|
+
header_style: NotRequired[Optional["StyleType"]]
|
|
91
|
+
footer_style: NotRequired[Optional["StyleType"]]
|
|
92
|
+
border_style: NotRequired[Optional["StyleType"]]
|
|
93
|
+
title_style: NotRequired[Optional["StyleType"]]
|
|
94
|
+
caption_style: NotRequired[Optional["StyleType"]]
|
|
95
|
+
title_justify: NotRequired["JustifyMethod"]
|
|
96
|
+
caption_justify: NotRequired["JustifyMethod"]
|
|
97
|
+
highlight: NotRequired[bool]
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
class PanelKwargs(TypedDict):
|
|
101
|
+
box: NotRequired[Union[str, "Box"]]
|
|
102
|
+
title: NotRequired[Optional["TextType"]]
|
|
103
|
+
title_align: NotRequired["AlignMethod"]
|
|
104
|
+
subtitle: NotRequired[Optional["TextType"]]
|
|
105
|
+
subtitle_align: NotRequired["AlignMethod"]
|
|
106
|
+
safe_box: NotRequired[Optional[bool]]
|
|
107
|
+
expand: NotRequired[bool]
|
|
108
|
+
style: NotRequired["StyleType"]
|
|
109
|
+
border_style: NotRequired["StyleType"]
|
|
110
|
+
width: NotRequired[Optional[int]]
|
|
111
|
+
height: NotRequired[Optional[int]]
|
|
112
|
+
padding: NotRequired["PaddingDimensions"]
|
|
113
|
+
highlight: NotRequired[bool]
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
class RichHelpConfigurationDict(TypedDict):
|
|
117
|
+
"""Typed dict for rich_config() kwargs."""
|
|
118
|
+
|
|
119
|
+
theme: NotRequired[Optional[str]]
|
|
120
|
+
enable_theme_env_var: NotRequired[bool]
|
|
121
|
+
style_option: NotRequired["StyleType"]
|
|
122
|
+
style_option_negative: NotRequired[Optional["StyleType"]]
|
|
123
|
+
style_argument: NotRequired["StyleType"]
|
|
124
|
+
style_command: NotRequired["StyleType"]
|
|
125
|
+
style_command_aliases: NotRequired["StyleType"]
|
|
126
|
+
style_switch: NotRequired["StyleType"]
|
|
127
|
+
style_switch_negative: NotRequired[Optional["StyleType"]]
|
|
128
|
+
style_metavar: NotRequired["StyleType"]
|
|
129
|
+
style_metavar_append: NotRequired["StyleType"]
|
|
130
|
+
style_metavar_separator: NotRequired["StyleType"]
|
|
131
|
+
style_range_append: NotRequired["StyleType"]
|
|
132
|
+
style_header_text: NotRequired["StyleType"]
|
|
133
|
+
style_epilog_text: NotRequired["StyleType"]
|
|
134
|
+
style_footer_text: NotRequired["StyleType"]
|
|
135
|
+
style_usage: NotRequired["StyleType"]
|
|
136
|
+
style_usage_command: NotRequired["StyleType"]
|
|
137
|
+
style_usage_separator: NotRequired["StyleType"]
|
|
138
|
+
style_deprecated: NotRequired["StyleType"]
|
|
139
|
+
style_helptext_first_line: NotRequired["StyleType"]
|
|
140
|
+
style_helptext: NotRequired["StyleType"]
|
|
141
|
+
style_option_help: NotRequired["StyleType"]
|
|
142
|
+
style_command_help: NotRequired["StyleType"]
|
|
143
|
+
style_option_default: NotRequired["StyleType"]
|
|
144
|
+
style_option_envvar: NotRequired["StyleType"]
|
|
145
|
+
style_required_short: NotRequired["StyleType"]
|
|
146
|
+
style_required_long: NotRequired["StyleType"]
|
|
147
|
+
style_options_panel_border: NotRequired["StyleType"]
|
|
148
|
+
style_options_panel_box: NotRequired[Optional[Union[str, "Box"]]]
|
|
149
|
+
style_options_panel_help_style: NotRequired["StyleType"]
|
|
150
|
+
style_options_panel_title_style: NotRequired["StyleType"]
|
|
151
|
+
style_options_panel_padding: NotRequired["PaddingDimensions"]
|
|
152
|
+
style_options_panel_style: NotRequired["StyleType"]
|
|
153
|
+
align_options_panel: NotRequired["AlignMethod"]
|
|
154
|
+
style_options_table_show_lines: NotRequired[bool]
|
|
155
|
+
style_options_table_leading: NotRequired[int]
|
|
156
|
+
style_options_table_pad_edge: NotRequired[bool]
|
|
157
|
+
style_options_table_padding: NotRequired["PaddingDimensions"]
|
|
158
|
+
style_options_table_expand: NotRequired[bool]
|
|
159
|
+
style_options_table_box: NotRequired[Optional[Union[str, "Box"]]]
|
|
160
|
+
style_options_table_row_styles: NotRequired[Optional[List["StyleType"]]]
|
|
161
|
+
style_options_table_border_style: NotRequired[Optional["StyleType"]]
|
|
162
|
+
style_commands_panel_border: NotRequired["StyleType"]
|
|
163
|
+
panel_inline_help_in_title: NotRequired[bool]
|
|
164
|
+
panel_inline_help_delimiter: NotRequired[str]
|
|
165
|
+
style_commands_panel_box: NotRequired[Optional[Union[str, "Box"]]]
|
|
166
|
+
style_commands_panel_help_style: NotRequired["StyleType"]
|
|
167
|
+
style_commands_panel_title_style: NotRequired["StyleType"]
|
|
168
|
+
style_commands_panel_padding: NotRequired["PaddingDimensions"]
|
|
169
|
+
style_commands_panel_style: NotRequired["StyleType"]
|
|
170
|
+
align_commands_panel: NotRequired[AlignMethod]
|
|
171
|
+
style_commands_table_show_lines: NotRequired[bool]
|
|
172
|
+
style_commands_table_leading: NotRequired[int]
|
|
173
|
+
style_commands_table_pad_edge: NotRequired[bool]
|
|
174
|
+
style_commands_table_padding: NotRequired["PaddingDimensions"]
|
|
175
|
+
style_commands_table_expand: NotRequired[bool]
|
|
176
|
+
style_commands_table_box: NotRequired[Optional[Union[str, "Box"]]]
|
|
177
|
+
style_commands_table_row_styles: NotRequired[Optional[List["StyleType"]]]
|
|
178
|
+
style_commands_table_border_style: NotRequired[Optional["StyleType"]]
|
|
179
|
+
style_commands_table_column_width_ratio: NotRequired[Optional[Union[Tuple[None, None], Tuple[int, int]]]]
|
|
180
|
+
style_errors_panel_border: NotRequired["StyleType"]
|
|
181
|
+
style_errors_panel_box: NotRequired[Optional[Union[str, "Box"]]]
|
|
182
|
+
align_errors_panel: NotRequired[AlignMethod]
|
|
183
|
+
style_errors_suggestion: NotRequired["StyleType"]
|
|
184
|
+
style_errors_suggestion_command: NotRequired["StyleType"]
|
|
185
|
+
style_aborted: NotRequired["StyleType"]
|
|
186
|
+
style_padding_usage: NotRequired["StyleType"]
|
|
187
|
+
style_padding_helptext: NotRequired["StyleType"]
|
|
188
|
+
style_padding_epilog: NotRequired["StyleType"]
|
|
189
|
+
|
|
190
|
+
panel_title_padding: NotRequired[int]
|
|
191
|
+
width: NotRequired[Optional[int]]
|
|
192
|
+
max_width: NotRequired[Optional[int]]
|
|
193
|
+
color_system: NotRequired[Optional[Literal["auto", "standard", "256", "truecolor", "windows"]]]
|
|
194
|
+
force_terminal: NotRequired[Optional[bool]]
|
|
195
|
+
options_table_column_types: NotRequired[List["OptionColumnType"]]
|
|
196
|
+
commands_table_column_types: NotRequired[List["CommandColumnType"]]
|
|
197
|
+
options_table_help_sections: NotRequired[List["OptionHelpSectionType"]]
|
|
198
|
+
commands_table_help_sections: NotRequired[List["CommandHelpSectionType"]]
|
|
199
|
+
|
|
200
|
+
header_text: NotRequired[Optional[Union[str, "Text"]]]
|
|
201
|
+
footer_text: NotRequired[Optional[Union[str, "Text"]]]
|
|
202
|
+
panel_title_string: NotRequired[str]
|
|
203
|
+
deprecated_string: NotRequired[str]
|
|
204
|
+
deprecated_with_reason_string: NotRequired[str]
|
|
205
|
+
default_string: NotRequired[str]
|
|
206
|
+
envvar_string: NotRequired[str]
|
|
207
|
+
required_short_string: NotRequired[str]
|
|
208
|
+
required_long_string: NotRequired[str]
|
|
209
|
+
range_string: NotRequired[str]
|
|
210
|
+
append_metavars_help_string: NotRequired[str]
|
|
211
|
+
append_range_help_string: NotRequired[str]
|
|
212
|
+
arguments_panel_title: NotRequired[str]
|
|
213
|
+
options_panel_title: NotRequired[str]
|
|
214
|
+
commands_panel_title: NotRequired[str]
|
|
215
|
+
errors_panel_title: NotRequired[str]
|
|
216
|
+
delimiter_comma: NotRequired[str]
|
|
217
|
+
delimiter_slash: NotRequired[str]
|
|
218
|
+
errors_suggestion: NotRequired[Optional[Union[str, Text]]]
|
|
219
|
+
errors_epilogue: NotRequired[Optional[Union[str, Text]]]
|
|
220
|
+
aborted_text: NotRequired[str]
|
|
221
|
+
padding_header_text: NotRequired["PaddingDimensions"]
|
|
222
|
+
padding_helptext: NotRequired["PaddingDimensions"]
|
|
223
|
+
padding_helptext_deprecated: NotRequired["PaddingDimensions"]
|
|
224
|
+
padding_helptext_first_line: NotRequired["PaddingDimensions"]
|
|
225
|
+
padding_usage: NotRequired["PaddingDimensions"]
|
|
226
|
+
padding_epilog: NotRequired["PaddingDimensions"]
|
|
227
|
+
padding_footer_text: NotRequired["PaddingDimensions"]
|
|
228
|
+
padding_errors_panel: NotRequired["PaddingDimensions"]
|
|
229
|
+
padding_errors_suggestion: NotRequired["PaddingDimensions"]
|
|
230
|
+
padding_errors_epilogue: NotRequired["PaddingDimensions"]
|
|
231
|
+
|
|
232
|
+
# Behaviours
|
|
233
|
+
show_arguments: NotRequired[Optional[bool]]
|
|
234
|
+
show_metavars_column: NotRequired[Optional[bool]]
|
|
235
|
+
commands_before_options: NotRequired[bool]
|
|
236
|
+
append_metavars_help: NotRequired[Optional[bool]]
|
|
237
|
+
group_arguments_options: NotRequired[bool]
|
|
238
|
+
option_envvar_first: NotRequired[Optional[bool]]
|
|
239
|
+
text_markup: NotRequired[Literal["ansi", "rich", "markdown", None]]
|
|
240
|
+
text_kwargs: NotRequired[Optional[Dict[str, Any]]]
|
|
241
|
+
text_emojis: NotRequired[bool]
|
|
242
|
+
text_paragraph_linebreaks: NotRequired[Optional[Literal["\n", "\n\n"]]]
|
|
243
|
+
use_markdown: NotRequired[Optional[bool]]
|
|
244
|
+
use_markdown_emoji: NotRequired[Optional[bool]]
|
|
245
|
+
use_rich_markup: NotRequired[Optional[bool]]
|
|
246
|
+
command_groups: NotRequired[Dict[str, List[CommandGroupDict]]]
|
|
247
|
+
option_groups: NotRequired[Dict[str, List[OptionGroupDict]]]
|
|
248
|
+
use_click_short_help: NotRequired[bool]
|
|
249
|
+
highlighter_patterns: NotRequired[List[str]]
|
|
250
|
+
legacy_windows: NotRequired[Optional[bool]]
|
|
@@ -4,15 +4,18 @@ from __future__ import annotations
|
|
|
4
4
|
|
|
5
5
|
import os
|
|
6
6
|
import sys
|
|
7
|
+
import warnings
|
|
8
|
+
from contextlib import contextmanager
|
|
7
9
|
from functools import wraps
|
|
8
10
|
from gettext import gettext
|
|
9
11
|
from importlib import (
|
|
10
12
|
import_module,
|
|
11
13
|
metadata, # type: ignore[import,unused-ignore]
|
|
12
14
|
)
|
|
13
|
-
from typing import Any, Dict, List, Literal, Optional, Tuple
|
|
15
|
+
from typing import Any, Dict, Generator, List, Literal, Optional, Tuple
|
|
14
16
|
|
|
15
17
|
import click
|
|
18
|
+
from click.core import ParameterSource
|
|
16
19
|
|
|
17
20
|
from rich_click.decorators import argument as _rich_argument
|
|
18
21
|
from rich_click.decorators import command as _rich_command
|
|
@@ -20,10 +23,18 @@ from rich_click.decorators import option as _rich_option
|
|
|
20
23
|
from rich_click.decorators import option_panel, pass_context
|
|
21
24
|
from rich_click.decorators import version_option as _rich_version_option
|
|
22
25
|
from rich_click.patch import patch as _patch
|
|
26
|
+
from rich_click.rich_click_theme import COLORS, FORMATS, RichClickThemeNotFound, get_theme
|
|
23
27
|
from rich_click.rich_context import RichContext
|
|
24
28
|
from rich_click.rich_help_configuration import RichHelpConfiguration
|
|
25
29
|
|
|
26
30
|
|
|
31
|
+
DISABLE_WARNINGS_NOTE = (
|
|
32
|
+
"[red]You can pass [b]--suppress-warnings[/b] to the rich-click CLI"
|
|
33
|
+
" or set the [b]RICH_CLICK_CLI_SUPPRESS_WARNINGS[/b] environment variable"
|
|
34
|
+
" to disable this message.[/red]"
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
|
|
27
38
|
def entry_points(*, group: str) -> "metadata.EntryPoints": # type: ignore[name-defined]
|
|
28
39
|
"""entry_points function that is compatible with Python 3.7+."""
|
|
29
40
|
if sys.version_info >= (3, 10):
|
|
@@ -118,10 +129,9 @@ def _get_module_path_and_function_name(script: str, suppress_warnings: bool) ->
|
|
|
118
129
|
" and you have set a custom PYTHONPATH."
|
|
119
130
|
f"\n\nThe selected script is '{module_path}:{function_name}', which is being executed now."
|
|
120
131
|
"\n\nIt is safer and recommended that you specify the MODULE:CLICK_COMMAND"
|
|
121
|
-
f" ('{module_path}:{function_name}') instead of the script ('{script}'), like this:"
|
|
132
|
+
f" ('{module_path}:{function_name}') instead of the script ('{script}'), like this:[/]"
|
|
122
133
|
f"\n\n>>> {' '.join(_args)}"
|
|
123
|
-
"\n\
|
|
124
|
-
" which will disable this message.[/]",
|
|
134
|
+
f"\n\n{DISABLE_WARNINGS_NOTE}",
|
|
125
135
|
)
|
|
126
136
|
|
|
127
137
|
if ":" in script and not module_path:
|
|
@@ -145,8 +155,6 @@ def list_themes(ctx: RichContext, param: click.Parameter, value: bool) -> None:
|
|
|
145
155
|
from rich.table import Table
|
|
146
156
|
from rich.text import Text
|
|
147
157
|
|
|
148
|
-
from rich_click.rich_theme import THEMES
|
|
149
|
-
|
|
150
158
|
formatter = ctx.make_formatter()
|
|
151
159
|
|
|
152
160
|
console = Console(
|
|
@@ -171,21 +179,21 @@ def list_themes(ctx: RichContext, param: click.Parameter, value: bool) -> None:
|
|
|
171
179
|
_theme = None
|
|
172
180
|
else:
|
|
173
181
|
_theme = selected
|
|
174
|
-
if
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
elif _theme is not None:
|
|
181
|
-
from rich_click.rich_theme import COLORS, FORMATS
|
|
182
|
-
|
|
183
|
-
if _theme in FORMATS:
|
|
184
|
-
f = _theme
|
|
185
|
-
found = True
|
|
186
|
-
elif _theme in COLORS:
|
|
187
|
-
c = _theme
|
|
182
|
+
if _theme:
|
|
183
|
+
try:
|
|
184
|
+
get_theme(_theme)
|
|
185
|
+
except RichClickThemeNotFound:
|
|
186
|
+
found = False
|
|
187
|
+
else:
|
|
188
188
|
found = True
|
|
189
|
+
if "-" in _theme:
|
|
190
|
+
c, f, *_ = _theme.split("-")
|
|
191
|
+
elif _theme in FORMATS:
|
|
192
|
+
f = _theme
|
|
193
|
+
found = True
|
|
194
|
+
elif _theme in COLORS:
|
|
195
|
+
c = _theme
|
|
196
|
+
found = True
|
|
189
197
|
|
|
190
198
|
if selected is None:
|
|
191
199
|
selected_text = "[red bold]RICH_CLICK_THEME[/] is not set"
|
|
@@ -194,8 +202,8 @@ def list_themes(ctx: RichContext, param: click.Parameter, value: bool) -> None:
|
|
|
194
202
|
else:
|
|
195
203
|
selected_text = (
|
|
196
204
|
f"[blue bold]RICH_CLICK_THEME[/blue bold]=[blue]{selected!r}[/blue]"
|
|
197
|
-
f"\n\n[b]Colors:[/b] {c}"
|
|
198
|
-
f"\n[b]Format:[/b] {f}"
|
|
205
|
+
f"\n\n[b]Colors:[/b] {c or '[dim](null)[/]'}"
|
|
206
|
+
f"\n[b]Format:[/b] {f or '[dim](null)[/]'}"
|
|
199
207
|
)
|
|
200
208
|
|
|
201
209
|
colors = Table(
|
|
@@ -211,83 +219,16 @@ def list_themes(ctx: RichContext, param: click.Parameter, value: bool) -> None:
|
|
|
211
219
|
)
|
|
212
220
|
colors.columns[0].max_width = 1
|
|
213
221
|
colors.columns[1].style = "bold"
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
"[b](Default)[/b] Original rich-click colors",
|
|
219
|
-
)
|
|
220
|
-
colors.add_row(
|
|
221
|
-
"✓" if c == "solarized" else "",
|
|
222
|
-
"solarized",
|
|
223
|
-
"[bright_green]▓▓[/] [bright_red]▓▓[/] [bright_cyan]▓▓[/]",
|
|
224
|
-
"Bright, colorful, vibrant accents",
|
|
225
|
-
)
|
|
226
|
-
colors.add_row(
|
|
227
|
-
"✓" if c == "nord" else "",
|
|
228
|
-
"nord",
|
|
229
|
-
"[blue]▓▓[/] [bright_blue]▓▓[/] [cyan]▓▓[/]",
|
|
230
|
-
"Many shades of cool colors",
|
|
231
|
-
)
|
|
232
|
-
colors.add_row(
|
|
233
|
-
"✓" if c == "star" else "",
|
|
234
|
-
"star",
|
|
235
|
-
"[yellow]▓▓[/] [blue]▓▓[/] [default]▓▓[/]",
|
|
236
|
-
"Litestar theme; royal feel",
|
|
237
|
-
)
|
|
238
|
-
colors.add_row(
|
|
239
|
-
"✓" if c == "quartz" else "",
|
|
240
|
-
"quartz",
|
|
241
|
-
"[magenta]▓▓[/] [dim magenta]▓▓[/] [blue]▓▓[/]",
|
|
242
|
-
"Dark and radiant",
|
|
243
|
-
)
|
|
244
|
-
colors.add_row(
|
|
245
|
-
"✓" if c == "quartz2" else "",
|
|
246
|
-
"quartz2",
|
|
247
|
-
"[magenta]▓▓[/] [blue]▓▓[/] [yellow]▓▓[/]",
|
|
248
|
-
"Remix of 'quartz' with accents",
|
|
249
|
-
)
|
|
250
|
-
colors.add_row(
|
|
251
|
-
"✓" if c == "cargo" else "",
|
|
252
|
-
"cargo",
|
|
253
|
-
"[green]▓▓[/] [cyan]▓▓[/] [default]▓▓[/]",
|
|
254
|
-
"Cargo CLI theme; legible and bold",
|
|
255
|
-
)
|
|
256
|
-
colors.add_row(
|
|
257
|
-
"✓" if c == "forest" else "",
|
|
258
|
-
"forest",
|
|
259
|
-
"[green]▓▓[/] [yellow]▓▓[/] [cyan]▓▓[/]",
|
|
260
|
-
"Earthy tones with analogous colors",
|
|
261
|
-
)
|
|
262
|
-
colors.add_row(
|
|
263
|
-
"✓" if c == "dracula" else "",
|
|
264
|
-
"dracula",
|
|
265
|
-
"[magenta]▓▓[/] [red]▓▓[/] [yellow]▓▓[/]",
|
|
266
|
-
"Vibrant high-contract dark theme",
|
|
267
|
-
)
|
|
268
|
-
colors.add_row(
|
|
269
|
-
"✓" if c == "dracula2" else "",
|
|
270
|
-
"dracula2",
|
|
271
|
-
"[magenta on black]▓▓[/] [red on black]▓▓[/] [black]▓▓[/]",
|
|
272
|
-
"Dracula theme with forced black background",
|
|
273
|
-
)
|
|
274
|
-
for _c in ["red", "green", "yellow", "blue", "magenta", "cyan"]:
|
|
222
|
+
for r in COLORS.values():
|
|
223
|
+
if r.hidden:
|
|
224
|
+
continue
|
|
225
|
+
selected_row = c == r.name or (c is None and r.name == "default")
|
|
275
226
|
colors.add_row(
|
|
276
|
-
"
|
|
277
|
-
|
|
278
|
-
f"[
|
|
279
|
-
|
|
227
|
+
"*" if selected_row else "",
|
|
228
|
+
r.name,
|
|
229
|
+
" ".join([f"[{_}]▓▓[/]" for _ in r.primary_colors[:3]]),
|
|
230
|
+
r.description,
|
|
280
231
|
)
|
|
281
|
-
colors.add_row(
|
|
282
|
-
"✓" if c == f"{_c}2" else "",
|
|
283
|
-
f"{_c}2",
|
|
284
|
-
f"[{_c}]▓▓[/] [default]▓▓[/] [dim]▓▓[/]",
|
|
285
|
-
f"Simple theme with {_c} accents on object names",
|
|
286
|
-
)
|
|
287
|
-
colors.add_row(
|
|
288
|
-
"✓" if c == "mono" else "", "mono", "[default]▓▓[/] [dim]▓▓[/]", "Monochromatic theme with no colors"
|
|
289
|
-
)
|
|
290
|
-
colors.add_row("✓" if c == "plain" else "", "plain", "[default]▓▓[/]", "No style at all")
|
|
291
232
|
|
|
292
233
|
formats = Table(
|
|
293
234
|
"",
|
|
@@ -300,13 +241,9 @@ def list_themes(ctx: RichContext, param: click.Parameter, value: bool) -> None:
|
|
|
300
241
|
expand=True,
|
|
301
242
|
)
|
|
302
243
|
formats.columns[1].style = "bold"
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
formats.add_row("✓" if f == "slim" else "", "slim", "Simple, classic, no-fuss CLI format")
|
|
307
|
-
formats.add_row("✓" if f == "modern" else "", "modern", "Beautiful modern look")
|
|
308
|
-
formats.add_row("✓" if f == "robo" else "", "robo", "Spacious with sharp corners")
|
|
309
|
-
formats.add_row("✓" if f == "nu" else "", "nu", "Great balance of compactness, legibility, and style")
|
|
244
|
+
for r in FORMATS.values():
|
|
245
|
+
selected_row = f == r.name or (f is None and r.name == "box")
|
|
246
|
+
formats.add_row("*" if selected_row else "", r.name, r.description)
|
|
310
247
|
|
|
311
248
|
how_to_use = Padding(
|
|
312
249
|
Text("\n\n", overflow="fold").join(
|
|
@@ -398,6 +335,8 @@ def list_themes(ctx: RichContext, param: click.Parameter, value: bool) -> None:
|
|
|
398
335
|
"--suppress-warnings/--do-not-suppress-warnings",
|
|
399
336
|
is_flag=True,
|
|
400
337
|
default=False,
|
|
338
|
+
envvar="RICH_CLICK_CLI_SUPPRESS_WARNINGS",
|
|
339
|
+
show_envvar=True,
|
|
401
340
|
panel="Advanced Options",
|
|
402
341
|
help="Suppress warnings when there are conflicting entry_points." " This situation is extremely rare.",
|
|
403
342
|
)
|
|
@@ -406,7 +345,8 @@ def list_themes(ctx: RichContext, param: click.Parameter, value: bool) -> None:
|
|
|
406
345
|
is_flag=True,
|
|
407
346
|
default=True,
|
|
408
347
|
panel="Advanced Options",
|
|
409
|
-
help="If set, patch [
|
|
348
|
+
help="If set, patch [reverse][option][b]rich_click.Command[/][/][/],"
|
|
349
|
+
" not just [reverse][option][b]click.Command[/][/][/].",
|
|
410
350
|
)
|
|
411
351
|
@_rich_option(
|
|
412
352
|
"--themes",
|
|
@@ -467,14 +407,23 @@ https://ewels.github.io/rich-click/latest/documentation/rich_click_cli/[/]
|
|
|
467
407
|
|
|
468
408
|
>>> [command]rich-click[/] [argument]my_package[/] [argument]cmd[/] [option]--foo[/] 3
|
|
469
409
|
""" # noqa: D401
|
|
470
|
-
|
|
471
|
-
if
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
410
|
+
try:
|
|
411
|
+
if rich_config:
|
|
412
|
+
if theme:
|
|
413
|
+
rich_config.setdefault("theme", theme)
|
|
414
|
+
import rich_click.rich_click as rc
|
|
415
|
+
|
|
416
|
+
rc._THEME_FROM_CLI = theme
|
|
417
|
+
cfg = RichHelpConfiguration.load_from_globals(**rich_config)
|
|
418
|
+
elif theme:
|
|
419
|
+
import rich_click.rich_click as rc
|
|
420
|
+
|
|
421
|
+
rc._THEME_FROM_CLI = theme
|
|
422
|
+
cfg = RichHelpConfiguration.load_from_globals(theme=theme)
|
|
423
|
+
else:
|
|
424
|
+
cfg = RichHelpConfiguration.load_from_globals()
|
|
425
|
+
except RichClickThemeNotFound as e:
|
|
426
|
+
raise click.ClickException(e.args[0] if e.args else "Theme not found")
|
|
478
427
|
|
|
479
428
|
if (show_help or not script_and_args) and not ctx.resilient_parsing:
|
|
480
429
|
cfg.use_markdown = False
|
|
@@ -488,21 +437,27 @@ https://ewels.github.io/rich-click/latest/documentation/rich_click_cli/[/]
|
|
|
488
437
|
ctx.exit(2)
|
|
489
438
|
ctx.exit(0)
|
|
490
439
|
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
440
|
+
@contextmanager
|
|
441
|
+
def patch_ctx() -> Generator[None, None, None]:
|
|
442
|
+
if ctx.get_parameter_source("typer") != ParameterSource.ENVIRONMENT:
|
|
443
|
+
try:
|
|
444
|
+
with warnings.catch_warnings():
|
|
445
|
+
warnings.filterwarnings("error", category=ImportWarning)
|
|
446
|
+
yield
|
|
447
|
+
except ImportWarning as e:
|
|
448
|
+
if not suppress_warnings and any("Typer" in a for a in e.args):
|
|
449
|
+
import rich
|
|
450
|
+
|
|
451
|
+
rich.print(
|
|
452
|
+
f"[red]WARNING: Attempted to patch Typer, but Typer is not installed.[/red]"
|
|
453
|
+
f"\n\n{DISABLE_WARNINGS_NOTE}"
|
|
454
|
+
)
|
|
455
|
+
else:
|
|
456
|
+
yield
|
|
503
457
|
|
|
504
458
|
# patch click before importing the program function
|
|
505
|
-
|
|
459
|
+
with patch_ctx():
|
|
460
|
+
_patch(rich_config=cfg, patch_rich_click=patch_rich_click)
|
|
506
461
|
|
|
507
462
|
script, *args = script_and_args
|
|
508
463
|
|
|
@@ -526,8 +481,8 @@ https://ewels.github.io/rich-click/latest/documentation/rich_click_cli/[/]
|
|
|
526
481
|
# and PYTHONPATH does not include ".".
|
|
527
482
|
sys.path.append(os.path.abspath("."))
|
|
528
483
|
module = import_module(module_path)
|
|
529
|
-
except ModuleNotFoundError:
|
|
530
|
-
raise click.ClickException(
|
|
484
|
+
except ModuleNotFoundError as e:
|
|
485
|
+
raise click.ClickException(e.args[0] if e.args else "Unknown error")
|
|
531
486
|
try:
|
|
532
487
|
f = getattr(module, function_name)
|
|
533
488
|
except AttributeError:
|
|
@@ -541,8 +496,8 @@ https://ewels.github.io/rich-click/latest/documentation/rich_click_cli/[/]
|
|
|
541
496
|
|
|
542
497
|
try:
|
|
543
498
|
runpy.run_path(module_path, run_name="__main__")
|
|
544
|
-
except ImportError:
|
|
545
|
-
raise click.ClickException(
|
|
499
|
+
except ImportError as e:
|
|
500
|
+
raise click.ClickException(e.args[0] if e.args else "Unknown error")
|
|
546
501
|
|
|
547
502
|
else:
|
|
548
503
|
|
|
@@ -557,8 +512,8 @@ https://ewels.github.io/rich-click/latest/documentation/rich_click_cli/[/]
|
|
|
557
512
|
sys.path.append(os.path.abspath("."))
|
|
558
513
|
try:
|
|
559
514
|
runpy.run_module(module_path, run_name="__main__")
|
|
560
|
-
except ImportError:
|
|
561
|
-
raise click.ClickException(
|
|
515
|
+
except ImportError as e:
|
|
516
|
+
raise click.ClickException(e.args[0] if e.args else "Unknown error")
|
|
562
517
|
|
|
563
518
|
prog = module_path.split(".", 1)[0]
|
|
564
519
|
sys.argv = [prog, *args]
|