[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