[h5py] 135/455: Rebuild unit tests; update h5a, h5g, new base class for struct wrappers

Ghislain Vaillant ghisvail-guest at moszumanska.debian.org
Thu Jul 2 18:19:25 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 5e6aa7ea984673de08f0330e38540471bf062159
Author: andrewcollette <andrew.collette at gmail.com>
Date:   Tue Oct 14 09:12:47 2008 +0000

    Rebuild unit tests; update h5a, h5g, new base class for struct wrappers
---
 h5py/h5.pxd                  |  3 ++
 h5py/h5.pyx                  | 37 +++++++++++++++++
 h5py/h5a.pyx                 | 29 ++++++++------
 h5py/h5g.pyx                 | 39 ++++++++----------
 h5py/h5o.pyx                 | 27 ++++++-------
 h5py/tests/__init__.py       | 50 +++++++++++++----------
 h5py/tests/common.py         | 42 ++++++++++++++------
 h5py/tests/test_h5a.py       | 95 +++++++++++++++++++++++++++++---------------
 h5py/tests/test_h5d.py       |  9 ++---
 h5py/tests/test_h5f.py       | 13 ++++--
 h5py/tests/test_h5g.py       | 41 +++++++------------
 h5py/tests/test_h5i.py       |  9 ++---
 h5py/tests/test_h5t.py       | 14 +++----
 h5py/tests/test_highlevel.py | 32 +++++++--------
 h5py/utils.pyx               | 26 +++++++-----
 setup.py                     | 34 ++++++++++------
 16 files changed, 297 insertions(+), 203 deletions(-)

diff --git a/h5py/h5.pxd b/h5py/h5.pxd
index 6bff2c8..c05246a 100644
--- a/h5py/h5.pxd
+++ b/h5py/h5.pxd
@@ -41,6 +41,9 @@ cdef class ObjectID:
     cdef readonly int _locked
     cdef object _hash
 
+cdef class SmartStruct:
+    cdef object __weakref__
+
 # Library init.  Safe to call more than once.
 cdef int init_hdf5() except -1
 
diff --git a/h5py/h5.pyx b/h5py/h5.pyx
index b521785..4b5801c 100644
--- a/h5py/h5.pyx
+++ b/h5py/h5.pyx
@@ -37,6 +37,7 @@ from python_exc cimport PyErr_SetString
 
 import atexit
 import threading
+import inspect
 
 IF H5PY_18API:
     ITER_INC    = H5_ITER_INC     # Increasing order
@@ -46,6 +47,42 @@ IF H5PY_18API:
     INDEX_NAME      = H5_INDEX_NAME       # Index on names      
     INDEX_CRT_ORDER = H5_INDEX_CRT_ORDER  # Index on creation order    
 
+cdef class SmartStruct:
+
+    """ Provides basic mechanics for structs """
+    
+    def _hash(self):
+        raise TypeError("%s instances are unhashable" % self.__class__.__name__)
+
+    def __hash__(self):
+        # This is forwarded so that I don't have to reimplement __richcmp__ everywhere
+        return self._hash()
+
+    def __richcmp__(self, object other, int how):
+        """Equality based on hash"""
+        cdef bint truthval = 0
+
+        if how != 2 and how != 3:
+            return NotImplemented
+
+        if isinstance(other, type(self)):
+            try:
+                truthval = hash(self) == hash(other)
+            except TypeError:
+                pass
+
+        if how == 2:
+            return truthval
+        return not truthval
+
+    def __repr__(self):
+        """ Prints a header followed by a list of public property values """
+        ostr = "=== %s ===\n%s"
+        attrnames = [x[0] for x in inspect.getmembers(self) if not x[0].startswith('_')]
+        attrstring = "\n".join(["%s: %s" % (x, getattr(self, x)) for x in attrnames])
+        ostr %= (self.__class__.__name__, attrstring)
+        return ostr
+
 cdef class H5PYConfig:
 
     """
diff --git a/h5py/h5a.pyx b/h5py/h5a.pyx
index a578787..3fcbd4b 100644
--- a/h5py/h5a.pyx
+++ b/h5py/h5a.pyx
@@ -18,7 +18,7 @@ include "config.pxi"
 include "sync.pxi"
 
 # Compile-time imports
-from h5 cimport init_hdf5
+from h5 cimport init_hdf5, SmartStruct
 from h5t cimport TypeID, typewrap, py_create
 from h5s cimport SpaceID
 from h5p cimport PropID, pdefault
@@ -43,7 +43,7 @@ IF H5PY_18API:
         Create a new attribute, attached to an existing object.
 
         Keywords:
-        * STRING obj_name (".")     Attach attribute to this group member
+        * STRING obj_name (".")     Attach attribute to this group member instead
         * PropID lapl (None)        Determines how obj_name is interpreted
         """
 
@@ -67,8 +67,8 @@ ELSE:
 IF H5PY_18API:
     @sync
     def open(ObjectID loc not None, char* name=NULL, int index=-1, *,
-            char* obj_name='.', int index_type=H5_INDEX_NAME, int order=H5_ITER_NATIVE,
-            PropID lapl=None):
+        char* obj_name='.', int index_type=H5_INDEX_NAME, int order=H5_ITER_NATIVE,
+        PropID lapl=None):
         """(ObjectID loc, STRING name=, INT index=, **kwds) => AttrID
        
         Open an attribute attached to an existing object.  You must specify
@@ -203,14 +203,14 @@ def iterate(ObjectID loc not None, object func, int index=0):
     attributes attached to this object.  You callable should have the
     signature:
 
-        func(STRING name, *args) => Result
+        func(STRING name) => Result
 
     Returning None continues iteration; returning anything else aborts
     iteration and returns that value.
 
-    The parameter *args will make your code forward-compatible with the
-    1.8.X version of this function, which supplies additional arguments
-    to the callback.
+    Tip: To make your code forward-compatible with later versions of this
+    function (which supply more information to the callback), add an
+    additional *args parameter.
     """
     if index < 0:
         raise ValueError("Starting index must be a non-negative integer.")
