test_extending.py 3.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. import os
  2. import pytest
  3. import shutil
  4. import subprocess
  5. import sys
  6. import warnings
  7. import numpy as np
  8. try:
  9. import cffi
  10. except ImportError:
  11. cffi = None
  12. if sys.flags.optimize > 1:
  13. # no docstrings present to inspect when PYTHONOPTIMIZE/Py_OptimizeFlag > 1
  14. # cffi cannot succeed
  15. cffi = None
  16. try:
  17. with warnings.catch_warnings(record=True) as w:
  18. # numba issue gh-4733
  19. warnings.filterwarnings('always', '', DeprecationWarning)
  20. import numba
  21. except ImportError:
  22. numba = None
  23. try:
  24. import cython
  25. from Cython.Compiler.Version import version as cython_version
  26. except ImportError:
  27. cython = None
  28. else:
  29. from distutils.version import LooseVersion
  30. # Cython 0.29.21 is required for Python 3.9 and there are
  31. # other fixes in the 0.29 series that are needed even for earlier
  32. # Python versions.
  33. # Note: keep in sync with the one in pyproject.toml
  34. required_version = LooseVersion('0.29.21')
  35. if LooseVersion(cython_version) < required_version:
  36. # too old or wrong cython, skip the test
  37. cython = None
  38. @pytest.mark.skipif(cython is None, reason="requires cython")
  39. @pytest.mark.slow
  40. def test_cython(tmp_path):
  41. srcdir = os.path.join(os.path.dirname(__file__), '..')
  42. shutil.copytree(srcdir, tmp_path / 'random')
  43. # build the examples and "install" them into a temporary directory
  44. build_dir = tmp_path / 'random' / '_examples' / 'cython'
  45. subprocess.check_call([sys.executable, 'setup.py', 'build', 'install',
  46. '--prefix', str(tmp_path / 'installdir'),
  47. '--single-version-externally-managed',
  48. '--record', str(tmp_path/ 'tmp_install_log.txt'),
  49. ],
  50. cwd=str(build_dir),
  51. )
  52. # gh-16162: make sure numpy's __init__.pxd was used for cython
  53. # not really part of this test, but it is a convenient place to check
  54. with open(build_dir / 'extending.c') as fid:
  55. txt_to_find = 'NumPy API declarations from "numpy/__init__.pxd"'
  56. for i, line in enumerate(fid):
  57. if txt_to_find in line:
  58. break
  59. else:
  60. assert False, ("Could not find '{}' in C file, "
  61. "wrong pxd used".format(txt_to_find))
  62. # get the path to the so's
  63. so1 = so2 = None
  64. with open(tmp_path /'tmp_install_log.txt') as fid:
  65. for line in fid:
  66. if 'extending.' in line:
  67. so1 = line.strip()
  68. if 'extending_distributions' in line:
  69. so2 = line.strip()
  70. assert so1 is not None
  71. assert so2 is not None
  72. # import the so's without adding the directory to sys.path
  73. from importlib.machinery import ExtensionFileLoader
  74. extending = ExtensionFileLoader('extending', so1).load_module()
  75. extending_distributions = ExtensionFileLoader('extending_distributions', so2).load_module()
  76. # actually test the cython c-extension
  77. from numpy.random import PCG64
  78. values = extending_distributions.uniforms_ex(PCG64(0), 10, 'd')
  79. assert values.shape == (10,)
  80. assert values.dtype == np.float64
  81. @pytest.mark.skipif(numba is None or cffi is None,
  82. reason="requires numba and cffi")
  83. def test_numba():
  84. from numpy.random._examples.numba import extending # noqa: F401
  85. @pytest.mark.skipif(cffi is None, reason="requires cffi")
  86. def test_cffi():
  87. from numpy.random._examples.cffi import extending # noqa: F401