[h5py] 240/455: Native Python exception support
Ghislain Vaillant
ghisvail-guest at moszumanska.debian.org
Thu Jul 2 18:19:37 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 6abd6c7643fa5f8a526186896b0237bcf09ad788
Author: andrewcollette <andrew.collette at gmail.com>
Date: Wed Apr 22 00:30:29 2009 +0000
Native Python exception support
---
h5py/__init__.py | 3 +-
h5py/_stub.py | 14 ++++
h5py/_sync.py | 1 +
h5py/h5.pyx | 151 +----------------------------------------
h5py/h5e.pxd | 6 +-
h5py/h5e.pyx | 199 ++++++++++++++++++++++++++++++++++++++++++++++++-------
setup.py | 2 +-
7 files changed, 200 insertions(+), 176 deletions(-)
diff --git a/h5py/__init__.py b/h5py/__init__.py
index 434180f..0ea2184 100644
--- a/h5py/__init__.py
+++ b/h5py/__init__.py
@@ -32,7 +32,8 @@ except ImportError, e:
import utils, h5, h5a, h5d, h5f, h5fd, h5g, h5i, h5p, h5r, h5s, h5t, h5z, highlevel, version
from highlevel import File, Group, Dataset, Datatype, AttributeManager, is_hdf5, CoordsList
-from h5 import H5Error, get_config
+from h5 import get_config
+from h5e import H5Error
import filters, selections
diff --git a/h5py/_stub.py b/h5py/_stub.py
new file mode 100644
index 0000000..aec11cc
--- /dev/null
+++ b/h5py/_stub.py
@@ -0,0 +1,14 @@
+
+# Cython has limits on what you can declare inside control structures. This
+# native-Python module is a shim to allow things like dynamic class
+# definitions and functional closures.
+
+def generate_class(cls1, cls2):
+ """ Create a new class from two bases. The new name is the concatenation
+ of cls2.__name__ with "H5"; e.g. KeyError -> KeyErrorH5.
+ """
+ class HybridClass(cls1, cls2):
+ pass
+ HybridClass.__name__ = cls2.__name__+"H5"
+ return HybridClass
+
diff --git a/h5py/_sync.py b/h5py/_sync.py
index 4e763c7..765e690 100644
--- a/h5py/_sync.py
+++ b/h5py/_sync.py
@@ -21,6 +21,7 @@ phil = get_phil()
config = get_config()
logger = logging.getLogger('h5py.functions')
+
def uw_apply(wrap, func):
# Cython methods don't have a "module" attribute for some reason
if hasattr(func, '__module__'):
diff --git a/h5py/h5.pyx b/h5py/h5.pyx
index fe95423..d812da5 100644
--- a/h5py/h5.pyx
+++ b/h5py/h5.pyx
@@ -22,7 +22,8 @@ __doc__ = \
include "config.pxi"
-from python_exc cimport PyErr_SetString
+
+from h5e cimport register_thread
import atexit
import threading
@@ -376,145 +377,6 @@ def _open():
# === Public exception hierarchy ==============================================
-
-
-
-# === Error stack inspection ==================================================
-
-cdef class ErrorStackElement:
- """
- Represents an entry in the HDF5 error stack.
- Modeled on the H5E_error_t struct. All properties are read-only.
-
- Attributes:
-
- * maj_num: INT major error number
- * min_num: INT minor error number
- * func_name: STRING name of failing function
- * file_name: STRING name of file in which error occurreed
- * line: UINT line number at which error occured
- * desc: STRING description of error
- """
- cdef readonly int maj_num
- cdef readonly int min_num
- cdef readonly object func_name
- cdef readonly object file_name
- cdef readonly unsigned int line
- cdef readonly object desc
-
- @sync
- def __str__(self):
- return '%2d:%2d "%s" at %s (%s: %s)' % (self.maj_num, self.min_num,
- self.desc, self.func_name, H5Eget_major(<H5E_major_t>self.maj_num),
- H5Eget_minor(<H5E_minor_t>self.min_num) )
-
-cdef herr_t walk_cb(int n, H5E_error_t *err_desc, void* stack_in):
- # Callback function to extract elements from the HDF5 error stack
-
- stack = <object>stack_in
- cdef ErrorStackElement element
-
- element = ErrorStackElement()
- element.maj_num = err_desc.maj_num
- element.min_num = err_desc.min_num
- element.func_name = err_desc.func_name
- element.file_name = err_desc.file_name
- element.desc = err_desc.desc
-
- stack.append(element)
-
- return 0
-
- at sync
-def error_stack():
- """ () => LIST error_stack
-
- Retrieve the HDF5 error stack as a list of ErrorStackElement objects,
- with the most recent call (the deepest one) listed last.
- """
- stack = []
- H5Ewalk(H5E_WALK_DOWNWARD, walk_cb, <void*>stack)
- return stack
-
-cpdef object error_string():
- """ () => STRING error_stack
-
- Return a string representation of the current error condition.
- Format is one line of the format::
-
- '<Description> (<Function name>: <error type>)'
-
- If the stack is more than one level deep, this is followed by a
- header and then n lines of the format::
-
- ' n: "<Description>" at <function name>'
- """
- cdef int stacklen
- cdef ErrorStackElement el
-
- stack = error_stack()
- stacklen = len(stack)
-
- if stacklen == 0:
- msg = "No HDF5 error recorded"
- else:
- el = stack[0]
- msg = "%s (%s)" % (el.desc.capitalize(), el.func_name)
- if stacklen > 1:
- msg = msg + "\nHDF5 Error Stack:"
- for i from 0<=i<stacklen:
- #msg = msg + '\n' + str(stack[i])
- el = stack[i]
- maj_msg = H5Eget_major(<H5E_major_t>el.maj_num)
- min_msg = H5Eget_minor(<H5E_minor_t>el.min_num)
- msg = msg + '\n %d: "%s" at %s [%s :: %s]' % \
- (i, el.desc.capitalize(), el.func_name, maj_msg, min_msg)
-
- return msg
-
- at sync
-def clear():
- """ ()
-
- Clear the error stack.
- """
- H5Eclear()
-
-# === Automatic exception API =================================================
-
-cdef herr_t extract_cb(int n, H5E_error_t *err_desc, void* data_in):
- # Callback to determine error information at top/bottom of stack
- cdef H5E_error_t *err_struct
- err_struct = <H5E_error_t*>data_in
- err_struct.maj_num = err_desc.maj_num
- err_struct.min_num = err_desc.min_num
- return 1
-
-cdef herr_t err_callback(void* client_data) with gil:
- # Callback which sets Python exception based on the current error stack.
-
- # MUST be "with gil" as it can be called by nogil HDF5 routines.
- # By definition any function for which this can be called already
- # holds the PHIL.
-
- cdef H5E_error_t err_struct
- cdef H5E_major_t mj
-
- # Determine the error numbers for the first entry on the stack.
- H5Ewalk(H5E_WALK_UPWARD, extract_cb, &err_struct)
- mj = err_struct.maj_num
-
- try:
- exc = _exceptions[mj]
- except KeyError:
- exc = H5Error
-
- msg = error_string()
- PyErr_SetString(exc, msg) # Can't use "raise" or the traceback points here
-
- return 1
-
-
# === Library init ============================================================
def _exithack():
@@ -545,13 +407,6 @@ def _exithack():
hdf5_inited = 0
-cpdef int register_thread() except -1:
- """ Register the current thread for native HDF5 exception support.
- """
- if H5Eset_auto(err_callback, NULL) < 0:
- raise RuntimeError("Failed to register HDF5 exception callback")
- return 0
-
cdef int init_hdf5() except -1:
# Initialize the library and register Python callbacks for exception
# handling. Safe to call more than once.
@@ -580,6 +435,6 @@ _version_tuple = tuple([int(x) for x in H5PY_VERSION.split('.')])
-
+from h5e import H5Error
diff --git a/h5py/h5e.pxd b/h5py/h5e.pxd
index 04c10e4..2cedcdf 100644
--- a/h5py/h5e.pxd
+++ b/h5py/h5e.pxd
@@ -8,6 +8,10 @@ include "defs.pxd"
# === H5E - Error handling API ================================================
+cdef herr_t err_callback(void* client_data) with gil
+
+cpdef int register_thread() except -1
+
cdef extern from "hdf5.h":
# Major error numbers
@@ -15,7 +19,7 @@ cdef extern from "hdf5.h":
H5E_NONE_MAJOR = 0, # special zero, no error
H5E_ARGS, # invalid arguments to routine
H5E_RESOURCE, # resource unavailable
- H5E_INTERNAL, # Internal error (too specific to document)
+ H5E_INTERNAL, # Internal error (too specific to document)
H5E_FILE, # file Accessability
H5E_IO, # Low-level I/O
H5E_FUNC, # function Entry/Exit
diff --git a/h5py/h5e.pyx b/h5py/h5e.pyx
index 3ed2f07..0904418 100644
--- a/h5py/h5e.pyx
+++ b/h5py/h5e.pyx
@@ -1,11 +1,15 @@
"""
- New exceptions module!
+ Implements HDF5 error support and Python exception translation.
"""
include "config.pxi"
-include "defs.pxd"
+
+
+from python_exc cimport PyErr_SetString
+from h5 cimport SmartStruct
+import _stub
class H5Error(Exception):
""" Base class for internal HDF5 library exceptions.
@@ -142,6 +146,8 @@ class SkipListError(H5Error):
""" H5E_SLIST """
pass
+# Traditional major error classes. One of these (or H5Error) is always a
+# parent class of the raised exception.
cdef dict _major_table = {
H5E_ARGS: ArgsError,
H5E_RESOURCE: ResourceError,
@@ -170,39 +176,182 @@ cdef dict _major_table = {
H5E_ERROR: ErrorError,
H5E_SLIST: SkipListError}
+# Python-style minor error classes. If the minor error code matches an entry
+# in this dict, the generated exception will also descend from the indicated
+# built-in exception.
cdef dict _minor_table = {
- H5E_SEEKERROR: IOError, # Seek failed
- H5E_READERROR: IOError, # Read failed
- H5E_WRITEERROR: IOError, # Write failed
- H5E_CLOSEERROR: IOError, # Close failed
- H5E_OVERFLOW: IOError, # Address overflowed
- H5E_FCNTL: IOError, # File control (fcntl) failed
-
- H5E_FILEEXISTS: ValueError, # File already exists
- H5E_FILEOPEN: ValueError, # File already open
- H5E_NOTHDF5: ValueError, # Not an HDF5 file
- H5E_BADFILE: ValueError, # Bad file ID accessed
-
- H5E_BADATOM: KeyError, # Unable to find atom information (already closed?)
- H5E_BADGROUP: KeyError, # Unable to find ID group information
- H5E_BADSELECT: ValueError, # Invalid selection (hyperslabs)
+ H5E_SEEKERROR: IOError, # Seek failed
+ H5E_READERROR: IOError, # Read failed
+ H5E_WRITEERROR: IOError, # Write failed
+ H5E_CLOSEERROR: IOError, # Close failed
+ H5E_OVERFLOW: IOError, # Address overflowed
+ H5E_FCNTL: IOError, # File control (fcntl) failed
+
+ H5E_NOFILTER: IOError, # Requested filter is not available
+ H5E_CALLBACK: IOError, # Callback failed
+ H5E_CANAPPLY: IOError, # Error from filter 'can apply' callback
+ H5E_SETLOCAL: IOError, # Error from filter 'set local' callback
+ H5E_NOENCODER: IOError, # Filter present but encoding disabled
+
+ H5E_FILEEXISTS: ValueError, # File already exists
+ H5E_FILEOPEN: ValueError, # File already open
+ H5E_NOTHDF5: ValueError, # Not an HDF5 file
+ H5E_BADFILE: ValueError, # Bad file ID accessed
+
+ H5E_BADATOM: ValueError, # Unable to find atom information (already closed?)
+ H5E_BADGROUP: ValueError, # Unable to find ID group information
+ H5E_BADSELECT: ValueError, # Invalid selection (hyperslabs)
H5E_UNINITIALIZED: ValueError, # Information is uinitialized
- H5E_UNSUPPORTED: NotImplementedError, # Feature is unsupported
-
- H5E_BADTYPE: TypeError, # Inappropriate type
- H5E_BADRANGE: ValueError, # Out of range
- H5E_BADVALUE: ValueError, # Bad value
- H5E_NOTFOUND: KeyError, # Object not found
- H5E_EXISTS: ValueError, # Object already exists
- H5E_CANTCONVERT: TypeError # Can't convert datatypes
+ H5E_UNSUPPORTED: NotImplementedError, # Feature is unsupported
+
+ H5E_NOTFOUND: KeyError, # Object not found
+ H5E_CANTINSERT: TypeError, # Unable to insert object
+
+ H5E_BADTYPE: TypeError, # Inappropriate type
+ H5E_BADRANGE: ValueError, # Out of range
+ H5E_BADVALUE: ValueError, # Bad value
+
+ H5E_EXISTS: ValueError, # Object already exists
+ H5E_CANTCONVERT: TypeError # Can't convert datatypes
}
+# "Fudge" table to accomodate annoying inconsistencies in HDF5's use
+# of the minor error codes. If a (major, minor) entry appears here,
+# it will override any entry in the minor error table.
+cdef dict _exact_table = {
+ (H5E_CACHE, H5E_BADVALUE): IOError, # obj create w/o write intent 1.8
+ (H5E_RESOURCE, H5E_CANTINIT): IOError, # obj create w/o write intent 1.6
+ (H5E_INTERNAL, H5E_SYSERRSTR): IOError, # e.g. wrong file permissions
+ }
+# === Error stack inspection ==================================================
+cdef class ErrorStackElement(SmartStruct):
+ """
+ Encapsulation of the H5E_error_t structure.
+ """
+
+ cdef H5E_error_t e
+
+ property func_name:
+ """ Name of HDF5 C function in which error occurred """
+ def __get__(self):
+ return self.e.func_name
+ property desc:
+ """ Brief description of the error """
+ def __get__(self):
+ s = self.e.desc
+ return s.capitalize()
+ property code:
+ """ A 2-tuple of error codes (major, minor) """
+ def __get__(self):
+ return (<int>self.e.maj_num, <int>self.e.min_num)
+ property code_desc:
+ """ A 2-tuple of strings (major description, minor description) """
+ def __get__(self):
+ return H5Eget_major(self.e.maj_num), H5Eget_minor(self.e.min_num)
+
+def get_major(int code):
+ """ Get description for a major error code """
+ return H5Eget_major(<H5E_major_t>code)
+
+def get_minor(int code):
+ """ Get description for a minor error code """
+ return H5Eget_minor(<H5E_minor_t>code)
+
+_verbose = False
+def verbose(bint v):
+ global _verbose
+ _verbose = bool(v)
+
+class ErrorStack(list):
+
+ """
+ Represents the HDF5 error stack
+ """
+ def __init__(self, *args, **kwds):
+ list.__init__(self, *args, **kwds)
+ H5Ewalk(H5E_WALK_UPWARD, walk_cb, <void*>self)
+ def get_exc_msg(self):
+ """ Returns a 2-tuple (exception class, string message) representing
+ the current error condition, or None if no error exists.
+ """
+ global _verbose
+ if len(self) == 0:
+ return None
+
+ major, minor = self[0].code
+
+ maj_class = _major_table.get(major, H5Error)
+ min_class = _exact_table.get((major, minor), None)
+ if min_class is None:
+ min_class = _minor_table.get(minor, None)
+
+ if min_class is None:
+ exc = maj_class
+ else:
+ exc = _stub.generate_class(maj_class, min_class)
+
+ msg = "%s (%s: %s)" % (self[0].desc, self[0].code_desc[0],
+ self[0].code_desc[1])
+ if _verbose:
+ msg += '\n'+str(self)
+
+ return exc, msg
+
+ def __str__(self):
+ """ Return a string representation of the error stack """
+ if len(self) == 0:
+ return "No HDF5 error recorded"
+ s = 'HDF5 Error Stack:'
+ for idx, el in enumerate(self):
+ s += '\n %d: "%s" at %s' % (idx, el.desc, el.func_name)
+ s += '\n %s :: %s' % el.code_desc
+
+ return s
+
+cdef herr_t walk_cb(int n, H5E_error_t *err_desc, void* stack_in):
+ # Callback function to extract elements from the HDF5 error stack
+
+ stack = <object>stack_in
+
+ cdef ErrorStackElement element
+ element = ErrorStackElement()
+
+ element.e = err_desc[0]
+ stack.append(element)
+
+ return 0
+
+cdef herr_t err_callback(void* client_data) with gil:
+ # Callback which sets Python exception based on the current error stack.
+
+ # MUST be "with gil" as it can be called by nogil HDF5 routines.
+ # By definition any function for which this can be called already
+ # holds the PHIL.
+
+ stack = ErrorStack()
+
+ a = stack.get_exc_msg()
+ if a is None:
+ exc, msg = RuntimeError, "No HDF5 exception information found"
+ else:
+ exc, msg = a
+
+ PyErr_SetString(exc, msg) # Can't use "raise" or the traceback points here
+
+ return 1
+
+cpdef int register_thread() except -1:
+ """ Register the current thread for native HDF5 exception support.
+ """
+ if H5Eset_auto(err_callback, NULL) < 0:
+ raise RuntimeError("Failed to register HDF5 exception callback")
+ return 0
diff --git a/setup.py b/setup.py
index a6fcdb0..b4edf09 100644
--- a/setup.py
+++ b/setup.py
@@ -56,7 +56,7 @@ def debug(instring):
def localpath(*args):
return op.abspath(reduce(op.join, (op.dirname(__file__),)+args))
-MODULES = ['h5', 'h5f', 'h5g', 'h5s', 'h5t', 'h5d', 'h5a', 'h5p', 'h5z',
+MODULES = ['h5', 'h5e', 'h5f', 'h5g', 'h5s', 'h5t', 'h5d', 'h5a', 'h5p', 'h5z',
'h5i', 'h5r', 'h5fd', 'utils', 'h5o', 'h5l']
EXTRA_SRC = {'h5': [ localpath("lzf/lzf_filter.c"),
--
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