[h5py] 124/455: Fix hashing, more thread decorators

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 b522c9ad2bba2ac2823f9e2515ac44fe47464400
Author: andrewcollette <andrew.collette at gmail.com>
Date:   Mon Sep 22 06:43:06 2008 +0000

    Fix hashing, more thread decorators
---
 h5py/h5.pxd       |  18 +++++----
 h5py/h5.pyx       | 118 +++++++++++++++++++++++++++++++++++++-----------------
 h5py/h5d.pyx      |  11 -----
 h5py/h5f.pyx      |  12 ------
 h5py/h5g.pyx      |  30 +++++++++-----
 h5py/h5p.pyx      |  12 ++++++
 h5py/std_code.pxi |   4 +-
 setup.py          |   2 +-
 8 files changed, 126 insertions(+), 81 deletions(-)

diff --git a/h5py/h5.pxd b/h5py/h5.pxd
index 51a2792..1697524 100644
--- a/h5py/h5.pxd
+++ b/h5py/h5.pxd
@@ -18,11 +18,6 @@ include "std_defs.pxi"
 
 # === Custom C extensions =====================================================
 
-cdef int _enable_exceptions() except -1
-cdef int _disable_exceptions() except -1
-
-cdef object standard_richcmp(object self, object other, int how)
-
 cdef class PHIL:
 
     cdef object lock
@@ -36,8 +31,7 @@ cpdef PHIL get_phil()
 
 cdef class H5PYConfig:
 
-    # Global 
-    cdef object _complex_names      # ('r','i')
+    cdef object _complex_names
     cdef readonly object API_16
     cdef readonly object API_18
     cdef readonly object DEBUG
@@ -51,6 +45,9 @@ cdef class ObjectID:
     cdef object _hash           # Used by subclasses to cache a hash value,
                                 # which may be expensive to compute.
 
+cdef object standard_richcmp(object self, object other, int how)
+cdef object obj_hash(ObjectID obj)
+
 # === HDF5 API ================================================================
 
 cdef extern from "hdf5.h":
@@ -64,7 +61,14 @@ cdef extern from "hdf5.h":
   herr_t H5open() except *
   herr_t H5close() except *
 
+  # For object hashing
+
+  ctypedef struct H5G_stat_t:
+    unsigned long fileno[2]
+    unsigned long objno[2]
 
+  herr_t H5Gget_objinfo(hid_t loc_id, char* name, int follow_link, H5G_stat_t *statbuf) except *
+ 
   # --- Reflection ------------------------------------------------------------
   ctypedef enum H5I_type_t:
     H5I_BADID        = -1
diff --git a/h5py/h5.pyx b/h5py/h5.pyx
index f529cdd..046baa4 100644
--- a/h5py/h5.pyx
+++ b/h5py/h5.pyx
@@ -48,24 +48,64 @@ IF H5PY_DEBUG:
     log_threads = logging.getLogger('h5py.threads')
 
 
+def loglevel(lev):
+    """ (INT lev)
+        
+        Shortcut to set the logging level on all library streams.
+        Does nothing if not built in debug mode.
+    """
+    IF H5PY_DEBUG:
+        for x in ('h5py.identifiers', 'h5py.functions', 'h5py.threads'):
+            l = logging.getLogger(x)
+            l.setLevel(lev)
+    ELSE:
+        pass
+
 # --- C extensions and classes ------------------------------------------------
 
 cdef object standard_richcmp(object self, object other, int how):
-    # This needs to be shared because of weird CPython quirks involving
-    # subclasses and the __hash__ method.
+    # HDF5 object identity is determined by comparing hash values.  In the
+    # absence of a logical comparision method (for example, TypeId.equal()),
+    # this hash-based identity is used for comparison.
+    
+    # Subject to:
+    # 1. Both must be of the same type
+    # 2. Both must be hashable
+    # 3. Only == and != comparisons are supported
+    #
+    # Otherwise NotImplemented is returned, for Python's fallback mechanics.
 