@@ -237,7 +237,7 @@ def py_listattrs(ObjectID loc not None):
 
 
 IF H5PY_18API:
-    cdef class AttrInfo:
+    cdef class AttrInfo(SmartStruct):
 
         cdef H5A_info_t info
 
@@ -258,6 +258,9 @@ IF H5PY_18API:
             def __get__(self):
                 return self.info.data_size
 
+        def _hash(self):
+            return hash((self.corder_valid, self.corder, self.cset, self.data_size))
+
     @sync
     def get_info(ObjectID loc not None, char* name=NULL, int index=-1, *,
                 char* obj_name='.', PropID lapl=None,
@@ -350,8 +353,8 @@ cdef class AttrID(ObjectID):
         Numpy array must have the same shape as the HDF5 attribute, and a 
         conversion-compatible datatype.
 
-        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.
+        The Numpy array must be writable and C-contiguous.  If this is not
+        the case, the read will fail with an exception.
         """
         cdef TypeID mtype
         cdef hid_t space_id
@@ -377,8 +380,8 @@ cdef class AttrID(ObjectID):
         the Numpy array must have the same shape as the HDF5 attribute, and
         a conversion-compatible datatype.  
 
-        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.
+        The Numpy array must be C-contiguous.  If this is not the case, 
+        the write will fail with an exception.
         """
         cdef TypeID mtype
         cdef hid_t space_id
diff --git a/h5py/h5g.pyx b/h5py/h5g.pyx
index 4535417..a4df95a 100644
--- a/h5py/h5g.pyx
+++ b/h5py/h5g.pyx
@@ -18,7 +18,7 @@ include "config.pxi"
 include "sync.pxi"
 
 # Compile-time imports
-from h5 cimport init_hdf5
+from h5 cimport init_hdf5, SmartStruct
 from utils cimport emalloc, efree
 from h5p cimport PropID, pdefault
 IF H5PY_18API:
@@ -45,21 +45,23 @@ LINK_ERROR = H5G_LINK_ERROR
 LINK_HARD  = H5G_LINK_HARD
 LINK_SOFT  = H5G_LINK_SOFT
 
-cdef class GroupStat:
-    """ Represents the H5G_stat_t structure containing group member info.
+cdef class GroupStat(SmartStruct):
+    """Represents the H5G_stat_t structure containing group member info.
 
-        Fields (read-only):
-        fileno  ->  2-tuple uniquely* identifying the current file
-        objno   ->  2-tuple uniquely* identifying this object
-        nlink   ->  Number of hard links to this object
-        mtime   ->  Modification time of this object
-        linklen ->  Length of the symbolic link name, or 0 if not a link.
+    Fields (read-only):
+    fileno  ->  2-tuple uniquely* identifying the current file
+    objno   ->  2-tuple uniquely* identifying this object
+    nlink   ->  Number of hard links to this object
+    mtime   ->  Modification time of this object
+    linklen ->  Length of the symbolic link name, or 0 if not a link.
 
-        *"Uniquely identifying" means unique among currently open files, 
-        not universally unique.
+    *"Uniquely identifying" means unique among currently open files, 
+    not universally unique.
+
+    Hashable: Yes
+    Equality: Yes
     """
     cdef H5G_stat_t infostruct
-    cdef object __weakref__
 
     property fileno:
         def __get__(self):
@@ -80,16 +82,9 @@ cdef class GroupStat:
         def __get__(self):
             return self.infostruct.linklen
 
-    def __str__(self):
-        return \
-"""
-fileno %s
-objno %s
-nlink %d
-typecode %d
-mtime %d
-linklen %d
-""" % (self.fileno, self.objno, self.nlink, self.type, self.mtime, self.linklen)
+    def _hash(self):
+        return hash((self.fileno, self.objno, self.nlink, self.type, self.mtime, self.linklen))
+
 
 cdef class GroupIter:
 
diff --git a/h5py/h5o.pyx b/h5py/h5o.pyx
index 2c6c1b9..00096c7 100644
--- a/h5py/h5o.pyx
+++ b/h5py/h5o.pyx
@@ -50,8 +50,7 @@ cdef class ObjInfo:
 
 @sync
 def get_info(ObjectID obj not None):
-    """ (ObjectID obj) => ObjInfo
-    """
+    """(ObjectID obj) => ObjInfo"""
 
     cdef ObjInfo info
     info = ObjInfo()
@@ -90,23 +89,23 @@ cdef herr_t cb_obj_iterate(hid_t obj, char* name, H5O_info_t *info, void* data)
 def visit(ObjectID loc not None, object func, *,
           int idx_type=H5_INDEX_NAME, int order=H5_ITER_NATIVE,
           char* name=".", PropID lapl=None):
-    """ (ObjectID loc, CALLABLE func, **kwds) => <Return value from func>
+    """(ObjectID loc, CALLABLE func, **kwds) => <Return value from func>
 
-        Iterate a function or callable object over all objects below the
-        specified one.  Your callable should conform to the signature:
+    Iterate a function or callable object over all objects below the
+    specified one.  Your callable should conform to the signature:
 
-            func(STRING name, ObjInfo info) => Result
+        func(STRING name, ObjInfo info) => Result
 
-        Returning None or a logical False continues iteration; returning
-        anything else aborts iteration and returns that value.
+    Returning None or a logical False continues iteration; returning
+    anything else aborts iteration and returns that value.
 
-        Keyword-only arguments:
-        * STRING name ("."):            Visit a subgroup of "loc" instead
-        * PropLAID lapl (None):          Control how "name" is interpreted
-        * INT idx_type (h5.INDEX_NAME):  What indexing strategy to use
-        * INT order (h5.ITER_NATIVE):    Order in which iteration occurs
+    Keyword-only arguments:
+    * STRING name ("."):            Visit a subgroup of "loc" instead
+    * PropLAID lapl (None):          Control how "name" is interpreted
+    * INT idx_type (h5.INDEX_NAME):  What indexing strategy to use
+    * INT order (h5.ITER_NATIVE):    Order in which iteration occurs
     """
-    cdef _ObjectVisitor visit = _ObjectVisitor()
+    cdef _ObjectVisitor visit = _ObjectVisitor(func)
 
     H5Ovisit_by_name(loc.id, name, <H5_index_t>idx_type,
         <H5_iter_order_t>order, cb_obj_iterate, <void*>visit, pdefault(lapl))
diff --git a/h5py/tests/__init__.py b/h5py/tests/__init__.py
index 62a7746..712ca7d 100644
--- a/h5py/tests/__init__.py
+++ b/h5py/tests/__init__.py
@@ -12,11 +12,13 @@
 
 import unittest
 import sys
-import test_h5a, test_h5d, test_h5f, \
-       test_h5g, test_h5i, test_h5p, \
-       test_h5s, test_h5t, test_h5, \
-       test_h5r, \
-       test_highlevel, test_threads
+
+from common import HDF5TestCase
+import  test_h5a, test_h5d, test_h5f,\
+        test_h5g, test_h5i, test_h5p,\
+        test_h5s, test_h5t, test_h5,\
+        test_h5r,\
+        test_highlevel, test_threads, test_utils
 
 from h5py import *
 
@@ -31,36 +33,42 @@ sections = {'h5a': test_h5a.TestH5A, 'h5d': test_h5d.TestH5D,
             'File': test_highlevel.TestFile,
             'Group': test_highlevel.TestGroup,
             'Dataset': test_highlevel.TestDataset,
-            'threads': test_threads.TestThreads }
+            'threads': test_threads.TestThreads,
+            'utils': test_utils.TestUtils }
 
