google/pasta

Failed to recognize comma on exec function on python2.7

williamjamir opened this issue · 7 comments

Hi,

The parser does not recognize the comma on exec function with python2.7

I did try to create a PR solving this issue, I was doing a function " in_or_comma() " but I realized that the problem would be deeper than this because the visit_exec is treating the exec as a statement instead of function. Am I right?

Here it's a small reproducible example of the error:

File:
exec('x = 10' , {} )

Script:

import pasta
from pasta.augment import rename

path = r'test.py'

with open(path) as file:
        tree = pasta.parse(file.read())

Error:

pasta.base.annotate.AnnotationError: Expected 'in' but found ','
line 1: exec ('x = 10', {})

cc @nicoddemus

Hmm. So the parsed AST from this is:
"Module(body=[Exec(body=Tuple(elts=[Str(s='x = 10'), Dict(keys=[], values=[])], ctx=Load()), globals=None, locals=None)])"

I can't reproduce it on python 2.7.6:

import pasta
t = pasta.parse("exec('x = 10' , {} )")

It shouldn't be expecting "in" unless the ast parses out something for globals. What's your python version? Can you provide the output of:

import ast
ast.dump(ast.parse("exec('x = 10' , {} )"))

I'm using Python 2.7.14

Below you can check the output requested

$ python
Python 2.7.14 | packaged by conda-forge | (default, Dec 25 2017, 01:16:05) 
[GCC 4.8.2 20140120 (Red Hat 4.8.2-15)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import ast
>>> ast.dump(ast.parse("exec('x = 10' , {} )"))
"Module(body=[Exec(body=Str(s='x = 10'), globals=Dict(keys=[], values=[]), locals=None)])"

Okay, that explains it anyway :)

Looks like some change in the parser, so I'll have to account for both. Thanks for reporting it!

Just out of curiosity (I know it will not interfere with this problem), this different behavior occurred in the transition from Python 2.7.8 to 2.7.9

Checking the changelog I found this:

  • Issue #21591: Correctly handle qualified exec statements in tuple form by moving compatibility layer from run-time to AST transformation.

It seems I was too hasty.

Executing the code available on the master I found this issue with exec too.

Executing against a single line with exec it's ok:
exec('cmd', {})

But when I added something after the exec, the parse breaks =/

exec('cmd', {})
print()

Error:

pasta.base.annotate.AnnotationError: Expected 'print' but found ')'
line 1: exec('cmd', {})

Full Stack

Traceback (most recent call last):                                                        
  File "script.py", line 6, in <module>                                                       
    tree = pasta.parse(file.read())                                                       
  File "w:\william\repo_pasta\pasta\__init__.py", line 25, in parse                       
    annotator.visit(t)                                                                    
  File "w:\william\repo_pasta\pasta\base\annotate.py", line 1048, in visit                
    super(AstAnnotator, self).visit(node)                                                 
  File "w:\william\repo_pasta\pasta\base\annotate.py", line 115, in visit                 
    super(BaseVisitor, self).visit(node)                                                  
  File "W:\alfasim\envs\test_pasta\lib\ast.py", line 241, in visit                        
    return visitor(node)                                                                  
  File "w:\william\repo_pasta\pasta\base\annotate.py", line 79, in wrapped                
    f(self, node, *args, **kwargs)                                                        
  File "w:\william\repo_pasta\pasta\base\annotate.py", line 168, in visit_Module          
    self.generic_visit(node)                                                              
  File "W:\alfasim\envs\test_pasta\lib\ast.py", line 249, in generic_visit                
    self.visit(item)                                                                      
  File "w:\william\repo_pasta\pasta\base\annotate.py", line 1048, in visit                
    super(AstAnnotator, self).visit(node)                                                 
  File "w:\william\repo_pasta\pasta\base\annotate.py", line 115, in visit                 
    super(BaseVisitor, self).visit(node)                                                  
  File "W:\alfasim\envs\test_pasta\lib\ast.py", line 241, in visit                        
    return visitor(node)                                                                  
  File "w:\william\repo_pasta\pasta\base\annotate.py", line 43, in wrapped                
    f(self, node, *args, **kwargs)                                                        
  File "w:\william\repo_pasta\pasta\base\annotate.py", line 575, in visit_Print           
    self.attr(node, 'print_open', ['print', self.ws], default='print ')                   
  File "w:\william\repo_pasta\pasta\base\annotate.py", line 1173, in attr                 
    attr_parts.append(self.token(attr_val))                                               
  File "w:\william\repo_pasta\pasta\base\annotate.py", line 1106, in token                
    token_val, token.src, token.start[0], token.line))                                    
pasta.base.annotate.AnnotationError: Expected 'print' but found ')'                       
line 1: exec('cmd', {})    

Yes, I see the problem. I'll need a more generic solution for this, it might also affect a few other places.

Generally, there needs to be support for when multiple children of a node can be parenthesized. Thanks for following up on it. I'll start working on this when I get a chance.