Skip to content

Consistent quote wrapping around MessageBuilder.format #3873

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

Merged
merged 29 commits into from
Aug 30, 2017

Conversation

OddBloke
Copy link
Contributor

This is a refreshed version of #3430, and fixes #3409.

@@ -277,13 +277,13 @@ class A: pass
class B: pass
[builtins fixtures/list.pyi]
[out]
main:3: error: Argument 1 to "f" has incompatible type *List[A]; expected "B"
main:4: error: Argument 2 to "f" has incompatible type *List[A]; expected "B"
main:3: error: Argument 1 to "f" has incompatible type *"List[A]"; expected "B"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the star should be inside quotes for types like this.

@OddBloke
Copy link
Contributor Author

OddBloke commented Aug 25, 2017 via email

@OddBloke
Copy link
Contributor Author

So looking at how the formatting of the star-args is done, I think the formatting methods should probably be refactored a bit.

Currently, the "public" API (.format and .format_simple) will only ever return quoted strings, which mean that callers have to remove the quotes on those strings if they want to use them for something else (like, for example, prepending * or ** inside the quotes). I think we should have additional methods that will return the "bare" formatted string (which the existing methods can then just wrap with the quoting logic).

Also, as far as I can tell, the only way that .format_simple gets called in the mypy code base is by .format (or one of the things that only .format calls), so I'll also look at dropping .format_simple in favour of just ._format_simple.

Daniel Watkins added 8 commits August 27, 2017 09:17
…mple

This makes the quoting code a little more consistent.
Instead update MessageBuilder.format to call _format_simple directly.
This is ._format_simple renamed to reflect its new intended contract.
This replaces strip_quotes(self.format(...)) calls, which have identical
effect.
This adds a bare parameter to format_distinctly, so that
MessageBuilder.incompatible_argument can take care of the quoting for
its special case.
@OddBloke
Copy link
Contributor Author

I've done that refactoring and addressed the comment from @ilevkivskyi.

Copy link
Member

@ilevkivskyi ilevkivskyi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry for a delay, this looks almost ready, just few small comments.

mypy/messages.py Outdated
else:
# Default case; we simply have to return something meaningful here.
return 'object'
Convert a type to a relatively short string suitable for error messages.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add an empty line after the first docstring line.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Line 189 is blank, it's just an existing blank line that the diff has kept from somewhere.

mypy/messages.py Outdated
.format_bare.
"""
ret = self.format_bare(typ, verbosity)
if ret in ['Module', 'overloaded function']:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not sure, but maybe add <nothing>, <deleted>, and union type ({} items)?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've added the first two, but don't have time to add the union and tuple ones right now.

mypy/messages.py Outdated
relatively short to avoid overly long error messages.
def format_bare(self, typ: Type, verbosity: int = 0) -> str:
"""
Convert a type to a relatively short string suitable for error messages.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again, an empty line after first line of docstring is needed here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as before, there is a blank line it's just not considered added for whatever reason.

mypy/messages.py Outdated
"""Jointly format a pair of types to distinct strings.

Increase the verbosity of the type strings until they become distinct.
"""
if bare:
format_method = self.format_bare
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you please add a comment why we need this more complex logic? Is it only for formatting callable arguments?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've expanded the docstring.

@@ -312,7 +312,7 @@ class C:
async def __aenter__(self) -> int: pass
def __aexit__(self, x, y, z) -> int: pass
async def f() -> None:
async with C() as x: # E: Incompatible types in "async with" for __aexit__ (actual type "int", expected type Awaitable[Any])
async with C() as x: # E: Incompatible types in "async with" for __aexit__ (actual type "int", expected type "Awaitable[Any]")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is still some inconsistency in formatting attribute names here __aexit__ and few lines above "__await__". Would you like to fix this in a separate PR?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, I suspect these will be more about specific message cleanup than anything else; I'll file an issue with the list of things you've spotted, so I don't lose track of them.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've opened #3887 for this.

x = yield from other_iterator()
x = yield from other_coroutine() # E: "yield from" can't be applied to "Aw"

async def plain_host_coroutine() -> None:
x = 0
x = await plain_generator() # E: Incompatible types in await (actual type Generator[str, None, int], expected type Awaitable[Any])
x = await plain_generator() # E: Incompatible types in await (actual type "Generator[str, None, int]", expected type "Awaitable[Any]")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similar situation here: await vs "yield from" few lines above.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But again, this is a story for a separate PR.

apply_str(Add5(), 'a') # E: Argument 1 to "apply_str" has incompatible type "Add5"; expected Callable[[str], int] \
# N: 'Add5.__call__' has type 'Callable[[Arg(int, 'x')], int]'
apply_str(Add5(), 'a') # E: Argument 1 to "apply_str" has incompatible type "Add5"; expected "Callable[[str], int]" \
# N: 'Add5.__call__' has type "Callable[[Arg(int, 'x')], int]"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Another potential idea: maybe use double quotes instead of single quotes in 'Add5.__call__'? (But not in this PR.)

@@ -579,7 +579,7 @@ class LongTypeName:
def __add__(self, x: 'LongTypeName') -> 'LongTypeName': pass
[builtins fixtures/tuple.pyi]
[out]
main:3: error: Unsupported operand types for + ("LongTypeName" and tuple(length 50))
main:3: error: Unsupported operand types for + ("LongTypeName" and "tuple(length 50)")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think tuple(length 50) should not be surrounded by quotes.

@OddBloke
Copy link
Contributor Author

@ilevkivskyi So I'm looking at stripping quotes for union types, and the test I'm writing has this output now:

Argument 1 to "takes_int" has incompatible type "union type (6 items)"; expected "int"

but would have:

Argument 1 to "takes_int" has incompatible type union type (6 items); expected "int"

which I find quite hard to parse. (The tuple formatting doesn't have the same problem, because it doesn't repeat the word "type" (it's just tuple(length N)).

I wonder if we should leave the union representation in quotes and then perhaps improve it in a different PR? (I was thinking <union type: N items> and <tuple: length N> (or even <tuple: N items> if we want it to be consistent), which I think are easier to parse).

@OddBloke
Copy link
Contributor Author

(I've pushed up a commit which does it just for tuples for now.)

@ilevkivskyi
Copy link
Member

Actually I like the idea of <union: N items> and <tuple: N items>, but again it is better for a separate PR.

Copy link
Member

@ilevkivskyi ilevkivskyi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! Looks good now.

@ilevkivskyi ilevkivskyi merged commit 3171c05 into python:master Aug 30, 2017
@OddBloke OddBloke deleted the quotewrap branch August 30, 2017 14:51
@OddBloke
Copy link
Contributor Author

\o/ Thanks!

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

Successfully merging this pull request may close these issues.

MessageBuilder.format inconsistently surrounds types with quotes
2 participants