If self.kernel is callable here, it get's interpreted as a metric (or the kernel function k(x_i, x_j) that computes one entry in the kernel matrix). It's probably better to interpret it as the function that computes the whole kernel matrix, e.g. change the line to
    return self.kernel(X, Y, **kernel_params)
Since most kernels can be computed more effectively than looping through all entries, this would allow more efficient and more general solutions. I'm not very familiar with the other scikit-learn methods but they seem to have a different behavior, too.