[h5py] 170/455: Make setup.py less insane

Ghislain Vaillant ghisvail-guest at moszumanska.debian.org
Thu Jul 2 18:19:29 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 62378de2e54b9893b45d74743dc4a2aeed5d7c78
Author: andrewcollette <andrew.collette at gmail.com>
Date:   Mon Dec 1 00:46:05 2008 +0000

    Make setup.py less insane
---
 h5py/h5.pyx |   6 +-
 setup.py    | 223 ++++++++++++++++++++++++++++++++----------------------------
 2 files changed, 123 insertions(+), 106 deletions(-)

diff --git a/h5py/h5.pyx b/h5py/h5.pyx
index b4fafc5..7e2539b 100644
--- a/h5py/h5.pyx
+++ b/h5py/h5.pyx
@@ -676,15 +676,15 @@ def _exithack():
     # it freaks out and dumps a message to stderr.  So we have Python dec_ref
     # everything when the interpreter's about to exit.
 
-    IF H5PY_DEBUG:
-        log_lib.info("* h5py is shutting down")
-
     cdef int count
     cdef int i
     cdef hid_t *objs
 
     count = H5Fget_obj_count(H5F_OBJ_ALL, H5F_OBJ_ALL)
     
+    IF H5PY_DEBUG:
+        log_lib.info("* h5py is shutting down (closing %d leftover IDs)" % count)
+
     if count > 0:
         objs = <hid_t*>malloc(sizeof(hid_t)*count)
         try:
diff --git a/setup.py b/setup.py
index c170d4d..5cf173c 100644
--- a/setup.py
+++ b/setup.py
@@ -47,12 +47,14 @@ from distutils.command.sdist import sdist
 from distutils.cmd import Command
 
 # Basic package options
-NAME = 'h5py'
+NAME = 'h5py'               # Software title
 VERSION = '1.0.0'
 MIN_NUMPY = '1.0.3'
 MIN_CYTHON = '0.9.8.1.1'
