[python-hdf5storage] 111/152: Added ability to discard or throw an error when writing a matlab incompatible type when doing matlab compatibility.

Ghislain Vaillant ghisvail-guest at moszumanska.debian.org
Mon Feb 29 08:24:39 UTC 2016


This is an automated email from the git hooks/post-receive script.

ghisvail-guest pushed a commit to annotated tag 0.1
in repository python-hdf5storage.

commit 742f1eba2208ebab8553e7426fd5684085b04a1e
Author: Freja Nordsiek <fnordsie at gmail.com>
Date:   Thu Feb 13 17:36:52 2014 -0500

    Added ability to discard or throw an error when writing a matlab incompatible type when doing matlab compatibility.
---
 hdf5storage/Marshallers.py | 38 ++++++++++++++++++++----------
 hdf5storage/__init__.py    | 58 ++++++++++++++++++++++++++++++++++++++++++----
 hdf5storage/lowlevel.py    | 22 ++++++++++++++++++
 3 files changed, 102 insertions(+), 16 deletions(-)

diff --git a/hdf5storage/Marshallers.py b/hdf5storage/Marshallers.py
index 752eef3..8390115 100644
--- a/hdf5storage/Marshallers.py
+++ b/hdf5storage/Marshallers.py
@@ -35,6 +35,7 @@ import numpy as np
 import h5py
 
 from hdf5storage.utilities import *
+from hdf5storage import lowlevel
 from hdf5storage.lowlevel import write_data, read_data
 
 
@@ -375,6 +376,18 @@ class NumpyScalarArrayMarshaller(TypeMarshaller):
         self.matlab_classes = list(self.__MATLAB_classes.values())
 
     def write(self, f, grp, name, data, type_string, options):
+        # If we are doing matlab compatibility and the data type is not
+        # one of those that is supported for matlab, skip writing the
+        # data or throw an error if appropriate.
+        if options.matlab_compatible \
+                and data.dtype.type not in self.__MATLAB_classes:
+            if options.action_for_matlab_incompatible == 'error':
+                raise lowlevel.TypeNotMatlabCompatibleError( \
+                    'Data type ' + data.dtype.name
+                    + ' not supported by MATLAB.')
+            elif options.action_for_matlab_incompatible == 'discard':
+                return
+
         # Need to make a set of data that will be stored. It will start
         # out as a copy of data and then be steadily manipulated.
 
@@ -579,19 +592,19 @@ class NumpyScalarArrayMarshaller(TypeMarshaller):
         # bytes each element takes up (dtype.itemsize). Otherwise,
         # the attributes must be deleted.
 
-        if options.matlab_compatible:
-            tp = data.dtype.type
-            if tp in self.__MATLAB_classes:
-                set_attribute_string(grp[name], 'MATLAB_class',
-                                     self.__MATLAB_classes[tp])
-            else:
-                set_attribute_string(grp[name], 'MATLAB_class', '')
-
+        tp = data.dtype.type
+        if options.matlab_compatible and tp in self.__MATLAB_classes:
+            set_attribute_string(grp[name], 'MATLAB_class',
+                                 self.__MATLAB_classes[tp])
             if tp in (np.bytes_, np.str_, np.bool_):
                 set_attribute(grp[name], 'MATLAB_int_decode', np.int64(
                               grp[name].dtype.itemsize))
             else:
                 del_attribute(grp[name], 'MATLAB_int_decode')
+        else:
+            del_attribute(grp[name], 'MATLAB_class')
+            del_attribute(grp[name], 'MATLAB_empty')
+            del_attribute(grp[name], 'MATLAB_int_decode')
 
     def read(self, f, grp, name, options):
         # If name is not present or is not a Dataset, then we can't read
@@ -933,10 +946,11 @@ class PythonDictMarshaller(TypeMarshaller):
         # be deleted).
         for k, v in data.items():
             write_data(f, grp2, k, v, None, options)
