code: def validate_pipeline_input(pipeline_function):
      """Decorator that validates inputs to forecast_pipeline function and sets defaults"""
  
      @functools.wraps(pipeline_function)
      def pipeline_wrapper(
          # The arguments to this wrapper must be identical to forecast_pipeline() function.
          # We don't use **kwargs
          # because it's easier to check parameters directly.
          # input
          df: pd.DataFrame,
          time_col=TIME_COL,
          value_col=VALUE_COL,
          date_format=None,
          tz=None,
          freq=None,
          train_end_date=None,
          anomaly_info=None,
          # model
          pipeline=None,
          regressor_cols=None,
          lagged_regressor_cols=None,
          estimator=SimpleSilverkiteEstimator(),
          hyperparameter_grid=None,
          hyperparameter_budget=None,
          n_jobs=COMPUTATION_N_JOBS,
          verbose=1,
          # forecast
          forecast_horizon=None,
          coverage=0.95,
          test_horizon=None,
          periods_between_train_test=None,
          agg_periods=None,
          agg_func=None,
          # evaluation
          score_func=EvaluationMetricEnum.MeanAbsolutePercentError.name,
          score_func_greater_is_better=False,
          cv_report_metrics=None,
          null_model_params=None,
          relative_error_tolerance=None,
          # CV
          cv_horizon=None,
          cv_min_train_periods=None,
          cv_expanding_window=False,
          cv_use_most_recent_splits=False,
          cv_periods_between_splits=None,
          cv_periods_between_train_test=0,
          cv_max_splits=3,
      ):
          if coverage is not None and (coverage < 0 or coverage > 1):
              raise ValueError(
                  f"coverage must be between 0 and 1, found {coverage}"
              )
          if (
              relative_error_tolerance is not None
              and relative_error_tolerance < 0
          ):
              raise ValueError(
                  f"relative_error_tolerance must non-negative, found {relative_error_tolerance}"
              )
  
          # default values for forecast horizon, test, and cross-validation parameters
          period = min_gap_in_seconds(df=df, time_col=time_col)
          num_observations = df.shape[0]
          default_time_params = get_default_time_parameters(
              period=period,
              num_observations=num_observations,
              forecast_horizon=forecast_horizon,
              test_horizon=test_horizon,
              periods_between_train_test=periods_between_train_test,
              cv_horizon=cv_horizon,
              cv_min_train_periods=cv_min_train_periods,
              cv_periods_between_train_test=cv_periods_between_train_test,
          )
          forecast_horizon = default_time_params.get("forecast_horizon")
          test_horizon = default_time_params.get("test_horizon")
          periods_between_train_test = default_time_params.get(
              "periods_between_train_test"
          )
          cv_horizon = default_time_params.get("cv_horizon")
          cv_min_train_periods = default_time_params.get(
              "cv_min_train_periods"
          )
          cv_periods_between_train_test = default_time_params.get(
              "cv_periods_between_train_test"
          )
  
          # ensures the values are integers in the proper domain
          if hyperparameter_budget is not None:
              hyperparameter_budget = get_integer(
                  hyperparameter_budget,
                  "hyperparameter_budget",
                  min_value=1,
              )
  
          if (
              cv_horizon == 0 or cv_max_splits == 0
          ) and test_horizon == 0:
              warnings.warn(
                  "Both CV and backtest are skipped! Make sure this is intended."
                  " It's important to check model performance on historical data."
                  " Set cv_horizon and cv_max_splits to nonzero values to enable CV."
                  " Set test_horizon to nonzero value to enable backtest."
              )
  
          if test_horizon == 0:
              warnings.warn(
                  "No data selected for test (test_horizon=0). "
                  "It is important to check out of sample performance"
              )
  
          # checks horizon against data size
          if num_observations < forecast_horizon * 2:
              warnings.warn(
                  f"Not enough training data to forecast the full forecast_horizon."
                  " Exercise extra caution with"
                  f" forecasted values after {num_observations // 2} periods."
              )
  
          if test_horizon > num_observations:
              raise ValueError(
                  f"test_horizon ({test_horizon}) is too large."
                  " Must be less than the number "
                  f"of input data points: {num_observations})"
              )
  
          if test_horizon > forecast_horizon:
              warnings.warn(
                  f"test_horizon should never be larger than forecast_horizon."
              )
  
          if test_horizon > num_observations // 3:
              warnings.warn(
                  f"test_horizon should be <= than 1/3 of the data set size to allow enough data to train"
                  f" a backtest model. Consider reducing to {num_observations // 3}. If this is smaller"
                  f" than the forecast_horizon, you will need to make a trade-off between setting"
                  f" test_horizon=forecast_horizon and having enough data left over to properly"
                  f" train a realistic backtest model."
              )
  
          log_message(
              f"forecast_horizon: {forecast_horizon}",
              LoggingLevelEnum.INFO,
          )
          log_message(
              f"test_horizon: {test_horizon}", LoggingLevelEnum.INFO
          )
          log_message(
              f"cv_horizon: {cv_horizon}", LoggingLevelEnum.INFO
          )
  
          return pipeline_function(
              df,
              time_col=time_col,
              value_col=value_col,
              date_format=date_format,
              tz=tz,
              freq=freq,
              train_end_date=train_end_date,
              anomaly_info=anomaly_info,
              pipeline=pipeline,
              regressor_cols=regressor_cols,
              lagged_regressor_cols=lagged_regressor_cols,
              estimator=estimator,
              hyperparameter_grid=hyperparameter_grid,
              hyperparameter_budget=hyperparameter_budget,
              n_jobs=n_jobs,
              verbose=verbose,
              forecast_horizon=forecast_horizon,
              coverage=coverage,
              test_horizon=test_horizon,
              periods_between_train_test=periods_between_train_test,
              agg_periods=agg_periods,
              agg_func=agg_func,
              score_func=score_func,
              score_func_greater_is_better=score_func_greater_is_better,
              cv_report_metrics=cv_report_metrics,
              null_model_params=null_model_params,
              relative_error_tolerance=relative_error_tolerance,
              cv_horizon=cv_horizon,
              cv_min_train_periods=cv_min_train_periods,
              cv_expanding_window=cv_expanding_window,
              cv_use_most_recent_splits=cv_use_most_recent_splits,
              cv_periods_between_splits=cv_periods_between_splits,
              cv_periods_between_train_test=cv_periods_between_train_test,
              cv_max_splits=cv_max_splits,
          )
  
      return pipeline_wrapper
  
