Repository: scipy/scipy

Issue:
DEP: deprecate and remove remaining usages of slur-adjacent "trapz"
I am not finding any other appearances of these terms except for `trapz`, which is still allowed as an alias for the trapezoidal distribution and as a `method` option of `quad_vec`. (Those uses don't appear to have been deprecated.)

_Originally posted by @mdhaber in https://github.com/scipy/scipy/pull/20278#pullrequestreview-1944140754_
            


Discussion:
I will address this before the next release if nobody gets there first
thanks @h-vetinari 

> which is still allowed as an alias for the trapezoidal distribution

IIRC we kept it as an undocumented alias when introducing `trapezoidal` to avoid users having to write if-else constructs depending on SciPy version. That is quite a few releases ago, so +1 for the proposal deprecations now.
I'm going to close this one as fixed by #20716; we'll track removal in the deprecation meta-issue.
@h-vetinari the alias for the trapezoidal distribution still remains
Yes, but it got deprecated, which is what this issue was about. I also said that the actual removal (after two releases) can be tracked in the meta-issue.

So I don't see what purpose this issue still serves. 
Only the `quad_vec` portion has been deprecated there is a statistical distribution that remains to be deprecated
https://github.com/scipy/scipy/blob/6e393bcf9759d7608e4a78ca227c92744ee0db71/scipy/stats/_continuous_distns.py#L9687-L9691
Ugh. Why are we not doing these at the same time. Let's deprecate both in 1.14 please 
> Ugh. Why are we not doing these at the same time. Let's deprecate both in 1.14 please

Politely, I would ask in the future you consider the tone of such comments.
The point is not to separate things that go together. If you do one without the other (like for the `special.comb` thing as well), it just creates yet more work. I don't mind _when_ these things land, but it's pointless to split the same deprecation across PRs, much less releases. Let's avoid half measures.

Resolving patch:
diff --git a/scipy/stats/_continuous_distns.py b/scipy/stats/_continuous_distns.py
--- a/scipy/stats/_continuous_distns.py
+++ b/scipy/stats/_continuous_distns.py
@@ -9683,12 +9683,51 @@ def _entropy(self, c, d):
         return 0.5 * (1.0-d+c) / (1.0+d-c) + np.log(0.5 * (1.0+d-c))
 
 
+# deprecation of trapz, see #20486
+deprmsg = ("`trapz` is deprecated in favour of `trapezoid` "
+           "and will be removed in SciPy 1.16.0.")
+
+
+class trapz_gen(trapezoid_gen):
+    # override __call__ protocol from rv_generic to also
+    # deprecate instantiation of frozen distributions
+    """
+
+    .. deprecated:: 1.14.0
+        `trapz` is deprecated and will be removed in SciPy 1.16.
+        Plese use `trapezoid` instead!
+    """
+    def __call__(self, *args, **kwds):
+        warnings.warn(deprmsg, DeprecationWarning, stacklevel=2)
+        return self.freeze(*args, **kwds)
+
+
 trapezoid = trapezoid_gen(a=0.0, b=1.0, name="trapezoid")
-# Note: alias kept for backwards compatibility. Rename was done
-# because trapz is a slur in colloquial English (see gh-12924).
-trapz = trapezoid_gen(a=0.0, b=1.0, name="trapz")
-if trapz.__doc__:
-    trapz.__doc__ = "trapz is an alias for `trapezoid`"
+trapz = trapz_gen(a=0.0, b=1.0, name="trapz")
+
+# since the deprecated class gets intantiated upon import (and we only want to
+# warn upon use), add the deprecation to each class method
+_method_names = [
+    "cdf", "entropy", "expect", "fit", "interval", "isf", "logcdf", "logpdf",
+    "logsf", "mean", "median", "moment", "pdf", "ppf", "rvs", "sf", "stats",
+    "std", "var"
+]
+
+
+class _DeprecationWrapper:
+    def __init__(self, method):
+        self.msg = (f"`trapz.{method}` is deprecated in favour of trapezoid.{method}. "
+                     "Please replace all uses of the distribution class "
+                     "`trapz` with `trapezoid`. `trapz` will be removed in SciPy 1.16.")
+        self.method = getattr(trapezoid, method)
+    
+    def __call__(self, *args, **kwargs):
+        warnings.warn(self.msg, DeprecationWarning, stacklevel=2)
+        return self.method(*args, **kwargs)
+
+
+for m in _method_names:
+    setattr(trapz, m, _DeprecationWrapper(m))
 
 
 class triang_gen(rv_continuous):


Test patch:
diff --git a/scipy/stats/tests/test_distributions.py b/scipy/stats/tests/test_distributions.py
--- a/scipy/stats/tests/test_distributions.py
+++ b/scipy/stats/tests/test_distributions.py
@@ -7338,7 +7338,20 @@ def test_trapezoid_vect(self):
     def test_trapz(self):
         # Basic test for alias
         x = np.linspace(0, 1, 10)
-        assert_almost_equal(stats.trapz.pdf(x, 0, 1), stats.uniform.pdf(x))
+        with pytest.deprecated_call(match="`trapz.pdf` is deprecated"):
+            result = stats.trapz.pdf(x, 0, 1)
+        assert_almost_equal(result, stats.uniform.pdf(x))
+
+    @pytest.mark.parametrize('method', ['pdf', 'logpdf', 'cdf', 'logcdf',
+                                        'sf', 'logsf', 'ppf', 'isf'])
+    def test_trapz_deprecation(self, method):
+        c, d = 0.2, 0.8
+        expected = getattr(stats.trapezoid, method)(1, c, d)
+        with pytest.deprecated_call(
+            match=f"`trapz.{method}` is deprecated",
+        ):
+            result = getattr(stats.trapz, method)(1, c, d)
+        assert result == expected
 
 
 class TestTriang: