Skip to content

Commit

Permalink
Merge pull request #14079 from peterbell10/boost-build
Browse files Browse the repository at this point in the history
BLD: Avoid importing scipy.stats during cythonize stage
  • Loading branch information
rgommers committed May 18, 2021
2 parents e2b0a21 + 95e5c85 commit 0617428
Show file tree
Hide file tree
Showing 6 changed files with 71 additions and 53 deletions.
11 changes: 11 additions & 0 deletions scipy/_build_utils/__init__.py
Expand Up @@ -18,6 +18,17 @@
def uses_blas64():
return (os.environ.get("NPY_USE_BLAS_ILP64", "0") != "0")

def import_file(folder, module_name):
"""Import a file directly, avoiding importing scipy"""
import importlib
import pathlib

fname = pathlib.Path(folder) / f'{module_name}.py'
spec = importlib.util.spec_from_file_location(module_name, str(fname))
module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(module)
return module


from scipy._lib._testutils import PytestTester
test = PytestTester(__name__)
Expand Down
35 changes: 15 additions & 20 deletions scipy/stats/_boost/__init__.py
@@ -1,22 +1,17 @@
try:
from scipy.stats._boost.beta_ufunc import (
_beta_pdf, _beta_cdf, _beta_sf, _beta_ppf,
_beta_isf, _beta_mean, _beta_variance,
_beta_skewness, _beta_kurtosis_excess,
)
from scipy.stats._boost.beta_ufunc import (
_beta_pdf, _beta_cdf, _beta_sf, _beta_ppf,
_beta_isf, _beta_mean, _beta_variance,
_beta_skewness, _beta_kurtosis_excess,
)

from scipy.stats._boost.binom_ufunc import (
_binom_pdf, _binom_cdf, _binom_sf, _binom_ppf,
_binom_isf, _binom_mean, _binom_variance,
_binom_skewness, _binom_kurtosis_excess,
)
from scipy.stats._boost.binom_ufunc import (
_binom_pdf, _binom_cdf, _binom_sf, _binom_ppf,
_binom_isf, _binom_mean, _binom_variance,
_binom_skewness, _binom_kurtosis_excess,
)

from scipy.stats._boost.nbinom_ufunc import (
_nbinom_pdf, _nbinom_cdf, _nbinom_sf, _nbinom_ppf,
_nbinom_isf, _nbinom_mean, _nbinom_variance,
_nbinom_skewness, _nbinom_kurtosis_excess,
)
except (ModuleNotFoundError, ImportError):
# scipy.stats doesn't exist during cythonize
# step of build!
pass
from scipy.stats._boost.nbinom_ufunc import (
_nbinom_pdf, _nbinom_cdf, _nbinom_sf, _nbinom_ppf,
_nbinom_isf, _nbinom_mean, _nbinom_variance,
_nbinom_skewness, _nbinom_kurtosis_excess,
)
File renamed without changes.
36 changes: 36 additions & 0 deletions scipy/stats/_boost/include/code_gen.py
Expand Up @@ -3,7 +3,14 @@
from typing import NamedTuple
from warnings import warn
from textwrap import dedent
from shutil import copyfile
import pathlib
import os

from gen_func_defs_pxd import ( # type: ignore
_gen_func_defs_pxd)
from _info import ( # type: ignore
_x_funcs, _no_x_funcs, _klass_mapper)

class _MethodDef(NamedTuple):
ufunc_name: str
Expand Down Expand Up @@ -139,3 +146,32 @@ def _ufunc_gen(scipy_dist: str, types: list, ctor_args: tuple,
0 # unused
)
'''))


if __name__ == '__main__':
# create target directory
_boost_dir = pathlib.Path(__file__).resolve().parent.parent
src_dir = _boost_dir / 'src'
src_dir.mkdir(exist_ok=True, parents=True)

# copy contents of include into directory to satisfy Cython
# PXD include conditions
inc_dir = _boost_dir / 'include'
src = 'templated_pyufunc.pxd'
copyfile(inc_dir / src, src_dir / src)

# generate the PXD and PYX wrappers
_gen_func_defs_pxd(
f'{src_dir}/func_defs.pxd',
x_funcs=_x_funcs,
no_x_funcs=_no_x_funcs)
for b, s in _klass_mapper.items():
_ufunc_gen(
scipy_dist=s.scipy_name,
types=['NPY_FLOAT', 'NPY_DOUBLE', 'NPY_LONGDOUBLE'],
ctor_args=s.ctor_args,
filename=f'{src_dir}/{s.scipy_name}_ufunc.pyx',
boost_dist=f'{b}_distribution',
x_funcs=_x_funcs,
no_x_funcs=_no_x_funcs,
)
6 changes: 4 additions & 2 deletions scipy/stats/_boost/setup.py
Expand Up @@ -11,7 +11,7 @@ def pre_build_hook(build_ext, ext):

def configuration(parent_package='', top_path=None):
from scipy._lib._boost_utils import _boost_dir
from _info import _klass_mapper # type: ignore
from scipy._build_utils import import_file
from numpy.distutils.misc_util import Configuration
import numpy as np
config = Configuration('_boost', parent_package, top_path)
Expand All @@ -32,7 +32,9 @@ def configuration(parent_package='', top_path=None):
]

# generate the PXD and PYX wrappers
src_dir = pathlib.Path(__file__).parent / 'src'
boost_dir = pathlib.Path(__file__).parent
src_dir = boost_dir / 'src'
_klass_mapper = import_file(boost_dir / 'include', '_info')._klass_mapper
for s in _klass_mapper.values():
ext = config.add_extension(
f'{s.scipy_name}_ufunc',
Expand Down
36 changes: 5 additions & 31 deletions scipy/stats/_generate_pyx.py
@@ -1,5 +1,7 @@
import pathlib
from shutil import copyfile
import subprocess
import sys


def isNPY_OLD():
Expand All @@ -22,37 +24,9 @@ def make_biasedurn():


def make_boost():
# create target directory
(pathlib.Path(__file__).parent / '_boost/src').mkdir(exist_ok=True,
parents=True)
src_dir = pathlib.Path(__file__).parent / '_boost/src'

# copy contents of include into directory to satisfy Cython
# PXD include conditions
inc_dir = pathlib.Path(__file__).parent / '_boost/include'
src = 'templated_pyufunc.pxd'
copyfile(inc_dir / src, src_dir / src)

# generate the PXD and PYX wrappers
from _boost.include.gen_func_defs_pxd import ( # type: ignore
_gen_func_defs_pxd)
from _boost.include.code_gen import _ufunc_gen # type: ignore
from _boost._info import ( # type: ignore
_x_funcs, _no_x_funcs, _klass_mapper)
_gen_func_defs_pxd(
f'{src_dir}/func_defs.pxd',
x_funcs=_x_funcs,
no_x_funcs=_no_x_funcs)
for b, s in _klass_mapper.items():
_ufunc_gen(
scipy_dist=s.scipy_name,
types=['NPY_FLOAT', 'NPY_DOUBLE', 'NPY_LONGDOUBLE'],
ctor_args=s.ctor_args,
filename=f'{src_dir}/{s.scipy_name}_ufunc.pyx',
boost_dist=f'{b}_distribution',
x_funcs=_x_funcs,
no_x_funcs=_no_x_funcs,
)
# Call code generator inside _boost directory
code_gen = pathlib.Path(__file__).parent / '_boost/include/code_gen.py'
subprocess.run([sys.executable, str(code_gen)], check=True)


if __name__ == '__main__':
Expand Down

0 comments on commit 0617428

Please sign in to comment.