def _shocks_to_epsilons(model, shocks, T):
    """
    Helper function to support input argument `shocks` being one of many
    different data types. Will always return a `T, n_e` matrix.
    """
    n_e = len(model.calibration['exogenous'])

    # if we have a DataFrame, convert it to a dict and rely on the method below
    if isinstance(shocks, pd.DataFrame):
        shocks = {k: shocks[k].tolist() for k in shocks.columns}

    # handle case where shocks might be a dict. Be careful to handle case where
    # value arrays are not the same length
    if isinstance(shocks, dict):
        epsilons = np.zeros((T + 1, n_e))
        for (i, k) in enumerate(model.symbols["exogenous"]):
            if k in shocks:
                this_shock = shocks[k]
                epsilons[:len(this_shock), i] = this_shock
                epsilons[len(this_shock):, i] = this_shock[-1]
            else:
                # otherwise set to value in calibration
                epsilons[:, i] = model.calibration["exogenous"][i]

        return epsilons

    # read from calibration if not given
    if shocks is None:
        shocks = model.calibration["exogenous"]

    # now we just assume that shocks is array-like and try using the output of
    # np.asarray(shocks)
    shocks = np.asarray(shocks)
    shocks = shocks.reshape((-1, n_e))

    # until last period, exogenous shock takes its last value
    epsilons = np.zeros((T + 1, n_e))
    epsilons[:(shocks.shape[0] - 1), :] = shocks[1:, :]
    epsilons[(shocks.shape[0] - 1):, :] = shocks[-1:, :]

    return epsilons
Helper function to support input argument `shocks` being one of many
    different data types. Will always return a `T, n_e` matrix.