Repository: scipy/scipy

Issue:
DEP: remove extradoc keyword in _distn_infrastructure
Documented as deprecated since https://github.com/scipy/scipy/commit/eb90ace863f0538dcacb67bcf246918037dc298b (scipy 0.10.0!), now with a warning since  #15748 / #15799.


Discussion:

Resolving patch:
diff --git a/scipy/stats/_distn_infrastructure.py b/scipy/stats/_distn_infrastructure.py
--- a/scipy/stats/_distn_infrastructure.py
+++ b/scipy/stats/_distn_infrastructure.py
@@ -605,6 +605,7 @@ class rv_generic:
     and rv_continuous.
 
     """
+
     def __init__(self, seed=None):
         super().__init__()
 
@@ -791,18 +792,14 @@ def _construct_doc(self, docdict, shapes_vals=None):
         # correct for empty shapes
         self.__doc__ = self.__doc__.replace('(, ', '(').replace(', )', ')')
 
-    def _construct_default_doc(self, longname=None, extradoc=None,
+    def _construct_default_doc(self, longname=None,
                                docdict=None, discrete='continuous'):
         """Construct instance docstring from the default template."""
         if longname is None:
             longname = 'A'
-        if extradoc is None:
-            extradoc = ''
-        if extradoc.startswith('\n\n'):
-            extradoc = extradoc[2:]
         self.__doc__ = ''.join(['%s %s random variable.' % (longname, discrete),
                                 '\n\n%(before_notes)s\n', docheaders['notes'],
-                                extradoc, '\n%(example)s'])
+                                '\n%(example)s'])
         self._construct_doc(docdict)
 
     def freeze(self, *args, **kwds):
@@ -1613,11 +1610,6 @@ class rv_continuous(rv_generic):
         its methods. If not provided, shape parameters will be inferred from
         the signature of the private methods, ``_pdf`` and ``_cdf`` of the
         instance.
-    extradoc :  str, optional, deprecated
-        This string is used as the last part of the docstring returned when a
-        subclass has no docstring of its own. Note: `extradoc` exists for
-        backwards compatibility and will be removed in SciPy 1.11.0, do not
-        use for new subclasses.
     seed : {None, int, `numpy.random.Generator`, `numpy.random.RandomState`}, optional
         If `seed` is None (or `np.random`), the `numpy.random.RandomState`
         singleton is used.
@@ -1771,21 +1763,18 @@ class rv_continuous(rv_generic):
     ``gaussian._pdf(y) / scale``.
 
     """
+
     def __init__(self, momtype=1, a=None, b=None, xtol=1e-14,
                  badvalue=None, name=None, longname=None,
-                 shapes=None, extradoc=None, seed=None):
+                 shapes=None, seed=None):
 
         super().__init__(seed)
 
-        if extradoc is not None:
-            warnings.warn("extradoc is deprecated and will be removed in "
-                          "SciPy 1.11.0", DeprecationWarning)
-
         # save the ctor parameters, cf generic freeze
         self._ctor_param = dict(
             momtype=momtype, a=a, b=b, xtol=xtol,
             badvalue=badvalue, name=name, longname=longname,
-            shapes=shapes, extradoc=extradoc, seed=seed)
+            shapes=shapes, seed=seed)
 
         if badvalue is None:
             badvalue = nan
