Wraps Metropolis step methods so they can handle extended parents of
    Gaussian processes.

def wrap_metropolis_for_gp_parents(metro_class):
    """
    Wraps Metropolis step methods so they can handle extended parents of
    Gaussian processes.
    """
    class wrapper(metro_class):
        __doc__ = """A modified version of class %s that handles parents of Gaussian processes.
Docstring of class %s: \n\n%s""" % (metro_class.__name__, metro_class.__name__, metro_class.__doc__)

        def __init__(self, stochastic, *args, **kwds):

            self.metro_class.__init__(self, stochastic, *args, **kwds)

            mb = set(self.markov_blanket)
            for c in list(self.children):
                if isinstance(c, GaussianProcess):
                    self.children |= c.extended_children
                    mb |= c.extended_children
            self.markov_blanket = list(mb)

            # Remove f from the set that will be used to compute
            # logp_plus_loglike.
            self.markov_blanket_no_f = set(
                filter(
                    lambda x: not isinstance(
                        x,
                        GaussianProcess),
                    self.markov_blanket))
            self.fs = filter(
                lambda x: isinstance(
                    x,
                    GaussianProcess),
                self.markov_blanket)
            self.fr_checks = [f.submodel.fr_check for f in self.fs]

        def get_logp_plus_loglike(self):
            return pm.logp_of_set(self.markov_blanket_no_f)
        logp_plus_loglike = property(get_logp_plus_loglike)

        def propose(self):
            self.metro_class.propose(self)
            try:
                # First make sure none of the stochastics handled by
                # metro_method forbid their current values.
                for s in self.stochastics:
                    s.logp
                # Then make sure the covariances are all still full-rank on the
                # observation locations.
                for frc in self.fr_checks:
                    frc.logp
                for f in self.fs:
                    f.rand()
                self.f_proposed = True
            except pm.ZeroProbability:
                self.f_proposed = False

        def reject(self):
            self.metro_class.reject(self)
            if self.f_proposed:
                for f in self.fs:
                    f.revert()

        @staticmethod
        def competence(stochastic, metro_class=metro_class):
            if any([isinstance(child, GaussianProcess)
                    for child in stochastic.extended_children]):
                return metro_class.competence(stochastic) + .01
            else:
                return 0

    wrapper.__name__ = 'GPParent%s' % metro_class.__name__
    wrapper.metro_class = metro_class

    return wrapper