tempdir.py 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. """TemporaryDirectory class, copied from Python 3
  2. This is copied from the stdlib and will be standard in Python 3.2 and onwards.
  3. """
  4. # Copyright (c) IPython Development Team.
  5. # Distributed under the terms of the Modified BSD License.
  6. from __future__ import print_function
  7. import os as _os
  8. import warnings as _warnings
  9. import sys as _sys
  10. # This code should only be used in Python versions < 3.2, since after that we
  11. # can rely on the stdlib itself.
  12. try:
  13. from tempfile import TemporaryDirectory
  14. except ImportError:
  15. from tempfile import mkdtemp, template
  16. class TemporaryDirectory(object):
  17. """Create and return a temporary directory. This has the same
  18. behavior as mkdtemp but can be used as a context manager. For
  19. example:
  20. with TemporaryDirectory() as tmpdir:
  21. ...
  22. Upon exiting the context, the directory and everthing contained
  23. in it are removed.
  24. """
  25. def __init__(self, suffix="", prefix=template, dir=None):
  26. self.name = mkdtemp(suffix, prefix, dir)
  27. self._closed = False
  28. def __enter__(self):
  29. return self.name
  30. def cleanup(self, _warn=False):
  31. if self.name and not self._closed:
  32. try:
  33. self._rmtree(self.name)
  34. except (TypeError, AttributeError) as ex:
  35. # Issue #10188: Emit a warning on stderr
  36. # if the directory could not be cleaned
  37. # up due to missing globals
  38. if "None" not in str(ex):
  39. raise
  40. print("ERROR: {!r} while cleaning up {!r}".format(ex, self,),
  41. file=_sys.stderr)
  42. return
  43. self._closed = True
  44. if _warn:
  45. self._warn("Implicitly cleaning up {!r}".format(self),
  46. Warning)
  47. def __exit__(self, exc, value, tb):
  48. self.cleanup()
  49. def __del__(self):
  50. # Issue a ResourceWarning if implicit cleanup needed
  51. self.cleanup(_warn=True)
  52. # XXX (ncoghlan): The following code attempts to make
  53. # this class tolerant of the module nulling out process
  54. # that happens during CPython interpreter shutdown
  55. # Alas, it doesn't actually manage it. See issue #10188
  56. _listdir = staticmethod(_os.listdir)
  57. _path_join = staticmethod(_os.path.join)
  58. _isdir = staticmethod(_os.path.isdir)
  59. _remove = staticmethod(_os.remove)
  60. _rmdir = staticmethod(_os.rmdir)
  61. _os_error = _os.error
  62. _warn = _warnings.warn
  63. def _rmtree(self, path):
  64. # Essentially a stripped down version of shutil.rmtree. We can't
  65. # use globals because they may be None'ed out at shutdown.
  66. for name in self._listdir(path):
  67. fullname = self._path_join(path, name)
  68. try:
  69. isdir = self._isdir(fullname)
  70. except self._os_error:
  71. isdir = False
  72. if isdir:
  73. self._rmtree(fullname)
  74. else:
  75. try:
  76. self._remove(fullname)
  77. except self._os_error:
  78. pass
  79. try:
  80. self._rmdir(path)
  81. except self._os_error:
  82. pass
  83. # extra temp-dir-related context managers
  84. class NamedFileInTemporaryDirectory(object):
  85. def __init__(self, filename, mode='w+b', bufsize=-1, **kwds):
  86. """
  87. Open a file named `filename` in a temporary directory.
  88. This context manager is preferred over `NamedTemporaryFile` in
  89. stdlib `tempfile` when one needs to reopen the file.
  90. Arguments `mode` and `bufsize` are passed to `open`.
  91. Rest of the arguments are passed to `TemporaryDirectory`.
  92. """
  93. self._tmpdir = TemporaryDirectory(**kwds)
  94. path = _os.path.join(self._tmpdir.name, filename)
  95. self.file = open(path, mode, bufsize)
  96. def cleanup(self):
  97. self.file.close()
  98. self._tmpdir.cleanup()
  99. __del__ = cleanup
  100. def __enter__(self):
  101. return self.file
  102. def __exit__(self, type, value, traceback):
  103. self.cleanup()
  104. class TemporaryWorkingDirectory(TemporaryDirectory):
  105. """
  106. Creates a temporary directory and sets the cwd to that directory.
  107. Automatically reverts to previous cwd upon cleanup.
  108. Usage example:
  109. with TemporaryWorkingDirectory() as tmpdir:
  110. ...
  111. """
  112. def __enter__(self):
  113. self.old_wd = _os.getcwd()
  114. _os.chdir(self.name)
  115. return super(TemporaryWorkingDirectory, self).__enter__()
  116. def __exit__(self, exc, value, tb):
  117. _os.chdir(self.old_wd)
  118. return super(TemporaryWorkingDirectory, self).__exit__(exc, value, tb)