Search code examples
pythonparsingpython-2.7pyparsing

Pyparsing setParseAction method in python 2.7 throws exceptions


This is a general problem with pyparsing and python 2.7 (in 3 it works just fine). The general structure is this:

class SomeParser(object):

    def some_action(self, string, loc, tok):
         print("action")

    def gramma(self):
          ...pyparsing gramma for some 

             language....
         some_rule = (token + token2).setParseAction(self.some_action)
         return some_rule

     def parse(self, string):
         self.gramma().parseString(string)
         return True

In python3 pyparsing works just fine, in 2.7 however I get

Parsing error : some_action() takes exactly 4 arguments (1 given)

My question is how to make it work in both versions?

EDIT: After some test I found that it is general problem, not only with class methods.


Solution

  • I think I found a problem (with a help of a friend), which is in pyparsing 1.5.6 and its _trim_arity function that tries to guess the number of arguments that func in setParseAction(func) is accepting. I changed it from:

    if not _PY3K:                                                                                                                                                               
        def _trim_arity(func, maxargs=2):                                                                                                                                                 
            limit = [0]                                                                                                                                                                   
            def wrapper(*args):                                                                                                                                                           
                while 1:                                                                                                                                                                  
                    try:                                                                                                                                                                  
                        return func(*args[limit[0]:])                                                                                                                                     
                    except TypeError:                                                                                                                                                     
                        if limit[0] <= maxargs:                                                                                                                                           
                            limit[0] += 1                                                                                                                                                 
                            continue                                                                                                                                                      
                        raise                                                                                                                                                             
            return wrapper                                                                                                                                                                
        else:                                                                                                                                                                                 
            def _trim_arity(func, maxargs=2):                                                                                                                                                 
                limit = maxargs                                                                                                                                                             
                def wrapper(*args):                                                                                                                                                                                                                                                                                                             
                    #~ nonlocal limit                                                                                                                                                         
                    while 1:                                                                                                                                                                  
                        try:                                                                                                                                                                  
                            return func(*args[limit:])                                                                                                                                        
                        except TypeError:                                                                                                                                                     
                            if limit:                                                                                                                                                         
                                limit -= 1                                                                                                                                                    
                                continue                                                                                                                                                      
                            raise                                                                                                                                                             
                return wrapper   
    

    to:

    if not _PY3K and False:                                                                                                                                                               
        def _trim_arity(func, maxargs=2):                                                                                                                                                 
            limit = [0]                                                                                                                                                                   
            def wrapper(*args):                                                                                                                                                           
                while 1:                                                                                                                                                                  
                    try:                                                                                                                                                                  
                        return func(*args[limit[0]:])                                                                                                                                     
                    except TypeError:                                                                                                                                                     
                        if limit[0] <= maxargs:                                                                                                                                           
                            limit[0] += 1                                                                                                                                                 
                            continue                                                                                                                                                      
                        raise                                                                                                                                                             
            return wrapper                                                                                                                                                                
        else:                                                                                                                                                                                 
            def _trim_arity(func, maxargs=2):                                                                                                                                                 
                # limit = maxargs                                                                                                                                                             
                def wrapper(*args):                                                                                                                                                           
                    limit = maxargs                                                                                                                                                           
                    #~ nonlocal limit                                                                                                                                                         
                    while 1:                                                                                                                                                                  
                        try:                                                                                                                                                                  
                            return func(*args[limit:])                                                                                                                                        
                        except TypeError:                                                                                                                                                     
                            if limit:                                                                                                                                                         
                                limit -= 1                                                                                                                                                    
                                continue                                                                                                                                                      
                            raise                                                                                                                                                             
                return wrapper   
    

    Not very elegant but I can see that in the trunk version on pyparsing it is fixed already.