#!/usr/bin/env python
import sys
import importlib
import types
import warnings

from numpydoc.validate import validate

from scipy._lib._public_api import PUBLIC_MODULES


skip_errors = [
    "GL01",  # inconsistent standards; see gh-24348
    "GL02",  # inconsistent standards; see gh-24348
    "GL03",  # overlaps with GL02; see gh-24348
    "GL09",
    "SS05",  # inconsistent standards; see gh-24348
    "SS06",
    "ES01",
    "PR08",
    "PR09",
    "RT02",  # questionable rule; see gh-24348
    "RT04",
    "RT05",
    "SA01",  # questionable rule; see gh-24348
    "SA02",
    "SA03",
    "SA04",
    "EX01",  # remove when gh-7168 is resolved
]


compiled_code_skips = {  # compiled code ignores "numpydoc ignore=" comments"
    "scipy.spatial.cKDTree" : ["SS02"],
    # TODO: the following ufuncs do not have a `__signature__`, this is worth fixing
    # for various typing and introspection reasons. One possible fix is to follow the
    # pattern used in https://github.com/numpy/numpy/pull/30211
    "scipy.special.agm" : ['PR02', 'PR01'],
    "scipy.special.bdtr" : ['PR02', 'PR01'],
    "scipy.special.bdtrc" : ['PR02', 'PR01'],
    "scipy.special.bdtri" : ['PR02', 'PR01'],
    "scipy.special.bdtrik" : ['PR02', 'PR01'],
    "scipy.special.bdtrin" : ['PR02', 'PR01'],
    "scipy.special.betainc" : ['PR02', 'PR01'],
    "scipy.special.betaincc" : ['PR02', 'PR01'],
    "scipy.special.betainccinv" : ['PR02', 'PR01'],
    "scipy.special.betaincinv" : ['PR02', 'PR01'],
    "scipy.special.boxcox" : ['PR02', 'PR01'],
    "scipy.special.boxcox1p" : ['PR02', 'PR01'],
    "scipy.special.btdtria" : ['PR02', 'PR01'],
    "scipy.special.btdtrib" : ['PR02', 'PR01'],
    "scipy.special.chdtr" : ['PR02', 'PR01'],
    "scipy.special.chdtrc" : ['PR02', 'PR01'],
    "scipy.special.chdtri" : ['PR02', 'PR01'],
    "scipy.special.chdtriv" : ['PR02', 'PR01'],
    "scipy.special.chndtr" : ['PR02', 'PR01'],
    "scipy.special.chndtridf" : ['PR02', 'PR01'],
    "scipy.special.chndtrinc" : ['PR02', 'PR01'],
    "scipy.special.chndtrix" : ['PR02', 'PR01'],
    "scipy.special.elliprc" : ['PR02', 'PR01'],
    "scipy.special.elliprd" : ['PR02', 'PR01'],
    "scipy.special.elliprf" : ['PR02', 'PR01'],
    "scipy.special.elliprg" : ['PR02', 'PR01'],
    "scipy.special.elliprj" : ['PR02', 'PR01'],
    "scipy.special.entr" : ['PR02', 'PR01'],
    "scipy.special.erfcinv" : ['PR02', 'PR01'],
    "scipy.special.erfinv" : ['PR02', 'PR01'],
    "scipy.special.eval_chebyc" : ['PR02', 'PR01'],
    "scipy.special.eval_chebys" : ['PR02', 'PR01'],
    "scipy.special.eval_chebyt" : ['PR02', 'PR01'],
    "scipy.special.eval_chebyu" : ['PR02', 'PR01'],
    "scipy.special.eval_gegenbauer" : ['PR02', 'PR01'],
    "scipy.special.eval_genlaguerre" : ['PR02', 'PR01'],
    "scipy.special.eval_hermite" : ['PR02', 'PR01'],
    "scipy.special.eval_hermitenorm" : ['PR02', 'PR01'],
    "scipy.special.eval_jacobi" : ['PR02', 'PR01'],
    "scipy.special.eval_laguerre" : ['PR02', 'PR01'],
    "scipy.special.eval_legendre" : ['PR02', 'PR01'],
    "scipy.special.eval_sh_chebyt" : ['PR02', 'PR01'],
    "scipy.special.eval_sh_chebyu" : ['PR02', 'PR01'],
    "scipy.special.eval_sh_jacobi" : ['PR02', 'PR01'],
    "scipy.special.eval_sh_legendre" : ['PR02', 'PR01'],
    "scipy.special.expn" : ['PR02', 'PR01'],
    "scipy.special.fdtr" : ['PR02', 'PR01'],
    "scipy.special.fdtrc" : ['PR02', 'PR01'],
    "scipy.special.fdtri" : ['PR02', 'PR01'],
    "scipy.special.fdtridfd" : ['PR02', 'PR01'],
    "scipy.special.gdtr" : ['PR02', 'PR01'],
    "scipy.special.gdtrc" : ['PR02', 'PR01'],
    "scipy.special.gdtria" : ['PR02', 'PR01'],
    "scipy.special.gdtrib" : ['PR02', 'PR01'],
    "scipy.special.gdtrix" : ['PR02', 'PR01'],
    "scipy.special.huber" : ['PR02', 'PR01'],
    "scipy.special.hyp0f1" : ['PR02', 'PR01'],
    "scipy.special.hyp1f1" : ['PR02', 'PR01'],
    "scipy.special.hyperu" : ['PR02', 'PR01'],
    "scipy.special.inv_boxcox" : ['PR02', 'PR01'],
    "scipy.special.inv_boxcox1p" : ['PR02', 'PR01'],
    "scipy.special.kl_div" : ['PR02', 'PR01'],
    "scipy.special.kn" : ['PR02', 'PR01'],
    "scipy.special.kolmogi" : ['PR02', 'PR01'],
    "scipy.special.kolmogorov" : ['PR02', 'PR01'],
    "scipy.special.lpmv" : ['PR02', 'PR01'],
    "scipy.special.nbdtr" : ['PR02', 'PR01'],
    "scipy.special.nbdtrc" : ['PR02', 'PR01'],
    "scipy.special.nbdtri" : ['PR02', 'PR01'],
    "scipy.special.nbdtrik" : ['PR02', 'PR01'],
    "scipy.special.nbdtrin" : ['PR02', 'PR01'],
    "scipy.special.ncfdtr" : ['PR02', 'PR01'],
    "scipy.special.ncfdtri" : ['PR02', 'PR01'],
    "scipy.special.ncfdtridfd" : ['PR02', 'PR01'],
    "scipy.special.ncfdtridfn" : ['PR02', 'PR01'],
    "scipy.special.ncfdtrinc" : ['PR02', 'PR01'],
    "scipy.special.nctdtr" : ['PR02', 'PR01'],
    "scipy.special.nctdtridf" : ['PR02', 'PR01'],
    "scipy.special.nctdtrinc" : ['PR02', 'PR01'],
    "scipy.special.nctdtrit" : ['PR02', 'PR01'],
    "scipy.special.ndtri" : ['PR02', 'PR01'],
    "scipy.special.ndtri_exp" : ['PR02', 'PR01'],
    "scipy.special.nrdtrimn" : ['PR02', 'PR01'],
    "scipy.special.nrdtrisd" : ['PR02', 'PR01'],
    "scipy.special.owens_t" : ['PR02', 'PR01'],
    "scipy.special.pdtr" : ['PR02', 'PR01'],
    "scipy.special.pdtrc" : ['PR02', 'PR01'],
    "scipy.special.pdtri" : ['PR02', 'PR01'],
    "scipy.special.pdtrik" : ['PR02', 'PR01'],
    "scipy.special.poch" : ['PR02', 'PR01'],
    "scipy.special.powm1" : ['PR02', 'PR01'],
    "scipy.special.pseudo_huber" : ['PR02', 'PR01'],
    "scipy.special.rel_entr" : ['PR02', 'PR01'],
    "scipy.special.round" : ['PR02', 'PR01'],
    "scipy.special.shichi" : ['PR02', 'PR01'],
    "scipy.special.sici" : ['PR02', 'PR01'],
    "scipy.special.smirnov" : ['PR02', 'PR01'],
    "scipy.special.smirnovi" : ['PR02', 'PR01'],
    "scipy.special.spence" : ['PR02', 'PR01'],
    "scipy.special.stdtr" : ['PR02', 'PR01'],
    "scipy.special.stdtridf" : ['PR02', 'PR01'],
    "scipy.special.stdtrit" : ['PR02', 'PR01'],
    "scipy.special.tklmbda" : ['PR02', 'PR01'],
    "scipy.special.wrightomega" : ['PR02', 'PR01'],
    "scipy.special.yn" : ['PR02', 'PR01'],
    "scipy.special.jn" : ['PR02', 'PR01'],
    "scipy.special.airy" : ['PR02', 'PR01'],
    "scipy.special.airye" : ['PR02', 'PR01'],
    "scipy.special.bei" : ['PR02', 'PR01'],
    "scipy.special.beip" : ['PR02', 'PR01'],
    "scipy.special.ber" : ['PR02', 'PR01'],
    "scipy.special.berp" : ['PR02', 'PR01'],
    "scipy.special.binom" : ['PR02', 'PR01'],
    "scipy.special.exp1" : ['PR02', 'PR01'],
    "scipy.special.expi" : ['PR02', 'PR01'],
    "scipy.special.expit" : ['PR02', 'PR01'],
    "scipy.special.exprel" : ['PR02', 'PR01'],
    "scipy.special.gamma" : ['PR02', 'PR01'],
    "scipy.special.gammaln" : ['PR02', 'PR01'],
    "scipy.special.hankel1" : ['PR02', 'PR01'],
    "scipy.special.hankel1e" : ['PR02', 'PR01'],
    "scipy.special.hankel2" : ['PR02', 'PR01'],
    "scipy.special.hankel2e" : ['PR02', 'PR01'],
    "scipy.special.hyp2f1" : ['PR02', 'PR01'],
    "scipy.special.it2i0k0" : ['PR02', 'PR01'],
    "scipy.special.it2j0y0" : ['PR02', 'PR01'],
    "scipy.special.it2struve0" : ['PR02', 'PR01'],
    "scipy.special.itairy" : ['PR02', 'PR01'],
    "scipy.special.iti0k0" : ['PR02', 'PR01'],
    "scipy.special.itj0y0" : ['PR02', 'PR01'],
    "scipy.special.itmodstruve0" : ['PR02', 'PR01'],
    "scipy.special.itstruve0" : ['PR02', 'PR01'],
    "scipy.special.iv" : ['PR02', 'PR01'],
    "scipy.special.ive" : ['PR02', 'PR01'],
    "scipy.special.jv" : ['PR02', 'PR01'],
    "scipy.special.jve" : ['PR02', 'PR01'],
    "scipy.special.kei" : ['PR02', 'PR01'],
    "scipy.special.keip" : ['PR02', 'PR01'],
    "scipy.special.kelvin" : ['PR02', 'PR01'],
    "scipy.special.ker" : ['PR02', 'PR01'],
    "scipy.special.kerp" : ['PR02', 'PR01'],
    "scipy.special.kv" : ['PR02', 'PR01'],
    "scipy.special.kve" : ['PR02', 'PR01'],
    "scipy.special.log_expit" : ['PR02', 'PR01'],
    "scipy.special.log_wright_bessel" : ['PR02', 'PR01'],
    "scipy.special.loggamma" : ['PR02', 'PR01'],
    "scipy.special.logit" : ['PR02', 'PR01'],
    "scipy.special.mathieu_a" : ['PR02', 'PR01'],
    "scipy.special.mathieu_b" : ['PR02', 'PR01'],
    "scipy.special.mathieu_cem" : ['PR02', 'PR01'],
    "scipy.special.mathieu_modcem1" : ['PR02', 'PR01'],
    "scipy.special.mathieu_modcem2" : ['PR02', 'PR01'],
    "scipy.special.mathieu_modsem1" : ['PR02', 'PR01'],
    "scipy.special.mathieu_modsem2" : ['PR02', 'PR01'],
    "scipy.special.mathieu_sem" : ['PR02', 'PR01'],
    "scipy.special.modfresnelm" : ['PR02', 'PR01'],
    "scipy.special.modfresnelp" : ['PR02', 'PR01'],
    "scipy.special.obl_ang1" : ['PR02', 'PR01'],
    "scipy.special.obl_ang1_cv" : ['PR02', 'PR01'],
    "scipy.special.obl_cv" : ['PR02', 'PR01'],
    "scipy.special.obl_rad1" : ['PR02', 'PR01'],
    "scipy.special.obl_rad1_cv" : ['PR02', 'PR01'],
    "scipy.special.obl_rad2" : ['PR02', 'PR01'],
    "scipy.special.obl_rad2_cv" : ['PR02', 'PR01'],
    "scipy.special.pbdv" : ['PR02', 'PR01'],
    "scipy.special.pbvv" : ['PR02', 'PR01'],
    "scipy.special.pbwa" : ['PR02', 'PR01'],
    "scipy.special.pro_ang1" : ['PR02', 'PR01'],
    "scipy.special.pro_ang1_cv" : ['PR02', 'PR01'],
    "scipy.special.pro_cv" : ['PR02', 'PR01'],
    "scipy.special.pro_rad1" : ['PR02', 'PR01'],
    "scipy.special.pro_rad1_cv" : ['PR02', 'PR01'],
    "scipy.special.pro_rad2" : ['PR02', 'PR01'],
    "scipy.special.pro_rad2_cv" : ['PR02', 'PR01'],
    "scipy.special.psi" : ['PR02', 'PR01'],
    "scipy.special.rgamma" : ['PR02', 'PR01'],
    "scipy.special.wright_bessel" : ['PR02', 'PR01'],
    "scipy.special.yv" : ['PR02', 'PR01'],
    "scipy.special.yve" : ['PR02', 'PR01'],
    "scipy.special.zetac" : ['PR02', 'PR01'],
    "scipy.special.sindg" : ['PR02', 'PR01'],
    "scipy.special.cosdg" : ['PR02', 'PR01'],
    "scipy.special.tandg" : ['PR02', 'PR01'],
    "scipy.special.cotdg" : ['PR02', 'PR01'],
    "scipy.special.i0" : ['PR02', 'PR01'],
    "scipy.special.i0e" : ['PR02', 'PR01'],
    "scipy.special.i1" : ['PR02', 'PR01'],
    "scipy.special.i1e" : ['PR02', 'PR01'],
    "scipy.special.k0" : ['PR02', 'PR01'],
    "scipy.special.k0e" : ['PR02', 'PR01'],
    "scipy.special.k1" : ['PR02', 'PR01'],
    "scipy.special.k1e" : ['PR02', 'PR01'],
    "scipy.special.y0" : ['PR02', 'PR01'],
    "scipy.special.y1" : ['PR02', 'PR01'],
    "scipy.special.j0" : ['PR02', 'PR01'],
    "scipy.special.j1" : ['PR02', 'PR01'],
    "scipy.special.struve" : ['PR02', 'PR01'],
    "scipy.special.modstruve" : ['PR02', 'PR01'],
    "scipy.special.beta" : ['PR02', 'PR01'],
    "scipy.special.betaln" : ['PR02', 'PR01'],
    "scipy.special.besselpoly" : ['PR02', 'PR01'],
    "scipy.special.gammasgn" : ['PR02', 'PR01'],
    "scipy.special.cbrt" : ['PR02', 'PR01'],
    "scipy.special.radian" : ['PR02', 'PR01'],
    "scipy.special.cosm1" : ['PR02', 'PR01'],
    "scipy.special.gammainc" : ['PR02', 'PR01'],
    "scipy.special.gammaincinv" : ['PR02', 'PR01'],
    "scipy.special.gammaincc" : ['PR02', 'PR01'],
    "scipy.special.gammainccinv" : ['PR02', 'PR01'],
    "scipy.special.fresnel" : ['PR02', 'PR01'],
    "scipy.special.ellipe" : ['PR02', 'PR01'],
    "scipy.special.ellipeinc" : ['PR02', 'PR01'],
    "scipy.special.ellipk" : ['PR02', 'PR01'],
    "scipy.special.ellipkinc" : ['PR02', 'PR01'],
    "scipy.special.ellipkm1" : ['PR02', 'PR01'],
    "scipy.special.ellipj" : ['PR02', 'PR01'],
    "scipy.special.erf" : ['PR02', 'PR01'],
    "scipy.special.erfc" : ['PR02', 'PR01'],
    "scipy.special.erfcx" : ['PR02', 'PR01'],
    "scipy.special.erfi" : ['PR02', 'PR01'],
    "scipy.special.voigt_profile" : ['PR02', 'PR01'],
    "scipy.special.wofz" : ['PR02', 'PR01'],
    "scipy.special.dawsn" : ['PR02', 'PR01'],
    "scipy.special.ndtr" : ['PR02', 'PR01'],
    "scipy.special.log_ndtr" : ['PR02', 'PR01'],
    "scipy.special.exp2" : ['PR02', 'PR01'],
    "scipy.special.exp10" : ['PR02', 'PR01'],
    "scipy.special.expm1" : ['PR02', 'PR01'],
    "scipy.special.log1p" : ['PR02', 'PR01'],
    "scipy.special.xlogy" : ['PR02', 'PR01'],
    "scipy.special.xlog1py" : ['PR02', 'PR01'],
    "scipy.special.digamma" : ['PR02', 'PR01'],
}

