[h5py] 121/455: More reasonable setup script for Cython
Ghislain Vaillant
ghisvail-guest at moszumanska.debian.org
Thu Jul 2 18:19:24 UTC 2015
This is an automated email from the git hooks/post-receive script.
ghisvail-guest pushed a commit to annotated tag 1.3.0
in repository h5py.
commit 8ea25630c765efaf5dc30a020976382faf563d2d
Author: andrewcollette <andrew.collette at gmail.com>
Date: Sun Sep 21 20:10:09 2008 +0000
More reasonable setup script for Cython
---
h5py/__init__.py | 1 -
h5py/tests/test_threads.py | 54 --------
setup_cython.py | 323 ++++++++++++++++++++++++---------------------
3 files changed, 173 insertions(+), 205 deletions(-)
diff --git a/h5py/__init__.py b/h5py/__init__.py
index 92a691a..5d5eec0 100644
--- a/h5py/__init__.py
+++ b/h5py/__init__.py
@@ -24,7 +24,6 @@ __doc__ = \
from h5 import _config as config
import utils, h5, h5a, h5d, h5f, h5g, h5i, h5p, h5r, h5s, h5t, h5z, highlevel
-import extras
from highlevel import File, Group, Dataset, Datatype, AttributeManager, CoordsList
diff --git a/h5py/tests/test_threads.py b/h5py/tests/test_threads.py
index 593cb77..6d23795 100644
--- a/h5py/tests/test_threads.py
+++ b/h5py/tests/test_threads.py
@@ -22,7 +22,6 @@ import time
from h5py import *
from h5py.h5 import H5Error
-from h5py.extras import h5sync
import h5py
LOCKTYPE = threading.RLock
@@ -212,59 +211,6 @@ class TestThreads(unittest.TestCase):
self.assert_(writethread.timestop < exit_lock_time)
- def test_decorator(self):
-
- time1 = 0
- time2 = 0
-
- class SleeperThread(Thread):
-
- def __init__(self, sleeptime, next_thread):
- Thread.__init__(self)
- self.sleeptime = sleeptime
- self.time = 0
- self.next_thread = next_thread
-
- @h5sync
- def run(self):
- if self.next_thread is not None:
- self.next_thread.start() # We should already hold the lock
- time.sleep(self.sleeptime/2.0)
- self.time = time.time()
- time.sleep(self.sleeptime/2.0)
-
- def run_dec(real_lock):
- oldlock = h5py.config.lock
- try:
- if not real_lock:
- h5py.config.lock = dummy_threading.RLock()
-
- thread_b = SleeperThread(1, None) # last thread
- thread_a = SleeperThread(2, thread_b) # first thread
-
- thread_a.start()
-
- thread_a.join()
- thread_b.join()
-
- if real_lock:
- self.assert_(thread_a.time < thread_b.time, "%f !< %f" % (thread_a.time, thread_b.time))
- else:
- self.assert_(thread_a.time > thread_b.time, "%f !> %f" % (thread_a.time, thread_b.time))
- finally:
- h5py.config.lock = oldlock
-
- run_dec(True)
- run_dec(False)
-
- @h5sync
- def thisismyname(foo):
- """ I'm a docstring! """
- pass
-
- self.assertEqual(thisismyname.__name__, "thisismyname")
- self.assertEqual(thisismyname.__doc__, " I'm a docstring! ")
-
diff --git a/setup_cython.py b/setup_cython.py
index 52b93f9..a49d8dd 100644
--- a/setup_cython.py
+++ b/setup_cython.py
@@ -41,56 +41,21 @@ from distutils.cmd import Command
from distutils.errors import DistutilsError, DistutilsExecError
from distutils.core import setup
from distutils.extension import Extension
+from distutils.command.build import build
-class CmdOptions(object):
- """ Manages package and compiler options. """
+# Basic package options
+NAME = 'h5py'
+VERSION = '0.3.1'
+MIN_NUMPY = '1.0.3'
+MIN_CYTHON = '0.9.8.1'
+KNOWN_API = (16,18) # Legal API levels (1.8.X or 1.6.X)
+SRC_PATH = 'h5py' # Name of directory with .pyx files
+CMD_CLASS = {} # Custom command classes for setup()
- def __init__(self):
-
- # Basic package options
- self.NAME = 'h5py'
- self.VERSION = '0.3.1'
- self.MIN_NUMPY = '1.0.3'
- self.MIN_CYTHON = '0.9.8.1'
- self.KNOWN_API = (16,18) # Legal API levels (1.8.X or 1.6.X)
- self.SRC_PATH = 'h5py' # Name of directory with .pyx files
- self.CMD_CLASS = {} # Custom command classes for setup()
-
- # Compilation flags
- self.CYTHON = False # Run Cython. Default is OFF for distribution.
- self.API = (16,) # API levels to include. Default is 1.6.X only.
- self.DEBUG = 0 # Compile-time debug level. Default is OFF.
- self.HDF5 = None # Custom HDF5 directory.
-
- # Feature flags
- self.THREADS = False # Thread-aware (safety & non-blocking IO)
-
- def get_pxi(self):
- """ Return a string with compile-time defines. """
-
- pxi_str = \
-"""# This file is automatically generated. Do not edit.
-
-DEF H5PY_VERSION = "%(VERSION)s"
-
-DEF H5PY_API = %(API_MAX)d # Highest API level (i.e. 18 or 16)
-DEF H5PY_16API = %(API_16)d # 1.6.X API available
-DEF H5PY_18API = %(API_18)d # 1.8.X API available
-
-DEF H5PY_DEBUG = %(DEBUG)d # Logging-level number, or 0 to disable
-
-DEF H5PY_THREADS = %(THREADS)d # Enable thread-safety and non-blocking reads
-
-"""
- opts = dict(self.__dict__)
- opts.update({ "API_MAX": max(self.API),
- "API_16": 16 in self.API,
- "API_18": 18 in self.API})
- return pxi_str % opts
-
-
-opts = CmdOptions() # Global to hold compilation options
+# Compilation flags
+HDF5 = None # Custom HDF5 directory.
+API = "16"
def fatal(instring, code=1):
print >> sys.stderr, "Fatal: "+instring
@@ -108,81 +73,30 @@ if not (sys.version_info[0:2] >= (2,5)):
# Check for Numpy (required)
try:
import numpy
- if numpy.version.version < opts.MIN_NUMPY:
- fatal("Numpy version %s is out of date (>= %s needed)" % (numpy.version.version, opts.MIN_NUMPY))
+ if numpy.version.version < MIN_NUMPY:
+ fatal("Numpy version %s is out of date (>= %s needed)" % (numpy.version.version, MIN_NUMPY))
except ImportError:
- fatal("Numpy not installed (version >= %s required)" % opts.MIN_NUMPY)
+ fatal("Numpy not installed (version >= %s required)" % MIN_NUMPY)
# === Parse command line arguments ============================================
for arg in sys.argv[:]:
- if arg == '--cython':
- opts.CYTHON = True
- sys.argv.remove(arg)
-
- elif arg.find('--api=') == 0:
- try:
- api = arg[6:]
- api = tuple(int(x) for x in api.split(',') if len(x) > 0)
- if len(api) == 0 or not all(x in opts.KNOWN_API for x in api):
- raise Exception
- except Exception:
- fatal('Illegal option to --api= (legal values are %s)' % ','.join(str(x) for x in opts.KNOWN_API))
- opts.API = api
- opts.CYTHON = True
- sys.argv.remove(arg)
-
- elif arg.find('--debug=') == 0:
- try:
- opts.DEBUG = int(arg[8:])
- except:
- fatal('Debuglevel not understood (wants --debug=<n>)')
- opts.CYTHON = True
- sys.argv.remove(arg)
-
- elif arg.find('--hdf5=') == 0:
+ if arg.find('--hdf5=') == 0:
splitarg = arg.split('=',1)
if len(splitarg) != 2:
fatal("HDF5 directory not understood (wants --hdf5=/path/to/hdf5)")
path = op.abspath(splitarg[1])
if not op.exists(path):
fatal("HDF5 path is illegal: %s" % path)
- opts.HDF5 = path
- opts.CYTHON = True
+ HDF5 = path
sys.argv.remove(arg)
- elif arg.find('--threads') == 0:
- opts.THREADS = True
- opts.CYTHON = True
- sys.argv.remove(arg)
-
-# Check if the config.pxi file needs to be updated for the given
-# command-line options.
-pxi_path = op.join(opts.SRC_PATH, 'config.pxi')
-pxi = opts.get_pxi()
-if not op.exists(pxi_path):
- try:
- f = open(pxi_path, 'w')
- f.write(pxi)
- f.close()
- except IOError:
- fatal('Failed write to "%s"' % pxi_path)
- opts.CYTHON = True
- if not "--force" in sys.argv: sys.argv.append("--force") # Cython ignores .pxi change
-else:
- try:
- f = open(pxi_path, 'r+')
- except IOError:
- fatal("Can't read file %s" % pxi_path)
- if f.read() != pxi:
- f.close()
- f = open(pxi_path, 'w')
- f.write(pxi)
- opts.CYTHON = True
- if not "--force" in sys.argv: sys.argv.append("--force") # Cython ignores .pxi change
- f.close()
+ if arg.find('--api=') == 0:
+ # We need to know this in order to generate the correct module list,
+ # although it's technically handled by the build object.
+ API = arg[5:]
if 'sdist' in sys.argv:
if os.path.exists('MANIFEST'):
@@ -197,36 +111,21 @@ modules = ['h5' , 'h5f', 'h5g', 'h5s', 'h5t', 'h5d',
'h5a', 'h5p', 'h5z', 'h5i', 'h5r', 'h5fd', 'utils']
# Only enable H5O and H5L interface if we're building against 1.8.X
-if 18 in opts.API:
+if "18" in API:
modules += ['h5o','h5l']
# C source files required for Cython code (with extension)
extra_src = ['utils_low.c']
-if opts.CYTHON:
- try:
- from Cython.Compiler.Main import Version
- from Cython.Distutils import build_ext
- except ImportError:
- fatal("Cython recompilation required, but Cython not installed.")
-
- if Version.version < opts.MIN_CYTHON:
- fatal("Old Cython version detected; at least %s required" % opts.MIN_CYTHON)
-
- # This is what enables Cython. Explicit calls to compile() don't work yet,
- # which is really annoying and breaks a lot of the options behavior.
- opts.CMD_CLASS.update({'build_ext': build_ext})
-
-
# Platform-dependent arguments to setup() or Extension()
if os.name == 'nt':
- if opts.HDF5 is None:
+ if HDF5 is None:
fatal("On Windows, HDF5 directory must be specified.")
libraries = ['hdf5dll']
- include_dirs = [numpy.get_include(), op.join(opts.HDF5, 'include')]
- library_dirs = [op.join(opts.HDF5, 'dll2')] # Must contain only "hdf5dll.dll.a"
+ include_dirs = [numpy.get_include(), op.join(HDF5, 'include')]
+ library_dirs = [op.join(HDF5, 'dll2')] # Must contain only "hdf5dll.dll.a"
runtime_dirs = []
extra_compile_args = ['-DH5_USE_16_API', '-D_HDF5USEDLL_', '-DH5_SIZEOF_SSIZE_T=4']
extra_link_args = []
@@ -238,12 +137,12 @@ if os.name == 'nt':
else: # Assume Unix-like
libraries = ['hdf5']
- if opts.HDF5 is None:
+ if HDF5 is None:
include_dirs = [numpy.get_include(), '/usr/include', '/usr/local/include']
library_dirs = ['/usr/lib/', '/usr/local/lib']
else:
- include_dirs = [numpy.get_include(), op.join(opts.HDF5, 'include')]
- library_dirs = [op.join(opts.HDF5, 'lib')]
+ include_dirs = [numpy.get_include(), op.join(HDF5, 'include')]
+ library_dirs = [op.join(HDF5, 'lib')]
runtime_dirs = library_dirs
extra_compile_args = ['-DH5_USE_16_API', '-Wno-unused', '-Wno-uninitialized']
extra_link_args = []
@@ -251,15 +150,12 @@ else: # Assume Unix-like
package_data = {'h5py': ['*.pyx'],
'h5py.tests': ['data/*.hdf5']}
-# Explicit list of source files for each module.
-mod_paths = [op.join(opts.SRC_PATH, x) for x in modules]
-extra_paths = [op.join(opts.SRC_PATH, x) for x in extra_src]
-if opts.CYTHON:
- module_sources = [[x+'.pyx']+extra_paths for x in mod_paths]
-else:
- module_sources = [[x+'.c']+extra_paths for x in mod_paths]
+# Explicit list of C source files for each module.
+mod_paths = [op.join(SRC_PATH, x) for x in modules]
+extra_paths = [op.join(SRC_PATH, x) for x in extra_src]
+module_sources = [[x+'.c']+extra_paths for x in mod_paths]
-extensions = [ Extension(opts.NAME+'.'+module,
+extensions = [ Extension(NAME+'.'+module,
sources,
include_dirs = include_dirs,
libraries = libraries,
@@ -272,22 +168,149 @@ extensions = [ Extension(opts.NAME+'.'+module,
# === Custom extensions for distutils =========================================
-class test(Command):
+class cybuild(build):
+
+ """ Cython-aware subclass of build """
+
+ user_options = build.user_options + \
+ [('cython','c','Run Cython'),
+ ('hdebug=', 'q','Set debug level'),
+ ('api=', 'a', 'API levels'),
+ ('threads', 't', 'Thread-aware')]
+ boolean_options = build.boolean_options + ['cython', 'threads']
+
+ def initialize_options(self):
+ self.cython = False
+ self.threads = False
+ self.api = (16,)
+ self.hdebug = 0
+ build.initialize_options(self)
+
+ def finalize_options(self):
+
+ print "finalizing"
+ # Validate API levels
+ if self.api != (16,):
+ self.cython = True
+ print self.api
+ try:
+ self.api = tuple(int(x) for x in self.api.split(',') if len(x) > 0)
+ if len(self.api) == 0 or not all(x in KNOWN_API for x in self.api):
+ raise Exception
+ except Exception:
+ fatal('Illegal option %s to --api= (legal values are %s)' % (self.api, ','.join(str(x) for x in KNOWN_API)))
+
+ # Validate debug level
+ if self.hdebug != 0:
+ print self.hdebug
+ self.cython = True
+ try:
+ self.hdebug = int(self.hdebug)
+ except TypeError:
+ fatal('Debuglevel not understood (wants --debug=<integer>)')
+ build.finalize_options(self)
+
+ def _get_pxi(self):
+ """ Get the configuration .pxi for the current options. """
+
+ pxi_str = \
+"""# This file is automatically generated. Do not edit.
+# HDF5: %(HDF5)s
+
+DEF H5PY_VERSION = "%(VERSION)s"
+
+DEF H5PY_API = %(API_MAX)d # Highest API level (i.e. 18 or 16)
+DEF H5PY_16API = %(API_16)d # 1.6.X API available
+DEF H5PY_18API = %(API_18)d # 1.8.X API available
+
+DEF H5PY_DEBUG = %(DEBUG)d # Logging-level number, or 0 to disable
+
+DEF H5PY_THREADS = %(THREADS)d # Enable thread-safety and non-blocking reads
+"""
+ pxi_str %= {"VERSION": VERSION, "API_MAX": max(self.api),
+ "API_16": 16 in self.api, "API_18": 18 in self.api,
+ "DEBUG": self.hdebug, "THREADS": self.threads,
+ "HDF5": HDF5}
+
+ return pxi_str
+
+ def run(self, *args, **kwds):
+
+ # Necessary because Cython doesn't detect changes to the .pxi
+ recompile_all = False
+
+ # Check if the config.pxi file needs to be updated for the given
+ # command-line options.
+ pxi_path = op.join(SRC_PATH, 'config.pxi')
+ pxi = self._get_pxi()
+ if not op.exists(pxi_path):
+ try:
+ f = open(pxi_path, 'w')
+ f.write(pxi)
+ f.close()
+ except IOError:
+ fatal('Failed write to "%s"' % pxi_path)
+ recompile_all = True
+ else:
+ try:
+ f = open(pxi_path, 'r+')
+ except IOError:
+ fatal("Can't read file %s" % pxi_path)
+ if f.read() != pxi:
+ f.close()
+ f = open(pxi_path, 'w')
+ f.write(pxi)
+ recompile_all = True
+ f.close()
+
+ if self.force: forceall = True
+
+ if self.cython:
+ print "Running Cython..."
+ try:
+ from Cython.Compiler.Main import Version, compile, CompilationOptions
+ from Cython.Distutils import build_ext
+ except ImportError:
+ fatal("Cython recompilation required, but Cython not installed.")
+
+ if Version.version < MIN_CYTHON:
+ fatal("Old Cython version detected; at least %s required" % MIN_CYTHON)
+
+ cyopts = CompilationOptions(verbose=False)
+
+ # Build each extension
+ # This should be a single call to compile_multiple, but it's
+ # broken in Cython 0.9.8.1.1
+ for module in modules:
+ pyx_path = op.join(SRC_PATH,module+'.pyx')
+ c_path = op.join(SRC_PATH,module+'.c')
+ if not op.exists(c_path) or \
+ os.stat(pyx_path).st_mtime > os.stat(c_path).st_mtime or \
+ recompile_all:
+ print "Cythoning %s" % pyx_path
+ result = compile(pyx_path, cyopts)
+ if result.num_errors != 0:
+ fatal("Cython error; aborting.")
+
+ build.run(self, *args, **kwds)
+
+class test(cybuild):
description = "Build and run unit tests"
- user_options = [('sections=','s','Comma separated list of tests ("-" prefix to NOT run)')]
+ user_options = cybuild.user_options + [('sections=','s','Comma separated list of tests ("-" prefix to NOT run)')]
def initialize_options(self):
self.sections = None
+ cybuild.initialize_options(self)
def finalize_options(self):
pass
+ cybuild.finalize_options(self)
def run(self):
- buildobj = self.distribution.get_command_obj('build')
- buildobj.run()
+ cybuild.run(self)
oldpath = sys.path
try:
- sys.path = [op.abspath(buildobj.build_lib)] + oldpath
+ sys.path = [op.abspath(self.build_lib)] + oldpath
import h5py.tests
if not h5py.tests.runtests(None if self.sections is None else tuple(self.sections.split(','))):
raise DistutilsError("Unit tests failed.")
@@ -316,8 +339,8 @@ class dev(Command):
shutil.rmtree(x)
except OSError:
pass
- fnames = [ op.join(opts.SRC_PATH, x+'.dep') for x in modules ] + \
- [ op.join(opts.SRC_PATH, x+'.c') for x in modules ] + \
+ fnames = [ op.join(SRC_PATH, x+'.dep') for x in modules ] + \
+ [ op.join(SRC_PATH, x+'.c') for x in modules ] + \
[ 'MANIFEST']
for name in fnames:
@@ -350,9 +373,9 @@ class dev(Command):
# New commands for setup (e.g. "python setup.py test")
if os.name == 'nt':
- opts.CMD_CLASS.update({'test': test})
+ CMD_CLASS.update({'build': cybuild, 'test': test})
else:
- opts.CMD_CLASS.update({'dev': dev, 'test': test})
+ CMD_CLASS.update({'build': cybuild, 'dev': dev, 'test': test})
cls_txt = \
@@ -386,8 +409,8 @@ reading and writing data from Python.
"""
setup(
- name = opts.NAME,
- version = opts.VERSION,
+ name = NAME,
+ version = VERSION,
description = short_desc,
long_description = long_desc,
classifiers = [x for x in cls_txt.split("\n") if x],
@@ -399,8 +422,8 @@ setup(
packages = ['h5py','h5py.tests'],
package_data = package_data,
ext_modules = extensions,
- requires = ['numpy (>=%s)' % opts.MIN_NUMPY],
- cmdclass = opts.CMD_CLASS
+ requires = ['numpy (>=%s)' % MIN_NUMPY],
+ cmdclass = CMD_CLASS
)
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-science/packages/h5py.git
More information about the debian-science-commits
mailing list