-
-
Notifications
You must be signed in to change notification settings - Fork 2.9k
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
Implement a reveal_locals expression. (#3387) #3425
Conversation
Some discussion with @JukkaL : I also fixed unnecessary moving of some classes in b0ca357 There is still a bug where |
I prefer just locals; global could be too much. |
@ddfisher I fixed some of the issues we discussed. I unified The main downside is I still cannot deal with the issue where:
The second |
5c1230e
to
62402cf
Compare
@ddfisher OK, I've rebased this PR against master, added some tests, added some docs, and fixed some test breakage (Travis runs successfully now) . Some of the issues I had with type inference a month ago appear to be gone, I'm assuming changes in the past month have made the method used in this PR work now. Still needs a good review though. The commits are a bit of a mess, but I will squash them once I get some feedback. Thanks for your help. |
Thanks for the updates! I'll try to take a look in the next couple days! |
@ddfisher Due to the recent mypy release, I've rebased this PR on top of master, fixing conflicts and fixing new typing linting errors. All tests are passing again. |
@aisipos Are you interested in finishing this up? |
Hi @JukkaL, I would be happy to finish it up. It's been a while since I gave it any attention, but I will try to get it up to date again with master this weekend. |
64a824f
to
81bf4a8
Compare
Hi @JukkaL, I have rebased this on top of master and fixed all the tests. However, it should get a review from a maintainer. I'm happy to address any concerns about the functionality or implementation. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good, I just had a few minor things. This feature will make it easier for users to troubleshoot cases when mypy doesn't work as expected. Apologies for the slow response, let's try to get this merged soon.
docs/source/common_issues.rst
Outdated
|
||
a = 1 | ||
b = 'one' | ||
reveal_locals() # Revealed local types are '{'a': builtins.int, 'b': builtins.str} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this missing a closing quote?
mypy/checkexpr.py
Outdated
self.msg.note("'reveal_type' always outputs 'Any' in unchecked functions", expr) | ||
return revealed_type | ||
if expr.kind == REVEAL_TYPE: | ||
if expr.expr is not None: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe using assert expr.expr is not None
would make sense here? Now if the condition is false, we might read an undefined variable below.
mypy/messages.py
Outdated
s = "{{{}}}".format( | ||
', '.join("'{}': {}".format(k, v) for k, v in sorted_locals.items()) | ||
) | ||
self.fail('Revealed local types are \'{}\''.format(s), context) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What about using double quotes around this since the message contains single quotes? The current output is a bit unclear. I'd actually prefer displaying one item at a line, such as like this:
Revelead local types:
a: int
b: str
c: ...
This could make it a little easier to find the type of a particular variable.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd be happy to change the implementation to write multiple lines, but then I don't know how to use the test functions to verify multi-line output. Is this possible?
mypy/nodes.py
Outdated
class RevealTypeExpr(Expression): | ||
"""Reveal type expression reveal_type(expr).""" | ||
class RevealExpr(Expression): | ||
"""Reveal type expression reveal_type(expr) or reveal locals expression.""" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe say "... reveal_locals() expression" to make this a bit more explicit?
mypy/nodes.py
Outdated
def __init__( | ||
self, kind: int, | ||
expr: Optional[Expression] = None, | ||
local_nodes: 'Optional[List[Var]]'=None) -> None: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Style nit: We use spaces around =
.
mypy/traverser.py
Outdated
if o.kind == REVEAL_TYPE: | ||
from mypy.nodes import Expression | ||
from typing import cast | ||
expr = cast(Expression, o.expr) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd prefer to use assert o.expr is not None
here, as it's a bit clearer.
mypy/treetransform.py
Outdated
return RevealTypeExpr(self.expr(node.expr)) | ||
def visit_reveal_expr(self, node: RevealExpr) -> RevealExpr: | ||
if node.kind == REVEAL_TYPE: | ||
return RevealExpr(kind=REVEAL_TYPE, expr=self.expr(cast(Expression, node.expr))) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Again, I'd use assert node.expr is not None
here.
@@ -2302,3 +2302,14 @@ f = lambda: 5 | |||
reveal_type(f) | |||
[out] | |||
main:2: error: Revealed type is 'def () -> builtins.int' | |||
|
|||
[case testRevealLocalsFunction] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for adding tests! I have one idea for additional test: using reveal_locals()
inside class body.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is the test testRevealLocalsOnClassVars
sufficient for this?
@JukkaL OK, I think I have addressed all your recent feedback and have pushed my changes. Have another look? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the updates! Looks good now.
This PR is a "rough draft" implementation of a
reveal_locals
expression, which as it stands can produce from this input:this output:
I am new to the codebase so likely this PR will need a fair bit more work and would like some feedback. I certainly need to add new tests and documentation but wanted to do that after a first round of feedback if possible.
Some notes:
type_map
attribute of theTypeChecker
instance to produce the output. I don't know if this is the correct approach but it seemed the simplest to my admittedly cursory knowledge of the codebase.locals
attribute of theSemanticAnalyzer
into eachRevealLocalsExpr
, but at the moment I am not using it. This could lead to other ways of implementing this but I wasn't sure of the best use of it.However, it's worth considering who the "audience" of this output is. The dictionary output is more machine parseable, which could be useful for editor plugins that use this functionality. Admittedly, when I first thought of this feature, this was the use case I was thinking of.
gives:
The output should be the same for both lines. I do not know of an easy fix yet.
Feedback is welcomed. I realize there will be likely many changes to this before it is merge ready.