# Buggy code
def fit(self, X, y):
    """Fit MultiTaskElasticNet model with coordinate descent

    Parameters
    -----------
    X : ndarray, shape (n_samples, n_features)
        Data
    y : ndarray, shape (n_samples, n_tasks)
        Target. Will be cast to X's dtype if necessary

    Notes
    -----

    Coordinate descent is an algorithm that considers each column of
    data at a time hence it will automatically convert the X input
    as a Fortran-contiguous numpy array if necessary.

    To avoid memory re-allocation it is advised to allocate the
    initial data in memory directly using that format.
    """
    X = check_array(
        X,
        dtype=[np.float64, np.float32],
        order="F",
        copy=self.copy_X and self.fit_intercept,
    )
    y = check_array(y, dtype=X.dtype.type, ensure_2d=False)

    if hasattr(self, "l1_ratio"):
        model_str = "ElasticNet"
    else:
        model_str = "Lasso"
    if y.ndim == 1:
        raise ValueError("For mono-task outputs, use %s" % model_str)

    n_samples, n_features = X.shape
    _, n_tasks = y.shape

    if n_samples != y.shape[0]:
        raise ValueError(
            "X and y have inconsistent dimensions (%d != %d)" % (n_samples, y.shape[0])
        )

    X, y, X_offset, y_offset, X_scale = _preprocess_data(
        X, y, self.fit_intercept, self.normalize, copy=False
    )

    if not self.warm_start or self.coef_ is None:
        self.coef_ = np.zeros((n_tasks, n_features), dtype=X.dtype.type, order="F")

    l1_reg = self.alpha * self.l1_ratio * n_samples
    l2_reg = self.alpha * (1.0 - self.l1_ratio) * n_samples

    self.coef_ = np.asfortranarray(self.coef_)  # coef contiguous in memory

    if self.selection not in ["random", "cyclic"]:
        raise ValueError("selection should be either random or cyclic.")
    random = self.selection == "random"

    self.coef_, self.dual_gap_, self.eps_, self.n_iter_ = (
        cd_fast.enet_coordinate_descent_multi_task(
            self.coef_,
            l1_reg,
            l2_reg,
            X,
            y,
            self.max_iter,
            self.tol,
            check_random_state(self.random_state),
            random,
        )
    )

    self._set_intercept(X_offset, y_offset, X_scale)

    if self.dual_gap_ > self.eps_:
        warnings.warn(
            "Objective did not converge, you might want"
            " to increase the number of iterations",
            ConvergenceWarning,
        )

    # return self for chaining fit and predict calls
    return self


# Traceback (AttributeError)
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-2-445bda46f02e> in <module>()
22 Y = np.dot(X, coef.T) + rng.randn(n_samples, n_tasks)
23
---> 24 coef_multi_task_lasso_ = MultiTaskLasso(alpha=1., warm_start = True).fit(X, Y).coef_

/anaconda3/lib/python3.6/site-packages/sklearn/linear_model/coordinate_descent.py in fit(self, X, y)
1794             X, y, self.fit_intercept, self.normalize, copy=False)
1795
-> 1796         if not self.warm_start or self.coef_ is None:
1797             self.coef_ = np.zeros((n_tasks, n_features), dtype=X.dtype.type,
1798                                   order='F')

AttributeError: 'MultiTaskLasso' object has no attribute 'coef_'

# Fixed code
def fit(self, X, y):
    """Fit MultiTaskElasticNet model with coordinate descent

    Parameters
    -----------
    X : ndarray, shape (n_samples, n_features)
        Data
    y : ndarray, shape (n_samples, n_tasks)
        Target. Will be cast to X's dtype if necessary

    Notes
    -----

    Coordinate descent is an algorithm that considers each column of
    data at a time hence it will automatically convert the X input
    as a Fortran-contiguous numpy array if necessary.

    To avoid memory re-allocation it is advised to allocate the
    initial data in memory directly using that format.
    """
    X = check_array(
        X,
        dtype=[np.float64, np.float32],
        order="F",
        copy=self.copy_X and self.fit_intercept,
    )
    y = check_array(y, dtype=X.dtype.type, ensure_2d=False)

    if hasattr(self, "l1_ratio"):
        model_str = "ElasticNet"
    else:
        model_str = "Lasso"
    if y.ndim == 1:
        raise ValueError("For mono-task outputs, use %s" % model_str)

    n_samples, n_features = X.shape
    _, n_tasks = y.shape

    if n_samples != y.shape[0]:
        raise ValueError(
            "X and y have inconsistent dimensions (%d != %d)" % (n_samples, y.shape[0])
        )

    X, y, X_offset, y_offset, X_scale = _preprocess_data(
        X, y, self.fit_intercept, self.normalize, copy=False
    )

    if not self.warm_start or not hasattr(self, "coef_"):
        self.coef_ = np.zeros((n_tasks, n_features), dtype=X.dtype.type, order="F")

    l1_reg = self.alpha * self.l1_ratio * n_samples
    l2_reg = self.alpha * (1.0 - self.l1_ratio) * n_samples

    self.coef_ = np.asfortranarray(self.coef_)  # coef contiguous in memory

    if self.selection not in ["random", "cyclic"]:
        raise ValueError("selection should be either random or cyclic.")
    random = self.selection == "random"

    self.coef_, self.dual_gap_, self.eps_, self.n_iter_ = (
        cd_fast.enet_coordinate_descent_multi_task(
            self.coef_,
            l1_reg,
            l2_reg,
            X,
            y,
            self.max_iter,
            self.tol,
            check_random_state(self.random_state),
            random,
        )
    )

    self._set_intercept(X_offset, y_offset, X_scale)

    if self.dual_gap_ > self.eps_:
        warnings.warn(
            "Objective did not converge, you might want"
            " to increase the number of iterations",
            ConvergenceWarning,
        )

    # return self for chaining fit and predict calls
    return self