docstr: Process nodes from passed tree to extract filters.
  
  Collects all assignments in the tree.
  Collects all function calls in the tree.
  Walk over the tree and handle each comparison node.
  For each comparison node, defined what `df` is this node related to.
  Parse constants values from the comparison node.
  Add to the result dict.
  
  Args:
      tree (str): A snippet of code to be parsed.
  
  Returns:
      dict: The `defaultdict(list)` instance containing all filters
          parsed from the passed instructions tree. The dictionary has
          the following structure:
          {
              "<df_number>": [
                  ("<left_operand>", "<operator>", "<right_operand>")
              ]
          }
docstr_tok: ["Process","nodes","from","passed","tree","to","extract","filters",".","Collects","all","assignments","in","the","tree",".","Collects","all","function","calls","in","the","tree",".","Walk","over","the","tree","and","handle","each","comparison","node",".","For","each","comparison","node",",","defined","what","`","df","`","is","this","node","related","to",".","Parse","constants","values","from","the","comparison","node",".","Add","to","the","result","dict",".","Args",":","tree","(","str",")",":","A","snippet","of","code","to","be","parsed",".","Returns",":","dict",":","The","`","defaultdict","(","list",")","`","instance","containing","all","filters","parsed","from","the","passed","instructions","tree",".","The","dictionary","has","the","following","structure",":","{","``","<","df_number",">","''",":","[","(","``","<","left_operand",">","''",",","``","<","operator",">","''",",","``","<","right_operand",">","''",")","]","}"]
code: def _extract_comparisons(self, tree: ast.Module) -> dict[str, list]:
      """
      Process nodes from passed tree to extract filters.
  
      Collects all assignments in the tree.
      Collects all function calls in the tree.
      Walk over the tree and handle each comparison node.
      For each comparison node, defined what `df` is this node related to.
      Parse constants values from the comparison node.
      Add to the result dict.
  
      Args:
          tree (str): A snippet of code to be parsed.
  
      Returns:
          dict: The `defaultdict(list)` instance containing all filters
              parsed from the passed instructions tree. The dictionary has
              the following structure:
              {
                  "<df_number>": [
                      ("<left_operand>", "<operator>", "<right_operand>")
                  ]
              }
      """
      comparisons = defaultdict(list)
      current_df = "dfs[0]"
  
      visitor = AssignmentVisitor()
      visitor.visit(tree)
      assignments = visitor.assignment_nodes
  
      call_visitor = CallVisitor()
      call_visitor.visit(tree)
      calls = call_visitor.call_nodes
  
      for node in ast.walk(tree):
          if isinstance(node, ast.Compare):
              is_call_on_left = isinstance(node.left, ast.Call)
              is_polars = False
              is_calling_col = False
              try:
                  is_polars = node.left.func.value.id in (
                      "pl",
                      "polars",
                  )
                  is_calling_col = node.left.func.attr == "col"
              except AttributeError:
                  pass
  
              if is_call_on_left and is_polars and is_calling_col:
                  df_name = self._get_nearest_func_call(
                      node.lineno, calls, "filter"
                  ).func.value.id
                  current_df = self._get_df_id_by_nearest_assignment(
                      node.lineno, assignments, df_name
                  )
                  left_str = node.left.args[0].value
  
                  for op, right in zip(node.ops, node.comparators):
                      op_str = self._ast_comparator_map.get(
                          type(op), "Unknown"
                      )
                      right_str = right.value
  
                      comparisons[current_df].append(
                          (left_str, op_str, right_str)
                      )
              elif isinstance(node.left, ast.Subscript):
                  name, *slices = self._tokenize_operand(node.left)
                  current_df = (
                      self._get_df_id_by_nearest_assignment(
                          node.lineno, assignments, name
                      )
                      or current_df
                  )
                  left_str = slices[-1] if slices else name
  
                  for op, right in zip(node.ops, node.comparators):
                      op_str = self._ast_comparator_map.get(
                          type(op), "Unknown"
                      )
                      name, *slices = self._tokenize_operand(right)
                      right_str = slices[-1] if slices else name
  
                      comparisons[current_df].append(
                          (left_str, op_str, right_str)
                      )
      return comparisons
  
imports: import re
  import ast
  import uuid
  from collections import defaultdict
  import astor
  import pandas
  from pandasai.helpers.path import find_project_root
  from pandasai.helpers.skills_manager import SkillsManager
  from pandasai.helpers.sql import extract_table_names
  from .node_visitors import AssignmentVisitor, CallVisitor
  from .save_chart import add_save_chart
  from .optional import import_dependency
  from ..exceptions import BadImportError, MaliciousQueryError, NoResultFoundError, InvalidConfigError
  from ..constants import WHITELISTED_BUILTINS, WHITELISTED_LIBRARIES
  from typing import Union, List, Generator, Any
  from ..helpers.logger import Logger
  from ..schemas.df_config import Config
  import logging
  import traceback
label_desc: Use image node_id 19 for calling the CodeManager obj's underlying member method code with example usage: obj._extract_comparisons(tree) and returns: comparisons