-            if options.matlab_compatible:
-                set_attribute_string(grp2[k], 'H5PATH', grp2.name)
-            else:
-                del_attribute(grp2[k], 'H5PATH')
+            if k in grp2:
+                if options.matlab_compatible:
+                    set_attribute_string(grp2[k], 'H5PATH', grp2.name)
+                else:
+                    del_attribute(grp2[k], 'H5PATH')
 
     def write_metadata(self, f, grp, name, data, type_string, options):
         # First, call the inherited version to do most of the work.
diff --git a/hdf5storage/__init__.py b/hdf5storage/__init__.py
index 1f29927..a02d535 100644
--- a/hdf5storage/__init__.py
+++ b/hdf5storage/__init__.py
@@ -43,7 +43,9 @@ import datetime
 import h5py
 
 from . import lowlevel
-from hdf5storage.lowlevel import Hdf5storageError, CantReadError
+from hdf5storage.lowlevel import Hdf5storageError, CantReadError, \
+    TypeNotMatlabCompatibleError
+
 from . import Marshallers
 
 
@@ -81,6 +83,9 @@ class Options(object):
         See Attributes.
     matlab_compatible : bool, optional
         See Attributes.
+    action_for_matlab_incompatible: str, optional
+        See Attributes. Only valid values are 'ignore', 'discard', and
+        'error'.
     delete_unused_variables:  : bool, optional
         See Attributes.
     make_atleast_2d : bool, optional
@@ -108,6 +113,7 @@ class Options(object):
     ----------
     store_python_metadata : bool
     matlab_compatible : bool
+    action_for_matlab_incompatible: {'ignore', 'discard', 'error'}
     delete_unused_variables : bool
     make_atleast_2d : bool
     convert_numpy_bytes_to_utf16 : bool
@@ -128,6 +134,7 @@ class Options(object):
     """
     def __init__(self, store_python_metadata=True,
                  matlab_compatible=True,
+                 action_for_matlab_incompatible='error',
                  delete_unused_variables=False,
                  make_atleast_2d=False,
                  convert_numpy_bytes_to_utf16=False,
@@ -142,6 +149,7 @@ class Options(object):
         # Set the defaults.
 
         self._store_python_metadata = True
+        self._action_for_matlab_incompatible = 'error'
         self._delete_unused_variables = False
         self._make_atleast_2d = False
         self._convert_numpy_bytes_to_utf16 = False
@@ -159,6 +167,8 @@ class Options(object):
         # other ones.
 
         self.store_python_metadata = store_python_metadata
+        self.action_for_matlab_incompatible = \
+            action_for_matlab_incompatible
         self.delete_unused_variables = delete_unused_variables
         self.make_atleast_2d = make_atleast_2d
         self.convert_numpy_bytes_to_utf16 = convert_numpy_bytes_to_utf16
@@ -261,6 +271,33 @@ class Options(object):
                 self._group_for_references = "/#refs#"
 
     @property
+    def action_for_matlab_incompatible(self):
+        """ The action to do when writing non-MATLAB compatible data.
+
+        {'ignore', 'discard', 'error'}
+
+        The action to perform when doing MATLAB compatibility but a type
+        being written is not MATLAB compatible. The actions are to write
+        the data anyways ('ignore'), don't write the incompatible data
+        ('discard'), or throw a ``TypeNotMatlabCompatibleError``
+        exception. The default is 'error'.
+
+        See Also
+        --------
+        matlab_compatible
+        hdf5storage.lowlevel.TypeNotMatlabCompatibleError
+
+        """
+        return self._action_for_matlab_incompatible
+
+    @action_for_matlab_incompatible.setter
+    def action_for_matlab_incompatible(self, value):
+        # Check that it is one of the allowed values, and then set
+        # it. This option does not effect MATLAB compatibility.
+        if value in ('ignore', 'discard', 'error'):
+            self._action_for_matlab_incompatible = value
+
+    @property
     def delete_unused_variables(self):
         """ Whether or not to delete file variables not written to.
 
