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

Use MessageBuilder.pretty_callable in more places #5490

Open
ilevkivskyi opened this issue Aug 16, 2018 · 4 comments
Open

Use MessageBuilder.pretty_callable in more places #5490

ilevkivskyi opened this issue Aug 16, 2018 · 4 comments

Comments

@ilevkivskyi
Copy link
Member

Currently callable types in many error messages are formatted as

Callable[[Arg('x', int), VarArg(str)], int]

We should probably switch to more "native" format that is already used in some errors (e.g. for protocol and overloads):

def (x: int, *args: str) -> int

The main obstacle here is probably updating all tests that use the old format.

This is a follow up for #5463

@ilevkivskyi
Copy link
Member Author

Another thing to note here is that maybe we need to trim horizontally long signatures anyway. Some complex overloads in typeshed can produce huge error messages.

@JukkaL
Copy link
Collaborator

JukkaL commented Nov 11, 2021

Increasing priority since Arg(...) and VarArg(...) can look quite confusing and ugly in error messages.

I think that we can always use the "native" format for complex callable types. We'd then only use Callable[...] in messages if we can use one of these variants:

  • Callable[[X, ..., Y], Z] (simple callable types with only positional arguments shown are okay)
  • Callable[..., X] (a type with explicit ... is okay)

For everything else we can probably use the more readable def (...) -> t syntax. We should never need Arg(...), etc.

The relevant code is in mypy.messages.format_type_inner. If anybody would like to contribute a PR, I'm happy to review it (feel free to cc me).

@JukkaL
Copy link
Collaborator

JukkaL commented Apr 18, 2023

#12037 implements this, but needs some conflicts fixed. Anybody want to help with this?

@sergab11
Copy link

Hey, @JukkaL , I'm a newby in contributing to Mypy, so correct me if I'm wrong...
I thought about a solution. The changes involve the mypy.messages.format_callable_args:

def format_callable_args(
tp: Type,
format: Callable[[Type], str], 
verbosity: int,
) -> str:
 """Format a bunch of Callable arguments into a string"""
 arg_strings = []
 is_only_callable = False
 has_non_positional_arguments = False

 arg_names = []
 arg_types = []
 arg_kinds = []

 if isinstance(tp, ParamSpecType):
      arg_names = tp.prefix.arg_names
      arg_types = tp.prefix.arg_types
      arg_kinds = tp.prefix.arg_kinds
 else:
      is_only_callable = True
      arg_names = tp.arg_names
      arg_types = tp.arg_types
      arg_kinds = tp.arg_kinds

 for arg_name, arg_type, arg_kind in zip(arg_names, arg_types, arg_kinds):
     if arg_kind == ARG_POS and arg_name is None or verbosity == 0 and arg_kind.is_positional():
         arg_strings.append(format(arg_type))
     else:
         has_non_positional_arguments = True
         constructor = ARG_CONSTRUCTOR_NAMES[arg_kind]
         if arg_kind.is_star() or arg_name is None:
             arg_strings.append(f"{constructor}({format(arg_type)})")
         else:
             arg_strings.append(f"{constructor}({format(arg_type)}, {repr(arg_name)})")

 if is_only_callable and has_non_positional_arguments:
     return "pretty callable"

 return ", ".join(arg_strings)

And in the mypy.messages.format_type_inner (in the isinstance(func, CallableType): clause):

  args = format_callable_args(
                func, format, verbosity
              )
  if args == "pretty callable": 
     return pretty_callable(func)
  return f"Callable[[{args}], {return_type}]"

Thank you for your attention!!

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

3 participants