# This file is part of h5py, a Python interface to the HDF5 library. # # http://www.h5py.org # # Copyright 2008-2013 Andrew Collette and contributors # # License: Standard 3-clause BSD; see "license.txt" for full license terms # and contributor agreement. """ Tests the h5py.File object. """ import h5py from h5py._hl.files import _drivers from h5py import File from .common import ut, TestCase import pytest import io import tempfile import os def nfiles(): return h5py.h5f.get_obj_count(h5py.h5f.OBJ_ALL, h5py.h5f.OBJ_FILE) def ngroups(): return h5py.h5f.get_obj_count(h5py.h5f.OBJ_ALL, h5py.h5f.OBJ_GROUP) class TestDealloc(TestCase): """ Behavior on object deallocation. Note most of this behavior is delegated to FileID. """ def test_autoclose(self): """ File objects close automatically when out of scope, but other objects remain open. """ start_nfiles = nfiles() start_ngroups = ngroups() fname = self.mktemp() f = h5py.File(fname, 'w') g = f['/'] self.assertEqual(nfiles(), start_nfiles+1) self.assertEqual(ngroups(), start_ngroups+1) del f self.assertTrue(g) self.assertEqual(nfiles(), start_nfiles) self.assertEqual(ngroups(), start_ngroups+1) f = g.file self.assertTrue(f) self.assertEqual(nfiles(), start_nfiles+1) self.assertEqual(ngroups(), start_ngroups+1) del g self.assertEqual(nfiles(), start_nfiles+1) self.assertEqual(ngroups(), start_ngroups) del f self.assertEqual(nfiles(), start_nfiles) self.assertEqual(ngroups(), start_ngroups) class TestDriverRegistration(TestCase): def test_register_driver(self): called_with = [None] def set_fapl(plist, *args, **kwargs): called_with[0] = args, kwargs return _drivers['sec2'](plist) h5py.register_driver('new-driver', set_fapl) self.assertIn('new-driver', h5py.registered_drivers()) fname = self.mktemp() h5py.File(fname, driver='new-driver', driver_arg_0=0, driver_arg_1=1, mode='w') self.assertEqual( called_with, [((), {'driver_arg_0': 0, 'driver_arg_1': 1})], ) def test_unregister_driver(self): h5py.register_driver('new-driver', lambda plist: None) self.assertIn('new-driver', h5py.registered_drivers()) h5py.unregister_driver('new-driver') self.assertNotIn('new-driver', h5py.registered_drivers()) with self.assertRaises(ValueError) as e: fname = self.mktemp() h5py.File(fname, driver='new-driver', mode='w') self.assertEqual(str(e.exception), 'Unknown driver type "new-driver"') class TestCache(TestCase): def test_defaults(self): fname = self.mktemp() f = h5py.File(fname, 'w') self.assertEqual(list(f.id.get_access_plist().get_cache()), [0, 521, 1048576, 0.75]) def test_nbytes(self): fname = self.mktemp() f = h5py.File(fname, 'w', rdcc_nbytes=1024) self.assertEqual(list(f.id.get_access_plist().get_cache()), [0, 521, 1024, 0.75]) def test_nslots(self): fname = self.mktemp() f = h5py.File(fname, 'w', rdcc_nslots=125) self.assertEqual(list(f.id.get_access_plist().get_cache()), [0, 125, 1048576, 0.75]) def test_w0(self): fname = self.mktemp() f = h5py.File(fname, 'w', rdcc_w0=0.25) self.assertEqual(list(f.id.get_access_plist().get_cache()), [0, 521, 1048576, 0.25]) class TestFileObj(TestCase): def check_write(self, fileobj): f = h5py.File(fileobj, 'w') self.assertEqual(f.driver, 'fileobj') self.assertEqual(f.filename, repr(fileobj)) f.create_dataset('test', data=list(range(12))) self.assertEqual(list(f), ['test']) self.assertEqual(list(f['test'][:]), list(range(12))) f.close() def check_read(self, fileobj): f = h5py.File(fileobj, 'r') self.assertEqual(list(f), ['test']) self.assertEqual(list(f['test'][:]), list(range(12))) self.assertRaises(Exception, f.create_dataset, 'another.test', data=list(range(3))) f.close() def test_BytesIO(self): with io.BytesIO() as fileobj: self.assertEqual(len(fileobj.getvalue()), 0) self.check_write(fileobj) self.assertGreater(len(fileobj.getvalue()), 0) self.check_read(fileobj) def test_file(self): fname = self.mktemp() try: with open(fname, 'wb+') as fileobj: self.assertEqual(os.path.getsize(fname), 0) self.check_write(fileobj) self.assertGreater(os.path.getsize(fname), 0) self.check_read(fileobj) with open(fname, 'rb') as fileobj: self.check_read(fileobj) finally: os.remove(fname) def test_TemporaryFile(self): # in this test, we check explicitly that temp file gets # automatically deleted upon h5py.File.close()... fileobj = tempfile.NamedTemporaryFile() fname = fileobj.name f = h5py.File(fileobj, 'w') del fileobj # ... but in your code feel free to simply # f = h5py.File(tempfile.TemporaryFile()) f.create_dataset('test', data=list(range(12))) self.assertEqual(list(f), ['test']) self.assertEqual(list(f['test'][:]), list(range(12))) self.assertTrue(os.path.isfile(fname)) f.close() self.assertFalse(os.path.isfile(fname)) def test_exception_open(self): self.assertRaises(Exception, h5py.File, None, driver='fileobj', mode='x') self.assertRaises(Exception, h5py.File, 'rogue', driver='fileobj', mode='x') self.assertRaises(Exception, h5py.File, self, driver='fileobj', mode='x') def test_exception_read(self): class BrokenBytesIO(io.BytesIO): def readinto(self, b): raise Exception('I am broken') f = h5py.File(BrokenBytesIO(), 'w') f.create_dataset('test', data=list(range(12))) self.assertRaises(Exception, list, f['test']) def test_exception_write(self): class BrokenBytesIO(io.BytesIO): allow_write = False def write(self, b): if self.allow_write: return super().write(b) else: raise Exception('I am broken') bio = BrokenBytesIO() f = h5py.File(bio, 'w') try: self.assertRaises(Exception, f.create_dataset, 'test', data=list(range(12))) finally: # Un-break writing so we can close: errors while closing get messy. bio.allow_write = True f.close() @ut.skip("Incompletely closed files can cause segfaults") def test_exception_close(self): fileobj = io.BytesIO() f = h5py.File(fileobj, 'w') fileobj.close() self.assertRaises(Exception, f.close) def test_exception_writeonly(self): # HDF5 expects read & write access to a file it's writing; # check that we get the correct exception on a write-only file object. fileobj = open(os.path.join(self.tempdir, 'a.h5'), 'wb') with self.assertRaises(io.UnsupportedOperation): f = h5py.File(fileobj, 'w') group = f.create_group("group") group.create_dataset("data", data='foo', dtype=h5py.string_dtype()) def test_method_vanish(self): fileobj = io.BytesIO() f = h5py.File(fileobj, 'w') f.create_dataset('test', data=list(range(12))) self.assertEqual(list(f['test'][:]), list(range(12))) fileobj.readinto = None self.assertRaises(Exception, list, f['test']) class TestTrackOrder(TestCase): def populate(self, f): for i in range(100): # Mix group and dataset creation. if i % 10 == 0: f.create_group(str(i)) else: f[str(i)] = [i] def test_track_order(self): fname = self.mktemp() f = h5py.File(fname, 'w', track_order=True) # creation order self.populate(f) self.assertEqual(list(f), [str(i) for i in range(100)]) def test_no_track_order(self): fname = self.mktemp() f = h5py.File(fname, 'w', track_order=False) # name alphanumeric self.populate(f) self.assertEqual(list(f), sorted([str(i) for i in range(100)])) class TestFileMetaBlockSize(TestCase): """ Feature: The meta block size can be manipulated, changing how metadata is aggregated and the offset of the first dataset. """ def test_file_create_with_meta_block_size_4096(self): # Test a large meta block size of 4 kibibytes meta_block_size = 4096 with File( self.mktemp(), 'w', meta_block_size=meta_block_size, libver="latest" ) as f: f["test"] = 5 self.assertEqual(f.meta_block_size, meta_block_size) # Equality is expected for HDF5 1.10 self.assertGreaterEqual(f["test"].id.get_offset(), meta_block_size) def test_file_create_with_meta_block_size_512(self): # Test a small meta block size of 512 bytes # The smallest verifiable meta_block_size is 463 meta_block_size = 512 libver = "latest" with File( self.mktemp(), 'w', meta_block_size=meta_block_size, libver=libver ) as f: f["test"] = 3 self.assertEqual(f.meta_block_size, meta_block_size) # Equality is expected for HDF5 1.10 self.assertGreaterEqual(f["test"].id.get_offset(), meta_block_size) # Default meta_block_size is 2048. This should fail if meta_block_size is not set. self.assertLess(f["test"].id.get_offset(), meta_block_size*2)