[h5py] 55/455: Cleanup and started work on python extensions for h5t

Ghislain Vaillant ghisvail-guest at moszumanska.debian.org
Thu Jul 2 18:19:17 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 00dae18e8d43ca2914d124bc03f78898aeaec6da
Author: andrewcollette <andrew.collette at gmail.com>
Date:   Tue Jun 17 23:53:00 2008 +0000

    Cleanup and started work on python extensions for h5t
---
 h5py/h5a.pxd |   2 +-
 h5py/h5a.pyx | 143 +++++++++++++---------------
 h5py/h5d.pxd |   2 +-
 h5py/h5d.pyx | 104 ++++++++++-----------
 h5py/h5f.pyx |  96 ++++++++++---------
 h5py/h5g.pyx |  76 +++++++--------
 h5py/h5i.pyx |   9 +-
 h5py/h5p.pxd |   9 +-
 h5py/h5p.pyx | 113 +++++++++++++++++-----
 h5py/h5r.pyx |  28 +++---
 h5py/h5s.pyx |  48 ++++++----
 h5py/h5t.pxd |   6 +-
 h5py/h5t.pyx | 300 +++++++++++++++++++++++++++++++++++++++++++++++++----------
 13 files changed, 602 insertions(+), 334 deletions(-)

diff --git a/h5py/h5a.pxd b/h5py/h5a.pxd
index 3905792..687fb10 100644
--- a/h5py/h5a.pxd
+++ b/h5py/h5a.pxd
@@ -38,7 +38,7 @@ 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)
+  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 *
 
 
diff --git a/h5py/h5a.pyx b/h5py/h5a.pyx
index 32f623c..45b585a 100644
--- a/h5py/h5a.pyx
+++ b/h5py/h5a.pyx
@@ -16,7 +16,7 @@
 
 # Pyrex compile-time imports
 from h5p cimport H5P_DEFAULT
-from h5t cimport TypeID, PY_H5Tclose
+from h5t cimport TypeID
 from h5s cimport SpaceID, H5Sclose
 
 from numpy cimport import_array, ndarray, PyArray_DATA
@@ -32,17 +32,17 @@ import_array()
 
 # === General attribute operations ============================================
 
-def create(ObjectID loc_id not None, char* name, TypeID type_id not None, 
-            SpaceID space_id not None):
-    """ (ObjectID loc_id, STRING name, TypeID type_id, SpaceID space_id) 
+def create(ObjectID loc not None, char* name, TypeID tid not None, 
+            SpaceID space not None):
+    """ (ObjectID loc, STRING name, TypeID tid, SpaceID space) 
         => INT attr_id
 
         Create a new attribute attached to a parent object, specifiying an 
         HDF5 datatype and dataspace.
     """
-    return AttrID(H5Acreate(loc_id.id, name, type_id.id, space_id.id, H5P_DEFAULT))
+    return AttrID(H5Acreate(loc.id, name, tid.id, space.id, H5P_DEFAULT))
 
-def open_idx(ObjectID loc_id not None, int idx):
+def open_idx(ObjectID loc not None, int idx):
     """ (ObjectID loc_id, UINT idx) => INT attr_id
 
         Open an exisiting attribute on an object, by zero-based index.
@@ -52,54 +52,43 @@ def open_idx(ObjectID loc_id not None, int idx):
     # HDF5 library.
     if idx < 0:
         raise ValueError("Index must be a non-negative integer.")
-    return AttrID(H5Aopen_idx(loc_id.id, idx))
+    return AttrID(H5Aopen_idx(loc.id, idx))
 
-def open_name(ObjectID loc_id not None, char* name):
-    """ (ObjectID loc_id, STRING name) => INT attr_id
+def open_name(ObjectID loc not None, char* name):
+    """ (ObjectID loc, STRING name) => INT attr_id
 
         Open an existing attribute on an object, by name.
     """
-    return AttrID(H5Aopen_name(loc_id.id, name))
+    return AttrID(H5Aopen_name(loc.id, name))
 
-def close(AttrID attr_id not None):
-    """ (AttrID attr_id)
-
-        Close this attribute and release resources.
-    """
-    H5Aclose(attr_id.id)
-
-def delete(ObjectID loc_id not None, char* name):
-    """ (ObjectID loc_id, STRING name)
+def delete(ObjectID loc not None, char* name):
+    """ (ObjectID loc, STRING name)
 
         Remove an attribute from an object.
     """
-    H5Adelete(loc_id.id, name)
+    H5Adelete(loc.id, name)
 