-    if how == 2 or how == 3:
-        
-        if not isinstance(self, ObjectID) and isinstance(other, ObjectID):
-            return NotImplemented
+    if how != 2 and how != 3:
+        return NotImplemented
 
+    if not type(self) == type(other) and isinstance(self, ObjectID):
+        return NotImplemented   # Can't compare across types
+
+    try:
         eq = (hash(self) == hash(other))
+    except TypeError:
+        return NotImplemented   # Can't compare unhashable instances
 
-        if how == 2:
-            return eq
-        return not eq
+    if how == 2:
+        return eq
+    return not eq
 
-    return NotImplemented
+cdef object obj_hash(ObjectID obj):
+    # Try to compute the hash of the given file-resident object, raising
+    # TypeError if it can't be done.
+    
+    # This is a counterpart to standard_richcmp.
+
+    cdef H5G_stat_t stat
+
+    phil.acquire()
+    try:
+        H5Gget_objinfo(obj.id, '.', 0, &stat)
+        return hash((stat.fileno[0], stat.fileno[1], stat.objno[0], stat.objno[1]))
+    except:
+        raise TypeError("Objects of class %s cannot be hashed" % obj.__class__.__name__)
+    finally:
+        phil.release()
 
 cdef class H5PYConfig:
 
@@ -190,38 +230,45 @@ cdef class ObjectID:
             across copies.
         """
         cdef ObjectID copy
-        copy = type(self)(self.id)
-        assert isinstance(copy, ObjectID), "ObjectID copy encountered invalid type"
-        if self._valid and not self._locked:
-            H5Iinc_ref(self.id)
-        copy._locked = self._locked
-        IF H5PY_DEBUG:
-            log_ident.debug("c %s" % str(self))
-        return copy
+        phil.acquire()
+        try:
+            copy = type(self)(self.id)
+            if self._valid and not self._locked:
+                H5Iinc_ref(self.id)
+            copy._locked = self._locked
+            IF H5PY_DEBUG:
+                log_ident.debug("c %s" % str(self))
+            return copy
+        finally:
+            phil.release()
 
     def __richcmp__(self, object other, int how):
         """ Supports only == and != """
         return standard_richcmp(self, other, how)
 
     def __hash__(self):
-        """ Hash method defaults to the identifer, as this cannot change over
-            the life of the object.
+        """ By default HDF5 objects are hashed based on their file and object
+            numbers.  Objects which are not file-resident cannot be hashed.
         """
-        return self.id
+        if self._hash is None:
+            self._hash = obj_hash(self)
+        return self._hash
 
-    
     def __str__(self):
-        ref = str(H5Iget_ref(self.id)) if self._valid else "X"
-        lck = "L" if self._locked else "U"
-
-        return "%s [%s] (%s) %d" % (self.__class__.__name__, ref, lck, self.id)
+        phil.acquire()
+        try:
+            ref = str(H5Iget_ref(self.id)) if self._valid else "X"
+            lck = "L" if self._locked else "U"
+            return "%s [%s] (%s) %d" % (self.__class__.__name__, ref, lck, self.id)
+        finally:
+            phil.release()
 
     def __repr__(self):
         return self.__str__()
 
 # === HDF5 "H5" API ===========================================================
 
-
+ at sync
 def get_libversion():
     """ () => TUPLE (major, minor, release)
 
@@ -236,13 +283,13 @@ def get_libversion():
 
     return (major, minor, release)
 
-
+ at sync
 def _close():
     """ Internal function; do not call unless you want to lose all your data.
     """
     H5close()
 
-
+ at sync
 def _open():
     """ Internal function; do not call unless you want to lose all your data.
     """
@@ -253,9 +300,6 @@ def _open():
 
 class H5Error(Exception):
     """ Base class for internal HDF5 library exceptions.
