typer icon indicating copy to clipboard operation
typer copied to clipboard

Bad argument help for type of optional argument

Open AlirezaTheH opened this issue 1 year ago • 3 comments

First Check

  • [X] I added a very descriptive title to this issue.
  • [X] I used the GitHub search to find a similar issue and didn't find it.
  • [X] I searched the Typer documentation, with the integrated search.
  • [X] I already searched in Google "How to X in Typer" and didn't find any information.
  • [X] I already read and followed all the tutorial in the docs and didn't find an answer.
  • [X] I already checked if it is not related to Typer but to Click.

Commit to Help

  • [x] I commit to help with one of those options 👆

Example Code

import typer
from typing import Optional


def main(name: Optional[str] = typer.Argument(None)):
   if name:
       typer.echo(f'Name: {name}')

if __name__ == '__main__':
    typer.run(main)

Description

For optional arguments Typer shows their metavar instead of type in argument help. For above example instead of TEXT we get [NAME] in argument help.

Operating System

macOS

Operating System Details

No response

Typer Version

0.6.1

Python Version

3.10

Additional Context

No response

AlirezaTheH avatar Aug 02 '22 10:08 AlirezaTheH

You can manually specify the metavar like this:

import typer
from typing import Optional


def main(name: Optional[str] = typer.Argument(None, metavar='name')):
    if name:
        typer.echo(f'Name: {name}')


if __name__ == '__main__':
    typer.run(main)

osintalex avatar Aug 03 '22 14:08 osintalex

Yes, but this is erasing the problem.

AlirezaTheH avatar Aug 04 '22 12:08 AlirezaTheH

I would say that issue is caused by logic in here: https://github.com/tiangolo/typer/blob/7f44e6db6267efa87918e8700212de41a7fbdc3e/typer/rich_utils.py#L367-L377

To reiterate the exact issue - following code:

import sys, typer
sys.argv[1:] = ['--help']

def example(*,
            arg1: int,
            arg2: int = 42,
            arg3: int = typer.Argument(...),
            arg4: int = typer.Argument(42),
            arg5: int = typer.Option(...),
            arg6: int = typer.Option(42),
            arg7: int = typer.Argument(42, metavar='metaarg7'),
            arg8: int = typer.Argument(42, metavar='ARG8'),
        ):
    pass

typer.run(example)

Produces following help message:

Usage: Example.py [OPTIONS] ARG1 ARG3 [ARG4] metaarg7 ARG8

Arguments:
 *    arg1      INTEGER   [default: None] [required]
 *    arg3      INTEGER   [default: None] [required]
      arg4      [ARG4]    [default: 42]
      arg7      metaarg7  [default: 42]
      arg8      INTEGER   [default: 42]

Options:
    --arg2      INTEGER   [default: 42]
 *  --arg5      INTEGER   [default: None] [required]
    --arg6      INTEGER   [default: 42]

The usage example works as intended and documented - for each argument a metavar is displayed.

The issue is in rest of help message. As the code is written - the second column is designed to contain metavar. But due to condition metavar_str == param.name.upper() in most cases it actually contains type name instead of metavar. It is also containing type for all options.

While this condition is core of the issue it probably was added quite reasonably - because metavar column is not really useful. Similarly to OP, I would also prefer changing this column to just always contain type.

Noxitu avatar Sep 06 '22 18:09 Noxitu