legacy_functions = [
    "scipy.integrate.complex_ode",
    "scipy.integrate.ode",
    "scipy.stats.rv_histogram",
    "scipy.stats.distributions.rv_histogram",
    "scipy.stats.rv_continuous",
    "scipy.stats.distributions.rv_continuous",
    "scipy.stats.rv_discrete",
    "scipy.stats.distributions.rv_discrete",
    "scipy.stats.distributions.ksone",
    "scipy.stats.distributions.kstwo",
    "scipy.stats.distributions.kstwobign",
    "scipy.stats.distributions.norm",
    "scipy.stats.distributions.alpha",
    "scipy.stats.distributions.anglit",
    "scipy.stats.distributions.arcsine",
    "scipy.stats.distributions.beta",
    "scipy.stats.distributions.betaprime",
    "scipy.stats.distributions.bradford",
    "scipy.stats.distributions.burr",
    "scipy.stats.distributions.burr12",
    "scipy.stats.distributions.fisk",
    "scipy.stats.distributions.cauchy",
    "scipy.stats.distributions.chi",
    "scipy.stats.distributions.chi2",
    "scipy.stats.distributions.cosine",
    "scipy.stats.distributions.dgamma",
    "scipy.stats.distributions.dpareto_lognorm",
    "scipy.stats.distributions.dweibull",
    "scipy.stats.distributions.expon",
    "scipy.stats.distributions.exponnorm",
    "scipy.stats.distributions.exponweib",
    "scipy.stats.distributions.exponpow",
    "scipy.stats.distributions.fatiguelife",
    "scipy.stats.distributions.foldcauchy",
    "scipy.stats.distributions.f",
    "scipy.stats.distributions.foldnorm",
    "scipy.stats.distributions.weibull_min",
    "scipy.stats.distributions.truncweibull_min",
    "scipy.stats.distributions.weibull_max",
    "scipy.stats.distributions.genlogistic",
    "scipy.stats.distributions.genpareto",
    "scipy.stats.distributions.genexpon",
    "scipy.stats.distributions.genextreme",
    "scipy.stats.distributions.gamma",
    "scipy.stats.distributions.erlang",
    "scipy.stats.distributions.gengamma",
    "scipy.stats.distributions.genhalflogistic",
    "scipy.stats.distributions.genhyperbolic",
    "scipy.stats.distributions.gompertz",
    "scipy.stats.distributions.gumbel_r",
    "scipy.stats.distributions.gumbel_l",
    "scipy.stats.distributions.halfcauchy",
    "scipy.stats.distributions.halflogistic",
    "scipy.stats.distributions.halfnorm",
    "scipy.stats.distributions.hypsecant",
    "scipy.stats.distributions.gausshyper",
    "scipy.stats.distributions.invgamma",
    "scipy.stats.distributions.invgauss",
    "scipy.stats.distributions.geninvgauss",
    "scipy.stats.distributions.norminvgauss",
    "scipy.stats.distributions.invweibull",
    "scipy.stats.distributions.jf_skew_t",
    "scipy.stats.distributions.johnsonsb",
    "scipy.stats.distributions.johnsonsu",
    "scipy.stats.distributions.landau",
    "scipy.stats.distributions.laplace",
    "scipy.stats.distributions.laplace_asymmetric",
    "scipy.stats.distributions.levy",
    "scipy.stats.distributions.levy_l",
    "scipy.stats.distributions.logistic",
    "scipy.stats.distributions.loggamma",
    "scipy.stats.distributions.loglaplace",
    "scipy.stats.distributions.lognorm",
    "scipy.stats.distributions.gibrat",
    "scipy.stats.distributions.maxwell",
    "scipy.stats.distributions.mielke",
    "scipy.stats.distributions.kappa4",
    "scipy.stats.distributions.kappa3",
    "scipy.stats.distributions.moyal",
    "scipy.stats.distributions.nakagami",
    "scipy.stats.distributions.ncx2",
    "scipy.stats.distributions.ncf",
    "scipy.stats.distributions.t",
    "scipy.stats.distributions.nct",
    "scipy.stats.distributions.pareto",
    "scipy.stats.distributions.lomax",
    "scipy.stats.distributions.pearson3",
    "scipy.stats.distributions.powerlaw",
    "scipy.stats.distributions.powerlognorm",
    "scipy.stats.distributions.powernorm",
    "scipy.stats.distributions.rdist",
    "scipy.stats.distributions.rayleigh",
    "scipy.stats.distributions.loguniform",
    "scipy.stats.distributions.reciprocal",
    "scipy.stats.distributions.rice",
    "scipy.stats.distributions.irwinhall",
    "scipy.stats.distributions.recipinvgauss",
    "scipy.stats.distributions.semicircular",
    "scipy.stats.distributions.skewcauchy",
    "scipy.stats.distributions.skewnorm",
    "scipy.stats.distributions.trapezoid",
    "scipy.stats.distributions.triang",
    "scipy.stats.distributions.truncexpon",
    "scipy.stats.distributions.truncnorm",
    "scipy.stats.distributions.truncpareto",
    "scipy.stats.distributions.tukeylambda",
    "scipy.stats.distributions.uniform",
    "scipy.stats.distributions.vonmises",
    "scipy.stats.distributions.vonmises_line",
    "scipy.stats.distributions.wald",
    "scipy.stats.distributions.wrapcauchy",
    "scipy.stats.distributions.gennorm",
    "scipy.stats.distributions.halfgennorm",
    "scipy.stats.distributions.crystalball",
    "scipy.stats.distributions.argus",
    "scipy.stats.distributions.studentized_range",
    "scipy.stats.distributions.rel_breitwigner",
    "scipy.stats.distributions.levy_stable",
    "scipy.stats.distributions.binom",
    "scipy.stats.distributions.bernoulli",
    "scipy.stats.distributions.betabinom",
    "scipy.stats.distributions.nbinom",
    "scipy.stats.distributions.betanbinom",
    "scipy.stats.distributions.geom",
    "scipy.stats.distributions.hypergeom",
    "scipy.stats.distributions.nhypergeom",
    "scipy.stats.distributions.logser",
    "scipy.stats.distributions.poisson",
    "scipy.stats.distributions.planck",
    "scipy.stats.distributions.boltzmann",
    "scipy.stats.distributions.randint",
    "scipy.stats.distributions.zipf",
    "scipy.stats.distributions.zipfian",
    "scipy.stats.distributions.dlaplace",
    "scipy.stats.distributions.poisson_binom",
    "scipy.stats.distributions.skellam",
    "scipy.stats.distributions.yulesimon",
    "scipy.stats.distributions.nchypergeom_fisher",
    "scipy.stats.distributions.nchypergeom_wallenius",
    "scipy.stats.alpha",
    "scipy.stats.anglit",
    "scipy.stats.arcsine",
    "scipy.stats.argus",
    "scipy.stats.bernoulli",
    "scipy.stats.beta",
    "scipy.stats.betabinom",
    "scipy.stats.betanbinom",
    "scipy.stats.betaprime",
    "scipy.stats.binom",
    "scipy.stats.boltzmann",
    "scipy.stats.bradford",
    "scipy.stats.burr",
    "scipy.stats.burr12",
    "scipy.stats.cauchy",
    "scipy.stats.chi",
    "scipy.stats.chi2",
    "scipy.stats.cosine",
    "scipy.stats.crystalball",
    "scipy.stats.dgamma",
    "scipy.stats.dlaplace",
    "scipy.stats.dpareto_lognorm",
    "scipy.stats.dweibull",
    "scipy.stats.erlang",
    "scipy.stats.expon",
    "scipy.stats.exponnorm",
    "scipy.stats.exponpow",
    "scipy.stats.exponweib",
    "scipy.stats.f",
    "scipy.stats.fatiguelife",
    "scipy.stats.fisk",
    "scipy.stats.foldcauchy",
    "scipy.stats.foldnorm",
    "scipy.stats.gamma",
    "scipy.stats.gausshyper",
    "scipy.stats.genexpon",
    "scipy.stats.genextreme",
    "scipy.stats.gengamma",
    "scipy.stats.genhalflogistic",
    "scipy.stats.genhyperbolic",
    "scipy.stats.geninvgauss",
    "scipy.stats.genlogistic",
    "scipy.stats.gennorm",
    "scipy.stats.genpareto",
    "scipy.stats.geom",
    "scipy.stats.gibrat",
    "scipy.stats.gompertz",
    "scipy.stats.gumbel_l",
    "scipy.stats.gumbel_r",
    "scipy.stats.halfcauchy",
    "scipy.stats.halfgennorm",
    "scipy.stats.halflogistic",
    "scipy.stats.halfnorm",
    "scipy.stats.hypergeom",
    "scipy.stats.hypsecant",
    "scipy.stats.invgamma",
    "scipy.stats.invgauss",
    "scipy.stats.invweibull",
    "scipy.stats.irwinhall",
    "scipy.stats.jf_skew_t",
    "scipy.stats.johnsonsb",
    "scipy.stats.johnsonsu",
    "scipy.stats.kappa3",
    "scipy.stats.kappa4",
    "scipy.stats.ksone",
    "scipy.stats.kstwo",
    "scipy.stats.kstwobign",
    "scipy.stats.landau",
    "scipy.stats.laplace",
    "scipy.stats.laplace_asymmetric",
    "scipy.stats.levy",
    "scipy.stats.levy_l",
    "scipy.stats.levy_stable",
    "scipy.stats.loggamma",
    "scipy.stats.logistic",
    "scipy.stats.loglaplace",
    "scipy.stats.lognorm",
    "scipy.stats.logser",
    "scipy.stats.loguniform",
    "scipy.stats.lomax",
    "scipy.stats.maxwell",
    "scipy.stats.mielke",
    "scipy.stats.moyal",
    "scipy.stats.multivariate_normal",
    "scipy.stats.nakagami",
    "scipy.stats.nbinom",
    "scipy.stats.ncf",
    "scipy.stats.nchypergeom_fisher",
    "scipy.stats.nchypergeom_wallenius",
    "scipy.stats.nct",
    "scipy.stats.ncx2",
    "scipy.stats.nhypergeom",
    "scipy.stats.norm",
    "scipy.stats.norminvgauss",
    "scipy.stats.pareto",
    "scipy.stats.pearson3",
    "scipy.stats.planck",
    "scipy.stats.poisson",
    "scipy.stats.poisson_binom",
    "scipy.stats.powerlaw",
    "scipy.stats.powerlognorm",
    "scipy.stats.powernorm",
    "scipy.stats.randint",
    "scipy.stats.rayleigh",
    "scipy.stats.rdist",
    "scipy.stats.recipinvgauss",
    "scipy.stats.reciprocal",
    "scipy.stats.rel_breitwigner",
    "scipy.stats.rice",
    "scipy.stats.semicircular",
    "scipy.stats.skellam",
    "scipy.stats.skewcauchy",
    "scipy.stats.skewnorm",
    "scipy.stats.studentized_range",
    "scipy.stats.t",
    "scipy.stats.trapezoid",
    "scipy.stats.triang",
    "scipy.stats.truncexpon",
    "scipy.stats.truncnorm",
    "scipy.stats.truncpareto",
    "scipy.stats.truncweibull_min",
    "scipy.stats.tukeylambda",
    "scipy.stats.uniform",
    "scipy.stats.vonmises",
    "scipy.stats.vonmises_line",
    "scipy.stats.wald",
    "scipy.stats.weibull_max",
    "scipy.stats.weibull_min",
    "scipy.stats.wrapcauchy",
    "scipy.stats.yulesimon",
    "scipy.stats.zipf",
    "scipy.stats.zipfian",
    "scipy.interpolate.InterpolatedUnivariateSpline",
    "scipy.interpolate.LSQUnivariateSpline",
    "scipy.interpolate.UnivariateSpline",
    "scipy.interpolate.splder",
    "scipy.interpolate.Rbf",
    "scipy.interpolate.interp2d",
    "scipy.sparse.lil_matrix",
    "scipy.sparse.dok_matrix",
    "scipy.sparse.dia_matrix",
    "scipy.sparse.csc_matrix",
    "scipy.sparse.csr_matrix",
    "scipy.sparse.coo_matrix",
    "scipy.sparse.bsr_matrix",
    "scipy.sparse.isspmatrix_lil",
    "scipy.sparse.isspmatrix_dok",
    "scipy.sparse.isspmatrix_dia",
    "scipy.sparse.isspmatrix_csr",
    "scipy.sparse.isspmatrix_csc",
    "scipy.sparse.isspmatrix_coo",
    "scipy.sparse.isspmatrix_bsr",
    "scipy.sparse.isspmatrix",
    "scipy.sparse.spmatrix",
    "scipy.optimize.BroydenFirst",
    "scipy.optimize.KrylovJacobian",
    "scipy.optimize.newton_krylov",
    "scipy.linalg.LinAlgError",  # this is from numpy
    "scipy.optimize.fmin_bfgs",
    "scipy.optimize.fmin_tnc",
    "scipy.optimize.fmin_ncg",
    "scipy.optimize.fmin_cobyla",
    "scipy.optimize.anderson",
    "scipy.optimize.broyden1",
    "scipy.optimize.broyden2",
    "scipy.optimize.diagbroyden",
    "scipy.optimize.excitingmixing",
    "scipy.optimize.linearmixing",
    "scipy.ndimage.sum",
    "scipy.signal.sosfreqz"
]

