[h5py] 134/455: Various fixes and additions; H5A improvements for 1.8

Ghislain Vaillant ghisvail-guest at moszumanska.debian.org
Thu Jul 2 18:19:25 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 24dcdb12fdb00044e20f7132341116376a78824d
Author: andrewcollette <andrew.collette at gmail.com>
Date:   Sat Oct 11 03:42:08 2008 +0000

    Various fixes and additions; H5A improvements for 1.8
---
 h5py/defs.pxd          |  32 ++++-
 h5py/h5a.pyx           | 342 ++++++++++++++++++++++++++++++++-----------------
 h5py/h5g.pyx           |  95 +++++++-------
 h5py/highlevel.py      | 174 ++++++++++++++++---------
 h5py/tests/test_h5a.py |  28 ++--
 h5py/utils.pxd         |   4 +-
 h5py/utils.pyx         |  14 +-
 setup.py               |   7 +-
 8 files changed, 429 insertions(+), 267 deletions(-)

diff --git a/h5py/defs.pxd b/h5py/defs.pxd
index 2fdf6ab..c57b5ff 100644
--- a/h5py/defs.pxd
+++ b/h5py/defs.pxd
@@ -392,8 +392,8 @@ cdef extern from "hdf5.h":
   int    H5Gget_objname_by_idx(hid_t loc_id, hsize_t idx, char *name, size_t size ) except *
   int    H5Gget_objtype_by_idx(hid_t loc_id, hsize_t idx ) except *
 
-  ctypedef herr_t (*H5G_iterate_t)(hid_t group, char *name, op_data) except -1
-  herr_t H5Giterate(hid_t loc_id, char *name, int *idx, H5G_iterate_t operator, operator_data  ) except *
+  ctypedef herr_t (*H5G_iterate_t)(hid_t group, char *name, void* op_data) except 2
+  herr_t H5Giterate(hid_t loc_id, char *name, int *idx, H5G_iterate_t operator, void* data) except *
   herr_t H5Gget_objinfo(hid_t loc_id, char* name, int follow_link, H5G_stat_t *statbuf) except *
 
   herr_t H5Gget_linkval(hid_t loc_id, char *name, size_t size, char *value) except *
@@ -1214,8 +1214,8 @@ cdef extern from "hdf5.h":
   hid_t     H5Aget_space(hid_t attr_id) except *
   hid_t     H5Aget_type(hid_t attr_id) except *
 
-  ctypedef herr_t (*H5A_operator_t)(hid_t loc_id, char *attr_name, operator_data) except -1
-  herr_t    H5Aiterate(hid_t loc_id, unsigned * idx, H5A_operator_t op, op_data) except *
+  ctypedef herr_t (*H5A_operator_t)(hid_t loc_id, char *attr_name, void* operator_data) except 2
+  herr_t    H5Aiterate(hid_t loc_id, unsigned * idx, H5A_operator_t op, void* op_data) except *
 
   IF H5PY_18API:
 
@@ -1225,11 +1225,29 @@ cdef extern from "hdf5.h":
       H5T_cset_t        cset        # Character set of attribute name
       hsize_t           data_size   # Size of raw data
 
-    herr_t H5Aopen(hid_t obj_id, char *attr_name, hid_t aapl_id) 
+    hid_t H5Acreate_by_name(hid_t loc_id, char *obj_name, char *attr_name,
+        hid_t type_id, hid_t space_id, hid_t acpl_id, hid_t aapl_id, hid_t lapl_id) except *
+ 
+    herr_t H5Aopen(hid_t obj_id, char *attr_name, hid_t aapl_id) except *
     herr_t H5Aopen_by_name( hid_t loc_id, char *obj_name, char *attr_name,
-        hid_t aapl_id, hid_t lapl_id) 
+        hid_t aapl_id, hid_t lapl_id) except *
     herr_t H5Aopen_by_idx(hid_t loc_id, char *obj_name, H5_index_t idx_type,
-        H5_iter_order_t order, hsize_t n, hid_t aapl_id, hid_t lapl_id) 
+        H5_iter_order_t order, hsize_t n, hid_t aapl_id, hid_t lapl_id) except *
+    htri_t H5Aexists_by_name( hid_t loc_id, char *obj_name, char *attr_name,
+                                hid_t lapl_id) except *
+    htri_t H5Aexists(hid_t obj_id, char *attr_name) except *
+
+    herr_t H5Arename(hid_t loc_id, char *old_attr_name, char *new_attr_name) except *
+    herr_t H5Arename_by_name(hid_t loc_id, char *obj_name, char *old_attr_name,
+            char *new_attr_name, hid_t lapl_id) except *
+
+    herr_t H5Aget_info( hid_t attr_id, H5A_info_t *ainfo) except *
+    herr_t H5Aget_info_by_name(hid_t loc_id, char *obj_name, char *attr_name,
+                                H5A_info_t *ainfo, hid_t lapl_id) except *
+    herr_t H5Aget_info_by_idx(hid_t loc_id, char *obj_name, H5_index_t idx_type,
+              H5_iter_order_t order, hsize_t n, H5A_info_t *ainfo, hid_t lapl_id) except *
+
+
 
 
 
diff --git a/h5py/h5a.pyx b/h5py/h5a.pyx
index 518ac48..a578787 100644
--- a/h5py/h5a.pyx
+++ b/h5py/h5a.pyx
@@ -32,157 +32,264 @@ import_array()
 
 # === General attribute operations ============================================
 
