Skip to content

Commit 8da2761

Browse files
authored
Add show_hidden option (#52)
* Add show_hidden option * Applied formatting * Add test for _show_options()
1 parent 427fe5f commit 8da2761

5 files changed

Lines changed: 131 additions & 24 deletions

File tree

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,3 +135,4 @@ Options:
135135
- `depth`: _(Optional, default: `0`)_ Offset to add when generating headers.
136136
- `style`: _(Optional, default: `plain`)_ Style for the options section. The possible choices are `plain` and `table`.
137137
- `remove_ascii_art`: _(Optional, default: `False`)_ When docstrings begin with the escape character `\b`, all text will be ignored until the next blank line is encountered.
138+
- `show_hidden`: _(Optional, default: `False`)_ Show commands and options that are marked as hidden.

mkdocs_click/_docs.py

Lines changed: 59 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
# All rights reserved
33
# Licensed under the Apache license (see LICENSE)
44
import inspect
5+
from contextlib import contextmanager, ExitStack
56
from typing import Iterator, List, cast
67

78
import click
@@ -16,11 +17,18 @@ def make_command_docs(
1617
depth: int = 0,
1718
style: str = "plain",
1819
remove_ascii_art: bool = False,
20+
show_hidden: bool = False,
1921
has_attr_list: bool = False,
2022
) -> Iterator[str]:
2123
"""Create the Markdown lines for a command and its sub-commands."""
2224
for line in _recursively_make_command_docs(
23-
prog_name, command, depth=depth, style=style, remove_ascii_art=remove_ascii_art, has_attr_list=has_attr_list
25+
prog_name,
26+
command,
27+
depth=depth,
28+
style=style,
29+
remove_ascii_art=remove_ascii_art,
30+
show_hidden=show_hidden,
31+
has_attr_list=has_attr_list,
2432
):
2533
if line.strip() == "\b":
2634
continue
@@ -35,21 +43,31 @@ def _recursively_make_command_docs(
3543
depth: int = 0,
3644
style: str = "plain",
3745
remove_ascii_art: bool = False,
46+
show_hidden: bool = False,
3847
has_attr_list: bool = False,
3948
) -> Iterator[str]:
4049
"""Create the raw Markdown lines for a command and its sub-commands."""
4150
ctx = click.Context(cast(click.Command, command), info_name=prog_name, parent=parent)
4251

52+
if ctx.command.hidden and not show_hidden:
53+
return
54+
4355
yield from _make_title(ctx, depth, has_attr_list=has_attr_list)
4456
yield from _make_description(ctx, remove_ascii_art=remove_ascii_art)
4557
yield from _make_usage(ctx)
46-
yield from _make_options(ctx, style)
58+
yield from _make_options(ctx, style, show_hidden=show_hidden)
4759

4860
subcommands = _get_sub_commands(ctx.command, ctx)
4961

5062
for command in sorted(subcommands, key=lambda cmd: cmd.name): # type: ignore
5163
yield from _recursively_make_command_docs(
52-
cast(str, command.name), command, parent=ctx, depth=depth + 1, style=style, has_attr_list=has_attr_list
64+
cast(str, command.name),
65+
command,
66+
parent=ctx,
67+
depth=depth + 1,
68+
style=style,
69+
show_hidden=show_hidden,
70+
has_attr_list=has_attr_list,
5371
)
5472

5573

@@ -152,37 +170,55 @@ def _make_usage(ctx: click.Context) -> Iterator[str]:
152170
yield ""
153171

154172

155-
def _make_options(ctx: click.Context, style: str = "plain") -> Iterator[str]:
173+
def _make_options(ctx: click.Context, style: str = "plain", show_hidden: bool = False) -> Iterator[str]:
156174
"""Create the Markdown lines describing the options for the command."""
157175

158176
if style == "plain":
159-
return _make_plain_options(ctx)
177+
return _make_plain_options(ctx, show_hidden=show_hidden)
160178
elif style == "table":
161-
return _make_table_options(ctx)
179+
return _make_table_options(ctx, show_hidden=show_hidden)
162180
else:
163181
raise MkDocsClickException(f"{style} is not a valid option style, which must be either `plain` or `table`.")
164182

165183

166-
def _make_plain_options(ctx: click.Context) -> Iterator[str]:
184+
@contextmanager
185+
def _show_options(ctx: click.Context) -> Iterator[None]:
186+
"""Context manager that temporarily shows all hidden options."""
187+
options = [opt for opt in ctx.command.get_params(ctx) if isinstance(opt, click.Option) and opt.hidden]
188+
189+
try:
190+
for option in options:
191+
option.hidden = False
192+
yield
193+
finally:
194+
for option in options:
195+
option.hidden = True
196+
197+
198+
def _make_plain_options(ctx: click.Context, show_hidden: bool = False) -> Iterator[str]:
167199
"""Create the plain style options description."""
168-
formatter = ctx.make_formatter()
169-
click.Command.format_options(ctx.command, ctx, formatter)
200+
with ExitStack() as stack:
201+
if show_hidden:
202+
stack.enter_context(_show_options(ctx))
170203

171-
option_lines = formatter.getvalue().splitlines()
204+
formatter = ctx.make_formatter()
205+
click.Command.format_options(ctx.command, ctx, formatter)
172206

173-
# First line is redundant "Options"
174-
option_lines = option_lines[1:]
207+
option_lines = formatter.getvalue().splitlines()
175208

176-
if not option_lines: # pragma: no cover
177-
# We expect at least `--help` to be present.
178-
raise RuntimeError("Expected at least one option")
209+
# First line is redundant "Options"
210+
option_lines = option_lines[1:]
179211

180-
yield "**Options:**"
181-
yield ""
182-
yield "```"
183-
yield from option_lines
184-
yield "```"
185-
yield ""
212+
if not option_lines: # pragma: no cover
213+
# We expect at least `--help` to be present.
214+
raise RuntimeError("Expected at least one option")
215+
216+
yield "**Options:**"
217+
yield ""
218+
yield "```"
219+
yield from option_lines
220+
yield "```"
221+
yield ""
186222

187223

188224
# Unicode "Vertical Line" character (U+007C), HTML-compatible.
@@ -251,10 +287,11 @@ def _format_table_option_row(option: click.Option) -> str:
251287
return f"| {names} | {value_type} | {description} | {default} |"
252288

253289

254-
def _make_table_options(ctx: click.Context) -> Iterator[str]:
290+
def _make_table_options(ctx: click.Context, show_hidden: bool = False) -> Iterator[str]:
255291
"""Create the table style options description."""
256292

257293
options = [param for param in ctx.command.get_params(ctx) if isinstance(param, click.Option)]
294+
options = [option for option in options if not option.hidden or show_hidden]
258295
option_rows = [_format_table_option_row(option) for option in options]
259296

260297
yield "**Options:**"

mkdocs_click/_extension.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ def replace_command_docs(has_attr_list: bool = False, **options: Any) -> Iterato
2424
depth = int(options.get("depth", 0))
2525
style = options.get("style", "plain")
2626
remove_ascii_art = options.get("remove_ascii_art", False)
27+
show_hidden = options.get("show_hidden", False)
2728

2829
command_obj = load_command(module, command)
2930

@@ -35,6 +36,7 @@ def replace_command_docs(has_attr_list: bool = False, **options: Any) -> Iterato
3536
depth=depth,
3637
style=style,
3738
remove_ascii_art=remove_ascii_art,
39+
show_hidden=show_hidden,
3840
has_attr_list=has_attr_list,
3941
)
4042

