# Buggy code
def kneighbors(self, X=None, n_neighbors=None, return_distance=True):
    """Finds the K-neighbors of a point.
        Returns indices of and distances to the neighbors of each point.

        Parameters
        ----------
        X : array-like, shape (n_query, n_features), \
                or (n_query, n_indexed) if metric == 'precomputed'
            The query point or points.
            If not provided, neighbors of each indexed point are returned.
            In this case, the query point is not considered its own neighbor.

        n_neighbors : int
            Number of neighbors to get (default is the value
            passed to the constructor).

        return_distance : boolean, optional. Defaults to True.
            If False, distances will not be returned

        Returns
        -------
        dist : array
            Array representing the lengths to points, only present if
            return_distance=True

        ind : array
            Indices of the nearest points in the population matrix.

        Examples
        --------
        In the following example, we construct a NeighborsClassifier
        class from an array representing our data set and ask who's
        the closest point to [1,1,1]

        >>> samples = [[0., 0., 0.], [0., .5, 0.], [1., 1., .5]]
        >>> from sklearn.neighbors import NearestNeighbors
        >>> neigh = NearestNeighbors(n_neighbors=1)
        >>> neigh.fit(samples) # doctest: +ELLIPSIS
        NearestNeighbors(algorithm='auto', leaf_size=30, ...)
        >>> print(neigh.kneighbors([[1., 1., 1.]])) # doctest: +ELLIPSIS
        (array([[0.5]]), array([[2]]))

        As you can see, it returns [[0.5]], and [[2]], which means that the
        element is at distance 0.5 and is the third element of samples
        (indexes start at 0). You can also query for multiple points:

        >>> X = [[0., 1., 0.], [1., 0., 1.]]
        >>> neigh.kneighbors(X, return_distance=False) # doctest: +ELLIPSIS
        array([[1],
               [2]]...)

        """
    check_is_fitted(self, ["_fit_method", "_fit_X"], all_or_any=any)

    if n_neighbors is None:
        n_neighbors = self.n_neighbors
    elif n_neighbors <= 0:
        raise ValueError("Expected n_neighbors > 0. Got %d" % n_neighbors)
    else:
        if not np.issubdtype(type(n_neighbors), np.integer):
            raise TypeError(
                "n_neighbors does not take %s value, "
                "enter integer value" % type(n_neighbors)
            )

    if X is not None:
        query_is_train = False
        X = check_array(X, accept_sparse="csr")
    else:
        query_is_train = True
        X = self._fit_X
        # Include an extra neighbor to account for the sample itself being
        # returned, which is removed later
        n_neighbors += 1

    train_size = self._fit_X.shape[0]
    if n_neighbors > train_size:
        raise ValueError(
            "Expected n_neighbors <= n_samples, "
            " but n_samples = %d, n_neighbors = %d" % (train_size, n_neighbors)
        )
    n_samples, _ = X.shape
    sample_range = np.arange(n_samples)[:, None]

    n_jobs = effective_n_jobs(self.n_jobs)
    if self._fit_method == "brute":
        reduce_func = partial(
            self._kneighbors_reduce_func,
            n_neighbors=n_neighbors,
            return_distance=return_distance,
        )

        # for efficiency, use squared euclidean distances
        kwds = (
            {"squared": True}
            if self.effective_metric_ == "euclidean"
            else self.effective_metric_params_
        )

        result = list(
            pairwise_distances_chunked(
                X,
                self._fit_X,
                reduce_func=reduce_func,
                metric=self.effective_metric_,
                n_jobs=n_jobs,
                **kwds,
            )
        )

    elif self._fit_method in ["ball_tree", "kd_tree"]:
        if issparse(X):
            raise ValueError(
                "%s does not work with sparse matrices. Densify the data, "
                "or set algorithm='brute'" % self._fit_method
            )
        if sys.version_info < (3,) or LooseVersion(joblib_version) < LooseVersion(
            "0.12"
        ):
            # Deal with change of API in joblib
            delayed_query = delayed(self._tree.query, check_pickle=False)
            parallel_kwargs = {"backend": "threading"}
        else:
            delayed_query = delayed(self._tree.query)
            parallel_kwargs = {"prefer": "threads"}
        result = Parallel(n_jobs, **parallel_kwargs)(
            delayed_query(X[s], n_neighbors, return_distance)
            for s in gen_even_slices(X.shape[0], n_jobs)
        )
    else:
        raise ValueError("internal: _fit_method not recognized")

    if return_distance:
        dist, neigh_ind = zip(*result)
        result = np.vstack(dist), np.vstack(neigh_ind)
    else:
        result = np.vstack(result)

    if not query_is_train:
        return result
    else:
        # If the query data is the same as the indexed data, we would like
        # to ignore the first nearest neighbor of every sample, i.e
        # the sample itself.
        if return_distance:
            dist, neigh_ind = result
        else:
            neigh_ind = result

        sample_mask = neigh_ind != sample_range

        # Corner case: When the number of duplicates are more
        # than the number of neighbors, the first NN will not
        # be the sample, but a duplicate.
        # In that case mask the first duplicate.
        dup_gr_nbrs = np.all(sample_mask, axis=1)
        sample_mask[:, 0][dup_gr_nbrs] = False

        neigh_ind = np.reshape(neigh_ind[sample_mask], (n_samples, n_neighbors - 1))

        if return_distance:
            dist = np.reshape(dist[sample_mask], (n_samples, n_neighbors - 1))
            return dist, neigh_ind
        return neigh_ind


