[h5py] 65/455: Implemented conditional compilation, debug support, HL fixes, browser.

Ghislain Vaillant ghisvail-guest at moszumanska.debian.org
Thu Jul 2 18:19:18 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 38f755d0392558364182435418198777c1555184
Author: andrewcollette <andrew.collette at gmail.com>
Date:   Fri Jul 4 02:07:16 2008 +0000

    Implemented conditional compilation, debug support, HL fixes, browser.
---
 h5py/browse.py        | 152 ++++++++++++++++++++++++++++++++++++++++++++++++++
 h5py/defs_c.pxd       |   1 -
 h5py/h5.pxd           |   1 +
 h5py/h5.pyx           |  43 ++++++++++----
 h5py/h5d.pyx          |   2 +-
 h5py/h5t.pyx          |  12 +++-
 h5py/highlevel.py     | 122 ++++++++++++++++++++++++++--------------
 h5py/tests/test_h5.py |   8 +--
 h5py/utils_hl.py      |   9 +++
 setup.py              |  75 +++++++++++++++++++++----
 10 files changed, 354 insertions(+), 71 deletions(-)

diff --git a/h5py/browse.py b/h5py/browse.py
new file mode 100644
index 0000000..61a5f29
--- /dev/null
+++ b/h5py/browse.py
@@ -0,0 +1,152 @@
+#+
+# 
+# This file is part of h5py, a low-level Python interface to the HDF5 library.
+# 
+# Copyright (C) 2008 Andrew Collette
+# http://h5py.alfven.org
+# License: BSD  (See LICENSE.txt for full license)
+# 
+# $Date$
+# 
+#-
+
+import cmd
+import os
+import posixpath
+from utils_hl import hbasename
+
+from h5py.highlevel import File, Group, Dataset, Datatype
+from h5py import h5g
+
+class _H5Browser(cmd.Cmd):
+
+    """
+        HDF5 file browser class which holds state between sessions.
+    """
+
+    def __init__(self):
+        """ Create a new browser instance.
+        """
+        cmd.Cmd.__init__(self)
+        self.path = '/'
+        self.known_paths = {}
+        self.file = None #: Holds a File instance while executing, the file name otherwise.
+
+    def __call__(self, what=None, mode='r', importdict=None):
+        """ Browse the file, putting any imported names into importdict. """
+
+        if what is None:
+            if self.file is None:
+                raise ValueError("Either a file name or File object must be supplied.")
+            else:
+                self.file = File(self.file, mode=mode)
+
+        elif isinstance(what, File):
+            self.file = what
+
+        elif isinstance(what, str):
+            self.file = File(what, mode=mode)
+
+        else:
+            raise ValueError("Only a string file name or an File object may be supplied.")
+
+        # Now self.file is a File object, no matter what
+
+        try:
+            self.path = self.known_paths[os.path.abspath(self.file.name)]
+        except KeyError:
+            self.path = '/'
+
+        self.importdict = importdict
+        self.cmdloop('Browsing "%s". Type "help" for commands, "exit" to exit.' % os.path.basename(self.file.name))
+        self.importdict = None  # don't hold a reference to this between browse sessions
+
+        self.known_paths[os.path.abspath(self.file.name)] = self.path
+        self.file = self.file.name
+
+    def _error(self, msg):
+        print "Error: "+str(msg)
+
+    def abspath(self, path):
+        """ Correctly interpret the given path fragment, relative to the
+            current path.
+        """
+        apath = posixpath.join(self.path, path)
+        apath = posixpath.normpath(apath)
+        return apath
+
+    def get_candidates(path, criterion=lambda grp, name: True):
+        """ Get a list of candidates, in the group pointed to by
+            "path", which satisfy a particular criterion.
+        """
+        pass
+
+    def do_exit(self, line):
+        return True
+
+    def do_EOF(self, line):
+        return True
+
+    def do_pwd(self, line):
+        print self.path
+
+    def do_cd(self, line):
+        path = line.strip()
+        if path == '': path = '/'
+        path = self.abspath(path)
+        dname = posixpath.dirname(path)
+        bname = posixpath.basename(path)
+        print dname, bname
+        try:
+            pgrp = self.file[dname]
+            if bname != '' and not pgrp.id.get_objinfo(bname).type == h5g.GROUP:
+                self._error('"%s" is not an HDF5 group' % bname)
+            else:
+                self.path = path
+        except:
+            self._error('Can\'t open group "%s"' % path)
+
+    def complete_cd(self, text, line, begidx, endidx):
+        text = text.strip()
+        grpname = posixpath.join(self.path,posixpath.dirname(text))
+        targetname = posixpath.basename(text)
+
+        try:
+            grp = self.file[grpname]
+            return [posixpath.join(grpname,x) for x in grp \
+                        if x.find(targetname) == 0 and \
+                        grp.id.get_objinfo(x).type == h5g.GROUP]
+        except:
+            return []
+
+    def do_ls(self, line):
+        """ List contents of the specified group, or this one """
+
+        line = line.strip()
+        if line == '':
+            grpname = self.path
+        else:
+            grpname = posixpath.join(self.path, line)
+
+        try:
+            grp = self.file[grpname]
+            for name in grp:
+                print name
+        except:
+            self._error('Can\'t list contents of group "%s"' % hbasename(grpname))
+
+    def complete_ls(self, *args):
+        return self.complete_cd(*args)
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/h5py/defs_c.pxd b/h5py/defs_c.pxd
index 69a7793..6ae13c2 100644
--- a/h5py/defs_c.pxd
+++ b/h5py/defs_c.pxd
@@ -36,4 +36,3 @@ cdef extern from "unistd.h":
   ctypedef long ssize_t
 
 
