# Buggy code
def fit(self, y, X=None, fh=None, **fit_params):
    """Fit to training data.

    Parameters
    ----------
    y : pd.Series
        Target time series to which to fit the forecaster.
    fh : int, list or np.array, optional (default=None)
        The forecasters horizon with the steps ahead to to predict.
    X : pd.DataFrame, optional (default=None)
        Exogenous variables are ignored
    Returns
    -------
    self : returns an instance of self.
    """
    y = check_y(y)

    # validate cross-validator
    cv = check_cv(self.cv)
    base_forecaster = clone(self.forecaster)

    scoring = check_scoring(self.scoring)
    scorers = {scoring.name: scoring}
    refit_metric = scoring.name

    fit_and_score_kwargs = dict(
        scorer=scorers,
        fit_params=fit_params,
        return_train_score=self.return_train_score,
        return_times=True,
        return_parameters=False,
        error_score=self.error_score,
        verbose=self.verbose,
    )

    results = {}
    all_candidate_params = []
    all_out = []

    def evaluate_candidates(candidate_params):
        candidate_params = list(candidate_params)
        n_candidates = len(candidate_params)

        if self.verbose > 0:
            n_splits = cv.get_n_splits(y)
            print(  # noqa
                "Fitting {0} folds for each of {1} candidates,"
                " totalling {2} fits".format(
                    n_splits, n_candidates, n_candidates * n_splits
                )
            )

        out = []
        for parameters in candidate_params:
            r = _fit_and_score(
                clone(base_forecaster),
                cv,
                y,
                X,
                parameters=parameters,
                **fit_and_score_kwargs,
            )
            out.append(r)

        n_splits = cv.get_n_splits(y)

        if len(out) < 1:
            raise ValueError(
                "No fits were performed. "
                "Was the CV iterator empty? "
                "Were there no candidates?"
            )

        all_candidate_params.extend(candidate_params)
        all_out.extend(out)

        nonlocal results
        results = self._format_results(all_candidate_params, scorers, all_out)
        return results

    self._run_search(evaluate_candidates)

    self.best_index_ = results["rank_test_%s" % refit_metric].argmin()
    self.best_score_ = results["mean_test_%s" % refit_metric][self.best_index_]
    self.best_params_ = results["params"][self.best_index_]

    self.best_forecaster_ = clone(base_forecaster).set_params(**self.best_params_)

    if self.refit:
        refit_start_time = time.time()
        self.best_forecaster_.fit(y, X, fh)
        self.refit_time_ = time.time() - refit_start_time

    # Store the only scorer not as a dict for single metric evaluation
    self.scorer_ = scorers[scoring.name]

    self.cv_results_ = results
    self.n_splits_ = cv.get_n_splits(y)

    self._is_fitted = True
    return self


# Traceback (ValueError)
ValueError                                Traceback (most recent call last)
<ipython-input-3-4a75cca05732> in <module>
16 MODEL_Auto_ARIMA.fit(
17     y_train=y_df["y"],
---> 18     X_train=X_df
19 )

~/miniconda3/envs/RATP37/lib/python3.7/site-packages/sktime/forecasting/arima.py in fit(self, y_train, fh, X_train, **fit_args)
363         self._set_y_X(y_train, X_train)
364         self._set_fh(fh)
--> 365         self._forecaster.fit(y_train, exogenous=X_train, **fit_args)
366         self._is_fitted = True
367         return self

~/miniconda3/envs/RATP37/lib/python3.7/site-packages/pmdarima/arima/auto.py in fit(self, y, X, **fit_args)
218             with_intercept=self.with_intercept,
219             sarimax_kwargs=sarimax_kwargs,
--> 220             **fit_args)
221
222         return self

~/miniconda3/envs/RATP37/lib/python3.7/site-packages/pmdarima/arima/auto.py in auto_arima(y, X, start_p, d, start_q, max_p, max_d, max_q, start_P, D, start_Q, max_P, max_D, max_Q, max_order, m, seasonal, stationary, information_criterion, alpha, test, seasonal_test, stepwise, n_jobs, start_params, trend, method, maxiter, offset_test_args, seasonal_test_args, suppress_warnings, error_action, trace, random, random_state, n_fits, return_valid_fits, out_of_sample_size, scoring, scoring_args, with_intercept, sarimax_kwargs, **fit_args)
390
391     # Temporary shim until we remove `exogenous` support completely
--> 392     X, fit_args = pm_compat.get_X(X, **fit_args)
393
394     # pop out the deprecated kwargs

~/miniconda3/envs/RATP37/lib/python3.7/site-packages/pmdarima/compat/pmdarima.py in get_X(X, **kwargs)
12     exog = kwargs.pop("exogenous", None)
13     if X is not None and exog is not None:
---> 14         raise ValueError("Multiple values provided for both X and exogenous")
15
16     if exog is not None:

ValueError: Multiple values provided for both X and exogenous

# Fixed code
def fit(self, y, X=None, fh=None, **fit_params):
    """Fit to training data.

    Parameters
    ----------
    y : pd.Series
        Target time series to which to fit the forecaster.
    fh : int, list or np.array, optional (default=None)
        The forecasters horizon with the steps ahead to to predict.
    X : pd.DataFrame, optional (default=None)
        Exogenous variables are ignored
    Returns
    -------
    self : returns an instance of self.
    """
    y, X = check_y_X(y, X)

    # validate cross-validator
    cv = check_cv(self.cv)
    base_forecaster = clone(self.forecaster)

    scoring = check_scoring(self.scoring)
    scorers = {scoring.name: scoring}
    refit_metric = scoring.name

    fit_and_score_kwargs = dict(
        scorer=scorers,
        fit_params=fit_params,
        return_train_score=self.return_train_score,
        return_times=True,
        return_parameters=False,
        error_score=self.error_score,
        verbose=self.verbose,
    )

    results = {}
    all_candidate_params = []
    all_out = []

    def evaluate_candidates(candidate_params):
        candidate_params = list(candidate_params)
        n_candidates = len(candidate_params)

        if self.verbose > 0:
            n_splits = cv.get_n_splits(y)
            print(  # noqa
                "Fitting {0} folds for each of {1} candidates,"
                " totalling {2} fits".format(
                    n_splits, n_candidates, n_candidates * n_splits
                )
            )

        out = []
        for parameters in candidate_params:
            r = _fit_and_score(
                clone(base_forecaster),
                cv,
                y,
                X,
                parameters=parameters,
                **fit_and_score_kwargs,
            )
            out.append(r)

        n_splits = cv.get_n_splits(y)

        if len(out) < 1:
            raise ValueError(
                "No fits were performed. "
                "Was the CV iterator empty? "
                "Were there no candidates?"
            )

        all_candidate_params.extend(candidate_params)
        all_out.extend(out)

        nonlocal results
        results = self._format_results(all_candidate_params, scorers, all_out)
        return results

    self._run_search(evaluate_candidates)

    self.best_index_ = results["rank_test_%s" % refit_metric].argmin()
    self.best_score_ = results["mean_test_%s" % refit_metric][self.best_index_]
    self.best_params_ = results["params"][self.best_index_]

    self.best_forecaster_ = clone(base_forecaster).set_params(**self.best_params_)

    if self.refit:
        refit_start_time = time.time()
        self.best_forecaster_.fit(y, X, fh)
        self.refit_time_ = time.time() - refit_start_time

    # Store the only scorer not as a dict for single metric evaluation
    self.scorer_ = scorers[scoring.name]

    self.cv_results_ = results
    self.n_splits_ = cv.get_n_splits(y)

    self._is_fitted = True
    return self