Skip to content
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

Unable to get the else while parsing through AST module #88343

Closed
bikrammehra97 mannequin opened this issue May 19, 2021 · 6 comments
Closed

Unable to get the else while parsing through AST module #88343

bikrammehra97 mannequin opened this issue May 19, 2021 · 6 comments
Labels
3.7 (EOL) end of life interpreter-core (Objects, Python, Grammar, and Parser dirs) type-feature A feature request or enhancement

Comments

@bikrammehra97
Copy link
Mannequin

bikrammehra97 mannequin commented May 19, 2021

BPO 44177
Nosy @ericvsmith, @lysnikolaou

Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.

Show more details

GitHub fields:

assignee = None
closed_at = <Date 2021-05-20.12:08:24.679>
created_at = <Date 2021-05-19.09:49:02.635>
labels = ['interpreter-core', 'invalid', 'type-feature', '3.7']
title = 'Unable to get the else while parsing through AST module'
updated_at = <Date 2021-05-20.12:08:24.678>
user = 'https://bugs.python.org/bikrammehra97'

bugs.python.org fields:

activity = <Date 2021-05-20.12:08:24.678>
actor = 'eric.smith'
assignee = 'none'
closed = True
closed_date = <Date 2021-05-20.12:08:24.679>
closer = 'eric.smith'
components = ['Parser']
creation = <Date 2021-05-19.09:49:02.635>
creator = 'bikrammehra97'
dependencies = []
files = []
hgrepos = []
issue_num = 44177
keywords = []
message_count = 6.0
messages = ['393941', '393947', '393949', '393950', '394016', '394018']
nosy_count = 3.0
nosy_names = ['eric.smith', 'lys.nikolaou', 'bikrammehra97']
pr_nums = []
priority = 'normal'
resolution = 'not a bug'
stage = 'resolved'
status = 'closed'
superseder = None
type = 'enhancement'
url = 'https://bugs.python.org/issue44177'
versions = ['Python 3.7']

@bikrammehra97
Copy link
Mannequin Author

bikrammehra97 mannequin commented May 19, 2021

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

@bikrammehra97 bikrammehra97 mannequin added 3.7 (EOL) end of life interpreter-core (Objects, Python, Grammar, and Parser dirs) type-feature A feature request or enhancement labels May 19, 2021
@ericvsmith
Copy link
Member

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.

@bikrammehra97
Copy link
Mannequin Author

bikrammehra97 mannequin commented May 19, 2021

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

@ericvsmith
Copy link
Member

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.

@bikrammehra97
Copy link
Mannequin Author

bikrammehra97 mannequin commented May 20, 2021

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

@bikrammehra97 bikrammehra97 mannequin reopened this May 20, 2021
@bikrammehra97 bikrammehra97 mannequin reopened this May 20, 2021
@ericvsmith
Copy link
Member

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.

@ezio-melotti ezio-melotti transferred this issue from another repository Apr 10, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
3.7 (EOL) end of life interpreter-core (Objects, Python, Grammar, and Parser dirs) type-feature A feature request or enhancement
Projects
None yet
Development

No branches or pull requests

1 participant