-SRC_PATH = 'h5py'      # Name of directory with .pyx files
-CMD_CLASS = {}         # Custom command classes for setup()
+SRC_PATH = 'h5py'           # Name of directory with .pyx files
+HAVE_CYTHON = False         # Flag (updated below in "Import Checks")
+CMD_CLASS = {}              # Custom command classes for setup()
+PICKLE_FILE = 'buildconf.pickle'
 
 # The list of modules depends on max API version
 MODULES = {16:  ['h5', 'h5f', 'h5g', 'h5s', 'h5t', 'h5d', 'h5a', 'h5p', 'h5z',
@@ -61,11 +63,12 @@ MODULES = {16:  ['h5', 'h5f', 'h5g', 'h5s', 'h5t', 'h5d', 'h5a', 'h5p', 'h5z',
                  'h5i', 'h5r', 'h5fd', 'utils', 'h5o', 'h5l']}
 
 def version_check(vers, required):
+    """ Compare versions between two "."-separated strings. """
 
-    def _tpl(istr):
+    def tpl(istr):
         return tuple(int(x) for x in istr.split('.'))
 
-    return _tpl(vers) >= _tpl(required)
+    return tpl(vers) >= tpl(required)
 
 def fatal(instring, code=1):
     print >> sys.stderr, "Fatal: "+instring
@@ -75,7 +78,16 @@ def warn(instring):
     print >> sys.stderr, "Warning: "+instring
 
 
-# === Required imports ========================================================
+# === Import Checks ===========================================================
+
+# Evil test options for setup.py
+for arg in sys.argv[:]:
+    if arg.find('--disable-numpy') == 0:
+        sys.argv.remove(arg)
+        sys.modules['numpy'] = None
+    if arg.find('--disable-cython') == 0:
+        sys.argv.remove(arg)
+        sys.modules['Cython'] = None
 
 # Check Python version (2.5 or greater required)
 if not (sys.version_info[0:2] >= (2,5)):
@@ -89,7 +101,17 @@ try:
 except ImportError:
     fatal("Numpy not installed (version >= %s required)" % MIN_NUMPY)
 
-    
+try:
+    from Cython.Compiler.Main import Version, compile, compile_multiple, CompilationOptions
+    if version_check(Version.version, MIN_CYTHON):
+        HAVE_CYTHON = True
+    else:
+        HAVE_CYTHON = False
+        warn("Old Cython %s version ignored; at least %s required" % (Version.version, MIN_CYTHON))
+except ImportError:
+    HAVE_CYTHON = False
+    warn("Cython (http://cython.org) is not available; only default build possible")
+
 # === Platform-dependent compiler config ======================================
 
 
@@ -99,6 +121,9 @@ class ExtensionCreator(object):
         serves as a factory for Extension instances.  This is in a
         class as opposed to module code since the HDF5 location
         isn't known until runtime.
+
+        Note this is a purely C-oriented process; it doesn't know or
+        care about Cython.
     """
 
     def __init__(self, hdf5_loc=None):
@@ -146,7 +171,7 @@ class ExtensionCreator(object):
 
 class cybuild(build):
 
-    """ Cython-aware builder
+    """ Cython-aware builder.
     """
 
     user_options = build.user_options + \
@@ -157,29 +182,10 @@ class cybuild(build):
                      ('diag', 'd','Enable library debug logging'),
                      ('no-threads', 't', 'Build without thread support')]
 
-    boolean_options = build.boolean_options + ['cython', 'cython-only', 'threads','diag']
-
-
-    def get_hdf5_version(self):
-        """ Try to determine the installed HDF5 version and return either
-            16 or 18, or None if it can't be determined.
-        """
-        if self.hdf5 is not None:
-            cmd = reduce(op.join, (self.hdf5, 'bin', 'h5cc'))+" -showconfig"
-        else:
-            cmd = "h5cc -showconfig"
-        output = commands.getoutput(cmd)
-        l = output.find("HDF5 Version")
-        if l > 0:
-            if output[l:l+30].find('1.8') > 0:
-                return 18
-            elif output[l:l+30].find('1.6') > 0:
-                return 16
-        return None
+    boolean_options = build.boolean_options + ['cython', 'cython-only', 'no-threads','diag']
 
     def initialize_options(self):
         build.initialize_options(self)
-        self._default = True
 
         # Build options
         self.hdf5 = None
@@ -199,19 +205,12 @@ class cybuild(build):
         if self.no_threads:
             warn("Option --no-threads will disappear soon")
 
-        if any((self.cython, self.cython_only, self.diag, self.no_threads,
-                self.api, self.hdf5)):
-            self._default = False
-            self.cython = True
-
         if self.hdf5 is not None:
-            self._default = False
             self.hdf5 = op.abspath(self.hdf5)
             if not op.exists(self.hdf5):
                 fatal('Specified HDF5 directory "%s" does not exist' % self.hdf5)
 
         if self.api is not None:
-            self._default = False
             try:
                 self.api = int(self.api)
                 if self.api not in (16,18):
@@ -221,42 +220,63 @@ class cybuild(build):
 
     def run(self):
 
-        if self._default and op.exists('buildconf.pickle'):
-            # Read extensions info from pickle file
-            print "=> Using existing build configuration"
-            with open('buildconf.pickle','r') as f:
-                modules, extensions = pickle.load(f)
-        else:
-            print "=> Creating new build configuration"
-
-            # Try to guess the installed HDF5 version
-            if self.api is None:
-                self.api = self.get_hdf5_version()
-                if self.api is None:
-                    warn("Can't determine HDF5 version, assuming 1.6 (use --api= to override)")
-                    self.api = 16
+        if self.api is None:
+            self.api = self.get_hdf5_version()  # either 16 or 18
 
-            modules = MODULES[self.api]
-            creator = ExtensionCreator(self.hdf5)
-            extensions = [creator.create_extension(x) for x in modules]            
-            with open('buildconf.pickle','w') as f:
-                pickle.dump((modules, extensions), f)
+        modules = MODULES[self.api]
+        creator = ExtensionCreator(self.hdf5)
+        extensions = [creator.create_extension(x) for x in modules]
 
         self.distribution.ext_modules = extensions
 
-        if not all(op.exists(op.join(SRC_PATH, x+'.c')) for x in modules):
-            self.cython = True
-
-        # Rebuild the C source files if necessary
-        if self.cython:
-            self.compile_cython(sorted(modules))
+        # Cython must be run if any of the following are true:
+        # 1. Some of the .c files don't exist
+        # 2. The current config options don't match the last used options
+        # 3. Either option --cython or --cython-only is provided
+
+        src_missing = not all(op.exists(op.join(SRC_PATH, x+'.c')) for x in modules)
+        pxi = self.generate_pxi()
+        stale_pxi = pxi != self.read_pxi()
+
+        if any((src_missing, stale_pxi, self.cython, self.cython_only)):
+            if not HAVE_CYTHON:
+                fatal("Cython recompilation required, but Cython is unavailable or out of date")
+            if stale_pxi:
+                self.write_pxi(pxi)  # Do this AFTER the Cython check
+            self.compile_cython(sorted(modules), stale_pxi)
             if self.cython_only:
                 exit(0)
 
         # Hand over control to distutils
         build.run(self)
 
-    def get_pxi(self):
+        # For commands test and doc, which need to know about this build
+        with open(PICKLE_FILE,'w') as f:
+            pickle.dump((modules, extensions, self.build_lib), f)
+
+    def get_hdf5_version(self):
+        """ Try to determine the installed HDF5 version.
+
+            Returns either 16 or 18.  Defaults to 16 (and prints a warning)
+            if the installed version can't be identified.
+        """
+        if self.hdf5 is not None:
+            cmd = reduce(op.join, (self.hdf5, 'bin', 'h5cc'))+" -showconfig"
+        else:
+            cmd = "h5cc -showconfig"
+        output = commands.getoutput(cmd)
+        l = output.find("HDF5 Version")
+
+        if l > 0:
+            if output[l:l+30].find('1.8') > 0:
+                return 18
+            elif output[l:l+30].find('1.6') > 0:
+                return 16
+
+        warn("Can't determine HDF5 version, assuming 1.6 (use --api= to override)")
+        return 16
+
+    def generate_pxi(self):
         """ Generate a Cython .pxi file reflecting the current options. """
 
         pxi_str = \
@@ -276,17 +296,35 @@ DEF H5PY_THREADS = %(THREADS)d  # Enable thread-safety and non-blocking reads
                     "API_16": True, "API_18": self.api == 18,
                     "DEBUG": 10 if self.diag else 0, "THREADS": not self.no_threads}
 