- at sync
-def create(ObjectID loc not None, char* name, TypeID tid not None, 
-            SpaceID space not None):
-    """ (ObjectID loc, STRING name, TypeID tid, SpaceID space) 
-        => AttrID
+# --- create, create_by_name ---
+
+IF H5PY_18API:
+    @sync
+    def create(ObjectID loc not None, char* name, TypeID tid not None,
+        SpaceID space not None, *, char* obj_name='.', PropID lapl=None):
+        """(ObjectID loc, STRING name, TypeID tid, SpaceID space, **kwds) => AttrID
+            
+        Create a new attribute, attached to an existing object.
+
+        Keywords:
+        * STRING obj_name (".")     Attach attribute to this group member
+        * PropID lapl (None)        Determines how obj_name is interpreted
+        """
+
+        return AttrID(H5Acreate_by_name(loc.id, obj_name, name, tid.id,
+                space.id, H5P_DEFAULT, H5P_DEFAULT, pdefault(lapl)))
+
+ELSE:
+    @sync
+    def create(ObjectID loc not None, char* name, TypeID tid not None, 
+        SpaceID space not None):
+        """(ObjectID loc, STRING name, TypeID tid, SpaceID space) => AttrID
 
         Create a new attribute attached to a parent object, specifiying an 
         HDF5 datatype and dataspace.
-    """
-    return AttrID(H5Acreate(loc.id, name, tid.id, space.id, H5P_DEFAULT))
+        """
+        return AttrID(H5Acreate(loc.id, name, tid.id, space.id, H5P_DEFAULT))
+
+
+# --- open, open_by_name, open_by_idx ---
 
 IF H5PY_18API:
     @sync