# Traceback (TypeError)
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-36-9fc0a20fa010> in <module>
----> 1 pickle.loads(cloudpickle.dumps(knn._tree.query))

~/pypy3-v6.0.0-linux64/lib-python/3/pickle.py in _loads(s, fix_imports, encoding, errors)
1585     file = io.BytesIO(s)
1586     return _Unpickler(file, fix_imports=fix_imports,
-> 1587                       encoding=encoding, errors=errors).load()
1588
1589 # Use the faster _pickle if possible

~/pypy3-v6.0.0-linux64/lib-python/3/pickle.py in load(self)
1061                     raise EOFError
1062                 assert isinstance(key, bytes_types)
-> 1063                 dispatch[key[0]](self)
1064         except _Stop as stopinst:
1065             return stopinst.value

~/pypy3-v6.0.0-linux64/lib-python/3/pickle.py in load_newobj(self)
1345         args = self.stack.pop()
1346         cls = self.stack.pop()
-> 1347         obj = cls.__new__(cls, *args)
1348         self.append(obj)
1349     dispatch[NEWOBJ[0]] = load_newobj

TypeError: object.__new__(getset_descriptor) is not safe, use getset_descriptor.__new__()

# Fixed code
def kneighbors(self, X=None, n_neighbors=None, return_distance=True):
    """Finds the K-neighbors of a point.
        Returns indices of and distances to the neighbors of each point.

        Parameters
        ----------
        X : array-like, shape (n_query, n_features), \
                or (n_query, n_indexed) if metric == 'precomputed'
            The query point or points.
            If not provided, neighbors of each indexed point are returned.
            In this case, the query point is not considered its own neighbor.

        n_neighbors : int
            Number of neighbors to get (default is the value
            passed to the constructor).

        return_distance : boolean, optional. Defaults to True.
            If False, distances will not be returned

        Returns
        -------
        dist : array
            Array representing the lengths to points, only present if
            return_distance=True

        ind : array
            Indices of the nearest points in the population matrix.

        Examples
        --------
        In the following example, we construct a NeighborsClassifier
        class from an array representing our data set and ask who's
        the closest point to [1,1,1]

        >>> samples = [[0., 0., 0.], [0., .5, 0.], [1., 1., .5]]
        >>> from sklearn.neighbors import NearestNeighbors
        >>> neigh = NearestNeighbors(n_neighbors=1)
        >>> neigh.fit(samples) # doctest: +ELLIPSIS
        NearestNeighbors(algorithm='auto', leaf_size=30, ...)
        >>> print(neigh.kneighbors([[1., 1., 1.]])) # doctest: +ELLIPSIS
        (array([[0.5]]), array([[2]]))

        As you can see, it returns [[0.5]], and [[2]], which means that the
        element is at distance 0.5 and is the third element of samples
        (indexes start at 0). You can also query for multiple points:

        >>> X = [[0., 1., 0.], [1., 0., 1.]]
        >>> neigh.kneighbors(X, return_distance=False) # doctest: +ELLIPSIS
        array([[1],
               [2]]...)

        """
    check_is_fitted(self, ["_fit_method", "_fit_X"], all_or_any=any)

    if n_neighbors is None:
        n_neighbors = self.n_neighbors
    elif n_neighbors <= 0:
        raise ValueError("Expected n_neighbors > 0. Got %d" % n_neighbors)
    else:
        if not np.issubdtype(type(n_neighbors), np.integer):
            raise TypeError(
                "n_neighbors does not take %s value, "
                "enter integer value" % type(n_neighbors)
            )

    if X is not None:
        query_is_train = False
        X = check_array(X, accept_sparse="csr")
    else:
        query_is_train = True
        X = self._fit_X
        # Include an extra neighbor to account for the sample itself being
        # returned, which is removed later
        n_neighbors += 1

    train_size = self._fit_X.shape[0]
    if n_neighbors > train_size:
        raise ValueError(
            "Expected n_neighbors <= n_samples, "
            " but n_samples = %d, n_neighbors = %d" % (train_size, n_neighbors)
        )
    n_samples, _ = X.shape
    sample_range = np.arange(n_samples)[:, None]

    n_jobs = effective_n_jobs(self.n_jobs)
    if self._fit_method == "brute":
        reduce_func = partial(
            self._kneighbors_reduce_func,
            n_neighbors=n_neighbors,
            return_distance=return_distance,
        )

        # for efficiency, use squared euclidean distances
        kwds = (
            {"squared": True}
            if self.effective_metric_ == "euclidean"
            else self.effective_metric_params_
        )

        result = list(
            pairwise_distances_chunked(
                X,
                self._fit_X,
                reduce_func=reduce_func,
                metric=self.effective_metric_,
                n_jobs=n_jobs,
                **kwds,
            )
        )

    elif self._fit_method in ["ball_tree", "kd_tree"]:
        if issparse(X):
            raise ValueError(
                "%s does not work with sparse matrices. Densify the data, "
                "or set algorithm='brute'" % self._fit_method
            )
        if sys.version_info < (3,) or LooseVersion(joblib_version) < LooseVersion(
            "0.12"
        ):
            # Deal with change of API in joblib
            delayed_query = delayed(_tree_query_parallel_helper, check_pickle=False)
            parallel_kwargs = {"backend": "threading"}
        else:
            delayed_query = delayed(_tree_query_parallel_helper)
            parallel_kwargs = {"prefer": "threads"}
        result = Parallel(n_jobs, **parallel_kwargs)(
            delayed_query(self._tree, X[s], n_neighbors, return_distance)
            for s in gen_even_slices(X.shape[0], n_jobs)
        )
    else:
        raise ValueError("internal: _fit_method not recognized")

    if return_distance:
        dist, neigh_ind = zip(*result)
        result = np.vstack(dist), np.vstack(neigh_ind)
    else:
        result = np.vstack(result)

    if not query_is_train:
        return result
    else:
        # If the query data is the same as the indexed data, we would like
        # to ignore the first nearest neighbor of every sample, i.e
        # the sample itself.
        if return_distance:
            dist, neigh_ind = result
        else:
            neigh_ind = result

        sample_mask = neigh_ind != sample_range

        # Corner case: When the number of duplicates are more
        # than the number of neighbors, the first NN will not
        # be the sample, but a duplicate.
        # In that case mask the first duplicate.
        dup_gr_nbrs = np.all(sample_mask, axis=1)
        sample_mask[:, 0][dup_gr_nbrs] = False

        neigh_ind = np.reshape(neigh_ind[sample_mask], (n_samples, n_neighbors - 1))

        if return_distance:
            dist = np.reshape(dist[sample_mask], (n_samples, n_neighbors - 1))
            return dist, neigh_ind
        return neigh_ind