code: def test_train_end_date_gap_regressors():
      """Tests the parameters `train_end_date` and `periods_between_train_test`
      on a dataset with regressors.
      """
      data = generate_df_with_reg_for_tests(
          freq="D",
          periods=60,
          train_start_date=datetime.datetime(2018, 1, 1),
          remove_extra_cols=True,
      )
      regressor_cols = ["regressor1", "regressor2", "regressor_categ"]
      keep_cols = [TIME_COL, VALUE_COL] + regressor_cols
      df = data["df"][keep_cols].copy()
      # Setting NaN values at the end, omitting `regressor_categ` as
      # we do not have a null transformer for categorical variables yet
      df.loc[df.tail(2).index, "regressor1"] = np.nan
      df.loc[df.tail(5).index, "regressor2"] = np.nan
      available_forecast_horizon = 8
      df.loc[
          df.tail(available_forecast_horizon).index, VALUE_COL
      ] = np.nan
  
      # Default `train_end_date`, default `regressor_cols`
      with pytest.warns(UserWarning) as record:
          result = forecast_pipeline(
              df=df,
              train_end_date=None,
              regressor_cols=None,
              pipeline=get_dummy_pipeline(include_preprocessing=True),
              forecast_horizon=10,
          )
          ts = result.timeseries
          assert (
              f"{ts.original_value_col} column of the provided time series contains "
              f"null values at the end, or the input `train_end_date` is beyond the last timestamp available. "
              f"Setting `train_end_date` to the last timestamp with a non-null value "
              f"({ts.train_end_date})." in record[0].message.args[0]
          )
          assert ts.train_end_date == datetime.datetime(2018, 2, 21)
          assert ts.last_date_for_reg is None
          assert result.forecast.test_evaluation is None
  
      # `train_end_date` later than last date in df, all available `regressor_cols`
      with pytest.warns(UserWarning) as record:
          train_end_date = datetime.datetime(2018, 3, 10)
          result = forecast_pipeline(
              df,
              train_end_date=train_end_date,
              regressor_cols=regressor_cols,
              pipeline=get_dummy_pipeline(
                  include_preprocessing=True,
                  regressor_cols=regressor_cols,
              ),
              forecast_horizon=5,
          )
          ts = result.timeseries
          assert (
              f"{VALUE_COL} column of the provided time series contains "
              f"null values at the end, or the input `train_end_date` is beyond the last timestamp available. "
              f"Setting `train_end_date` to the last timestamp with a non-null value "
              f"({datetime.datetime(2018, 2, 21)})."
              in record[0].message.args[0]
          )
          assert ts.train_end_date == datetime.datetime(2018, 2, 21)
          assert ts.last_date_for_reg == datetime.datetime(2018, 3, 1)
          forecast = result.forecast
          assert forecast.df[TIME_COL].max() == datetime.datetime(
              2018, 2, 26
          )
          assert forecast.test_evaluation is None
  
      # `train_end_date` in between last date in df and last date before null;
      # user passes no `regressor_cols`
      with pytest.warns(UserWarning) as record:
          train_end_date = datetime.datetime(2018, 2, 26)
          result = forecast_pipeline(
              df=df,
              train_end_date=train_end_date,
              regressor_cols=[],
              pipeline=get_dummy_pipeline(
                  include_preprocessing=True, regressor_cols=[]
              ),
              forecast_horizon=5,
          )
          ts = result.timeseries
          assert (
              f"{VALUE_COL} column of the provided time series contains trailing NAs"
              in record[0].message.args[0]
          )
          assert (
              ts.train_end_date == train_end_date
          )  # Unchanged when `train_end_date` is specified.
          assert ts.last_date_for_reg is None
          forecast = result.forecast
          assert forecast.df[TIME_COL].max() == datetime.datetime(
              2018, 3, 3
          )
          assert forecast.test_evaluation is None
  
      # `train_end_date` smaller than last date before null,
      # using a subset of the `regressor_cols`.
      train_end_date = datetime.datetime(2018, 2, 17)
      regressor_cols = ["regressor2"]
      result = forecast_pipeline(
          df=df,
          train_end_date=train_end_date,
          regressor_cols=regressor_cols,
          pipeline=get_dummy_pipeline(
              include_preprocessing=True, regressor_cols=regressor_cols
          ),
          forecast_horizon=5,
      )
      ts = result.timeseries
      assert ts.train_end_date == datetime.datetime(2018, 2, 17)
      assert ts.last_date_for_reg == datetime.datetime(2018, 2, 24)
      forecast = result.forecast
      assert forecast.df[TIME_COL].max() == datetime.datetime(
          2018, 2, 22
      )
      assert forecast.forecast_horizon == 5
      assert forecast.test_evaluation is not None
  
      # `periods_between_train_test` is provided, attempts to predict beyond
      # the last known regressor value
      regressor_cols = ["regressor1", "regressor2"]
      forecast_horizon = 5
      periods_between_train_test = 2
      test_horizon = 3
      result = forecast_pipeline(
          df,
          forecast_horizon=forecast_horizon,
          test_horizon=test_horizon,
          regressor_cols=regressor_cols,
          periods_between_train_test=periods_between_train_test,
          pipeline=get_dummy_pipeline(
              include_preprocessing=True, regressor_cols=regressor_cols
          ),
      )
      n_cols = len(["ts", "actual", "forecast"])
      # Number of rows up to last non NaN value column entry
      train_size = df.shape[0] - available_forecast_horizon
      df_train = df.iloc[:train_size]
      assert result.backtest.df_train.shape == (
          train_size - test_horizon - periods_between_train_test,
          n_cols,
      )
      # Backtest data corresponds to `df_test`.
      assert result.backtest.df_test.shape == (test_horizon, n_cols)
      assert result.backtest.df.shape == (train_size, n_cols)
      assert (
          result.backtest.train_end_date
          == df_train.iloc[
              -(test_horizon + periods_between_train_test + 1)
          ][TIME_COL]
      )
      assert (
          result.backtest.test_start_date
          == df_train.iloc[-test_horizon][TIME_COL]
      )
      # Forecast horizon (5) + periods_between_train_test (2) extends beyond the
      # length of available regressors (6). Skips (2), then predicts the next
      # 4 before running out available regressors.
      # Future prediction can not exceed length of available regressors.
      assert result.forecast.df_train.shape == (train_size, n_cols)
      assert result.forecast.df_test.shape == (4, n_cols)
      assert (
          result.forecast.df.iloc[-1][TIME_COL]
          == result.timeseries.last_date_for_reg
      )
      assert (
          result.forecast.train_end_date == df_train.iloc[-1][TIME_COL]
      )
      expected_forecast_test_start_date = pd.date_range(
          start=result.forecast.train_end_date,
          periods=periods_between_train_test + 2,
          freq=result.timeseries.freq,
      )[-1]
      assert (
          result.forecast.test_start_date
          == expected_forecast_test_start_date
      )
  
