Mercurial > hg > vamp-build-and-test
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) |