docs: def save_dictionary(data, filename):
      """Save dictionary in a single file .spydata file"""
      filename = osp.abspath(filename)
      old_cwd = getcwd()
      os.chdir(osp.dirname(filename))
      error_message = None
      skipped_keys = []
      data_copy = {}
  
      try:
          # Copy dictionary before modifying it to fix #6689
          for obj_name, obj_value in data.items():
              # Skip modules, since they can't be pickled, users virtually never
              # would want them to be and so they don't show up in the skip list.
              # Skip callables, since they are only pickled by reference and thus
              # must already be present in the user's environment anyway.
              if not (callable(obj_value) or isinstance(obj_value,
                                                        types.ModuleType)):
                  # If an object cannot be deepcopied, then it cannot be pickled.
                  # Ergo, we skip it and list it later.
                  try:
                      data_copy[obj_name] = copy.deepcopy(obj_value)
                  except Exception:
                      skipped_keys.append(obj_name)
          data = data_copy
          if not data:
              raise RuntimeError('No supported objects to save')
  
          saved_arrays = {}
          if load_array is not None:
              # Saving numpy arrays with np.save
              arr_fname = osp.splitext(filename)[0]
              for name in list(data.keys()):
                  try:
                      if isinstance(data[name],
                                    np.ndarray) and data[name].size > 0:
                          # Save arrays at data root
                          fname = __save_array(data[name], arr_fname,
                                               len(saved_arrays))
                          saved_arrays[(name, None)] = osp.basename(fname)
                          data.pop(name)
                      elif isinstance(data[name], (list, dict)):
                          # Save arrays nested in lists or dictionaries
                          if isinstance(data[name], list):
                              iterator = enumerate(data[name])
                          else:
                              iterator = iter(list(data[name].items()))
                          to_remove = []
                          for index, value in iterator:
                              if isinstance(value,
                                            np.ndarray) and value.size > 0:
                                  fname = __save_array(value, arr_fname,
                                                       len(saved_arrays))
                                  saved_arrays[(name, index)] = (
                                      osp.basename(fname))
                                  to_remove.append(index)
                          for index in sorted(to_remove, reverse=True):
                              data[name].pop(index)
                  except (RuntimeError, pickle.PicklingError, TypeError,
                          AttributeError, IndexError):
                      # If an array can't be saved with numpy for some reason,
                      # leave the object intact and try to save it normally.
                      pass
              if saved_arrays:
                  data['__saved_arrays__'] = saved_arrays
  
          pickle_filename = osp.splitext(filename)[0] + '.pickle'
          # Attempt to pickle everything.
          # If pickling fails, iterate through to eliminate problem objs & retry.
          with open(pickle_filename, 'w+b') as fdesc:
              try:
                  pickle.dump(data, fdesc, protocol=2)
              except (pickle.PicklingError, AttributeError, TypeError,
                      ImportError, IndexError, RuntimeError):
                  data_filtered = {}
                  for obj_name, obj_value in data.items():
                      try:
                          pickle.dumps(obj_value, protocol=2)
                      except Exception:
                          skipped_keys.append(obj_name)
                      else:
                          data_filtered[obj_name] = obj_value
                  if not data_filtered:
                      raise RuntimeError('No supported objects to save')
                  pickle.dump(data_filtered, fdesc, protocol=2)
  
          # Use PAX (POSIX.1-2001) format instead of default GNU.
          # This improves interoperability and UTF-8/long variable name support.
          with tarfile.open(filename, "w", format=tarfile.PAX_FORMAT) as tar:
              for fname in ([pickle_filename]
                            + [fn for fn in list(saved_arrays.values())]):
                  tar.add(osp.basename(fname))
                  os.remove(fname)
      except (RuntimeError, pickle.PicklingError, TypeError) as error:
          error_message = to_text_string(error)
      else:
          if skipped_keys:
              skipped_keys.sort()
              error_message = ('Some objects could not be saved: '
                               + ', '.join(skipped_keys))
      finally:
          os.chdir(old_cwd)
      return error_message