-    def open(ObjectID loc not None, char* name=NULL, int idx=-1, *,
-            char* obj_name='.', int idx_type=H5_INDEX_NAME, int order=H5_ITER_NATIVE,
+    def open(ObjectID loc not None, char* name=NULL, int index=-1, *,
+            char* obj_name='.', int index_type=H5_INDEX_NAME, int order=H5_ITER_NATIVE,
             PropID lapl=None):
-        """
-            (ObjectID loc, STRING name=NULL, INT order=-1, **kwds)
-            => AttrID
+        """(ObjectID loc, STRING name=, INT index=, **kwds) => AttrID
        
-            Open an attribute attached to an existing object.  You must specify
-            exactly one of either name or idx.
-
-            Keyword-only arguments:
-            * STRING obj_name (NULL):       Attribute is attached to this group member
-            * PropID lapl (None):           Controls how "obj_name" is interpreted
-            * INT idx_type (h5.INDEX_NAME)  Controls how idx is interpreted
-            * INT order (h5.ITER_NATIVE)    Controls how idx is interpreted
+        Open an attribute attached to an existing object.  You must specify
+        exactly one of either name or idx.
+
+        Keyword-only arguments:
+        * STRING obj_name ("."):         Attribute is attached to this group member
+        * PropID lapl (None):            Controls how "obj_name" is interpreted
+        * INT index_type (h5.INDEX_NAME) Controls how idx is interpreted
+        * INT order (h5.ITER_NATIVE)     Controls how idx is interpreted
         """
-        if (name == NULL and idx < 0) or (name != NULL and idx >= 0):
-            raise ValueError("Exactly one of name or idx must be specified")
+        if (name == NULL and index < 0) or (name != NULL and index >= 0):
+            raise TypeError("Exactly one of name or idx must be specified")
 
         if name != NULL:
             return AttrID(H5Aopen_by_name(loc.id, obj_name, name,
                             H5P_DEFAULT, pdefault(lapl)))
         else:
             return AttrID(H5Aopen_by_idx(loc.id, obj_name,
-                <H5_index_t>idx_type, <H5_iter_order_t>order, idx,
+                <H5_index_t>index_type, <H5_iter_order_t>order, index,
                 H5P_DEFAULT, pdefault(lapl)))
 
 ELSE:
     @sync
-    def open(ObjectID loc not None, char* name=NULL, int idx=-1):
-        """ (ObjectID loc, STRING name=NULL, INT idx=-1) => AttrID
+    def open(ObjectID loc not None, char* name=NULL, int index=-1):
+        """(ObjectID loc, STRING name=, INT index=) => AttrID
 
-            Open an attribute attached to an existing object.  You must specify
-            exactly one of either name or idx.
+        Open an attribute attached to an existing object.  You must specify
+        exactly one of either name or idx.
         """
-        if (name == NULL and idx < 0) or (name != NULL and idx >= 0):
-            raise ValueError("Exactly one of name or idx must be specified")
+        if (name == NULL and index < 0) or (name != NULL and index >= 0):
+            raise TypeError("Exactly one of name or idx must be specified")
 
         if name != NULL:
             return AttrID(H5Aopen_name(loc.id, name))
         else:
-            return AttrID(H5Aopen_idx(loc.id, idx))
+            return AttrID(H5Aopen_idx(loc.id, index))
+
+
+# --- exists, exists_by_name ---
+
+IF H5PY_18API:
+    @sync
+    def exists(ObjectID loc not None, char* name, *,
+                char* obj_name=NULL, PropID lapl=None):
+        """(ObjectID loc, STRING name, **kwds) => BOOL
+
+        Determine if an attribute is attached to this object.
+
+        Keywords:
+        * STRING obj_name:  Look for attributes attached to this group member
+        * PropID lapl:      Determines how "obj_name" is interpreted
+        """
+        if obj_name is NULL:
+            return <bint>H5Aexists(loc.id, name)
+        else:
+            return <bint>H5Aexists_by_name(loc.id, obj_name, name, pdefault(lapl))
+ELSE:
+    cdef herr_t cb_exist(hid_t loc_id, char* attr_name, void* ref_name) except 2:
+
+        if strcmp(attr_name, <char*>ref_name) == 0:
+            return 1
+        return 0
+
+    @sync
+    def exists(ObjectID loc not None, char* name):
+        """(ObjectID loc, STRING name) => BOOL
+
+        Determine if an attribute named "ref_name" is attached to this object.
+        """
+        cdef unsigned int i=0
+
+        return <bint>H5Aiterate(loc.id, &i, <H5A_operator_t>cb_exist, <void*>name)
+
+
+# --- rename, rename_by_name ---
+
+IF H5PY_18API:
+    @sync
+    def rename(ObjectID loc not None, char* name, char* new_name, *,
+        char* obj_name='.', PropID lapl=None):
+        """(ObjectID loc, STRING name, STRING new_name, **kwds)
+
+        Rename an attribute.
+
+        Keywords:
+        * STRING obj_name (".")     Attribute is attached to this group member
+        * PropID lapl (None)        Determines how obj_name is interpreted
+        """
+        H5Arename_by_name(loc.id, obj_name, name, new_name, pdefault(lapl))
 
 @sync
 def delete(ObjectID loc not None, char* name):
-    """ (ObjectID loc, STRING name)
+    """(ObjectID loc, STRING name)
 
-        Remove an attribute from an object.
+    Remove an attribute from an object.
     """
     H5Adelete(loc.id, name)
 
 @sync
 def get_num_attrs(ObjectID loc not None):
-    """ (ObjectID loc) => INT number_of_attributes
+    """(ObjectID loc) => INT
 
-        Determine the number of attributes attached to an HDF5 object.
+    Determine the number of attributes attached to an HDF5 object.
     """
     return H5Aget_num_attrs(loc.id)
 
-cdef herr_t iter_cb(hid_t loc_id, char *attr_name, object int_tpl) except -1:
-    # Iteration callback.  Returns 0 under normal execution, +1 to stop early
-    # if StopIteration is raised, and -1 if any other exception occurrs.
-    loc, func, data = int_tpl
+cdef class _AttrVisitor:
 
-    try:
-        func(loc, attr_name, data)
-    except StopIteration:
-        return 1
+    cdef object func
+    cdef object retval
+
+    def __init__(self, func):
+        self.func = func
+        self.retval = None
 
+cdef herr_t cb_attr_iter(hid_t loc_id, char* attr_name, void* vis_in) except 2:
+
+    cdef _AttrVisitor vis = <_AttrVisitor>vis_in
+
+    vis.retval = vis.func(attr_name)
+
+    if vis.retval is not None:
+        return 1
     return 0
 
 @sync
-def iterate(ObjectID loc not None, object func, object data=None, int startidx=0):
-    """ (ObjectID loc, FUNCTION func, OBJECT data=None, UINT startidx=0)
-        => INT last_attribute_index
-
-        Iterate an arbitrary Python function over the attributes attached
-        to an object.  You can also start at an arbitrary attribute by
-        specifying its (zero-based) index.
-
-        Your function:
-        1.  Should accept three arguments: the ObjectID for the parent object, 
-            the (STRING) name of the attribute, and an arbitrary Python object
-            you provide as data.  Any return value is ignored.
-        2.  Raise StopIteration to bail out before all attributes are processed.
-        3.  Raising anything else immediately aborts iteration, and the
-            exception is propagated.
+def iterate(ObjectID loc not None, object func, int index=0):
+    """(ObjectID loc, CALLABLE func, INT index=0) => <Return value from func>
+
+    Iterate a callable (function, method or callable object) over the
+    attributes attached to this object.  You callable should have the
+    signature:
+
+        func(STRING name, *args) => Result
+
+    Returning None continues iteration; returning anything else aborts
+    iteration and returns that value.
+
+    The parameter *args will make your code forward-compatible with the
+    1.8.X version of this function, which supplies additional arguments
+    to the callback.
     """
-    cdef unsigned int i
-    if startidx < 0:
+    if index < 0:
         raise ValueError("Starting index must be a non-negative integer.")
-    i = startidx
 
-    int_tpl = (loc, func, data)
+    cdef unsigned int i = index
+    cdef _AttrVisitor vis = _AttrVisitor(func)
 
-    H5Aiterate(loc.id, &i, <H5A_operator_t>iter_cb, int_tpl)
+    H5Aiterate(loc.id, &i, <H5A_operator_t>cb_attr_iter, <void*>vis)
 
-cdef herr_t list_cb(hid_t loc_id, char *attr_name, object listin):
-    
-    cdef list thelist
-    thelist = listin
+    return vis.retval
 
-    thelist.append(attr_name)
-    return 0
 
 @sync
 def py_listattrs(ObjectID loc not None):
-    """ (ObjectID loc) => LIST
+    """(ObjectID loc) => LIST
 
-        Get a list of the names of the attributes attached to an object.
+    Get a list of the names of the attributes attached to an object.
     """
-    cdef list retlist
-    cdef unsigned int i
-    i = 0
     retlist = []
-    H5Aiterate(loc.id, &i, <H5A_operator_t>list_cb, retlist)
+    iterate(loc, retlist.append)
     return retlist
 
-cdef herr_t cb_exist(hid_t loc_id, char* attr_name, object ref_name):
 
-    if ref_name == attr_name:
-        return 1
-    return 0
 
- at sync
-def py_exists(ObjectID loc not None, object ref_name):
-    """ (ObjectID loc, STRING ref_name) => BOOL
 
-        Determine if an attribute named "ref_name" is attached to this object.
-    """
-    cdef unsigned int i
-    cdef herr_t retval
-    i=0
-
-    retval = H5Aiterate(loc.id, &i, <H5A_operator_t>cb_exist, ref_name)
-    
-    return <bint>retval
-        
+IF H5PY_18API:
+    cdef class AttrInfo:
+
+        cdef H5A_info_t info
+
+        property corder_valid:
+            """Indicates if the creation order is valid"""
+            def __get__(self):
+                return <bint>self.info.corder_valid
+        property corder:
+            """Creation order"""
+            def __get__(self):
+                return <int>self.info.corder
+        property cset:
+            """Character set of attribute name (integer typecode from h5t)"""
+            def __get__(self):
+                return <int>self.info.cset
+        property data_size:
+            """Size of raw data"""
+            def __get__(self):
+                return self.info.data_size
+
+    @sync
+    def get_info(ObjectID loc not None, char* name=NULL, int index=-1, *,
+                char* obj_name='.', PropID lapl=None,
+                int index_type=H5_INDEX_NAME, int order=H5_ITER_NATIVE):
+        """(ObjectID loc, STRING name=, INT index=, **kwds) => AttrInfo
+
+        Get information about an attribute, in one of two ways:
+
+        1. If you have the attribute identifier, just pass it in
+        2. If you have the parent object, supply it and exactly one of
+           either name or index.
+
+        Keywords:
+        * STRING obj_name (".")             Use this group member instead
+        * PropID lapl (None)                How "obj_name" is resolved
+        * INT index_type (h5.INDEX_NAME)    Which index to use
+        * INT order (h5.ITER_NATIVE)        What order the index is in
+        """
+        cdef AttrInfo info = AttrInfo()
+
+        if name == NULL and index < 0:
+            H5Aget_info(loc.id, &info.info)
+        elif name != NULL and index >= 0:
+            raise TypeError("At most one of name and index may be specified")
+        elif name != NULL:
+            H5Aget_info_by_name(loc.id, obj_name, name, &info.info, pdefault(lapl))
+        elif index >= 0:
+            H5Aget_info_by_idx(loc.id, obj_name, <H5_index_t>index_type,
+                <H5_iter_order_t>order, index, &info.info, pdefault(lapl))
+
+        return info
+
 # === Attribute class & methods ===============================================
 
 cdef class AttrID(ObjectID):
@@ -205,14 +312,12 @@ cdef class AttrID(ObjectID):
         Equality: Identifier comparison
     """
     property name:
-        """ The attribute's name
-        """
+        """The attribute's name"""
         def __get__(self):
             return self.get_name()
 
     property shape:
-        """ A Numpy-style shape tuple representing the attribute's dataspace.
-        """
+        """A Numpy-style shape tuple representing the attribute's dataspace"""
         def __get__(self):
 
             cdef SpaceID space
@@ -220,8 +325,7 @@ cdef class AttrID(ObjectID):
             return space.get_simple_extent_dims()
 
     property dtype:
-        """ A Numpy-stype dtype object representing the attribute's datatype
-        """
+        """A Numpy-stype dtype object representing the attribute's datatype"""
         def __get__(self):
 
             cdef TypeID tid
@@ -230,24 +334,24 @@ cdef class AttrID(ObjectID):
 
     @sync
     def _close(self):
-        """ ()
+        """()
 
-            Close this attribute and release resources.  You don't need to
-            call this manually; attributes are automatically destroyed when
-            their Python wrappers are freed.
+        Close this attribute and release resources.  You don't need to
+        call this manually; attributes are automatically destroyed when
+        their Python wrappers are freed.
         """
         H5Aclose(self.id)
 
     @sync
     def read(self, ndarray arr_obj not None):
-        """ (NDARRAY arr_obj)
+        """(NDARRAY arr_obj)
 
-            Read the attribute data into the given Numpy array.  Note that the 
-            Numpy array must have the same shape as the HDF5 attribute, and a 
-            conversion-compatible datatype.
+        Read the attribute data into the given Numpy array.  Note that the 
+        Numpy array must have the same shape as the HDF5 attribute, and a 
+        conversion-compatible datatype.
 
-            The Numpy array must be writable, C-contiguous and own its data.
-            If this is not the case, an ValueError is raised and the read fails.
+        The Numpy array must be writable, C-contiguous and own its data.
+        If this is not the case, an ValueError is raised and the read fails.
         """
         cdef TypeID mtype
         cdef hid_t space_id
@@ -267,14 +371,14 @@ cdef class AttrID(ObjectID):
 
     @sync
     def write(self, ndarray arr_obj not None):
-        """ (NDARRAY arr_obj)
+        """(NDARRAY arr_obj)
 
-            Write the contents of a Numpy array too the attribute.  Note that
-            the Numpy array must have the same shape as the HDF5 attribute, and
-            a conversion-compatible datatype.  
+        Write the contents of a Numpy array too the attribute.  Note that
+        the Numpy array must have the same shape as the HDF5 attribute, and
+        a conversion-compatible datatype.  
 
-            The Numpy array must be C-contiguous and own its data.  If this is
-            not the case, ValueError will be raised and the write will fail.
+        The Numpy array must be C-contiguous and own its data.  If this is
+        not the case, ValueError will be raised and the write will fail.
         """
         cdef TypeID mtype
         cdef hid_t space_id
@@ -293,9 +397,9 @@ cdef class AttrID(ObjectID):
 
     @sync
     def get_name(self):
-        """ () => STRING name
+        """() => STRING name
 
-            Determine the name of an attribute, given its identifier.
+        Determine the name of an attribute, given its identifier.
         """
         cdef int blen
         cdef char* buf
@@ -314,17 +418,17 @@ cdef class AttrID(ObjectID):
 
     @sync
     def get_space(self):
-        """ () => INT space_id
+        """() => SpaceID
 
-            Create and return a copy of the attribute's dataspace.
+        Create and return a copy of the attribute's dataspace.
         """
         return SpaceID(H5Aget_space(self.id))
 
     @sync
     def get_type(self):
-        """ () => TypeID
+        """() => TypeID
 
-            Create and return a copy of the attribute's datatype.
+        Create and return a copy of the attribute's datatype.
         """
         return typewrap(H5Aget_type(self.id))
 
diff --git a/h5py/h5g.pyx b/h5py/h5g.pyx
index 8d41d98..4535417 100644
--- a/h5py/h5g.pyx
+++ b/h5py/h5g.pyx
@@ -112,8 +112,7 @@ cdef class GroupIter:
 
     def __next__(self):
         if self.idx == self.nobjs:
-            if self.grp is not None:
-                self.grp = None
+            self.grp = None
             raise StopIteration
         
         retval = self.grp.get_objname_by_idx(self.idx)
@@ -122,7 +121,6 @@ cdef class GroupIter:
 
 # === Basic group management ==================================================
 
-# COMPAT: 1.8 update
 IF H5PY_18API:
     @sync
     def open(ObjectID loc not None, char* name, PropID gapl=None):
@@ -140,7 +138,7 @@ ELSE:
         """
         return GroupID(H5Gopen(loc.id, name))
 
-# COMPAT: 1.8 update
+
 IF H5PY_18API:
     @sync
     def create(ObjectID loc not None, char* name, PropID lcpl=None,
@@ -162,59 +160,51 @@ ELSE:
         """
         return GroupID(H5Gcreate(loc.id, name, -1))
 
-cdef herr_t iter_cb_helper(hid_t gid, char *name, object int_tpl) except -1:
-    # Callback function for H5Giterate
-    # Automatic exception propagation breaks in 1.8 for some reason, so
-    # stuff the exception into a mutable object.
+cdef class _GroupVisitor:
 
-    cdef list err_list
-    loc, func, data, err_list = int_tpl
+    cdef object func
+    cdef object retval
 
-    try:
-        func(loc, name, data)
-    except StopIteration:
-        return 1
-    except Exception, e:
-        err_list.append(e)
-        return 1
+    def __init__(self, func):
+        self.func = func
+        self.retval = None
+
+cdef herr_t cb_group_iter(hid_t gid, char *name, void* vis_in) except 2:
 
+    cdef _GroupVisitor vis = <_GroupVisitor>vis_in
+
+    vis.retval = vis.func(name)
+
+    if vis.retval is not None:
+        return 1
     return 0
 
 @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, 
-            UINT startidx=0) => INT last_index_processed
-
-        Iterate an arbitrary Python function over a group.  Note that the
-        group is specified by a parent and a name; if you have a group
-        identifier and want to iterate over it; pass in "." for the name.
-        You can also start at an arbitrary member by specifying its 
-        (zero-based) index.
-
-        Your function:
-        1.  Should accept three arguments: the GroupID of the group, the 
-            (STRING) name of the member, and an arbitary Python object you 
-            provide as data.  Any return value is ignored.
-        2.  Raise StopIteration to bail out before all members are processed.
-        3.  Raising anything else immediately aborts iteration, and the
-            exception is propagated.
-    """
-    cdef int i
-    cdef list err_list
-    err_list = []
+def iterate(GroupID loc not None, object func, int startidx=0, *,
+            char* obj_name='.'):
+    """ (GroupID loc, CALLABLE func, UINT startidx=0, **kwds)
+        => Return value from func
 
-    if startidx < 0:
-        raise ValueError("Starting index must be non-negative.")
-    i = startidx
+        Iterate a callable (function, method or callable object) over the
+        members of a group.  Your callable should have the signature:
+
+            func(STRING name) => Result
 
-    int_tpl = (loc, func, data, err_list)
+        Returning None continues iteration; returning anything else aborts
+        iteration and returns that value.
+
+        Keywords:
+        * STRING obj_name (".")     Iterate over this subgroup instead
+    """
+    if startidx < 0:
+        raise ValueError("Starting index must be non-negative")
 
-    H5Giterate(loc.id, name, &i, <H5G_iterate_t>iter_cb_helper, int_tpl)
+    cdef int i = startidx
+    cdef _GroupVisitor vis = _GroupVisitor(func)
 
-    if len(err_list) > 0:
-        raise err_list[0]
+    H5Giterate(loc.id, obj_name, &i, <H5G_iterate_t>cb_group_iter, <void*>vis)
 
+    return vis.retval
 
 @sync
 def get_objinfo(ObjectID obj not None, object name='.', int follow_link=1):
@@ -451,11 +441,14 @@ cdef class GroupID(ObjectID):
 
             Determine if a group member of the given name is present
         """
-        try:
-            H5Gget_objinfo(self.id, name, 1, NULL)
-            return True
-        except H5Error:
-            return False    
+        IF H5PY_18API:
+            return <bint>H5Lexists(self.id, name, H5P_DEFAULT)
+        ELSE:
+            try:
+                H5Gget_objinfo(self.id, name, 1, NULL)
+                return True
+            except H5Error:
+                return False    
 
     @nosync
     def __iter__(self):
