]>
Commit | Line | Data |
---|---|---|
4710c53d | 1 | """Temporary files.\r |
2 | \r | |
3 | This module provides generic, low- and high-level interfaces for\r | |
4 | creating temporary files and directories. The interfaces listed\r | |
5 | as "safe" just below can be used without fear of race conditions.\r | |
6 | Those listed as "unsafe" cannot, and are provided for backward\r | |
7 | compatibility only.\r | |
8 | \r | |
9 | This module also provides some data items to the user:\r | |
10 | \r | |
11 | TMP_MAX - maximum number of names that will be tried before\r | |
12 | giving up.\r | |
13 | template - the default prefix for all temporary names.\r | |
14 | You may change this to control the default prefix.\r | |
15 | tempdir - If this is set to a string before the first use of\r | |
16 | any routine from this module, it will be considered as\r | |
17 | another candidate location to store temporary files.\r | |
18 | """\r | |
19 | \r | |
20 | __all__ = [\r | |
21 | "NamedTemporaryFile", "TemporaryFile", # high level safe interfaces\r | |
22 | "SpooledTemporaryFile",\r | |
23 | "mkstemp", "mkdtemp", # low level safe interfaces\r | |
24 | "mktemp", # deprecated unsafe interface\r | |
25 | "TMP_MAX", "gettempprefix", # constants\r | |
26 | "tempdir", "gettempdir"\r | |
27 | ]\r | |
28 | \r | |
29 | \r | |
30 | # Imports.\r | |
31 | \r | |
32 | import os as _os\r | |
33 | import errno as _errno\r | |
34 | from random import Random as _Random\r | |
35 | \r | |
36 | try:\r | |
37 | from cStringIO import StringIO as _StringIO\r | |
38 | except ImportError:\r | |
39 | from StringIO import StringIO as _StringIO\r | |
40 | \r | |
41 | try:\r | |
42 | import fcntl as _fcntl\r | |
43 | except ImportError:\r | |
44 | def _set_cloexec(fd):\r | |
45 | pass\r | |
46 | else:\r | |
47 | def _set_cloexec(fd):\r | |
48 | try:\r | |
49 | flags = _fcntl.fcntl(fd, _fcntl.F_GETFD, 0)\r | |
50 | except IOError:\r | |
51 | pass\r | |
52 | else:\r | |
53 | # flags read successfully, modify\r | |
54 | flags |= _fcntl.FD_CLOEXEC\r | |
55 | _fcntl.fcntl(fd, _fcntl.F_SETFD, flags)\r | |
56 | \r | |
57 | \r | |
58 | try:\r | |
59 | import thread as _thread\r | |
60 | except ImportError:\r | |
61 | import dummy_thread as _thread\r | |
62 | _allocate_lock = _thread.allocate_lock\r | |
63 | \r | |
64 | _text_openflags = _os.O_RDWR | _os.O_CREAT | _os.O_EXCL\r | |
65 | if hasattr(_os, 'O_NOINHERIT'):\r | |
66 | _text_openflags |= _os.O_NOINHERIT\r | |
67 | if hasattr(_os, 'O_NOFOLLOW'):\r | |
68 | _text_openflags |= _os.O_NOFOLLOW\r | |
69 | \r | |
70 | _bin_openflags = _text_openflags\r | |
71 | if hasattr(_os, 'O_BINARY'):\r | |
72 | _bin_openflags |= _os.O_BINARY\r | |
73 | \r | |
74 | if hasattr(_os, 'TMP_MAX'):\r | |
75 | TMP_MAX = _os.TMP_MAX\r | |
76 | else:\r | |
77 | TMP_MAX = 10000\r | |
78 | \r | |
79 | template = "tmp"\r | |
80 | \r | |
81 | # Internal routines.\r | |
82 | \r | |
83 | _once_lock = _allocate_lock()\r | |
84 | \r | |
85 | if hasattr(_os, "lstat"):\r | |
86 | _stat = _os.lstat\r | |
87 | elif hasattr(_os, "stat"):\r | |
88 | _stat = _os.stat\r | |
89 | else:\r | |
90 | # Fallback. All we need is something that raises os.error if the\r | |
91 | # file doesn't exist.\r | |
92 | def _stat(fn):\r | |
93 | try:\r | |
94 | f = open(fn)\r | |
95 | except IOError:\r | |
96 | raise _os.error\r | |
97 | f.close()\r | |
98 | \r | |
99 | def _exists(fn):\r | |
100 | try:\r | |
101 | _stat(fn)\r | |
102 | except _os.error:\r | |
103 | return False\r | |
104 | else:\r | |
105 | return True\r | |
106 | \r | |
107 | class _RandomNameSequence:\r | |
108 | """An instance of _RandomNameSequence generates an endless\r | |
109 | sequence of unpredictable strings which can safely be incorporated\r | |
110 | into file names. Each string is six characters long. Multiple\r | |
111 | threads can safely use the same instance at the same time.\r | |
112 | \r | |
113 | _RandomNameSequence is an iterator."""\r | |
114 | \r | |
115 | characters = ("abcdefghijklmnopqrstuvwxyz" +\r | |
116 | "ABCDEFGHIJKLMNOPQRSTUVWXYZ" +\r | |
117 | "0123456789_")\r | |
118 | \r | |
119 | def __init__(self):\r | |
120 | self.mutex = _allocate_lock()\r | |
121 | self.rng = _Random()\r | |
122 | self.normcase = _os.path.normcase\r | |
123 | \r | |
124 | def __iter__(self):\r | |
125 | return self\r | |
126 | \r | |
127 | def next(self):\r | |
128 | m = self.mutex\r | |
129 | c = self.characters\r | |
130 | choose = self.rng.choice\r | |
131 | \r | |
132 | m.acquire()\r | |
133 | try:\r | |
134 | letters = [choose(c) for dummy in "123456"]\r | |
135 | finally:\r | |
136 | m.release()\r | |
137 | \r | |
138 | return self.normcase(''.join(letters))\r | |
139 | \r | |
140 | def _candidate_tempdir_list():\r | |
141 | """Generate a list of candidate temporary directories which\r | |
142 | _get_default_tempdir will try."""\r | |
143 | \r | |
144 | dirlist = []\r | |
145 | \r | |
146 | # First, try the environment.\r | |
147 | for envname in 'TMPDIR', 'TEMP', 'TMP':\r | |
148 | dirname = _os.getenv(envname)\r | |
149 | if dirname: dirlist.append(dirname)\r | |
150 | \r | |
151 | # Failing that, try OS-specific locations.\r | |
152 | if _os.name == 'riscos':\r | |
153 | dirname = _os.getenv('Wimp$ScrapDir')\r | |
154 | if dirname: dirlist.append(dirname)\r | |
155 | elif _os.name == 'nt':\r | |
156 | dirlist.extend([ r'c:\temp', r'c:\tmp', r'\temp', r'\tmp' ])\r | |
157 | else:\r | |
158 | dirlist.extend([ '/tmp', '/var/tmp', '/usr/tmp' ])\r | |
159 | \r | |
160 | # As a last resort, the current directory.\r | |
161 | try:\r | |
162 | dirlist.append(_os.getcwd())\r | |
163 | except (AttributeError, _os.error):\r | |
164 | dirlist.append(_os.curdir)\r | |
165 | \r | |
166 | return dirlist\r | |
167 | \r | |
168 | def _get_default_tempdir():\r | |
169 | """Calculate the default directory to use for temporary files.\r | |
170 | This routine should be called exactly once.\r | |
171 | \r | |
172 | We determine whether or not a candidate temp dir is usable by\r | |
173 | trying to create and write to a file in that directory. If this\r | |
174 | is successful, the test file is deleted. To prevent denial of\r | |
175 | service, the name of the test file must be randomized."""\r | |
176 | \r | |
177 | namer = _RandomNameSequence()\r | |
178 | dirlist = _candidate_tempdir_list()\r | |
179 | flags = _text_openflags\r | |
180 | \r | |
181 | for dir in dirlist:\r | |
182 | if dir != _os.curdir:\r | |
183 | dir = _os.path.normcase(_os.path.abspath(dir))\r | |
184 | # Try only a few names per directory.\r | |
185 | for seq in xrange(100):\r | |
186 | name = namer.next()\r | |
187 | filename = _os.path.join(dir, name)\r | |
188 | try:\r | |
189 | fd = _os.open(filename, flags, 0600)\r | |
190 | fp = _os.fdopen(fd, 'w')\r | |
191 | fp.write('blat')\r | |
192 | fp.close()\r | |
193 | _os.unlink(filename)\r | |
194 | del fp, fd\r | |
195 | return dir\r | |
196 | except (OSError, IOError), e:\r | |
197 | if e[0] != _errno.EEXIST:\r | |
198 | break # no point trying more names in this directory\r | |
199 | pass\r | |
200 | raise IOError, (_errno.ENOENT,\r | |
201 | ("No usable temporary directory found in %s" % dirlist))\r | |
202 | \r | |
203 | _name_sequence = None\r | |
204 | \r | |
205 | def _get_candidate_names():\r | |
206 | """Common setup sequence for all user-callable interfaces."""\r | |
207 | \r | |
208 | global _name_sequence\r | |
209 | if _name_sequence is None:\r | |
210 | _once_lock.acquire()\r | |
211 | try:\r | |
212 | if _name_sequence is None:\r | |
213 | _name_sequence = _RandomNameSequence()\r | |
214 | finally:\r | |
215 | _once_lock.release()\r | |
216 | return _name_sequence\r | |
217 | \r | |
218 | \r | |
219 | def _mkstemp_inner(dir, pre, suf, flags):\r | |
220 | """Code common to mkstemp, TemporaryFile, and NamedTemporaryFile."""\r | |
221 | \r | |
222 | names = _get_candidate_names()\r | |
223 | \r | |
224 | for seq in xrange(TMP_MAX):\r | |
225 | name = names.next()\r | |
226 | file = _os.path.join(dir, pre + name + suf)\r | |
227 | try:\r | |
228 | fd = _os.open(file, flags, 0600)\r | |
229 | _set_cloexec(fd)\r | |
230 | return (fd, _os.path.abspath(file))\r | |
231 | except OSError, e:\r | |
232 | if e.errno == _errno.EEXIST:\r | |
233 | continue # try again\r | |
234 | raise\r | |
235 | \r | |
236 | raise IOError, (_errno.EEXIST, "No usable temporary file name found")\r | |
237 | \r | |
238 | \r | |
239 | # User visible interfaces.\r | |
240 | \r | |
241 | def gettempprefix():\r | |
242 | """Accessor for tempdir.template."""\r | |
243 | return template\r | |
244 | \r | |
245 | tempdir = None\r | |
246 | \r | |
247 | def gettempdir():\r | |
248 | """Accessor for tempfile.tempdir."""\r | |
249 | global tempdir\r | |
250 | if tempdir is None:\r | |
251 | _once_lock.acquire()\r | |
252 | try:\r | |
253 | if tempdir is None:\r | |
254 | tempdir = _get_default_tempdir()\r | |
255 | finally:\r | |
256 | _once_lock.release()\r | |
257 | return tempdir\r | |
258 | \r | |
259 | def mkstemp(suffix="", prefix=template, dir=None, text=False):\r | |
260 | """User-callable function to create and return a unique temporary\r | |
261 | file. The return value is a pair (fd, name) where fd is the\r | |
262 | file descriptor returned by os.open, and name is the filename.\r | |
263 | \r | |
264 | If 'suffix' is specified, the file name will end with that suffix,\r | |
265 | otherwise there will be no suffix.\r | |
266 | \r | |
267 | If 'prefix' is specified, the file name will begin with that prefix,\r | |
268 | otherwise a default prefix is used.\r | |
269 | \r | |
270 | If 'dir' is specified, the file will be created in that directory,\r | |
271 | otherwise a default directory is used.\r | |
272 | \r | |
273 | If 'text' is specified and true, the file is opened in text\r | |
274 | mode. Else (the default) the file is opened in binary mode. On\r | |
275 | some operating systems, this makes no difference.\r | |
276 | \r | |
277 | The file is readable and writable only by the creating user ID.\r | |
278 | If the operating system uses permission bits to indicate whether a\r | |
279 | file is executable, the file is executable by no one. The file\r | |
280 | descriptor is not inherited by children of this process.\r | |
281 | \r | |
282 | Caller is responsible for deleting the file when done with it.\r | |
283 | """\r | |
284 | \r | |
285 | if dir is None:\r | |
286 | dir = gettempdir()\r | |
287 | \r | |
288 | if text:\r | |
289 | flags = _text_openflags\r | |
290 | else:\r | |
291 | flags = _bin_openflags\r | |
292 | \r | |
293 | return _mkstemp_inner(dir, prefix, suffix, flags)\r | |
294 | \r | |
295 | \r | |
296 | def mkdtemp(suffix="", prefix=template, dir=None):\r | |
297 | """User-callable function to create and return a unique temporary\r | |
298 | directory. The return value is the pathname of the directory.\r | |
299 | \r | |
300 | Arguments are as for mkstemp, except that the 'text' argument is\r | |
301 | not accepted.\r | |
302 | \r | |
303 | The directory is readable, writable, and searchable only by the\r | |
304 | creating user.\r | |
305 | \r | |
306 | Caller is responsible for deleting the directory when done with it.\r | |
307 | """\r | |
308 | \r | |
309 | if dir is None:\r | |
310 | dir = gettempdir()\r | |
311 | \r | |
312 | names = _get_candidate_names()\r | |
313 | \r | |
314 | for seq in xrange(TMP_MAX):\r | |
315 | name = names.next()\r | |
316 | file = _os.path.join(dir, prefix + name + suffix)\r | |
317 | try:\r | |
318 | _os.mkdir(file, 0700)\r | |
319 | return file\r | |
320 | except OSError, e:\r | |
321 | if e.errno == _errno.EEXIST:\r | |
322 | continue # try again\r | |
323 | raise\r | |
324 | \r | |
325 | raise IOError, (_errno.EEXIST, "No usable temporary directory name found")\r | |
326 | \r | |
327 | def mktemp(suffix="", prefix=template, dir=None):\r | |
328 | """User-callable function to return a unique temporary file name. The\r | |
329 | file is not created.\r | |
330 | \r | |
331 | Arguments are as for mkstemp, except that the 'text' argument is\r | |
332 | not accepted.\r | |
333 | \r | |
334 | This function is unsafe and should not be used. The file name\r | |
335 | refers to a file that did not exist at some point, but by the time\r | |
336 | you get around to creating it, someone else may have beaten you to\r | |
337 | the punch.\r | |
338 | """\r | |
339 | \r | |
340 | ## from warnings import warn as _warn\r | |
341 | ## _warn("mktemp is a potential security risk to your program",\r | |
342 | ## RuntimeWarning, stacklevel=2)\r | |
343 | \r | |
344 | if dir is None:\r | |
345 | dir = gettempdir()\r | |
346 | \r | |
347 | names = _get_candidate_names()\r | |
348 | for seq in xrange(TMP_MAX):\r | |
349 | name = names.next()\r | |
350 | file = _os.path.join(dir, prefix + name + suffix)\r | |
351 | if not _exists(file):\r | |
352 | return file\r | |
353 | \r | |
354 | raise IOError, (_errno.EEXIST, "No usable temporary filename found")\r | |
355 | \r | |
356 | \r | |
357 | class _TemporaryFileWrapper:\r | |
358 | """Temporary file wrapper\r | |
359 | \r | |
360 | This class provides a wrapper around files opened for\r | |
361 | temporary use. In particular, it seeks to automatically\r | |
362 | remove the file when it is no longer needed.\r | |
363 | """\r | |
364 | \r | |
365 | def __init__(self, file, name, delete=True):\r | |
366 | self.file = file\r | |
367 | self.name = name\r | |
368 | self.close_called = False\r | |
369 | self.delete = delete\r | |
370 | \r | |
371 | def __getattr__(self, name):\r | |
372 | # Attribute lookups are delegated to the underlying file\r | |
373 | # and cached for non-numeric results\r | |
374 | # (i.e. methods are cached, closed and friends are not)\r | |
375 | file = self.__dict__['file']\r | |
376 | a = getattr(file, name)\r | |
377 | if not issubclass(type(a), type(0)):\r | |
378 | setattr(self, name, a)\r | |
379 | return a\r | |
380 | \r | |
381 | # The underlying __enter__ method returns the wrong object\r | |
382 | # (self.file) so override it to return the wrapper\r | |
383 | def __enter__(self):\r | |
384 | self.file.__enter__()\r | |
385 | return self\r | |
386 | \r | |
387 | # NT provides delete-on-close as a primitive, so we don't need\r | |
388 | # the wrapper to do anything special. We still use it so that\r | |
389 | # file.name is useful (i.e. not "(fdopen)") with NamedTemporaryFile.\r | |
390 | if _os.name != 'nt':\r | |
391 | # Cache the unlinker so we don't get spurious errors at\r | |
392 | # shutdown when the module-level "os" is None'd out. Note\r | |
393 | # that this must be referenced as self.unlink, because the\r | |
394 | # name TemporaryFileWrapper may also get None'd out before\r | |
395 | # __del__ is called.\r | |
396 | unlink = _os.unlink\r | |
397 | \r | |
398 | def close(self):\r | |
399 | if not self.close_called:\r | |
400 | self.close_called = True\r | |
401 | self.file.close()\r | |
402 | if self.delete:\r | |
403 | self.unlink(self.name)\r | |
404 | \r | |
405 | def __del__(self):\r | |
406 | self.close()\r | |
407 | \r | |
408 | # Need to trap __exit__ as well to ensure the file gets\r | |
409 | # deleted when used in a with statement\r | |
410 | def __exit__(self, exc, value, tb):\r | |
411 | result = self.file.__exit__(exc, value, tb)\r | |
412 | self.close()\r | |
413 | return result\r | |
414 | else:\r | |
415 | def __exit__(self, exc, value, tb):\r | |
416 | self.file.__exit__(exc, value, tb)\r | |
417 | \r | |
418 | \r | |
419 | def NamedTemporaryFile(mode='w+b', bufsize=-1, suffix="",\r | |
420 | prefix=template, dir=None, delete=True):\r | |
421 | """Create and return a temporary file.\r | |
422 | Arguments:\r | |
423 | 'prefix', 'suffix', 'dir' -- as for mkstemp.\r | |
424 | 'mode' -- the mode argument to os.fdopen (default "w+b").\r | |
425 | 'bufsize' -- the buffer size argument to os.fdopen (default -1).\r | |
426 | 'delete' -- whether the file is deleted on close (default True).\r | |
427 | The file is created as mkstemp() would do it.\r | |
428 | \r | |
429 | Returns an object with a file-like interface; the name of the file\r | |
430 | is accessible as file.name. The file will be automatically deleted\r | |
431 | when it is closed unless the 'delete' argument is set to False.\r | |
432 | """\r | |
433 | \r | |
434 | if dir is None:\r | |
435 | dir = gettempdir()\r | |
436 | \r | |
437 | if 'b' in mode:\r | |
438 | flags = _bin_openflags\r | |
439 | else:\r | |
440 | flags = _text_openflags\r | |
441 | \r | |
442 | # Setting O_TEMPORARY in the flags causes the OS to delete\r | |
443 | # the file when it is closed. This is only supported by Windows.\r | |
444 | if _os.name == 'nt' and delete:\r | |
445 | flags |= _os.O_TEMPORARY\r | |
446 | \r | |
447 | (fd, name) = _mkstemp_inner(dir, prefix, suffix, flags)\r | |
448 | file = _os.fdopen(fd, mode, bufsize)\r | |
449 | return _TemporaryFileWrapper(file, name, delete)\r | |
450 | \r | |
451 | if _os.name != 'posix' or _os.sys.platform == 'cygwin':\r | |
452 | # On non-POSIX and Cygwin systems, assume that we cannot unlink a file\r | |
453 | # while it is open.\r | |
454 | TemporaryFile = NamedTemporaryFile\r | |
455 | \r | |
456 | else:\r | |
457 | def TemporaryFile(mode='w+b', bufsize=-1, suffix="",\r | |
458 | prefix=template, dir=None):\r | |
459 | """Create and return a temporary file.\r | |
460 | Arguments:\r | |
461 | 'prefix', 'suffix', 'dir' -- as for mkstemp.\r | |
462 | 'mode' -- the mode argument to os.fdopen (default "w+b").\r | |
463 | 'bufsize' -- the buffer size argument to os.fdopen (default -1).\r | |
464 | The file is created as mkstemp() would do it.\r | |
465 | \r | |
466 | Returns an object with a file-like interface. The file has no\r | |
467 | name, and will cease to exist when it is closed.\r | |
468 | """\r | |
469 | \r | |
470 | if dir is None:\r | |
471 | dir = gettempdir()\r | |
472 | \r | |
473 | if 'b' in mode:\r | |
474 | flags = _bin_openflags\r | |
475 | else:\r | |
476 | flags = _text_openflags\r | |
477 | \r | |
478 | (fd, name) = _mkstemp_inner(dir, prefix, suffix, flags)\r | |
479 | try:\r | |
480 | _os.unlink(name)\r | |
481 | return _os.fdopen(fd, mode, bufsize)\r | |
482 | except:\r | |
483 | _os.close(fd)\r | |
484 | raise\r | |
485 | \r | |
486 | class SpooledTemporaryFile:\r | |
487 | """Temporary file wrapper, specialized to switch from\r | |
488 | StringIO to a real file when it exceeds a certain size or\r | |
489 | when a fileno is needed.\r | |
490 | """\r | |
491 | _rolled = False\r | |
492 | \r | |
493 | def __init__(self, max_size=0, mode='w+b', bufsize=-1,\r | |
494 | suffix="", prefix=template, dir=None):\r | |
495 | self._file = _StringIO()\r | |
496 | self._max_size = max_size\r | |
497 | self._rolled = False\r | |
498 | self._TemporaryFileArgs = (mode, bufsize, suffix, prefix, dir)\r | |
499 | \r | |
500 | def _check(self, file):\r | |
501 | if self._rolled: return\r | |
502 | max_size = self._max_size\r | |
503 | if max_size and file.tell() > max_size:\r | |
504 | self.rollover()\r | |
505 | \r | |
506 | def rollover(self):\r | |
507 | if self._rolled: return\r | |
508 | file = self._file\r | |
509 | newfile = self._file = TemporaryFile(*self._TemporaryFileArgs)\r | |
510 | del self._TemporaryFileArgs\r | |
511 | \r | |
512 | newfile.write(file.getvalue())\r | |
513 | newfile.seek(file.tell(), 0)\r | |
514 | \r | |
515 | self._rolled = True\r | |
516 | \r | |
517 | # The method caching trick from NamedTemporaryFile\r | |
518 | # won't work here, because _file may change from a\r | |
519 | # _StringIO instance to a real file. So we list\r | |
520 | # all the methods directly.\r | |
521 | \r | |
522 | # Context management protocol\r | |
523 | def __enter__(self):\r | |
524 | if self._file.closed:\r | |
525 | raise ValueError("Cannot enter context with closed file")\r | |
526 | return self\r | |
527 | \r | |
528 | def __exit__(self, exc, value, tb):\r | |
529 | self._file.close()\r | |
530 | \r | |
531 | # file protocol\r | |
532 | def __iter__(self):\r | |
533 | return self._file.__iter__()\r | |
534 | \r | |
535 | def close(self):\r | |
536 | self._file.close()\r | |
537 | \r | |
538 | @property\r | |
539 | def closed(self):\r | |
540 | return self._file.closed\r | |
541 | \r | |
542 | @property\r | |
543 | def encoding(self):\r | |
544 | return self._file.encoding\r | |
545 | \r | |
546 | def fileno(self):\r | |
547 | self.rollover()\r | |
548 | return self._file.fileno()\r | |
549 | \r | |
550 | def flush(self):\r | |
551 | self._file.flush()\r | |
552 | \r | |
553 | def isatty(self):\r | |
554 | return self._file.isatty()\r | |
555 | \r | |
556 | @property\r | |
557 | def mode(self):\r | |
558 | return self._file.mode\r | |
559 | \r | |
560 | @property\r | |
561 | def name(self):\r | |
562 | return self._file.name\r | |
563 | \r | |
564 | @property\r | |
565 | def newlines(self):\r | |
566 | return self._file.newlines\r | |
567 | \r | |
568 | def next(self):\r | |
569 | return self._file.next\r | |
570 | \r | |
571 | def read(self, *args):\r | |
572 | return self._file.read(*args)\r | |
573 | \r | |
574 | def readline(self, *args):\r | |
575 | return self._file.readline(*args)\r | |
576 | \r | |
577 | def readlines(self, *args):\r | |
578 | return self._file.readlines(*args)\r | |
579 | \r | |
580 | def seek(self, *args):\r | |
581 | self._file.seek(*args)\r | |
582 | \r | |
583 | @property\r | |
584 | def softspace(self):\r | |
585 | return self._file.softspace\r | |
586 | \r | |
587 | def tell(self):\r | |
588 | return self._file.tell()\r | |
589 | \r | |
590 | def truncate(self):\r | |
591 | self._file.truncate()\r | |
592 | \r | |
593 | def write(self, s):\r | |
594 | file = self._file\r | |
595 | rv = file.write(s)\r | |
596 | self._check(file)\r | |
597 | return rv\r | |
598 | \r | |
599 | def writelines(self, iterable):\r | |
600 | file = self._file\r | |
601 | rv = file.writelines(iterable)\r | |
602 | self._check(file)\r | |
603 | return rv\r | |
604 | \r | |
605 | def xreadlines(self, *args):\r | |
606 | return self._file.xreadlines(*args)\r |