From da0f8cab88fad53f54d8dae350885fc0d26b1a04 Mon Sep 17 00:00:00 2001 From: Yudai NAKATA Date: Sat, 21 Nov 2020 02:21:07 +0900 Subject: [PATCH 1/5] Markup options in a table format --- mkdocs_click/_docs.py | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/mkdocs_click/_docs.py b/mkdocs_click/_docs.py index a1d19d9..37e2090 100644 --- a/mkdocs_click/_docs.py +++ b/mkdocs_click/_docs.py @@ -106,13 +106,24 @@ def _make_options(ctx: click.Context) -> Iterator[str]: click.Command.format_options(ctx.command, ctx, formatter) # First line is redundant "Options" # Last line is `--help` - option_lines = formatter.getvalue().splitlines()[1:-1] - if not option_lines: + fragments = [elem.lstrip(" ").rstrip("\n") for elem in formatter.buffer[1:-1] if not elem.isspace()][:-1] + # This line assumes that help messages do not start with a hyphen. + indices_option = list(map(lambda x: x[0], filter(lambda x: x[1].startswith("-"), enumerate(fragments)))) + options = [ + # Appending None to List[int] is necessary because we need to include the last element of fragments + # while using slicing. + fragments[i:j] + for i, j in zip(indices_option, indices_option[1:] + [None]) # type: ignore[list-item] + ] + if not options: return - yield "Options:" + yield "**Options:**" yield "" - yield "```" - yield from option_lines - yield "```" + yield "| Option | Description |" + yield "| ------ | ----------- |" + for option in options: + # This might result in a bad appearance if help messagge is written in + # languages that don't separate words by whitespaces (e.g., Chinese, Japanese and Thai) + yield f"| `{option[0]}` | {' '.join(option[1:]) if len(option) > 1 else ''} |" yield "" From 23df50eccc5fed3109f30791b000e941c6637038 Mon Sep 17 00:00:00 2001 From: Yudai NAKATA Date: Sat, 21 Nov 2020 02:23:07 +0900 Subject: [PATCH 2/5] Update test --- tests/app/expected.md | 10 +++++----- tests/unit/test_docs.py | 17 ++++++++--------- 2 files changed, 13 insertions(+), 14 deletions(-) diff --git a/tests/app/expected.md b/tests/app/expected.md index 95b47a0..36b4454 100644 --- a/tests/app/expected.md +++ b/tests/app/expected.md @@ -28,12 +28,12 @@ Usage: cli bar hello [OPTIONS] ``` -Options: +**Options:** -``` - --count INTEGER Number of greetings. - --name TEXT The person to greet. -``` +| Option | Description | +| ------ | ----------- | +| `--count INTEGER` | Number of greetings. | +| `--name TEXT` | The person to greet. | ## foo diff --git a/tests/unit/test_docs.py b/tests/unit/test_docs.py index f145777..2f23629 100644 --- a/tests/unit/test_docs.py +++ b/tests/unit/test_docs.py @@ -28,12 +28,11 @@ def hello(): hello [OPTIONS] ``` - Options: - - ``` - -d, --debug TEXT Include debug output - ``` + **Options:** + | Option | Description | + | ------ | ----------- | + | `-d, --debug TEXT` | Include debug output | """ ).strip() @@ -90,11 +89,11 @@ def test_custom_multicommand(): multi hello [OPTIONS] ``` - Options: + **Options:** - ``` - -d, --debug TEXT Include debug output - ``` + | Option | Description | + | ------ | ----------- | + | `-d, --debug TEXT` | Include debug output | """ ).lstrip() From 6f89573f71a1d410351b25dad258ffa004d21965 Mon Sep 17 00:00:00 2001 From: Yudai NAKATA Date: Thu, 26 Nov 2020 01:18:03 +0900 Subject: [PATCH 3/5] Resolve the restrictions in the previous commit --- mkdocs_click/_docs.py | 22 ++++------------------ 1 file changed, 4 insertions(+), 18 deletions(-) diff --git a/mkdocs_click/_docs.py b/mkdocs_click/_docs.py index 37e2090..1b25c93 100644 --- a/mkdocs_click/_docs.py +++ b/mkdocs_click/_docs.py @@ -102,28 +102,14 @@ def _make_usage(ctx: click.Context) -> Iterator[str]: def _make_options(ctx: click.Context) -> Iterator[str]: """Create the Markdown lines describing the options for the command.""" - formatter = ctx.make_formatter() - click.Command.format_options(ctx.command, ctx, formatter) - # First line is redundant "Options" - # Last line is `--help` - fragments = [elem.lstrip(" ").rstrip("\n") for elem in formatter.buffer[1:-1] if not elem.isspace()][:-1] - # This line assumes that help messages do not start with a hyphen. - indices_option = list(map(lambda x: x[0], filter(lambda x: x[1].startswith("-"), enumerate(fragments)))) - options = [ - # Appending None to List[int] is necessary because we need to include the last element of fragments - # while using slicing. - fragments[i:j] - for i, j in zip(indices_option, indices_option[1:] + [None]) # type: ignore[list-item] - ] - if not options: + options = [param.get_help_record(ctx) for param in ctx.command.get_params(ctx) if isinstance(param, click.Option)] + if options[0][0] == "--help": return yield "**Options:**" yield "" yield "| Option | Description |" yield "| ------ | ----------- |" - for option in options: - # This might result in a bad appearance if help messagge is written in - # languages that don't separate words by whitespaces (e.g., Chinese, Japanese and Thai) - yield f"| `{option[0]}` | {' '.join(option[1:]) if len(option) > 1 else ''} |" + for option in options[:-1]: + yield f"| `{option[0]}` | {option[1]} |" yield "" From 86df8d2fa2e80e0e267d1d5046250ecf4966ab92 Mon Sep 17 00:00:00 2001 From: Yudai NAKATA Date: Sat, 28 Nov 2020 01:19:04 +0900 Subject: [PATCH 4/5] Add columns for type, required, and default --- mkdocs_click/_docs.py | 41 ++++++++++++++++++++++++++++++++++------- tests/app/expected.md | 8 ++++---- tests/unit/test_docs.py | 12 ++++++------ 3 files changed, 44 insertions(+), 17 deletions(-) diff --git a/mkdocs_click/_docs.py b/mkdocs_click/_docs.py index 1b25c93..b1c37a6 100644 --- a/mkdocs_click/_docs.py +++ b/mkdocs_click/_docs.py @@ -1,7 +1,7 @@ # (C) Datadog, Inc. 2020-present # All rights reserved # Licensed under the Apache license (see LICENSE) -from typing import Iterator, List, Optional, cast +from typing import Iterator, List, Optional, cast, Iterable import click @@ -102,14 +102,41 @@ def _make_usage(ctx: click.Context) -> Iterator[str]: def _make_options(ctx: click.Context) -> Iterator[str]: """Create the Markdown lines describing the options for the command.""" - options = [param.get_help_record(ctx) for param in ctx.command.get_params(ctx) if isinstance(param, click.Option)] - if options[0][0] == "--help": + + def backquote(opts: Iterable[str]) -> List[str]: + return [f"`{opt}`" for opt in opts] + + def format_possible_value(opt: click.Option) -> str: + param_type = opt.type + + if isinstance(param_type, click.Choice): + return f"{param_type.name.upper()} ({' | '.join(backquote(param_type.choices))})" + elif isinstance(param_type, click.DateTime): + return f"{param_type.name.upper()} ({' | '.join(backquote(param_type.formats))})" + elif isinstance(param_type, (click.IntRange, click.FloatRange)): + if param_type.min is not None and param_type.max is not None: + return f"{param_type.name.upper()} (between `{param_type.min}` and `{param_type.max}`)" + elif param_type.min is not None: + return f"{param_type.name.upper()} (`{param_type.min}` and above)" + else: + return f"{param_type.name.upper()} (`{param_type.max}` and below)" + else: + return param_type.name.upper() + + params = [param for param in ctx.command.get_params(ctx) if isinstance(param, click.Option)] + + if params[0].opts[0] == "--help": return yield "**Options:**" yield "" - yield "| Option | Description |" - yield "| ------ | ----------- |" - for option in options[:-1]: - yield f"| `{option[0]}` | {option[1]} |" + yield "| Option | Type | Description | Required | Default |" + yield "| ------ | ---- | ----------- | -------- | ------- |" + for param in params[:-1]: + options = f"{', '.join(backquote(param.opts))}{'/{}'.format(', '.join(backquote(param.secondary_opts))) if param.secondary_opts != [] else ''}" # noqa: E501 + value_type = format_possible_value(param) + description = param.help if param.help is not None else "No description given" + required = "✔" if param.required else "" + default = f"`{param.default}`" if param.default is not None else "" + yield f"| {options} | {value_type} | {description} | {required} | {default} |" yield "" diff --git a/tests/app/expected.md b/tests/app/expected.md index 36b4454..e4987bd 100644 --- a/tests/app/expected.md +++ b/tests/app/expected.md @@ -30,10 +30,10 @@ cli bar hello [OPTIONS] **Options:** -| Option | Description | -| ------ | ----------- | -| `--count INTEGER` | Number of greetings. | -| `--name TEXT` | The person to greet. | +| Option | Type | Description | Required | Default | +| ------ | ---- | ----------- | -------- | ------- | +| `--count` | INTEGER | Number of greetings. | | `1` | +| `--name` | TEXT | The person to greet. | | | ## foo diff --git a/tests/unit/test_docs.py b/tests/unit/test_docs.py index 2f23629..bcb5d51 100644 --- a/tests/unit/test_docs.py +++ b/tests/unit/test_docs.py @@ -30,9 +30,9 @@ def hello(): **Options:** - | Option | Description | - | ------ | ----------- | - | `-d, --debug TEXT` | Include debug output | + | Option | Type | Description | Required | Default | + | ------ | ---- | ----------- | -------- | ------- | + | `-d`, `--debug` | TEXT | Include debug output | | | """ ).strip() @@ -91,9 +91,9 @@ def test_custom_multicommand(): **Options:** - | Option | Description | - | ------ | ----------- | - | `-d, --debug TEXT` | Include debug output | + | Option | Type | Description | Required | Default | + | ------ | ---- | ----------- | -------- | ------- | + | `-d`, `--debug` | TEXT | Include debug output | | | """ ).lstrip() From c22f6198ac39c7a0a713d76d09d25d0f0cc9bcbd Mon Sep 17 00:00:00 2001 From: Yudai NAKATA Date: Wed, 9 Dec 2020 12:38:40 +0900 Subject: [PATCH 5/5] Format in the same way as mkdocstrings' parameters --- mkdocs_click/_docs.py | 9 ++++----- tests/app/expected.md | 8 ++++---- tests/unit/test_docs.py | 12 ++++++------ 3 files changed, 14 insertions(+), 15 deletions(-) diff --git a/mkdocs_click/_docs.py b/mkdocs_click/_docs.py index b1c37a6..a18c7a1 100644 --- a/mkdocs_click/_docs.py +++ b/mkdocs_click/_docs.py @@ -130,13 +130,12 @@ def format_possible_value(opt: click.Option) -> str: yield "**Options:**" yield "" - yield "| Option | Type | Description | Required | Default |" - yield "| ------ | ---- | ----------- | -------- | ------- |" + yield "| Name | Type | Description | Default |" + yield "| ------ | ---- | ----------- | ------- |" for param in params[:-1]: options = f"{', '.join(backquote(param.opts))}{'/{}'.format(', '.join(backquote(param.secondary_opts))) if param.secondary_opts != [] else ''}" # noqa: E501 value_type = format_possible_value(param) description = param.help if param.help is not None else "No description given" - required = "✔" if param.required else "" - default = f"`{param.default}`" if param.default is not None else "" - yield f"| {options} | {value_type} | {description} | {required} | {default} |" + default = f"`{param.default}`" if param.default is not None else "_required_" + yield f"| {options} | {value_type} | {description} | {default} |" yield "" diff --git a/tests/app/expected.md b/tests/app/expected.md index e4987bd..ec02ee2 100644 --- a/tests/app/expected.md +++ b/tests/app/expected.md @@ -30,10 +30,10 @@ cli bar hello [OPTIONS] **Options:** -| Option | Type | Description | Required | Default | -| ------ | ---- | ----------- | -------- | ------- | -| `--count` | INTEGER | Number of greetings. | | `1` | -| `--name` | TEXT | The person to greet. | | | +| Name | Type | Description | Default | +| ------ | ---- | ----------- | ------- | +| `--count` | INTEGER | Number of greetings. | `1` | +| `--name` | TEXT | The person to greet. | _required_ | ## foo diff --git a/tests/unit/test_docs.py b/tests/unit/test_docs.py index bcb5d51..b47ddbf 100644 --- a/tests/unit/test_docs.py +++ b/tests/unit/test_docs.py @@ -30,9 +30,9 @@ def hello(): **Options:** - | Option | Type | Description | Required | Default | - | ------ | ---- | ----------- | -------- | ------- | - | `-d`, `--debug` | TEXT | Include debug output | | | + | Name | Type | Description | Default | + | ------ | ---- | ----------- | ------- | + | `-d`, `--debug` | TEXT | Include debug output | _required_ | """ ).strip() @@ -91,9 +91,9 @@ def test_custom_multicommand(): **Options:** - | Option | Type | Description | Required | Default | - | ------ | ---- | ----------- | -------- | ------- | - | `-d`, `--debug` | TEXT | Include debug output | | | + | Name | Type | Description | Default | + | ------ | ---- | ----------- | ------- | + | `-d`, `--debug` | TEXT | Include debug output | _required_ | """ ).lstrip()