code: def clean_dimensions(data, param_name):
      # called under: fit
  
      if data is None:
          msg = f"{param_name} cannot be None"
          _log.error(msg)
          raise ValueError(msg)
  
      while True:
          if isinstance(data, ma.masked_array):
              # do this before np.ndarray since ma.masked_array is a subclass of np.ndarray
              mask = data.mask
              if mask is not ma.nomask:
                  if mask.any():
                      msg = (
                          f"{param_name} cannot contain missing values"
                      )
                      _log.error(msg)
                      raise ValueError(msg)
              data = data.data
          elif isinstance(data, np.ndarray):
              pass
          elif _pandas_installed and isinstance(data, pd.Series):
              if data.hasnans:
                  # if hasnans is true then there is definetly a real missing value in there and not just a mask
                  msg = f"{param_name} cannot contain missing values"
                  _log.error(msg)
                  raise ValueError(msg)
              # can be a non-numpy datatype, but has enough conformance for us to work on it
              data = data.values
          elif _pandas_installed and isinstance(data, pd.DataFrame):
              if data.shape[1] == 1:
                  data = data.iloc[:, 0]
                  if data.hasnans:
                      # if hasnans is true then there is definetly a real missing value in there and not just a mask
                      msg = (
                          f"{param_name} cannot contain missing values"
                      )
                      _log.error(msg)
                      raise ValueError(msg)
                  # can be a non-numpy datatype, but has enough conformance for us to work on it
                  data = data.values
              else:
                  # can be a non-numpy datatype, but has enough conformance for us to work on it
                  data = data.astype(np.object_, copy=False).values
          elif _scipy_installed and isinstance(
              data, sp.sparse.spmatrix
          ):
              data = data.toarray()
          elif isinstance(data, list) or isinstance(data, tuple):
              data = np.array(data, np.object_)
          elif callable(getattr(data, "__array__", None)):
              data = data.__array__()
          elif isinstance(data, str):
              # we have just 1 item, so re-pack it and return
              ret = np.empty(1, np.object_)
              ret.itemset(0, data)
              return ret
          else:
              try:
                  data = list(data)
              except TypeError:
                  # we have just 1 item, so re-pack it and return
                  ret = np.empty(1, np.object_)
                  ret.itemset(0, data)
                  return ret
              data = np.array(data, np.object_)
  
          data = _remove_extra_dimensions(data)
  
          if data.shape[0] == 0:
              # data.ndim must be 1
              return data
  
          if data.dtype.type is not np.object_:
              if 3 <= data.ndim:
                  msg = f"{param_name} cannot have 3rd dimension"
                  _log.error(msg)
                  raise TypeError(msg)
              if (
                  issubclass(data.dtype.type, np.floating)
                  and np.isnan(data).any()
              ):
                  msg = f"{param_name} cannot contain missing values"
                  _log.error(msg)
                  raise ValueError(msg)
              return data
  
          if data.shape[0] != 1:
              break
  
          data = data[0]
  
      n_second_dim = None
  
      # check the interior items
      idx = 0
      n = len(data)
      while idx < n:
          item = data[idx]
  
          if isinstance(item, str):
              if n_second_dim is not None and n_second_dim != 1:
                  msg = f"{param_name} is not consistent in length for the second dimension"
                  _log.error(msg)
                  raise TypeError(msg)
              n_second_dim = 1
              idx = idx + 1
              continue
  
          # TODO: if we checked item for various types like numpy, and those types were not of type np.object_
          # then we could avoid iterating the list contents below, or if the list contained only list
          # then sometimes we would not have to re-convert data to a list, which we need to do below incase
          # item is an iterator and therefore must modify data[idx] to insert the list we created from the iterator
  
          try:
              item = list(item)
          except TypeError:
              if n_second_dim is not None and n_second_dim != 1:
                  msg = f"{param_name} is not consistent in length for the second dimension"
                  _log.error(msg)
                  raise TypeError(msg)
              n_second_dim = 1
              idx = idx + 1
              continue
  
          if data is not list:
              data = list(data)
  
          n_items = len(item)
          if n_items == 1:
              # keep iterating down into them until they hit a non-1 length
              data[idx] = item[0]
              continue
  
          if n_second_dim is not None and n_second_dim != n_items:
              msg = f"{param_name} is not consistent in length for the second dimension"
              _log.error(msg)
              raise TypeError(msg)
          n_second_dim = n_items
  
          # now check if any of the sub-items are iterable
          sub_idx = 0
          while sub_idx < n_items:
              subitem = item[sub_idx]
  
              if isinstance(subitem, str):
                  sub_idx = sub_idx + 1
                  continue
  
              try:
                  subitem = list(subitem)
              except TypeError:
                  sub_idx = sub_idx + 1
                  continue
  
              if len(subitem) != 1:
                  msg = f"{param_name} cannot have 3rd dimension"
                  _log.error(msg)
                  raise TypeError(msg)
  
              # keep iterating down into them until they hit a non-1 length
              item[sub_idx] = subitem[0]
  
          # if it was an iterable or we dug into any of the items, we need to replace it
          data[idx] = item
          idx = idx + 1
  
      if n_second_dim == 0:
          return np.empty(0, np.object_)
  
      data = np.array(
          data, np.object_, copy=False
      )  # in case it was converted to list
  
      if _pandas_installed:
          # pandas also has the pd.NA value that indicates missing.  If Pandas is available though
          # we can use it's function that checks for pd.NA, np.nan, and None
          if pd.isna(data).any():
              msg = f"{param_name} cannot contain missing values"
              _log.error(msg)
              raise ValueError(msg)
      else:
          # data != data is a check for nan that works even with mixed types, since nan != nan
          if (data == _none_ndarray).any() or (data != data).any():
              msg = f"{param_name} cannot contain missing values"
              _log.error(msg)
              raise ValueError(msg)
  
      return data
  
file_path: interpret/python/interpret-core/interpret/utils/_clean_simple.py
imports: import numpy
  import numpy.ma
  from sklearn.base import is_classifier, is_regressor
  from ._clean_x import preclean_X
  from ._link import link_func
  import logging
label_desc: Use image node_id 2 for calling a global function with example usage: clean_dimensions(data, param_name) and returns: data, np, data, data, ret, ret