~ubuntu-branches/ubuntu/maverick/python3.1/maverick

« back to all changes in this revision

Viewing changes to Lib/os.py

  • Committer: Bazaar Package Importer
  • Author(s): Matthias Klose
  • Date: 2009-03-23 00:01:27 UTC
  • Revision ID: james.westby@ubuntu.com-20090323000127-5fstfxju4ufrhthq
Tags: upstream-3.1~a1+20090322
ImportĀ upstreamĀ versionĀ 3.1~a1+20090322

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
r"""OS routines for Mac, NT, or Posix depending on what system we're on.
 
2
 
 
3
This exports:
 
4
  - all functions from posix, nt, os2, or ce, e.g. unlink, stat, etc.
 
5
  - os.path is either posixpath or ntpath
 
6
  - os.name is either 'posix', 'nt', 'os2' or 'ce'.
 
7
  - os.curdir is a string representing the current directory ('.' or ':')
 
8
  - os.pardir is a string representing the parent directory ('..' or '::')
 
9
  - os.sep is the (or a most common) pathname separator ('/' or ':' or '\\')
 
10
  - os.extsep is the extension separator (always '.')
 
11
  - os.altsep is the alternate pathname separator (None or '/')
 
12
  - os.pathsep is the component separator used in $PATH etc
 
13
  - os.linesep is the line separator in text files ('\r' or '\n' or '\r\n')
 
14
  - os.defpath is the default search path for executables
 
15
  - os.devnull is the file path of the null device ('/dev/null', etc.)
 
16
 
 
17
Programs that import and use 'os' stand a better chance of being
 
18
portable between different platforms.  Of course, they must then
 
19
only use functions that are defined by all platforms (e.g., unlink
 
20
and opendir), and leave all pathname manipulation to os.path
 
21
(e.g., split and join).
 
22
"""
 
23
 
 
24
#'
 
25
 
 
26
import sys, errno
 
27
 
 
28
_names = sys.builtin_module_names
 
29
 
 
30
# Note:  more names are added to __all__ later.
 
31
__all__ = ["altsep", "curdir", "pardir", "sep", "pathsep", "linesep",
 
32
           "defpath", "name", "path", "devnull",
 
33
           "SEEK_SET", "SEEK_CUR", "SEEK_END"]
 
34
 
 
35
def _get_exports_list(module):
 
36
    try:
 
37
        return list(module.__all__)
 
38
    except AttributeError:
 
39
        return [n for n in dir(module) if n[0] != '_']
 
40
 
 
41
if 'posix' in _names:
 
42
    name = 'posix'
 
43
    linesep = '\n'
 
44
    from posix import *
 
45
    try:
 
46
        from posix import _exit
 
47
    except ImportError:
 
48
        pass
 
49
    import posixpath as path
 
50
 
 
51
    import posix
 
52
    __all__.extend(_get_exports_list(posix))
 
53
    del posix
 
54
 
 
55
elif 'nt' in _names:
 
56
    name = 'nt'
 
57
    linesep = '\r\n'
 
58
    from nt import *
 
59
    try:
 
60
        from nt import _exit
 
61
    except ImportError:
 
62
        pass
 
63
    import ntpath as path
 
64
 
 
65
    import nt
 
66
    __all__.extend(_get_exports_list(nt))
 
67
    del nt
 
68
 
 
69
elif 'os2' in _names:
 
70
    name = 'os2'
 
71
    linesep = '\r\n'
 
72
    from os2 import *
 
73
    try:
 
74
        from os2 import _exit
 
75
    except ImportError:
 
76
        pass
 
77
    if sys.version.find('EMX GCC') == -1:
 
78
        import ntpath as path
 
79
    else:
 
80
        import os2emxpath as path
 
81
        from _emx_link import link
 
82
 
 
83
    import os2
 
84
    __all__.extend(_get_exports_list(os2))
 
85
    del os2
 
86
 
 
87
elif 'ce' in _names:
 
88
    name = 'ce'
 
