test_compile_function.py 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. """See https://github.com/numpy/numpy/pull/11937.
  2. """
  3. from __future__ import division, absolute_import, print_function
  4. import sys
  5. import os
  6. import uuid
  7. from importlib import import_module
  8. import pytest
  9. import numpy.f2py
  10. from numpy.testing import assert_equal
  11. from . import util
  12. def setup_module():
  13. if sys.platform == 'win32' and sys.version_info[0] < 3:
  14. pytest.skip('Fails with MinGW64 Gfortran (Issue #9673)')
  15. if not util.has_c_compiler():
  16. pytest.skip("Needs C compiler")
  17. if not util.has_f77_compiler():
  18. pytest.skip('Needs FORTRAN 77 compiler')
  19. # extra_args can be a list (since gh-11937) or string.
  20. # also test absence of extra_args
  21. @pytest.mark.parametrize(
  22. "extra_args", [['--noopt', '--debug'], '--noopt --debug', '']
  23. )
  24. def test_f2py_init_compile(extra_args):
  25. # flush through the f2py __init__ compile() function code path as a
  26. # crude test for input handling following migration from
  27. # exec_command() to subprocess.check_output() in gh-11937
  28. # the Fortran 77 syntax requires 6 spaces before any commands, but
  29. # more space may be added/
  30. fsource = """
  31. integer function foo()
  32. foo = 10 + 5
  33. return
  34. end
  35. """
  36. # use various helper functions in util.py to enable robust build /
  37. # compile and reimport cycle in test suite
  38. moddir = util.get_module_dir()
  39. modname = util.get_temp_module_name()
  40. cwd = os.getcwd()
  41. target = os.path.join(moddir, str(uuid.uuid4()) + '.f')
  42. # try running compile() with and without a source_fn provided so
  43. # that the code path where a temporary file for writing Fortran
  44. # source is created is also explored
  45. for source_fn in [target, None]:
  46. # mimic the path changing behavior used by build_module() in
  47. # util.py, but don't actually use build_module() because it has
  48. # its own invocation of subprocess that circumvents the
  49. # f2py.compile code block under test
  50. try:
  51. os.chdir(moddir)
  52. ret_val = numpy.f2py.compile(
  53. fsource,
  54. modulename=modname,
  55. extra_args=extra_args,
  56. source_fn=source_fn
  57. )
  58. finally:
  59. os.chdir(cwd)
  60. # check for compile success return value
  61. assert_equal(ret_val, 0)
  62. # we are not currently able to import the Python-Fortran
  63. # interface module on Windows / Appveyor, even though we do get
  64. # successful compilation on that platform with Python 3.x
  65. if sys.platform != 'win32':
  66. # check for sensible result of Fortran function; that means
  67. # we can import the module name in Python and retrieve the
  68. # result of the sum operation
  69. return_check = import_module(modname)
  70. calc_result = return_check.foo()
  71. assert_equal(calc_result, 15)
  72. def test_f2py_init_compile_failure():
  73. # verify an appropriate integer status value returned by
  74. # f2py.compile() when invalid Fortran is provided
  75. ret_val = numpy.f2py.compile(b"invalid")
  76. assert_equal(ret_val, 1)
  77. def test_f2py_init_compile_bad_cmd():
  78. # verify that usage of invalid command in f2py.compile() returns
  79. # status value of 127 for historic consistency with exec_command()
  80. # error handling
  81. # patch the sys Python exe path temporarily to induce an OSError
  82. # downstream NOTE: how bad of an idea is this patching?
  83. try:
  84. temp = sys.executable
  85. sys.executable = 'does not exist'
  86. # the OSError should take precedence over invalid Fortran
  87. ret_val = numpy.f2py.compile(b"invalid")
  88. assert_equal(ret_val, 127)
  89. finally:
  90. sys.executable = temp
  91. @pytest.mark.parametrize('fsource',
  92. ['program test_f2py\nend program test_f2py',
  93. b'program test_f2py\nend program test_f2py',])
  94. def test_compile_from_strings(tmpdir, fsource):
  95. # Make sure we can compile str and bytes gh-12796
  96. cwd = os.getcwd()
  97. try:
  98. os.chdir(str(tmpdir))
  99. ret_val = numpy.f2py.compile(
  100. fsource,
  101. modulename='test_compile_from_strings',
  102. extension='.f90')
  103. assert_equal(ret_val, 0)
  104. finally:
  105. os.chdir(cwd)