code: def assert_attrs_equal(attrs, attrs_exp, tolerance=0):
      """Test that attributes are equal.
  
      Walks dictionary recursively. Numerical attributes are compared with
      the given relative tolerance.
      """
      keys_diff = set(attrs).difference(set(attrs_exp))
      assert not keys_diff, "Different set of keys: {}".format(
          keys_diff
      )
      for key in attrs_exp:
          err_msg = "Attribute {} does not match expectation".format(
              key
          )
          if isinstance(attrs[key], dict):
              assert_attrs_equal(attrs[key], attrs_exp[key], tolerance)
          else:
              try:
                  np.testing.assert_allclose(
                      attrs[key],
                      attrs_exp[key],
                      rtol=tolerance,
                      err_msg=err_msg,
                  )
              except TypeError:
                  assert attrs[key] == attrs_exp[key], err_msg
  
imports: from contextlib import contextmanager
  from datetime import datetime
  from typing import Any
  from unittest import mock
  import dask.array
  import numpy
  from pyresample import create_area_def
  from pyresample.geometry import BaseDefinition, SwathDefinition
  from xarray import DataArray
  from satpy import Scene
  from satpy.composites import GenericCompositor, IncompatibleAreas
  from satpy.dataset import DataID, DataQuery
  from satpy.dataset.dataid import default_id_keys_config, minimal_default_keys_config
  from satpy.modifiers import ModifierBase
  from satpy.readers.file_handlers import BaseFileHandler
label_desc: Use image node_id 12 for calling a global function with example usage: assert_attrs_equal(attrs, attrs_exp, tolerance) without return types