diff --git a/h5py/highlevel.py b/h5py/highlevel.py
index 907e8e9..d7a1645 100644
--- a/h5py/highlevel.py
+++ b/h5py/highlevel.py
@@ -73,6 +73,7 @@ try:
 except ImportError:
     readline = None
 
+
 class LockableObject(object):
 
     """
@@ -81,6 +82,7 @@ class LockableObject(object):
 
     _lock = h5.get_phil()
 
+
 class HLObject(LockableObject):
 
     """
@@ -98,12 +100,10 @@ class HLObject(LockableObject):
     attrs = property(lambda self: self._attrs,
         doc = "Provides access to HDF5 attributes. See AttributeManager.")
 
-    def __repr__(self):
-        return str(self)
-
     def __nonzero__(self):
         return self.id.__nonzero__()
 
+
 class Group(HLObject):
 
     """ Represents an HDF5 group.
@@ -127,9 +127,6 @@ class Group(HLObject):
         the AttributeManager class.
     """
 
-    names = property(lambda self: tuple(self),
-        doc = "Tuple of group member names")
-
     def __init__(self, parent_object, name, create=False):
         """ Create a new Group object, from a parent object and a name.
 
@@ -183,9 +180,7 @@ class Group(HLObject):
                 htype.commit(self.id, name)
 
             else:
-                if not isinstance(obj, numpy.ndarray):
-                    obj = numpy.array(obj)
-                Dataset(self, name, data=obj)
+                self.create_dataset(name, data=obj)
 
     def __getitem__(self, name):
         """ Open an object attached to this group. 
@@ -222,12 +217,6 @@ class Group(HLObject):
         """ Iterate over member names """
         return self.id.__iter__()
 