-def get_num_attrs(ObjectID loc_id not None):
-    """ (ObjectID loc_id) => INT number_of_attributes
+def get_num_attrs(ObjectID loc not None):
+    """ (ObjectID loc) => INT number_of_attributes
 
         Determine the number of attributes attached to an HDF5 object.
     """
-    return H5Aget_num_attrs(loc_id.id)
+    return H5Aget_num_attrs(loc.id)
 
-cdef herr_t iter_cb(hid_t loc_id, char *attr_name, object int_tpl):
-
-    func = int_tpl[0]
-    data = int_tpl[1]
-    exc_list = int_tpl[2]
+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
 
     try:
-        func(loc_id, attr_name, data)
+        func(loc, attr_name, data)
     except StopIteration:
         return 1
-    except Exception, e:
-        exc_list.append(e)
-        return -1
 
     return 0
 
-def iterate(ObjectID loc_id not None, object func, object data=None, int startidx=0):
-    """ (ObjectID loc_id, FUNCTION func, OBJECT data=None, UINT startidx=0)
+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
@@ -107,26 +96,21 @@ def iterate(ObjectID loc_id not None, object func, object data=None, int startid
         specifying its (zero-based) index.
 
         Your function:
-        1.  Should accept three arguments: the (INT) id of the parent object, 
-            the (STRING) name of the attribute, and an arbitary Python object
+        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.
     """
     cdef unsigned int i
-    cdef herr_t retval
     if startidx < 0:
         raise ValueError("Starting index must be a non-negative integer.")
     i = startidx
 
-    int_tpl = (func, data,[])
-
-    retval = H5Aiterate(loc_id.id, &i, <H5A_operator_t>iter_cb, int_tpl)
+    int_tpl = (loc, func, data)
 
-    if retval < 0:
-        if len(int_tpl[2]) != 0:
-            raise int_tpl[2][0]
+    H5Aiterate(loc.id, &i, <H5A_operator_t>iter_cb, int_tpl)
 
 # === Attribute class & methods ===============================================
 
@@ -155,14 +139,14 @@ cdef class AttrID(ObjectID):
             """ Retrieve the dataspace of this attribute, as a Numpy-style 
                 shape tuple.
             """
-            cdef hid_t sid
-            sid = 0
+            cdef SpaceID space
+            space = None
             try:
-                sid = H5Aget_space(self.id)
-                return h5s.get_simple_extent_dims(sid)
+                space = self.get_space()
+                return space.get_simple_extent_dims()
             finally:
-                if sid:
-                    H5Sclose(sid)
+                if space is not None:
+                    space.close()
 
     property dtype:
         def __get__(self):
@@ -171,15 +155,23 @@ cdef class AttrID(ObjectID):
                 the underlying HDF5 datatype, but is appropriate for use in e.g. the 
                 read() and write() functions defined in this module.
             """
-            cdef hid_t type_id
-            type_id = 0
-            
+            cdef TypeID tid
+            tid = None
             try:
-                type_id = H5Aget_type(self.id)
-                return h5t.py_translate_h5t(type_id)
+                tid = self.get_type()
+                return h5t.py_translate_h5t(tid)
             finally:
-                if type_id:
-                    PY_H5Tclose(type_id)
+                if tid is not None:
+                    tid.close()
+
+    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.
+        """
+        H5Aclose(self.id)
 
     def read(self, ndarray arr_obj not None):
         """ (NDARRAY arr_obj)
@@ -191,25 +183,24 @@ cdef class AttrID(ObjectID):
             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 hid_t attr_id
-        cdef hid_t mtype_id
+        cdef TypeID mtype
         cdef hid_t space_id
-        attr_id = self.id
-        mtype_id = 0
+        mtype = None
         space_id = 0
 
         try:
-            mtype_id = h5t.py_translate_dtype(arr_obj.dtype)
-            space_id = H5Aget_space(attr_id)
+            space_id = H5Aget_space(self.id)
             check_numpy_write(arr_obj, space_id)
 
-            H5Aread(attr_id, mtype_id, PyArray_DATA(arr_obj))
+            mtype = h5t.py_translate_dtype(arr_obj.dtype)
+
+            H5Aread(self.id, mtype.id, PyArray_DATA(arr_obj))
 
         finally:
-            if mtype_id:
-                PY_H5Tclose(mtype_id)
             if space_id:
                 H5Sclose(space_id)
+            if mtype is not None:
+                mtype.close()
 
     def write(self, ndarray arr_obj not None):
         """ (NDARRAY arr_obj)
@@ -221,42 +212,38 @@ cdef class AttrID(ObjectID):
             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 hid_t attr_id
-        cdef hid_t mtype_id
+        cdef TypeID mtype
         cdef hid_t space_id
-        attr_id = self.id
-        mtype_id = 0
+        mtype_id = None
         space_id = 0
 
         try:
-            mtype_id = h5t.py_translate_dtype(arr_obj.dtype)
-            space_id = H5Aget_space(attr_id)
+            space_id = H5Aget_space(self.id)
             check_numpy_read(arr_obj, space_id)
+            mtype = h5t.py_translate_dtype(arr_obj.dtype)
 
-            H5Awrite(attr_id, mtype_id, PyArray_DATA(arr_obj))
+            H5Awrite(self.id, mtype_id, PyArray_DATA(arr_obj))
 
         finally:
-            if mtype_id:
-                PY_H5Tclose(mtype_id)
             if space_id:
                 H5Sclose(space_id)
+            if mtype is not None:
+                mtype.close()
 
     def get_name(self):
         """ () => STRING name
 
             Determine the name of an attribute, given its identifier.
         """
-        cdef hid_t attr_id
         cdef int blen
         cdef char* buf
-        attr_id = self.id
         buf = NULL
 
         try:
-            blen = H5Aget_name(attr_id, 0, NULL)
+            blen = H5Aget_name(self.id, 0, NULL)
             assert blen >= 0
             buf = <char*>emalloc(sizeof(char)*blen+1)
-            blen = H5Aget_name(attr_id, blen+1, buf)
+            blen = H5Aget_name(self.id, blen+1, buf)
             strout = buf
         finally:
             efree(buf)
diff --git a/h5py/h5d.pxd b/h5py/h5d.pxd
index 1647ca9..ab28358 100644
--- a/h5py/h5d.pxd
+++ b/h5py/h5d.pxd
@@ -22,7 +22,7 @@ cdef class DatasetID(ObjectID):
 
 from h5t cimport class TypeID
 from h5s cimport class SpaceID
-from h5p cimport class PropID, pdefault
+from h5p cimport class PropID, PropDCID, PropDXID, pdefault
 from numpy cimport class ndarray
 
 
diff --git a/h5py/h5d.pyx b/h5py/h5d.pyx
index fa80b19..c5d4edf 100644
--- a/h5py/h5d.pyx
+++ b/h5py/h5d.pyx
@@ -26,8 +26,6 @@
 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
-from h5t cimport PY_H5Tclose, H5Tget_size
-from h5p cimport H5P_DEFAULT, H5Pclose
 from numpy cimport import_array, PyArray_DATA
 from utils cimport  check_numpy_read, check_numpy_write, \
                     convert_tuple, \
@@ -66,10 +64,10 @@ FILL_VALUE_USER_DEFINED = H5D_FILL_VALUE_USER_DEFINED
 
 # === Basic dataset operations ================================================
 
-def create(ObjectID loc_id not None, char* name, TypeID type_id not None, 
-            SpaceID space_id not None, PropID plist=None):
-    """ (ObjectID loc_id, STRING name, TypeID type_id, SpaceID space_id,
-         PropID plist=None ) 
+def create(ObjectID loc not None, char* name, TypeID tid not None, 
+            SpaceID space not None, PropDCID plist=None):
+    """ (ObjectID loc, STRING name, TypeID tid, SpaceID space,
+         PropDCID plist=None ) 
         => DatasetID
 
         Create a new dataset under an HDF5 file or group id.  Keyword plist 
@@ -79,19 +77,16 @@ def create(ObjectID loc_id not None, char* name, TypeID type_id not None,
     """
     cdef hid_t plist_id
     plist_id = pdefault(plist)
-    return DatasetID(H5Dcreate(loc_id.id, name, type_id.id, space_id.id, plist_id))
+    return DatasetID(H5Dcreate(loc.id, name, tid.id, space.id, plist_id))
 
-def open(ObjectID loc_id not None, char* name):
-    """ (ObjectID loc_id, STRING name) => DatasetID
+def open(ObjectID loc not None, char* name):
+    """ (ObjectID loc, STRING name) => DatasetID
 
         Open an existing dataset attached to a group or file object, by name.
     """
-    return DatasetID(H5Dopen(loc_id, name))
+    return DatasetID(H5Dopen(loc.id, name))
+
 
-def close(DatasetID dset_id not None):
-    """ (DatasetID dset_id)
-    """
-    H5Dclose(dset_id.id)
 
 # === Dataset I/O =============================================================
 
@@ -110,22 +105,20 @@ cdef class DatasetID(ObjectID):
         shape:  Numpy-style shape tuple representing the dataspace
         rank:   Integer giving dataset rank
     """
-    property dtype:
-        def __get__(self):
-            pass
 
-    property shape:
-        def __get__(self):
-            pass
+    def close(self):
+        """ ()
 
-    property rank:
-        def __get__(self):
-            pass
+            Terminate access through this identifier.  You shouldn't have to
+            call this manually; Dataset objects are automatically destroyed
+            when their Python wrappers are freed.
+        """
+        H5Dclose(self.id)
 
-    def read(self, SpaceID mspace_id not None, SpaceID fspace_id not None, 
-                   ndarray arr_obj not None, PropID plist=None):
-        """ (SpaceID mspace_id, SpaceID fspace_id, NDARRAY arr_obj, 
-             PropID plist=None)
+    def read(self, SpaceID mspace not None, SpaceID fspace not None, 
+                   ndarray arr_obj not None, PropDXID plist=None):
+        """ (SpaceID mspace, SpaceID fspace, NDARRAY arr_obj, 
+             PropDXID plist=None)
 
             Read data from an HDF5 dataset into a Numpy array.  For maximum 
             flexibility, you can specify dataspaces for the file and the Numpy
@@ -143,48 +136,48 @@ cdef class DatasetID(ObjectID):
             
             For a friendlier version of this function, try py_read_slab().
         """
-        cdef TypeID mtype_id
+        cdef TypeID mtype
         cdef hid_t plist_id
+        mtype = None
         plist_id = pdefault(plist)
-        mtype_id = 0
 
         try:
-            mtype_id = h5t.py_translate_dtype(arr_obj.dtype)
+            mtype = h5t.py_translate_dtype(arr_obj.dtype)
             check_numpy_write(arr_obj, -1)
 
-            H5Dread(self.id, mtype_id.id, mspace_id.id, fspace_id.id, plist_id, PyArray_DATA(arr_obj))
+            H5Dread(self.id, mtype.id, mspace.id, fspace.id, plist_id, PyArray_DATA(arr_obj))
 
         finally:
-            if mtype_id:
-                PY_H5Tclose(mtype_id)
+            if mtype is not None:
+                mtype.close()
         
-    def write(self, SpaceID mspace_id not None, SpaceID fspace_id not None, 
-                    ndarray arr_obj not None, PropID plist=None):
-        """ (SpaceID mspace_id, SpaceID fspace_id, NDARRAY arr_obj, 
-             PropID plist=None)
+    def write(self, SpaceID mspace not None, SpaceID fspace not None, 
+                    ndarray arr_obj not None, PropDXID plist=None):
+        """ (SpaceID mspace, SpaceID fspace, NDARRAY arr_obj, PropDXID plist=None)
 
-            Write data from a Numpy array to an HDF5 dataset. Keyword plist may be 
-            a dataset transfer property list.
+            Write data from a Numpy array to an HDF5 dataset. Keyword plist may 
+            be a dataset transfer property list.
 
-            The provided Numpy array must be C-contiguous, and own its data.  If 
-            this is not the case, ValueError will be raised and the read will fail.
+            The provided Numpy array must be C-contiguous, and own its data.  
+            If this is not the case, ValueError will be raised and the read 
+            will fail.
 
             For a friendlier version of this function, try py_write_slab()
         """
-        cdef TypeID mtype_id
+        cdef TypeID mtype
         cdef hid_t plist_id
+        mtype = None
         plist_id = pdefault(plist)
-        mtype_id = 0
 
         try:
-            mtype_id = h5t.py_translate_dtype(arr_obj.dtype)
+            mtype = h5t.py_translate_dtype(arr_obj.dtype)
             check_numpy_read(arr_obj, -1)
 
-            H5Dwrite(self.id, mtype_id.id, mspace_id.id, fspace_id.id, plist_id, PyArray_DATA(arr_obj))
+            H5Dwrite(self.id, mtype.id, mspace.id, fspace.id, plist_id, PyArray_DATA(arr_obj))
 
         finally:
-            if mtype_id:
-                PY_H5Tclose(mtype_id)
+            if mtype_id is not None:
+                mtype.close()
 
     def extend(self, object shape):
         """ (TUPLE shape)
@@ -193,22 +186,21 @@ cdef class DatasetID(ObjectID):
             that a dataset may only be extended up to the maximum dimensions of 
             its dataspace, which are fixed when the dataset is created.
         """
-        cdef hid_t dset_id
-        cdef hsize_t* dims
         cdef int rank
         cdef hid_t space_id
-        dset_id = self.id
+        cdef hsize_t* dims
         space_id = 0
         dims = NULL
 
         try:
-            space_id = H5Dget_space(dset_id)
+            space_id = H5Dget_space(self.id)
             rank = H5Sget_simple_extent_ndims(space_id)
 
             require_tuple(shape, 0, rank, "shape")
+
             dims = <hsize_t*>emalloc(sizeof(hsize_t)*rank)
             convert_tuple(shape, dims, rank)
-            H5Dextend(dset_id, dims)
+            H5Dextend(self.id, dims)
 
         finally:
             efree(dims)
@@ -216,7 +208,7 @@ cdef class DatasetID(ObjectID):
                 H5Sclose(space_id)
 
     def get_space(self):
-        """ () => SpaceID space_id
+        """ () => SpaceID
 
             Create and return a new copy of the dataspace for this dataset.
         """
@@ -240,7 +232,7 @@ cdef class DatasetID(ObjectID):
 
             Create and return a new copy of the datatype for this dataset.
         """
-        return TypeID(H5Dget_type(dset_id))
+        return TypeID(H5Dget_type(self.id))
 
     def get_create_plist(self):
         """ () => PropDSCreateID
@@ -248,7 +240,7 @@ cdef class DatasetID(ObjectID):
             Create a new copy of the dataset creation property list used when 
             this dataset was created.
         """
-        return PropDSCreateID(H5Dget_create_plist(self.id))
+        return PropDCID(H5Dget_create_plist(self.id))
 
     def get_offset(self):
         """ () => LONG offset
@@ -257,7 +249,7 @@ cdef class DatasetID(ObjectID):
         """
         return H5Dget_offset(self.id)
 
-    def get_storage_size(hid_t dset_id):
+    def get_storage_size(self):
         """ () => LONG storage_size
 
             Determine the amount of file space required for a dataset.  Note this
diff --git a/h5py/h5f.pyx b/h5py/h5f.pyx
index 123b112..5a150c6 100644
--- a/h5py/h5f.pyx
+++ b/h5py/h5f.pyx
@@ -15,7 +15,7 @@
 """
 
 # Pyrex compile-time imports
-from h5p cimport PropID, pdefault, H5P_DEFAULT
+from h5p cimport PropFCID, PropFAID, PropMID, pdefault, H5P_DEFAULT
 from utils cimport emalloc, efree, pybool
 
 # Runtime imports
@@ -47,26 +47,21 @@ OBJ_LOCAL   = H5F_OBJ_LOCAL
 
 # === File operations =========================================================
 
-def open(char* name, unsigned int flags=H5F_ACC_RDWR, ):
-    """ (STRING name, UINT flags=ACC_RDWR, PropID accesslist=None)
+def open(char* name, unsigned int flags=H5F_ACC_RDWR, PropFAID accesslist=None):
+    """ (STRING name, UINT flags=ACC_RDWR, PropFAID accesslist=None)
         => FileID
 
         Open an existing HDF5 file.  Keyword "flags" may be ACC_RWDR or
-        ACC_RDONLY.
+        ACC_RDONLY.  Accesslist may be a file access property list.
     """
     cdef hid_t plist_id
     plist_id = pdefault(accesslist)
-    return FileID(H5Fopen(name, flags, accesslist))
+    return FileID(H5Fopen(name, flags, plist_id))
 
-def close(FileID file_id):
-    """ (FileID file_id)
-    """
-    H5Fclose(file_id.id)
-
-def create(char* name, int flags=H5F_ACC_TRUNC, PropID createlist=None,
-                                                PropID accesslist=None):
-    """ (STRING name, INT flags=ACC_TRUNC, PropID createlist=None,
-                                           PropID accesslist=None)
+def create(char* name, int flags=H5F_ACC_TRUNC, PropFCID createlist=None,
+                                                PropFAID accesslist=None):
+    """ (STRING name, INT flags=ACC_TRUNC, PropFCID createlist=None,
+                                           PropFAID accesslist=None)
         => FileID
 
         Create a new HDF5 file.  Keyword "flags" may be either:
@@ -90,26 +85,37 @@ def is_hdf5(char* name):
     """
     return pybool(H5Fis_hdf5(name))
 
-def mount(ObjectID loc_id not None, char* name, FileID file_id not None, 
-          PropID mountlist=None):
-    """ (ObjectID loc_id, STRING name, FileID file_id, PropID mountlist=None)
+def flush(ObjectID obj, int scope=H5F_SCOPE_LOCAL):
+    """ (ObjectID obj, INT scope=SCOPE_LOCAL)
+
+        Tell the HDF5 library to flush file buffers to disk.  "obj" may
+        be the file identifier, or the identifier of any object residing in
+        the file.  Keyword "scope" may be:
+            SCOPE_LOCAL:    Flush only the given file
+            SCOPE_GLOBAL:   Flush the entire virtual file
+    """
+    H5Fflush(obj.id, <H5F_scope_t>scope)
+
+def mount(ObjectID loc not None, char* name, FileID fid not None, 
+          PropMID mountlist=None):
+    """ (ObjectID loc, STRING name, FileID fid, PropMID mountlist=None)
     
         Mount an open file as "name" under group loc_id.  If present, mountlist
         is a mount property list.
     """
     cdef hid_t plist_id
     plist_id = pdefault(mountlist)
-    H5Fmount(loc_id.id, name, file_id.id, plist_id)
+    H5Fmount(loc.id, name, fid.id, plist_id)
     
-def unmount(ObjectID loc_id not None, char* name):
-    """ (ObjectID loc_id, STRING name)
+def unmount(ObjectID loc not None, char* name):
+    """ (ObjectID loc, STRING name)
 
         Unmount a file, mounted as "name" under group loc_id.
     """
-    H5Funmount(loc_id.id, name)
+    H5Funmount(loc.id, name)
 
-def get_name(ObjectID obj_id not None):
-    """ (INT obj_id) => STRING file_name
+def get_name(ObjectID obj not None):
+    """ (ObjectID obj) => STRING file_name
         
         Determine the name of the file in which the specified object resides.
     """
@@ -117,11 +123,11 @@ def get_name(ObjectID obj_id not None):
     cdef char* name
     name = NULL
 
-    size = H5Fget_name(obj_id.id, NULL, 0)
+    size = H5Fget_name(obj.id, NULL, 0)
     assert size >= 0
     name = <char*>emalloc(sizeof(char)*(size+1))
     try:    
-        H5Fget_name(obj_id.id, name, size+1)
+        H5Fget_name(obj.id, name, size+1)
         pname = name
         return pname
     finally:
@@ -135,22 +141,23 @@ cdef class FileID(ObjectID):
         Represents an HDF5 file identifier.
     """
 
-    def flush(self, int scope=H5F_SCOPE_LOCAL):
-        """ (INT scope=SCOPE_LOCAL)
+    def close(self):
+        """ ()
 
-            Tell the HDF5 library to flush file buffers to disk.  file_id may
-            be the file identifier, or the identifier of any object residing in
-            the file.  Keyword "scope" may be:
-                SCOPE_LOCAL:    Flush only the given file
-                SCOPE_GLOBAL:   Flush the entire virtual file
+            Terminate access through this identifier.  Note that depending on
+            what property list settings were used to open the file, the
+            physical file might not be closed until all remaining open
+            identifiers are freed.  
         """
-        H5Fflush(self.id, <H5F_scope_t>scope)
+        H5Fclose(self.id)
 
 
     def reopen(self):
-        """ () => INT new_file_id
+        """ () => FileID
 
             Retrieve another identifier for a file (which must still be open).
+            The new identifier is guaranteed to neither be mounted nor contain
+            a mounted file.
         """
         return FileID(H5Freopen(self.id))
 
@@ -189,26 +196,29 @@ cdef class FileID(ObjectID):
         return H5Fget_freespace(self.id)
 
 
-    
     def get_obj_count(self, int types=H5F_OBJ_ALL):
         """ (INT types=OBJ_ALL) => INT n_objs
 
             Get the number of open objects in the file.  The value of "types" 
             may be one of h5f.OBJ_*, or any bitwise combination (e.g. 
-            OBJ_FILE | OBJ_ATTR).  The special value OBJ_ALL matches all object
-            types, and OBJ_LOCAL will only match objects opened through this
-            specific identifier.
+            OBJ_FILE | OBJ_ATTR).  
+
+            The special value OBJ_ALL matches all object types, and 
+            OBJ_LOCAL will only match objects opened through this specific 
+            identifier.
         """
         return H5Fget_obj_count(self.id, types)
 
     def get_obj_ids(self, int types=H5F_OBJ_ALL):
         """ (INT types=OBJ_ALL) => LIST open_ids
 
-            Get a list of identifiers for open objects in the file.  The value of 
-            "types" may be one of h5f.OBJ_*, or any bitwise combination (e.g. 
-            OBJ_FILE | OBJ_ATTR).  The special value OBJ_ALL matches all object
-            types, and OBJ_LOCAL will only match objects opened through this
-            specific identifier.
+            Get a list of identifiers for open objects in the file.  The value 
+            of "types" may be one of h5f.OBJ_*, or any bitwise combination (e.g. 
+            OBJ_FILE | OBJ_ATTR). 
+
+            The special value OBJ_ALL matches all object types, and 
+            OBJ_LOCAL will only match objects opened through this specific 
+            identifier. 
         """
         cdef int count
         cdef hid_t *obj_list
diff --git a/h5py/h5g.pyx b/h5py/h5g.pyx
index a51d611..f9d9ca4 100644
--- a/h5py/h5g.pyx
+++ b/h5py/h5g.pyx
@@ -58,45 +58,39 @@ cdef class GroupStat:
 
 # === Basic group management ==================================================
 
-def open(ObjectID loc_id not None, char* name):
-    """ (ObjectID loc_id, STRING name)
+def open(ObjectID loc not None, char* name):
+    """ (ObjectID loc, STRING name) => GroupID
 
         Open an existing HDF5 group, attached to some other group.
     """
-    return GroupID(H5Gopen(loc_id.id, name))
+    return GroupID(H5Gopen(loc.id, name))
 
-def close(GroupID group_id not None):
-    """ (GroupID group_id)
-    """
-    H5Gclose(group_id.id)
-
-def create(ObjectID loc_id not None, char* name, int size_hint=-1):
-    """ (ObjectID loc_id, STRING name, INT size_hint=-1)
+def create(ObjectID loc not None, char* name, int size_hint=-1):
+    """ (ObjectID loc, STRING name, INT size_hint=-1) => GroupID
 
         Create a new group, under a given parent group.  If given, size_hint
         is an estimate of the space to reserve (in bytes) for group member
         names.
     """
-    return GroupID(H5Gcreate(loc_id.id, name, size_hint))
+    return GroupID(H5Gcreate(loc.id, name, size_hint))
 
 cdef herr_t iter_cb_helper(hid_t gid, char *name, object int_tpl) except -1:
     # Callback function for H5Giterate
 
-    func = int_tpl[0]
-    data = int_tpl[1]
+    loc, func, data = int_tpl
 
     # An unhandled exception (anything except StopIteration) will 
     # cause Pyrex to immediately return -1, which stops H5Giterate.
     try:
-        func(gid, name, data)
+        func(loc, name, data)
     except StopIteration:
         return 1
 
     return 0
 
-def iterate(GroupID loc_id not None, char* name, object func, object data=None, 
+def iterate(GroupID loc not None, char* name, object func, object data=None, 
             int startidx=0):
-    """ (GroupID loc_id, STRING name, FUNCTION func, OBJECT data=None, 
+    """ (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
@@ -106,7 +100,7 @@ def iterate(GroupID loc_id not None, char* name, object func, object data=None,
         (zero-based) index.
 
         Your function:
-        1.  Should accept three arguments: the (INT) id of the group, the 
+        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.
@@ -114,14 +108,13 @@ def iterate(GroupID loc_id not None, char* name, object func, object data=None,
             exception is propagated.
     """
     cdef int i
-
     if startidx < 0:
         raise ValueError("Starting index must be non-negative.")
-
     i = startidx
-    int_tpl = (func, data)
 
-    H5Giterate(loc_id.id, name, &i, <H5G_iterate_t>iter_cb_helper, int_tpl)
+    int_tpl = (loc, func, data)
+
+    H5Giterate(loc.id, name, &i, <H5G_iterate_t>iter_cb_helper, int_tpl)
 
 # === Group member management =================================================
 
@@ -131,10 +124,19 @@ cdef class GroupID(ObjectID):
         Represents an HDF5 group identifier
     """
 
+    def close(self):
+        """ ()
+
+            Terminate access through this identifier.  You shouldn't have to
+            call this manually; group identifiers are automatically released
+            when their Python wrappers are freed.
+        """
+        H5Gclose(self.id)
+
     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, GroupID remote=None)
+        """ (STRING current_name, STRING new_name, INT link_type=LINK_HARD, 
+             GroupID remote=None)
 
             Create a new hard or soft link.  current_name identifies
             the link target (object the link will point to).  The new link is
@@ -153,17 +155,16 @@ cdef class GroupID(ObjectID):
         H5Glink2(self.id, current_name, <H5G_link_t>link_type, remote_id, new_name)
 
     def unlink(self, char* name):
-        """ (INT loc_id, STRING name)
+        """ (STRING name)
 
-            Remove a link to an object from this group
+            Remove a link to an object from this group.
         """
         H5Gunlink(self.id, name)
 
     def move(self, char* current_name, char* new_name, GroupID remote=None):
-        """ (INT loc_id, STRING current_name, STRING new_name, 
-                GroupID remote=None)
+        """ (STRING current_name, STRING new_name, GroupID remote=None)
 
-            Relink an object.  loc_id and current_name identify the object.
+            Relink an object.  current_name identifies the object.
             new_name and (optionally) another group "remote" determine
             where it should be moved.
         """
@@ -230,14 +231,15 @@ cdef class GroupID(ObjectID):
         return retval
 
     def get_objinfo(self, char* name, int follow_link=1):
-        """ (STRING name, BOOL follow_link=True)
-            => GroupStat object
-
-            Obtain information about an arbitrary object attached to a group. The
-            return value is a GroupStat object; see that class's docstring
-            for a description of its attributes.  If follow_link is True (default)
-            and the object is a symbolic link, the information returned describes 
-            its target.  Otherwise the information describes the link itself.
+        """ (STRING name, BOOL follow_link=True) => GroupStat object
+
+            Obtain information about an arbitrary object attached to a group. 
+            The return value is a GroupStat object; see that class's docstring
+            for a description of its attributes.  
+
+            If follow_link is True (default) and the object is a symbolic link, 
+            the information returned describes its target.  Otherwise the 
+            information describes the link itself.
         """
         cdef H5G_stat_t stat
         cdef GroupStat statobj
@@ -278,7 +280,6 @@ cdef class GroupID(ObjectID):
         finally:
             efree(value)
 
-
     def set_comment(self, char* name, char* comment):
         """ (STRING name, STRING comment)
 
@@ -286,7 +287,6 @@ cdef class GroupID(ObjectID):
         """
         H5Gset_comment(self.id, name, comment)
 
-
     def get_comment(self, char* name):
         """ (STRING name) => STRING comment
 
diff --git a/h5py/h5i.pyx b/h5py/h5i.pyx
index 67e163b..04bfe4a 100644
--- a/h5py/h5i.pyx
+++ b/h5py/h5i.pyx
@@ -15,6 +15,7 @@
 """
 
 # Pyrex compile-time imports
+from h5f cimport FileID
 from utils cimport emalloc, efree
 
 # Runtime imports
@@ -51,7 +52,7 @@ def get_type(ObjectID obj not None):
     return <int>H5Iget_type(obj.id)
 
 def get_name(ObjectID obj not None):
-    """ (ObjectID obj) => STRING name or None
+    """ (ObjectID obj) => STRING name, or None
 
         Determine (a) name of an HDF5 object.  Because an object has as many
         names as there are hard links to it, this may not be unique.  If
@@ -77,10 +78,10 @@ def get_name(ObjectID obj not None):
 def get_file_id(ObjectID obj not None):
     """ (ObjectID obj) => FileID
 
-        Obtain an identifier for the file in which this object resides,
-        re-opening the file if necessary.
+        Obtain an identifier for the file in which this object resides.
     """
-    return ObjectID(H5Iget_file_id(obj.id))
+    # TODO: does the library function correctly increment the ref count?
+    return FileID(H5Iget_file_id(obj.id))
 
 def inc_ref(ObjectID obj not None):
     """ (ObjectID obj)
diff --git a/h5py/h5p.pxd b/h5py/h5p.pxd
index 445ccf5..6eec6eb 100644
--- a/h5py/h5p.pxd
+++ b/h5py/h5p.pxd
@@ -22,13 +22,8 @@ cdef class PropID(ObjectID):
     pass
 
 cdef class PropClassID(PropID):
-    """ Represents an HDF5 property list class """
-    pass
-
-cdef class PropImmutableClassID(PropClassID):
-    """ Special case of an HDF5 property list class, which isn't
-        automatically closed.  These are used for the built-in
-        classes.
+    """ Represents an HDF5 property list class.  These can be either (locked)
+        library-defined classes or user-created classes.
     """
     pass
 
diff --git a/h5py/h5p.pyx b/h5py/h5p.pyx
index 4469bb1..e4eda3a 100644
--- a/h5py/h5p.pyx
+++ b/h5py/h5p.pyx
@@ -22,8 +22,6 @@ from utils cimport  require_tuple, convert_dims, convert_tuple, \
 
 # Runtime imports
 import h5
-import h5t
-from h5 import DDict
 
 cdef object lockid(hid_t id_in):
     cdef PropClassID pid
@@ -104,6 +102,12 @@ cdef class PropInstanceID(PropID):
         return type(self)(H5Pcopy(self.id))
 
     def close(self):
+        """ ()
+    
+            Terminate access through this identifier.  You shouldn't have to
+            do this manually, as propery lists are automatically deleted when
+            their Python wrappers are freed.
+        """
         H5Pclose(self.id)
 
     def get_class(self):
@@ -125,7 +129,11 @@ cdef class PropInstanceID(PropID):
 cdef class PropFCID(PropInstanceID):
 
     """
-        Represents a file creation property list
+        Represents a file creation property list.
+
+        Each property list entry is associated with a Python object property,
+        in addition to the HDF5 set/get pair.  The set/get docstrings are
+        authoritative.
     """
 
     def get_version(self):
@@ -149,6 +157,10 @@ cdef class PropFCID(PropInstanceID):
 
         return (super_, freelist, stab, shhdr)
 
+    property version:
+        def __get__(self):
+            return self.get_version()
+
     def set_userblock(self, hsize_t size):
         """ (INT/LONG size)
 
@@ -166,6 +178,12 @@ cdef class PropFCID(PropInstanceID):
         H5Pget_userblock(self.id, &size)
         return size
 
+    property userblock:
+        def __get__(self):
+            return self.get_userblock()
+        def __set__(self, val):
+            self.set_userblock(val)
+
     def set_sizes(self, size_t addr, size_t size):
         """ (UINT addr, UINT size)
 
@@ -188,6 +206,14 @@ cdef class PropFCID(PropInstanceID):
         H5Pget_sizes(self.id, &addr, &size)
         return (addr, size)
 
+    property sizes:
+        def __get__(self):
+            return self.get_sizes()
+        def __set__(self, tpl):
+            require_tuple(tpl, 0, 2, "value")
+            a, b = tpl
+            self.set_sizes(a,b)
+
     def set_sym_k(self, unsigned int ik, unsigned int lk):
         """ (INT ik, INT lk)
 
@@ -206,6 +232,14 @@ cdef class PropFCID(PropInstanceID):
         H5Pget_sym_k(self.id, &ik, &lk)
         return (ik, lk)
 
+    property sym_k:
+        def __get__(self):
+            return self.get_sym_k()
+        def __set__(self, tpl):
+            require_tuple(tpl, 0, 2, "value")
+            a, b = tpl
+            self.set_sym_k(a,b)
+
     def set_istore_k(self, unsigned int ik):
         """ (UINT ik)    [File creation]
 
@@ -222,6 +256,12 @@ cdef class PropFCID(PropInstanceID):
         H5Pget_istore_k(self.id, &ik)
         return ik
 
+    property istore_k:
+        def __get__(self):
+            return self.get_istore_k()
+        def __set__(self, a):
+            self.set_istore_k(a)
+
 # === Dataset creation properties =============================================
 
 cdef class PropDCID(PropInstanceID):
@@ -231,7 +271,7 @@ cdef class PropDCID(PropInstanceID):
     """
 
     def set_layout(self, int layout_code):
-        """ (INT layout_code)    [Dataset creation]
+        """ (INT layout_code)
 
             Set dataset storage strategy; legal values are:
             * h5d.COMPACT
@@ -241,7 +281,7 @@ cdef class PropDCID(PropInstanceID):
         H5Pset_layout(self.id, layout_code)
     
     def get_layout(self):
-        """ () => INT layout_code   [Dataset creation]
+        """ () => INT layout_code
 
             Determine the storage strategy of a dataset; legal values are:
             * h5d.COMPACT
@@ -250,13 +290,18 @@ cdef class PropDCID(PropInstanceID):
         """
         return <int>H5Pget_layout(self.id)
 
+    property layout:
+        def __get__(self):
+            return self.get_layout()
+        def __set__(self, val):
+            self.set_layout(val)
+
     def set_chunk(self, object chunksize):
-        """ (INT plist_id, TUPLE chunksize)    [Dataset creation]
+        """ (TUPLE chunksize)
 
             Set the dataset chunk size.  It's up to you to provide 
             values which are compatible with your dataset.
         """
-        cdef herr_t retval
         cdef int rank
         cdef hsize_t* dims
         dims = NULL
@@ -290,10 +335,18 @@ cdef class PropDCID(PropInstanceID):
         finally:
             efree(dims)
 
-# === Filter functions ========================================================
+    property chunk:
+        def __get__(self):
+            return self.get_chunk()
+        def __set__(self, val):
+            self.set_chunk(val)
 
+    # === Filter functions ====================================================
+    # These do not have Python properties because the order of addition is
+    # important, and no get_* functions are provided by HDF5.
+    
     def set_deflate(self, unsigned int level=5):
-        """ (UINT level=5)    [Dataset creation]
+        """ (UINT level=5)
 
             Enable DEFLATE (gzip) compression, at the given level.
             Valid levels are 0-9, default is 5.
@@ -301,30 +354,30 @@ cdef class PropDCID(PropInstanceID):
         H5Pset_deflate(self.id, level)
     
     def set_fletcher32(self):
-        """ ()    [Dataset creation]
+        """ ()
 
-            Enable Fletcher32 error correction on an existing list.
+            Enable Fletcher32 error correction on this list.
         """
         H5Pset_fletcher32(self.id)
 
     def set_shuffle(self):
-        """ ()    [Dataset creation]
+        """ ()
 
-            Enable to use of the shuffle filter.  Use this immediately before the
-            DEFLATE filter to increase the compression ratio.
+            Enable to use of the shuffle filter.  Use this immediately before 
+            the DEFLATE filter to increase the compression ratio.
         """
         H5Pset_shuffle(self.id)
 
     def set_szip(self, unsigned int options, unsigned int pixels_per_block):
-        """ (UINT options, UINT pixels_per_block)   [Dataset creation]
+        """ (UINT options, UINT pixels_per_block)
 
-            Enable SZIP compression.  See the HDF5 docs for argument meanings, and
-            general restrictions on use of the SZIP format.
+            Enable SZIP compression.  See the HDF5 docs for argument meanings, 
+            and general restrictions on use of the SZIP format.
         """
         H5Pset_szip(self.id, options, pixels_per_block)
 
     def remove_filter(self, int filter_class):
-        """ (INT filter_class)    [Dataset creation]
+        """ (INT filter_class)
 
             Remove a filter from the pipeline.  The class code is one of 
             h5z.FILTER_*.
@@ -342,9 +395,8 @@ cdef class PropFAID(PropInstanceID):
     def set_fclose_degree(self, int close_degree):
         """ (INT close_degree)
 
-            Set the file-close degree, which determines the library behavior when
-            a file is closed when objects are still open.  See the HDF5 docs for 
-            a full explanation.  Legal values:
+            Set the file-close degree, which determines library behavior when
+            a file is closed when objects are still open.  Legal values:
 
             * h5f.CLOSE_WEAK
             * h5f.CLOSE_SEMI
@@ -353,7 +405,26 @@ cdef class PropFAID(PropInstanceID):
         """
         H5Pset_fclose_degree(self.id, <H5F_close_degree_t>close_degree)
 
+    def get_fclose_degree(self):
+        """ () => INT close_degree
 
+            Get the file-close degree, which determines library behavior when
+            a file is closed when objects are still open.  Legal values:
+
+            * h5f.CLOSE_WEAK
+            * h5f.CLOSE_SEMI
+            * h5f.CLOSE_STRONG
+            * h5f.CLOSE_DEFAULT
+        """
+        cdef H5F_close_degree_t deg
+        H5Pget_fclose_degree(self.id, &deg)
+        return deg
+
+    property fclose_degree:
+        def __get__(self):
+            return self.get_fclose_degree()
+        def __set__(self,val):
+            self.set_fclose_degree(val)
     
 
 
diff --git a/h5py/h5r.pyx b/h5py/h5r.pyx
index e239b2f..e9a09db 100644
--- a/h5py/h5r.pyx
+++ b/h5py/h5r.pyx
@@ -55,8 +55,8 @@ cdef class Reference:
 
 # === Reference API ===========================================================
 
-def create(ObjectID loc_id not None, char* name, int ref_type, SpaceID space=None):
-    """ (ObjectID loc_id, STRING name, INT ref_type, SpaceID space=None)
+def create(ObjectID loc not None, char* name, int ref_type, SpaceID space=None):
+    """ (ObjectID loc, STRING name, INT ref_type, SpaceID space=None)
         => ReferenceObject ref
 
         Create a new reference. The value of ref_type detemines the kind
@@ -78,23 +78,23 @@ def create(ObjectID loc_id not None, char* name, int ref_type, SpaceID space=Non
     else:
         space_id = space.id
 
-    H5Rcreate(&ref.ref, loc_id.id, name, <H5R_type_t>ref_type, space_id)
+    H5Rcreate(&ref.ref, loc.id, name, <H5R_type_t>ref_type, space_id)
     ref.typecode = ref_type
 
     return ref
 
-def dereference(ObjectID file_id not None, Reference ref):
-    """ (ObjectID file_id, ReferenceObject ref) => INT obj_id
+def dereference(ObjectID fid not None, Reference ref):
+    """ (ObjectID fid, ReferenceObject ref) => INT obj_id
 
         Open the object pointed to by "ref" and return its identifier.
-        The containing file must be provided via file_id, which can be
+        The containing file must be provided via fid, which can be
         a file identifier or an identifier for any object which lives
         in the file.
     """
-    return H5Rdereference(file_id.id, <H5R_type_t>ref.typecode, &ref.ref)
+    return H5Rdereference(fid.id, <H5R_type_t>ref.typecode, &ref.ref)
 
-def get_region(ObjectID dataset_id not None, Reference ref):
-    """ (ObjectID dataset_id, Reference ref) => INT dataspace_id
+def get_region(ObjectID dataset not None, Reference ref):
+    """ (ObjectID dataset, Reference ref) => INT dataspace_id
 
         Retrieve the dataspace selection pointed to by a reference.
         Returns a copy of the dataset's dataspace, with the appropriate
@@ -102,14 +102,14 @@ def get_region(ObjectID dataset_id not None, Reference ref):
 
         The given reference object must be of type DATASET_REGION.
     """
-    return H5Rget_region(dataset_id.id, <H5R_type_t>ref.typecode, &ref.ref)
+    return H5Rget_region(dataset.id, <H5R_type_t>ref.typecode, &ref.ref)
 
-def get_obj_type(ObjectID ds_id not None, Reference ref):
-    """ (ObjectID ds_id, Reference ref) => INT obj_code
+def get_obj_type(ObjectID ds not None, Reference ref):
+    """ (ObjectID ds, Reference ref) => INT obj_code
 
         Determine what type of object an object reference points to.  The
         reference may be either type OBJECT or DATASET_REGION.  For 
-        DATASET_REGION, the parameter ds_id must be either the dataset 
+        DATASET_REGION, the parameter ds must be either the dataset 
         identifier, or the identifier for the object within which the
         dataset is contained.
         
@@ -119,7 +119,7 @@ def get_obj_type(ObjectID ds_id not None, Reference ref):
         h5g.DATASET     Dataset
         h5g.TYPE        Named datatype
     """
-    return <int>H5Rget_obj_type(ds_id.id, <H5R_type_t>ref.typecode, &ref.ref)
+    return <int>H5Rget_obj_type(ds.id, <H5R_type_t>ref.typecode, &ref.ref)
 
 
 
diff --git a/h5py/h5s.pyx b/h5py/h5s.pyx
index 5b9b9df..d5615d2 100644
--- a/h5py/h5s.pyx
+++ b/h5py/h5s.pyx
@@ -98,10 +98,24 @@ def create_simple(object dims_tpl, object max_dims_tpl=None):
 cdef class SpaceID(ObjectID):
 
     """
-        Represents a dataspace identifier
+        Represents a dataspace identifier.
+
+        Python extensions (readonly):
+
+        shape
     """
 
+    property shape:
+        def __get__(self):
+            return self.get_simple_extent_dims()
+
     def close(self):
+        """ ()
+
+            Terminate access through this identifier.  You shouldn't have to
+            call this manually; dataspace objects are automatically destroyed
+            when their Python wrappers are freed.
+        """
         H5Sclose(self.id)
 
     def copy(self):
@@ -134,7 +148,7 @@ cdef class SpaceID(ObjectID):
         dims = NULL
 
         try:
-            if not self.is_simple():
+            if not H5Sis_simple(self.id):
                 raise ValueError("%d is not a simple dataspace" % space_id)
 
             rank = H5Sget_simple_extent_ndims(self.id)
@@ -163,10 +177,10 @@ cdef class SpaceID(ObjectID):
         return H5Sget_simple_extent_ndims(self.id)
 
     def get_simple_extent_dims(self, int maxdims=0):
-        """ (INT space_id, BOOL maxdims=False) => TUPLE shape
+        """ (BOOL maxdims=False) => TUPLE shape
 
-            Determine the shape of a "simple" (slab) dataspace.  If "maxdims" is
-            True, retrieve the maximum dataspace size instead.
+            Determine the shape of a "simple" (slab) dataspace.  If "maxdims" 
+            is True, retrieve the maximum dataspace size instead.
         """
         cdef int rank
         cdef hsize_t* dims
@@ -200,10 +214,10 @@ cdef class SpaceID(ObjectID):
         """
         return <int>H5Sget_simple_extent_type(self.id)
 
-# === Extents =================================================================
+    # === Extents =============================================================
 
-    def extent_copy(self, SpaceID source_id not None):
-        """ (SpaceID source_id)
+    def extent_copy(self, SpaceID source not None):
+        """ (SpaceID source)
 
             Replace this dataspace's extent with another's, changing its
             typecode if necessary.
@@ -211,7 +225,7 @@ cdef class SpaceID(ObjectID):
         H5Sextent_copy(self.id, source.id)
 
     def set_extent_simple(self, object dims_tpl, object max_dims_tpl=None):
-        """ (INT space_id, TUPLE dims_tpl, TUPLE max_dims_tpl=None)
+        """ (TUPLE dims_tpl, TUPLE max_dims_tpl=None)
 
             Reset the dataspace extent via a tuple of dimensions.  
             Every element of dims_tpl must be a positive integer.  
@@ -245,13 +259,13 @@ cdef class SpaceID(ObjectID):
             efree(max_dims)
 
     def set_extent_none(self):
-        """ (INT space_id)
+        """ ()
 
             Remove the dataspace extent; typecode changes to NO_CLASS.
         """
         H5Sset_extent_none(self.id)
 
-# === General selection operations ============================================
+    # === General selection operations ========================================
 
     def get_select_type(self):
         """ () => INT select_code
@@ -321,7 +335,7 @@ cdef class SpaceID(ObjectID):
         """
         return pybool(H5Sselect_valid(self.id))
 
-# === Point selection functions ===============================================
+    # === Point selection functions ===========================================
 
     def get_select_elem_npoints(self):
         """ () => LONG npoints
@@ -406,7 +420,7 @@ cdef class SpaceID(ObjectID):
         finally:
             efree(coords)
 
-# === Hyperslab selection functions ===========================================
+    # === Hyperslab selection functions =======================================
 
     def get_select_hyper_nblocks(self):
         """ () => LONG nblocks
@@ -457,10 +471,10 @@ cdef class SpaceID(ObjectID):
         return outlist
     
 
-    def select_hyperslab(self, object start, object count, 
-        object stride=None, object block=None, int op=H5S_SELECT_SET):
-        """ (INT space_id, TUPLE start, TUPLE count, TUPLE stride=None, 
-                TUPLE block=None, INT op=SELECT_SET)
+    def select_hyperslab(self, object start, object count, object stride=None, 
+                         object block=None, int op=H5S_SELECT_SET):
+        """ (TUPLE start, TUPLE count, TUPLE stride=None, TUPLE block=None, 
+             INT op=SELECT_SET)
          
             Select a block region from an existing dataspace.  See the HDF5
             documentation for the meaning of the "block" and "op" keywords.
diff --git a/h5py/h5t.pxd b/h5py/h5t.pxd
index 72d75e5..7cf5ff7 100644
--- a/h5py/h5t.pxd
+++ b/h5py/h5t.pxd
@@ -18,6 +18,7 @@ include "std_defs.pxi"
 from h5 cimport class ObjectID
 
 cdef class TypeID(ObjectID):
+    cdef object _complex_names
 
     cdef int enum_convert(self, long long *buf, int reverse) except -1
  
@@ -234,11 +235,6 @@ cdef extern from "hdf5.h":
   herr_t    H5Tset_tag(hid_t type_id, char* tag) except *
   char*     H5Tget_tag(hid_t type_id) except? NULL
 
-# === Custom C API ============================================================
-
-# Close the datatype, ignoring all errors.
-cdef herr_t PY_H5Tclose(hid_t type_id) except *
-
 
 
 
diff --git a/h5py/h5t.pyx b/h5py/h5t.pyx
index 244e1f4..2126c26 100644
--- a/h5py/h5t.pyx
+++ b/h5py/h5t.pyx
@@ -79,19 +79,6 @@ from h5 import DDict, ArgsError
 import sys
 
 # === Custom C API ============================================================
-
-cdef herr_t PY_H5Tclose(hid_t type_id) except *:
-    # Unconditionally close a datatype, ignoring all errors.
-
-    cdef err_c cookie
-    cdef herr_t retval
-    cookie = pause_errors()
-    try:
-        retval = H5Tclose(type_id)
-    finally:
-        resume_errors(cookie)
-
-    return retval
     
 cdef object lockid(hid_t id_in):
     cdef TypeID tid
@@ -182,12 +169,30 @@ NATIVE_UINT64 = lockid(H5T_NATIVE_UINT64)
 # Null terminated (C) string type
 C_S1 = lockid(H5T_C_S1)
 
+# Map array protocol strings to their HDF5 atomic equivalents
+# Not sure why LE/BE versions of I8/U8 exist; I'll include them anyway.
+_code_map = {
+    "<i1": STD_I8LE, "<i2": STD_I16LE, "<i4": STD_I32LE, "<i8": STD_I64LE,
+    ">i1": STD_I8BE, ">i2": STD_I16BE, ">i4": STD_I32BE, ">i8": STD_I64BE,
+    "|i1": NATIVE_INT8, "|u1": NATIVE_UINT8, 
+    "<u1": STD_U8LE, "<u2": STD_U16LE, "<u4": STD_U32LE, "<u8": STD_U64LE,
+    ">u1": STD_U8BE, ">u2": STD_U16BE, ">u4": STD_U32BE, ">u8": STD_U64BE,
+    "<f4": IEEE_F32LE, "<f8": IEEE_F64LE, ">f4": IEEE_F32BE, ">f8": IEEE_F64BE 
+            }
+
+# Intermediate mapping which takes complex types to their components
+_complex_map = { "<c8": IEEE_F32LE, "<c16": IEEE_F64LE, 
+                 ">c8": IEEE_F32BE, ">c16": IEEE_F64BE }
+
+_order_map = { H5T_ORDER_NONE: '|', H5T_ORDER_LE: '<', H5T_ORDER_BE: '>'}
+_sign_map  = { H5T_SGN_NONE: 'u', H5T_SGN_2: 'i' }
+
 # === General datatype operations =============================================
 
 def create(int classtype, size_t size):
-    """ (INT class, INT size) => INT type_id
+    """ (INT classtype, INT size) => TypeID
         
-        Create a new HDF5 type object.  Legal values are 
+        Create a new HDF5 type object.  Legal class values are 
         COMPOUND, OPAQUE, and ENUM.
     """
     # If it's not one of these, the library SEGFAULTS. Thanks, guys.
@@ -225,11 +230,11 @@ def array_create(TypeID base not None, object dims_tpl):
         efree(dims)
 
 def enum_create(TypeID base not None):
-    """ (TypeID base) => INT new_type_id
+    """ (TypeID base) => TypeID new_enum
 
         Create a new enumerated type based on an (integer) parent type.
     """
-    return H5Tenum_create(base.id)
+    return TypeID(H5Tenum_create(base.id))
 
 # === XXXX ====
 
@@ -237,8 +242,28 @@ cdef class TypeID(ObjectID):
 
     """
         Represents an HDF5 datatype identifier.
+
+        Python properties:
+        dtype:          Numpy representation of the datatype.
     """
 
+    def __init__(self, hid_t id_):
+        self._complex_names = ('r', 'i')
+
+    property complex_names:
+        def __get__(self):
+            return self._complex_names
+        def __set__(self, item):
+            require_tuple(item, 0, -1, "complex_names")
+
+            if len(item) != 0 or len(item) != 2:
+                raise ValueError("complex_names must be either () or a 2-tuple")
+            for entry in item:
+                if not isinstance(entry, str):
+                    raise ValueError("complex_names must be a 2-tuple of strings")
+
+            self._complex_names = item
+
     def commit(self, ObjectID group not None, char* name):
         """ (ObjectID group, STRING name)
 
@@ -269,9 +294,9 @@ cdef class TypeID(ObjectID):
         return pybool(H5Tequal(self.id, typeid.id))
 
     def lock(self):
-        """ (self)
+        """ ()
 
-            Lock a datatype, which makes it immutable and indestructible.
+            Lock this datatype, which makes it immutable and indestructible.
             Once locked, it can't be unlocked.
         """
         H5Tlock(self.id)
@@ -299,7 +324,7 @@ cdef class TypeID(ObjectID):
         return TypeID(H5Tget_super(self.id))
 
     def get_native_type(self, int direction=H5T_DIR_DEFAULT):
-        """ (INT direction) => INT new_type_id
+        """ (INT direction=DIR_DEFAULT) => TypeID
 
             Determine the native C equivalent for the given datatype.
             Legal values for "direction" are:
@@ -309,12 +334,12 @@ cdef class TypeID(ObjectID):
             These determine which direction the list of native datatypes is
             searched; see the HDF5 docs for a definitive list.
 
-            The returned datatype is always an unlocked copy of one of NATIVE_*.
+            The returned datatype is always an unlocked copy of one of NATIVE_*
         """
         return TypeID(H5Tget_native_type(self.id, <H5T_direction_t>direction))
 
     def detect_class(self, int classtype):
-        """ (INT class) => BOOL class_is_present
+        """ (INT classtype) => BOOL class_is_present
 
             Determine if a member of the given class exists in a compound
             datatype.  The search is recursive.
@@ -325,16 +350,14 @@ cdef class TypeID(ObjectID):
         """ Close this datatype.  If it's locked, nothing happens.
         """
         if not self._locked:
-            H5Tclose(type_id)
-
-# === Atomic datatype operations ==============================================
+            H5Tclose(self.id)
 
+    # === Atomic datatype operations ==========================================
 
     def set_size(self, size_t size):
-        """ (INT size)
+        """ (UINT size)
 
-            Set the total size of the datatype, in bytes.  Useful mostly for
-            string types.
+            Set the total size of the datatype, in bytes.
         """
         H5Tset_size(self.id, size)
 
@@ -349,9 +372,9 @@ cdef class TypeID(ObjectID):
         return <int>H5Tget_order(self.id)
 
     def set_order(self, int order):
-        """ (INT type_id, INT order)
+        """ (INT order)
 
-            Set the byte order of the datatype. "order" must be one of
+            Set the byte order of the datatype; must be one of
              ORDER_LE
              ORDER_BE
              ORDER_NATIVE
@@ -359,7 +382,7 @@ cdef class TypeID(ObjectID):
         H5Tset_order(self.id, <H5T_order_t>order)
 
     def get_sign(self):
-        """ (INT type_id) => INT sign
+        """ () => INT sign
 
             Obtain the "signedness" of the datatype; one of:
               SGN_NONE:  Unsigned
@@ -385,8 +408,7 @@ cdef class TypeID(ObjectID):
         """
         return pybool(H5Tis_variable_str(self.id))
 
-# === Compound datatype operations ============================================
-
+    # === Compound datatype operations ========================================
 
     def get_nmembers(self):
         """ () => INT number_of_members
@@ -405,7 +427,6 @@ cdef class TypeID(ObjectID):
             raise ValueError("Member index must be non-negative.")
         return H5Tget_member_class(self.id, member)
 
-    
     def get_member_name(self, int member):
         """ (INT member) => STRING name
         
@@ -436,7 +457,7 @@ cdef class TypeID(ObjectID):
         return H5Tget_member_index(self.id, name)
 
     def get_member_offset(self, int member):
-        """ (INT member_index) => INT offset
+        """ (INT member) => INT offset
 
             Determine the offset, in bytes, of the beginning of the specified
             member of a compound datatype.
@@ -444,7 +465,7 @@ cdef class TypeID(ObjectID):
         return H5Tget_member_offset(self.id, member)
 
     def get_member_type(self, int member):
-        """ (INT member_index) => INT type_id
+        """ (INT member) => TypeID
 
             Create a copy of a member of a compound datatype, identified by its
             index.
@@ -454,7 +475,7 @@ cdef class TypeID(ObjectID):
         return TypeID(H5Tget_member_type(self.id, member))
 
     def insert(self, char* name, size_t offset, TypeID field not None):
-        """ (STRING name, INT offset, TypeID field)
+        """ (STRING name, UINT offset, TypeID field)
 
             Add a named member datatype to a compound datatype.  The parameter
             offset indicates the offset from the start of the compound datatype,
@@ -470,7 +491,7 @@ cdef class TypeID(ObjectID):
         """
         H5Tpack(self.id)
 
-# === Array datatype operations ===============================================
+    # === Array datatype operations ===========================================
 
     def get_array_ndims(self):
         """ () => INT rank
@@ -480,9 +501,10 @@ cdef class TypeID(ObjectID):
         return H5Tget_array_ndims(self.id)
 
     def get_array_dims(self):
-        """ (INT type_id) => TUPLE dimensions
+        """ () => TUPLE dimensions
 
-            Get the dimensions of the given array datatype as a tuple of integers.
+            Get the dimensions of the given array datatype as
+            a tuple of integers.
         """
         cdef hsize_t rank   
         cdef hsize_t* dims
@@ -496,12 +518,11 @@ cdef class TypeID(ObjectID):
         finally:
             efree(dims)
 
-# === Enumeration datatypes ===================================================
-
+    # === Enumeration datatypes ===============================================
 
     cdef int enum_convert(self, long long *buf, int reverse) except -1:
         # Convert the long long value in "buf" to the native representation
-        # of this (enumerated type).  Conversion performed in-place.
+        # of this (enumerated) type.  Conversion performed in-place.
         # Reverse: false => llong->type; true => type->llong
 
         cdef hid_t basetype
@@ -520,7 +541,7 @@ cdef class TypeID(ObjectID):
             else:
                 H5Tconvert(basetype, H5T_NATIVE_LLONG, 1, buf, NULL, H5P_DEFAULT)
         finally:
-            PY_H5Tclose(basetype)
+            H5Tclose(basetype)
 
     def enum_insert(self, char* name, long long value):
         """ (STRING name, INT/LONG value)
@@ -550,13 +571,12 @@ cdef class TypeID(ObjectID):
         buf = value
         self.enum_convert(&buf, 0)
         retval = H5Tenum_nameof(self.id, &buf, name, 1024)
-        if retval < 0:  # not sure whether H5Tenum_nameof will actually log an error
-            raise RuntimeError("Failed to determine enum name of %d" % value)
+        assert retval >= 0
         retstring = name
         return retstring
 
     def enum_valueof(self, char* name):
-        """ (STRING name) => LONG value)
+        """ (STRING name) => LONG value
 
             Get the value associated with an enum name.
         """
@@ -583,8 +603,7 @@ cdef class TypeID(ObjectID):
         self.enum_convert(&val, 1)
         return val
 
-# === Opaque datatypes ========================================================
-
+    # === Opaque datatypes ====================================================
 
     def set_tag(self, char* tag):
         """ (STRING tag)
@@ -609,6 +628,189 @@ cdef class TypeID(ObjectID):
         finally:
             free(buf)
 
+    def py_dtype(self):
+        """ ()
+
+            Create a Numpy dtype object as similar as possible to the given 
+            HDF5 datatype object.  The result is guaranteed to be logically 
+            compatible with the original object, with no loss of precision, 
+            but may not implement the same memory layout as the HDF5 type.
+        """
+        cdef TypeID tmp_type
+        cdef H5T_class_t classtype
+        classtype = self.get_class()
+        
+        if classtype == H5T_INTEGER:
+            typeobj = dtype( _order_map[self.get_order()] + 
+                             _sign_map[self.get_sign()] + str(self.get_size()) )
+
+        elif classtype == H5T_FLOAT:
+            typeobj = dtype( _order_map[self.get_order()] + 
+                            "f" + str(self.get_size()) )
+
+        elif classtype == H5T_STRING:
+            if self.is_variable_str():
+                raise ValueError("Variable-length strings are not supported.")
+
+            typeobj = dtype("|S" + str(self.get_size()))
+
+        elif classtype == H5T_OPAQUE:
+            typeobj = dtype("|V" + str(self.get_size()))
+
+        elif classtype == H5T_COMPOUND:
+
+            nfields = self.get_nmembers()
+            field_names = []
+            field_types = []
+
+            # First step: read field names and their Numpy dtypes into 
+            # two separate arrays.
+            for i from 0 <= i < nfields:
+                tmp_type = self.get_member_type(i)
+                tmp_type.complex_names = self.complex_names
+                try:
+                    field_names.append(self.get_member_name(i))
+                    field_types.append(tmp_type.py_dtype())
+                finally:
+                    tmp_type.close()
+
+            # 1. Check if it should be converted to a complex number
+            if len(field_names) == 2                    and \
+               tuple(field_names) == self.complex_names and \
+               field_types[0] == field_types[1]         and \
+               field_types[0].kind == 'f':
+
+                bstring = field_types[0].str
+                blen = int(bstring[2:])
+                nstring = bstring[0] + "c" + str(2*blen)
+                typeobj = dtype(nstring)
+
+            # 2. Otherwise, read all fields of the compound type, in HDF5 order.
+            else:
+                typeobj = dtype(zip(field_names, field_types))
+
+        elif classtype == H5T_ENUM:
+            # Have to recover enum dictionaries manually.
+            tmp_type = self.get_super()
+            try:
+                typeobj = tmp_type.py_dtype()
+            finally:
+                tmp_type.close()
+
+        elif classtype == H5T_ARRAY:
+            tmp_type = self.get_super()
+            tmp_type.complex_names = self.complex_names
+            try:
+                base_dtype = tmp_type.py_dtype()
+            finally:
+                tmp_type.close()
+            shape = tid.get_array_dims()
+            typeobj = dtype( (base_dtype, shape) )
+
+        else:
+            raise ValueError('Unsupported datatype class "%s"' % PY_NAMES[classtype])
+
+        return typeobj
+
+# === Python extension functions ==============================================
+
+
+def py_create(dtype dt not None, object complex_names=None):
+    """ ( DTYPE dt, TUPLE complex_names=None, DICT enum=None) => TypeID
+
+        Given a Numpy dtype object, generate a byte-for-byte memory-compatible
+        HDF5 datatype object.  The result is guaranteed to be transient and
+        unlocked.
+
+        complex_names:
+            Specifies when and how to interpret Python complex numbers as
+            HDF5 compound datatypes.  May be None or a tuple with strings 
+            (real name, img name).  "None" indicates the default mapping of
+            ("r", "i"). This option is also applied to subtypes of arrays 
+            and compound types.
+    """
+    cdef TypeID otype
+    cdef TypeID base
+    cdef TypeID tmp
+    cdef dtype dt_tmp
+    cdef char kind
+    cdef char byteorder
+    cdef int length
+
+    otype = None
+
+    if complex_names is None:
+        complex_names = DEFAULT_COMPLEX_NAMES
+    else: 
+        _validate_complex(complex_names)
+
+    kind = dt.kind
+    byteorder = dt.byteorder
+    length = int(dt.str[2:])  # is there a better way to do this?
+    names = dt.names
+        
+    # Check for an enum dict first
+    if enum is not None:
+        if kind != c'i' and kind != c'u':
+            raise ValueError("Enumerated types may only have integer bases.")
+    
+        otype = enum_create(_code_map[dt.str])
+
+        for key in sorted(enum):
+            otype.enum_insert(key, enum[key])
+
+    # Anything with field names is considered to be a compound type
+    elif names is not None:
+        otype = create(H5T_COMPOUND, length)
+        for name in names:
+            dt_tmp, offset = dt.fields[name]
+            tmp = py_create(dt_tmp, complex_names)
+            try:
+                otype.insert(name, offset, tmp)
+            finally:
+                tmp.close()
+
+    # Integers and floats map directly to HDF5 atomic types
+    elif kind == c'u' or kind  == c'i' or kind == c'f': 
+        try:
+            otype =  _code_map[dt.str].copy()
+        except KeyError:
+            raise ValueError("Failed to find '%s' in atomic code map" % dt.str)
+
+    # Complex numbers are stored as HDF5 structs, with names defined at runtime
+    elif kind == c'c':
+
+        if length == 8:
+            otype = TypeID(create_ieee_complex64(byteorder, _complex_names[0], _complex_names[1]))
+        elif length == 16:
+            otype = TypeID(create_ieee_complex128(byteorder, _complex_names[0], _complex_names[1]))
+        else:
+            raise ValueError("Unsupported length %d for complex dtype: %s" % (length, repr(dt)))
+
+    # Opaque/array types are differentiated by the presence of a subdtype
+    elif kind == c'V':
+
+        if dt.subdtype:
+            dt_tmp, shape = dt.subdtype
+            base = py_create(dt_tmp, complex_names)
+            try:
+                otype = array_create(base, shape)
+            finally:
+                base.close()
+        else:
+            otype = create(H5T_OPAQUE, length)
+                
+    # Strings are assumed to be stored C-style.
+    elif kind == c'S':
+        otype = TypeID(H5Tcopy(H5T_C_S1))
+        otype.set_size(length)
+
+    else:
+        raise ValueError("No conversion path for dtype: %s" % repr(dt))
+
+    if complex_names is not None:
+        otype.complex_names = complex_names
+    return otype
 
 
 

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