-    def compile_cython(self, modules):
-        """ Regenerate the C source files for the build process.
-        """
+    def read_pxi(self):
+        """ Returns the current config.pxi file, or an empty string. """
+
+        pxi_path = op.join(SRC_PATH, 'config.pxi')
+        if not op.exists(pxi_path):
+            return ""
+
+        try:
+            f = open(pxi_path, 'r')
+            return f.read()
+        except (IOError, OSError):
+            fatal("Can't read file %s" % pxi_path)
+        else:
+            f.close()
+    
+    def write_pxi(self, pxi):
+        """ Unconditionally overwrite the config.pxi file """
 
+        pxi_path = op.join(SRC_PATH, 'config.pxi')
         try:
-            from Cython.Compiler.Main import Version, compile, compile_multiple, CompilationOptions
-        except ImportError:
-            fatal("Cython recompilation required, but Cython >=%s not installed." % MIN_CYTHON)
+            f = open(pxi_path, 'w')
+            f.write(pxi)
+            f.close()
+        except IOError:
+            fatal('Failed write to "%s"' % pxi_path)
 
-        if not version_check(Version.version, MIN_CYTHON):
-            fatal("Old Cython %s version detected; at least %s required" % (Version.version, MIN_CYTHON))
+    def compile_cython(self, modules, recompile_all=False):
+        """ Regenerate the C source files for the build process.
+        """
 
         print "Running Cython (%s)..." % Version.version
         print "  API level: %d" % self.api
@@ -294,33 +332,6 @@ DEF H5PY_THREADS = %(THREADS)d  # Enable thread-safety and non-blocking reads
         print "  Diagnostic mode: %s" % ('yes' if self.diag else 'no')
         print "  HDF5: %s" % ('default' if self.hdf5 is None else self.hdf5)
 
-        # 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()
-
         # Build each extension
         # This should be a single call to compile_multiple, but it's
         # broken in Cython 0.9.8.1.1
@@ -362,11 +373,15 @@ class test(Command):
 
     def run(self):
 
-        buildobj = self.distribution.get_command_obj('build')
-        buildobj.run()
+        try:
+            with open(PICKLE_FILE, 'r') as f:
+                modules, extensions, build_path = pickle.load(f)
+        except (IOError, OSError):
+            fatal("Project must be built before tests can be run")
+
         oldpath = sys.path
         try:
-            sys.path = [op.abspath(buildobj.build_lib)] + oldpath
+            sys.path = [op.abspath(build_path)] + oldpath
             import h5py.tests
             if not h5py.tests.runtests(None if self.sections is None else tuple(self.sections.split(',')), self.detail):
                 raise DistutilsError("Unit tests failed.")
@@ -390,9 +405,11 @@ class doc(Command):
 
     def run(self):
 
-        buildobj = self.distribution.get_command_obj('build')
-        buildobj.run()
-        pth = op.abspath(buildobj.build_lib)
+        try:
+            with open(PICKLE_FILE, 'r') as f:
+                modules, extensions, pth = pickle.load(f)
+        except (IOError, OSError):
+            fatal("Project must be built before docs can be compiled")
 
         if self.rebuild and op.exists('docs/build'):
             shutil.rmtree('docs/build')
@@ -437,7 +454,7 @@ class cyclean(Command):
 
         fnames = [ op.join(SRC_PATH, x+'.dep') for x in allmodules ] + \
                  [ op.join(SRC_PATH, x+'.c') for x in allmodules ] + \
-                 [ op.join(SRC_PATH, 'config.pxi'), 'buildconf.pickle']
+                 [ op.join(SRC_PATH, 'config.pxi'), PICKLE_FILE]
 
         for name in fnames:
             try:

-- 
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