-        Subclass of EnvironmentError; errno is computed from the HDF5 major
-        and minor error numbers:
-            1000*(major number) + minor number
     """
     pass
 
@@ -444,7 +488,7 @@ cdef class ErrorStackElement:
     cdef readonly unsigned int line
     cdef readonly object desc
 
-    
+    @sync
     def __str__(self):
         return '%2d:%2d "%s" at %s (%s: %s)' % (self.maj_num, self.min_num,
                 self.desc, self.func_name, H5Eget_major(<H5E_major_t>self.maj_num),
@@ -467,7 +511,7 @@ cdef herr_t walk_cb(int n, H5E_error_t *err_desc, void* stack_in):
 
     return 0
 
-
+ at sync
 def error_stack():
     """ () => LIST error_stack
 
@@ -478,7 +522,7 @@ def error_stack():
     H5Ewalk(H5E_WALK_DOWNWARD, walk_cb, <void*>stack)
     return stack
 
-
+ at nosync
 def error_string():
     """ () => STRING error_stack
 
@@ -511,7 +555,7 @@ def error_string():
 
     return msg
 
-
+ at sync
 def clear():
     """ ()
 
@@ -565,7 +609,7 @@ cdef int _disable_exceptions() except -1:
 
 # === Library init ============================================================
 
-
+ at sync
 def _exithack():
     """ Internal function; do not call unless you want to lose all your data.
     """
diff --git a/h5py/h5d.pyx b/h5py/h5d.pyx
index 3d0ef86..7db815a 100644
--- a/h5py/h5d.pyx
+++ b/h5py/h5d.pyx
@@ -16,7 +16,6 @@
 include "std_code.pxi"
 
 # Pyrex compile-time imports
-from h5 cimport standard_richcmp
 from h5s cimport H5S_ALL, H5S_UNLIMITED, H5S_SCALAR, H5S_SIMPLE, \
                     H5Sget_simple_extent_type, H5Sclose, H5Sselect_all, \
                     H5Sget_simple_extent_ndims, H5Sget_select_npoints
@@ -30,8 +29,6 @@ from h5 cimport HADDR_UNDEF
 # Runtime imports
 import h5
 import h5t
-import h5s
-import h5g
 
 import_array()
 
@@ -338,13 +335,5 @@ cdef class DatasetID(ObjectID):
         """
         return H5Dget_storage_size(self.id)
 
-    def __richcmp__(self, object other, int how):
-        return standard_richcmp(self, other, how)
-
-    def __hash__(self):
-        if self._hash is None:
-            info = h5g.get_objinfo(self)
-            self._hash = hash( (info.fileno, info.objno) )
-        return self._hash
 
 
diff --git a/h5py/h5f.pyx b/h5py/h5f.pyx
index 2ccf169..d132e34 100644
--- a/h5py/h5f.pyx
+++ b/h5py/h5f.pyx
@@ -16,7 +16,6 @@
 include "std_code.pxi"
 
 # Pyrex compile-time imports
-from h5 cimport standard_richcmp
 from h5p cimport propwrap, pdefault, PropFAID, PropFCID, H5P_DEFAULT
 from h5t cimport typewrap
 from h5a cimport AttrID
@@ -28,7 +27,6 @@ from utils cimport emalloc, efree, pybool
 
 # Runtime imports
 import h5
-import h5g
 
 # === Public constants and data structures ====================================
 
@@ -307,16 +305,6 @@ cdef class FileID(ObjectID):
             only tracks free space until the file is closed.
         """
         return H5Fget_freespace(self.id)
-    
-    def __richcmp__(self, object other, int how):
-        return standard_richcmp(self, other, how)
-
-    def __hash__(self):
-        # Obtain the file number from the root group metadata
-        if self._hash is None:
-            info = h5g.get_objinfo(self)
-            self._hash = hash(info.fileno)
-        return self._hash
 
 
 
