fastapi / typer

Typer, build great CLIs. Easy to code. Based on Python type hints.
https://typer.tiangolo.com/
MIT License
15.77k stars 671 forks source link

Potential bug with new lines in the help output when markdown mode is used #447

Open renardeinside opened 2 years ago

renardeinside commented 2 years ago

First Check

Commit to Help

Example Code

import typer

app = typer.Typer(rich_markup_mode="markdown", name="tester-app")

@app.command(name="tester-cmd", help="""
    Header

    Line 1
    Line 2
    Line 3
""")
def cmd():
    pass

if __name__ == "__main__":
    app()

Description

Input:

> tester-app tester-cmd --help

Output:

 Usage: dbx tester-cmd [OPTIONS]                                                                                                                                            

Header                                                                                                                                                                     
Line 1 Line 2 Line 3     

Expected output:

Header                                                                                                                                                                     
Line 1 
Line 2
Line 3     

If I run the same command with: app = typer.Typer(rich_markup_mode="rich", name="tester-app")

I get the expected result:

 Header                                                                                                                                                                     
 Line 1                                                                                                                                                                     
 Line 2                                                                                                                                                                     
 Line 3   

If I add more newlines in markdown mode, I get the following: Input:

@app.command(name="tester-cmd", help="""
    Header

    Line 1

    Line 2

    Line 3
""")
def cmd():
    pass        

Output:

 Header                                                                                                                                                                     
 Line 1 Line 2 Line 3 

It only works if I add 3 newlines: Input:

@app.command(name="tester-cmd", help="""
    Header

    Line 1

    Line 2

    Line 3
""")
def cmd():
    pass

Output:

 Header                                                                                                                                                                     
 Line 1                                                                                                                                                                     

 Line 2                                                                                                                                                                     

 Line 3 

But it's also not the desired output. Desired output would be something similar to rich formatting:

 Header                                                                                                                                                                     
 Line 1                                                                                                                                                                     
 Line 2                                                                                                                                                                     
 Line 3   

Operating System

macOS

Operating System Details

Apple M1, macOs Monterey 12.2.1

Typer Version

0.6.1

Python Version

Python 3.9.12

Additional Context

No response

renardeinside commented 2 years ago

For those who were running into the same issue, here is a quick monkey patch I've prepared:

  1. add the custom output formatter:
    
    import inspect
    from typing import Union, Iterable

import click from rich.console import group from rich.markdown import Markdown from rich.text import Text from typer.core import MarkupMode from typer.rich_utils import MARKUP_MODE_MARKDOWN, STYLE_HELPTEXT_FIRST_LINE, _make_rich_rext

@group() def _get_custom_help_text( *, obj: Union[click.Command, click.Group], markup_mode: MarkupMode, ) -> Iterable[Union[Markdown, Text]]:

Fetch and dedent the help text

help_text = inspect.cleandoc(obj.help or "")

# Trim off anything that comes after \f on its own line
help_text = help_text.partition("\f")[0]

# Get the first paragraph
first_line = help_text.split("\n\n")[0]
# Remove single linebreaks
if markup_mode != MARKUP_MODE_MARKDOWN and not first_line.startswith("\b"):
    first_line = first_line.replace("\n", " ")
yield _make_rich_rext(
    text=first_line.strip(),
    style=STYLE_HELPTEXT_FIRST_LINE,
    markup_mode=markup_mode,
)

# Get remaining lines, remove single line breaks and format as dim
remaining_paragraphs = help_text.split("\n\n")[1:]
if remaining_paragraphs:
    remaining_lines = inspect.cleandoc("\n\n".join(remaining_paragraphs).replace("<br/>", "\\"))
    yield _make_rich_rext(
        text=remaining_lines,
        style="cyan",
        markup_mode=markup_mode,
    )

2. Monkey-patch the original method **before** initializing the `app` object:

import typer.rich_utils

typer.rich_utils._get_help_text = _get_custom_help_text



This allows you to use `<br/>` tag , which is recognized by other markdown readers, for example by `mkdocs-click`. 

Some output limitations of the method above:
- `<br/>` can only be specified in command help, this method won't work in arguments/options help strings
- `<br/>` shall only be specified once and and the end of the string that is followed by a non-empty line.
jhamman commented 1 year ago

We've also just run into this issue. Markdown that is rendered correctly by Rich is not rendered correctly when fed through a Typer docstring. @renardeinside's monkeypatch may work but a proper fix would be much more palatable.

jaklan commented 1 year ago

One more bump, it makes the Markdown mode not really usable unfortunately.

MartinSoto commented 11 months ago

It's now over a year since this problem was reported and Markdown support remains completely broken. Is this library abandonware by now? It'd be a real pity.

demizer commented 11 months ago

+1 for https://github.com/tiangolo/typer/pull/671 to get merged. This is a real bummer when using rich and markdown in help docs.

benrhodes26 commented 8 months ago

Yeah, would love to see a fix for this!

svlandeg commented 8 months ago

Is this library abandonware by now?

It isn't 🙂. Open-source maintenance is quite a bit of work, and we're facing some backlog, but we're still committed to maintaining and improving typer. In the next few months, we hope to be making more progress on that backlog.

Thanks all for your comments & contributions, they're very much appreciated!