code: def parse_function_call(expression):
      
      class Walker(ast.NodeVisitor):
          "ast NodeVisition helper class"
          def __init__(self):
              self.results = {'func': None, 'args': [], 'kwargs': {}}
  
          def resolveName(self, node):
              if isinstance(node, ast.Name):
                  self.results['func'] += node.id
              elif isinstance(node, ast.Attribute):
                  self.resolveName(node.value)
                  self.results['func'] += "." + node.attr
  
          def visit_Call(self, node):
              "Visit the first call function"
              if self.results['func'] is not None:
                  return
              self.results['func'] = ""
              self.resolveName(node.func)
              self.results['args'] = [unparse(arg).strip() for arg in node.args]
              self.results['kwargs'] = {kw.arg:unparse(kw.value).strip().strip('\'"') for kw in node.keywords}
  
      walker = Walker()
      walker.visit(ast.parse(expression))
      return walker.results
docs: Parse an expression looking for a function call
      return a dictionary with function name, args and kwargs
      e.g:
      {
          'func': 'display',
          'args': ['df'],
          'kwargs': {
              'aggregation': "'SUM'",
              'nostore_cw': "'1098'",
              'rowCount': "'500'"
          }
      }