@@ -818,6 +855,9 @@ def write(data, path='/', filename='data.h5', truncate_existing=False,
     ------
     NotImplementedError
         If writing `data` is not supported.
+    TypeNotMatlabCompatibleError
+        If writing a type not compatible with MATLAB and
+        `options.action_for_matlab_incompatible` is set to ``'error'``.
 
     See Also
     --------
@@ -1037,6 +1077,7 @@ def read(path='/', filename='data.h5',
 
 def savemat(file_name, mdict, appendmat=True, format='7.3',
             oned_as='row', store_python_metadata=True,
+            action_for_matlab_incompatible='error',
             marshaller_collection=None, truncate_existing=False,
             truncate_invalid_matlab=False, **keywords):
     """ Save a dictionary of python types to a MATLAB MAT file.
@@ -1073,6 +1114,11 @@ def savemat(file_name, mdict, appendmat=True, format='7.3',
         Whether or not to store Python type information. Doing so allows
         most types to be read back perfectly. Only applicable if not
         dispatching to SciPy (`format` >= 7.3).
+    action_for_matlab_incompatible: str, optional
+        The action to perform writing data that is not MATLAB
+        compatible. The actions are to write the data anyways
+        ('ignore'), don't write the incompatible data ('discard'), or
+        throw a ``TypeNotMatlabCompatibleError`` exception.
     marshaller_collection : MarshallerCollection, optional
         Collection of marshallers to disk to use. Only applicable if
         not dispatching to SciPy (`format` >= 7.3).
@@ -1093,6 +1139,9 @@ def savemat(file_name, mdict, appendmat=True, format='7.3',
         If `format` < 7.3 and the ``scipy`` module can't be found.
     NotImplementedError
         If writing a variable in `mdict` is not supported.
+    TypeNotMatlabCompatibleError
+        If writing a type not compatible with MATLAB and
+        `action_for_matlab_incompatible` is set to ``'error'``.
 
     Notes
     -----
@@ -1126,9 +1175,10 @@ def savemat(file_name, mdict, appendmat=True, format='7.3',
         file_name = file_name + '.mat'
 
     # Make the options with matlab compatibility forced.
-    options = Options(store_python_metadata=store_python_metadata,
-                      matlab_compatible=True, oned_as=oned_as,
-                      marshaller_collection=marshaller_collection)
+    options = Options(store_python_metadata=store_python_metadata, \
+        matlab_compatible=True, oned_as=oned_as, \
+        action_for_matlab_incompatible=action_for_matlab_incompatible, \
+        marshaller_collection=marshaller_collection)
 
     # Write the variables in the dictionary to file one at a time. For
     # the first one, the file needs to be truncated or truncated if not
diff --git a/hdf5storage/lowlevel.py b/hdf5storage/lowlevel.py
index baf3832..379dbfa 100644
--- a/hdf5storage/lowlevel.py
+++ b/hdf5storage/lowlevel.py
@@ -42,6 +42,25 @@ class Hdf5storageError(IOError):
 
 class CantReadError(Hdf5storageError):
     """ Exception for a failure to read the desired data."""
+    pass
+
+
+class TypeNotMatlabCompatibleError(Hdf5storageError):
+    """ Exception for trying to write non-MATLAB compatible data.
+
+    In the event that MATLAB compatibility is being done
+    (``Options.matlab_compatible``) and a Python type is not importable
+    by MATLAB, the data is either not written or this exception is
+    thrown depending on the value of
+    ``Options.action_for_matlab_incompatible``.
+
+    See Also
+    --------
+    hdf5storage.Options.matlab_compatible
+    hdf5storage.Options.action_for_matlab_incompatible
+
+    """
+    pass
 
 
 def write_data(f, grp, name, data, type_string, options):
@@ -70,6 +89,9 @@ def write_data(f, grp, name, data, type_string, options):
     ------
     NotImplementedError
         If writing `data` is not supported.
+    TypeNotMatlabCompatibleError
+        If writing a type not compatible with MATLAB and
+        `options.action_for_matlab_incompatible` is set to ``'error'``.
 
     See Also
     --------

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-science/packages/python-hdf5storage.git



More information about the debian-science-commits mailing list