-order = ('h5a', 'h5d', 'h5f', 'h5g', 'h5i', 'h5r', 'h5p', 'h5p.fcid', 'h5p.faid',
-         'h5p.dcid', 'h5p.dxid', 'h5s', 'h5', 'File', 'Group', 'Dataset',
-         'threads')
+def runtests(requests=None, verbosity=1):
+    """Run unit tests
 
-def buildsuite(cases):
-    """ cases should be an iterable of TestCase subclasses """
-    loader = unittest.TestLoader()
-    suite = unittest.TestSuite()
-    for test_case in cases:
-        suite.addTests(loader.loadTestsFromTestCase(test_case))
-    return suite
+    Requests: iterable of test section names to run. Prefix with '-'
+    to explicitly disable.  Example:
+        ('h5a', 'h5g', 'File'), or ('-h5t', '-h5g')
 
-def runtests(requests=None):
+    Verbosity: TextTestRunner verbosity level.  Level 4 prints additional
+    h5py-specific information.
+    """
     if requests is None:
         requests = ()
     excluded = [x[1:] for x in requests if len(x) >=2 and x.find('-') == 0]
     included = [x for x in requests if x.find('-') != 0]
 
-    cases = order if len(included) is 0 else included
+    cases = tuple(sections) if len(included) is 0 else included
     cases = [x for x in cases if x not in excluded]
     try:
         cases = [sections[x] for x in cases]
     except KeyError, e:
         raise RuntimeError('Test "%s" is unknown' % e.args[0])
 
-    suite = buildsuite(cases)
-    retval = unittest.TextTestRunner(verbosity=3).run(suite)
-    print "=== Tested HDF5 %s (%s API) ===" % (h5.hdf5_version, h5.api_version)
+    HDF5TestCase.h5py_verbosity = verbosity
+    
+    loader = unittest.TestLoader()
+    suite = unittest.TestSuite()
+    for case in sorted(cases):
+        suite.addTests(loader.loadTestsFromTestCase(case))
+
+    retval = unittest.TextTestRunner(verbosity=verbosity).run(suite)
+
+    if verbosity >= 1:
+        print "=== Tested HDF5 %s (%s API) ===" % (h5.hdf5_version, h5.api_version)
     return retval.wasSuccessful()
 
 def autotest():
diff --git a/h5py/tests/common.py b/h5py/tests/common.py
index 020ce9f..c8281ae 100644
--- a/h5py/tests/common.py
+++ b/h5py/tests/common.py
@@ -10,20 +10,27 @@
 # 
 #-
 
+import os
 import unittest
 import tempfile
-import os
-from os.path import join, dirname
+import os.path as op
 import shutil
-from h5py import h5f, h5p
+from h5py import h5f, h5p, h5
 import h5py
 
-DATADIR = join(dirname(h5py.__file__), 'tests/data')
+DATADIR = op.join(op.dirname(h5py.__file__), 'tests/data')
 
 def getfullpath(name):
-    return join(DATADIR, name)
+    return op.abspath(op.join(DATADIR, name))
+
+def api_18(func):
+    """Decorator to enable 1.8.X-only API functions"""
+    if h5.get_config().API_18:
+        return func
+    return None
+
 