89
    linesep = '\r\n'
 
90
    from ce import *
 
91
    try:
 
92
        from ce import _exit
 
93
    except ImportError:
 
94
        pass
 
95
    # We can use the standard Windows path.
 
96
    import ntpath as path
 
97
 
 
98
    import ce
 
99
    __all__.extend(_get_exports_list(ce))
 
100
    del ce
 
101
 
 
102
else:
 
103
    raise ImportError('no os specific module found')
 
104
 
 
105
sys.modules['os.path'] = path
 
106
from os.path import (curdir, pardir, sep, pathsep, defpath, extsep, altsep,
 
107
    devnull)
 
108
 
 
109
del _names
 
110
 
 
111
# Python uses fixed values for the SEEK_ constants; they are mapped
 
112
# to native constants if necessary in posixmodule.c
 
113
SEEK_SET = 0
 
114
SEEK_CUR = 1
 
115
SEEK_END = 2
 
116
 
 
117
#'
 
118
 
 
119
# Super directory utilities.
 
120
# (Inspired by Eric Raymond; the doc strings are mostly his)
 
121
 
 
122
def makedirs(name, mode=0o777):
 
123
    """makedirs(path [, mode=0o777])
 
124
 
 
125
    Super-mkdir; create a leaf directory and all intermediate ones.
 
126
    Works like mkdir, except that any intermediate path segment (not
 
127
    just the rightmost) will be created if it does not exist.  This is
 
128
    recursive.
 
129
 
 
130
    """
 
131
    head, tail = path.split(name)
 
132
    if not tail:
 
133
        head, tail = path.split(head)
 
134
    if head and tail and not path.exists(head):
 
135
        try:
 
136
            makedirs(head, mode)
 
137
        except OSError as e:
 
138
            # be happy if someone already created the path
 
139
            if e.errno != errno.EEXIST:
 
140
                raise
 
141
        if tail == curdir:           # xxx/newdir/. exists if xxx/newdir exists
 
142
            return
 
143
    mkdir(name, mode)
 
144
 
 
145
def removedirs(name):
 
146
    """removedirs(path)
 
147
 
 
148
    Super-rmdir; remove a leaf directory and all empty intermediate
 
149
    ones.  Works like rmdir except that, if the leaf directory is
 
150
    successfully removed, directories corresponding to rightmost path
 
151
    segments will be pruned away until either the whole path is
 
152
    consumed or an error occurs.  Errors during this latter phase are
 
153
    ignored -- they generally mean that a directory was not empty.
 
154
 
 
155
    """
 
156
    rmdir(name)
 
157
    head, tail = path.split(name)
 
158
    if not tail:
 
159
        head, tail = path.split(head)
 
160
    while head and tail:
 
161
        try:
 
162
            rmdir(head)
 
163
        except error:
 
164
            break
 
165
        head, tail = path.split(head)
 
166
 
 
167
def renames(old, new):
 
168
    """renames(old, new)
 
169
 
 
170
    Super-rename; create directories as necessary and delete any left
 
171
    empty.  Works like rename, except creation of any intermediate
 
172
    directories needed to make the new pathname good is attempted
 
173
    first.  After the rename, directories corresponding to rightmost
 
174
    path segments of the old name will be pruned way until either the
 
175
    whole path is consumed or a nonempty directory is found.
 
176
 
 
177
    Note: this function can fail with the new directory structure made
 
178
    if you lack permissions needed to unlink the leaf directory or
 
179
    file.
 
180
 
 
181
    """
 
182
    head, tail = path.split(new)
 
183
    if head and tail and not path.exists(head):
 
184
        makedirs(head)
 
185
    rename(old, new)
 
186
    head, tail = path.split(old)
 
187
    if head and tail:
 
188
        try:
 
189
            removedirs(head)
 
190
        except error:
 
191
            pass
 
192
 
 
193
__all__.extend(["makedirs", "removedirs", "renames"])
 
