# -*- coding: utf-8 -*- ######################################################################## # # License: BSD # Created: 2005-09-29 # Author: Ivan Vilata i Balaguer - ivan@selidor.net # # $Id$ # ######################################################################## """Test module for compatibility with plain HDF files""" import unittest import tempfile import shutil import os import numpy import tables from tables.tests import common from tables.tests.common import allequal class HDF5CompatibilityTestCase(common.PyTablesTestCase): """ Base class for HDF5 compatibility tests. Test cases deriving from this class must define an ``h5fname`` attribute with the name of the file to be opened, and a ``_test()`` method with checks on the opened file. """ def setUp(self): self.h5file = None def tearDown(self): if self.h5file is not None: self.h5file.close() self.h5file = None def test(self): self.h5fname = self._testFilename(self.h5fname) self.h5file = tables.open_file(self.h5fname) self._test() class EnumTestCase(HDF5CompatibilityTestCase): """ Test for enumerated datatype. See ftp://ftp.hdfgroup.org/HDF5/current/src/unpacked/test/enum.c. """ h5fname = 'smpl_enum.h5' def _test(self): self.assertTrue('/EnumTest' in self.h5file) arr = self.h5file.get_node('/EnumTest') self.assertTrue(isinstance(arr, tables.Array)) enum = arr.get_enum() expectedEnum = tables.Enum(['RED', 'GREEN', 'BLUE', 'WHITE', 'BLACK']) self.assertEqual(enum, expectedEnum) data = list(arr.read()) expectedData = [ enum[name] for name in ['RED', 'GREEN', 'BLUE', 'WHITE', 'BLACK', 'RED', 'GREEN', 'BLUE', 'WHITE', 'BLACK']] self.assertEqual(data, expectedData) class NumericTestCase(HDF5CompatibilityTestCase): """ Test for several numeric datatypes. See ftp://ftp.ncsa.uiuc.edu/HDF/files/hdf5/samples/[fiu]l?{8,16,32,64}{be,le}.c (they seem to be no longer available). """ def _test(self): self.assertTrue('/TestArray' in self.h5file) arr = self.h5file.get_node('/TestArray') self.assertTrue(isinstance(arr, tables.Array)) self.assertEqual(arr.atom.type, self.type) self.assertEqual(arr.byteorder, self.byteorder) self.assertEqual(arr.shape, (6, 5)) data = arr.read() expectedData = numpy.array([ [0, 1, 2, 3, 4], [1, 2, 3, 4, 5], [2, 3, 4, 5, 6], [3, 4, 5, 6, 7], [4, 5, 6, 7, 8], [5, 6, 7, 8, 9]], dtype=self.type) self.assertTrue(common.areArraysEqual(data, expectedData)) class F64BETestCase(NumericTestCase): h5fname = 'smpl_f64be.h5' type = 'float64' byteorder = 'big' class F64LETestCase(NumericTestCase): h5fname = 'smpl_f64le.h5' type = 'float64' byteorder = 'little' class I64BETestCase(NumericTestCase): h5fname = 'smpl_i64be.h5' type = 'int64' byteorder = 'big' class I64LETestCase(NumericTestCase): h5fname = 'smpl_i64le.h5' type = 'int64' byteorder = 'little' class I32BETestCase(NumericTestCase): h5fname = 'smpl_i32be.h5' type = 'int32' byteorder = 'big' class I32LETestCase(NumericTestCase): h5fname = 'smpl_i32le.h5' type = 'int32' byteorder = 'little' class ChunkedCompoundTestCase(HDF5CompatibilityTestCase): """ Test for a more complex and chunked compound structure. This is generated by a chunked version of the example in ftp://ftp.ncsa.uiuc.edu/HDF/files/hdf5/samples/compound2.c. """ h5fname = 'smpl_compound_chunked.h5' def _test(self): self.assertTrue('/CompoundChunked' in self.h5file) tbl = self.h5file.get_node('/CompoundChunked') self.assertTrue(isinstance(tbl, tables.Table)) self.assertEqual( tbl.colnames, ['a_name', 'c_name', 'd_name', 'e_name', 'f_name', 'g_name']) self.assertEqual(tbl.coltypes['a_name'], 'int32') self.assertEqual(tbl.coldtypes['a_name'].shape, ()) self.assertEqual(tbl.coltypes['c_name'], 'string') self.assertEqual(tbl.coldtypes['c_name'].shape, ()) self.assertEqual(tbl.coltypes['d_name'], 'int16') self.assertEqual(tbl.coldtypes['d_name'].shape, (5, 10)) self.assertEqual(tbl.coltypes['e_name'], 'float32') self.assertEqual(tbl.coldtypes['e_name'].shape, ()) self.assertEqual(tbl.coltypes['f_name'], 'float64') self.assertEqual(tbl.coldtypes['f_name'].shape, (10,)) self.assertEqual(tbl.coltypes['g_name'], 'uint8') self.assertEqual(tbl.coldtypes['g_name'].shape, ()) for m in range(len(tbl)): row = tbl[m] # This version of the loop seems to fail because of ``iterrows()``. # for (m, row) in enumerate(tbl): self.assertEqual(row['a_name'], m) self.assertEqual(row['c_name'], b"Hello!") dRow = row['d_name'] for n in range(5): for o in range(10): self.assertEqual(dRow[n][o], m + n + o) self.assertAlmostEqual(row['e_name'], m * 0.96, places=6) fRow = row['f_name'] for n in range(10): self.assertAlmostEqual(fRow[n], m * 1024.9637) self.assertEqual(row['g_name'], ord('m')) class ContiguousCompoundTestCase(HDF5CompatibilityTestCase): """ Test for support of native contiguous compound datasets. This example has been provided by Dav Clark. """ h5fname = 'non-chunked-table.h5' def _test(self): self.assertTrue('/test_var/structure variable' in self.h5file) tbl = self.h5file.get_node('/test_var/structure variable') self.assertTrue(isinstance(tbl, tables.Table)) self.assertEqual( tbl.colnames, ['a', 'b', 'c', 'd']) self.assertEqual(tbl.coltypes['a'], 'float64') self.assertEqual(tbl.coldtypes['a'].shape, ()) self.assertEqual(tbl.coltypes['b'], 'float64') self.assertEqual(tbl.coldtypes['b'].shape, ()) self.assertEqual(tbl.coltypes['c'], 'float64') self.assertEqual(tbl.coldtypes['c'].shape, (2,)) self.assertEqual(tbl.coltypes['d'], 'string') self.assertEqual(tbl.coldtypes['d'].shape, ()) for row in tbl.iterrows(): self.assertEqual(row['a'], 3.0) self.assertEqual(row['b'], 4.0) self.assertTrue(allequal(row['c'], numpy.array([2.0, 3.0], dtype="float64"))) self.assertEqual(row['d'], b"d") self.h5file.close() class ContiguousCompoundAppendTestCase(HDF5CompatibilityTestCase): """ Test for appending data to native contiguous compound datasets. """ h5fname = 'non-chunked-table.h5' def _test(self): self.assertTrue('/test_var/structure variable' in self.h5file) self.h5file.close() # Do a copy to a temporary to avoid modifying the original file h5fname_copy = tempfile.mktemp(".h5") shutil.copy(self.h5fname, h5fname_copy) # Reopen in 'a'ppend mode try: self.h5file = tables.open_file(h5fname_copy, 'a') except IOError: # Problems for opening (probably not permisions to write the file) return tbl = self.h5file.get_node('/test_var/structure variable') # Try to add rows to a non-chunked table (this should raise an error) self.assertRaises(tables.HDF5ExtError, tbl.append, [(4.0, 5.0, [2.0, 3.0], 'd')]) # Appending using the Row interface self.assertRaises(tables.HDF5ExtError, tbl.row.append) # Remove the file copy self.h5file.close() # Close the handler first os.remove(h5fname_copy) class ExtendibleTestCase(HDF5CompatibilityTestCase): """ Test for extendible datasets. See the example programs in the Introduction to HDF5. """ h5fname = 'smpl_SDSextendible.h5' def _test(self): self.assertTrue('/ExtendibleArray' in self.h5file) arr = self.h5file.get_node('/ExtendibleArray') self.assertTrue(isinstance(arr, tables.EArray)) self.assertEqual(arr.byteorder, 'big') self.assertEqual(arr.atom.type, 'int32') self.assertEqual(arr.shape, (10, 5)) self.assertEqual(arr.extdim, 0) self.assertEqual(len(arr), 10) data = arr.read() expectedData = numpy.array([ [1, 1, 1, 3, 3], [1, 1, 1, 3, 3], [1, 1, 1, 0, 0], [2, 0, 0, 0, 0], [2, 0, 0, 0, 0], [2, 0, 0, 0, 0], [2, 0, 0, 0, 0], [2, 0, 0, 0, 0], [2, 0, 0, 0, 0], [2, 0, 0, 0, 0]], dtype=arr.atom.type) self.assertTrue(common.areArraysEqual(data, expectedData)) class SzipTestCase(HDF5CompatibilityTestCase): """ Test for native HDF5 files with datasets compressed with szip. """ h5fname = 'test_szip.h5' def _test(self): self.assertTrue('/dset_szip' in self.h5file) arr = self.h5file.get_node('/dset_szip') filters = "Filters(complib='szip', shuffle=False, fletcher32=False)" self.assertEqual(repr(arr.filters), filters) # this demonstrates github #203 class MatlabFileTestCase(common.PyTablesTestCase): def setUp(self): h5fname = 'matlab_file.mat' file_path = self._testFilename(h5fname) self.h5file = tables.open_file(file_path, 'r') def tearDown(self): self.h5file.close() def test_unicode(self): array = self.h5file.get_node(unicode('/'), unicode('a')) self.assertEqual(array.shape, (3, 1)) # in Python 3 this will be the same as the test above def test_string(self): array = self.h5file.get_node('/', 'a') self.assertEqual(array.shape, (3, 1)) def test_numpy_str(self): array = self.h5file.get_node(numpy.str_('/'), numpy.str_('a')) self.assertEqual(array.shape, (3, 1)) def suite(): """Return a test suite consisting of all the test cases in the module.""" theSuite = unittest.TestSuite() niter = 1 for i in range(niter): theSuite.addTest(unittest.makeSuite(EnumTestCase)) theSuite.addTest(unittest.makeSuite(F64BETestCase)) theSuite.addTest(unittest.makeSuite(F64LETestCase)) theSuite.addTest(unittest.makeSuite(I64BETestCase)) theSuite.addTest(unittest.makeSuite(I64LETestCase)) theSuite.addTest(unittest.makeSuite(I32BETestCase)) theSuite.addTest(unittest.makeSuite(I32LETestCase)) theSuite.addTest(unittest.makeSuite(ChunkedCompoundTestCase)) theSuite.addTest(unittest.makeSuite(ContiguousCompoundTestCase)) theSuite.addTest(unittest.makeSuite(ContiguousCompoundAppendTestCase)) theSuite.addTest(unittest.makeSuite(ExtendibleTestCase)) theSuite.addTest(unittest.makeSuite(SzipTestCase)) theSuite.addTest(unittest.makeSuite(MatlabFileTestCase)) return theSuite if __name__ == '__main__': unittest.main(defaultTest='suite') ## Local Variables: ## mode: python ## py-indent-offset: 4 ## tab-width: 4 ## fill-column: 72 ## End: