-
-
Notifications
You must be signed in to change notification settings - Fork 35
Create a version to use with typer>=0.4.0 and click 8. #67
Conversation
@tiangolo , I find this package very helpful to complement typer, and I hope this PR will help keep it up-to-date. The hard work was already done in the typer package. The key to getting autocompletion to work in typer-cli was to make TyperCLIGroup inherit from typer.core.TyperGroup (line 54). I'm not sure if there was a better approach than to set no_args_is_help=True in the callback for the typer CLI app (line 159). The no_args_is_help parameter default changed from None to False in typer 0.4.0, and this change caused test_script_help in test_help.py and test_sub.py to fail. My line 159 allows them to pass. The test workflow passes in my repo, and I updated it to check click 7 and python 3.9. I'm not sure if some other workflows need updating or if I should have left the version number in init.py alone. |
Hooray, very excited for this to merge! |
BUMP Any updates on this? |
@jimmywan , I noticed that @tiangolo has done some recent work in the typer repo, but I haven't heard from any typer-cli maintainers regarding this pull request. I also just noticed that the test workflow here fails on the latest pre-release version of poetry, while typer uses flint instead of poetry. I wouldn't mind converting typer-cli to use flint if that makes sense. |
@cdcadman Thx for the context. I'm actually rolling off some legacy maintenance work that I had done that references this so if there is no immediate fix, I'll probably just bow out here. |
I'm interested in this pull request too. FWIW I checked out @cdcadman 's fork and ran the tests under Mac OSX 12.6, python 3.9.12. Everything passed. |
For anyone who got to here because they really want to use I added a from pathlib import Path
from typing import cast
import typer
import typer.core
from click import Command, Group
app = typer.Typer()
def get_docs_for_click(
*,
obj: Command,
ctx: typer.Context,
indent: int = 0,
name: str = "",
call_prefix: str = "",
) -> str:
docs = "#" * (1 + indent)
command_name = name or obj.name
if call_prefix:
command_name = f"{call_prefix} {command_name}"
title = f"`{command_name}`" if command_name else "CLI"
docs += f" {title}\n\n"
if obj.help:
docs += f"{obj.help}\n\n"
usage_pieces = obj.collect_usage_pieces(ctx)
if usage_pieces:
docs += "**Usage**:\n\n"
docs += "```console\n"
docs += "$ "
if command_name:
docs += f"{command_name} "
docs += f"{' '.join(usage_pieces)}\n"
docs += "```\n\n"
args = []
opts = []
for param in obj.get_params(ctx):
rv = param.get_help_record(ctx)
if rv is not None:
if param.param_type_name == "argument":
args.append(rv)
elif param.param_type_name == "option":
opts.append(rv)
if args:
docs += "**Arguments**:\n\n"
for arg_name, arg_help in args:
docs += f"* `{arg_name}`"
if arg_help:
docs += f": {arg_help}"
docs += "\n"
docs += "\n"
if opts:
docs += "**Options**:\n\n"
for opt_name, opt_help in opts:
docs += f"* `{opt_name}`"
if opt_help:
docs += f": {opt_help}"
docs += "\n"
docs += "\n"
if obj.epilog:
docs += f"{obj.epilog}\n\n"
if isinstance(obj, Group):
group: Group = cast(Group, obj)
commands = group.list_commands(ctx)
if commands:
docs += "**Commands**:\n\n"
for command in commands:
command_obj = group.get_command(ctx, command)
assert command_obj
docs += f"* `{command_obj.name}`"
command_help = command_obj.get_short_help_str()
if command_help:
docs += f": {command_help}"
docs += "\n"
docs += "\n"
for command in commands:
command_obj = group.get_command(ctx, command)
assert command_obj
use_prefix = ""
if command_name:
use_prefix += f"{command_name}"
docs += get_docs_for_click(
obj=command_obj, ctx=ctx, indent=indent + 1, call_prefix=use_prefix
)
return docs
@app.command(help="Generate markdown version of usage documentation")
def generate(
ctx: typer.Context,
name: str = typer.Option("", help="The name of the CLI program to use in docs."),
output: Path = typer.Option(
None,
help="An output file to write docs to, like README.md.",
file_okay=True,
dir_okay=False,
),
) -> None:
"""
Generate Markdown docs for a Typer app.
"""
from ..main import app as main_app
click_obj = typer.main.get_command(main_app)
docs = get_docs_for_click(obj=click_obj, ctx=ctx, name=name)
clean_docs = f"{docs.strip()}\n"
if output:
output.write_text(clean_docs)
typer.echo(f"Docs saved to: {output}")
else:
typer.echo(clean_docs) I saved this to a file called
Within from .commands.docs import app as docs_app
app.add_typer(docs_app, name="docs", help="Generate documentation") |
Based on tiangolo#67.
Based on tiangolo#67.
Based on tiangolo#67.
Based on tiangolo#67.
Hey! want to see if there's any updates on when this will be merged? |
I think I will close this PR soon. The typer repo is being maintained, but typer-cli isn't getting attention from anyone with write access. The code that drkeoni pasted above helped solve the problem which prompted me to create this PR. |
I am closing, since this has been open for a long time. Here is the
|
😭 |
Thank you @cdcadman! 🍰 This was included as part of #82, it even preserved your commits. 😎 And thanks everyone for the input here. ☕ I'll make a couple of extra tweaks and release version
|
Thanks @omBratteng for keeping my commits alive. Thanks @tiangolo for merging #82 and releasing typer-cli version 0.0.13. |
This pull request is intended to resolve #50 and #53. I tested it on Windows Powershell with click 8.0.0 and click 7.1.2, and also ran the tests under both versions of click.