-
diff --git a/h5py/h5.pxd b/h5py/h5.pxd
index 95f8f4c..4e90b59 100644
--- a/h5py/h5.pxd
+++ b/h5py/h5.pxd
@@ -14,6 +14,7 @@
 # license is available at licenses/pytables.txt, in the distribution root
 # directory.
 
+include "conditions.pxi"
 from defs_c cimport size_t, ssize_t
 
 # Common structs and types from HDF5
diff --git a/h5py/h5.pyx b/h5py/h5.pyx
index 359bfe3..76b8231 100644
--- a/h5py/h5.pyx
+++ b/h5py/h5.pyx
@@ -9,8 +9,6 @@
 # $Date$
 # 
 #-
-
-
 """
     Common module for the HDF5 low-level interface library.  
 
@@ -19,9 +17,21 @@
     - API_VERS, API_VERS_TPL:  API version (1.6 or 1.8) used to compile h5py.
 
     All exception classes and error handling functions are also in this module.
+
+    This module is designed to be imported before any other h5py module is
+    executed.  It opens the library and enables debug logging, if required.
 """
+
+include "conditions.pxi"
 from python cimport PyErr_SetObject
 
+# Logging is only enabled when compiled with H5PY_DEBUG nonzero
+IF H5PY_DEBUG:
+    import logging
+    logger = logging.getLogger('h5py')
+    logger.setLevel(H5PY_DEBUG)
+    logger.addHandler(logging.StreamHandler())
+
 # === API =====================================================================
 
 def get_libversion():
@@ -38,10 +48,10 @@ def get_libversion():
 
     return (major, minor, release)
     
-HDF5_VERS_TPL = get_libversion()        
-HDF5_VERS = "%d.%d.%d" % HDF5_VERS_TPL
-API_VERS = '1.6'
-API_VERS_TPL = (1,6)
+hdf5_version_tuple = get_libversion()        
+hdf5_version = "%d.%d.%d" % hdf5_version_tuple
+api_version_tuple = (H5PY_API_MAJ, H5PY_API_MIN)
+api_version = H5PY_API
 
 
 class DDict(dict):
@@ -54,14 +64,24 @@ class DDict(dict):
 
 cdef class ObjectID:
         