-class TestBase(unittest.TestCase):
+class HDF5TestCase(unittest.TestCase):
 
     """
         Base test for unit test classes which deal with a particular
@@ -32,20 +39,31 @@ class TestBase(unittest.TestCase):
         TestBase class will figure out the correct directory.
     """
 
-    def __init__(self, *args, **kwds):
-        unittest.TestCase.__init__(self, *args, **kwds)
-        self.HDFNAME = getfullpath(self.HDFNAME) # resolve absolute location
+    h5py_verbosity = 0
 
-    def setUp(self):
+    def output(self, ipt):
+        """Print to stdout, only if verbosity levels so requires"""
+        if self.h5py_verbosity >= 3:
+            print ipt
+
+    def setup_fid(self, hdfname):
+        """Open a copy of an HDF5 file and set its identifier as self.fid"""
+        hdfname = getfullpath(hdfname)
         newname = tempfile.mktemp('.hdf5')
-        shutil.copy(self.HDFNAME, newname)
+        shutil.copy(hdfname, newname)
 
         plist = h5p.create(h5p.FILE_ACCESS)
         plist.set_fclose_degree(h5f.CLOSE_STRONG)
         self.fid = h5f.open(newname, h5f.ACC_RDWR, fapl=plist)
         self.fname = newname
+        self.src_fname = hdfname
 
-    def tearDown(self):
+    def teardown_fid(self):
+        """Close the HDF5 file copy and delete it"""
         self.fid.close()
         os.unlink(self.fname)
 
+
+
+    
+
diff --git a/h5py/tests/test_h5a.py b/h5py/tests/test_h5a.py
index 9ea330c..b69afea 100644
--- a/h5py/tests/test_h5a.py
+++ b/h5py/tests/test_h5a.py
@@ -12,7 +12,7 @@
 
 from numpy import array, ndarray, dtype, all, ones
 
-from common import TestBase
+from common import HDF5TestCase, api_18
 
 from h5py import *
 from h5py.h5 import H5Error
