class_docstr: Abstract test class for testing model chat code.
class_docstr_tok: ["Abstract","test","class","for","testing","model","chat","code","."]
docstr: Check the actual and expected values of the final chat data.
  
  TODO: this is hard to maintain. It'd be better to just delete the non-deterministic keys from actual_value beforehand, inside self._remove_non_deterministic_keys().
docstr_tok: ["Check","the","actual","and","expected","values","of","the","final","chat","data",".","TODO",":","this","is","hard","to","maintain",".","It","'d","be","better","to","just","delete","the","non-deterministic","keys","from","actual_value","beforehand",",","inside","self._remove_non_deterministic_keys","(",")","."]
code: def _check_final_chat_data(
      self, actual_value: Dict[str, Any], expected_value: Dict[str, Any]
  ):
      """
      Check the actual and expected values of the final chat data.
  
      TODO: this is hard to maintain. It'd be better to just delete the non-deterministic keys from actual_value beforehand, inside self._remove_non_deterministic_keys().
      """
      for key_inner, expected_value_inner in expected_value.items():
          if key_inner == "dialog":
              assert len(actual_value[key_inner]) == len(
                  expected_value_inner
              )
              for actual_message, expected_message in zip(
                  actual_value[key_inner], expected_value_inner
              ):
                  clean_actual_message = {
                      k: v
                      for k, v in actual_message.items()
                      if k != "update_id"
                  }
                  clean_expected_message = {
                      k: v
                      for k, v in expected_message.items()
                      if k != "update_id"
                  }
                  self.assertDictEqual(
                      clean_actual_message,
                      clean_expected_message,
                      f"The following dictionaries are different: {clean_actual_message} and {clean_expected_message}",
                  )
          elif key_inner == "task_description":
              for (
                  key_inner2,
                  expected_value_inner2,
              ) in expected_value_inner.items():
                  if key_inner2 == "model_file":
                      pass
                      # The path to the model file depends on the random
                      # tmpdir
                  elif key_inner2 == "model_opt":
                      keys_to_ignore = [
                          "datapath",
                          "dict_file",
                          "model_file",
                          "override",
                          "parlai_home",
                          "starttime",
                      ]
                      # These paths depend on the random tmpdir and the host
                      # machine
                      for (
                          key_inner3,
                          expected_value_inner3,
                      ) in expected_value_inner2.items():
                          if key_inner3 in keys_to_ignore:
                              pass
                          else:
                              self.assertEqual(
                                  actual_value[key_inner][key_inner2][
                                      key_inner3
                                  ],
                                  expected_value_inner3,
                                  f"Error in key {key_inner3}!",
                              )
                  else:
                      self.assertEqual(
                          actual_value[key_inner][key_inner2],
                          expected_value_inner2,
                          f"Error in key {key_inner2}!",
                      )
          else:
              self.assertEqual(
                  actual_value[key_inner],
                  expected_value_inner,
                  f"Error in key {key_inner}!",
              )
  
imports: import base64
  import datetime
  import json
  import os
  import random
  import threading
  import time
  import unittest
  from io import BytesIO
  from typing import Any, Dict, Optional, Tuple
  from PIL import Image
  from parlai.core.message import Message
  from parlai.core.metrics import Metric
  from parlai.core.params import ParlaiParser
  from parlai.core.loader import load_task_module
  from parlai.crowdsourcing.utils.tests import AbstractParlAIChatTest
  from parlai.tasks.blended_skill_talk.agents import ContextGenerator
label_desc: Use image node_id 5 for calling the AbstractModelChatTest obj's underlying member method code with example usage: obj._check_final_chat_data(actual_value, expected_value) without return types