194
 
 
195
def walk(top, topdown=True, onerror=None, followlinks=False):
 
196
    """Directory tree generator.
 
197
 
 
198
    For each directory in the directory tree rooted at top (including top
 
199
    itself, but excluding '.' and '..'), yields a 3-tuple
 
200
 
 
201
        dirpath, dirnames, filenames
 
202
 
 
203
    dirpath is a string, the path to the directory.  dirnames is a list of
 
204
    the names of the subdirectories in dirpath (excluding '.' and '..').
 
205
    filenames is a list of the names of the non-directory files in dirpath.
 
206
    Note that the names in the lists are just names, with no path components.
 
207
    To get a full path (which begins with top) to a file or directory in
 
208
    dirpath, do os.path.join(dirpath, name).
 
209
 
 
210
    If optional arg 'topdown' is true or not specified, the triple for a
 
211
    directory is generated before the triples for any of its subdirectories
 
212
    (directories are generated top down).  If topdown is false, the triple
 
213
    for a directory is generated after the triples for all of its
 
214
    subdirectories (directories are generated bottom up).
 
215
 
 
216
    When topdown is true, the caller can modify the dirnames list in-place
 
217
    (e.g., via del or slice assignment), and walk will only recurse into the
 
218
    subdirectories whose names remain in dirnames; this can be used to prune
 
219
    the search, or to impose a specific order of visiting.  Modifying
 
220
    dirnames when topdown is false is ineffective, since the directories in
 
221
    dirnames have already been generated by the time dirnames itself is
 
222
    generated.
 
223
 
 
224
    By default errors from the os.listdir() call are ignored.  If
 
225
    optional arg 'onerror' is specified, it should be a function; it
 
226
    will be called with one argument, an os.error instance.  It can
 
227
    report the error to continue with the walk, or raise the exception
 
228
    to abort the walk.  Note that the filename is available as the
 
229
    filename attribute of the exception object.
 
230
 
 
231
    By default, os.walk does not follow symbolic links to subdirectories on
 
232
    systems that support them.  In order to get this functionality, set the
 
233
    optional argument 'followlinks' to true.
 
234
 
 
235
    Caution:  if you pass a relative pathname for top, don't change the
 
236
    current working directory between resumptions of walk.  walk never
 
237
    changes the current directory, and assumes that the client doesn't
 
238
    either.
 
239
 
 
240
    Example:
 
241
 
 
242
    import os
 
243
    from os.path import join, getsize
 
244
    for root, dirs, files in os.walk('python/Lib/email'):
 
245
        print(root, "consumes", end="")
 
246
        print(sum([getsize(join(root, name)) for name in files]), end="")
 
247
        print("bytes in", len(files), "non-directory files")
 
248
        if 'CVS' in dirs:
 
249
            dirs.remove('CVS')  # don't visit CVS directories
 
250
    """
 
251
 
 
252
    from os.path import join, isdir, islink
 
253
 
 
254
    # We may not have read permission for top, in which case we can't
 
255
    # get a list of the files the directory contains.  os.walk
 
256
    # always suppressed the exception then, rather than blow up for a
 
257
    # minor reason when (say) a thousand readable directories are still
 
258
    # left to visit.  That logic is copied here.
 
259
    try:
 
260
        # Note that listdir and error are globals in this module due
 
261
        # to earlier import-*.
 
262
        names = listdir(top)
 
263
    except error as err:
 
264
        if onerror is not None:
 
265
            onerror(err)
 
266
        return
 
267
 
 
268
    dirs, nondirs = [], []
 
269
    for name in names:
 
270
        if isdir(join(top, name)):
 
271
            dirs.append(name)
 
272
        else:
 
273
            nondirs.append(name)
 
274
 
 
275
    if topdown:
 
276
        yield top, dirs, nondirs
 
277
    for name in dirs:
 
278
        path = join(top, name)
 
279
        if followlinks or not islink(path):
 
280
            for x in walk(path, topdown, onerror, followlinks):
 
281
                yield x
 
282
    if not topdown:
 
283
        yield top, dirs, nondirs
 
284
 
 
285
__all__.append("walk")
 
286
 
 
287
# Make sure os.environ exists, at least
 
288
try:
 
289
    environ
 
290
except NameError:
 
291
    environ = {}
 
292
 
 
293
def execl(file, *args):
 
294
    """execl(file, *args)
 
295
 
 
296
    Execute the executable file with argument list args, replacing the
 
297
    current process. """
 
298
    execv(file, args)
 
299
 
 
300
def execle(file, *args):
 
301
    """execle(file, *args, env)
 
302
 
 
303
    Execute the executable file with argument list args and
 
304
    environment env, replacing the current process. """
 
305
    env = args[-1]
 
306
    execve(file, args[:-1], env)
 
307
 
 
308
def execlp(file, *args):
 
309
    """execlp(file, *args)
 
310
 
 
311
    Execute the executable file (which is searched for along $PATH)
 
312
    with argument list args, replacing the current process. """
 
313
    execvp(file, args)
 
314
 
 
315
def execlpe(file, *args):
 
316
    """execlpe(file, *args, env)
 
317
 
 
318
    Execute the executable file (which is searched for along $PATH)
 
319
    with argument list args and environment env, replacing the current
 
320
    process. """
 
321
    env = args[-1]
 
322
    execvpe(file, args[:-1], env)
 
323
 
 
324
def execvp(file, args):
 
325
    """execp(file, args)
 
326
 
 
327
    Execute the executable file (which is searched for along $PATH)
 
328
    with argument list args, replacing the current process.
 
329
    args may be a list or tuple of strings. """
 
330
    _execvpe(file, args)
 
331
 
 
332
def execvpe(file, args, env):
 
333
    """execvpe(file, args, env)
 
334
 
 
335
    Execute the executable file (which is searched for along $PATH)
 
336
    with argument list args and environment env , replacing the
 
337
    current process.
 
338
    args may be a list or tuple of strings. """
 
339
    _execvpe(file, args, env)
 
340
 
 
341
__all__.extend(["execl","execle","execlp","execlpe","execvp","execvpe"])
 
342
 
 
343
def _execvpe(file, args, env=None):
 
344
    if env is not None:
 
345
        func = execve
 
346
        argrest = (args, env)
 
347
    else:
 
348
        func = execv
 
349
        argrest = (args,)
 
350
        env = environ
 
351
 
 
352
    head, tail = path.split(file)
 
353
    if head:
 
354
        func(file, *argrest)
 
355
        return
 
356
    if 'PATH' in env:
 
357
        envpath = env['PATH']
 
358
    else:
 
359
        envpath = defpath
 
360
    PATH = envpath.split(pathsep)
 
361
    last_exc = saved_exc = None
 
362
    saved_tb = None
 
363
    for dir in PATH:
 
364
        fullname = path.join(dir, file)
 
365
        try:
 
366
            func(fullname, *argrest)
 
367
        except error as e:
 
368
            last_exc = e
 
369
            tb = sys.exc_info()[2]
 
370
            if (e.errno != errno.ENOENT and e.errno != errno.ENOTDIR
 
371
                and saved_exc is None):
 
372
                saved_exc = e
 
373
                saved_tb = tb
 
374
    if saved_exc:
 
375
        raise saved_exc.with_traceback(saved_tb)
 
376
    raise last_exc.with_traceback(tb)
 
377
 
 
378
 
 
379
# Change environ to automatically call putenv(), unsetenv if they exist.
 
380
from _abcoll import MutableMapping  # Can't use collections (bootstrap)
 
381
 
 
382
class _Environ(MutableMapping):
 
383
    def __init__(self, environ, keymap, putenv, unsetenv):
 
384
        self.keymap = keymap
 
385
        self.putenv = putenv
 
386
        self.unsetenv = unsetenv
 
387
        self.data = data = {}
 
388
        for key, value in environ.items():
 
