相关文章推荐
有情有义的大白菜  ·  python ...·  1 月前    · 
完美的馒头  ·  python QTreeWidget ...·  3 周前    · 
失眠的烤红薯  ·  python qt textBrowser ...·  3 周前    · 
帅气的领带  ·  【Pyspark ...·  1 周前    · 
近视的橙子  ·  python ...·  6 天前    · 
从容的生姜  ·  PEP484 Type Hints ...·  1 年前    · 
痴情的帽子  ·  fs.readfilesync is ...·  1 年前    · 
Collectives™ on Stack Overflow

Find centralized, trusted content and collaborate around the technologies you use most.

Learn more about Collectives

Teams

Q&A for work

Connect and share knowledge within a single location that is structured and easy to search.

Learn more about Teams

IndentationError during `ast.parse` and `ast.walk` of a function which is a method inside class

Ask Question

I think I'm aware of the usual causes for IndentationError like described in IndentationError: unindent does not match any outer indentation level for example. This doesn't apply here.

Also, I know about textwrap.dedent but it doesn't feel like it's the right approach here?

If I have a "regular" function, I can do ast.parse and ast.walk like this:

import ast
import inspect
def a():
code = inspect.getsource(a)
nodes = ast.walk(ast.parse(code))
for node in nodes:

However, if the function is a method inside a class like:

class B:
    def c(self):
code = inspect.getsource(B.c)
nodes = ast.walk(ast.parse(code))

I get:

IndentationError: unexpected indent

Which makes sense, I guess, since B.c is indented by one level. So how do I ast.parse and ast.walk here instead?

Possible duplicate of IndentationError: unindent does not match any outer indentation level – ivan_pozdeev Jun 6, 2019 at 14:17 You could parse the entire class and then find the matching function definition inside that. But that function definition may not correspond to the value of B.c at runtime, which may be a good thing or bad thing. – Alex Hall Jun 6, 2019 at 14:43 OK, I retract my previous support for dedent as it doesn't work in all cases. I've actually seen a library that used it and people who used that library ran into the edge case and reported a bug that took a while to figure out. Basically it's easy for B.c to contain some code which is less indented than the def c part. So if you want something that works in all cases you'll need another solution. But you'll also need to explain your use case some more as the solution will depend on that. See my comment above, for example. – Alex Hall Jan 6, 2020 at 13:29

Its because you grabbed the method than tried walking it without undoing the indents. Your class is:

class B:
    def c(self):
code = inspect.getsource(B.c)
nodes = ast.walk(ast.parse(code))

If you print code you see:

    def c(self):

Note: The above code has one indent. You need to un-indent it:

import inspect
import ast
import textwrap
class B:
    def c(self):
code = textwrap.dedent(inspect.getsource(B.c))
nodes = ast.walk(ast.parse(code))
                ast is designed to read valid python code from text. You parsed a subset of valid code then passed it to ast as text, but since you only grabbed part of the code it is no longer valid (bad indenting).
– Error - Syntactical Remorse
                Jun 6, 2019 at 14:32
                I should add that this will work for the problem you have presented, but if you want to make modifications to the AST and compile it into a new function, then the context such as the class will matter and this solution won't be enough.
– Alex Hall
                Jun 6, 2019 at 14:40
        

Thanks for contributing an answer to Stack Overflow!

  • Please be sure to answer the question. Provide details and share your research!

But avoid

  • Asking for help, clarification, or responding to other answers.
  • Making statements based on opinion; back them up with references or personal experience.

To learn more, see our tips on writing great answers.