@@ -28,17 +28,16 @@ ATTRIBUTES = {  'String Attribute': ("This is a string.", dtype('S18'), ()),
 ATTRIBUTES_ORDER = ['String Attribute', 'Integer', 'Integer Array', 'Byte']
 NEW_ATTRIBUTES = {'New float': ( 3.14, dtype('<f4'), ()) }
 
-class TestH5A(TestBase):
 
-    HDFNAME = HDFNAME
+class TestH5A(HDF5TestCase):
 
     def setUp(self):
-        TestBase.setUp(self)
+        self.setup_fid(HDFNAME)
         self.obj = h5g.open(self.fid, OBJECTNAME)
 
     def tearDown(self):
         self.obj._close()
-        TestBase.tearDown(self)
+        self.teardown_fid()
 
     def is_attr(self, attr):
         return (h5i.get_type(attr) == h5i.ATTR)
@@ -67,18 +66,56 @@ class TestH5A(TestBase):
             attr.read(arr_val)
             self.assert_(all(arr_val == arr_ref))
 
+    @api_18
+    def test_create_18(self):
+
+        space = h5s.create(h5s.SCALAR)
+        htype = h5t.py_create('=f4')
+
+        attr = h5a.create(self.fid, "New Attribute", htype, space, obj_name="Group")
+        self.assert_(h5a.exists(self.fid, "New Attribute", obj_name="Group"))
+
+
     def test_open_idx(self):
         for idx, name in enumerate(ATTRIBUTES_ORDER):
-            attr = h5a.open(self.obj, idx=idx)
+            attr = h5a.open(self.obj, index=idx)
             self.assert_(self.is_attr(attr), "Open: index %d" % idx)
 
-    def test_open(self):
+    def test_open_name(self):
         for name in ATTRIBUTES:
             attr = h5a.open(self.obj, name)
             self.assert_(self.is_attr(attr), 'Open: name "%s"' % name)
 
+    @api_18
+    def test_open_name_18(self):
+        for name in ATTRIBUTES:
+            attr = h5a.open(self.fid, name, obj_name=OBJECTNAME)
+            self.assert_(self.is_attr(attr))
+
+    @api_18
+    def test_rename_18(self):
+        h5a.rename(self.obj, ATTRIBUTES_ORDER[0], "NewName1")
+        self.assert_(h5a.exists(self.obj, "NewName1"))
+        self.assert_(not h5a.exists(self.obj, ATTRIBUTES_ORDER[0]))
+    
+        h5a.rename(self.fid, ATTRIBUTES_ORDER[1], "NewName2", obj_name=OBJECTNAME)
+        self.assert_(h5a.exists(self.obj, "NewName2"))
+        self.assert_(not h5a.exists(self.obj, ATTRIBUTES_ORDER[1]))
+           
+    @api_18
+    def test_get_info_18(self):
+        info = h5a.get_info(self.obj, ATTRIBUTES_ORDER[0])
+        info.corder_valid
+        info.corder
+        info.cset
+        info.data_size
+
+        h5a.get_info(self.fid, ATTRIBUTES_ORDER[0], obj_name=OBJECTNAME)
+        h5a.get_info(self.obj, index=1)
+        h5a.get_info(self.fid, index=1, obj_name=OBJECTNAME)
+
     def test_close(self):
-        attr = h5a.open(self.obj, idx=0)
+        attr = h5a.open(self.obj, index=0)
         self.assert_(self.is_attr(attr))
         attr._close()
         self.assert_(not self.is_attr(attr))
@@ -141,34 +178,23 @@ class TestH5A(TestBase):
 
     def test_iterate(self):
 
-        def iterate_all(id, name, namelist):
-            namelist.append(name)
-
-        def iterate_two(id, name, namelist):
-            if len(namelist) == 2:
-                raise StopIteration
-            namelist.append(name)
-
-        def iterate_fault(id, name, namelist):
-            if len(namelist) == 2:
-                raise RuntimeError("Intentional fault")
-            namelist.append(name)
-
         namelist = []
-        h5a.iterate(self.obj, iterate_all, namelist)
+        result = h5a.iterate(self.obj, namelist.append)
         self.assertEqual(namelist, ATTRIBUTES_ORDER)
+        self.assert_(result is None)
 
         namelist = []
-        h5a.iterate(self.obj, iterate_two, namelist)
+        def iterate_two(name):
+            if len(namelist) >= 2:
+                return True
+            namelist.append(name)
+        result = h5a.iterate(self.obj, iterate_two)
         self.assertEqual(namelist, ATTRIBUTES_ORDER[0:2])
+        self.assert_(result is True)
 
-        namelist = []
-        self.assertRaises(RuntimeError, h5a.iterate, self.obj, iterate_fault, namelist)
-        self.assertEqual(namelist, ATTRIBUTES_ORDER[0:2])
-        
-        namelist = []
-        h5a.iterate(self.obj, iterate_two, namelist, 1)
-        self.assertEqual(namelist, ATTRIBUTES_ORDER[1:3])
+        def iter_fault(name):
+            raise RuntimeError
+        self.assertRaises(RuntimeError, h5a.iterate, self.obj, iter_fault)
 
     def test_prop_name(self):
         
@@ -194,11 +220,14 @@ class TestH5A(TestBase):
 
         self.assertEqual(attrlist, ATTRIBUTES_ORDER)
 
-    def test_py_exists(self):
+    def test_exists(self):
 
-        self.assert_(h5a.py_exists(self.obj, ATTRIBUTES_ORDER[0]))
-        self.assert_(not h5a.py_exists(self.obj, "Something else"))
+        self.assert_(h5a.exists(self.obj, ATTRIBUTES_ORDER[0]))
+        self.assert_(not h5a.exists(self.obj, "Something else"))
 
+    @api_18
+    def test_exists_18(self):
+        self.assert_(h5a.exists(self.fid, ATTRIBUTES_ORDER[0], obj_name=OBJECTNAME))
 
 
 
diff --git a/h5py/tests/test_h5d.py b/h5py/tests/test_h5d.py
index 86fcf06..5a5b7ab 100644
--- a/h5py/tests/test_h5d.py
+++ b/h5py/tests/test_h5d.py
@@ -11,7 +11,7 @@
 #-
 
 import numpy
-from common import TestBase
+from common import HDF5TestCase
 
 from h5py import *
 from h5py.h5 import H5Error
@@ -34,17 +34,16 @@ for i in range(SHAPE[0]):
     basearray[i]["f_name"][:] = numpy.array((1024.9637*i,)*10)
     basearray[i]["g_name"] = 109
 
-class TestH5D(TestBase):
+class TestH5D(HDF5TestCase):
 
-    HDFNAME = HDFNAME
 
     def setUp(self):
-        TestBase.setUp(self)
+        self.setup_fid(HDFNAME)
         self.dset = h5d.open(self.fid, "CompoundChunked")
 
     def tearDown(self):
         self.dset._close()
-        TestBase.tearDown(self)
+        self.teardown_fid()
 
     def test_open_close(self):
         dset = h5d.open(self.fid, "CompoundChunked")
diff --git a/h5py/tests/test_h5f.py b/h5py/tests/test_h5f.py
index 800c7a8..0f58aab 100644
--- a/h5py/tests/test_h5f.py
+++ b/h5py/tests/test_h5f.py
@@ -13,19 +13,24 @@
 import numpy
 import os
 import tempfile
-from common import TestBase
+from common import getfullpath, HDF5TestCase
 
 from h5py import *
 from h5py.h5 import H5Error
 
 HDFNAME = 'attributes.hdf5'
 
-class TestH5F(TestBase):
+class TestH5F(HDF5TestCase):
 
-    HDFNAME = HDFNAME
+
+    def setUp(self):
+        self.setup_fid(HDFNAME)
+
+    def tearDown(self):
+        self.teardown_fid()
 
     def test_open_close(self):
-        fid = h5f.open(self.HDFNAME, h5f.ACC_RDONLY)
+        fid = h5f.open(getfullpath(HDFNAME), h5f.ACC_RDONLY)
         self.assertEqual(h5i.get_type(fid), h5i.FILE)
         fid.close()
         self.assertEqual(h5i.get_type(fid), h5i.BADID)
diff --git a/h5py/tests/test_h5g.py b/h5py/tests/test_h5g.py
index 77ceea5..95858c0 100644
--- a/h5py/tests/test_h5g.py
+++ b/h5py/tests/test_h5g.py
@@ -10,7 +10,7 @@
 # 
 #-
 
-from common import TestBase
+from common import HDF5TestCase
 
 from h5py import *
 from h5py.h5 import H5Error
@@ -20,17 +20,16 @@ OBJECTNAME = 'Group'
 TEST_GROUPS = ['Subgroup1','Subgroup2','Subgroup3']
 NEW_LINK_NAME = 'Link name'
 
-class TestH5G(TestBase):
+class TestH5G(HDF5TestCase):
 
-    HDFNAME = HDFNAME
 
     def setUp(self):
-        TestBase.setUp(self)
+        self.setup_fid(HDFNAME)
         self.obj = h5g.open(self.fid, OBJECTNAME)
 
     def tearDown(self):
         self.obj._close()
-        TestBase.tearDown(self)
+        self.teardown_fid()
 
     def is_grp(self, item):
         return h5i.get_type(item) == h5i.GROUP
@@ -112,34 +111,22 @@ class TestH5G(TestBase):
 
     def test_iterate(self):
 
-        def iterate_all(id, name, namelist):
-            namelist.append(name)
-
-        def iterate_two(id, name, namelist):
-            if len(namelist) == 2:
-                raise StopIteration
-            namelist.append(name)
-
-        def iterate_fault(id, name, namelist):
-            if len(namelist) == 2:
-                raise RuntimeError("Intentional fault")
-            namelist.append(name)
-
         namelist = []
-        h5g.iterate(self.obj, '.', iterate_all, namelist)
+        h5g.iterate(self.obj, namelist.append)
         self.assertEqual(namelist, TEST_GROUPS)
 
         namelist = []
-        h5g.iterate(self.obj, '.', iterate_two, namelist)
+        def iterate_two(name):
+            if len(namelist) == 2:
+                return True
+            namelist.append(name)
+        result = h5g.iterate(self.obj, iterate_two)
         self.assertEqual(namelist, TEST_GROUPS[0:2])
+        self.assert_(result is True)
 
-        namelist = []
-        self.assertRaises(RuntimeError, h5g.iterate, self.obj, '.', iterate_fault, namelist)
-        self.assertEqual(namelist, TEST_GROUPS[0:2])
-        
-        namelist = []
-        h5g.iterate(self.obj, '.', iterate_two, namelist, 1)
-        self.assertEqual(namelist, TEST_GROUPS[1:3])
+        def iter_fault(name):
+            raise RuntimeError
+        self.assertRaises(RuntimeError, h5g.iterate, self.obj, iter_fault)
 
     def test_get_set_comment(self):
 
diff --git a/h5py/tests/test_h5i.py b/h5py/tests/test_h5i.py
index 418aebb..a1cdb27 100644
--- a/h5py/tests/test_h5i.py
+++ b/h5py/tests/test_h5i.py
@@ -10,7 +10,7 @@
 # 
 #-
 
-from common import TestBase
+from common import HDF5TestCase
 
 from h5py import *
 from h5py.h5 import H5Error
@@ -18,17 +18,16 @@ from h5py.h5 import H5Error
 HDFNAME = 'attributes.hdf5'
 OBJECTNAME = 'Group'
 
-class TestH5I(TestBase):
+class TestH5I(HDF5TestCase):
 
-    HDFNAME = HDFNAME
 
     def setUp(self):
-        TestBase.setUp(self)
+        self.setup_fid(HDFNAME)
         self.obj = h5g.open(self.fid, OBJECTNAME)
 
     def tearDown(self):
         self.obj._close()
-        TestBase.tearDown(self)
+        self.teardown_fid()
 
     def test_get_type(self):
         self.assertEqual(h5i.get_type(self.fid), h5i.FILE)
diff --git a/h5py/tests/test_h5t.py b/h5py/tests/test_h5t.py
index 29c82e1..adbbad5 100644
--- a/h5py/tests/test_h5t.py
+++ b/h5py/tests/test_h5t.py
@@ -32,9 +32,6 @@ simple_types = \
 
 class TestH5T(unittest.TestCase):
 
-    def tearDown(self):
-        h5t.py_complex_names(reset=True)
-
     def test_create(self):
         types = {h5t.COMPOUND: h5t.TypeCompoundID, h5t.OPAQUE: h5t.TypeOpaqueID}
         sizes = (1,4,256)
@@ -77,7 +74,7 @@ class TestH5T(unittest.TestCase):
             htype2 = htype.copy()
             self.assertEqual(htype.dtype, htype2.dtype)
             self.assert_(htype is not htype2)
-            self.assert_(htype != htype2)
+            self.assert_(htype == htype2)
 
     def test_equal(self):
 
@@ -215,7 +212,7 @@ class TestH5T(unittest.TestCase):
         enum_bases = [ x for x in simple_types if 'i' in x or 'u' in x]
         for x in enum_bases:
             dt = dtype(x)
-            htype = h5t.py_create(dt, enum=enum)
+            htype = h5t.py_create(dt, enum_vals=enum)
             self.assertEqual(type(htype), h5t.TypeEnumID)
             self.assertEqual(dt, htype.dtype)
             for name, val in enum.iteritems():
@@ -253,10 +250,12 @@ class TestH5T(unittest.TestCase):
                  (' Re!#@$%\t\tREALr\neal ^;;;"<>? ', ' \t*&^  . ^@IMGI        MG!~\t\n\r') ]
 
         complex_types = [x for x in simple_types if 'c' in x]
