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