OLD | NEW |
(Empty) | |
| 1 # Copyright 2010 Google Inc. All Rights Reserved. |
| 2 # |
| 3 # Licensed under the Apache License, Version 2.0 (the "License"); |
| 4 # you may not use this file except in compliance with the License. |
| 5 # You may obtain a copy of the License at |
| 6 # |
| 7 # http://www.apache.org/licenses/LICENSE-2.0 |
| 8 # |
| 9 # Unless required by applicable law or agreed to in writing, software |
| 10 # distributed under the License is distributed on an "AS IS" BASIS, |
| 11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 12 # See the License for the specific language governing permissions and |
| 13 # limitations under the License. |
| 14 |
| 15 """Fake tempfile module. |
| 16 |
| 17 Fake implementation of the python2.4.1 tempfile built-in module that works with |
| 18 a FakeFilesystem object. |
| 19 """ |
| 20 #pylint: disable-all |
| 21 |
| 22 import errno |
| 23 import logging |
| 24 import os |
| 25 import stat |
| 26 import tempfile |
| 27 |
| 28 import fake_filesystem |
| 29 |
| 30 try: |
| 31 import StringIO as io # pylint: disable-msg=C6204 |
| 32 except ImportError: |
| 33 import io # pylint: disable-msg=C6204 |
| 34 |
| 35 |
| 36 class FakeTempfileModule(object): |
| 37 """Uses a FakeFilesystem to provide a mock for the tempfile 2.4.1 module. |
| 38 |
| 39 Common usage: |
| 40 filesystem = fake_filesystem.FakeFilesystem() |
| 41 my_tempfile_module = mock_tempfile.FakeTempfileModule(filesystem) |
| 42 |
| 43 See also: default keyword arguments for Dependency Injection on |
| 44 http://go/tott-episode-12 |
| 45 """ |
| 46 |
| 47 def __init__(self, filesystem): |
| 48 self._filesystem = filesystem |
| 49 self._tempfile = tempfile |
| 50 self.tempdir = None # initialized by mktemp(), others |
| 51 self._temp_prefix = 'tmp' |
| 52 self._mktemp_retvals = [] |
| 53 |
| 54 # pylint: disable-msg=W0622 |
| 55 def _TempFilename(self, suffix='', prefix=None, dir=None): |
| 56 """Create a temporary filename that does not exist. |
| 57 |
| 58 This is a re-implementation of how tempfile creates random filenames, |
| 59 and is probably different. |
| 60 |
| 61 Does not modify self._filesystem, that's your job. |
| 62 |
| 63 Output: self.tempdir is initialized if unset |
| 64 Args: |
| 65 suffix: filename suffix |
| 66 prefix: filename prefix |
| 67 dir: dir to put filename in |
| 68 Returns: |
| 69 string, temp filename that does not exist |
| 70 """ |
| 71 if dir is None: |
| 72 dir = self._filesystem.JoinPaths(self._filesystem.root.name, 'tmp') |
| 73 filename = None |
| 74 if prefix is None: |
| 75 prefix = self._temp_prefix |
| 76 while not filename or self._filesystem.Exists(filename): |
| 77 # pylint: disable-msg=W0212 |
| 78 filename = self._filesystem.JoinPaths(dir, '%s%s%s' % ( |
| 79 prefix, |
| 80 next(self._tempfile._RandomNameSequence()), |
| 81 suffix)) |
| 82 return filename |
| 83 |
| 84 # pylint: disable-msg=W0622,W0613 |
| 85 def TemporaryFile(self, mode='w+b', bufsize=-1, |
| 86 suffix='', prefix=None, dir=None): |
| 87 """Return a file-like object deleted on close(). |
| 88 |
| 89 Python 2.4.1 tempfile.TemporaryFile.__doc__ = |
| 90 >Return a file (or file-like) object that can be used as a temporary |
| 91 >storage area. The file is created using mkstemp. It will be destroyed as |
| 92 >soon as it is closed (including an implicit close when the object is |
| 93 >garbage collected). Under Unix, the directory entry for the file is |
| 94 >removed immediately after the file is created. Other platforms do not |
| 95 >support this; your code should not rely on a temporary file created using |
| 96 >this function having or not having a visible name in the file system. |
| 97 > |
| 98 >The mode parameter defaults to 'w+b' so that the file created can be read |
| 99 >and written without being closed. Binary mode is used so that it behaves |
| 100 >consistently on all platforms without regard for the data that is stored. |
| 101 >bufsize defaults to -1, meaning that the operating system default is used. |
| 102 > |
| 103 >The dir, prefix and suffix parameters are passed to mkstemp() |
| 104 |
| 105 Args: |
| 106 mode: optional string, see above |
| 107 bufsize: optional int, see above |
| 108 suffix: optional string, see above |
| 109 prefix: optional string, see above |
| 110 dir: optional string, see above |
| 111 Returns: |
| 112 a file-like object. |
| 113 """ |
| 114 # pylint: disable-msg=C6002 |
| 115 # TODO: prefix, suffix, bufsize, dir, mode unused? |
| 116 # cannot be cStringIO due to .name requirement below |
| 117 retval = io.StringIO() |
| 118 retval.name = '<fdopen>' # as seen on 2.4.3 |
| 119 return retval |
| 120 |
| 121 # pylint: disable-msg=W0622,W0613 |
| 122 def NamedTemporaryFile(self, mode='w+b', bufsize=-1, |
| 123 suffix='', prefix=None, dir=None, delete=True): |
| 124 """Return a file-like object with name that is deleted on close(). |
| 125 |
| 126 Python 2.4.1 tempfile.NamedTemporaryFile.__doc__ = |
| 127 >This function operates exactly as TemporaryFile() does, except that |
| 128 >the file is guaranteed to have a visible name in the file system. That |
| 129 >name can be retrieved from the name member of the file object. |
| 130 |
| 131 Args: |
| 132 mode: optional string, see above |
| 133 bufsize: optional int, see above |
| 134 suffix: optional string, see above |
| 135 prefix: optional string, see above |
| 136 dir: optional string, see above |
| 137 delete: optional bool, see above |
| 138 Returns: |
| 139 a file-like object including obj.name |
| 140 """ |
| 141 # pylint: disable-msg=C6002 |
| 142 # TODO: bufsiz unused? |
| 143 temp = self.mkstemp(suffix=suffix, prefix=prefix, dir=dir) |
| 144 filename = temp[1] |
| 145 mock_open = fake_filesystem.FakeFileOpen( |
| 146 self._filesystem, delete_on_close=delete) |
| 147 obj = mock_open(filename, mode) |
| 148 obj.name = filename |
| 149 return obj |
| 150 |
| 151 # pylint: disable-msg=C6409 |
| 152 def mkstemp(self, suffix='', prefix=None, dir=None, text=False): |
| 153 """Create temp file, returning a 2-tuple: (9999, filename). |
| 154 |
| 155 Important: Returns 9999 instead of a real file descriptor! |
| 156 |
| 157 Python 2.4.1 tempfile.mkstemp.__doc__ = |
| 158 >mkstemp([suffix, [prefix, [dir, [text]]]]) |
| 159 > |
| 160 >User-callable function to create and return a unique temporary file. |
| 161 >The return value is a pair (fd, name) where fd is the file descriptor |
| 162 >returned by os.open, and name is the filename. |
| 163 > |
| 164 >...[snip args]... |
| 165 > |
| 166 >The file is readable and writable only by the creating user ID. |
| 167 >If the operating system uses permission bits to indicate whether |
| 168 >a file is executable, the file is executable by no one. The file |
| 169 >descriptor is not inherited by children of this process. |
| 170 > |
| 171 >Caller is responsible for deleting the file when done with it. |
| 172 |
| 173 NOTE: if dir is unspecified, this call creates a directory. |
| 174 |
| 175 Output: self.tempdir is initialized if unset |
| 176 Args: |
| 177 suffix: optional string, filename suffix |
| 178 prefix: optional string, filename prefix |
| 179 dir: optional string, directory for temp file; must exist before call |
| 180 text: optional boolean, True = open file in text mode. |
| 181 default False = open file in binary mode. |
| 182 Returns: |
| 183 2-tuple containing |
| 184 [0] = int, file descriptor number for the file object |
| 185 [1] = string, absolute pathname of a file |
| 186 Raises: |
| 187 OSError: when dir= is specified but does not exist |
| 188 """ |
| 189 # pylint: disable-msg=C6002 |
| 190 # TODO: optional boolean text is unused? |
| 191 # default dir affected by "global" |
| 192 filename = self._TempEntryname(suffix, prefix, dir) |
| 193 fh = self._filesystem.CreateFile(filename, st_mode=stat.S_IFREG|0o600) |
| 194 fd = self._filesystem.AddOpenFile(fh) |
| 195 |
| 196 self._mktemp_retvals.append(filename) |
| 197 return (fd, filename) |
| 198 |
| 199 # pylint: disable-msg=C6409 |
| 200 def mkdtemp(self, suffix='', prefix=None, dir=None): |
| 201 """Create temp directory, returns string, absolute pathname. |
| 202 |
| 203 Python 2.4.1 tempfile.mkdtemp.__doc__ = |
| 204 >mkdtemp([suffix[, prefix[, dir]]]) |
| 205 >Creates a temporary directory in the most secure manner |
| 206 >possible. [...] |
| 207 > |
| 208 >The user of mkdtemp() is responsible for deleting the temporary |
| 209 >directory and its contents when done with it. |
| 210 > [...] |
| 211 >mkdtemp() returns the absolute pathname of the new directory. [...] |
| 212 |
| 213 Args: |
| 214 suffix: optional string, filename suffix |
| 215 prefix: optional string, filename prefix |
| 216 dir: optional string, directory for temp dir. Must exist before call |
| 217 Returns: |
| 218 string, directory name |
| 219 """ |
| 220 dirname = self._TempEntryname(suffix, prefix, dir) |
| 221 self._filesystem.CreateDirectory(dirname, perm_bits=0o700) |
| 222 |
| 223 self._mktemp_retvals.append(dirname) |
| 224 return dirname |
| 225 |
| 226 def _TempEntryname(self, suffix, prefix, dir): |
| 227 """Helper function for mk[ds]temp. |
| 228 |
| 229 Args: |
| 230 suffix: string, filename suffix |
| 231 prefix: string, filename prefix |
| 232 dir: string, directory for temp dir. Must exist before call |
| 233 Returns: |
| 234 string, entry name |
| 235 """ |
| 236 # default dir affected by "global" |
| 237 if dir is None: |
| 238 call_mkdir = True |
| 239 dir = self.gettempdir() |
| 240 else: |
| 241 call_mkdir = False |
| 242 |
| 243 entryname = None |
| 244 while not entryname or self._filesystem.Exists(entryname): |
| 245 entryname = self._TempFilename(suffix=suffix, prefix=prefix, dir=dir) |
| 246 if not call_mkdir: |
| 247 # This is simplistic. A bad input of suffix=/f will cause tempfile |
| 248 # to blow up, but this mock won't. But that's already a broken |
| 249 # corner case |
| 250 parent_dir = os.path.dirname(entryname) |
| 251 try: |
| 252 self._filesystem.GetObject(parent_dir) |
| 253 except IOError as err: |
| 254 assert 'No such file or directory' in str(err) |
| 255 # python -c 'import tempfile; tempfile.mkstemp(dir="/no/such/dr")' |
| 256 # OSError: [Errno 2] No such file or directory: '/no/such/dr/tmpFBuqjO' |
| 257 raise OSError( |
| 258 errno.ENOENT, |
| 259 'No such directory in mock filesystem', |
| 260 parent_dir) |
| 261 return entryname |
| 262 |
| 263 # pylint: disable-msg=C6409 |
| 264 def gettempdir(self): |
| 265 """Get default temp dir. Sets default if unset.""" |
| 266 if self.tempdir: |
| 267 return self.tempdir |
| 268 # pylint: disable-msg=C6002 |
| 269 # TODO: environment variables TMPDIR TEMP TMP, or other dirs? |
| 270 self.tempdir = '/tmp' |
| 271 return self.tempdir |
| 272 |
| 273 # pylint: disable-msg=C6409 |
| 274 def gettempprefix(self): |
| 275 """Get temp filename prefix. |
| 276 |
| 277 NOTE: This has no effect on py2.4 |
| 278 |
| 279 Returns: |
| 280 string, prefix to use in temporary filenames |
| 281 """ |
| 282 return self._temp_prefix |
| 283 |
| 284 # pylint: disable-msg=C6409 |
| 285 def mktemp(self, suffix=''): |
| 286 """mktemp is deprecated in 2.4.1, and is thus unimplemented.""" |
| 287 raise NotImplementedError |
| 288 |
| 289 def _SetTemplate(self, template): |
| 290 """Setter for 'template' property.""" |
| 291 self._temp_prefix = template |
| 292 logging.error('tempfile.template= is a NOP in python2.4') |
| 293 |
| 294 def __SetTemplate(self, template): |
| 295 """Indirect setter for 'template' property.""" |
| 296 self._SetTemplate(template) |
| 297 |
| 298 def __DeprecatedTemplate(self): |
| 299 """template property implementation.""" |
| 300 raise NotImplementedError |
| 301 |
| 302 # reading from template is deprecated, setting is ok. |
| 303 template = property(__DeprecatedTemplate, __SetTemplate, |
| 304 doc="""Set the prefix for temp filenames""") |
| 305 |
| 306 def FakeReturnedMktempValues(self): |
| 307 """For validation purposes, mktemp()'s return values are stored.""" |
| 308 return self._mktemp_retvals |
| 309 |
| 310 def FakeMktempReset(self): |
| 311 """Clear the stored mktemp() values.""" |
| 312 self._mktemp_retvals = [] |
OLD | NEW |