-    def iteritems(self):
-        """ Iterate over the group members as (name, value) pairs """
-        with self._lock:
-            for name in self:
-                yield (name, self[name])
-
     def create_group(self, name):
         """ Create and return a subgroup.
 
@@ -279,20 +268,60 @@ class Group(HLObject):
                 outstr += '\nComment:\n'+cmnt
             return outstr
 
+    # Dictionary compatibility methods
+
+    def listnames(self):
+        """ Get a list containing member names """
+        with self._lock:
+            return list(self)
+
+    def iternames(self):
+        """ Get an iterator over member names """
+        with self._lock:
+            return iter(self)
+
+    def listobjects(self):
+        """ Get a list containing member objects """
+        with self._lock:
+            return [self[x] for x in self]
+
+    def iterobjects(self):
+        """ Get an iterator over member objects """
+        with self._lock:
+            for x in self:
+                yield self[x]
+
+    def listitems(self):
+        """ Get a list of tuples containing (name, object) pairs """
+        with self._lock:
+            return [(x, self[x]) for x in self]
+
+    def iteritems(self):
+        """ Get an iterator over (name, object) pairs """
+        with self._lock:
+            for x in self:
+                yield (x, self[x])
+
+    # New 1.8.X methods
+
     def visit(self, func):
-        """ Recursively iterate a function or callable object over the file,
-            calling it exactly once for each object with the signature:
+        """ Recursively visit all names in this group and subgroups.
+
+            You supply a callable (function, method or callable object); it
+            will be called exactly once for each link in this group and every
+            group below it. Your callable must conform to the signature:
 
-                func(<name>) => <None or return value>
+                func(<member name>) => <None or return value>
 
             Returning None continues iteration, returning anything else stops
-            and immediately returns that value from Group.visit.
+            and immediately returns that value from the visit method.
 
             Example:
 
             # List the entire contents of the file
+            >>> f = File("foo.hdf5")
             >>> list_of_names = []
-            >>> grp.visit(list_of_names.append)
+            >>> f.visit(list_of_names.append)
 
             Only available with HDF5 1.8.X.
         """
@@ -306,14 +335,28 @@ class Group(HLObject):
             return h5o.visit(self.id, call_proxy)
 
     def visititems(self, func):
-        """ Recursively iterate a function or callable object over the file,
-            calling it exactly once for each object, with the signature::
-    
-                func(<name>, <object instance>) => <None or return value>
+        """ Recursively visit names and objects in this group and subgroups.
+
+            You supply a callable (function, method or callable object); it
+            will be called exactly once for each link in this group and every
+            group below it. Your callable must conform to the signature:
+
+                func(<member name>, <object>) => <None or return value>
 
             Returning None continues iteration, returning anything else stops
-            and immediately returns that value from Group.visit.
+            and immediately returns that value from the visit method.
+
+            Example:
 
+            # Get a list of all datasets in the file
+            >>> mylist = []
+            >>> def func(name, obj):
+            ...     if isinstance(obj, Dataset):
+            ...         mylist.append(name)
+            ...
+            >>> f = File('foo.hdf5')
+            >>> f.visititems(func)
+   
             Only available with HDF5 1.8.X.
         """
         if not config.API_18:
@@ -325,8 +368,7 @@ class Group(HLObject):
 
             return h5o.visit(self.id, call_proxy)
 
-
-    def __str__(self):
+    def __repr__(self):
         with self._lock:
             try:
                 return 'Group "%s" (%d members)' % (hbasename(self.name), len(self))
@@ -425,10 +467,10 @@ class File(Group):
             if self.id._valid:
                 self.close()
             
-    def __str__(self):
+    def __repr__(self):
         with self._lock:
             try:
-                return 'File "%s", root members: %s' % (self.name, ', '.join(['"%s"' % name for name in self]))
+                return 'File "%s", %d root members' % (self.name, len(self))
             except:
                 return "Invalid file"
 
@@ -545,19 +587,28 @@ class Dataset(HLObject):
                     raise ValueError('You cannot specify keywords when opening a dataset.')
                 self.id = h5d.open(group.id, name)
             else:
-                if ((data is None) and (shape is None)) or \
-                   ((data is not None) and (shape is not None)):
-                    raise ValueError("*Either* data *or* the shape must be specified.")
-                
+                # Convert data to a C-contiguous ndarray
                 if data is not None:
+                    data = numpy.asarray(data, order="C")
+
+                # Validate shape
+                if shape is None and data is None:
+                    raise ValueError("Either data or shape must be specified")
+                elif shape is None and data is not None:
                     shape = data.shape
+                elif shape is not None and data is not None:
+                    if numpy.product(shape) != numpy.product(data.shape):
+                        raise ValueError("Shape tuple is incompatible with data")
+
+                # Validate dtype
+                if dtype is None and data is None:
+                    dtype = numpy.dtype("=f4")
+                elif dtype is None and data is not None:
                     dtype = data.dtype
                 else:
-                    if dtype is None:
-                        dtype = "=f4"
-                
-                dtype = numpy.dtype(dtype)
+                    dtype = numpy.dtype(dtype)
 
+                # Generate chunks if necessary
                 if chunks is True or \
                    (any((compression, shuffle, fletcher32, maxshape)) and chunks is None):
                     chunks = guess_chunk(shape, dtype.itemsize)
@@ -571,7 +622,7 @@ class Dataset(HLObject):
                 if shuffle:
                     plist.set_shuffle()
                 if compression is not None:
-                    if compression is True:  # prevent accidental abuse
+                    if compression is True:
                         compression = 6
                     plist.set_deflate(compression)
                 if fletcher32:
@@ -602,12 +653,16 @@ class Dataset(HLObject):
     def __len__(self):
         """ The size of the first axis.  TypeError if scalar.
         """
+        size = self.len()
+        if size > sys.maxint:
+            raise OverflowError("Value too big for Python's __len__; use Dataset.len() instead.")
+        return size
+
+    def len(self):
+        """ The size of the first axis.  TypeError if scalar. """
         shape = self.shape
         if len(shape) == 0:
             raise TypeError("Attempt to take len() of scalar dataset")
-        size = shape[0]
-        if size > sys.maxint:
-            raise OverflowError("Dataset length is larger than Python's len() function can handle")
         return shape[0]
 
     def __iter__(self):
@@ -663,7 +718,7 @@ class Dataset(HLObject):
                 new_dtype = numpy.dtype([(name, basetype.fields[name][0]) for name in names])
 
             # Create the holder array
-            arr = numpy.ndarray(mspace.shape, new_dtype)
+            arr = numpy.ndarray(mspace.shape, new_dtype, order='C')
 
             # Perform the actual read
             self.id.read(mspace, fspace, arr)
@@ -692,7 +747,7 @@ class Dataset(HLObject):
             if len(names) != 0:
                 raise NotImplementedError("Field name selections are not yet allowed for write.")
 
-            val = numpy.array(val)  # So that you can assign scalars, sequences
+            val = numpy.asarray(val, order='C')
 
             fspace = self.id.get_space()
 
@@ -705,11 +760,11 @@ class Dataset(HLObject):
 
             self.id.write(mspace, fspace, val)
 
-    def __str__(self):
+    def __repr__(self):
         with self._lock:
             try:
-                return 'Dataset "%s": %s %s' % (hbasename(self.name),
-                        str(self.shape), repr(self.dtype))
+                return 'Dataset "%s": %s %s' % \
+                    (hbasename(self.name), self.shape, self.dtype.str)
             except:
                 return "Invalid dataset"
 
@@ -752,9 +807,9 @@ class AttributeManager(LockableObject):
             as a Numpy ndarray.
         """
         with self._lock:
-            attr = h5a.open_name(self.id, name)
+            attr = h5a.open(self.id, name)
 
-            arr = numpy.ndarray(attr.shape, dtype=attr.dtype)
+            arr = numpy.ndarray(attr.shape, dtype=attr.dtype, order='C')
             attr.read(arr)
 
             if len(arr.shape) == 0:
@@ -770,8 +825,7 @@ class AttributeManager(LockableObject):
             If the creation fails, the data is not recoverable.
         """
         with self._lock:
-            if not isinstance(value, numpy.ndarray):
-                value = numpy.array(value)
+            value = numpy.asarray(value, order='C')
 
             space = h5s.create_simple(value.shape)
             htype = h5t.py_create(value.dtype)
@@ -789,9 +843,9 @@ class AttributeManager(LockableObject):
 
     def __len__(self):
         """ Number of attributes attached to the object. """
+        # I expect we will not have more than 2**32 attributes
         return h5a.get_num_attrs(self.id)
 
-
     def __iter__(self):
         """ Iterate over the names of attributes. """
         with self._lock:
@@ -806,22 +860,16 @@ class AttributeManager(LockableObject):
 
     def __contains__(self, name):
         """ Determine if an attribute exists, by name. """
-        return h5a.py_exists(self.id, name)
+        return h5a.exists(self.id, name)
 
-    def __str__(self):
+    def __repr__(self):
         with self._lock:
             try:
-                rstr = 'Attributes of "%s": ' % hbasename(h5i.get_name(self.id))
-                if len(self) == 0:
-                    rstr += '(none)'
-                else:
-                    rstr += ', '.join(['"%s"' % x for x in self])
-                return rstr
+                return 'Attributes of "%s" (%d)' % \
+                    (hbasename(h5i.get_name(self.id)), len(self))
             except:
                 return "Invalid attributes object"
 
-    def __repr__(self):
-        return str(self)
 
 class Datatype(HLObject):
 
@@ -850,10 +898,10 @@ class Datatype(HLObject):
             self.id = h5t.open(grp.id, name)
             self._attrs = AttributeManager(self)
 
-    def __str__(self):
+    def __repr__(self):
         with self._lock:
             try:
-                return "Named datatype object (%s)" % str(self.dtype)
+                return "Named datatype object (%s)" % self.dtype.str
             except:
                 return "Invalid datatype object"
 
diff --git a/h5py/tests/test_h5a.py b/h5py/tests/test_h5a.py
index fe0ead4..9ea330c 100644
--- a/h5py/tests/test_h5a.py
+++ b/h5py/tests/test_h5a.py
@@ -60,7 +60,7 @@ class TestH5A(TestBase):
             attr.write(arr_ref)
             self.assertRaises(TypeError, attr.write, arr_fail)
 
-            attr = h5a.open_name(obj, name)
+            attr = h5a.open(obj, name)
             dt = attr.dtype
             shape = attr.shape
             arr_val = ndarray(shape, dtype=dt)
@@ -69,16 +69,16 @@ class TestH5A(TestBase):
 
     def test_open_idx(self):
         for idx, name in enumerate(ATTRIBUTES_ORDER):
-            attr = h5a.open_idx(self.obj, idx)
+            attr = h5a.open(self.obj, idx=idx)
             self.assert_(self.is_attr(attr), "Open: index %d" % idx)
 
-    def test_open_name(self):
+    def test_open(self):
         for name in ATTRIBUTES:
-            attr = h5a.open_name(self.obj, name)
+            attr = h5a.open(self.obj, name)
             self.assert_(self.is_attr(attr), 'Open: name "%s"' % name)
 
     def test_close(self):
-        attr = h5a.open_idx(self.obj, 0)
+        attr = h5a.open(self.obj, idx=0)
         self.assert_(self.is_attr(attr))
         attr._close()
         self.assert_(not self.is_attr(attr))
@@ -87,12 +87,12 @@ class TestH5A(TestBase):
 
         obj = h5g.open(self.fid, OBJECTNAME)
 
-        attr = h5a.open_name(obj, ATTRIBUTES_ORDER[0])
+        attr = h5a.open(obj, ATTRIBUTES_ORDER[0])
         self.assert_(self.is_attr(attr))
         del attr
 
         h5a.delete(obj, ATTRIBUTES_ORDER[0])
-        self.assertRaises(H5Error, h5a.open_name, obj, ATTRIBUTES_ORDER[0])
+        self.assertRaises(H5Error, h5a.open, obj, ATTRIBUTES_ORDER[0])
 
 
     # === Attribute I/O =======================================================
@@ -101,7 +101,7 @@ class TestH5A(TestBase):
         for name in ATTRIBUTES:
             value, dt, shape = ATTRIBUTES[name]
 
-            attr = h5a.open_name(self.obj, name)
+            attr = h5a.open(self.obj, name)
             arr_holder = ndarray(shape, dtype=dt)
             arr_reference = array(value, dtype=dt)
 
@@ -122,13 +122,13 @@ class TestH5A(TestBase):
     def test_get_name(self):
     
         for name in ATTRIBUTES:
-            attr = h5a.open_name(self.obj, name)
+            attr = h5a.open(self.obj, name)
             self.assertEqual(attr.get_name(), name)
 
     def test_get_space(self):
 
         for name, (value, dt, shape) in ATTRIBUTES.iteritems():
-            attr = h5a.open_name(self.obj, name)
+            attr = h5a.open(self.obj, name)
             space = attr.get_space()
             shape_tpl = space.get_simple_extent_dims()
             self.assertEqual(shape_tpl, shape)
@@ -136,7 +136,7 @@ class TestH5A(TestBase):
     def test_get_type(self):
 
         for name, (value, dt, shape) in ATTRIBUTES.iteritems():
-            attr = h5a.open_name(self.obj, name)
+            attr = h5a.open(self.obj, name)
             htype = attr.get_type()
 
     def test_iterate(self):
@@ -173,19 +173,19 @@ class TestH5A(TestBase):
     def test_prop_name(self):
         
         for name in ATTRIBUTES:
-            attr = h5a.open_name(self.obj, name)
+            attr = h5a.open(self.obj, name)
             self.assertEqual(attr.name, name)
 
     def test_prop_shape(self):
 
         for name, (val, dt, shape) in ATTRIBUTES.iteritems():
-            attr = h5a.open_name(self.obj, name)
+            attr = h5a.open(self.obj, name)
             self.assertEqual(attr.shape, shape)
 
     def test_prop_dtype(self):
 
         for name, (val, dt, shape) in ATTRIBUTES.iteritems():
-            attr = h5a.open_name(self.obj, name)
+            attr = h5a.open(self.obj, name)
             self.assertEqual(attr.dtype, dt)
 
     def test_py_listattrs(self):
diff --git a/h5py/utils.pxd b/h5py/utils.pxd
index 4e0dbc0..3e3434a 100644
--- a/h5py/utils.pxd
+++ b/h5py/utils.pxd
@@ -17,8 +17,8 @@ from numpy cimport ndarray
 cdef void* emalloc(size_t size) except? NULL
 cdef void efree(void* ptr)
 
-cdef int check_numpy_read(ndarray arr, hid_t space_id=*) except -1
-cdef int check_numpy_write(ndarray arr, hid_t space_id=*) except -1
+cpdef int check_numpy_read(ndarray arr, hid_t space_id=*) except -1
+cpdef int check_numpy_write(ndarray arr, hid_t space_id=*) except -1
 
 cdef int convert_tuple(object tuple, hsize_t *dims, hsize_t rank) except -1
 cdef object convert_dims(hsize_t* dims, hsize_t rank)
diff --git a/h5py/utils.pyx b/h5py/utils.pyx
index 1643e76..515dd08 100644
--- a/h5py/utils.pyx
+++ b/h5py/utils.pyx
@@ -22,7 +22,7 @@ from numpy cimport ndarray, import_array, \
                     PyArray_SimpleNew, PyArray_ContiguousFromAny, \
                     PyArray_FROM_OTF, PyArray_DIM, \
                     NPY_CONTIGUOUS, NPY_NOTSWAPPED, NPY_FORCECAST, \
-                    NPY_C_CONTIGUOUS, NPY_OWNDATA, NPY_WRITEABLE
+                    NPY_C_CONTIGUOUS, NPY_WRITEABLE
 
 
 # Initialization
@@ -76,12 +76,12 @@ cdef int check_numpy(ndarray arr, hid_t space_id, int write):
     # Validate array flags
 
     if write:
-        if not (arr.flags & (NPY_C_CONTIGUOUS | NPY_OWNDATA | NPY_WRITEABLE)):
-            PyErr_SetString(TypeError, "Array must be writable, C-contiguous and own its data.")
+        if not (arr.flags & NPY_C_CONTIGUOUS and arr.flags & NPY_WRITEABLE):
+            PyErr_SetString(TypeError, "Array must be C-contiguous and writable")
             return -1
     else:
-        if not (arr.flags & (NPY_C_CONTIGUOUS | NPY_OWNDATA)):
-            PyErr_SetString(TypeError, "Array must be C-contiguous and own its data.")
+        if not (arr.flags & NPY_C_CONTIGUOUS):
+            PyErr_SetString(TypeError, "Array must be C-contiguous")
             return -1
 
     # Validate dataspace compatibility, if it's provided
@@ -114,10 +114,10 @@ cdef int check_numpy(ndarray arr, hid_t space_id, int write):
             free(space_dims)
     return 1
 
-cdef int check_numpy_write(ndarray arr, hid_t space_id=-1) except -1:
+cpdef int check_numpy_write(ndarray arr, hid_t space_id=-1) except -1:
     return check_numpy(arr, space_id, 1)
 
-cdef int check_numpy_read(ndarray arr, hid_t space_id=-1) except -1:
+cpdef int check_numpy_read(ndarray arr, hid_t space_id=-1) except -1:
     return check_numpy(arr, space_id, 0)
 
 # === Conversion between HDF5 buffers and tuples ==============================
diff --git a/setup.py b/setup.py
index b78fd36..76ec000 100644
--- a/setup.py
+++ b/setup.py
@@ -153,9 +153,8 @@ class cybuild(build):
 
 
     def get_hdf5_version(self):
-        """ Try to determine the installed HDF5 version and return a tuple
-            containing the appropriate API levels, or None if it can't be
-            determined.
+        """ 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"
@@ -207,7 +206,7 @@ class cybuild(build):
                 warn("Can't determine HDF5 version, assuming 1.6 (use --api= to override)")
                 self.api = 16
         else:
-            # User specified the API levels
+            # User specified the API level
             self._default = False
             try:
                 self.api = int(self.api)

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