Hello I am currently using the Python ast package with ast.NodeVisitor to generate code for another VM. I found Astroid during my search for a type inference solution. The documentation is abit sparse for me, and I was hoping someone could help me with extending the AST with Astroid's. At first I tried AstroidManager().ast_from_file(f) but I got astroid.exceptions.AstroidBuildingException: Unable to load module tests/single_function.se (No module named tests/single_function.se) I then tried something like ast_se = ast.parse(code) module_se = TreeRebuilder(AstroidManager()).visit_module(ast_se, "blah", "blah", "blah") Which gets me a module, but I couldn't seem to pass it to MyNodeVisitor.visit(module_se) or ast.dump(module_se) (not surprising as it's not an AST) So my question is, how do I build an AST with Astroid from a stand-alone file, walk the ast in a fashion similar to NodeVisitor, and if possible query types from the extended AST nodes? Thanks, Jarrad
Hi Jarrad, On Thu, Apr 23, 2015 at 7:43 PM, Jarrad Hope <me@jarradhope.com> wrote:
Hello
I am currently using the Python ast package with ast.NodeVisitor to generate code for another VM. I found Astroid during my search for a type inference solution.
The documentation is abit sparse for me, and I was hoping someone could help me with extending the AST with Astroid's.
It can definitely be improved. If you find something that can be better explained, don't hesitate to open a new issue.
At first I tried AstroidManager().ast_from_file(f)
but I got astroid.exceptions.AstroidBuildingException: Unable to load module tests/single_function.se (No module named tests/single_function.se)
Most likely due to the weird extension.
I then tried something like ast_se = ast.parse(code) module_se = TreeRebuilder(AstroidManager()).visit_module(ast_se, "blah", "blah", "blah")
Which gets me a module, but I couldn't seem to pass it to MyNodeVisitor.visit(module_se)
or ast.dump(module_se) (not surprising as it's not an AST)
Indeed. For obtaining the string representation, just use node.as_string(). But do take in account the fact that what astroid returns when doing .as_string() might not be the actual code you passed it. That's a result of using ast.parse for parsing the source code, ast.dump(ast.parse(X)) isn't always X.
So my question is, how do I build an AST with Astroid from a stand-alone file, walk the ast in a fashion similar to NodeVisitor, and if possible query types from the extended AST nodes?
Actually we seems to lack a generic NodeVisitor implementation. We have something in astroid.utils.ASTWalker, but it needs some polishing before considering it. Here's what you can do until then: from astroid.builder import AstroidBuilder from astroid.utils import ASTWalker builder = AstroidBuilder() module = builder.file_build("a.py") class Walker(object): def visit_getattr(self, node): print("getattr", node) def visit_module(self, node): print("module", node) walker = ASTWalker(Walker()) walker.walk(module)
Thanks for the timely reply Claudiu Hmm, I tried the example you provided, it returns AttributeError: 'Walker' object has no attribute 'set_context' I tried finding references to set_context but couldn't find any, i added the following to Walker def set_context(self, node, child_node): pass which let me execute, but unsure if that is going to mess with anything? set_context sounds kind of important :) On Fri, Apr 24, 2015 at 5:21 AM, Claudiu Popa <pcmanticore@gmail.com> wrote:
Hi Jarrad,
On Thu, Apr 23, 2015 at 7:43 PM, Jarrad Hope <me@jarradhope.com> wrote:
Hello
I am currently using the Python ast package with ast.NodeVisitor to generate code for another VM. I found Astroid during my search for a type inference solution.
The documentation is abit sparse for me, and I was hoping someone could help me with extending the AST with Astroid's.
It can definitely be improved. If you find something that can be better explained, don't hesitate to open a new issue.
At first I tried AstroidManager().ast_from_file(f)
but I got astroid.exceptions.AstroidBuildingException: Unable to load module tests/single_function.se (No module named tests/single_function.se)
Most likely due to the weird extension.
I then tried something like ast_se = ast.parse(code) module_se = TreeRebuilder(AstroidManager()).visit_module(ast_se, "blah", "blah", "blah")
Which gets me a module, but I couldn't seem to pass it to MyNodeVisitor.visit(module_se)
or ast.dump(module_se) (not surprising as it's not an AST)
Indeed. For obtaining the string representation, just use node.as_string(). But do take in account the fact that what astroid returns when doing .as_string() might not be the actual code you passed it. That's a result of using ast.parse for parsing the source code, ast.dump(ast.parse(X)) isn't always X.
So my question is, how do I build an AST with Astroid from a stand-alone file, walk the ast in a fashion similar to NodeVisitor, and if possible query types from the extended AST nodes?
Actually we seems to lack a generic NodeVisitor implementation. We have something in astroid.utils.ASTWalker, but it needs some polishing before considering it. Here's what you can do until then:
from astroid.builder import AstroidBuilder from astroid.utils import ASTWalker
builder = AstroidBuilder() module = builder.file_build("a.py")
class Walker(object):
def visit_getattr(self, node): print("getattr", node)
def visit_module(self, node): print("module", node)
walker = ASTWalker(Walker()) walker.walk(module)
apologies for double email, I was looking into inference and it looks like theres some context required for inference? specifically function argument types? I tried next(node.infer()) and iterating through the infer generator but all i can seem to muster is a "YES/_Yes" object I looked in source and unit tests but it's not clear what YES means I see test_infer_arguments, which seems to test inference of function arguments based on their calls, it it possible to infer arguments based on their interaction with locals? for example def double(x): return(x * 2) I'd like to be able to walk the double function arguments and infer x is an int based on it's interaction with Const(int) On Fri, Apr 24, 2015 at 8:38 AM, Jarrad Hope <me@jarradhope.com> wrote:
Thanks for the timely reply Claudiu
Hmm, I tried the example you provided, it returns AttributeError: 'Walker' object has no attribute 'set_context'
I tried finding references to set_context but couldn't find any,
i added the following to Walker def set_context(self, node, child_node): pass
which let me execute, but unsure if that is going to mess with anything? set_context sounds kind of important :)
On Fri, Apr 24, 2015 at 5:21 AM, Claudiu Popa <pcmanticore@gmail.com> wrote:
Hi Jarrad,
On Thu, Apr 23, 2015 at 7:43 PM, Jarrad Hope <me@jarradhope.com> wrote:
Hello
I am currently using the Python ast package with ast.NodeVisitor to generate code for another VM. I found Astroid during my search for a type inference solution.
The documentation is abit sparse for me, and I was hoping someone could help me with extending the AST with Astroid's.
It can definitely be improved. If you find something that can be better explained, don't hesitate to open a new issue.
At first I tried AstroidManager().ast_from_file(f)
but I got astroid.exceptions.AstroidBuildingException: Unable to load module tests/single_function.se (No module named tests/single_function.se)
Most likely due to the weird extension.
I then tried something like ast_se = ast.parse(code) module_se = TreeRebuilder(AstroidManager()).visit_module(ast_se, "blah", "blah", "blah")
Which gets me a module, but I couldn't seem to pass it to MyNodeVisitor.visit(module_se)
or ast.dump(module_se) (not surprising as it's not an AST)
Indeed. For obtaining the string representation, just use node.as_string(). But do take in account the fact that what astroid returns when doing .as_string() might not be the actual code you passed it. That's a result of using ast.parse for parsing the source code, ast.dump(ast.parse(X)) isn't always X.
So my question is, how do I build an AST with Astroid from a stand-alone file, walk the ast in a fashion similar to NodeVisitor, and if possible query types from the extended AST nodes?
Actually we seems to lack a generic NodeVisitor implementation. We have something in astroid.utils.ASTWalker, but it needs some polishing before considering it. Here's what you can do until then:
from astroid.builder import AstroidBuilder from astroid.utils import ASTWalker
builder = AstroidBuilder() module = builder.file_build("a.py")
class Walker(object):
def visit_getattr(self, node): print("getattr", node)
def visit_module(self, node): print("module", node)
walker = ASTWalker(Walker()) walker.walk(module)
On Fri, Apr 24, 2015 at 5:52 AM, Jarrad Hope <me@jarradhope.com> wrote:
apologies for double email,
I was looking into inference and it looks like theres some context required for inference? specifically function argument types?
The context is also used for optimization, because it has a cache of inferred objects. next(node.infer(context=InferenceContext()) should be enough for start.
I tried next(node.infer()) and iterating through the infer generator but all i can seem to muster is a "YES/_Yes" object I looked in source and unit tests but it's not clear what YES means
YES node represents something that wasn't inferrable at a given time. To explain better through an example. Let's say we have a module, called missing, which doesn't exist at all anywhere. Trying to infer the x from this code will lead to an YES, meaning that astroid knows something is there, but can't know what. from missing import Missing x = Missing()
I see test_infer_arguments, which seems to test inference of function arguments based on their calls, it it possible to infer arguments based on their interaction with locals?
for example def double(x): return(x * 2)
What you need here is a call context (see astroid.bases.CallContext). All by itself, that x is nothing more than a YES node, but if you provide a call context, than you can reach something more useful. Here's an example of how the inference is actually getting to a result: from astroid.builder import AstroidBuilder b = AstroidBuilder() node = b.string_build(''' def test(x): return x*2 f = test(3) ''') f = node['f'] result = next(f.infer()) print(result) # Const print(result.value) # it finds out that's actually 6
I'd like to be able to walk the double function arguments and infer x is an int based on it's interaction with Const(int)
* Jarrad Hope <me@jarradhope.com> [2015-04-24 09:52:20 +0700]:
I see test_infer_arguments, which seems to test inference of function arguments based on their calls, it it possible to infer arguments based on their interaction with locals?
for example def double(x): return(x * 2)
I'd like to be able to walk the double function arguments and infer x is an int based on it's interaction with Const(int)
x could as well be a float. Or a string. Or anything with __mul__ implemented: (python3) >>> class Foo: ... def __mul__(self, other): ... return 'x' ... >>> def double(x): ... return x * 2 ... >>> f = Foo() >>> d Florian -- http://www.the-compiler.org | me@the-compiler.org (Mail/XMPP) GPG: 916E B0C8 FD55 A072 | http://the-compiler.org/pubkey.asc I love long mails! | http://email.is-not-s.ms/
On Fri, Apr 24, 2015 at 4:38 AM, Jarrad Hope <me@jarradhope.com> wrote:
Thanks for the timely reply Claudiu
No problem. :-)
Hmm, I tried the example you provided, it returns AttributeError: 'Walker' object has no attribute 'set_context'
I tried finding references to set_context but couldn't find any,
i added the following to Walker def set_context(self, node, child_node): pass
which let me execute, but unsure if that is going to mess with anything? set_context sounds kind of important :)
Yeah, forgot about that. That particular line seems to be an old artifact which wasn't removed after a cleanup. Removing it could be a first start for contributing to astroid, btw. ;-)
participants (3)
-
Claudiu Popa
-
Florian Bruhin
-
Jarrad Hope