__init__.py 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263
  1. # Imports
  2. import asyncio
  3. from tempfile import (
  4. TemporaryFile as syncTemporaryFile,
  5. NamedTemporaryFile as syncNamedTemporaryFile,
  6. SpooledTemporaryFile as syncSpooledTemporaryFile,
  7. TemporaryDirectory as syncTemporaryDirectory,
  8. _TemporaryFileWrapper as syncTemporaryFileWrapper,
  9. )
  10. from io import FileIO, TextIOBase, BufferedReader, BufferedWriter, BufferedRandom
  11. from functools import partial, singledispatch
  12. from ..base import AiofilesContextManager
  13. from ..threadpool.text import AsyncTextIOWrapper
  14. from ..threadpool.binary import AsyncBufferedIOBase, AsyncBufferedReader, AsyncFileIO
  15. from .temptypes import AsyncSpooledTemporaryFile, AsyncTemporaryDirectory
  16. __all__ = [
  17. "NamedTemporaryFile",
  18. "TemporaryFile",
  19. "SpooledTemporaryFile",
  20. "TemporaryDirectory",
  21. ]
  22. # ================================================================
  23. # Public methods for async open and return of temp file/directory
  24. # objects with async interface
  25. # ================================================================
  26. def NamedTemporaryFile(
  27. mode="w+b",
  28. buffering=-1,
  29. encoding=None,
  30. newline=None,
  31. suffix=None,
  32. prefix=None,
  33. dir=None,
  34. delete=True,
  35. loop=None,
  36. executor=None,
  37. ):
  38. """Async open a named temporary file"""
  39. return AiofilesContextManager(
  40. _temporary_file(
  41. named=True,
  42. mode=mode,
  43. buffering=buffering,
  44. encoding=encoding,
  45. newline=newline,
  46. suffix=suffix,
  47. prefix=prefix,
  48. dir=dir,
  49. delete=delete,
  50. loop=loop,
  51. executor=executor,
  52. )
  53. )
  54. def TemporaryFile(
  55. mode="w+b",
  56. buffering=-1,
  57. encoding=None,
  58. newline=None,
  59. suffix=None,
  60. prefix=None,
  61. dir=None,
  62. loop=None,
  63. executor=None,
  64. ):
  65. """Async open an unnamed temporary file"""
  66. return AiofilesContextManager(
  67. _temporary_file(
  68. named=False,
  69. mode=mode,
  70. buffering=buffering,
  71. encoding=encoding,
  72. newline=newline,
  73. suffix=suffix,
  74. prefix=prefix,
  75. dir=dir,
  76. loop=loop,
  77. executor=executor,
  78. )
  79. )
  80. def SpooledTemporaryFile(
  81. max_size=0,
  82. mode="w+b",
  83. buffering=-1,
  84. encoding=None,
  85. newline=None,
  86. suffix=None,
  87. prefix=None,
  88. dir=None,
  89. loop=None,
  90. executor=None,
  91. ):
  92. """Async open a spooled temporary file"""
  93. return AiofilesContextManager(
  94. _spooled_temporary_file(
  95. max_size=max_size,
  96. mode=mode,
  97. buffering=buffering,
  98. encoding=encoding,
  99. newline=newline,
  100. suffix=suffix,
  101. prefix=prefix,
  102. dir=dir,
  103. loop=loop,
  104. executor=executor,
  105. )
  106. )
  107. def TemporaryDirectory(suffix=None, prefix=None, dir=None, loop=None, executor=None):
  108. """Async open a temporary directory"""
  109. return AiofilesContextManagerTempDir(
  110. _temporary_directory(
  111. suffix=suffix, prefix=prefix, dir=dir, loop=loop, executor=executor
  112. )
  113. )
  114. # =========================================================
  115. # Internal coroutines to open new temp files/directories
  116. # =========================================================
  117. async def _temporary_file(
  118. named=True,
  119. mode="w+b",
  120. buffering=-1,
  121. encoding=None,
  122. newline=None,
  123. suffix=None,
  124. prefix=None,
  125. dir=None,
  126. delete=True,
  127. loop=None,
  128. executor=None,
  129. max_size=0,
  130. ):
  131. """Async method to open a temporary file with async interface"""
  132. if loop is None:
  133. loop = asyncio.get_event_loop()
  134. if named:
  135. cb = partial(
  136. syncNamedTemporaryFile,
  137. mode=mode,
  138. buffering=buffering,
  139. encoding=encoding,
  140. newline=newline,
  141. suffix=suffix,
  142. prefix=prefix,
  143. dir=dir,
  144. delete=delete,
  145. )
  146. else:
  147. cb = partial(
  148. syncTemporaryFile,
  149. mode=mode,
  150. buffering=buffering,
  151. encoding=encoding,
  152. newline=newline,
  153. suffix=suffix,
  154. prefix=prefix,
  155. dir=dir,
  156. )
  157. f = await loop.run_in_executor(executor, cb)
  158. # Wrap based on type of underlying IO object
  159. if type(f) is syncTemporaryFileWrapper:
  160. # _TemporaryFileWrapper was used (named files)
  161. result = wrap(f.file, f, loop=loop, executor=executor)
  162. # add delete property
  163. result.delete = f.delete
  164. return result
  165. else:
  166. # IO object was returned directly without wrapper
  167. return wrap(f, f, loop=loop, executor=executor)
  168. async def _spooled_temporary_file(
  169. max_size=0,
  170. mode="w+b",
  171. buffering=-1,
  172. encoding=None,
  173. newline=None,
  174. suffix=None,
  175. prefix=None,
  176. dir=None,
  177. loop=None,
  178. executor=None,
  179. ):
  180. """Open a spooled temporary file with async interface"""
  181. if loop is None:
  182. loop = asyncio.get_event_loop()
  183. cb = partial(
  184. syncSpooledTemporaryFile,
  185. max_size=max_size,
  186. mode=mode,
  187. buffering=buffering,
  188. encoding=encoding,
  189. newline=newline,
  190. suffix=suffix,
  191. prefix=prefix,
  192. dir=dir,
  193. )
  194. f = await loop.run_in_executor(executor, cb)
  195. # Single interface provided by SpooledTemporaryFile for all modes
  196. return AsyncSpooledTemporaryFile(f, loop=loop, executor=executor)
  197. async def _temporary_directory(
  198. suffix=None, prefix=None, dir=None, loop=None, executor=None
  199. ):
  200. """Async method to open a temporary directory with async interface"""
  201. if loop is None:
  202. loop = asyncio.get_event_loop()
  203. cb = partial(syncTemporaryDirectory, suffix, prefix, dir)
  204. f = await loop.run_in_executor(executor, cb)
  205. return AsyncTemporaryDirectory(f, loop=loop, executor=executor)
  206. class AiofilesContextManagerTempDir(AiofilesContextManager):
  207. """With returns the directory location, not the object (matching sync lib)"""
  208. async def __aenter__(self):
  209. self._obj = await self._coro
  210. return self._obj.name
  211. @singledispatch
  212. def wrap(base_io_obj, file, *, loop=None, executor=None):
  213. """Wrap the object with interface based on type of underlying IO"""
  214. raise TypeError("Unsupported IO type: {}".format(base_io_obj))
  215. @wrap.register(TextIOBase)
  216. def _(base_io_obj, file, *, loop=None, executor=None):
  217. return AsyncTextIOWrapper(file, loop=loop, executor=executor)
  218. @wrap.register(BufferedWriter)
  219. def _(base_io_obj, file, *, loop=None, executor=None):
  220. return AsyncBufferedIOBase(file, loop=loop, executor=executor)
  221. @wrap.register(BufferedReader)
  222. @wrap.register(BufferedRandom)
  223. def _(base_io_obj, file, *, loop=None, executor=None):
  224. return AsyncBufferedReader(file, loop=loop, executor=executor)
  225. @wrap.register(FileIO)
  226. def _(base_io_obj, file, *, loop=None, executor=None):
  227. return AsyncFileIO(file, loop=loop, executor=executor)