@@ -1802,7 +1791,6 @@ def __init__(self, momtype=1, a=None, b=None, xtol=1e-14,
         self.xtol = xtol
         self.moment_type = momtype
         self.shapes = shapes
-        self.extradoc = extradoc
 
         self._construct_argparser(meths_to_inspect=[self._pdf, self._cdf],
                                   locscale_in='loc=0, scale=1',
@@ -1820,7 +1808,6 @@ def __init__(self, momtype=1, a=None, b=None, xtol=1e-14,
             # Skip adding docstrings if interpreter is run with -OO
             if self.__doc__ is None:
                 self._construct_default_doc(longname=longname,
-                                            extradoc=extradoc,
                                             docdict=docdict,
                                             discrete='continuous')
             else:
@@ -1872,7 +1859,6 @@ def _updated_ctor_param(self):
         dct['badvalue'] = self.badvalue
         dct['name'] = self.name
         dct['shapes'] = self.shapes
-        dct['extradoc'] = self.extradoc
         return dct
 
     def _ppf_to_solve(self, x, q, *args):
@@ -2946,11 +2932,6 @@ class rv_discrete(rv_generic):
         If not provided, shape parameters will be inferred from
         the signatures of the private methods, ``_pmf`` and ``_cdf`` of
         the instance.
-    extradoc :  str, optional, deprecated
-        This string is used as the last part of the docstring returned when a
-        subclass has no docstring of its own. Note: `extradoc` exists for
-        backwards compatibility and will be removed in SciPy 1.11.0, do not
-        use for new subclasses.
     seed : {None, int, `numpy.random.Generator`, `numpy.random.RandomState`}, optional
         If `seed` is None (or `np.random`), the `numpy.random.RandomState`
         singleton is used.
@@ -3042,7 +3023,7 @@ class rv_discrete(rv_generic):
     """
     def __new__(cls, a=0, b=inf, name=None, badvalue=None,
                 moment_tol=1e-8, values=None, inc=1, longname=None,
-                shapes=None, extradoc=None, seed=None):
+                shapes=None, seed=None):
 
         if values is not None:
             # dispatch to a subclass
@@ -3053,19 +3034,15 @@ def __new__(cls, a=0, b=inf, name=None, badvalue=None,
 
     def __init__(self, a=0, b=inf, name=None, badvalue=None,
                  moment_tol=1e-8, values=None, inc=1, longname=None,
-                 shapes=None, extradoc=None, seed=None):
+                 shapes=None, seed=None):
 
         super().__init__(seed)
 
-        if extradoc is not None:
-            warnings.warn("extradoc is deprecated and will be removed in "
-                          "SciPy 1.11.0", DeprecationWarning)
-
         # cf generic freeze
         self._ctor_param = dict(
             a=a, b=b, name=name, badvalue=badvalue,
             moment_tol=moment_tol, values=values, inc=inc,
-            longname=longname, shapes=shapes, extradoc=extradoc, seed=seed)
+            longname=longname, shapes=shapes, seed=seed)
 
         if badvalue is None:
             badvalue = nan
@@ -3084,7 +3061,7 @@ def __init__(self, a=0, b=inf, name=None, badvalue=None,
                                   # scale=1 for discrete RVs
                                   locscale_out='loc, 1')
         self._attach_methods()
-        self._construct_docstrings(name, longname, extradoc)
+        self._construct_docstrings(name, longname)
 
     def __getstate__(self):
         dct = self.__dict__.copy()
@@ -3116,11 +3093,10 @@ def _attach_methods(self):
         # now that self.numargs is defined, we can adjust nin
         self._cdfvec.nin = self.numargs + 1
 
-    def _construct_docstrings(self, name, longname, extradoc):
+    def _construct_docstrings(self, name, longname):
         if name is None:
             name = 'Distribution'
         self.name = name
-        self.extradoc = extradoc
 
         # generate docstring for subclass instances
         if longname is None:
@@ -3134,7 +3110,6 @@ def _construct_docstrings(self, name, longname, extradoc):
             # Skip adding docstrings if interpreter is run with -OO
             if self.__doc__ is None:
                 self._construct_default_doc(longname=longname,
-                                            extradoc=extradoc,
                                             docdict=docdict_discrete,
                                             discrete='discrete')
             else:
@@ -3160,7 +3135,6 @@ def _updated_ctor_param(self):
         dct['inc'] = self.inc
         dct['name'] = self.name
         dct['shapes'] = self.shapes
-        dct['extradoc'] = self.extradoc
         return dct
 
     def _nonzero(self, k, *args):
@@ -3742,16 +3716,13 @@ class rv_sample(rv_discrete):
 
     The ctor ignores most of the arguments, only needs the `values` argument.
     """
+
     def __init__(self, a=0, b=inf, name=None, badvalue=None,
                  moment_tol=1e-8, values=None, inc=1, longname=None,
-                 shapes=None, extradoc=None, seed=None):
+                 shapes=None, seed=None):
 
         super(rv_discrete, self).__init__(seed)
 
-        if extradoc is not None:
-            warnings.warn("extradoc is deprecated and will be removed in "
-                          "SciPy 1.11.0", DeprecationWarning)
-
         if values is None:
             raise ValueError("rv_sample.__init__(..., values=None,...)")
 
@@ -3759,7 +3730,7 @@ def __init__(self, a=0, b=inf, name=None, badvalue=None,
         self._ctor_param = dict(
             a=a, b=b, name=name, badvalue=badvalue,
             moment_tol=moment_tol, values=values, inc=inc,
-            longname=longname, shapes=shapes, extradoc=extradoc, seed=seed)
+            longname=longname, shapes=shapes, seed=seed)
 
         if badvalue is None:
             badvalue = nan
@@ -3795,7 +3766,7 @@ def __init__(self, a=0, b=inf, name=None, badvalue=None,
 
         self._attach_methods()
 
-        self._construct_docstrings(name, longname, extradoc)
+        self._construct_docstrings(name, longname)
 
     def __getstate__(self):
         dct = self.__dict__.copy()


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
@@ -5983,12 +5983,6 @@ def test_540_567():
                         decimal=10, err_msg='test_540_567')
 
 
-def test_regression_ticket_1316():
-    # The following was raising an exception, because _construct_default_doc()
-    # did not handle the default keyword extradoc=None.  See ticket #1316.
-    stats._continuous_distns.gamma_gen(name='gamma')
-
-
 def test_regression_ticket_1326():
     # adjust to avoid nan with 0*log(0)
     assert_almost_equal(stats.chi2.pdf(0.0, 2), 0.5, 14)