389
            data[keymap(key)] = str(value)
 
390
    def __getitem__(self, key):
 
391
        return self.data[self.keymap(key)]
 
392
    def __setitem__(self, key, value):
 
393
        value = str(value)
 
394
        self.putenv(key, value)
 
395
        self.data[self.keymap(key)] = value
 
396
    def __delitem__(self, key):
 
397
        self.unsetenv(key)
 
398
        del self.data[self.keymap(key)]
 
399
    def __iter__(self):
 
400
        for key in self.data:
 
401
            yield key
 
402
    def __len__(self):
 
403
        return len(self.data)
 
404
    def copy(self):
 
405
        return dict(self)
 
406
    def setdefault(self, key, value):
 
407
        if key not in self:
 
408
            self[key] = value
 
409
        return self[key]
 
410
 
 
411
try:
 
412
    _putenv = putenv
 
413
except NameError:
 
414
    _putenv = lambda key, value: None
 
415
else:
 
416
    __all__.append("putenv")
 
417
 
 
418
try:
 
419
    _unsetenv = unsetenv
 
420
except NameError:
 
421
    _unsetenv = lambda key: _putenv(key, "")
 
422
else:
 
423
    __all__.append("unsetenv")
 
424
 
 
425
if name in ('os2', 'nt'): # Where Env Var Names Must Be UPPERCASE
 
426
    _keymap = lambda key: str(key.upper())
 
427
else:  # Where Env Var Names Can Be Mixed Case
 
428
    _keymap = lambda key: str(key)
 
429
 
 
430
environ = _Environ(environ, _keymap, _putenv, _unsetenv)
 
431
 
 
432
 
 
433
def getenv(key, default=None):
 
434
    """Get an environment variable, return None if it doesn't exist.
 
435
    The optional second argument can specify an alternate default."""
 
436
    return environ.get(key, default)
 
437
__all__.append("getenv")
 
438
 
 
439
def _exists(name):
 
440
    try:
 
441
        eval(name)
 
442
        return True
 
443
    except NameError:
 
444
        return False
 
445
 
 
446
# Supply spawn*() (probably only for Unix)
 
447
if _exists("fork") and not _exists("spawnv") and _exists("execv"):
 
448
 
 
449
    P_WAIT = 0
 
450
    P_NOWAIT = P_NOWAITO = 1
 
451
 
 
452
    # XXX Should we support P_DETACH?  I suppose it could fork()**2
 
453
    # and close the std I/O streams.  Also, P_OVERLAY is the same
 
454
    # as execv*()?
 
455
 
 
456
    def _spawnvef(mode, file, args, env, func):
 
457
        # Internal helper; func is the exec*() function to use
 
458
        pid = fork()
 
459
        if not pid:
 
460
            # Child
 
461
            try:
 
462
                if env is None:
 
463
                    func(file, args)
 
464
                else:
 
465
                    func(file, args, env)
 
466
            except:
 
467
                _exit(127)
 
468
        else:
 
469
            # Parent
 
470
            if mode == P_NOWAIT:
 
471
                return pid # Caller is responsible for waiting!
 
472
            while 1:
 
473
                wpid, sts = waitpid(pid, 0)
 
474
                if WIFSTOPPED(sts):
 
475
                    continue
 
476
                elif WIFSIGNALED(sts):
 
477
                    return -WTERMSIG(sts)
 
478
                elif WIFEXITED(sts):
 
479
                    return WEXITSTATUS(sts)
 
480
                else:
 
481
                    raise error("Not stopped, signaled or exited???")
 
482
 
 
483
    def spawnv(mode, file, args):
 
484
        """spawnv(mode, file, args) -> integer
 
485
 
 
486
Execute file with arguments from args in a subprocess.
 
487
If mode == P_NOWAIT return the pid of the process.
 
488
If mode == P_WAIT return the process's exit code if it exits normally;
 
489
otherwise return -SIG, where SIG is the signal that killed it. """
 
490
        return _spawnvef(mode, file, args, None, execv)
 