+        config = h5.get_config()
 
+        oldnames = config.complex_names
         try:
             for name in names:
-                h5t.py_complex_names(name[0], name[1])
+                config.complex_names = name
                 for ctype in complex_types:
                     dt = dtype(ctype)
                     htype = h5t.py_create(dt)
@@ -265,8 +264,7 @@ class TestH5T(unittest.TestCase):
                     self.assertEqual(htype.get_member_name(0), name[0])
                     self.assertEqual(htype.get_member_name(1), name[1])
         finally:
-            h5t.py_complex_names(reset=True)
-
+            config.complex_names = oldnames
 
 
 
diff --git a/h5py/tests/test_highlevel.py b/h5py/tests/test_highlevel.py
index d856740..41dd640 100644
--- a/h5py/tests/test_highlevel.py
+++ b/h5py/tests/test_highlevel.py
@@ -20,7 +20,7 @@ import numpy
 from h5py.highlevel import *
 from h5py import *
 from h5py.h5 import H5Error
-from common import getfullpath
+from common import getfullpath, HDF5TestCase
 
 class SliceFreezer(object):
     def __getitem__(self, args):
@@ -42,7 +42,7 @@ TYPES = TYPES1 + TYPES2
 SHAPES = [(), (1,), (10,5), (1,10), (10,1), (100,1,100), (51,2,1025)]
 
  
