annotate DEPENDENCIES/mingw32/Python27/Lib/site-packages/numpy/f2py/tests/util.py @ 133:4acb5d8d80b6 tip

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