Repository: scipy/scipy
File: scipy/stats/_distribution_infrastructure.py (Python)

Code before:

    Create a custom distribution with multiple parameterizations. Here we create a
    custom version of the Beta distribution that has an alternative parameterization
    in terms of the mean ``mu`` and a dispersion parameter ``nu``.

    >>> class MyBeta:
    ...     @property
    ...     def __make_distribution_version__(self):
    ...         return "1.16.0"
    ...
    ...     @property
    ...     def parameters(self):
    ...         return (
    ...             {"a": (0, np.inf), "b": (0, np.inf)},
    ...             {"mu": (0, np.inf), "nu": (0, np.inf)},
    ...         )
    ...
    ...     def _process_parameters(self, a=None, b=None, mu=None, nu=None):
    ...         if a is not None and b is not None and mu is None and nu is None:
    ...             nu = a + b
    ...             mu = a / nu
    ...         elif mu is not None and nu is not None and a is None and b is None:
    ...             a = mu * nu
    ...             b = nu - a
    ...         else:
    ...             raise ValueError("Invalid parameterization of MyBeta.")
    ...         return {"a": a, "b": b, "mu": mu, "nu": nu}
    ...
    ...     @property
    ...     def support(self):
    ...         return {'endpoints': (0, 1)}
    ...
    ...     def pdf(self, x, a, b, mu, nu):
    ...         return special._ufuncs._beta_pdf(x, a, b)
    ...
    ...     def cdf(self, x, a, b, mu, nu):
    ...         return special.betainc(a, b, x)
    >>>
    >>> MyBeta = stats.make_distribution(MyBeta())
    >>> X = MyBeta(a=2.0, b=2.0)
    >>> Y = MyBeta(mu=0.5, nu=4.0)
    >>> np.isclose(X.pdf(0.3), Y.pdf(0.3))
    np.True_

    """
    if dist in {stats.levy_stable, stats.vonmises}:
        raise NotImplementedError(f"`{dist.name}` is not supported.")

    if isinstance(dist, stats.rv_continuous):
        return _make_distribution_rv_generic(dist)
    elif getattr(dist, "__make_distribution_version__", "0.0.0") >= "1.16.0":

Review comment (suggestion):
Are you sure this is needed? The infrastructure should raise before getting here unless either (`a` and `b` are provided) OR (`mu` and `nu` are provided). See e.g.:
```python3
from scipy.stats._new_distributions import _LogUniform
_LogUniform(a=1, b=10).entropy()  # np.float64(1.9853249917449787)
_LogUniform(log_a=0, log_b=np.log(10)).entropy()  # np.float64(1.9853249917449787)
_LogUniform(log_a=0, b=np.log(10)).entropy()
# ValueError: The provided parameters `{b, log_a}` do not match a supported parameterization of the `_LogUniform` distribution family.
```
So you really should only have to do `if a is not None` and `else`, really.

Code after:
    >>> class MyBeta:
    ...     @property
    ...     def __make_distribution_version__(self):
    ...         return "1.16.0"
    ...
    ...     @property
    ...     def parameters(self):
    ...         return ({"a": (0, np.inf), "b": (0, np.inf)},
    ...                 {"mu": (0, 1), "nu": (0, np.inf)})
    ...
    ...     def process_parameters(self, a=None, b=None, mu=None, nu=None):
    ...         if a is not None and b is not None:
    ...             nu = a + b
    ...             mu = a / nu
    ...         else:
    ...             a = mu * nu
    ...             b = nu - a
    ...         return dict(a=a, b=b, mu=mu, nu=nu)
    ...
    ...     @property
    ...     def support(self):
    ...         return {'endpoints': (0, 1)}
    ...
    ...     def pdf(self, x, a, b, mu, nu):
    ...         return special._ufuncs._beta_pdf(x, a, b)
    ...
    ...     def cdf(self, x, a, b, mu, nu):
    ...         return special.betainc(a, b, x)
    >>>
    >>> MyBeta = stats.make_distribution(MyBeta())
    >>> X = MyBeta(a=2.0, b=2.0)
    >>> Y = MyBeta(mu=0.5, nu=4.0)
    >>> np.isclose(X.pdf(0.3), Y.pdf(0.3))
    np.True_

    """
    if dist in {stats.levy_stable, stats.vonmises}:
        raise NotImplementedError(f"`{dist.name}` is not supported.")

    if isinstance(dist, stats.rv_continuous):
        return _make_distribution_rv_generic(dist)
    elif getattr(dist, "__make_distribution_version__", "0.0.0") >= "1.16.0":
        return _make_distribution_custom(dist)
    else:
        message = ("The argument must be an instance of `rv_continuous` or an instance "
                   "of a class with attribute `__make_distribution_version__ >= 1.16`.")
        raise ValueError(message)


def _make_distribution_rv_generic(dist):
    parameters = []