class_docstr: Provides some helper functions to make testing easier.
class_docstr_tok: ["Provides","some","helper","functions","to","make","testing","easier","."]
docstr: Uses `np.allclose()` on number arrays.
  
  :raises: (AssertionError) Using TestCase's self.failureException
docstr_tok: ["Uses","`","np.allclose","(",")","`","on","number","arrays",".",":","raises",":","(","AssertionError",")","Using","TestCase","'s","self.failureException"]
code: def assert_dict_equal(self, d1, d2, msg=None):
      """
      Uses `np.allclose()` on number arrays.
  
      :raises: (AssertionError) Using TestCase's self.failureException
  
      """
      self.assertIsInstance(
          d1, dict, "First argument is not a dictionary"
      )
      self.assertIsInstance(
          d2, dict, "Second argument is not a dictionary"
      )
  
      for node, path in node_generator(d1):
          # first check that this sub-dict is contained in both dicts
          try:
              comp_node = get_by_path(d2, path)
          except (KeyError, IndexError):
              standard_msg = (
                  "Path {} exists in dict 1, but not dict 2.".format(
                      path
                  )
              )
              self.fail(self._formatMessage(msg, standard_msg))
          self.assertIsInstance(
              comp_node,
              dict,
              "Value at path {} is not a dict.".format(path),
          )
  
          # check that each key in the first is contained in the second
          for key, val in node.items():
              if isinstance(val, dict):
                  continue  # this gets tested as its own node
  
              # check that the values at this key are equal
              val_path = path + (key,)
              try:
                  comp_val = comp_node[key]
              except KeyError:
                  standard_msg = "Path {} exists in dict 1, but not dict 2.".format(
                      self._format_path(val_path)
                  )
                  self.fail(self._formatMessage(msg, standard_msg))
  
              if isinstance(val, np.ndarray) or isinstance(
                  comp_val, np.ndarray
              ):
                  if np.array_equal(val, comp_val):
                      continue
              elif val == comp_val:
                  continue
  
              if is_num_list(val) and is_num_list(comp_val):
                  if np.allclose(val, comp_val):
                      continue
  
              standard_msg = (
                  "Value comparison failed at path {}.\n"
                  "{} != {}".format(
                      self._format_path(val_path), val, comp_val
                  )
              )
              self.fail(self._formatMessage(msg, standard_msg))
  
          # finally, check that keys in the second are in the first
          for key in comp_node:
              val_path = path + (key,)
              if key not in node:
                  standard_msg = "Path {} exists in dict 2, but not dict 1.".format(
                      self._format_path(val_path)
                  )
                  self.fail(self._formatMessage(msg, standard_msg))
  
file_path: plotly.py/packages/python/plotly/plotly/tests/test_optional/optional_utils.py
imports: import numpy
  from plotly import optional_imports
  from plotly.tests.utils import is_num_list
  from plotly.utils import get_by_path, node_generator
  import copy
label_desc: Use image node_id 3 for calling the NumpyTestUtilsMixin obj's underlying member method code with example usage: obj.assert_dict_equal(d1, d2, msg) without return types