+    property _valid:
+        """ Indicates whether or not this identifier points to an HDF5 object.
+        """
+        def __get__(self):
+            return H5Iget_type(self.id) != H5I_BADID
+
     def __cinit__(self, hid_t id_):
         """ Object init; simply records the given ID. """
         self._locked = 0
         self.id = id_
+        IF H5PY_DEBUG:
+            logger.debug("+ %s" % str(self))
 
     def __dealloc__(self):
         """ Automatically decrefs the ID, if it's valid. """
-        if (not self._locked) and (H5Iget_type(self.id) != H5I_BADID):
+        IF H5PY_DEBUG:
+            logger.debug("- %s" % str(self))
+        if (not self._locked) and self._valid:
             H5Idec_ref(self.id)
 
     def __copy__(self):
@@ -73,9 +93,11 @@ cdef class ObjectID:
         cdef ObjectID copy
         copy = type(self)(self.id)
         assert typecheck(copy, ObjectID), "ObjectID copy encountered invalid type"
-        if H5Iget_type(self.id) != H5I_BADID and not self._locked:
+        if self._valid and not self._locked:
             H5Iinc_ref(self.id)
         copy._locked = self._locked
+        IF H5PY_DEBUG:
+            logger.debug("c %s" % str(self))
         return copy
 
     def __richcmp__(self, object other, int how):
@@ -94,10 +116,11 @@ cdef class ObjectID:
         raise TypeError("Only equality comparisons are supported.")
 
     def __str__(self):
-        if H5Iget_type(self.id) != H5I_BADID:
+        if self._valid:
             ref = str(H5Iget_ref(self.id))
         else:
             ref = "INVALID"
+
         if self._locked:
             lstr = "locked"
         else:
@@ -108,8 +131,6 @@ cdef class ObjectID:
     def __repr__(self):
         return self.__str__()
 
-# === Automatic error handling ================================================
-
 
 # === Public exception hierarchy ==============================================
 
diff --git a/h5py/h5d.pyx b/h5py/h5d.pyx
index 02b2528..29dc9a3 100644
--- a/h5py/h5d.pyx
+++ b/h5py/h5d.pyx
@@ -183,7 +183,7 @@ cdef class DatasetID(ObjectID):
             H5Dwrite(self.id, mtype.id, mspace.id, fspace.id, plist_id, PyArray_DATA(arr_obj))
 
         finally:
-            if mtype_id is not None:
+            if mtype is not None:
                 mtype.close()
 
     def extend(self, object shape):
diff --git a/h5py/h5t.pyx b/h5py/h5t.pyx
index e406474..ee9211e 100644
--- a/h5py/h5t.pyx
+++ b/h5py/h5t.pyx
@@ -14,6 +14,8 @@
     HDF5 "H5T" data-type API
 """
 
+include "conditions.pxi"
+
 # Pyrex compile-time imports
 from defs_c cimport free
 from h5p cimport H5P_DEFAULT
@@ -298,6 +300,9 @@ cdef class TypeID(ObjectID):
     cdef object py_dtype(self):
         raise NotImplementedError("Don't know how to convert %s objects to Numpy" % self.__class__.__name__)
 
+    def __repr__(self):
+        return str(self)+" "+str(self.dtype)
+
     def commit(self, ObjectID group not None, char* name):
         """ (ObjectID group, STRING name)
 
@@ -624,7 +629,6 @@ cdef class TypeIntegerID(TypeAtomicID):
         return dtype( _order_map[self.get_order()] + 
                       _sign_map[self.get_sign()] + str(self.get_size()) )
 
