[h5py] 57/455: Better OO design 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 2c2e5b35434b0a27c1aa172fc61eed55ff5503c6
Author: andrewcollette <andrew.collette at gmail.com>
Date:   Thu Jun 19 01:44:43 2008 +0000

    Better OO design for h5t
---
 h5py/h5.pyx  |   5 +-
 h5py/h5t.pxd |  39 +++++-
 h5py/h5t.pyx | 388 +++++++++++++++++++++++++++++++++--------------------------
 3 files changed, 254 insertions(+), 178 deletions(-)

diff --git a/h5py/h5.pyx b/h5py/h5.pyx
index 1d5cc14..38067ed 100644
--- a/h5py/h5.pyx
+++ b/h5py/h5.pyx
@@ -63,10 +63,11 @@ cdef class ObjectID:
             H5Idec_ref(self.id)
 
     def __copy__(self):
-        """ Create a new instance and incref the ID. """
+        """ Create another object wrapper which points to the same id. """
         copy = type(self)(self.id)
-        if not self._locked:
+        if H5Iget_type(self.id) != H5I_BADID and not self._locked:
             H5Iinc_ref(self.id)
+        copy._locked = self._locked
         return copy
 
     def __str__(self):
diff --git a/h5py/h5t.pxd b/h5py/h5t.pxd
index 9ac6adb..82fec6d 100644
--- a/h5py/h5t.pxd
+++ b/h5py/h5t.pxd
@@ -20,9 +20,43 @@ from h5 cimport class ObjectID
 cdef class TypeID(ObjectID):
     cdef object _complex_names
 
+    cdef object py_dtype(self)
+
+# --- Top-level classes ---
+
+cdef class TypeArrayID(TypeID):
+    pass
+
+cdef class TypeOpaqueID(TypeID):
+    pass
+
+cdef class TypeStringID(TypeID):
+    # Both vlen and fixed-len strings
+    pass
+
+cdef class TypeVlenID(TypeID):
+    # Non-string vlens
+    pass
+
+cdef class TypeTimeID(TypeID):
+    pass
+
+cdef class TypeBitfieldID(TypeID):
+    pass
+
+# --- Numeric atomic types ---
+
 cdef class TypeAtomicID(TypeID):
     pass
 
+cdef class TypeIntegerID(TypeAtomicID):
+    pass
+
+cdef class TypeFloatID(TypeAtomicID):
+    pass
+
+# --- Enums & compound types ---
+
 cdef class TypeCompositeID(TypeID):
     pass
 
@@ -33,11 +67,6 @@ cdef class TypeEnumID(TypeCompositeID):
 cdef class TypeCompoundID(TypeCompositeID):
     pass
 
-cdef class TypeArrayID(TypeID):
-    pass
-
-cdef class TypeOpaqueID(TypeID):
-    pass
 
 cdef object typewrap(hid_t id_)
  