diff --git a/h5py/h5g.pyx b/h5py/h5g.pyx
index 1ad2bbf..50a8bbb 100644
--- a/h5py/h5g.pyx
+++ b/h5py/h5g.pyx
@@ -120,6 +120,7 @@ cdef class GroupIter:
 
 # COMPAT: 1.8 update
 IF H5PY_18API:
+    @sync
     def open(ObjectID loc not None, char* name, PropID gapl=None):
         """ (ObjectID loc, STRING name, PropGAID gapl=None)
 
@@ -127,6 +128,7 @@ IF H5PY_18API:
         """
         return GroupID(H5Gopen2(loc.id, name, pdefault(gapl)))
 ELSE:
+    @sync
     def open(ObjectID loc not None, char* name):
         """ (ObjectID loc, STRING name) => GroupID
 
@@ -136,6 +138,7 @@ ELSE:
 
 # COMPAT: 1.8 update
 IF H5PY_18API:
+    @sync
     def create(ObjectID loc not None, char* name, PropID lcpl=None,
                PropID gcpl=None, PropID gapl=None):
         """ (ObjectID loc, STRING name, PropLCID lcpl=None, PropGCID gcpl=None,
@@ -147,6 +150,7 @@ IF H5PY_18API:
                                                 pdefault(gcpl),
                                                 pdefault(gapl)))
 ELSE:
