Mypy: [Feature Request] Provide an API to get the type of the expressions in the AST

Created on 6 Apr 2018  Â·  13Comments  Â·  Source: python/mypy

Knowing the type of the expressions in the AST is useful for IDEs (and IDE plugins) to support autocompletion, for static analyzers and for refactoring tools. As a matter of fact, both jedi and pylint have their own heuristics for type inference.

In my specific use case I would like to use the type information to write a safe refactoring tool. The idea is to be able to say that you want to refactor specific methods. For example one could want to refactor string.find into string.index, as:

pos = expr.find(x)
if  pos >= 0:
  # do something with pos
else:
  # do something else

where expr is any string expression, like 'string', string_var, (var + 'foo'), string_var.replace(' ', '-'), etc.

into

try:
  pos = var.index(x)
  # do something with pos
except ValueError:
  # do something else

To safely do this refactoring, one needs to be able to query the type of sub expressions, given their location in the source file. Otherwise, given that find is a common name present in many different classes, the refactoring, would blindly be applied to all of them.

Note: this is the feature request version of issue #4713.

feature needs discussion priority-1-normal

Most helpful comment

Okay, let's open this since there is renewed interest.

Maybe we should develop something similar to Pyre's API? Maybe we could even just copy the same API style, to make it easier for clients to switch.

This would a reasonable thing to have. At least most of the Pyre API features should be easy enough to implement on top of dmypy.

The core team doesn't have a lot of spare cycles, but if somebody wants to look into this, I'm happy to give some help.

All 13 comments

If you're doing refactoring, wouldn't it be better to use lib2to3's AST? I've got something that resolves the non-dynamic names in lib2to3's AST and am (slowly) working on resolving the dynamic names (e.g., y in x = MyClass(); x.y) and imported names (just a "small matter of programming").

I'm interested in this - particularly for convenient inspection of source code in an IDE. Most other typed languages can support "type reveal on hover" for expressions.

This is easier said than done. Of course it would be helpful if it
magically existed, but this is not a simple addition to the stdlib ast
module.

On Sun, Jun 10, 2018 at 3:10 PM Daniel notifications@github.com wrote:

I'm interested in this - particularly for convenient inspection source
code from an IDE. Most other typed languages support a "type reveal on
hover" for expressions.

—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub
https://github.com/python/mypy/issues/4868#issuecomment-396086034, or mute
the thread
https://github.com/notifications/unsubscribe-auth/ACwrMnsV9tamGE_09Ro8wTEGyFtWVZVOks5t7Zk2gaJpZM4TKh4B
.

--
--Guido van Rossum (python.org/~guido)

Do you need an annotated AST, or is it sufficient to have the tokens in the file mapped to fully qualified names (FQNs) and types? I have some code for mapping all the tokens to FQNs and partial code for their type information (the main thing missing is for imports, which I'm working on but it's summer and I'm doing it in my spare time).

@kamahen What do you mean by tokens? I'm guessing you refer to names/bindings or do you refer to the tokens as outputted by the tokenize module.

That would still be very helpful, as it would allow to easily refactor calls to a modules without having to make assumptions on how it is imported.

@sk- Yes, it's more-or-less the tokens as output by the tokenize module, although I use lib2to3, which has its own tokenizer. My output is a simplified AST with the tokens and fully qualified names. It would probably be easy to merge this information back into the original AST by doing a simple tree traversal of the AST while progressing through the list of tokens with their FQNs.)

Eventually, I hope to have inferred types with all the tokens, but that code is currently missing some features, such as proper handling of import.

If you want to play around with my code, I can give you my latest version (which isn't yet on github).

Are you planning on using the AST in lib2to3, which has the source location information in its AST, or something else?

@kamahen That'd be perfect, as I'm also using lib2to3.

I'd be happy to play with the code you have so far.

OK, let me get things into a slightly better shape, then I'll send it to you (or put it on github if it's not too awful). This week is rather busy, but hopefully some time next week.

There are two parts of the code -- the first produces a simplified AST with fully qualified names (currently, it outputs in JSON); the second takes that simplified AST and figures out how to resolve . operations (which is what you want for your smarter refactoring). Most of the resolving logic is done, except for handling imports. The output is also JSON, in a somewhat unfriendly format. But that can be easily changed.

(BTW, the most expensive part of the code seems to be the JSON marshaling/unmarshaling).

I've pushed an interim version of my code to https://github.com/kamahen/pykythe

Its outputs will take some explaining, so (assuming you want to play with it), I suggest you follow the setup instructions and run the test (make all_tests all_test2). At that point, I can tell you what to look at and how to interpret the outputs (and, if you wish, I can probably produce the outputs in a different and easier to use format ... for example, if you only want to use the fully-qualified name outputs, there's a simpler way of running the code).

The main things that are missing:

  • import is partially implemented and still has some bugs
  • builtins aren't yet handled
  • no caching of imports, so processing will be slow when I finish implementing imports and builtins
  • incomplete resolution of "." operation for imports

I'm closing this since there is no concrete proposal and there doesn't seem to be much active interest in this issue.

Just wanted to mention that [LibCST](https://github.com/Instagram/LibCST) has a TypeInferenceProvider which uses Pyre's query functionality. See https://pyre-check.org/docs/querying-pyre.html and https://libcst.readthedocs.io/en/latest/metadata.html#type-inference-metadata.

It'd be great if we could use Mypy instead of Pyre.

Hm, dmypy (mypy's daemon mode) has much of the same information available, there's just no API for it yet. We do have an experimental API that suggests the signature for an unannotated function based on how it's called (dmypy suggest).

Maybe we should develop something similar to Pyre's API? Maybe we could even just copy the same API style, to make it easier for clients to switch.

Okay, let's open this since there is renewed interest.

Maybe we should develop something similar to Pyre's API? Maybe we could even just copy the same API style, to make it easier for clients to switch.

This would a reasonable thing to have. At least most of the Pyre API features should be easy enough to implement on top of dmypy.

The core team doesn't have a lot of spare cycles, but if somebody wants to look into this, I'm happy to give some help.

Was this page helpful?
0 / 5 - 0 ratings