imports: import functools
  import warnings
  from dataclasses import dataclass
  import pandas
  from sklearn import clone
  from sklearn.model_selection import ParameterGrid
  from sklearn.model_selection import RandomizedSearchCV
  from sklearn.model_selection import train_test_split
  from sklearn.pipeline import Pipeline
  from greykite.common.constants import TIME_COL
  from greykite.common.constants import VALUE_COL
  from greykite.common.evaluation import EvaluationMetricEnum
  from greykite.common.logging import LoggingLevelEnum
  from greykite.common.logging import log_message
  from greykite.common.python_utils import get_integer
  from greykite.common.time_properties import min_gap_in_seconds
  from greykite.framework.constants import COMPUTATION_N_JOBS
  from greykite.framework.constants import CV_REPORT_METRICS_ALL
  from greykite.framework.input.univariate_time_series import UnivariateTimeSeries
  from greykite.framework.output.univariate_forecast import UnivariateForecast
  from greykite.framework.pipeline.utils import get_basic_pipeline
  from greykite.framework.pipeline.utils import get_default_time_parameters
  from greykite.framework.pipeline.utils import get_forecast
  from greykite.framework.pipeline.utils import get_hyperparameter_searcher
  from greykite.sklearn.cross_validation import RollingTimeSeriesSplit
  from greykite.sklearn.estimator.simple_silverkite_estimator import SimpleSilverkiteEstimator
label_desc: Use image node_id 1 for calling a global function with example usage: validate_pipeline_input(pipeline_function) and returns: pipeline_wrapper, pipeline_function