diff --git a/h5py/h5t.pyx b/h5py/h5t.pyx
index a2a89ed..ca922fa 100644
--- a/h5py/h5t.pyx
+++ b/h5py/h5t.pyx
@@ -179,35 +179,39 @@ _complex_map = { "<c8": IEEE_F32LE, "<c16": IEEE_F64LE,
 _order_map = { H5T_ORDER_NONE: '|', H5T_ORDER_LE: '<', H5T_ORDER_BE: '>'}
 _sign_map  = { H5T_SGN_NONE: 'u', H5T_SGN_2: 'i' }
 
-_class_names = { H5T_INTEGER: "INTEGER",
-            H5T_FLOAT: "FLOAT",
-            H5T_TIME: "TIME",
-            H5T_STRING: "STRING",
-            H5T_BITFIELD: "BITFIELD",
-            H5T_OPAQUE: "OPAQUE",
-            H5T_COMPOUND: "COMPOUND",
-            H5T_REFERENCE: "REFERENCE",
-            H5T_ENUM: "ENUM",
-            H5T_VLEN: "VLEN",
-            H5T_ARRAY: "ARRAY" }
-
 # === Custom C API ============================================================
     
 cdef object typewrap(hid_t id_):
-    _classes = { H5T_INTEGER: TypeAtomicID,
-                H5T_FLOAT: TypeAtomicID,
-                H5T_TIME: TypeID,
-                H5T_STRING: TypeAtomicID,
-                H5T_BITFIELD: TypeAtomicID,
-                H5T_OPAQUE: TypeOpaqueID,
-                H5T_COMPOUND: TypeCompoundID,
-                H5T_REFERENCE: TypeID,
-                H5T_ENUM: TypeEnumID,
-                H5T_VLEN: TypeAtomicID,
-                H5T_ARRAY: TypeArrayID }
+
     cdef H5T_class_t cls
     cls = H5Tget_class(id_)
-    return _classes.get(cls, TypeID)(id_)
+
+    if cls == H5T_INTEGER:
+        pcls = TypeIntegerID
+    elif cls == H5T_FLOAT:
+        pcls = TypeFloatID
+    elif cls == H5T_TIME:
+        pcls = TypeTimeID
+    elif cls == H5T_STRING:
+        pcls = TypeStringID
+    elif cls == H5T_BITFIELD:
+        pcls = TypeBitfieldID
+    elif cls == H5T_OPAQUE:
+        pcls = TypeOpaqueID
+    elif cls == H5T_COMPOUND:
+        pcls = TypeCompoundID
+    elif cls == H5T_REFERENCE:
+        pcls = TypeReferenceID
+    elif cls == H5T_ENUM:
+        pcls = TypeEnumID
+    elif cls == H5T_VLEN:
+        pcls = TypeVlenID
+    elif cls == H5T_ARRAY:
+        pcls = TypeArrayID
+    else:
+        pcls = TypeID
+
+    return pcls(id_)
 
 cdef object lockid(hid_t id_in):
     cdef TypeID tid
@@ -264,6 +268,7 @@ def enum_create(TypeID base not None):
     """
     return typewrap(H5Tenum_create(base.id))
 
+# === Base type class =========================================================
 
 cdef class TypeID(ObjectID):
 
@@ -278,30 +283,37 @@ cdef class TypeID(ObjectID):
     def __init__(self, hid_t id_):
         self._complex_names = ('r', 'i')
 
-    property complex_names:
+    def __copy__(self):
+        cpy = ObjectID.__copy__(self)
+        cpy._complex_names = self._complex_names
+        return cpy
+
+    property py_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")
+            if not typecheck(item, tuple) or (len(item) != 0 and len(item) != 2):
+                raise ValueError("py_complex_names must be either () or a 2-tuple of strings")
             for entry in item:
-                if not isinstance(entry, str):
-                    raise ValueError("complex_names must be a 2-tuple of strings")
+                if not typecheck(entry, str):
+                    raise ValueError("py_complex_names must be a 2-tuple of strings")
 
             self._complex_names = item
 
     property dtype:
+        """ Obtain a Numpy-style dtype object """
         def __get__(self):
             return self.py_dtype()
 
+    cdef object py_dtype(self):
+        raise NotImplementedError("Don't know how to convert %s objects to Numpy" % self.__class__.__name__)
+
     def commit(self, ObjectID group not None, char* name):
         """ (ObjectID group, STRING name)
 
             Commit this (transient) datatype to a named datatype in a file.
         """
-        return H5Tcommit(group.id, name, self.id)
+        H5Tcommit(group.id, name, self.id)
 
     def committed(self):
         """ () => BOOL is_comitted
@@ -358,7 +370,7 @@ cdef class TypeID(ObjectID):
     def get_super(self):
         """ () => TypeID
 
-            Determine the parent type of an array or enumeration datatype.
+            Determine the parent type of an array, enumeration or vlen datatype.
         """
         return typewrap(H5Tget_super(self.id))
 
@@ -391,92 +403,130 @@ cdef class TypeID(ObjectID):
         if not self._locked:
             H5Tclose(self.id)
 
-    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.
+# === Top-level classes (inherit directly from TypeID) ========================
+
+cdef class TypeArrayID(TypeID):
+
+    """
+        Represents an array datatype
+    """
+
+    def get_array_ndims(self):
+        """ () => INT rank
+
+            Get the rank of the given array datatype.
+        """
+        return H5Tget_array_ndims(self.id)
+
+    def get_array_dims(self):
+        """ () => TUPLE dimensions
+
+            Get the dimensions of the given array datatype as
+            a tuple of integers.
         """
+        cdef hsize_t rank   
+        cdef hsize_t* dims
+        dims = NULL
+
+        rank = H5Tget_array_dims(self.id, NULL, NULL)
+        dims = <hsize_t*>emalloc(sizeof(hsize_t)*rank)
+        try:
+            H5Tget_array_dims(self.id, dims, NULL)
+            return convert_dims(dims, rank)
+        finally:
+            efree(dims)
+
+    cdef object py_dtype(self):
+        # Numpy translation function for array types
         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))
+        tmp_type = self.get_super()
+        tmp_type.complex_names = self.complex_names
+        try:
+            base_dtype = tmp_type.py_dtype()
+        finally:
+            tmp_type.close()
+        shape = self.get_array_dims()
+        return dtype( (base_dtype, shape) )
 
-        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) )
+cdef class TypeOpaqueID(TypeID):
 
-        else:
-            raise ValueError('Unsupported datatype class "%s"' % PY_NAMES[classtype])
+    """
+        Represents an opaque type
+    """
 
-        return typeobj
+    def set_tag(self, char* tag):
+        """ (STRING tag)
+
+            Set a string describing the contents of an opaque datatype.
+        """
+        H5Tset_tag(self.id, tag)
+
+    def get_tag(self):
+        """ () => STRING tag
+
+            Get the tag associated with an opaque datatype.
+        """
+        cdef char* buf
+        buf = NULL
+
+        try:
+            buf = H5Tget_tag(self.id)
+            assert buf != NULL
+            tag = buf
+            return tag
+        finally:
+            free(buf)
+
+    cdef object py_dtype(self):
+        # Numpy translation function for opaque types
+        return dtype("|V" + str(self.get_size()))
+
+cdef class TypeStringID(TypeID):
 
-    def __str__(self):
-        return ObjectID.__str__(self)+": "+_class_names.get(self.get_class(), "UNKNOWN")
+    """
+        String datatypes, both fixed and vlen.
+    """
+
+    def is_variable_str(self):
+        """ () => BOOL is_variable
+
+            Determine if the given string datatype is a variable-length string.
+            Please note that reading/writing data in this format is impossible;
+            only fixed-length strings are currently supported.
+        """
+        return pybool(H5Tis_variable_str(self.id))
+
+    cdef object py_dtype(self):
+        # Numpy translation function for string types
+        if self.is_variable_str():
+            raise NotImplementedError("Variable-length strings are not supported.")
+
+        return dtype("|S" + str(self.get_size()))
+
+cdef class TypeVlenID(TypeID):
+
+    """
+        Non-string vlen datatypes.
+    """
+    pass
+
+cdef class TypeTimeID(TypeID):
+
+    """
+        Unix-style time_t
+    """
+    pass
+
+cdef class TypeBitfieldID(TypeID):
+
+    """
+        HDF5 bitfield type
+    """
+    pass
+
+# === Numeric classes (integers and floats) ===================================
 
 cdef class TypeAtomicID(TypeID):
 
@@ -504,6 +554,12 @@ cdef class TypeAtomicID(TypeID):
         """
         H5Tset_order(self.id, <H5T_order_t>order)
 
+cdef class TypeIntegerID(TypeAtomicID):
+
+    """
+        Integer atomic types
+    """
+
     def get_sign(self):
         """ () => INT sign
 
@@ -522,16 +578,24 @@ cdef class TypeAtomicID(TypeID):
         """
         H5Tset_sign(self.id, <H5T_sign_t>sign)
 
-    def is_variable_str(self):
-        """ () => BOOL is_variable
+    cdef object py_dtype(self):
+        # Translation function for integer types
+        return dtype( _order_map[self.get_order()] + 
+                      _sign_map[self.get_sign()] + str(self.get_size()) )
 
-            Determine if the given string datatype is a variable-length string.
-            Please note that reading/writing data in this format is impossible;
-            only fixed-length strings are currently supported.
-        """
-        return pybool(H5Tis_variable_str(self.id))
+cdef class TypeFloatID(TypeAtomicID):
+
+    """
+        Floating-point datatypes
+    """
+    cdef object py_dtype(self):
+        # Translation function for floating-point types
+        return dtype( _order_map[self.get_order()] + "f" + 
+                      str(self.get_size()) )
 
 
+# === Composite types (enums and compound) ====================================
+
 cdef class TypeCompositeID(TypeID):
 
     """
@@ -628,36 +692,40 @@ cdef class TypeCompoundID(TypeCompositeID):
         """
         H5Tpack(self.id)
 
-cdef class TypeArrayID(TypeID):
+    cdef object py_dtype(self):
 
-    """
-        Represents an array datatype
-    """
+        cdef TypeID tmp_type
+        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()
 
-    def get_array_ndims(self):
-        """ () => INT rank
+        # 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':
 
-            Get the rank of the given array datatype.
-        """
-        return H5Tget_array_ndims(self.id)
+            bstring = field_types[0].str
+            blen = int(bstring[2:])
+            nstring = bstring[0] + "c" + str(2*blen)
+            typeobj = dtype(nstring)
 
-    def get_array_dims(self):
-        """ () => TUPLE dimensions
-
-            Get the dimensions of the given array datatype as
-            a tuple of integers.
-        """
-        cdef hsize_t rank   
-        cdef hsize_t* dims
-        dims = NULL
+        # 2. Otherwise, read all fields of the compound type, in HDF5 order.
+        else:
+            typeobj = dtype(zip(field_names, field_types))
 
-        rank = H5Tget_array_dims(self.id, NULL, NULL)
-        dims = <hsize_t*>emalloc(sizeof(hsize_t)*rank)
-        try:
-            H5Tget_array_dims(self.id, dims, NULL)
-            return convert_dims(dims, rank)
-        finally:
-            efree(dims)
+        return typeobj
 
 cdef class TypeEnumID(TypeCompositeID):
 
@@ -748,36 +816,14 @@ cdef class TypeEnumID(TypeCompositeID):
         self.enum_convert(&val, 1)
         return val
 
-cdef class TypeOpaqueID(TypeID):
-
-    """
-        Represents an opaque type
-    """
-
-    def set_tag(self, char* tag):
-        """ (STRING tag)
-
-            Set a string describing the contents of an opaque datatype.
-        """
-        H5Tset_tag(self.id, tag)
-
-    def get_tag(self):
-        """ () => STRING tag
-
-            Get the tag associated with an opaque datatype.
-        """
-        cdef char* buf
-        buf = NULL
-
+    cdef object py_dtype(self):
+        # Translation function for enum types
+        cdef TypeID tmp_type
+        tmp_type = self.get_super()
         try:
-            buf = H5Tget_tag(self.id)
-            assert buf != NULL
-            tag = buf
-            return tag
+            typeobj = tmp_type.py_dtype()
         finally:
-            free(buf)
-
-
+            tmp_type.close()
 
 # === Python extension functions ==============================================
 

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