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

Format complicated type hints better in help #13655

Open
Zaharid opened this issue Apr 26, 2022 · 7 comments
Open

Format complicated type hints better in help #13655

Zaharid opened this issue Apr 26, 2022 · 7 comments

Comments

@Zaharid
Copy link
Contributor

Zaharid commented Apr 26, 2022

I typed

In [1]: from prompt_toolkit import prompt

In [2]: prompt??

because I wanted to know the default for some argument in that api. It printed the following,

Signature:
prompt(
    message: Union[str, ForwardRef('MagicFormattedText'), List[Union[Tuple[str, str], Tuple[str, str, Callable[[prompt_toolkit.mouse_events.MouseEvent], NoneType]]]], Callable[[], Any], NoneType] = None,
    *,
    history: Optional[prompt_toolkit.history.History] = None,
    editing_mode: Optional[prompt_toolkit.enums.EditingMode] = None,
    refresh_interval: Optional[float] = None,
    vi_mode: Optional[bool] = None,
    lexer: Optional[prompt_toolkit.lexers.base.Lexer] = None,
    completer: Optional[prompt_toolkit.completion.base.Completer] = None,
    complete_in_thread: Optional[bool] = None,
    is_password: Optional[bool] = None,
    key_bindings: Optional[prompt_toolkit.key_binding.key_bindings.KeyBindingsBase] = None,
    bottom_toolbar: Union[str, ForwardRef('MagicFormattedText'), List[Union[Tuple[str, str], Tuple[str, str, Callable[[prompt_toolkit.mouse_events.MouseEvent], NoneType]]]], Callable[[], Any], NoneType] = None,
    style: Optional[prompt_toolkit.styles.base.BaseStyle] = None,
    color_depth: Optional[prompt_toolkit.output.color_depth.ColorDepth] = None,
    cursor: Union[prompt_toolkit.cursor_shapes.CursorShape, prompt_toolkit.cursor_shapes.CursorShapeConfig, NoneType] = None,
    include_default_pygments_style: Union[prompt_toolkit.filters.base.Filter, bool, NoneType] = None,
    style_transformation: Optional[prompt_toolkit.styles.style_transformation.StyleTransformation] = None,
    swap_light_and_dark_colors: Union[prompt_toolkit.filters.base.Filter, bool, NoneType] = None,
    rprompt: Union[str, ForwardRef('MagicFormattedText'), List[Union[Tuple[str, str], Tuple[str, str, Callable[[prompt_toolkit.mouse_events.MouseEvent], NoneType]]]], Callable[[], Any], NoneType] = None,
    multiline: Union[prompt_toolkit.filters.base.Filter, bool, NoneType] = None,
    prompt_continuation: Union[str, ForwardRef('MagicFormattedText'), List[Union[Tuple[str, str], Tuple[str, str, Callable[[prompt_toolkit.mouse_events.MouseEvent], NoneType]]]], Callable[[int, int, int], Union[str, ForwardRef('MagicFormattedText'), List[Union[Tuple[str, str], Tuple[str, str, Callable[[prompt_toolkit.mouse_events.MouseEvent], NoneType]]]], Callable[[], Any], NoneType]], NoneType] = None,
    wrap_lines: Union[prompt_toolkit.filters.base.Filter, bool, NoneType] = None,
    enable_history_search: Union[prompt_toolkit.filters.base.Filter, bool, NoneType] = None,
    search_ignore_case: Union[prompt_toolkit.filters.base.Filter, bool, NoneType] = None,
    complete_while_typing: Union[prompt_toolkit.filters.base.Filter, bool, NoneType] = None,
    validate_while_typing: Union[prompt_toolkit.filters.base.Filter, bool, NoneType] = None,
    complete_style: Optional[prompt_toolkit.shortcuts.prompt.CompleteStyle] = None,
    auto_suggest: Optional[prompt_toolkit.auto_suggest.AutoSuggest] = None,
    validator: Optional[prompt_toolkit.validation.Validator] = None,
    clipboard: Optional[prompt_toolkit.clipboard.base.Clipboard] = None,
    mouse_support: Union[prompt_toolkit.filters.base.Filter, bool, NoneType] = None,
    input_processors: Optional[List[prompt_toolkit.layout.processors.Processor]] = None,
    placeholder: Union[str, ForwardRef('MagicFormattedText'), List[Union[Tuple[str, str], Tuple[str, str, Callable[[prompt_toolkit.mouse_events.MouseEvent], NoneType]]]], Callable[[], Any], NoneType] = None,
    reserve_space_for_menu: Optional[int] = None,
    enable_system_prompt: Union[prompt_toolkit.filters.base.Filter, bool, NoneType] = None,
    enable_suspend: Union[prompt_toolkit.filters.base.Filter, bool, NoneType] = None,
    enable_open_in_editor: Union[prompt_toolkit.filters.base.Filter, bool, NoneType] = None,
    tempfile_suffix: Union[str, Callable[[], str], NoneType] = None,
    tempfile: Union[str, Callable[[], str], NoneType] = None,
    default: str = '',
    accept_default: bool = False,
    pre_run: Optional[Callable[[], NoneType]] = None,
) -> str
Docstring:
Display the prompt.