-class TestFile(unittest.TestCase):
+class TestFile(HDF5TestCase):
 
     def setUp(self):
         newname = tempfile.mktemp('.hdf5')
@@ -152,7 +152,7 @@ class TestFile(unittest.TestCase):
             grp.id._close()
             str(grp.attrs)
 
-class TestDataset(unittest.TestCase):
+class TestDataset(HDF5TestCase):
 
     def setUp(self):
 
@@ -165,7 +165,7 @@ class TestDataset(unittest.TestCase):
 
     def test_Dataset_create(self):
         
-        print ''
+        self.output('')
 
         shapes = [(), (1,), (10,5), (1,10), (10,1), (100,1,100), (51,2,1025)]
         chunks = [None, (1,), (10,1), (1,1),  (1,1),  (50,1,100), (51,2,25)]
@@ -176,7 +176,7 @@ class TestDataset(unittest.TestCase):
 
         for shape, chunk in zip(shapes, chunks):
             for dt in TYPES:
-                print "    Creating %.20s %.40s" % (shape, dt)
+                self.output("    Creating %.20s %.40s" % (shape, dt))
                 dt = numpy.dtype(dt)
                 d = Dataset(self.f, "NewDataset", dtype=dt, shape=shape)
                 self.assertEqual(d.shape, shape)
@@ -184,7 +184,7 @@ class TestDataset(unittest.TestCase):
                 del self.f["NewDataset"]
 
                 if shape != ():
-                    print "        With chunk %s" % (chunk,)
+                    self.output("        With chunk %s" % (chunk,))
                     d = Dataset(self.f, "NewDataset", dtype=dt, shape=shape,
                                 chunks=chunk, shuffle=True, compression=6,
                                 fletcher32=True)
@@ -202,7 +202,7 @@ class TestDataset(unittest.TestCase):
 
     def test_Dataset_extend(self):
 
-        print ""
+        self.output("")
 
         init_shapes = [(100,), (100,100), (150,100)]
         max_shapes = [(200,), (200,200), (None, 100)]
@@ -224,7 +224,7 @@ class TestDataset(unittest.TestCase):
             self.assertEqual(ds.shape, shape)
 
             for final_shape in final_shapes[shape]:
-                print "    Extending %s to %s" % (shape, final_shape)
+                self.output("    Extending %s to %s" % (shape, final_shape))
                 newarr = numpy.arange(numpy.product(final_shape)).reshape(final_shape)
                 ds.extend(final_shape)
                 ds[...] = newarr
@@ -252,7 +252,7 @@ class TestDataset(unittest.TestCase):
         self.assertRaises(TypeError, list, d2)
 
     def test_Dataset_bigslice(self):
-        print ""
+        self.output("")
 
         s = SliceFreezer()
 
@@ -268,7 +268,7 @@ class TestDataset(unittest.TestCase):
             dset = self.f.create_dataset("dset", (2**62, 2**62), '=f4', maxshape=(None,None))
 
             for shp, slc in zip(shapes, slices):
-                print "    Testing base 2**%d" % numpy.log2(base)
+                self.output("    Testing base 2**%d" % numpy.log2(base))
 
                 empty = numpy.zeros(shp)
                 data = numpy.arange(numpy.product(shp), dtype='=f4').reshape(shp)
@@ -284,7 +284,7 @@ class TestDataset(unittest.TestCase):
         
     def test_Dataset_slicing(self):
 
-        print ''
+        self.output('')
 
         s = SliceFreezer()
         slices = [s[0,0,0], s[0,0,:], s[0,:,0], s[0,:,:]]
@@ -310,7 +310,7 @@ class TestDataset(unittest.TestCase):
                 self.assertEqual(d.dtype, srcarr.dtype)
                 for argtpl in slices:
                     # Test read
-                    print "    Checking read %.20s %s" % (dt, argtpl if not isinstance(argtpl, numpy.ndarray) else 'ARRAY')
+                    self.output("    Checking read %.20s %s" % (dt, argtpl if not isinstance(argtpl, numpy.ndarray) else 'ARRAY'))
                     hresult = d[argtpl]
                     nresult = srcarr[argtpl]
                     if isinstance(nresult, numpy.ndarray):
@@ -324,7 +324,7 @@ class TestDataset(unittest.TestCase):
                 d = Dataset(f, "NewDataset", data=srcarr)
                 for argtpl in slices:
                     # Test assignment
-                    print "    Checking write %.20s %s" % (dt, argtpl if not isinstance(argtpl, numpy.ndarray) else 'ARRAY')
+                    self.output("    Checking write %.20s %s" % (dt, argtpl if not isinstance(argtpl, numpy.ndarray) else 'ARRAY'))
                     srcarr[argtpl] = numpy.cos(srcarr[argtpl])
                     d[argtpl] = srcarr[argtpl]
                     self.assert_(numpy.all(d.value == srcarr))
@@ -375,7 +375,7 @@ class TestDataset(unittest.TestCase):
         self.assertRaises(H5Error, dsid.id.read, h5s.ALL, h5s.ALL, arr)
         # or it'll segfault...
 
