test_file.py 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848
  1. # This file is part of h5py, a Python interface to the HDF5 library.
  2. #
  3. # http://www.h5py.org
  4. #
  5. # Copyright 2008-2013 Andrew Collette and contributors
  6. #
  7. # License: Standard 3-clause BSD; see "license.txt" for full license terms
  8. # and contributor agreement.
  9. """
  10. File object test module.
  11. Tests all aspects of File objects, including their creation.
  12. """
  13. import pytest
  14. import os
  15. import stat
  16. import pickle
  17. import tempfile
  18. from sys import platform
  19. from .common import ut, TestCase, UNICODE_FILENAMES, closed_tempfile
  20. from h5py import File
  21. import h5py
  22. from .. import h5
  23. import pathlib
  24. class TestFileOpen(TestCase):
  25. """
  26. Feature: Opening files with Python-style modes.
  27. """
  28. def test_default(self):
  29. """ Default semantics in the presence or absence of a file """
  30. fname = self.mktemp()
  31. # No existing file; error
  32. with pytest.raises(FileNotFoundError):
  33. with File(fname):
  34. pass
  35. # Existing readonly file; open read-only
  36. with File(fname, 'w'):
  37. pass
  38. os.chmod(fname, stat.S_IREAD)
  39. try:
  40. with File(fname) as f:
  41. self.assertTrue(f)
  42. self.assertEqual(f.mode, 'r')
  43. finally:
  44. os.chmod(fname, stat.S_IWRITE)
  45. # File exists but is not HDF5; raise OSError
  46. with open(fname, 'wb') as f:
  47. f.write(b'\x00')
  48. with self.assertRaises(OSError):
  49. File(fname)
  50. def test_create(self):
  51. """ Mode 'w' opens file in overwrite mode """
  52. fname = self.mktemp()
  53. fid = File(fname, 'w')
  54. self.assertTrue(fid)
  55. fid.create_group('foo')
  56. fid.close()
  57. fid = File(fname, 'w')
  58. self.assertNotIn('foo', fid)
  59. fid.close()
  60. def test_create_exclusive(self):
  61. """ Mode 'w-' opens file in exclusive mode """
  62. fname = self.mktemp()
  63. fid = File(fname, 'w-')
  64. self.assertTrue(fid)
  65. fid.close()
  66. with self.assertRaises(FileExistsError):
  67. File(fname, 'w-')
  68. def test_append(self):
  69. """ Mode 'a' opens file in append/readwrite mode, creating if necessary """
  70. fname = self.mktemp()
  71. fid = File(fname, 'a')
  72. try:
  73. self.assertTrue(fid)
  74. fid.create_group('foo')
  75. assert 'foo' in fid
  76. finally:
  77. fid.close()
  78. fid = File(fname, 'a')
  79. try:
  80. assert 'foo' in fid
  81. fid.create_group('bar')
  82. assert 'bar' in fid
  83. finally:
  84. fid.close()
  85. os.chmod(fname, stat.S_IREAD) # Make file read-only
  86. try:
  87. with pytest.raises(PermissionError):
  88. File(fname, 'a')
  89. finally:
  90. # Make it writable again so it can be deleted on Windows
  91. os.chmod(fname, stat.S_IREAD | stat.S_IWRITE)
  92. def test_readonly(self):
  93. """ Mode 'r' opens file in readonly mode """
  94. fname = self.mktemp()
  95. fid = File(fname, 'w')
  96. fid.close()
  97. self.assertFalse(fid)
  98. fid = File(fname, 'r')
  99. self.assertTrue(fid)
  100. with self.assertRaises(ValueError):
  101. fid.create_group('foo')
  102. fid.close()
  103. def test_readwrite(self):
  104. """ Mode 'r+' opens existing file in readwrite mode """
  105. fname = self.mktemp()
  106. fid = File(fname, 'w')
  107. fid.create_group('foo')
  108. fid.close()
  109. fid = File(fname, 'r+')
  110. assert 'foo' in fid
  111. fid.create_group('bar')
  112. assert 'bar' in fid
  113. fid.close()
  114. def test_nonexistent_file(self):
  115. """ Modes 'r' and 'r+' do not create files """
  116. fname = self.mktemp()
  117. with self.assertRaises(FileNotFoundError):
  118. File(fname, 'r')
  119. with self.assertRaises(FileNotFoundError):
  120. File(fname, 'r+')
  121. def test_invalid_mode(self):
  122. """ Invalid modes raise ValueError """
  123. with self.assertRaises(ValueError):
  124. File(self.mktemp(), 'mongoose')
  125. @ut.skipIf(h5py.version.hdf5_version_tuple < (1, 10, 1),
  126. 'Requires HDF5 1.10.1 or later')
  127. class TestSpaceStrategy(TestCase):
  128. """
  129. Feature: Create file with specified file space strategy
  130. """
  131. def test_create_with_space_strategy(self):
  132. """ Create file with file space strategy """
  133. fname = self.mktemp()
  134. fid = File(fname, 'w', fs_strategy="page",
  135. fs_persist=True, fs_threshold=100)
  136. self.assertTrue(fid)
  137. # Unable to set file space strategy of an existing file
  138. with self.assertRaises(ValueError):
  139. File(fname, 'a', fs_strategy="page")
  140. # Invalid file space strategy type
  141. with self.assertRaises(ValueError):
  142. File(self.mktemp(), 'w', fs_strategy="invalid")
  143. dset = fid.create_dataset('foo', (100,), dtype='uint8')
  144. dset[...] = 1
  145. dset = fid.create_dataset('bar', (100,), dtype='uint8')
  146. dset[...] = 1
  147. del fid['foo']
  148. fid.close()
  149. fid = File(fname, 'a')
  150. plist = fid.id.get_create_plist()
  151. fs_strat = plist.get_file_space_strategy()
  152. assert(fs_strat[0] == 1)
  153. assert(fs_strat[1] == True)
  154. assert(fs_strat[2] == 100)
  155. dset = fid.create_dataset('foo2', (100,), dtype='uint8')
  156. dset[...] = 1
  157. fid.close()
  158. class TestModes(TestCase):
  159. """
  160. Feature: File mode can be retrieved via file.mode
  161. """
  162. def test_mode_attr(self):
  163. """ Mode equivalent can be retrieved via property """
  164. fname = self.mktemp()
  165. with File(fname, 'w') as f:
  166. self.assertEqual(f.mode, 'r+')
  167. with File(fname, 'r') as f:
  168. self.assertEqual(f.mode, 'r')
  169. def test_mode_external(self):
  170. """ Mode property works for files opened via external links
  171. Issue 190.
  172. """
  173. fname1 = self.mktemp()
  174. fname2 = self.mktemp()
  175. f1 = File(fname1, 'w')
  176. f1.close()
  177. f2 = File(fname2, 'w')
  178. try:
  179. f2['External'] = h5py.ExternalLink(fname1, '/')
  180. f3 = f2['External'].file
  181. self.assertEqual(f3.mode, 'r+')
  182. finally:
  183. f2.close()
  184. f3.close()
  185. f2 = File(fname2, 'r')
  186. try:
  187. f3 = f2['External'].file
  188. self.assertEqual(f3.mode, 'r')
  189. finally:
  190. f2.close()
  191. f3.close()
  192. class TestDrivers(TestCase):
  193. """
  194. Feature: Files can be opened with low-level HDF5 drivers. Does not
  195. include MPI drivers (see bottom).
  196. """
  197. @ut.skipUnless(os.name == 'posix', "Stdio driver is supported on posix")
  198. def test_stdio(self):
  199. """ Stdio driver is supported on posix """
  200. fid = File(self.mktemp(), 'w', driver='stdio')
  201. self.assertTrue(fid)
  202. self.assertEqual(fid.driver, 'stdio')
  203. fid.close()
  204. @ut.skipUnless(os.name == 'posix', "Sec2 driver is supported on posix")
  205. def test_sec2(self):
  206. """ Sec2 driver is supported on posix """
  207. fid = File(self.mktemp(), 'w', driver='sec2')
  208. self.assertTrue(fid)
  209. self.assertEqual(fid.driver, 'sec2')
  210. fid.close()
  211. def test_core(self):
  212. """ Core driver is supported (no backing store) """
  213. fname = self.mktemp()
  214. fid = File(fname, 'w', driver='core', backing_store=False)
  215. self.assertTrue(fid)
  216. self.assertEqual(fid.driver, 'core')
  217. fid.close()
  218. self.assertFalse(os.path.exists(fname))
  219. def test_backing(self):
  220. """ Core driver saves to file when backing store used """
  221. fname = self.mktemp()
  222. fid = File(fname, 'w', driver='core', backing_store=True)
  223. fid.create_group('foo')
  224. fid.close()
  225. fid = File(fname, 'r')
  226. assert 'foo' in fid
  227. fid.close()
  228. # keywords for other drivers are invalid when using the default driver
  229. with self.assertRaises(TypeError):
  230. File(fname, 'w', backing_store=True)
  231. def test_readonly(self):
  232. """ Core driver can be used to open existing files """
  233. fname = self.mktemp()
  234. fid = File(fname, 'w')
  235. fid.create_group('foo')
  236. fid.close()
  237. fid = File(fname, 'r', driver='core')
  238. self.assertTrue(fid)
  239. assert 'foo' in fid
  240. with self.assertRaises(ValueError):
  241. fid.create_group('bar')
  242. fid.close()
  243. def test_blocksize(self):
  244. """ Core driver supports variable block size """
  245. fname = self.mktemp()
  246. fid = File(fname, 'w', driver='core', block_size=1024,
  247. backing_store=False)
  248. self.assertTrue(fid)
  249. fid.close()
  250. def test_split(self):
  251. """ Split stores metadata in a separate file """
  252. fname = self.mktemp()
  253. fid = File(fname, 'w', driver='split')
  254. fid.close()
  255. self.assertTrue(os.path.exists(fname + '-m.h5'))
  256. fid = File(fname, 'r', driver='split')
  257. self.assertTrue(fid)
  258. fid.close()
  259. def test_fileobj(self):
  260. """ Python file object driver is supported """
  261. tf = tempfile.TemporaryFile()
  262. fid = File(tf, 'w', driver='fileobj')
  263. self.assertTrue(fid)
  264. self.assertEqual(fid.driver, 'fileobj')
  265. fid.close()
  266. # Driver must be 'fileobj' for file-like object if specified
  267. with self.assertRaises(ValueError):
  268. File(tf, 'w', driver='core')
  269. # TODO: family driver tests
  270. @ut.skipUnless(h5py.version.hdf5_version_tuple < (1, 10, 2),
  271. 'Requires HDF5 before 1.10.2')
  272. class TestLibver(TestCase):
  273. """
  274. Feature: File format compatibility bounds can be specified when
  275. opening a file.
  276. """
  277. def test_default(self):
  278. """ Opening with no libver arg """
  279. f = File(self.mktemp(), 'w')
  280. self.assertEqual(f.libver, ('earliest', 'latest'))
  281. f.close()
  282. def test_single(self):
  283. """ Opening with single libver arg """
  284. f = File(self.mktemp(), 'w', libver='latest')
  285. self.assertEqual(f.libver, ('latest', 'latest'))
  286. f.close()
  287. def test_multiple(self):
  288. """ Opening with two libver args """
  289. f = File(self.mktemp(), 'w', libver=('earliest', 'latest'))
  290. self.assertEqual(f.libver, ('earliest', 'latest'))
  291. f.close()
  292. def test_none(self):
  293. """ Omitting libver arg results in maximum compatibility """
  294. f = File(self.mktemp(), 'w')
  295. self.assertEqual(f.libver, ('earliest', 'latest'))
  296. f.close()
  297. @ut.skipIf(h5py.version.hdf5_version_tuple < (1, 10, 2),
  298. 'Requires HDF5 1.10.2 or later')
  299. class TestNewLibver(TestCase):
  300. """
  301. Feature: File format compatibility bounds can be specified when
  302. opening a file.
  303. Requirement: HDF5 1.10.2 or later
  304. """
  305. @classmethod
  306. def setUpClass(cls):
  307. super(TestNewLibver, cls).setUpClass()
  308. # Current latest library bound label
  309. if h5py.version.hdf5_version_tuple < (1, 11, 4):
  310. cls.latest = 'v110'
  311. elif h5py.version.hdf5_version_tuple < (1, 13, 0):
  312. cls.latest = 'v112'
  313. else:
  314. cls.latest = 'v114'
  315. def test_default(self):
  316. """ Opening with no libver arg """
  317. f = File(self.mktemp(), 'w')
  318. self.assertEqual(f.libver, ('earliest', self.latest))
  319. f.close()
  320. def test_single(self):
  321. """ Opening with single libver arg """
  322. f = File(self.mktemp(), 'w', libver='latest')
  323. self.assertEqual(f.libver, (self.latest, self.latest))
  324. f.close()
  325. def test_single_v108(self):
  326. """ Opening with "v108" libver arg """
  327. f = File(self.mktemp(), 'w', libver='v108')
  328. self.assertEqual(f.libver, ('v108', self.latest))
  329. f.close()
  330. def test_single_v110(self):
  331. """ Opening with "v110" libver arg """
  332. f = File(self.mktemp(), 'w', libver='v110')
  333. self.assertEqual(f.libver, ('v110', self.latest))
  334. f.close()
  335. @ut.skipIf(h5py.version.hdf5_version_tuple < (1, 11, 4),
  336. 'Requires HDF5 1.11.4 or later')
  337. def test_single_v112(self):
  338. """ Opening with "v112" libver arg """
  339. f = File(self.mktemp(), 'w', libver='v112')
  340. self.assertEqual(f.libver, ('v112', self.latest))
  341. f.close()
  342. def test_multiple(self):
  343. """ Opening with two libver args """
  344. f = File(self.mktemp(), 'w', libver=('earliest', 'v108'))
  345. self.assertEqual(f.libver, ('earliest', 'v108'))
  346. f.close()
  347. def test_none(self):
  348. """ Omitting libver arg results in maximum compatibility """
  349. f = File(self.mktemp(), 'w')
  350. self.assertEqual(f.libver, ('earliest', self.latest))
  351. f.close()
  352. class TestUserblock(TestCase):
  353. """
  354. Feature: Files can be create with user blocks
  355. """
  356. def test_create_blocksize(self):
  357. """ User blocks created with w, w-, x and properties work correctly """
  358. f = File(self.mktemp(), 'w-', userblock_size=512)
  359. try:
  360. self.assertEqual(f.userblock_size, 512)
  361. finally:
  362. f.close()
  363. f = File(self.mktemp(), 'x', userblock_size=512)
  364. try:
  365. self.assertEqual(f.userblock_size, 512)
  366. finally:
  367. f.close()
  368. f = File(self.mktemp(), 'w', userblock_size=512)
  369. try:
  370. self.assertEqual(f.userblock_size, 512)
  371. finally:
  372. f.close()
  373. # User block size must be an integer
  374. with self.assertRaises(ValueError):
  375. File(self.mktemp(), 'w', userblock_size='non')
  376. def test_write_only(self):
  377. """ User block only allowed for write """
  378. name = self.mktemp()
  379. f = File(name, 'w')
  380. f.close()
  381. with self.assertRaises(ValueError):
  382. f = h5py.File(name, 'r', userblock_size=512)
  383. with self.assertRaises(ValueError):
  384. f = h5py.File(name, 'r+', userblock_size=512)
  385. def test_match_existing(self):
  386. """ User block size must match that of file when opening for append """
  387. name = self.mktemp()
  388. f = File(name, 'w', userblock_size=512)
  389. f.close()
  390. with self.assertRaises(ValueError):
  391. f = File(name, 'a', userblock_size=1024)
  392. f = File(name, 'a', userblock_size=512)
  393. try:
  394. self.assertEqual(f.userblock_size, 512)
  395. finally:
  396. f.close()
  397. def test_power_of_two(self):
  398. """ User block size must be a power of 2 and at least 512 """
  399. name = self.mktemp()
  400. with self.assertRaises(ValueError):
  401. f = File(name, 'w', userblock_size=128)
  402. with self.assertRaises(ValueError):
  403. f = File(name, 'w', userblock_size=513)
  404. with self.assertRaises(ValueError):
  405. f = File(name, 'w', userblock_size=1023)
  406. def test_write_block(self):
  407. """ Test that writing to a user block does not destroy the file """
  408. name = self.mktemp()
  409. f = File(name, 'w', userblock_size=512)
  410. f.create_group("Foobar")
  411. f.close()
  412. pyfile = open(name, 'r+b')
  413. try:
  414. pyfile.write(b'X' * 512)
  415. finally:
  416. pyfile.close()
  417. f = h5py.File(name, 'r')
  418. try:
  419. assert "Foobar" in f
  420. finally:
  421. f.close()
  422. pyfile = open(name, 'rb')
  423. try:
  424. self.assertEqual(pyfile.read(512), b'X' * 512)
  425. finally:
  426. pyfile.close()
  427. class TestContextManager(TestCase):
  428. """
  429. Feature: File objects can be used as context managers
  430. """
  431. def test_context_manager(self):
  432. """ File objects can be used in with statements """
  433. with File(self.mktemp(), 'w') as fid:
  434. self.assertTrue(fid)
  435. self.assertTrue(not fid)
  436. @ut.skipIf(not UNICODE_FILENAMES, "Filesystem unicode support required")
  437. class TestUnicode(TestCase):
  438. """
  439. Feature: Unicode filenames are supported
  440. """
  441. def test_unicode(self):
  442. """ Unicode filenames can be used, and retrieved properly via .filename
  443. """
  444. fname = self.mktemp(prefix=chr(0x201a))
  445. fid = File(fname, 'w')
  446. try:
  447. self.assertEqual(fid.filename, fname)
  448. self.assertIsInstance(fid.filename, str)
  449. finally:
  450. fid.close()
  451. def test_unicode_hdf5_python_consistent(self):
  452. """ Unicode filenames can be used, and seen correctly from python
  453. """
  454. fname = self.mktemp(prefix=chr(0x201a))
  455. with File(fname, 'w') as f:
  456. self.assertTrue(os.path.exists(fname))
  457. def test_nonexistent_file_unicode(self):
  458. """
  459. Modes 'r' and 'r+' do not create files even when given unicode names
  460. """
  461. fname = self.mktemp(prefix=chr(0x201a))
  462. with self.assertRaises(IOError):
  463. File(fname, 'r')
  464. with self.assertRaises(IOError):
  465. File(fname, 'r+')
  466. class TestFileProperty(TestCase):
  467. """
  468. Feature: A File object can be retrieved from any child object,
  469. via the .file property
  470. """
  471. def test_property(self):
  472. """ File object can be retrieved from subgroup """
  473. fname = self.mktemp()
  474. hfile = File(fname, 'w')
  475. try:
  476. hfile2 = hfile['/'].file
  477. self.assertEqual(hfile, hfile2)
  478. finally:
  479. hfile.close()
  480. def test_close(self):
  481. """ All retrieved File objects are closed at the same time """
  482. fname = self.mktemp()
  483. hfile = File(fname, 'w')
  484. grp = hfile.create_group('foo')
  485. hfile2 = grp.file
  486. hfile3 = hfile['/'].file
  487. hfile2.close()
  488. self.assertFalse(hfile)
  489. self.assertFalse(hfile2)
  490. self.assertFalse(hfile3)
  491. def test_mode(self):
  492. """ Retrieved File objects have a meaningful mode attribute """
  493. hfile = File(self.mktemp(), 'w')
  494. try:
  495. grp = hfile.create_group('foo')
  496. self.assertEqual(grp.file.mode, hfile.mode)
  497. finally:
  498. hfile.close()
  499. class TestClose(TestCase):
  500. """
  501. Feature: Files can be closed
  502. """
  503. def test_close(self):
  504. """ Close file via .close method """
  505. fid = File(self.mktemp(), 'w')
  506. self.assertTrue(fid)
  507. fid.close()
  508. self.assertFalse(fid)
  509. def test_closed_file(self):
  510. """ Trying to modify closed file raises ValueError """
  511. fid = File(self.mktemp(), 'w')
  512. fid.close()
  513. with self.assertRaises(ValueError):
  514. fid.create_group('foo')
  515. def test_close_multiple_default_driver(self):
  516. fname = self.mktemp()
  517. f = h5py.File(fname, 'w')
  518. f.create_group("test")
  519. f.close()
  520. f.close()
  521. class TestFlush(TestCase):
  522. """
  523. Feature: Files can be flushed
  524. """
  525. def test_flush(self):
  526. """ Flush via .flush method """
  527. fid = File(self.mktemp(), 'w')
  528. fid.flush()
  529. fid.close()
  530. class TestRepr(TestCase):
  531. """
  532. Feature: File objects provide a helpful __repr__ string
  533. """
  534. def test_repr(self):
  535. """ __repr__ behaves itself when files are open and closed """
  536. fid = File(self.mktemp(), 'w')
  537. self.assertIsInstance(repr(fid), str)
  538. fid.close()
  539. self.assertIsInstance(repr(fid), str)
  540. class TestFilename(TestCase):
  541. """
  542. Feature: The name of a File object can be retrieved via .filename
  543. """
  544. def test_filename(self):
  545. """ .filename behaves properly for string data """
  546. fname = self.mktemp()
  547. fid = File(fname, 'w')
  548. try:
  549. self.assertEqual(fid.filename, fname)
  550. self.assertIsInstance(fid.filename, str)
  551. finally:
  552. fid.close()
  553. class TestCloseInvalidatesOpenObjectIDs(TestCase):
  554. """
  555. Ensure that closing a file invalidates object IDs, as appropriate
  556. """
  557. def test_close(self):
  558. """ Closing a file invalidates any of the file's open objects """
  559. with File(self.mktemp(), 'w') as f1:
  560. g1 = f1.create_group('foo')
  561. self.assertTrue(bool(f1.id))
  562. self.assertTrue(bool(g1.id))
  563. f1.close()
  564. self.assertFalse(bool(f1.id))
  565. self.assertFalse(bool(g1.id))
  566. with File(self.mktemp(), 'w') as f2:
  567. g2 = f2.create_group('foo')
  568. self.assertTrue(bool(f2.id))
  569. self.assertTrue(bool(g2.id))
  570. self.assertFalse(bool(f1.id))
  571. self.assertFalse(bool(g1.id))
  572. def test_close_one_handle(self):
  573. fname = self.mktemp()
  574. with File(fname, 'w') as f:
  575. f.create_group('foo')
  576. f1 = File(fname)
  577. f2 = File(fname)
  578. g1 = f1['foo']
  579. g2 = f2['foo']
  580. assert g1.id.valid
  581. assert g2.id.valid
  582. f1.close()
  583. assert not g1.id.valid
  584. # Closing f1 shouldn't close f2 or objects belonging to it
  585. assert f2.id.valid
  586. assert g2.id.valid
  587. f2.close()
  588. assert not f2.id.valid
  589. assert not g2.id.valid
  590. class TestPathlibSupport(TestCase):
  591. """
  592. Check that h5py doesn't break on pathlib
  593. """
  594. def test_pathlib_accepted_file(self):
  595. """ Check that pathlib is accepted by h5py.File """
  596. with closed_tempfile() as f:
  597. path = pathlib.Path(f)
  598. with File(path, 'w') as f2:
  599. self.assertTrue(True)
  600. def test_pathlib_name_match(self):
  601. """ Check that using pathlib does not affect naming """
  602. with closed_tempfile() as f:
  603. path = pathlib.Path(f)
  604. with File(path, 'w') as h5f1:
  605. pathlib_name = h5f1.filename
  606. with File(f, 'w') as h5f2:
  607. normal_name = h5f2.filename
  608. self.assertEqual(pathlib_name, normal_name)
  609. class TestPickle(TestCase):
  610. """Check that h5py.File can't be pickled"""
  611. def test_dump_error(self):
  612. with File(self.mktemp(), 'w') as f1:
  613. with self.assertRaises(TypeError):
  614. pickle.dumps(f1)
  615. # unittest doesn't work with pytest fixtures (and possibly other features),
  616. # hence no subclassing TestCase
  617. @pytest.mark.mpi
  618. class TestMPI(object):
  619. def test_mpio(self, mpi_file_name):
  620. """ MPIO driver and options """
  621. from mpi4py import MPI
  622. with File(mpi_file_name, 'w', driver='mpio', comm=MPI.COMM_WORLD) as f:
  623. assert f
  624. assert f.driver == 'mpio'
  625. @pytest.mark.skipif(h5py.version.hdf5_version_tuple < (1, 8, 9),
  626. reason="mpio atomic file operations were added in HDF5 1.8.9+")
  627. def test_mpi_atomic(self, mpi_file_name):
  628. """ Enable atomic mode for MPIO driver """
  629. from mpi4py import MPI
  630. with File(mpi_file_name, 'w', driver='mpio', comm=MPI.COMM_WORLD) as f:
  631. assert not f.atomic
  632. f.atomic = True
  633. assert f.atomic
  634. def test_close_multiple_mpio_driver(self, mpi_file_name):
  635. """ MPIO driver and options """
  636. from mpi4py import MPI
  637. f = File(mpi_file_name, 'w', driver='mpio', comm=MPI.COMM_WORLD)
  638. f.create_group("test")
  639. f.close()
  640. f.close()
  641. @ut.skipIf(h5py.version.hdf5_version_tuple < (1, 10, 1),
  642. 'Requires HDF5 1.10.1 or later')
  643. class TestSWMRMode(TestCase):
  644. """
  645. Feature: Create file that switches on SWMR mode
  646. """
  647. def test_file_mode_generalizes(self):
  648. fname = self.mktemp()
  649. fid = File(fname, 'w', libver='latest')
  650. g = fid.create_group('foo')
  651. # fid and group member file attribute should have the same mode
  652. assert fid.mode == g.file.mode == 'r+'
  653. fid.swmr_mode = True
  654. # fid and group member file attribute should still be 'r+'
  655. # even though file intent has changed
  656. assert fid.mode == g.file.mode == 'r+'
  657. fid.close()
  658. def test_swmr_mode_consistency(self):
  659. fname = self.mktemp()
  660. fid = File(fname, 'w', libver='latest')
  661. g = fid.create_group('foo')
  662. assert fid.swmr_mode == g.file.swmr_mode == False
  663. fid.swmr_mode = True
  664. # This setter should affect both fid and group member file attribute
  665. assert fid.swmr_mode == g.file.swmr_mode == True
  666. fid.close()
  667. # unittest doesn't work with pytest fixtures (and possibly other features),
  668. # hence no subclassing TestCase
  669. class TestROS3:
  670. @pytest.mark.skipif(h5py.version.hdf5_version_tuple < (1, 10, 6)
  671. or not h5.get_config().ros3,
  672. reason="ros3 file operations were added in HDF5 1.10.6+")
  673. def test_ros3(self):
  674. """ ROS3 driver and options """
  675. with File("https://dandiarchive.s3.amazonaws.com/ros3test.hdf5", 'r',
  676. driver='ros3') as f:
  677. assert f
  678. assert 'mydataset' in f.keys()
  679. assert f["mydataset"].shape == (100,)
  680. def test_close_gc(writable_file):
  681. # https://github.com/h5py/h5py/issues/1852
  682. for i in range(100):
  683. writable_file[str(i)] = []
  684. filename = writable_file.filename
  685. writable_file.close()
  686. # Ensure that Python's garbage collection doesn't interfere with closing
  687. # a file. Try a few times - the problem is not 100% consistent, but
  688. # normally showed up on the 1st or 2nd iteration for me. -TAK, 2021
  689. for i in range(10):
  690. with h5py.File(filename, 'r') as f:
  691. refs = [d.id for d in f.values()]
  692. refs.append(refs) # Make a reference cycle so GC is involved
  693. del refs # GC is likely to fire while closing the file