which I found rather unhelpful. For one the annotation of the argument I was interested in doesn't fit in a single line in the terminal. I wonder if there is a way to make less prominent long complicated annotations. This could be done by changing the color in which their are displayed, imposing a maximum length for the type hint or having an option is to hide annotations altogether from help. Another possibility would be to try to keep the type aliases as in the original source code rather than resolving them. Not sure how easy that is.

@MrMino
Copy link
Member

MrMino commented May 6, 2022

This reminds me of the same UX issue RTD has with typehints in their sphinx template. I agree, it's unhelpful at best.

For anyone interested in improving this (my future self included), look at the pinfo magic. Running pinfo? shows the module where it is implemented (so meta...).

@krassowski
Copy link
Member

Union[int, str] could be rendered as int | str without loss of information.

@krassowski
Copy link
Member

  • ForwardRef('MagicFormattedText') should be resolved to MagicFormattedText
  • prompt_toolkit.filters.base.Filter should be resolved to Filter though ideally there would be a way to click on it or hover to get the full path
  • NoneType should be replaced with None, as per mypy:

    None is a type with only one value, None. None is also used as the return type for functions that don’t return a value, i.e. functions that implicitly return None.

    The Python interpreter internally uses the name NoneType for the type of None, but None is always used in type annotations. The latter is shorter and reads better. (NoneType is available as types.NoneType on Python 3.10+, but is not exposed at all on earlier versions of Python.)
    https://mypy.readthedocs.io/en/stable/kinds_of_types.html

@krassowski
Copy link
Member

Testing with a recent ipython this looks mostly good though:

prompt(
    message: 'AnyFormattedText | None' = None,
    *,
    history: 'History | None' = None,
    editing_mode: 'EditingMode | None' = None,
    refresh_interval: 'float | None' = None,
    vi_mode: 'bool | None' = None,
    lexer: 'Lexer | None' = None,
    completer: 'Completer | None' = None,
    complete_in_thread: 'bool | None' = None,
    is_password: 'bool | None' = None,
    key_bindings: 'KeyBindingsBase | None' = None,
    bottom_toolbar: 'AnyFormattedText | None' = None,
    style: 'BaseStyle | None' = None,
    color_depth: 'ColorDepth | None' = None,
    cursor: 'AnyCursorShapeConfig' = None,
    include_default_pygments_style: 'FilterOrBool | None' = None,
    style_transformation: 'StyleTransformation | None' = None,
    swap_light_and_dark_colors: 'FilterOrBool | None' = None,
    rprompt: 'AnyFormattedText | None' = None,
    multiline: 'FilterOrBool | None' = None,
    prompt_continuation: 'PromptContinuationText | None' = None,
    wrap_lines: 'FilterOrBool | None' = None,
    enable_history_search: 'FilterOrBool | None' = None,
    search_ignore_case: 'FilterOrBool | None' = None,
    complete_while_typing: 'FilterOrBool | None' = None,
    validate_while_typing: 'FilterOrBool | None' = None,
    complete_style: 'CompleteStyle | None' = None,
    auto_suggest: 'AutoSuggest | None' = None,
    validator: 'Validator | None' = None,
    clipboard: 'Clipboard | None' = None,
    mouse_support: 'FilterOrBool | None' = None,
    input_processors: 'list[Processor] | None' = None,
    placeholder: 'AnyFormattedText | None' = None,
    reserve_space_for_menu: 'int | None' = None,
    enable_system_prompt: 'FilterOrBool | None' = None,
    enable_suspend: 'FilterOrBool | None' = None,
    enable_open_in_editor: 'FilterOrBool | None' = None,
    tempfile_suffix: 'str | Callable[[], str] | None' = None,
    tempfile: 'str | Callable[[], str] | None' = None,
    default: 'str' = '',
    accept_default: 'bool' = False,
    pre_run: 'Callable[[], None] | None' = None,
    set_exception_handler: 'bool' = True,
    handle_sigint: 'bool' = True,
    in_thread: 'bool' = False,
    inputhook: 'InputHook | None' = None,
) -> 'str'

@joelostblom
Copy link

Which version did you try? I just tried with 8.22.2 and I still see the long api prefixes in the help popup:

image

@krassowski
Copy link
Member

Yes, I can see that in altair. I guess prompt_toolkit changed their code. Does altair use from future import __annotations__?

@joelostblom
Copy link

Hmm, no I don't think so. Would that be helpful here?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants