Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Text blob from --help; descriptions from docstrings? #227

Open
dmyersturnbull opened this issue Jan 24, 2021 · 4 comments
Open

Text blob from --help; descriptions from docstrings? #227

dmyersturnbull opened this issue Jan 24, 2021 · 4 comments
Labels
feature New feature, enhancement or request

Comments

@dmyersturnbull
Copy link

dmyersturnbull commented Jan 24, 2021

Related to: #188.
Running mycli --help outputs a wall of text separated from the documentation on arguments and options.

Could Argument/Option help fields be set by parsing Napoleon-style docstrings?
Here's an example of the issue:

class Commands:
    @staticmethod
    @cli.command()
    def new(
        name: str,
        newest=typer.Option(False, hidden=True),
        prompt: bool = False,
    ) -> None:
        """
        Generates something.
        
        Args:
            name: The name to use
            newest: Use the newest version
            prompt: Prompt for full info
        """
mycli new --help
Usage: mycli new [OPTIONS] NAME

  Generates something.

  Args:     name: The name of the project, including any dashes or capital 
  letters   newest: Use the newest nightly release   prompt: Prompt for full info

Arguments:
  NAME  [required]

Options:
  --prompt / --no-prompt          [default: False]
@dmyersturnbull dmyersturnbull added the feature New feature, enhancement or request label Jan 24, 2021
@alextremblay
Copy link

I also use napolean / google-style docstrings and would also love to see this feature implemented

If that's not feasible, is there at least a way to get typer to stop mangling docstrings when it includes them in help text?
When I say mangling, i mean that when typer sees a docstring with a single newline character in it, it strips out the newline character, as in @dmyersturnbull's example, but when it encounters two newline characters in a row, it doesn't strip either of them

@alextremblay
Copy link

oh, i see now that it actually strips out ALL newline characters except the ones that separate the docstring summary from the rest of the docstring :(

@marcstreeter
Copy link

Yes! This ^^^ I don't use that format but I do use a format. It would be nice if different formats were supported (reStructuredText for instance), but even if only one format was supported that would be awesome.

@mateusoliveira43
Copy link

I had the same problem. Suppose this module is called cli.py

import typer

CLI = typer.Typer()


@CLI.command()
def greet() -> None:
    """
    Greet someone.

    Parameters
    ----------
    param1 : str
        description.
    param2 : str
        description.
    param3 : int
        description, by default typer.Option(...)
    param4 : int
        description, by default typer.Option(...)
    param5 : int
        description, by default typer.Option(...)
    """
    print("Hello there!")


@CLI.command()
def greet_back() -> None:
    """
    Greet Obi_wan back.

    Parameters
    ----------
    param1 : str
        description.
    param2 : str
        description.
    param3 : int
        description, by default typer.Option(...)
    param4 : int
        description, by default typer.Option(...)
    param5 : int
        description, by default typer.Option(...)
    """
    print("General Kenobi!")


if __name__ == "__main__":
    CLI()

by running python cli.py greet --help (with typer version 0.6.1), I receive
whole_docstring

But I would like to receive
only_sumary_docstring

What I did to avoid duplication, was to write this function

import inspect
from typing import Callable, Any

DOCSTRING_SECTIONS = {
    # Numpy style docstring
    "Parameters": True,
    "Returns": True,
    "Raises": True,
    # Google style docstring
    "Args:": True,
    "Returns:": True,
    "Raises:": True,
}
# reST (Sphinx) style docstring
SPHINX_PARAM = ":param"
SPHINX_RETURNS = ":returns"
SPHINX_RAISES = ":raises"


def get_help_from_docstring(command: Callable[..., Any]) -> str:
    """
    Get help message from callable object.

    Parameters
    ----------
    command : Callable[..., Any]
        Callable object (command, callback, ...).

    Returns
    -------
    str
        Docstring summary, if exists; empty string otherwise.
    """
    docstring = inspect.getdoc(command)
    if not docstring:
        return ""
    docstring_lines = docstring.strip().splitlines()
    help_message = ""
    for line in docstring_lines:
        if DOCSTRING_SECTIONS.get(line.strip()) or line.strip().startswith(
            (SPHINX_PARAM, SPHINX_RETURNS, SPHINX_RAISES)
        ):
            break
        help_message += line + "\n" if line else ""
    return help_message

I believe this resolves the problem for the 3 principal docstring formats today.

To it to be added to the Typer source code, I believe it should change all the inspect.getdoc(object) occurrences in typer/main.py to get_help_from_docstring(object).

Of course, this does not solve the problem from #336

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature New feature, enhancement or request
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants