This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

classification
Title: Unable to get the else while parsing through AST module
Type: enhancement Stage: resolved
Components: Parser Versions: Python 3.7
process
Status: closed Resolution: not a bug
Dependencies: Superseder:
Assigned To: Nosy List: bikrammehra97, eric.smith, lys.nikolaou
Priority: normal Keywords:

Created on 2021-05-19 09:49 by bikrammehra97, last changed 2022-04-11 14:59 by admin. This issue is now closed.

Messages (6)
msg393941 - (view) Author: Bikram Singh Mehra (bikrammehra97) Date: 2021-05-19 09:49
Hi Team,

I was parsing python file using AST module but ran into a situation where the else statement is not found in the parsed data.

---------------------
Module used is: ast
---------------------

In the parsed data I can see "if" followed by "elif" but the "else" part I am not able to see.

Sample code used:
---------------------
sample_data = """
if num > 0:
    print("Positive number")
elif num == 0:
    print("Zero")
else:
    print("Negative number")
"""
---------------------

tree = ast.parse(sample_data )

The above code provide me below data in ast.dump(tree)

Module(body=[If(test=Compare(left=Name(id='num', ctx=Load()), ops=[Gt()], comparators=[Constant(value=0, kind=None)]), body=[Expr(value=Call(func=Name(id='print', ctx=Load()), args=[Constant(value='Positive number', kind=None)], keywords=[]))], orelse=[If(test=Compare(left=Name(id='num', ctx=Load()), ops=[Eq()], comparators=[Constant(value=0, kind=None)]), body=[Expr(value=Call(func=Name(id='print', ctx=Load()), args=[Constant(value='Zero', kind=None)], keywords=[]))], orelse=[Expr(value=Call(func=Name(id='print', ctx=Load()), args=[Constant(value='Negative number', kind=None)], keywords=[]))])])], type_ignores=[])

While I was traversing through this tree I can't see else in the structure because it is subpart of orelse i.e. inside elif part.


Doc referred is : https://docs.python.org/3/library/ast.html
 

Thanks and Best Regards,
Bikram
msg393947 - (view) Author: Eric V. Smith (eric.smith) * (Python committer) Date: 2021-05-19 11:31
Formatting the result, I get:
Module(body=[If(test=Compare(left=Name(id='num', ctx=Load()),
                             ops=[Gt()],
                             comparators=[Constant(value=0, kind=None)]),
                body=[Expr(value=Call(func=Name(id='print', ctx=Load()),
                                      args=[Constant(value='Positive number',
                                                     kind=None)],
                                      keywords=[]))],
                orelse=[If(test=Compare(left=Name(id='num', ctx=Load()),
                                        ops=[Eq()],
                                        comparators=[Constant(value=0, kind=None)]),
                           body=[Expr(value=Call(func=Name(id='print', ctx=Load()),
                                                 args=[Constant(value='Zero', kind=None)],
                                                 keywords=[]))],
                           orelse=[Expr(value=Call(func=Name(id='print', ctx=Load()),
                                                   args=[Constant(value='Negative number', kind=None)],
                                                   keywords=[]))])])],
       type_ignores=[])

You'll have to extract the "else" part by walking the tree yourself.

> I was parsing python file using AST module but ran into a situation where the else statement is not found in the parsed data.

It is in the parsed data, though. Just not directly in the "If" node.
msg393949 - (view) Author: Bikram Singh Mehra (bikrammehra97) Date: 2021-05-19 12:00
Hi Eric,

Thanks for the quick response here,

I have gone through your suggestion but following that I am able to print the else node data i.e. "print("Negative number")" but unable to get the lineno of that else child node.

Could you please confirm if there is a way in AST where I can get the lineno of the else child node.

Thanks and Best Regards,
Bikram
msg393950 - (view) Author: Eric V. Smith (eric.smith) * (Python committer) Date: 2021-05-19 12:14
It's in the AST. 

>>> tree.body[0].orelse[0].orelse[0].lineno
7

To see it with dump, use: ast.dump(tree, include_attributes=True)

Which, after some reformatting, gives:

Module(body=[If(test=Compare(left=Name(id='num', ctx=Load(), lineno=2, col_offset=3, end_lineno=2, end_col_offset=6),
                             ops=[Gt()], comparators=[Constant(value=0, kind=None, lineno=2, col_offset=9, end_lineno=2, end_col_offset=10)],
                             lineno=2, col_offset=3, end_lineno=2, end_col_offset=10),
                body=[Expr(value=Call(func=Name(id='print', ctx=Load(), lineno=3, col_offset=4, end_lineno=3, end_col_offset=9),
                                      args=[Constant(value='Positive number', kind=None, lineno=3, col_offset=10, end_lineno=3, end_col_offset=27)],
                                      keywords=[], lineno=3, col_offset=4, end_lineno=3, end_col_offset=28),
                           lineno=3, col_offset=4, end_lineno=3, end_col_offset=28)],
                orelse=[If(test=Compare(left=Name(id='num', ctx=Load(), lineno=4, col_offset=5, end_lineno=4, end_col_offset=8),
                                        ops=[Eq()],
                                        comparators=[Constant(value=0, kind=None, lineno=4, col_offset=12, end_lineno=4, end_col_offset=13)], lineno=4, col_offset=5, end_lineno=4, end_col_offset=13),
                           body=[Expr(value=Call(func=Name(id='print', ctx=Load(), lineno=5, col_offset=4, end_lineno=5, end_col_offset=9),
                                                 args=[Constant(value='Zero', kind=None, lineno=5, col_offset=10, end_lineno=5, end_col_offset=16)],
                                                 keywords=[], lineno=5, col_offset=4, end_lineno=5, end_col_offset=17),
                                      lineno=5, col_offset=4, end_lineno=5, end_col_offset=17)],
                           orelse=[Expr(value=Call(func=Name(id='print', ctx=Load(), lineno=7, col_offset=4, end_lineno=7, end_col_offset=9),
                                                   args=[Constant(value='Negative number', kind=None, lineno=7, col_offset=10, end_lineno=7, end_col_offset=27)],
                                                   keywords=[], lineno=7, col_offset=4, end_lineno=7, end_col_offset=28),
                                        lineno=7, col_offset=4, end_lineno=7, end_col_offset=28)], lineno=4, col_offset=0, end_lineno=7, end_col_offset=28)],
                lineno=2, col_offset=0, end_lineno=7, end_col_offset=28)], type_ignores=[])"

I don't think there's any enhancement to be made here, so I'm going to close this issue.
msg394016 - (view) Author: Bikram Singh Mehra (bikrammehra97) Date: 2021-05-20 11:47
Hi Eric,

I have tried the action plan suggested by you in your last comment, but below are my logs and still I am unable to get lineno for else statement.


----The respective line no for each line are below ----


1 
2 if num > 0:
3     print("Positive number")
4 elif num == 0:
5     print("Zero")
6 else:
7     print("Negative number")



>The re-formatted dump is as below and doesn't have lineno for else statement

Module(body=[If(test=Compare(left=Name(id='num', ctx=Load(), lineno=2, col_offset=3, end_lineno=2, end_col_offset=6), 
							 ops=[Gt()], comparators=[Constant(value=0, kind=None, lineno=2, col_offset=9, end_lineno=2, end_col_offset=10)], lineno=2, col_offset=3, end_lineno=2, end_col_offset=10), 
				 body=[Expr(value=Call(func=Name(id='print', ctx=Load(), lineno=3, col_offset=4, end_lineno=3, end_col_offset=9), 							args=[Constant(value='Positive number', kind=None, lineno=3, col_offset=10, end_lineno=3, 
				 						end_col_offset=27)], 
				 						keywords=[], lineno=3, col_offset=4, end_lineno=3, end_col_offset=28), 
	 						lineno=3, col_offset=4, end_lineno=3, end_col_offset=28)], 
				orelse=[If(test=Compare(left=Name(id='num', ctx=Load(), lineno=4, col_offset=5, end_lineno=4, end_col_offset=8),
										 ops=[Eq()], 
										 comparators=[Constant(value=0, kind=None, lineno=4, col_offset=12, end_lineno=4, 
										 end_col_offset=13)], lineno=4, col_offset=5, end_lineno=4, end_col_offset=13), 
				 		body=[Expr(value=Call(func=Name(id='print', ctx=Load(), lineno=5, col_offset=4, end_lineno=5, end_col_offset=9), 
										 		args=[Constant(value='Zero', kind=None, lineno=5, col_offset=10, end_lineno=5, 
										 		end_col_offset=16)], 
										 		keywords=[], lineno=5, col_offset=4, end_lineno=5, end_col_offset=17), lineno=5, col_offset=4, end_lineno=5, end_col_offset=17)], 
			 			orelse=[Expr(value=Call(func=Name(id='print', ctx=Load(), lineno=7, col_offset=4, end_lineno=7, end_col_offset=9), 
			 									args=[Constant(value='Negative number', kind=None, lineno=7, col_offset=10, end_lineno=7, end_col_offset=27)], 
			 									keywords=[], lineno=7, col_offset=4, end_lineno=7, end_col_offset=28), 
			 									lineno=7, col_offset=4, end_lineno=7, end_col_offset=28)], lineno=4, col_offset=0, end_lineno=7,
			 									end_col_offset=28)], 
						lineno=2, col_offset=0, end_lineno=7, end_col_offset=28)], type_ignores=[])




> If we use tree to get the lineno then its giving as below 
tree.body[0].orelse[0].orelse[0].lineno
7



Here the lineno 7 denotes to the body of else statement not the else lineno.


Could you please help me out where you can show the respective line no of else statement i.e. 6 in above example.

Thanks and Best Regards,
Bikram
msg394018 - (view) Author: Eric V. Smith (eric.smith) * (Python committer) Date: 2021-05-20 12:08
There's no actual code associated with the "else" line, so there's no way to get the line number. dis.dis(sample_data) might give you some insight.

Since this all works as designed, I'm going to close this issue. You might get more help on StackOverflow or similar.
History
Date User Action Args
2022-04-11 14:59:45adminsetgithub: 88343
2021-05-20 12:08:24eric.smithsetstatus: open -> closed
resolution: not a bug
messages: + msg394018
2021-05-20 11:54:28pablogsalsetnosy: - pablogsal
2021-05-20 11:47:43bikrammehra97setstatus: closed -> open
resolution: works for me -> (no value)
messages: + msg394016
2021-05-19 12:14:41eric.smithsetstatus: open -> closed
resolution: works for me
messages: + msg393950

stage: resolved
2021-05-19 12:00:31bikrammehra97setmessages: + msg393949
2021-05-19 11:31:16eric.smithsetnosy: + eric.smith
messages: + msg393947
2021-05-19 09:49:02bikrammehra97create