+    @sync
     def create(ObjectID loc not None, char* name, int size_hint=-1):
         """ (ObjectID loc, STRING name, INT size_hint=-1) => GroupID
 
@@ -176,6 +180,7 @@ cdef herr_t iter_cb_helper(hid_t gid, char *name, object int_tpl) except -1:
 
 # COMPAT: 1.8 deprecation
 IF H5PY_16API:
+    @sync
     def iterate(GroupID loc not None, char* name, object func, object data=None, 
                 int startidx=0):
         """ (GroupID loc, STRING name, FUNCTION func, OBJECT data=None, 
@@ -212,6 +217,7 @@ IF H5PY_16API:
 
 # COMPAT: 1.8 deprecation
 IF H5PY_16API:
+    @sync
     def get_objinfo(ObjectID obj not None, object name='.', int follow_link=1):
         """ (ObjectID obj, STRING name='.', BOOL follow_link=True) => GroupStat object
 
@@ -256,6 +262,7 @@ cdef class GroupID(ObjectID):
         def __init__(self, hid_t id_):
             self.links = LinkProxy(id_)
 
+    @sync
     def _close(self):
         """ ()
 
@@ -269,6 +276,7 @@ cdef class GroupID(ObjectID):
 
     # COMPAT: 1.8 deprecation
     IF H5PY_16API:
+        @sync
         def link(self, char* current_name, char* new_name, 
                  int link_type=H5G_LINK_HARD, GroupID remote=None):
             """ (STRING current_name, STRING new_name, INT link_type=LINK_HARD, 
@@ -292,6 +300,7 @@ cdef class GroupID(ObjectID):
 
     # COMPAT: 1.8 deprecation
     IF H5PY_16API:
+        @sync
         def unlink(self, char* name):
             """ (STRING name)
 
@@ -301,6 +310,7 @@ cdef class GroupID(ObjectID):
    
     # COMPAT: 1.8 deprecation 
     IF H5PY_16API:
+        @sync
         def move(self, char* current_name, char* new_name, GroupID remote=None):
             """ (STRING current_name, STRING new_name, GroupID remote=None)
 
@@ -318,6 +328,7 @@ cdef class GroupID(ObjectID):
 
     # COMPAT: 1.8 deprecation
     IF H5PY_16API:
+        @sync
         def get_num_objs(self):
             """ () => INT number_of_objects
 
@@ -329,6 +340,7 @@ cdef class GroupID(ObjectID):
 
     # COMPAT: 1.8 deprecation
     IF H5PY_16API:
+        @sync
         def get_objname_by_idx(self, hsize_t idx):
             """ (INT idx) => STRING object_name
 
@@ -356,6 +368,7 @@ cdef class GroupID(ObjectID):
 
     # COMPAT: 1.8 deprecation
     IF H5PY_16API:
+        @sync
         def get_objtype_by_idx(self, hsize_t idx):
             """ (INT idx) => INT object_type_code
 
@@ -378,6 +391,7 @@ cdef class GroupID(ObjectID):
 
     # COMPAT: 1.8 deprecation
     IF H5PY_16API:
+        @sync
         def get_linkval(self, char* name):
             """ (STRING name) => STRING link_value
 
@@ -408,6 +422,7 @@ cdef class GroupID(ObjectID):
 
     # COMPAT: 1.8 deprecation
     IF H5PY_16API:
+        @sync
         def set_comment(self, char* name, char* comment):
             """ (STRING name, STRING comment)
 
@@ -417,6 +432,7 @@ cdef class GroupID(ObjectID):
 
     # COMPAT: 1.8 deprecation
     IF H5PY_16API:
+        @sync
         def get_comment(self, char* name):
             """ (STRING name) => STRING comment
 
@@ -439,6 +455,7 @@ cdef class GroupID(ObjectID):
 
     # === Special methods =====================================================
 
+    @sync
     def __contains__(self, char* name):
         """ (STRING name)
 
@@ -450,25 +467,16 @@ cdef class GroupID(ObjectID):
         except H5Error:
             return False    
 
+    @nosync
     def __iter__(self):
         """ Return an iterator over the names of group members. """
         return GroupIter(self)
 
+    @sync
     def __len__(self):
         """ Number of group members """
         cdef hsize_t size
         H5Gget_num_objs(self.id, &size)
         return size
 
-    def __richcmp__(self, object other, int how):
-        return standard_richcmp(self, other, how)
-
-    def __hash__(self):
-        if self._hash is None:
-            IF H5PY_16API:
-                info = get_objinfo(self)
-                self._hash = hash( (info.fileno, info.objno) )
-            ELSE:
-                self._hash = self.id
-        return self._hash
 
diff --git a/h5py/h5p.pyx b/h5py/h5p.pyx
index 3cfc98e..b02d229 100644
--- a/h5py/h5p.pyx
+++ b/h5py/h5p.pyx
@@ -17,6 +17,7 @@
 
 # Pyrex compile-time imports
 
+from h5 cimport standard_richcmp
 from utils cimport  require_tuple, convert_dims, convert_tuple, \
                     emalloc, efree, pybool, require_list, \
                     check_numpy_write, check_numpy_read
@@ -32,6 +33,17 @@ import_array()
 
 # === C API ===================================================================
 
+cdef class PropClassID(PropID):
+
+    def __richcmp__(self, object other, int how):
+        return standard_richcmp(self, other, how)
+
+    def __hash__(self):
+        """ Since classes are library-created and immutable, they are uniquely
+            identified by their HDF5 identifiers.
+        """
+        return hash(self.id)
+
 cdef hid_t pdefault(PropID pid):
 
     if pid is None:
diff --git a/h5py/std_code.pxi b/h5py/std_code.pxi
index 8d80420..ff7d280 100644
--- a/h5py/std_code.pxi
+++ b/h5py/std_code.pxi
@@ -17,8 +17,8 @@ include "config.pxi"
 
 # Defines the following decorators:
 #
-# sync:     Acquire PHIL for this function, and log function entry and lock
-#           acquisition in debug mode
+# sync:     Acquire PHIL for this function, and log function entry  in
+#           debug mode.
 # nosync:   Don't acquire PHIL, but log function entry in debug mode.
 #
 
diff --git a/setup.py b/setup.py
index b3fbce1..96c37b3 100644
--- a/setup.py
+++ b/setup.py
@@ -47,7 +47,7 @@ from distutils.command.sdist import sdist
 
 # Basic package options
 NAME = 'h5py'
-VERSION = '0.3.1'
+VERSION = '0.4.0'
 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)

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