[h5py] 29/455: Clean up complex h5t cruft

Ghislain Vaillant ghisvail-guest at moszumanska.debian.org
Thu Jul 2 18:19:14 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 236a7d85db8c06b8aceab314306f203361f00596
Author: andrewcollette <andrew.collette at gmail.com>
Date:   Sun May 25 02:17:59 2008 +0000

    Clean up complex h5t cruft
---
 h5py/h5t.pyx | 179 ++++++++++++++++++++++++++++++++++++++++++-----------------
 1 file changed, 129 insertions(+), 50 deletions(-)

diff --git a/h5py/h5t.pyx b/h5py/h5t.pyx
index 856632b..fdd40ca 100644
--- a/h5py/h5t.pyx
+++ b/h5py/h5t.pyx
@@ -45,11 +45,9 @@
     and field names (by default) "r" and "i".  Complex numbers can be auto-
     recovered from HDF5 objects provided they match this format and have
     compatible field names.  Since other people may have named their fields
-    e.g. "img" and "real", these names can be changed.  The function
-    py_set_complex_names(real_name, imaginary_name) allows you to select at
-    runtime what names are used to read in and write out complex-compound
-    objects.  To turn off this behavior completely, simply call 
-    py_set_complex_names with no arguments.
+    e.g. "img" and "real", these names can be changed.  The API functions
+    py_dtype_to_h5t and py_h5t_to_dtype take arguments which specify these
+    names.
 
 """
 
@@ -667,31 +665,74 @@ _complex_map = { "<c8": H5T_IEEE_F32LE, "<c16": H5T_IEEE_F64LE, ">c8": H5T_IEEE_
 _order_map = { H5T_ORDER_NONE: '|', H5T_ORDER_LE: '<', H5T_ORDER_BE: '>'}
 _sign_map  = { H5T_SGN_NONE: 'u', H5T_SGN_2: 'i' }
 
-_complex_names = ('r','i')
+DEFAULT_COMPLEX_NAMES = ('r','i')
+VALID_BYTEORDERS = ('<','>','=')
 
-# For an HDF5 compound object to be considered complex, the following must be
-# true:
+# For an HDF5 compound object to be considered complex, at least the following 
+# must be true:
 # (1) Must have exactly two fields
 # (2) Both must be IEEE floating-point, of the same precision and byteorder
-# (3) The field names must match the contents of _complex_names
 
-def py_set_complex_names(char* real_name=NULL, char* imag_name=NULL):
-    """ (STRING real_name, STRING imag_name) or ()
-
-        Sets the field names used to read and write complex numbers from HDF5
-        compound datatypes.  To disable all complex conversion, call with no
-        arguments.
+def _validate_complex(item):
+    """ Common validation function for complex names, which must be 2-tuples
+        containing strings.
     """
-    if real_name == NULL and imag_name == NULL:
-        _complex_names = None
-    elif real_name != NULL and imag_name != NULL:
-        _complex_names = (real_name, imag_name)
-    else:
-        raise ValueError("Must be called with no arguments or exactly 2: STRING real_name, STRING imag_name")
+    if not isinstance(item, tuple) or len(item) != 2 or \
+      not isinstance(item[0], str) or not isinstance(item[1], str):
+        raise ValueError("Complex names must be given a 2-tuples of strings: (real, img)")
 
+def _validate_byteorder(item):
+    """ Common validation function for byte orders, which must be <, > or =.
+    """
+    if not item in VALID_BYTEORDERS:
+        raise ValueError("Byte order must be one of "+", ".join(VALID_BYTEORDERS))
     
