comparison DEPENDENCIES/mingw32/Python27/Lib/site-packages/numpy/f2py/tests/util.py @ 87:2a2c65a20a8b

Add Python libs and headers
author Chris Cannam
date Wed, 25 Feb 2015 14:05:22 +0000
parents
children
comparison
equal deleted inserted replaced
86:413a9d26189e 87:2a2c65a20a8b
1 """
2 Utility functions for
3
4 - building and importing modules on test time, using a temporary location
5 - detecting if compilers are present
6
7 """
8 from __future__ import division, absolute_import, print_function
9
10 import os
11 import sys
12 import subprocess
13 import tempfile
14 import shutil
15 import atexit
16 import textwrap
17 import re
18 import random
19
20 import nose
21
22 from numpy.compat import asbytes, asstr
23 import numpy.f2py
24
25 try:
26 from hashlib import md5
27 except ImportError:
28 from md5 import new as md5
29
30 #
31 # Maintaining a temporary module directory
32 #
33
34 _module_dir = None
35
36 def _cleanup():
37 global _module_dir
38 if _module_dir is not None:
39 try:
40 sys.path.remove(_module_dir)
41 except ValueError:
42 pass
43 try:
44 shutil.rmtree(_module_dir)
45 except (IOError, OSError):
46 pass
47 _module_dir = None
48
49 def get_module_dir():
50 global _module_dir
51 if _module_dir is None:
52 _module_dir = tempfile.mkdtemp()
53 atexit.register(_cleanup)
54 if _module_dir not in sys.path:
55 sys.path.insert(0, _module_dir)
56 return _module_dir
57
58 def get_temp_module_name():
59 # Assume single-threaded, and the module dir usable only by this thread
60 d = get_module_dir()
61 for j in range(5403, 9999999):
62 name = "_test_ext_module_%d" % j
63 fn = os.path.join(d, name)
64 if name not in sys.modules and not os.path.isfile(fn+'.py'):
65 return name
66 raise RuntimeError("Failed to create a temporary module name")
67
68 def _memoize(func):
69 memo = {}
70 def wrapper(*a, **kw):
71 key = repr((a, kw))
72 if key not in memo:
73 try:
74 memo[key] = func(*a, **kw)
75 except Exception as e:
76 memo[key] = e
77 raise
78 ret = memo[key]
79 if isinstance(ret, Exception):
80 raise ret
81 return ret
82 wrapper.__name__ = func.__name__
83 return wrapper
84
85 #
86 # Building modules
87 #
88
89 @_memoize
90 def build_module(source_files, options=[], skip=[], only=[], module_name=None):
91 """
92 Compile and import a f2py module, built from the given files.
93
94 """
95
96 code = ("import sys; sys.path = %s; import numpy.f2py as f2py2e; "
97 "f2py2e.main()" % repr(sys.path))
98
99 d = get_module_dir()
100
101 # Copy files
102 dst_sources = []
103 for fn in source_files:
104 if not os.path.isfile(fn):
105 raise RuntimeError("%s is not a file" % fn)
106 dst = os.path.join(d, os.path.basename(fn))
107 shutil.copyfile(fn, dst)
108 dst_sources.append(dst)
109
110 fn = os.path.join(os.path.dirname(fn), '.f2py_f2cmap')
111 if os.path.isfile(fn):
112 dst = os.path.join(d, os.path.basename(fn))
113 if not os.path.isfile(dst):
114 shutil.copyfile(fn, dst)
115
116 # Prepare options
117 if module_name is None:
118 module_name = get_temp_module_name()
119 f2py_opts = ['-c', '-m', module_name] + options + dst_sources
120 if skip:
121 f2py_opts += ['skip:'] + skip
122 if only:
123 f2py_opts += ['only:'] + only
124
125 # Build
126 cwd = os.getcwd()
127 try:
128 os.chdir(d)
129 cmd = [sys.executable, '-c', code] + f2py_opts
130 p = subprocess.Popen(cmd, stdout=subprocess.PIPE,
131 stderr=subprocess.STDOUT)
132 out, err = p.communicate()
133 if p.returncode != 0:
134 raise RuntimeError("Running f2py failed: %s\n%s"
135 % (cmd[4:], asstr(out)))
136 finally:
137 os.chdir(cwd)
138
139 # Partial cleanup
140 for fn in dst_sources:
141 os.unlink(fn)
142
143 # Import
144 __import__(module_name)
145 return sys.modules[module_name]
146
147 @_memoize
148 def build_code(source_code, options=[], skip=[], only=[], suffix=None,
149 module_name=None):
150 """
151 Compile and import Fortran code using f2py.
152
153 """
154 if suffix is None:
155 suffix = '.f'
156
157 fd, tmp_fn = tempfile.mkstemp(suffix=suffix)
158 os.write(fd, asbytes(source_code))
159 os.close(fd)
160
161 try:
162 return build_module([tmp_fn], options=options, skip=skip, only=only,
163 module_name=module_name)
164 finally:
165 os.unlink(tmp_fn)
166
167 #
168 # Check if compilers are available at all...
169 #
170
171 _compiler_status = None
172 def _get_compiler_status():
173 global _compiler_status
174 if _compiler_status is not None:
175 return _compiler_status
176
177 _compiler_status = (False, False, False)
178
179 # XXX: this is really ugly. But I don't know how to invoke Distutils
180 # in a safer way...
181 code = """
182 import os
183 import sys
184 sys.path = %(syspath)s
185
186 def configuration(parent_name='',top_path=None):
187 global config
188 from numpy.distutils.misc_util import Configuration
189 config = Configuration('', parent_name, top_path)
190 return config
191
192 from numpy.distutils.core import setup
193 setup(configuration=configuration)
194
195 config_cmd = config.get_config_cmd()
196 have_c = config_cmd.try_compile('void foo() {}')
197 print('COMPILERS:%%d,%%d,%%d' %% (have_c,
198 config.have_f77c(),
199 config.have_f90c()))
200 sys.exit(99)
201 """
202 code = code % dict(syspath=repr(sys.path))
203
204 fd, script = tempfile.mkstemp(suffix='.py')
205 os.write(fd, asbytes(code))
206 os.close(fd)
207
208 try:
209 cmd = [sys.executable, script, 'config']
210 p = subprocess.Popen(cmd, stdout=subprocess.PIPE,
211 stderr=subprocess.STDOUT)
212 out, err = p.communicate()
213 m = re.search(asbytes(r'COMPILERS:(\d+),(\d+),(\d+)'), out)
214 if m:
215 _compiler_status = (bool(int(m.group(1))), bool(int(m.group(2))),
216 bool(int(m.group(3))))
217 finally:
218 os.unlink(script)
219
220 # Finished
221 return _compiler_status
222
223 def has_c_compiler():
224 return _get_compiler_status()[0]
225
226 def has_f77_compiler():
227 return _get_compiler_status()[1]
228
229 def has_f90_compiler():
230 return _get_compiler_status()[2]
231
232 #
233 # Building with distutils
234 #
235
236 @_memoize
237 def build_module_distutils(source_files, config_code, module_name, **kw):
238 """
239 Build a module via distutils and import it.
240
241 """
242 from numpy.distutils.misc_util import Configuration
243 from numpy.distutils.core import setup
244
245 d = get_module_dir()
246
247 # Copy files
248 dst_sources = []
249 for fn in source_files:
250 if not os.path.isfile(fn):
251 raise RuntimeError("%s is not a file" % fn)
252 dst = os.path.join(d, os.path.basename(fn))
253 shutil.copyfile(fn, dst)
254 dst_sources.append(dst)
255
256 # Build script
257 config_code = textwrap.dedent(config_code).replace("\n", "\n ")
258
259 code = """\
260 import os
261 import sys
262 sys.path = %(syspath)s
263
264 def configuration(parent_name='',top_path=None):
265 from numpy.distutils.misc_util import Configuration
266 config = Configuration('', parent_name, top_path)
267 %(config_code)s
268 return config
269
270 if __name__ == "__main__":
271 from numpy.distutils.core import setup
272 setup(configuration=configuration)
273 """ % dict(config_code=config_code, syspath = repr(sys.path))
274
275 script = os.path.join(d, get_temp_module_name() + '.py')
276 dst_sources.append(script)
277 f = open(script, 'wb')
278 f.write(asbytes(code))
279 f.close()
280
281 # Build
282 cwd = os.getcwd()
283 try:
284 os.chdir(d)
285 cmd = [sys.executable, script, 'build_ext', '-i']
286 p = subprocess.Popen(cmd, stdout=subprocess.PIPE,
287 stderr=subprocess.STDOUT)
288 out, err = p.communicate()
289 if p.returncode != 0:
290 raise RuntimeError("Running distutils build failed: %s\n%s"
291 % (cmd[4:], asstr(out)))
292 finally:
293 os.chdir(cwd)
294
295 # Partial cleanup
296 for fn in dst_sources:
297 os.unlink(fn)
298
299 # Import
300 __import__(module_name)
301 return sys.modules[module_name]
302
303 #
304 # Unittest convenience
305 #
306
307 class F2PyTest(object):
308 code = None
309 sources = None
310 options = []
311 skip = []
312 only = []
313 suffix = '.f'
314 module = None
315 module_name = None
316
317 def setUp(self):
318 if self.module is not None:
319 return
320
321 # Check compiler availability first
322 if not has_c_compiler():
323 raise nose.SkipTest("No C compiler available")
324
325 codes = []
326 if self.sources:
327 codes.extend(self.sources)
328 if self.code is not None:
329 codes.append(self.suffix)
330
331 needs_f77 = False
332 needs_f90 = False
333 for fn in codes:
334 if fn.endswith('.f'):
335 needs_f77 = True
336 elif fn.endswith('.f90'):
337 needs_f90 = True
338 if needs_f77 and not has_f77_compiler():
339 raise nose.SkipTest("No Fortran 77 compiler available")
340 if needs_f90 and not has_f90_compiler():
341 raise nose.SkipTest("No Fortran 90 compiler available")
342
343 # Build the module
344 if self.code is not None:
345 self.module = build_code(self.code, options=self.options,
346 skip=self.skip, only=self.only,
347 suffix=self.suffix,
348 module_name=self.module_name)
349
350 if self.sources is not None:
351 self.module = build_module(self.sources, options=self.options,
352 skip=self.skip, only=self.only,
353 module_name=self.module_name)