docs: def return_func_to_optimize(path, session, base_learner_origin, default_params,
                              metric_to_optimize, invert_metric, integers):
      """Creates the function to be optimized by Bayes Optimization.
  
      The function automatically handles the case of already existing base learners, and if
      no base learner for the hyperparameters exists yet, creates one and updates it in the
      usual way.
  
      Args:
          path (str): Path to Xcessiv notebook
  
          session: Database session passed down
  
          base_learner_origin: BaseLearnerOrigin object
  
          default_params (dict): Dictionary containing default params of estimator
  
          metric_to_optimize (str, unicode): String containing name of metric to optimize
  
          invert_metric (bool): Specifies whether metric should be inverted e.g. losses
  
          integers (set): Set of strings that specify which hyperparameters are integers
  
      Returns:
          func_to_optimize (function): Function to be optimized
      """
      def func_to_optimize(**params):
          base_estimator = base_learner_origin.return_estimator()
          base_estimator.set_params(**default_params)
          # For integer hyperparameters, make sure they are rounded off
          params = dict((key, val) if key not in integers else (key, int(val))
                        for key, val in iteritems(params))
          base_estimator.set_params(**params)
          hyperparameters = functions.make_serializable(base_estimator.get_params())
  
          # Look if base learner already exists
          base_learner = session.query(models.BaseLearner).\
              filter_by(base_learner_origin_id=base_learner_origin.id,
                        hyperparameters=hyperparameters).first()
  
          calculate_only = False
  
          # If base learner exists and has finished, just return its result
          if base_learner and base_learner.job_status == 'finished':
              if invert_metric:
                  return -base_learner.individual_score[metric_to_optimize]
              else:
                  return base_learner.individual_score[metric_to_optimize]
  
          # else if base learner exists but is unfinished, just calculate the result without storing
          elif base_learner and base_learner.job_status != 'finished':
              calculate_only = True
  
          # else if base learner does not exist, create it
          else:
              base_learner = models.BaseLearner(hyperparameters,
                                                'started',
                                                base_learner_origin)
              base_learner.job_id = get_current_job().id
              session.add(base_learner)
              session.commit()
  
          try:
              est = base_learner.return_estimator()
              extraction = session.query(models.Extraction).first()
              X, y = extraction.return_train_dataset()
              return_splits_iterable = functions.import_object_from_string_code(
                  extraction.meta_feature_generation['source'],
                  'return_splits_iterable'
              )
  
              meta_features_list = []
              trues_list = []
              for train_index, test_index in return_splits_iterable(X, y):
                  X_train, X_test = X[train_index], X[test_index]
                  y_train, y_test = y[train_index], y[test_index]
                  est = est.fit(X_train, y_train)
                  meta_features_list.append(
                      getattr(est, base_learner.base_learner_origin.
                              meta_feature_generator)(X_test)
                  )
                  trues_list.append(y_test)
              meta_features = np.concatenate(meta_features_list, axis=0)
              y_true = np.concatenate(trues_list)
  
              for key in base_learner.base_learner_origin.metric_generators:
                  metric_generator = functions.import_object_from_string_code(
                      base_learner.base_learner_origin.metric_generators[key],
                      'metric_generator'
                  )
                  base_learner.individual_score[key] = metric_generator(y_true, meta_features)
  
              # Only do this if you want to save things
              if not calculate_only:
                  meta_features_path = base_learner.meta_features_path(path)
  
                  if not os.path.exists(os.path.dirname(meta_features_path)):
                      os.makedirs(os.path.dirname(meta_features_path))
  
                  np.save(meta_features_path, meta_features, allow_pickle=False)
                  base_learner.job_status = 'finished'
                  base_learner.meta_features_exists = True
                  session.add(base_learner)
                  session.commit()
  
              if invert_metric:
                  return -base_learner.individual_score[metric_to_optimize]
              else:
                  return base_learner.individual_score[metric_to_optimize]
  
          except:
              session.rollback()
              base_learner.job_status = 'errored'
              base_learner.description['error_type'] = repr(sys.exc_info()[0])
              base_learner.description['error_value'] = repr(sys.exc_info()[1])
              base_learner.description['error_traceback'] = \
                  traceback.format_exception(*sys.exc_info())
              session.add(base_learner)
              session.commit()
              raise
      return func_to_optimize