491
 
 
492
    def spawnve(mode, file, args, env):
 
493
        """spawnve(mode, file, args, env) -> integer
 
494
 
 
495
Execute file with arguments from args in a subprocess with the
 
496
specified environment.
 
497
If mode == P_NOWAIT return the pid of the process.
 
498
If mode == P_WAIT return the process's exit code if it exits normally;
 
499
otherwise return -SIG, where SIG is the signal that killed it. """
 
500
        return _spawnvef(mode, file, args, env, execve)
 
501
 
 
502
    # Note: spawnvp[e] is't currently supported on Windows
 
503
 
 
504
    def spawnvp(mode, file, args):
 
505
        """spawnvp(mode, file, args) -> integer
 
506
 
 
507
Execute file (which is looked for along $PATH) with arguments from
 
508
args in a subprocess.
 
509
If mode == P_NOWAIT return the pid of the process.
 
510
If mode == P_WAIT return the process's exit code if it exits normally;
 
511
otherwise return -SIG, where SIG is the signal that killed it. """
 
512
        return _spawnvef(mode, file, args, None, execvp)
 
513
 
 
514
    def spawnvpe(mode, file, args, env):
 
515
        """spawnvpe(mode, file, args, env) -> integer
 
516
 
 
517
Execute file (which is looked for along $PATH) with arguments from
 
518
args in a subprocess with the supplied environment.
 
519
If mode == P_NOWAIT return the pid of the process.
 
520
If mode == P_WAIT return the process's exit code if it exits normally;
 
521
otherwise return -SIG, where SIG is the signal that killed it. """
 
522
        return _spawnvef(mode, file, args, env, execvpe)
 
523
 
 
524
if _exists("spawnv"):
 
525
    # These aren't supplied by the basic Windows code
 
526
    # but can be easily implemented in Python
 
527
 
 
528
    def spawnl(mode, file, *args):
 
529
        """spawnl(mode, file, *args) -> integer
 
530
 
 
531
Execute file with arguments from args in a subprocess.
 
532
If mode == P_NOWAIT return the pid of the process.
 
533
If mode == P_WAIT return the process's exit code if it exits normally;
 
534
otherwise return -SIG, where SIG is the signal that killed it. """
 
535
        return spawnv(mode, file, args)
 
536
 
 
537
    def spawnle(mode, file, *args):
 
538
        """spawnle(mode, file, *args, env) -> integer
 
539
 
 
540
Execute file with arguments from args in a subprocess with the
 
541
supplied environment.
 
542
If mode == P_NOWAIT return the pid of the process.
 
543
If mode == P_WAIT return the process's exit code if it exits normally;
 
544
otherwise return -SIG, where SIG is the signal that killed it. """
 
545
        env = args[-1]
 
546
        return spawnve(mode, file, args[:-1], env)
 
547
 
 
548
 
 
549
    __all__.extend(["spawnv", "spawnve", "spawnl", "spawnle",])
 
550
 
 
551
 
 
552
if _exists("spawnvp"):
 
553
    # At the moment, Windows doesn't implement spawnvp[e],
 
554
    # so it won't have spawnlp[e] either.
 
555
    def spawnlp(mode, file, *args):
 
556
        """spawnlp(mode, file, *args) -> integer
 
557
 
 
558
Execute file (which is looked for along $PATH) with arguments from
 
559
args in a subprocess with the supplied environment.
 
560
If mode == P_NOWAIT return the pid of the process.
 
561
If mode == P_WAIT return the process's exit code if it exits normally;
 
562
otherwise return -SIG, where SIG is the signal that killed it. """
 
563
        return spawnvp(mode, file, args)
 
564
 
 
565
    def spawnlpe(mode, file, *args):
 
566
        """spawnlpe(mode, file, *args, env) -> integer
 
567
 
 
568
Execute file (which is looked for along $PATH) with arguments from
 
569
args in a subprocess with the supplied environment.
 
570
If mode == P_NOWAIT return the pid of the process.
 
571
If mode == P_WAIT return the process's exit code if it exits normally;
 
572
otherwise return -SIG, where SIG is the signal that killed it. """
 