tests/app/cli.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@
99
@click.command()
1010
@click.option("--count", default=1, help="Number of greetings.")
1111
@click.option("--name", prompt="Your name", help="The person to greet.")
12-
def hello(count, name):
12+
@click.option("--hidden", hidden=True)
13+
def hello(count, name, hidden):
1314
"""Simple program that greets NAME for a total of COUNT times."""
1415

1516

@@ -33,13 +34,20 @@ def bar():
3334
"""The bar command"""
3435

3536

37+
@click.command(hidden=True)
38+
def hidden():
39+
"""The hidden command"""
40+
41+
3642
bar.add_command(hello)
3743

3844
cli.add_command(foo)
3945
cli.add_command(bar)
46+
cli.add_command(hidden)
4047

4148
cli_named.add_command(foo)
4249
cli_named.add_command(bar)
50+
cli_named.add_command(hidden)
4351

4452

4553
class MultiCLI(click.MultiCommand):

tests/test_docs.py

Lines changed: 60 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,12 @@
22
# All rights reserved
33
# Licensed under the Apache license (see LICENSE)
44
from textwrap import dedent
5+
from typing import cast
56

67
import click
78
import pytest
89

9-
from mkdocs_click._docs import make_command_docs
10+
from mkdocs_click._docs import make_command_docs, _show_options
1011
from mkdocs_click._exceptions import MkDocsClickException
1112

1213

@@ -231,3 +232,61 @@ def test_custom_multicommand(multi):
231232

232233
output = "\n".join(make_command_docs("multi", multi))
233234
assert output == expected
235+
236+
237+
@pytest.mark.parametrize("show_hidden", [True, False])
238+
@pytest.mark.parametrize("style", ["plain", "table"])
239+
def test_show_hidden_option(show_hidden, style):
240+
@click.command()
241+
@click.option("--hidden", hidden=True)
242+
def _test_cmd(hidden):
243+
"""Test cmd."""
244+
245+
output = "\n".join(make_command_docs("_test_cmd", _test_cmd, style=style, show_hidden=show_hidden))
246+
assert ("--hidden" in output) == show_hidden
247+
248+
249+
@pytest.mark.parametrize("show_hidden", [True, False])
250+
def test_show_hidden_command(show_hidden):
251+
@click.command(hidden=True)
252+
def _test_cmd():
253+
"""Test cmd."""
254+
255+
output = "\n".join(make_command_docs("_test_cmd", _test_cmd, show_hidden=show_hidden))
256+
assert (output != "") == show_hidden
257+
258+
259+
@pytest.mark.parametrize("show_hidden", [True, False])
260+
def test_show_hidden_group(show_hidden):
261+
@click.group(hidden=True)
262+
def _test_group():
263+
"""Test group."""
264+
265+
@_test_group.command(hidden=False)
266+
def _test_cmd():
267+
"""Test cmd."""
268+
269+
output = "\n".join(make_command_docs("_test_group", _test_group, show_hidden=show_hidden))
270+
assert (output != "") == show_hidden
271+
272+
273+
def test_show_options():
274+
@click.command()
275+
@click.option("--hidden", hidden=True)
276+
@click.option("--normal", hidden=False)
277+
def _test_cmd(hidden, normal):
278+
"""Test cmd."""
279+
280+
ctx = click.Context(cast(click.Command, _test_cmd), info_name="_test_cmd")
281+
opt_hidden = cast(click.Option, ctx.command.params[0])
282+
opt_normal = cast(click.Option, ctx.command.params[1])
283+
284+
assert opt_hidden.hidden
285+
assert not opt_normal.hidden
286+
287+
with _show_options(ctx):
288+
assert not opt_hidden.hidden
289+
assert not opt_normal.hidden
290+
291+
assert opt_hidden.hidden
292+
assert not opt_normal.hidden

0 commit comments

Comments
 (0)