class_docstr: A mixin class that provides probing of arguments that
  are needed by a handler during creation and prediction time
  by running the static analysis on the source code of the handler.
docstr: Probe the source code of the method with name method_name.
  Specifically, trace how the argument `args`, which is a dict is used in the method.
  
  Find all places where a key of the dict is used, and return a list of all keys that are used.
  E.g.,
  args["key1"] -> "key1" is accessed, and it is required
  args.get("key2", "default_value") -> "key2" is accessed, and it is optional (default value is provided)
  
  Return a list of dict
  where each dict looks like
  {
      "name": "key1",
      "required": True
  }
code: def probe_function(self, method_name: str) -> List[Dict]:
      """
      Probe the source code of the method with name method_name.
      Specifically, trace how the argument `args`, which is a dict is used in the method.
  
      Find all places where a key of the dict is used, and return a list of all keys that are used.
      E.g.,
      args["key1"] -> "key1" is accessed, and it is required
      args.get("key2", "default_value") -> "key2" is accessed, and it is optional (default value is provided)
  
      Return a list of dict
      where each dict looks like
      {
          "name": "key1",
          "required": True
      }
      """
      try:
          source_code = self.get_source_code(method_name)
      except Exception as e:
          logger.error(
              f"Failed to get source code of method {method_name} in {self.__class__.__name__}. Reason: {e}"
          )
          return []
  
      # parse the source code
      # fix the indentation
      source_code = textwrap.dedent(source_code)
      # parse the source code
      tree = ast.parse(source_code)
  
      # find all places where a key in args is accessed
      # and if it is accessed using args["key"] or args.get("key", "default_value")
  
      visitor = self.ArgProbeVisitor()
      visitor.visit(tree)
  
      # deduplicate the keys
      # if there two records with the same name but different required status
      # we should keep the one with required == True
      unique_arg_keys = {}
      for r in visitor.arg_keys:
          if r["name"] in unique_arg_keys:
              if r["required"]:
                  unique_arg_keys[r["name"]] = r["required"]
          else:
              unique_arg_keys[r["name"]] = r["required"]
  
      # convert back to list
      visitor.arg_keys = [
          {"name": k, "required": v} for k, v in unique_arg_keys.items()
      ]
  
      # filter out record where name == "using"
      return [r for r in visitor.arg_keys if r["name"] != "using"]
  
imports: import ast
  import inspect
  import textwrap
  from _ast import AnnAssign, AugAssign
  from typing import Any, Dict, List, Optional
  import pandas
  from mindsdb_sql.parser.ast.base import ASTNode
  from mindsdb.utilities import log
  from mindsdb.integrations.libs.response import HandlerResponse, HandlerStatusResponse
label_desc: Use image node_id 1 for calling the ArgProbeMixin obj's underlying member method code with example usage: obj.probe_function(method_name) and returns: unknown, list