573
        env = args[-1]
 
574
        return spawnvpe(mode, file, args[:-1], env)
 
575
 
 
576
 
 
577
    __all__.extend(["spawnvp", "spawnvpe", "spawnlp", "spawnlpe",])
 
578
 
 
579
import copyreg as _copyreg
 
580
 
 
581
def _make_stat_result(tup, dict):
 
582
    return stat_result(tup, dict)
 
583
 
 
584
def _pickle_stat_result(sr):
 
585
    (type, args) = sr.__reduce__()
 
586
    return (_make_stat_result, args)
 
587
 
 
588
try:
 
589
    _copyreg.pickle(stat_result, _pickle_stat_result, _make_stat_result)
 
590
except NameError: # stat_result may not exist
 
591
    pass
 
592
 
 
593
def _make_statvfs_result(tup, dict):
 
594
    return statvfs_result(tup, dict)
 
595
 
 
596
def _pickle_statvfs_result(sr):
 
597
    (type, args) = sr.__reduce__()
 
598
    return (_make_statvfs_result, args)
 
599
 
 
600
try:
 
601
    _copyreg.pickle(statvfs_result, _pickle_statvfs_result,
 
602
                     _make_statvfs_result)
 
603
except NameError: # statvfs_result may not exist
 
604
    pass
 
605
 
 
606
if not _exists("urandom"):
 
607
    def urandom(n):
 
608
        """urandom(n) -> str
 
609
 
 
610
        Return a string of n random bytes suitable for cryptographic use.
 
611
 
 
612
        """
 
613
        try:
 
614
            _urandomfd = open("/dev/urandom", O_RDONLY)
 
615
        except (OSError, IOError):
 
616
            raise NotImplementedError("/dev/urandom (or equivalent) not found")
 
617
        bs = b""
 
618
        while len(bs) < n:
 
619
            bs += read(_urandomfd, n - len(bs))
 
620
        close(_urandomfd)
 
621
        return bs
 
622
 
 
623
# Supply os.popen()
 
624
def popen(cmd, mode="r", buffering=None):
 
625
    if not isinstance(cmd, str):
 
626
        raise TypeError("invalid cmd type (%s, expected string)" % type(cmd))
 
627
    if mode not in ("r", "w"):
 
628
        raise ValueError("invalid mode %r" % mode)
 
629
    import subprocess, io
 
630
    if mode == "r":
 
631
        proc = subprocess.Popen(cmd,
 
632
                                shell=True,
 
633
                                stdout=subprocess.PIPE,
 
634
                                bufsize=buffering)
 
635
        return _wrap_close(io.TextIOWrapper(proc.stdout), proc)
 
636
    else:
 
637
        proc = subprocess.Popen(cmd,
 
638
                                shell=True,
 
639
                                stdin=subprocess.PIPE,
 
640
                                bufsize=buffering)
 
641
        return _wrap_close(io.TextIOWrapper(proc.stdin), proc)
 
642
 
 
643
# Helper for popen() -- a proxy for a file whose close waits for the process
 
644
class _wrap_close:
 
645
    def __init__(self, stream, proc):
 
646
        self._stream = stream
 
647
        self._proc = proc
 
648
    def close(self):
 
649
        self._stream.close()
 
650
        return self._proc.wait() << 8  # Shift left to match old behavior
 
651
    def __getattr__(self, name):
 
652
        return getattr(self._stream, name)
 
653
    def __iter__(self):
 
654
        return iter(self._stream)
 
655
 
 
656
# Supply os.fdopen()
 
657
def fdopen(fd, *args, **kwargs):
 
658
    if not isinstance(fd, int):
 
659
        raise TypeError("invalid fd type (%s, expected integer)" % type(fd))
 
660
    import io
 
661
    return io.open(fd, *args, **kwargs)