aboutsummaryrefslogtreecommitdiff
path: root/catapult/telemetry/third_party/pyfakefs/pyfakefs/fake_tempfile.py
blob: 090425d19fbaf0e3eeec4a9f02ccd363279c044e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
# Copyright 2010 Google Inc. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""Fake tempfile module.

Fake implementation of the python2.4.1 tempfile built-in module that works with
a FakeFilesystem object.
"""
#pylint: disable-all

import errno
import logging
import os
import stat
import tempfile

import fake_filesystem

try:
  import StringIO as io  # pylint: disable-msg=C6204
except ImportError:
  import io  # pylint: disable-msg=C6204


class FakeTempfileModule(object):
  """Uses a FakeFilesystem to provide a mock for the tempfile 2.4.1 module.

  Common usage:
  filesystem = fake_filesystem.FakeFilesystem()
  my_tempfile_module = mock_tempfile.FakeTempfileModule(filesystem)

  See also: default keyword arguments for Dependency Injection on
  http://go/tott-episode-12
  """

  def __init__(self, filesystem):
    self._filesystem = filesystem
    self._tempfile = tempfile
    self.tempdir = None  # initialized by mktemp(), others
    self._temp_prefix = 'tmp'
    self._mktemp_retvals = []

  # pylint: disable-msg=W0622
  def _TempFilename(self, suffix='', prefix=None, dir=None):
    """Create a temporary filename that does not exist.

    This is a re-implementation of how tempfile creates random filenames,
    and is probably different.

    Does not modify self._filesystem, that's your job.

    Output: self.tempdir is initialized if unset
    Args:
      suffix: filename suffix
      prefix: filename prefix
      dir: dir to put filename in
    Returns:
      string, temp filename that does not exist
    """
    if dir is None:
      dir = self._filesystem.JoinPaths(self._filesystem.root.name, 'tmp')
    filename = None
    if prefix is None:
      prefix = self._temp_prefix
    while not filename or self._filesystem.Exists(filename):
      # pylint: disable-msg=W0212
      filename = self._filesystem.JoinPaths(dir, '%s%s%s' % (
          prefix,
          next(self._tempfile._RandomNameSequence()),
          suffix))
    return filename

  # pylint: disable-msg=W0622,W0613
  def TemporaryFile(self, mode='w+b', bufsize=-1,
                    suffix='', prefix=None, dir=None):
    """Return a file-like object deleted on close().

    Python 2.4.1 tempfile.TemporaryFile.__doc__ =
    >Return a file (or file-like) object that can be used as a temporary
    >storage area. The file is created using mkstemp. It will be destroyed as
    >soon as it is closed (including an implicit close when the object is
    >garbage collected). Under Unix, the directory entry for the file is
    >removed immediately after the file is created. Other platforms do not
    >support this; your code should not rely on a temporary file created using
    >this function having or not having a visible name in the file system.
    >
    >The mode parameter defaults to 'w+b' so that the file created can be read
    >and written without being closed. Binary mode is used so that it behaves
    >consistently on all platforms without regard for the data that is stored.
    >bufsize defaults to -1, meaning that the operating system default is used.
    >
    >The dir, prefix and suffix parameters are passed to mkstemp()

    Args:
      mode: optional string, see above
      bufsize: optional int, see above
      suffix: optional string, see above
      prefix: optional string, see above
      dir: optional string, see above
    Returns:
      a file-like object.
    """
    # pylint: disable-msg=C6002
    # TODO: prefix, suffix, bufsize, dir, mode unused?
    # cannot be cStringIO due to .name requirement below
    retval = io.StringIO()
    retval.name = '<fdopen>'  # as seen on 2.4.3
    return retval

  # pylint: disable-msg=W0622,W0613
  def NamedTemporaryFile(self, mode='w+b', bufsize=-1,
                         suffix='', prefix=None, dir=None, delete=True):
    """Return a file-like object with name that is deleted on close().

    Python 2.4.1 tempfile.NamedTemporaryFile.__doc__ =
    >This function operates exactly as TemporaryFile() does, except that
    >the file is guaranteed to have a visible name in the file system. That
    >name can be retrieved from the name member of the file object.

    Args:
      mode: optional string, see above
      bufsize: optional int, see above
      suffix: optional string, see above
      prefix: optional string, see above
      dir: optional string, see above
      delete: optional bool, see above
    Returns:
      a file-like object including obj.name
    """
    # pylint: disable-msg=C6002
    # TODO: bufsiz unused?
    temp = self.mkstemp(suffix=suffix, prefix=prefix, dir=dir)
    filename = temp[1]
    mock_open = fake_filesystem.FakeFileOpen(
        self._filesystem, delete_on_close=delete)
    obj = mock_open(filename, mode)
    obj.name = filename
    return obj

  # pylint: disable-msg=C6409
  def mkstemp(self, suffix='', prefix=None, dir=None, text=False):
    """Create temp file, returning a 2-tuple: (9999, filename).

    Important: Returns 9999 instead of a real file descriptor!

    Python 2.4.1 tempfile.mkstemp.__doc__ =
    >mkstemp([suffix, [prefix, [dir, [text]]]])
    >
    >User-callable function to create and return a unique temporary file.
    >The return value is a pair (fd, name) where fd is the file descriptor
    >returned by os.open, and name is the filename.
    >
    >...[snip args]...
    >
    >The file is readable and writable only by the creating user ID.
    >If the operating system uses permission bits to indicate whether
    >a file is executable, the file is executable by no one. The file
    >descriptor is not inherited by children of this process.
    >
    >Caller is responsible for deleting the file when done with it.

    NOTE: if dir is unspecified, this call creates a directory.

    Output: self.tempdir is initialized if unset
    Args:
      suffix: optional string, filename suffix
      prefix: optional string, filename prefix
      dir: optional string, directory for temp file; must exist before call
      text: optional boolean, True = open file in text mode.
          default False = open file in binary mode.
    Returns:
      2-tuple containing
      [0] = int, file descriptor number for the file object
      [1] = string, absolute pathname of a file
    Raises:
      OSError: when dir= is specified but does not exist
    """
    # pylint: disable-msg=C6002
    # TODO: optional boolean text is unused?
    # default dir affected by "global"
    filename = self._TempEntryname(suffix, prefix, dir)
    fh = self._filesystem.CreateFile(filename, st_mode=stat.S_IFREG|0o600)
    fd = self._filesystem.AddOpenFile(fh)

    self._mktemp_retvals.append(filename)
    return (fd, filename)

  # pylint: disable-msg=C6409
  def mkdtemp(self, suffix='', prefix=None, dir=None):
    """Create temp directory, returns string, absolute pathname.

    Python 2.4.1 tempfile.mkdtemp.__doc__ =
    >mkdtemp([suffix[, prefix[, dir]]])
    >Creates a temporary directory in the most secure manner
    >possible. [...]
    >
    >The user of mkdtemp() is responsible for deleting the temporary
    >directory and its contents when done with it.
    > [...]
    >mkdtemp() returns the absolute pathname of the new directory. [...]

    Args:
      suffix: optional string, filename suffix
      prefix: optional string, filename prefix
      dir: optional string, directory for temp dir. Must exist before call
    Returns:
      string, directory name
    """
    dirname = self._TempEntryname(suffix, prefix, dir)
    self._filesystem.CreateDirectory(dirname, perm_bits=0o700)

    self._mktemp_retvals.append(dirname)
    return dirname

  def _TempEntryname(self, suffix, prefix, dir):
    """Helper function for mk[ds]temp.

    Args:
      suffix: string, filename suffix
      prefix: string, filename prefix
      dir: string, directory for temp dir. Must exist before call
    Returns:
      string, entry name
    """
    # default dir affected by "global"
    if dir is None:
      call_mkdir = True
      dir = self.gettempdir()
    else:
      call_mkdir = False

    entryname = None
    while not entryname or self._filesystem.Exists(entryname):
      entryname = self._TempFilename(suffix=suffix, prefix=prefix, dir=dir)
    if not call_mkdir:
      # This is simplistic. A bad input of suffix=/f will cause tempfile
      # to blow up, but this mock won't.  But that's already a broken
      # corner case
      parent_dir = os.path.dirname(entryname)
      try:
        self._filesystem.GetObject(parent_dir)
      except IOError as err:
        assert 'No such file or directory' in str(err)
        # python -c 'import tempfile; tempfile.mkstemp(dir="/no/such/dr")'
        # OSError: [Errno 2] No such file or directory: '/no/such/dr/tmpFBuqjO'
        raise OSError(
            errno.ENOENT,
            'No such directory in mock filesystem',
            parent_dir)
    return entryname

  # pylint: disable-msg=C6409
  def gettempdir(self):
    """Get default temp dir.  Sets default if unset."""
    if self.tempdir:
      return self.tempdir
    # pylint: disable-msg=C6002
    # TODO: environment variables TMPDIR TEMP TMP, or other dirs?
    self.tempdir = '/tmp'
    return self.tempdir

  # pylint: disable-msg=C6409
  def gettempprefix(self):
    """Get temp filename prefix.

    NOTE: This has no effect on py2.4

    Returns:
      string, prefix to use in temporary filenames
    """
    return self._temp_prefix

  # pylint: disable-msg=C6409
  def mktemp(self, suffix=''):
    """mktemp is deprecated in 2.4.1, and is thus unimplemented."""
    raise NotImplementedError

  def _SetTemplate(self, template):
    """Setter for 'template' property."""
    self._temp_prefix = template
    logging.error('tempfile.template= is a NOP in python2.4')

  def __SetTemplate(self, template):
    """Indirect setter for 'template' property."""
    self._SetTemplate(template)

  def __DeprecatedTemplate(self):
    """template property implementation."""
    raise NotImplementedError

  # reading from template is deprecated, setting is ok.
  template = property(__DeprecatedTemplate, __SetTemplate,
                      doc="""Set the prefix for temp filenames""")

  def FakeReturnedMktempValues(self):
    """For validation purposes, mktemp()'s return values are stored."""
    return self._mktemp_retvals

  def FakeMktempReset(self):
    """Clear the stored mktemp() values."""
    self._mktemp_retvals = []