-
 cdef class TypeFloatID(TypeAtomicID):
 
     """
@@ -1053,6 +1057,12 @@ def py_create(dtype dt not None, object complex_names=None, enum=None):
 
     if complex_names is not None:
         otype.complex_names = complex_names
+
+    IF H5PY_DEBUG:
+        import logging
+        logger = logging.getLogger('h5py')
+        logger.info( "H5T create: %s\n"
+                     "         => %s"  % (str(dt), repr(otype)))
     return otype
 
 
diff --git a/h5py/highlevel.py b/h5py/highlevel.py
index 17ee7ad..c363cbf 100644
--- a/h5py/highlevel.py
+++ b/h5py/highlevel.py
@@ -13,10 +13,18 @@
 import numpy
 
 from h5py import h5, h5f, h5g, h5s, h5t, h5d, h5a, h5p, h5z, h5i
-from utils_hl import slicer
+from h5py.h5 import H5Error
+from utils_hl import slicer, hbasename
 
+class HLObject(object):
 
-class Group(object):
+    name = property(lambda self: h5i.get_name(self.id),
+        doc = "Name of this object in the HDF5 file.  Not necessarily unique.")
+
+    def __repr__(self):
+        return str(self)
+
+class Group(HLObject):
 
     """ Represents an HDF5 group.
 
@@ -41,35 +49,36 @@ class Group(object):
         self._attrs = AttributeManager(self)
 
     def __setitem__(self, name, obj):
-        """ Add the given object to the group.  Here are the rules:
+        """ Add the given object to the group.  The action taken depends on
+            the type of object assigned:
 
-            1. If "obj" is a Dataset or Group object, a hard link is created
-                in this group which points to the given object.
+            1. Named HDF5 object (Dataset, Group, Datatype):
+                A hard link is created in this group which points to the
+                given object.
 
-            2. If "obj" is a Numpy ndarray, it is converted to a dataset
-                object, with default settings (contiguous storage, etc.).
+            2. Numpy ndarray:
+                The array is converted to a dataset object, with default
+                settings (contiguous storage, etc.).
 
-            3. If "obj is a Numpy dtype object or Datatype instance, commit
-                a copy of the datatype as a named datatype in the file.
+            3. Numpy dtype:
+                Commit a copy of the datatype as a named datatype in the file.
 
-            3. If "obj" is anything else, attempt to convert it to an ndarray
-                and store it.  Scalar values are stored as scalar datasets.
-                Raise ValueError if we can't understand the resulting array 
-                dtype.
+            4. Anything else:
+                Attempt to convert it to an ndarray and store it.  Scalar
+                values are stored as scalar datasets. Raise ValueError if we
+                can't understand the resulting array dtype.
         """
-        if isinstance(obj, Group) or isinstance(obj, Dataset):
+        if isinstance(obj, Group) or isinstance(obj, Dataset) or isinstance(obj, Datatype):
             self.id.link(name, h5i.get_name(obj.id), link_type=h5g.LINK_HARD)
+
         elif isinstance(obj, numpy.dtype):
             htype = h5t.py_create(obj)
             htype.commit(self.id, name)
-        elif isinstance(obj, Datatype):
-            htype = obj.id.copy()
-            htype.commit(self.id, name)
+
         else:
             if not isinstance(obj, numpy.ndarray):
                 obj = numpy.array(obj)
-            dset = Dataset(self, name, data=obj)
-            dset.close()
+            Dataset(self, name, data=obj)
 
     def __getitem__(self, name):
         """ Open an object attached to this group. 
@@ -80,8 +89,6 @@ class Group(object):
 
         if info.type == h5g.DATASET:
             dset = Dataset(self, name)
-            if dset.shape == ():
-                return dset[...]
             return dset
 
         elif info.type == h5g.GROUP:
@@ -103,21 +110,21 @@ class Group(object):
         return self.id.py_iter()
 
     def __str__(self):
-        return 'Group (%d members): ' % len(self) + ', '.join(['"%s"' % name for name in self])
-
-    def __repr__(self):
-        return str(self)
+        if self.id._valid:
+            return 'Group "%s" (%d members): %s' % (hbasename(self.name),
+                    len(self), ', '.join(['"%s"' % name for name in self]))
+        return "Closed group"
 
     def iteritems(self):
         for name in self:
-            return (name, self[name])
+            yield (name, self[name])
 
 class File(Group):
 
     """ Represents an HDF5 file on disk.
 
         Created with standard Python syntax File(name, mode).
-        Legal modes: r, r+, w, w+, a.
+        Legal modes: r, r+, w, w+, a  (default 'r')
 
         File objects inherit from Group objects; Group-like methods all
         operate on the HDF5 root group ('/').  Like Python file objects, you
@@ -133,7 +140,7 @@ class File(Group):
 
     # --- Public interface (File) ---------------------------------------------
 
-    def __init__(self, name, mode, noclobber=False):
+    def __init__(self, name, mode='r', noclobber=False):
         """ Create a new file object.  
 
             Valid modes (like Python's file() modes) are: 
@@ -178,12 +185,11 @@ class File(Group):
         h5f.flush(self.fid)
 
     def __str__(self):
-        return 'File "%s", root members: %s' % (self.name, ', '.join(['"%s"' % name for name in self]))
+        if self.id._valid:
+            return 'File "%s", root members: %s' % (self.name, ', '.join(['"%s"' % name for name in self]))
+        return "Closed file (%s)" % self.name
 
-    def __repr_(self):
-        return str(self)
-
-class Dataset(object):
+class Dataset(HLObject):
 
     """ High-level interface to an HDF5 dataset
     """
@@ -197,6 +203,15 @@ class Dataset(object):
     attrs = property(lambda self: self._attrs,
         doc = "Provides access to HDF5 attributes. See AttributeManager.")
 
+    def _getval(self):
+        arr = self[...]
+        if arr.shape == ():
+            return numpy.asscalar(arr)
+        return arr
+
+    value = property(_getval,
+        doc = "The entire dataset, as an array or scalar depending on the shape.")
+
     def __init__(self, group, name,
                     data=None, dtype=None, shape=None, 
                     chunks=None, compression=None, shuffle=False, fletcher32=False):
@@ -304,7 +319,10 @@ class Dataset(object):
             mtype = htype
 
         fspace = self.id.get_space()
-        fspace.select_hyperslab(start, count, stride)
+        if fspace.get_simple_extent_type() == h5s.SCALAR:
+            fspace.select_all()
+        else:
+            fspace.select_hyperslab(start, count, stride)
         mspace = h5s.create_simple(count)
 
         arr = numpy.ndarray(count, mtype.dtype)
@@ -339,12 +357,12 @@ class Dataset(object):
         self.id.write(mspace, fspace, array(val))
 
     def __str__(self):
-        return 'Dataset: '+str(self.shape)+'  '+repr(self.dtype)
+        if self.id._valid:
+            return 'Dataset "%s": %s %s' % (hbasename(self.name),
+                    str(self.shape), repr(self.dtype))
+        return "Closed dataset"
 
-    def __repr__(self):
-        return str(self)
-
-class AttributeManager(object):
+class AttributeManager(HLObject):
 
     """ Allows dictionary-style access to an HDF5 object's attributes.
 
@@ -390,7 +408,7 @@ class AttributeManager(object):
             h5a.delete(self.id, name)
         except H5Error:
             pass
-        attr = h5a.py_create(self.id, name, htype, space)
+        attr = h5a.create(self.id, name, htype, space)
         attr.write(value)
 
     def __delitem__(self, name):
@@ -408,9 +426,21 @@ class AttributeManager(object):
             yield (name, self[name])
 
     def __str__(self):
-        return "Attributes: "+', '.join(['"%s"' % x for x in self])
+        if self.id._valid:
+            rstr = 'Attributes of "%s": ' % hbasename(self.name)
+            if len(self) == 0:
+                rstr += '(none)'
+            else:
+                rstr += ', '.join(['"%s"' % x for x in self])
+        else:
+            rstr = "Attributes of closed object."
+
+        return rstr
 
-class Datatype(object):
+    def __repr__(self):
+        return str(self)
+
+class Datatype(HLObject):
 
     """
         Represents an HDF5 datatype.
@@ -423,7 +453,15 @@ class Datatype(object):
     def __init__(grp, name):
         self.id = h5t.open(grp.id, name)
 
+    def __str__(self):
+        if self.id._valid:
+            return "Named datatype object (%s)" % str(self.dtype)
+        return "Closed datatype object"
+
+# Browser component.  This is here to prevent issues with circular imports
+from browse import _H5Browser
 
+browse = _H5Browser()
 
 
 
diff --git a/h5py/tests/test_h5.py b/h5py/tests/test_h5.py
index 9908bea..44ca28f 100644
--- a/h5py/tests/test_h5.py
+++ b/h5py/tests/test_h5.py
@@ -19,7 +19,7 @@ class TestH5(unittest.TestCase):
         # For 1.6 API
         tpl = h5.get_libversion()
 
-        self.assertEqual(tpl, h5.HDF5_VERS_TPL)
-        self.assertEqual("%d.%d.%d" % tpl, h5.HDF5_VERS)
-        h5.API_VERS
-        h5.API_VERS_TPL
+        self.assertEqual(tpl, h5.hdf5_version_tuple)
+        self.assertEqual("%d.%d.%d" % tpl, h5.hdf5_version)
+        h5.api_version
+        h5.api_version_tuple
diff --git a/h5py/utils_hl.py b/h5py/utils_hl.py
index 3ae00b9..657f73c 100644
--- a/h5py/utils_hl.py
+++ b/h5py/utils_hl.py
@@ -2,6 +2,15 @@
 """
     Utility functions for high-level modules.
 """
+from posixpath import basename, normpath
+
+def hbasename(name):
+    """ Basename function with more readable handling of trailing slashes"""
+    bname = normpath(name)
+    bname = basename(bname)
+    if bname == '':
+        bname = '/'
+    return bname
 
 def slicer(shape, args):
     """ Parse a tuple containing Numpy-style extended slices.
diff --git a/setup.py b/setup.py
index 7de4235..58d07fe 100644
--- a/setup.py
+++ b/setup.py
@@ -17,7 +17,8 @@
 
     All commands take the usual distutils options, like --home, etc.  Pyrex is
     not required for installation, but will be invoked if the .c files are
-    missing or the option --pyrex (or --pyrex-only) is used.
+    missing, one of the --pyrex options is used, or if a non-default API 
+    version or debug level is requested.
 
     To build:
     python setup.py build
@@ -28,16 +29,20 @@
     To run the test suite locally (won't install anything):
     python setup.py test
 
+    Additional options (for all modes):
+        --pyrex         Have Pyrex recompile changed *.pyx files.
+        --pyrex-only    Have Pyrex recompile changed *.pyx files, and stop.
+        --pyrex-force   Recompile all *.pyx files, regardless of timestamps.
+
+        --api=<n>       Specifies API version.  Only "16" is currently allowed.
+        --debug=<n>     If nonzero, compile in debug mode.  The number is
+                        interpreted as a logging-module level number.
+
     Advanced developer options:
     python setup.py dev [--doc] [--clean] [--readme=<name.html>]
         --doc:      Rebuild HTML documentation (requires epydoc)
         --clean:    Wipe out build/ and Pyrex-created .c, .dep files
         --readme:   Compile the RST readme file into an HTML fragment
-
-    Universal options:
-        --pyrex         Have Pyrex recompile changed *.pyx files
-        --pyrex-only    Have Pyrex recompile changed *.pyx files, and stop.
-        --pyrex-force   Recompile all *.pyx files, regardless of timestamps
 """
 
 # === Global constants ========================================================
@@ -51,6 +56,8 @@ MIN_NUMPY = '1.0.3'
 custom_include_dirs = []    # = ["/some/other/path", "/an/other/path"]
 custom_library_dirs = []
 
+AUTO_HDR = "# This file is automatically generated.  Do not edit."
+
 # === Initial imports and utilities ===========================================
 
 from distutils.cmd import Command
@@ -77,19 +84,33 @@ def warn(instring):
 ENABLE_PYREX = False
 PYREX_ONLY = False
 PYREX_FORCE = False
+
+API_VERS = (1,6)
+DEBUG_LEVEL = 0
 DEV_MODE = False
+
 for arg in sys.argv[:]:
     if arg == '--pyrex':
         ENABLE_PYREX = True
         sys.argv.remove(arg)
-    if arg == '--pyrex-only':
+    elif arg == '--pyrex-only':
         ENABLE_PYREX = True
         PYREX_ONLY = True
         sys.argv.remove(arg)
-    if arg == '--pyrex-force':
+    elif arg == '--pyrex-force':
         ENABLE_PYREX=True
         PYREX_FORCE = True
         sys.argv.remove(arg)
+    elif arg.find('--api=') == 0:
+        api = arg[6:]
+        if api == '16':
+            API_VERS = (1,6)
+        else:
+            fatal('Unrecognized API version "%s" (only "16" currently allowed)' % api)
+        sys.argv.remove(arg)
+    elif arg.find('--debug=') == 0:
+        DEBUG_LEVEL = int(arg[8:])
+        sys.argv.remove(arg)
 
 if "dev" in sys.argv:
     DEV_MODE = True
@@ -123,7 +144,7 @@ vers_in = open('VERSION.txt', 'r')
 VERSION = vers_in.read().strip()
 vers_out = open(os.path.join(NAME,'version.py'),'w')
 rdfile = open('README.txt','r')
-vers_out.write('# This file is automatically generated; do not edit.\n')
+vers_out.write(AUTO_HDR+'\n')
 vers_out.write('"""\nPackage "h5py" extended information\n\n%s"""\nversion = "%s"\n\n' % (rdfile.read(), VERSION))
 rdfile.close()
 vers_out.close()
@@ -155,14 +176,44 @@ extra_compile_args = pyx_extra_args
 # Pyrex source files (without extension)
 pyrex_sources = [os.path.join(pyx_src_path, x) for x in pyx_modules]
 
-# Enable Pyrex if requested or needed
-if ENABLE_PYREX or not all([os.path.exists(x+'.c') for x in pyrex_sources]):
+# Check if the conditions.pxi file is up-to-date
+cond_path = os.path.join(pyx_src_path, 'conditions.pxi')
+cond = \
+"""
+%s
+
+DEF H5PY_API_MAJ = %d
+DEF H5PY_API_MIN = %d
+DEF H5PY_DEBUG = %d
+DEF H5PY_API = "%d.%d"
+""" % (AUTO_HDR, API_VERS[0], API_VERS[1], DEBUG_LEVEL,API_VERS[0], API_VERS[1])
+
+cond_file = open(cond_path,'r')
+cond_present = cond_file.read()
+cond_file.close()
+if cond_present != cond:
+    ENABLE_PYREX = True
+
+# If for some reason the .c files are missing, Pyrex is required.
+if not all([os.path.exists(x+'.c') for x in pyrex_sources]):
+    ENABLE_PYREX = True
+
+if ENABLE_PYREX:
+    print "Running Pyrex..."
     try:
         from Pyrex.Compiler.Main import Version
 
         if Version.version >= MIN_PYREX:
             from Pyrex.Compiler.Main import compile_multiple, CompilationOptions
 
+            # If we regenerate the file every time, Pyrex's timestamp checking
+            # is useless.  So only replace it if it's out of date.
+            if cond_present != cond:
+                print "Replacing conditions file..."
+                cond_file = open(cond_path,'w')
+                cond_file.write(cond)
+                cond_file.close()
+
             opts = CompilationOptions(verbose=True, timestamps=(not PYREX_FORCE))
             results = compile_multiple( [x+'.pyx' for x in pyrex_sources], opts)
 
@@ -178,6 +229,8 @@ if ENABLE_PYREX or not all([os.path.exists(x+'.c') for x in pyrex_sources]):
 
     except ImportError:
         fatal("Pyrex recompilation required, but Pyrex not installed.")
+else:
+    print "Pyrex not required, skipping."
 
 # Create extensions
 pyx_extensions = []

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