test_file.py 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500
  1. #!/usr/bin/env python
  2. #
  3. # Author: Mike McKerns (mmckerns @caltech and @uqfoundation)
  4. # Copyright (c) 2008-2016 California Institute of Technology.
  5. # Copyright (c) 2016-2024 The Uncertainty Quantification Foundation.
  6. # License: 3-clause BSD. The full license text is available at:
  7. # - https://github.com/uqfoundation/dill/blob/master/LICENSE
  8. import os
  9. import sys
  10. import string
  11. import random
  12. import dill
  13. dill.settings['recurse'] = True
  14. fname = "_test_file.txt"
  15. rand_chars = list(string.ascii_letters) + ["\n"] * 40 # bias newline
  16. buffer_error = ValueError("invalid buffer size")
  17. dne_error = FileNotFoundError("[Errno 2] No such file or directory: '%s'" % fname)
  18. def write_randomness(number=200):
  19. f = open(fname, "w")
  20. for i in range(number):
  21. f.write(random.choice(rand_chars))
  22. f.close()
  23. f = open(fname, "r")
  24. contents = f.read()
  25. f.close()
  26. return contents
  27. def trunc_file():
  28. open(fname, "w").close()
  29. def throws(op, args, exc):
  30. try:
  31. op(*args)
  32. except type(exc):
  33. return sys.exc_info()[1].args == exc.args
  34. else:
  35. return False
  36. def teardown_module():
  37. if os.path.exists(fname):
  38. os.remove(fname)
  39. def bench(strictio, fmode, skippypy):
  40. import platform
  41. if skippypy and platform.python_implementation() == 'PyPy':
  42. # Skip for PyPy...
  43. return
  44. # file exists, with same contents
  45. # read
  46. write_randomness()
  47. f = open(fname, "r")
  48. _f = dill.loads(dill.dumps(f, fmode=fmode))#, strictio=strictio))
  49. assert _f.mode == f.mode
  50. assert _f.tell() == f.tell()
  51. assert _f.read() == f.read()
  52. f.close()
  53. _f.close()
  54. # write
  55. f = open(fname, "w")
  56. f.write("hello")
  57. f_dumped = dill.dumps(f, fmode=fmode)#, strictio=strictio)
  58. f1mode = f.mode
  59. ftell = f.tell()
  60. f.close()
  61. f2 = dill.loads(f_dumped) #FIXME: fails due to pypy/issues/1233
  62. # TypeError: expected py_object instance instead of str
  63. f2mode = f2.mode
  64. f2tell = f2.tell()
  65. f2name = f2.name
  66. f2.write(" world!")
  67. f2.close()
  68. if fmode == dill.HANDLE_FMODE:
  69. assert open(fname).read() == " world!"
  70. assert f2mode == f1mode
  71. assert f2tell == 0
  72. elif fmode == dill.CONTENTS_FMODE:
  73. assert open(fname).read() == "hello world!"
  74. assert f2mode == f1mode
  75. assert f2tell == ftell
  76. assert f2name == fname
  77. elif fmode == dill.FILE_FMODE:
  78. assert open(fname).read() == "hello world!"
  79. assert f2mode == f1mode
  80. assert f2tell == ftell
  81. else:
  82. raise RuntimeError("Unknown file mode '%s'" % fmode)
  83. # append
  84. trunc_file()
  85. f = open(fname, "a")
  86. f.write("hello")
  87. f_dumped = dill.dumps(f, fmode=fmode)#, strictio=strictio)
  88. f1mode = f.mode
  89. ftell = f.tell()
  90. f.close()
  91. f2 = dill.loads(f_dumped)
  92. f2mode = f2.mode
  93. f2tell = f2.tell()
  94. f2.write(" world!")
  95. f2.close()
  96. assert f2mode == f1mode
  97. if fmode == dill.CONTENTS_FMODE:
  98. assert open(fname).read() == "hello world!"
  99. assert f2tell == ftell
  100. elif fmode == dill.HANDLE_FMODE:
  101. assert open(fname).read() == "hello world!"
  102. assert f2tell == ftell
  103. elif fmode == dill.FILE_FMODE:
  104. assert open(fname).read() == "hello world!"
  105. assert f2tell == ftell
  106. else:
  107. raise RuntimeError("Unknown file mode '%s'" % fmode)
  108. # file exists, with different contents (smaller size)
  109. # read
  110. write_randomness()
  111. f = open(fname, "r")
  112. fstr = f.read()
  113. f_dumped = dill.dumps(f, fmode=fmode)#, strictio=strictio)
  114. f1mode = f.mode
  115. ftell = f.tell()
  116. f.close()
  117. _flen = 150
  118. _fstr = write_randomness(number=_flen)
  119. if strictio: # throw error if ftell > EOF
  120. assert throws(dill.loads, (f_dumped,), buffer_error)
  121. else:
  122. f2 = dill.loads(f_dumped)
  123. assert f2.mode == f1mode
  124. if fmode == dill.CONTENTS_FMODE:
  125. assert f2.tell() == _flen
  126. assert f2.read() == ""
  127. f2.seek(0)
  128. assert f2.read() == _fstr
  129. assert f2.tell() == _flen # 150
  130. elif fmode == dill.HANDLE_FMODE:
  131. assert f2.tell() == 0
  132. assert f2.read() == _fstr
  133. assert f2.tell() == _flen # 150
  134. elif fmode == dill.FILE_FMODE:
  135. assert f2.tell() == ftell # 200
  136. assert f2.read() == ""
  137. f2.seek(0)
  138. assert f2.read() == fstr
  139. assert f2.tell() == ftell # 200
  140. else:
  141. raise RuntimeError("Unknown file mode '%s'" % fmode)
  142. f2.close()
  143. # write
  144. write_randomness()
  145. f = open(fname, "w")
  146. f.write("hello")
  147. f_dumped = dill.dumps(f, fmode=fmode)#, strictio=strictio)
  148. f1mode = f.mode
  149. ftell = f.tell()
  150. f.close()
  151. fstr = open(fname).read()
  152. f = open(fname, "w")
  153. f.write("h")
  154. _ftell = f.tell()
  155. f.close()
  156. if strictio: # throw error if ftell > EOF
  157. assert throws(dill.loads, (f_dumped,), buffer_error)
  158. else:
  159. f2 = dill.loads(f_dumped)
  160. f2mode = f2.mode
  161. f2tell = f2.tell()
  162. f2.write(" world!")
  163. f2.close()
  164. if fmode == dill.CONTENTS_FMODE:
  165. assert open(fname).read() == "h world!"
  166. assert f2mode == f1mode
  167. assert f2tell == _ftell
  168. elif fmode == dill.HANDLE_FMODE:
  169. assert open(fname).read() == " world!"
  170. assert f2mode == f1mode
  171. assert f2tell == 0
  172. elif fmode == dill.FILE_FMODE:
  173. assert open(fname).read() == "hello world!"
  174. assert f2mode == f1mode
  175. assert f2tell == ftell
  176. else:
  177. raise RuntimeError("Unknown file mode '%s'" % fmode)
  178. f2.close()
  179. # append
  180. trunc_file()
  181. f = open(fname, "a")
  182. f.write("hello")
  183. f_dumped = dill.dumps(f, fmode=fmode)#, strictio=strictio)
  184. f1mode = f.mode
  185. ftell = f.tell()
  186. f.close()
  187. fstr = open(fname).read()
  188. f = open(fname, "w")
  189. f.write("h")
  190. _ftell = f.tell()
  191. f.close()
  192. if strictio: # throw error if ftell > EOF
  193. assert throws(dill.loads, (f_dumped,), buffer_error)
  194. else:
  195. f2 = dill.loads(f_dumped)
  196. f2mode = f2.mode
  197. f2tell = f2.tell()
  198. f2.write(" world!")
  199. f2.close()
  200. assert f2mode == f1mode
  201. if fmode == dill.CONTENTS_FMODE:
  202. # position of writes cannot be changed on some OSs
  203. assert open(fname).read() == "h world!"
  204. assert f2tell == _ftell
  205. elif fmode == dill.HANDLE_FMODE:
  206. assert open(fname).read() == "h world!"
  207. assert f2tell == _ftell
  208. elif fmode == dill.FILE_FMODE:
  209. assert open(fname).read() == "hello world!"
  210. assert f2tell == ftell
  211. else:
  212. raise RuntimeError("Unknown file mode '%s'" % fmode)
  213. f2.close()
  214. # file does not exist
  215. # read
  216. write_randomness()
  217. f = open(fname, "r")
  218. fstr = f.read()
  219. f_dumped = dill.dumps(f, fmode=fmode)#, strictio=strictio)
  220. f1mode = f.mode
  221. ftell = f.tell()
  222. f.close()
  223. os.remove(fname)
  224. if strictio: # throw error if file DNE
  225. assert throws(dill.loads, (f_dumped,), dne_error)
  226. else:
  227. f2 = dill.loads(f_dumped)
  228. assert f2.mode == f1mode
  229. if fmode == dill.CONTENTS_FMODE:
  230. # FIXME: this fails on systems where f2.tell() always returns 0
  231. # assert f2.tell() == ftell # 200
  232. assert f2.read() == ""
  233. f2.seek(0)
  234. assert f2.read() == ""
  235. assert f2.tell() == 0
  236. elif fmode == dill.FILE_FMODE:
  237. assert f2.tell() == ftell # 200
  238. assert f2.read() == ""
  239. f2.seek(0)
  240. assert f2.read() == fstr
  241. assert f2.tell() == ftell # 200
  242. elif fmode == dill.HANDLE_FMODE:
  243. assert f2.tell() == 0
  244. assert f2.read() == ""
  245. assert f2.tell() == 0
  246. else:
  247. raise RuntimeError("Unknown file mode '%s'" % fmode)
  248. f2.close()
  249. # write
  250. write_randomness()
  251. f = open(fname, "w+")
  252. f.write("hello")
  253. f_dumped = dill.dumps(f, fmode=fmode)#, strictio=strictio)
  254. ftell = f.tell()
  255. f1mode = f.mode
  256. f.close()
  257. os.remove(fname)
  258. if strictio: # throw error if file DNE
  259. assert throws(dill.loads, (f_dumped,), dne_error)
  260. else:
  261. f2 = dill.loads(f_dumped)
  262. f2mode = f2.mode
  263. f2tell = f2.tell()
  264. f2.write(" world!")
  265. f2.close()
  266. if fmode == dill.CONTENTS_FMODE:
  267. assert open(fname).read() == " world!"
  268. assert f2mode == 'w+'
  269. assert f2tell == 0
  270. elif fmode == dill.HANDLE_FMODE:
  271. assert open(fname).read() == " world!"
  272. assert f2mode == f1mode
  273. assert f2tell == 0
  274. elif fmode == dill.FILE_FMODE:
  275. assert open(fname).read() == "hello world!"
  276. assert f2mode == f1mode
  277. assert f2tell == ftell
  278. else:
  279. raise RuntimeError("Unknown file mode '%s'" % fmode)
  280. # append
  281. trunc_file()
  282. f = open(fname, "a")
  283. f.write("hello")
  284. f_dumped = dill.dumps(f, fmode=fmode)#, strictio=strictio)
  285. ftell = f.tell()
  286. f1mode = f.mode
  287. f.close()
  288. os.remove(fname)
  289. if strictio: # throw error if file DNE
  290. assert throws(dill.loads, (f_dumped,), dne_error)
  291. else:
  292. f2 = dill.loads(f_dumped)
  293. f2mode = f2.mode
  294. f2tell = f2.tell()
  295. f2.write(" world!")
  296. f2.close()
  297. assert f2mode == f1mode
  298. if fmode == dill.CONTENTS_FMODE:
  299. assert open(fname).read() == " world!"
  300. assert f2tell == 0
  301. elif fmode == dill.HANDLE_FMODE:
  302. assert open(fname).read() == " world!"
  303. assert f2tell == 0
  304. elif fmode == dill.FILE_FMODE:
  305. assert open(fname).read() == "hello world!"
  306. assert f2tell == ftell
  307. else:
  308. raise RuntimeError("Unknown file mode '%s'" % fmode)
  309. # file exists, with different contents (larger size)
  310. # read
  311. write_randomness()
  312. f = open(fname, "r")
  313. fstr = f.read()
  314. f_dumped = dill.dumps(f, fmode=fmode)#, strictio=strictio)
  315. f1mode = f.mode
  316. ftell = f.tell()
  317. f.close()
  318. _flen = 250
  319. _fstr = write_randomness(number=_flen)
  320. # XXX: no safe_file: no way to be 'safe'?
  321. f2 = dill.loads(f_dumped)
  322. assert f2.mode == f1mode
  323. if fmode == dill.CONTENTS_FMODE:
  324. assert f2.tell() == ftell # 200
  325. assert f2.read() == _fstr[ftell:]
  326. f2.seek(0)
  327. assert f2.read() == _fstr
  328. assert f2.tell() == _flen # 250
  329. elif fmode == dill.HANDLE_FMODE:
  330. assert f2.tell() == 0
  331. assert f2.read() == _fstr
  332. assert f2.tell() == _flen # 250
  333. elif fmode == dill.FILE_FMODE:
  334. assert f2.tell() == ftell # 200
  335. assert f2.read() == ""
  336. f2.seek(0)
  337. assert f2.read() == fstr
  338. assert f2.tell() == ftell # 200
  339. else:
  340. raise RuntimeError("Unknown file mode '%s'" % fmode)
  341. f2.close() # XXX: other alternatives?
  342. # write
  343. f = open(fname, "w")
  344. f.write("hello")
  345. f_dumped = dill.dumps(f, fmode=fmode)#, strictio=strictio)
  346. f1mode = f.mode
  347. ftell = f.tell()
  348. fstr = open(fname).read()
  349. f.write(" and goodbye!")
  350. _ftell = f.tell()
  351. f.close()
  352. # XXX: no safe_file: no way to be 'safe'?
  353. f2 = dill.loads(f_dumped)
  354. f2mode = f2.mode
  355. f2tell = f2.tell()
  356. f2.write(" world!")
  357. f2.close()
  358. if fmode == dill.CONTENTS_FMODE:
  359. assert open(fname).read() == "hello world!odbye!"
  360. assert f2mode == f1mode
  361. assert f2tell == ftell
  362. elif fmode == dill.HANDLE_FMODE:
  363. assert open(fname).read() == " world!"
  364. assert f2mode == f1mode
  365. assert f2tell == 0
  366. elif fmode == dill.FILE_FMODE:
  367. assert open(fname).read() == "hello world!"
  368. assert f2mode == f1mode
  369. assert f2tell == ftell
  370. else:
  371. raise RuntimeError("Unknown file mode '%s'" % fmode)
  372. f2.close()
  373. # append
  374. trunc_file()
  375. f = open(fname, "a")
  376. f.write("hello")
  377. f_dumped = dill.dumps(f, fmode=fmode)#, strictio=strictio)
  378. f1mode = f.mode
  379. ftell = f.tell()
  380. fstr = open(fname).read()
  381. f.write(" and goodbye!")
  382. _ftell = f.tell()
  383. f.close()
  384. # XXX: no safe_file: no way to be 'safe'?
  385. f2 = dill.loads(f_dumped)
  386. f2mode = f2.mode
  387. f2tell = f2.tell()
  388. f2.write(" world!")
  389. f2.close()
  390. assert f2mode == f1mode
  391. if fmode == dill.CONTENTS_FMODE:
  392. assert open(fname).read() == "hello and goodbye! world!"
  393. assert f2tell == ftell
  394. elif fmode == dill.HANDLE_FMODE:
  395. assert open(fname).read() == "hello and goodbye! world!"
  396. assert f2tell == _ftell
  397. elif fmode == dill.FILE_FMODE:
  398. assert open(fname).read() == "hello world!"
  399. assert f2tell == ftell
  400. else:
  401. raise RuntimeError("Unknown file mode '%s'" % fmode)
  402. f2.close()
  403. def test_nostrictio_handlefmode():
  404. bench(False, dill.HANDLE_FMODE, False)
  405. teardown_module()
  406. def test_nostrictio_filefmode():
  407. bench(False, dill.FILE_FMODE, False)
  408. teardown_module()
  409. def test_nostrictio_contentsfmode():
  410. bench(False, dill.CONTENTS_FMODE, True)
  411. teardown_module()
  412. #bench(True, dill.HANDLE_FMODE, False)
  413. #bench(True, dill.FILE_FMODE, False)
  414. #bench(True, dill.CONTENTS_FMODE, True)
  415. if __name__ == '__main__':
  416. test_nostrictio_handlefmode()
  417. test_nostrictio_filefmode()
  418. test_nostrictio_contentsfmode()