-def py_h5t_to_dtype(hid_t type_id, object byteorder=None, int string_length=-1, object compound_fields=None):
-    """ TODO: rework this.
+def _validate_names(names):
+    """ Common validation function for compound object field names, which must
+        be tuples of strings.
+    """
+    if isinstance(item, tuple):
+        bad = False
+        for x in names:
+            if not isinstance(name, str):
+                bad = True
+                break
+        if not bad:
+            return
+    raise ValueError("Compound names must be given as a tuple of strings.")
+
+
+def py_h5t_to_dtype(hid_t type_id, object byteorder=None, 
+                        object compound_names=None, object complex_names=None):
+    """ (INT type_id, STRING byteorder=None, TUPLE compound_names=None.
+         TUPLE complex_names=None)
+        => DTYPE
+
+        Create a Numpy dtype object as similar as possible to the given HDF5
+        datatype object.  The result is not guaranteed to be memory-compatible
+        with the original datatype object.
+
+        Optional arguments:
+
+        byteorder:  
+            None or one of <, >, =.  Coerce the byte order of the resulting
+            dtype object.  "None" preserves the original HDF5 byte order.  
+            This option IS applied to subtypes of arrays and compound types.
+
+        compound_names:
+            None or a tuple indicating which fields of a compound type to 
+            preserve in the output.  Fields in the new dtype will be listed 
+            in the order that they appear here.  Specifying a field which 
+            doesn't appear in the HDF5 type raises ValueError.  This option
+            IS NOT applied to subtypes of a compound type, but IS applied to
+            subtypes of arrays.
+
+        complex_names:
+            Specifies when and how to interpret HDF5 compound datatypes as 
+            Python complex numbers.  May be None or a tuple with strings 
+            (real name, img name).  "None" indicates the default mapping of
+            ("r", "i").  To turn this off, set to the empty tuple "()".
+            This option IS applied to subtypes of arrays and compound types.
     """
     cdef int classtype
     cdef int sign
@@ -701,6 +742,21 @@ def py_h5t_to_dtype(hid_t type_id, object byteorder=None, int string_length=-1,
     cdef int i
     cdef hid_t tmp_id
 
+    # Argument validation and defaults
+
+    if byteorder is not None: 
+        _validate_byteorder(byteorder)
+
+    if compound_names is not None:
+        _validate_names(compound_names)
+
+    if complex_names is None:
+        complex_names = DEFAULT_COMPLEX_NAMES
+    elif complex_names != (): 
+        _validate_complex(complex_names)
+
+    # End argument validation
+
     classtype = get_class(type_id)
     
     if classtype == H5T_INTEGER:
@@ -716,10 +772,7 @@ def py_h5t_to_dtype(hid_t type_id, object byteorder=None, int string_length=-1,
 
     elif classtype == H5T_STRING:
         if is_variable_str(type_id):
-            if string_length <= 0:
-                raise ConversionError("Variable-length strings are unsupported; try using a fixed size via force_string_length")
-            else:
-                size = string_length
+            raise ConversionError("Variable-length strings are not supported.")
         else:
             size = get_size(type_id)
         typeobj = dtype("|S" + str(size))
@@ -729,6 +782,12 @@ def py_h5t_to_dtype(hid_t type_id, object byteorder=None, int string_length=-1,
         typeobj = dtype("|V" + str(size))
 
     elif classtype == H5T_COMPOUND:
+        # 1. Read field names and put them in a list
+        # 2. If a subset of names are requested, check to 
+        #       make sure they exist and use that list instead.
+        # 3. Alternately, if the type only has two fields, 
+        #       see if we should convert it as a complex number.
+
         nfields = get_nmembers(type_id)
         field_list = []
 
@@ -736,26 +795,31 @@ def py_h5t_to_dtype(hid_t type_id, object byteorder=None, int string_length=-1,
             tmp_id = get_member_type(type_id, i)
             try:
                 tmp_name = get_member_name(type_id, i)
-                field_list.append( (tmp_name, py_h5t_to_dtype(tmp_id, byteorder, string_length)) )
+                field_list.append( (
+                                    tmp_name, 
+                                    py_h5t_to_dtype(tmp_id, byteorder,
+                                      None, complex_names)
+                                 ) )
             finally:
                 H5Tclose(tmp_id)
 
-        if compound_fields is not None:
-            # If only specific fields are requested, provide them
-            # in the order specified
-            name_dict = dict(field_list)
-            field_list = []
-            for name in compound_fields:
-                if name in name_dict:
-                    field_list.append((name, name_dict[name]))
+        if compound_names is not None:
+            # Validate the requested fields
+            requested = set(compound_names)
+            present = set(field_list)
+            missing = requested - present
+            if len(missing) > 0:
+                raise ValueError("The following fields are not present in the given compound type:\n" + 
+                                 ", ".join(missing) )
+            field_list = compound_names
             
         elif len(field_list) == 2:
             # Special case: complex type.  Note this changes "field_list" to a string.
-            if _complex_names is not None                       and \
+            if complex_names is not None and complex_names != () and \
                field_list[0][1].str     == field_list[1][1].str and \
                field_list[0][1].str[1]  == 'f'                  and \
-               field_list[0][0].lower() == _complex_names[0]    and \
-               field_list[1][0].lower() == _complex_names[1]:
+               field_list[0][0].lower() == complex_names[0]     and \
+               field_list[1][0].lower() == complex_names[1]:
 
                     bstring = field_list[0][1].str
                     blen = int(bstring[2:])
@@ -770,14 +834,15 @@ def py_h5t_to_dtype(hid_t type_id, object byteorder=None, int string_length=-1,
         super_tid = H5Tget_super(type_id)
         try:
             edct = py_enum_to_dict(type_id)
-            typeobj = py_attach_enum(edct, py_h5t_to_dtype(super_tid))
+            # Superclass must be an integer, so only provide byteorder.
+            typeobj = py_attach_enum(edct, py_h5t_to_dtype(super_tid, byteorder))
         finally:
             H5Tclose(super_tid)
 
     elif classtype == H5T_ARRAY:
         super_tid = get_super(type_id)
         try:
-            base_dtype = py_h5t_to_dtype(super_tid)
+            base_dtype = py_h5t_to_dtype(super_tid, byteorder, compound_names, complex_names)
         finally:
             H5Tclose(super_tid)
         shape = get_array_dims(type_id)
@@ -790,16 +855,22 @@ def py_h5t_to_dtype(hid_t type_id, object byteorder=None, int string_length=-1,
         return typeobj.newbyteorder(byteorder)
     return typeobj
 
-def py_dtype_to_h5t(numpy.dtype dtype_in):
-    """ ( DTYPE dtype_in ) => INT type_id
+def py_dtype_to_h5t(numpy.dtype dtype_in, object complex_names=None):
+    """ ( DTYPE dtype_in, TUPLE complex_names=None) => INT type_id
 
         Given a Numpy dtype object, generate a byte-for-byte memory-compatible
         HDF5 transient datatype object.
+
+        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 hid_t type_out
     cdef hid_t tmp
     cdef hid_t basetype
-    cdef object names
     cdef int retval
 
     cdef char* type_str
@@ -809,6 +880,11 @@ def py_dtype_to_h5t(numpy.dtype dtype_in):
 
     type_out = -1
 
+    if complex_names is None:
+        complex_names = DEFAULT_COMPLEX_NAMES
+    else: 
+        _validate_complex(complex_names)
+
     type_str = dtype_in.str
     kind = type_str[1]
     byteorder = type_str[0]
@@ -830,7 +906,7 @@ def py_dtype_to_h5t(numpy.dtype dtype_in):
             type_out = create(H5T_COMPOUND, length)
             for name in dtype_in.names:
                 dt, offset = dtype_in.fields[name]
-                tmp = py_dtype_to_h5t(dt)
+                tmp = py_dtype_to_h5t(dt, complex_names)
                 try:
                     insert(type_out, name, offset, tmp)
                 finally:
@@ -845,8 +921,6 @@ def py_dtype_to_h5t(numpy.dtype dtype_in):
 
     # Complex numbers are stored as HDF5 structs, with names defined at runtime
     elif kind == c'c':
-        if _complex_names is None:
-            raise ConversionError("Support for writing complex numbers is turned off.  Use py_set_complex_names to turn it back on.")
 
         if length == 8:
             type_out = create_ieee_complex64(byteorder, _complex_names[0], _complex_names[1])
@@ -862,7 +936,7 @@ def py_dtype_to_h5t(numpy.dtype dtype_in):
     elif kind == c'V':
 
         if dtype_in.subdtype:
-            basetype = py_dtype_to_h5t(dtype_in.subdtype[0])
+            basetype = py_dtype_to_h5t(dtype_in.subdtype[0], complex_names)
             try:
                 type_out = array_create(basetype, dtype_in.subdtype[1])
             finally:
@@ -950,13 +1024,18 @@ def py_list_compound_names(hid_t type_in):
 
     return qlist
 
-def py_can_convert_dtype(object dt):
+def py_can_convert_dtype(object dt, object complex_names=None):
+    """ (DTYPE dt, TUPLE complex_names=None) => BOOL can_convert
 
+        Test whether the given Numpy dtype can be converted to the appropriate
+        memory-compatible HDF5 datatype.  complex_names works as in the
+        function h5t.py_dtype_to_h5t.
+    """
     cdef hid_t tid
     tid = 0
     can_convert = False
     try:
-        tid = py_dtype_to_h5t(dt)
+        tid = py_dtype_to_h5t(dt, complex_names)
         can_convert = True
     except ConversionError:
         pass

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