imports: import datetime
  import math
  import sys
  import warnings
  import numpy
  import pandas
  import pytest
  from scipy.stats import randint
  from sklearn.metrics import explained_variance_score
  from sklearn.metrics import mean_absolute_error
  from sklearn.metrics import mean_squared_error
  from sklearn.pipeline import Pipeline
  from greykite.common.constants import ACTUAL_COL
  from greykite.common.constants import ADJUSTMENT_DELTA_COL
  from greykite.common.constants import END_TIME_COL
  from greykite.common.constants import FRACTION_OUTSIDE_TOLERANCE
  from greykite.common.constants import METRIC_COL
  from greykite.common.constants import PREDICTED_COL
  from greykite.common.constants import QUANTILE_SUMMARY_COL
  from greykite.common.constants import START_TIME_COL
  from greykite.common.constants import TIME_COL
  from greykite.common.constants import VALUE_COL
  from greykite.common.constants import R2_null_model_score
  from greykite.common.evaluation import EvaluationMetricEnum
  from greykite.common.evaluation import add_finite_filter_to_scorer
  from greykite.common.evaluation import add_preaggregation_to_scorer
  from greykite.common.python_utils import assert_equal
  from greykite.common.python_utils import unique_elements_in_list
  from greykite.common.testing_utils import generate_df_for_tests
  from greykite.common.testing_utils import generate_df_with_reg_for_tests
  from greykite.framework.constants import CV_REPORT_METRICS_ALL
  from greykite.framework.constants import FRACTION_OUTSIDE_TOLERANCE_NAME
  from greykite.framework.input.univariate_time_series import UnivariateTimeSeries
  from greykite.framework.pipeline.pipeline import forecast_pipeline
  from greykite.framework.templates.prophet_template import ProphetTemplate
  from greykite.framework.utils.framework_testing_utils import check_forecast_pipeline_result
  from greykite.framework.utils.framework_testing_utils import mock_pipeline
  from greykite.sklearn.estimator.null_model import DummyEstimator
  from greykite.sklearn.estimator.prophet_estimator import ProphetEstimator
  from greykite.sklearn.estimator.silverkite_estimator import SilverkiteEstimator
  from greykite.sklearn.estimator.simple_silverkite_estimator import SimpleSilverkiteEstimator
  from greykite.sklearn.transform.column_selector import ColumnSelector
  from greykite.sklearn.transform.drop_degenerate_transformer import DropDegenerateTransformer
  from greykite.sklearn.transform.dtype_column_selector import DtypeColumnSelector
  from greykite.sklearn.transform.normalize_transformer import NormalizeTransformer
  from greykite.sklearn.transform.null_transformer import NullTransformer
  from greykite.sklearn.transform.pandas_feature_union import PandasFeatureUnion
  from greykite.sklearn.transform.zscore_outlier_transformer import ZscoreOutlierTransformer
label_desc: Use image node_id 7 for calling a global function with example usage: test_train_end_date_gap_regressors() without return types