message_skip = {"PR01" :  # SPEC7 skips
                ["Parameters {'seed'} not documented",
                 "Parameters {'random_state'} not documented"]}

# the method of these classes have no __doc__, skip for now
false_positives = ["scipy.stats.Uniform",
                   "scipy.stats.Normal",
                   "scipy.stats.Mixture",
                   "scipy.stats.Binomial",
                   "scipy.stats.Logistic"]

skip_modules = [
    "scipy.odr",
    "scipy.fftpack",
    "scipy.stats.mstats",
    "scipy.linalg.cython_lapack",
    "scipy.linalg.cython_blas",
]


def walk_class(module_str, class_, public_api):
    class_str = class_.__name__
    # skip private methods (and dunder methods)
    attrs = {a for a in dir(class_) if not a.startswith("_")}
    for attr in attrs:
        item = getattr(class_, attr)
        if isinstance(item, types.FunctionType):
            public_api.append(f"{module_str}.{class_str}.{attr}")


def walk_module(module_str):
    public_api = []

    module = importlib.import_module(module_str)

    for item_str in module.__all__:
        with warnings.catch_warnings(record=True) as w:
            warnings.simplefilter("always", category=DeprecationWarning)
            item = getattr(module, item_str)
            if w:
                continue

        if isinstance(item, float | int | dict):  # ignore constants
            continue
        elif isinstance(item, types.ModuleType):
            continue
        elif isinstance(item, type):  # classes
            public_api.append(f"{module_str}.{item_str}")
            walk_class(module_str, item, public_api)  # methods
        else:  # functions
            public_api.append(f"{module_str}.{item_str}")
    return public_api


def main():
    public_api = []

    # get a list of all public objects
    for module in PUBLIC_MODULES:
        if module in skip_modules:
            # deprecated / legacy modules
            continue
        public_api += walk_module(module)

    errors = 0
    for item in public_api:
        if (any(func in item for func in legacy_functions) or
            any(func in item for func in false_positives)):
            continue
        try:
            res = validate(item)
        except AttributeError:
            continue
        for err in res["errors"]:
            if (err[0] not in skip_errors and
                err[0] not in compiled_code_skips.get(item, []) and
                err[1] not in message_skip.get(err[0], [])):
                print(f"{item}: {err}")
                errors += 1
    sys.exit(errors)


if __name__ == '__main__':
    main()