-class TestGroup(unittest.TestCase):
+class TestGroup(HDF5TestCase):
 
     def setUp(self):
 
@@ -446,11 +446,11 @@ class TestGroup(unittest.TestCase):
     def test_Group_setgetitem(self):
         # Also tests named types
 
-        print ''
+        self.output('')
         for shape in SHAPES:
             for dt in TYPES1:
 
-                print "    Assigning %s %s" % (dt, shape)
+                self.output("    Assigning %s %s" % (dt, shape))
 
                 # test arbitrary datasets
                 dt_obj = numpy.dtype(dt)       
diff --git a/h5py/utils.pyx b/h5py/utils.pyx
index 515dd08..112b4e3 100644
--- a/h5py/utils.pyx
+++ b/h5py/utils.pyx
@@ -40,16 +40,13 @@ cdef void* emalloc(size_t size) except? NULL:
 
     cdef void *retval = NULL
 
-    if size < 0:
-        PyErr_SetString(RuntimeError, "Attempted negative malloc")
+    if size == 0:
         return NULL
-    elif size > 0:
-        retval = malloc(size)
-        if retval == NULL:
-            errmsg = "Can't malloc %d bytes" % size
-            PyErr_SetString(MemoryError, errmsg)
-            return NULL
-    else:
+
+    retval = malloc(size)
+    if retval == NULL:
+        errmsg = "Can't malloc %d bytes" % size
+        PyErr_SetString(MemoryError, errmsg)
         return NULL
 
     return retval
@@ -57,6 +54,13 @@ cdef void* emalloc(size_t size) except? NULL:
 cdef void efree(void* what):
     free(what)
 
+def _test_emalloc(size_t size):
+    """Stub to simplify unit tests"""
+    cdef void* mem
+    mem = emalloc(size)
+    if size == 0:
+        assert mem == NULL
+    efree(mem)
 
 # === Testing of NumPy arrays =================================================
 
@@ -104,11 +108,11 @@ cdef int check_numpy(ndarray arr, hid_t space_id, int write):
 
                 if write:
                     if PyArray_DIM(arr,i) < space_dims[i]:
-                        PyErr_SetString(TypeError, "Array dimensions incompatible with dataspace.")
+                        PyErr_SetString(TypeError, "Array dimensions are too small for the dataspace.")
                         return -1
                 else:
                     if PyArray_DIM(arr,i) > space_dims[i]:
-                        PyErr_SetString(TypeError, "Array dimensions incompatible with dataspace.")
+                        PyErr_SetString(TypeError, "Array dimensions are too large for the dataspace.")
                         return -1
         finally:
             free(space_dims)
diff --git a/setup.py b/setup.py
index 76ec000..9bd3127 100644
--- a/setup.py
+++ b/setup.py
@@ -44,6 +44,7 @@ from distutils.extension import Extension
 from distutils.command.build import build 
 from distutils.command.clean import clean
 from distutils.command.sdist import sdist
+from distutils.cmd import Command
 
 # Basic package options
 NAME = 'h5py'
@@ -332,42 +333,51 @@ DEF H5PY_THREADS = %(THREADS)d  # Enable thread-safety and non-blocking reads
             if result.num_errors != 0:
                 fatal("%d Cython errors; aborting" % result.num_errors)
 
-class test(cybuild):
+class test(Command):
 
     """ Run unit tests """
 
     description = "Run unit tests in-place"
-    user_options = cybuild.user_options + \
-                   [('sections=','s','Comma separated list of tests ("-" prefix to NOT run)')]
+    user_options = [('sections=','s','Comma separated list of tests ("-" prefix to NOT run)'),
+                    ('detail=', 'd', 'Level of output detail (0-3, default 1)')]
 
     def initialize_options(self):
         self.sections = None
-        cybuild.initialize_options(self)
+        self.output = False
+        self.detail = 1
 
     def finalize_options(self):
-        cybuild.finalize_options(self)
+        self.detail = int(self.detail)
 
     def run(self):
-        cybuild.run(self)
+
+        buildobj = self.distribution.get_command_obj('build')
+        buildobj.run()
         oldpath = sys.path
         try:
-            sys.path = [op.abspath(self.build_lib)] + oldpath
+            sys.path = [op.abspath(buildobj.build_lib)] + oldpath
             import h5py.tests
-            if not h5py.tests.runtests(None if self.sections is None else tuple(self.sections.split(','))):
+            if not h5py.tests.runtests(None if self.sections is None else tuple(self.sections.split(',')), self.detail):
                 raise DistutilsError("Unit tests failed.")
         finally:
             sys.path = oldpath
 
-class doc(cybuild):
+class doc(Command):
 
     """ Regenerate documentation.  Unix only, requires epydoc/sphinx. """
 
     description = "Rebuild documentation"
 
+    user_options = []
+    def initialize_options(self):
+        pass
+    def finalize_options(self):
+        pass
+
     def run(self):
 
-        self._explicit_only = True
-        cybuild.run(self)
+        buildobj = self.distribution.get_command_obj('build')
+        buildobj.run()
 
         for x in ('docs', 'docs/api-html'):
             if not op.exists(x):
@@ -375,7 +385,7 @@ class doc(cybuild):
 
         retval = os.spawnlp(os.P_WAIT, 'epydoc', '-q', '--html',
                     '-o', 'docs/api-html', '--config', 'docs.cfg', 
-                    os.path.join(self.build_lib, NAME) )
+                    os.path.join(buildobj.build_lib, NAME) )
         if retval != 0:
             warn("Could not run epydoc to build documentation.")
 

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