code: def assert_extension_array_equal(
      left,
      right,
      check_dtype: bool | Literal["equiv"] = True,
      index_values=None,
      check_exact: bool = False,
      rtol: float = 1.0e-5,
      atol: float = 1.0e-8,
      obj: str = "ExtensionArray",
  ) -> None:
      """
      Check that left and right ExtensionArrays are equal.
  
      Parameters
      ----------
      left, right : ExtensionArray
          The two arrays to compare.
      check_dtype : bool, default True
          Whether to check if the ExtensionArray dtypes are identical.
      index_values : numpy.ndarray, default None
          Optional index (shared by both left and right), used in output.
      check_exact : bool, default False
          Whether to compare number exactly.
      rtol : float, default 1e-5
          Relative tolerance. Only used when check_exact is False.
  
          .. versionadded:: 1.1.0
      atol : float, default 1e-8
          Absolute tolerance. Only used when check_exact is False.
  
          .. versionadded:: 1.1.0
      obj : str, default 'ExtensionArray'
          Specify object name being compared, internally used to show appropriate
          assertion message.
  
          .. versionadded:: 2.0.0
  
      Notes
      -----
      Missing values are checked separately from valid values.
      A mask of missing values is computed for each and checked to match.
      The remaining all-valid values are cast to object dtype and checked.
  
      Examples
      --------
      >>> from pandas import testing as tm
      >>> a = pd.Series([1, 2, 3, 4])
      >>> b, c = a.array, a.array
      >>> tm.assert_extension_array_equal(b, c)
      """
      assert isinstance(
          left, ExtensionArray
      ), "left is not an ExtensionArray"
      assert isinstance(
          right, ExtensionArray
      ), "right is not an ExtensionArray"
      if check_dtype:
          assert_attr_equal(
              "dtype", left, right, obj=f"Attributes of {obj}"
          )
  
      if (
          isinstance(left, DatetimeLikeArrayMixin)
          and isinstance(right, DatetimeLikeArrayMixin)
          and type(right) == type(left)
      ):
          # GH 52449
          if not check_dtype and left.dtype.kind in "mM":
              if not isinstance(left.dtype, np.dtype):
                  l_unit = cast(DatetimeTZDtype, left.dtype).unit
              else:
                  l_unit = np.datetime_data(left.dtype)[0]
              if not isinstance(right.dtype, np.dtype):
                  r_unit = cast(DatetimeTZDtype, left.dtype).unit
              else:
                  r_unit = np.datetime_data(right.dtype)[0]
              if (
                  l_unit != r_unit
                  and compare_mismatched_resolutions(
                      left._ndarray, right._ndarray, operator.eq
                  ).all()
              ):
                  return
          # Avoid slow object-dtype comparisons
          # np.asarray for case where we have a np.MaskedArray
          assert_numpy_array_equal(
              np.asarray(left.asi8),
              np.asarray(right.asi8),
              index_values=index_values,
              obj=obj,
          )
          return
  
      left_na = np.asarray(left.isna())
      right_na = np.asarray(right.isna())
      assert_numpy_array_equal(
          left_na,
          right_na,
          obj=f"{obj} NA mask",
          index_values=index_values,
      )
  
      left_valid = left[~left_na].to_numpy(dtype=object)
      right_valid = right[~right_na].to_numpy(dtype=object)
      if check_exact:
          assert_numpy_array_equal(
              left_valid,
              right_valid,
              obj=obj,
              index_values=index_values,
          )
      else:
          _testing.assert_almost_equal(
              left_valid,
              right_valid,
              check_dtype=bool(check_dtype),
              rtol=rtol,
              atol=atol,
              obj=obj,
              index_values=index_values,
          )
  
imports: from __future__ import annotations
  import operator
  from typing import Literal, cast
  import numpy
  from pandas._libs.missing import is_matching_na
  from pandas._libs.sparse import SparseIndex
  import pandas._libs.testing
  from pandas._libs.tslibs.np_datetime import compare_mismatched_resolutions
  from pandas.core.dtypes.common import is_bool, is_categorical_dtype, is_extension_array_dtype, is_integer_dtype, is_interval_dtype, is_number, is_numeric_dtype, needs_i8_conversion
  from pandas.core.dtypes.dtypes import CategoricalDtype, DatetimeTZDtype, PandasDtype
  from pandas.core.dtypes.missing import array_equivalent
  import pandas
  from pandas import Categorical, DataFrame, DatetimeIndex, Index, IntervalIndex, MultiIndex, PeriodIndex, RangeIndex, Series, TimedeltaIndex
  from pandas.core.algorithms import take_nd
  from pandas.core.arrays import DatetimeArray, ExtensionArray, IntervalArray, PeriodArray, TimedeltaArray
  from pandas.core.arrays.datetimelike import DatetimeLikeArrayMixin
  from pandas.core.arrays.string_ import StringDtype
  from pandas.core.indexes.api import safe_sort_index
  from pandas.io.formats.printing import pprint_thing
label_desc: Use image node_id 16 for calling a global function with example usage: assert_extension_array_equal(left, right, check_dtype, index_values, check_exact, rtol, atol, obj) without return types