Issue 1:
We ship two sets of wrappers for the Dierckx FITPACK library: the f2py wrappers,dfitpack, and handwritten _fitpack wrappers. The origin of duplication is long lost to history, likely traces all the way back to when multipack was a thing and numpy and scipy were not (for a historic archive of multipack, see https://github.com/matthew-brett/multipack).

I'd actually be interested in hearing the story behind this.

Both these sets of wrappers wrap the same fortran routines, but have somewhat differing defaults and conventions. Also over time some bug fixes were applied in one set of wrappers but not the other etc. #1408 suggests to get rid of _fitpack in favor of dfitpack. I'm not sure it's really possibly to get rid of it, but at least some deduplication would be a nice housekeeping. This issue is mainly to keep track of this housekeeping, without much urgency and without timing guarantees.

To a first approximation, dfitpack wrappers are used by the OOP interface, *UnivariateSpline and relatives;

_fitpack is used by splXXX routines. But do see below for details.

First, where is what. dfitpack wrappers are in generated by https://github.com/scipy/scipy/blob/main/scipy/interpolate/src/fitpack.pyf, python-level code which ends up in the top level namespace is in _fitpack2.py.

_fitpack wrappers are in https://github.com/scipy/scipy/blob/main/scipy/interpolate/src/_fitpackmodule.c. The route to the top-level namespace is a bit convoluted: splev and related names are imported from _fitpack_py.py; this module is a thin layer which does essentially

if isinstance(tck, BSpline):
# dispatch to BSpline methods
else:
# dispatch to _fitpack_impl

and _fitpack_impl.py is the python layer on top of the _fitpack extension.

Now, which wrappers are used where. Grepping _fitpack2.py shows these routines:

fitpack2
========

from dfitpack
-------------

routine used by

- dfitpack.fpcurf0 -- `UnivariateSpline.__init__`, `InterpolatedUnivariateSpline`
- dfitpack.fpcurf1 -- UnivariateSpline._reset_nest (`__init__`, `_set_smoothing_factor`)
- dfitpack.fpcurfm1 -- `LSQUnivariateSpline.__init__`
- dfitpack.splint -- `UnivariateSpline.integral`
- dfitpack.spalde -- `UnivariateSpline.derivatives`
- dfitpack.sproot -- `UnivariateSpline.roots`
- dfitpack.fpchec -- `LSQUnivariateSpline.__init__`

- dfitpack.parder -- `_BivariateSplineBase.__call__`
- dfitpack.bispev -- `_BivariateSplineBase.__call__`
- dfitpack.pardeu -- `_BivariateSplineBase.__call__`
- dfitpack.bispeu -- `_BivariateSplineBase.__call__`
- dfitpack.pardtc -- `_BivariateSplineBase.partial_derivative__`
- dfitpack.dblint -- `_BivariateSpline.integral`

- dfitpack.surfit_smth -- `SmoothBivariateSpline.__init__`
- dfitpack.surfit_lsq -- `LSQBivariateSpline.__init__`
- dfitpack.regrid_smth -- `RectBivariateSpline.__init__`
- dfitpack.spherefit_smth -- `SmoothSphereBivariateSpline.__init__`
- dfitpack.spherefit_lsq -- `LSQSphereBivariateSpline.__init__`
- dfitpack.regrid_smth_spher -- `RectSphereBivariateSpline.__init__`

from _fitpack_py
----------------

- _fitpack.splev -- `UnivariateSpline.__call__` -- via _fitpack_py.splev -- _fitpack_impl.splev

- splder -- `UnivariateSpline.derivative` --- _fitpack_impl.splder : this is pure python, *not* fitpack.splder!
- splantider -- `UnivariateSpline.antiferivative` --- _fitpack_impl.splantider : this is pure python, too

Note that the UnivariateSpline evaluation goes through _fitpack not dfitpack!

Grepping _fitpack_impl.py shows these:

_fitpack_impl
=============

from dftipack
-------------

- dfitpack.curfit -- `splrep` # do note that curfit.f calls fpcurf, which is wrapped separately for UnivariateSpline
- dfitpack.percur -- `splrep`
- dfitpack.dblint -- `dblint`

from _fitpack
-------------

- _fitpack.parcur -- `splPrep`
- _fitpack._spl_ -- `splev`
- _fitpack._splint -- `splint`
- _fitpack._sproot -- `sproot`
- _fitpack._spalde -- `spalde`
- _fitpack._surfit -- `bisplrep`
- _fitpack._bispev -- `bisplev`
- _fitpack._insert -- `insert`

So, what can be deduplicated. First candidates are splint, sproot and spalde. _fitpack._spl_ is used in both OOP and functional interfaces (which means that dfitpack.splev and dfitpack.splder are not used and not tested --- the swich between splder and splev can be done on the python side I think). Spline construction _fitpack.parcur can probably be replaced by dftipack.parcur but the latter is untested. _fitpack.insert is a curious beast which contains a non-trivial dance with a temporary storage, not sure how to replcate that with f2py.

Things to watch out for when/if deduplicating:

f2py interface insists that len(c) == len(t) : this is not always guaranteed I think, _fitpack allows len(c) == len(t) - k - 1 and ignores trailing elements in c. This restriction should probably be relaxed to len(c) >= len(t) - k - 1.

does f2py allow/undestand non-contiguous arrays, does it copy if not contiguous or it needs to be checked on the python side?

need to carefully check for default values (e.g. the default for s is different IIRC).

Issue 2:
Is it on purpose that these lines are duplicates? If so, a comment to explain why would be welcome.

https://github.com/scipy/scipy/blob/v0.14.0/scipy/stats/stats.py#L3873

https://github.com/scipy/scipy/blob/v0.14.0/scipy/stats/stats.py#L3875