os.py revision 54f0222547b1e92cd018ef132307a6f793dc9505
1r"""OS routines for Mac, DOS, NT, or Posix depending on what system we're on.
2
3This exports:
4  - all functions from posix, nt, dos, os2, mac, or ce, e.g. unlink, stat, etc.
5  - os.path is one of the modules posixpath, ntpath, macpath, or dospath
6  - os.name is 'posix', 'nt', 'dos', 'os2', 'mac', 'ce' or 'riscos'
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 ('.' or '/')
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
16Programs that import and use 'os' stand a better chance of being
17portable between different platforms.  Of course, they must then
18only use functions that are defined by all platforms (e.g., unlink
19and opendir), and leave all pathname manipulation to os.path
20(e.g., split and join).
21"""
22
23#'
24
25import sys
26
27_names = sys.builtin_module_names
28
29altsep = None
30
31__all__ = ["altsep", "curdir", "pardir", "sep", "pathsep", "linesep",
32           "defpath", "name"]
33
34def _get_exports_list(module):
35    try:
36        return list(module.__all__)
37    except AttributeError:
38        return [n for n in dir(module) if n[0] != '_']
39
40if 'posix' in _names:
41    name = 'posix'
42    linesep = '\n'
43    curdir = '.'; pardir = '..'; sep = '/'; pathsep = ':'
44    defpath = ':/bin:/usr/bin'
45    from posix import *
46    try:
47        from posix import _exit
48    except ImportError:
49        pass
50    import posixpath
51    path = posixpath
52    del posixpath
53
54    import posix
55    __all__.extend(_get_exports_list(posix))
56    del posix
57
58elif 'nt' in _names:
59    name = 'nt'
60    linesep = '\r\n'
61    curdir = '.'; pardir = '..'; sep = '\\'; pathsep = ';'
62    defpath = '.;C:\\bin'
63    from nt import *
64    for i in ['_exit']:
65        try:
66            exec "from nt import " + i
67        except ImportError:
68            pass
69    import ntpath
70    path = ntpath
71    del ntpath
72
73    import nt
74    __all__.extend(_get_exports_list(nt))
75    del nt
76
77elif 'dos' in _names:
78    name = 'dos'
79    linesep = '\r\n'
80    curdir = '.'; pardir = '..'; sep = '\\'; pathsep = ';'
81    defpath = '.;C:\\bin'
82    from dos import *
83    try:
84        from dos import _exit
85    except ImportError:
86        pass
87    import dospath
88    path = dospath
89    del dospath
90
91    import dos
92    __all__.extend(_get_exports_list(dos))
93    del dos
94
95elif 'os2' in _names:
96    name = 'os2'
97    linesep = '\r\n'
98    curdir = '.'; pardir = '..'; pathsep = ';'
99    if sys.version.find('EMX GCC') == -1:
100        # standard OS/2 compiler (VACPP or Watcom?)
101        sep = '\\'; altsep = '/'
102    else:
103        # EMX
104        sep = '/'; altsep = '\\'
105    defpath = '.;C:\\bin'
106    from os2 import *
107    try:
108        from os2 import _exit
109    except ImportError:
110        pass
111    if sys.version.find('EMX GCC') == -1:
112        import ntpath
113        path = ntpath
114        del ntpath
115    else:
116        import os2emxpath
117        path = os2emxpath
118        del os2emxpath
119
120    import os2
121    __all__.extend(_get_exports_list(os2))
122    del os2
123
124elif 'mac' in _names:
125    name = 'mac'
126    linesep = '\r'
127    curdir = ':'; pardir = '::'; sep = ':'; pathsep = '\n'
128    defpath = ':'
129    from mac import *
130    try:
131        from mac import _exit
132    except ImportError:
133        pass
134    import macpath
135    path = macpath
136    del macpath
137
138    import mac
139    __all__.extend(_get_exports_list(mac))
140    del mac
141
142elif 'ce' in _names:
143    name = 'ce'
144    linesep = '\r\n'
145    curdir = '.'; pardir = '..'; sep = '\\'; pathsep = ';'
146    defpath = '\\Windows'
147    from ce import *
148    for i in ['_exit']:
149        try:
150            exec "from ce import " + i
151        except ImportError:
152            pass
153    # We can use the standard Windows path.
154    import ntpath
155    path = ntpath
156    del ntpath
157
158    import ce
159    __all__.extend(_get_exports_list(ce))
160    del ce
161
162elif 'riscos' in _names:
163    name = 'riscos'
164    linesep = '\n'
165    curdir = '@'; pardir = '^'; sep = '.'; pathsep = ','
166    defpath = '<Run$Dir>'
167    from riscos import *
168    try:
169        from riscos import _exit
170    except ImportError:
171        pass
172    import riscospath
173    path = riscospath
174    del riscospath
175
176    import riscos
177    __all__.extend(_get_exports_list(riscos))
178    del riscos
179
180else:
181    raise ImportError, 'no os specific module found'
182
183
184if sep=='.':
185    extsep = '/'
186else:
187    extsep = '.'
188
189__all__.append("path")
190
191del _names
192
193sys.modules['os.path'] = path
194
195#'
196
197# Super directory utilities.
198# (Inspired by Eric Raymond; the doc strings are mostly his)
199
200def makedirs(name, mode=0777):
201    """makedirs(path [, mode=0777]) -> None
202
203    Super-mkdir; create a leaf directory and all intermediate ones.
204    Works like mkdir, except that any intermediate path segment (not
205    just the rightmost) will be created if it does not exist.  This is
206    recursive.
207
208    """
209    head, tail = path.split(name)
210    if not tail:
211        head, tail = path.split(head)
212    if head and tail and not path.exists(head):
213        makedirs(head, mode)
214    mkdir(name, mode)
215
216def removedirs(name):
217    """removedirs(path) -> None
218
219    Super-rmdir; remove a leaf directory and empty all intermediate
220    ones.  Works like rmdir except that, if the leaf directory is
221    successfully removed, directories corresponding to rightmost path
222    segments will be pruned way until either the whole path is
223    consumed or an error occurs.  Errors during this latter phase are
224    ignored -- they generally mean that a directory was not empty.
225
226    """
227    rmdir(name)
228    head, tail = path.split(name)
229    if not tail:
230        head, tail = path.split(head)
231    while head and tail:
232        try:
233            rmdir(head)
234        except error:
235            break
236        head, tail = path.split(head)
237
238def renames(old, new):
239    """renames(old, new) -> None
240
241    Super-rename; create directories as necessary and delete any left
242    empty.  Works like rename, except creation of any intermediate
243    directories needed to make the new pathname good is attempted
244    first.  After the rename, directories corresponding to rightmost
245    path segments of the old name will be pruned way until either the
246    whole path is consumed or a nonempty directory is found.
247
248    Note: this function can fail with the new directory structure made
249    if you lack permissions needed to unlink the leaf directory or
250    file.
251
252    """
253    head, tail = path.split(new)
254    if head and tail and not path.exists(head):
255        makedirs(head)
256    rename(old, new)
257    head, tail = path.split(old)
258    if head and tail:
259        try:
260            removedirs(head)
261        except error:
262            pass
263
264__all__.extend(["makedirs", "removedirs", "renames"])
265
266# Make sure os.environ exists, at least
267try:
268    environ
269except NameError:
270    environ = {}
271
272def execl(file, *args):
273    """execl(file, *args)
274
275    Execute the executable file with argument list args, replacing the
276    current process. """
277    execv(file, args)
278
279def execle(file, *args):
280    """execle(file, *args, env)
281
282    Execute the executable file with argument list args and
283    environment env, replacing the current process. """
284    env = args[-1]
285    execve(file, args[:-1], env)
286
287def execlp(file, *args):
288    """execlp(file, *args)
289
290    Execute the executable file (which is searched for along $PATH)
291    with argument list args, replacing the current process. """
292    execvp(file, args)
293
294def execlpe(file, *args):
295    """execlpe(file, *args, env)
296
297    Execute the executable file (which is searched for along $PATH)
298    with argument list args and environment env, replacing the current
299    process. """
300    env = args[-1]
301    execvpe(file, args[:-1], env)
302
303def execvp(file, args):
304    """execp(file, args)
305
306    Execute the executable file (which is searched for along $PATH)
307    with argument list args, replacing the current process.
308    args may be a list or tuple of strings. """
309    _execvpe(file, args)
310
311def execvpe(file, args, env):
312    """execv(file, args, env)
313
314    Execute the executable file (which is searched for along $PATH)
315    with argument list args and environment env , replacing the
316    current process.
317    args may be a list or tuple of strings. """
318    _execvpe(file, args, env)
319
320__all__.extend(["execl","execle","execlp","execlpe","execvp","execvpe"])
321
322_notfound = None
323def _execvpe(file, args, env=None):
324    if env is not None:
325        func = execve
326        argrest = (args, env)
327    else:
328        func = execv
329        argrest = (args,)
330        env = environ
331    global _notfound
332    head, tail = path.split(file)
333    if head:
334        apply(func, (file,) + argrest)
335        return
336    if 'PATH' in env:
337        envpath = env['PATH']
338    else:
339        envpath = defpath
340    PATH = envpath.split(pathsep)
341    if not _notfound:
342        if sys.platform[:4] == 'beos':
343            #  Process handling (fork, wait) under BeOS (up to 5.0)
344            #  doesn't interoperate reliably with the thread interlocking
345            #  that happens during an import.  The actual error we need
346            #  is the same on BeOS for posix.open() et al., ENOENT.
347            try: unlink('/_#.# ## #.#')
348            except error, _notfound: pass
349        else:
350            import tempfile
351            t = tempfile.mktemp()
352            # Exec a file that is guaranteed not to exist
353            try: execv(t, ('blah',))
354            except error, _notfound: pass
355    exc, arg = error, _notfound
356    for dir in PATH:
357        fullname = path.join(dir, file)
358        try:
359            apply(func, (fullname,) + argrest)
360        except error, (errno, msg):
361            if errno != arg[0]:
362                exc, arg = error, (errno, msg)
363    raise exc, arg
364
365
366# Change environ to automatically call putenv() if it exists
367try:
368    # This will fail if there's no putenv
369    putenv
370except NameError:
371    pass
372else:
373    import UserDict
374
375    # Fake unsetenv() for Windows
376    # not sure about os2 and dos here but
377    # I'm guessing they are the same.
378
379    if name in ('os2', 'nt', 'dos'):
380        def unsetenv(key):
381            putenv(key, "")
382
383    if name == "riscos":
384        # On RISC OS, all env access goes through getenv and putenv
385        from riscosenviron import _Environ
386    elif name in ('os2', 'nt', 'dos'):  # Where Env Var Names Must Be UPPERCASE
387        # But we store them as upper case
388        class _Environ(UserDict.UserDict):
389            def __init__(self, environ):
390                UserDict.UserDict.__init__(self)
391                data = self.data
392                for k, v in environ.items():
393                    data[k.upper()] = v
394            def __setitem__(self, key, item):
395                putenv(key, item)
396                self.data[key.upper()] = item
397            def __getitem__(self, key):
398                return self.data[key.upper()]
399            try:
400                unsetenv
401            except NameError:
402                def __delitem__(self, key):
403                    del self.data[key.upper()]
404            else:
405                def __delitem__(self, key):
406                    unsetenv(key)
407                    del self.data[key.upper()]
408            def has_key(self, key):
409                return key.upper() in self.data
410            def __contains__(self, key):
411                return key.upper() in self.data
412            def get(self, key, failobj=None):
413                return self.data.get(key.upper(), failobj)
414            def update(self, dict):
415                for k, v in dict.items():
416                    self[k] = v
417            def copy(self):
418                return dict(self)
419
420    else:  # Where Env Var Names Can Be Mixed Case
421        class _Environ(UserDict.UserDict):
422            def __init__(self, environ):
423                UserDict.UserDict.__init__(self)
424                self.data = environ
425            def __setitem__(self, key, item):
426                putenv(key, item)
427                self.data[key] = item
428            def update(self, dict):
429                for k, v in dict.items():
430                    self[k] = v
431            try:
432                unsetenv
433            except NameError:
434                pass
435            else:
436                def __delitem__(self, key):
437                    unsetenv(key)
438                    del self.data[key]
439            def copy(self):
440                return dict(self)
441
442
443    environ = _Environ(environ)
444
445    def getenv(key, default=None):
446        """Get an environment variable, return None if it doesn't exist.
447        The optional second argument can specify an alternate default."""
448        return environ.get(key, default)
449    __all__.append("getenv")
450
451def _exists(name):
452    try:
453        eval(name)
454        return True
455    except NameError:
456        return False
457
458# Supply spawn*() (probably only for Unix)
459if _exists("fork") and not _exists("spawnv") and _exists("execv"):
460
461    P_WAIT = 0
462    P_NOWAIT = P_NOWAITO = 1
463
464    # XXX Should we support P_DETACH?  I suppose it could fork()**2
465    # and close the std I/O streams.  Also, P_OVERLAY is the same
466    # as execv*()?
467
468    def _spawnvef(mode, file, args, env, func):
469        # Internal helper; func is the exec*() function to use
470        pid = fork()
471        if not pid:
472            # Child
473            try:
474                if env is None:
475                    func(file, args)
476                else:
477                    func(file, args, env)
478            except:
479                _exit(127)
480        else:
481            # Parent
482            if mode == P_NOWAIT:
483                return pid # Caller is responsible for waiting!
484            while 1:
485                wpid, sts = waitpid(pid, 0)
486                if WIFSTOPPED(sts):
487                    continue
488                elif WIFSIGNALED(sts):
489                    return -WTERMSIG(sts)
490                elif WIFEXITED(sts):
491                    return WEXITSTATUS(sts)
492                else:
493                    raise error, "Not stopped, signaled or exited???"
494
495    def spawnv(mode, file, args):
496        """spawnv(mode, file, args) -> integer
497
498Execute file with arguments from args in a subprocess.
499If mode == P_NOWAIT return the pid of the process.
500If mode == P_WAIT return the process's exit code if it exits normally;
501otherwise return -SIG, where SIG is the signal that killed it. """
502        return _spawnvef(mode, file, args, None, execv)
503
504    def spawnve(mode, file, args, env):
505        """spawnve(mode, file, args, env) -> integer
506
507Execute file with arguments from args in a subprocess with the
508specified environment.
509If mode == P_NOWAIT return the pid of the process.
510If mode == P_WAIT return the process's exit code if it exits normally;
511otherwise return -SIG, where SIG is the signal that killed it. """
512        return _spawnvef(mode, file, args, env, execve)
513
514    # Note: spawnvp[e] is't currently supported on Windows
515
516    def spawnvp(mode, file, args):
517        """spawnvp(mode, file, args) -> integer
518
519Execute file (which is looked for along $PATH) with arguments from
520args in a subprocess.
521If mode == P_NOWAIT return the pid of the process.
522If mode == P_WAIT return the process's exit code if it exits normally;
523otherwise return -SIG, where SIG is the signal that killed it. """
524        return _spawnvef(mode, file, args, None, execvp)
525
526    def spawnvpe(mode, file, args, env):
527        """spawnvpe(mode, file, args, env) -> integer
528
529Execute file (which is looked for along $PATH) with arguments from
530args in a subprocess with the supplied environment.
531If mode == P_NOWAIT return the pid of the process.
532If mode == P_WAIT return the process's exit code if it exits normally;
533otherwise return -SIG, where SIG is the signal that killed it. """
534        return _spawnvef(mode, file, args, env, execvpe)
535
536if _exists("spawnv"):
537    # These aren't supplied by the basic Windows code
538    # but can be easily implemented in Python
539
540    def spawnl(mode, file, *args):
541        """spawnl(mode, file, *args) -> integer
542
543Execute file with arguments from args in a subprocess.
544If mode == P_NOWAIT return the pid of the process.
545If mode == P_WAIT return the process's exit code if it exits normally;
546otherwise return -SIG, where SIG is the signal that killed it. """
547        return spawnv(mode, file, args)
548
549    def spawnle(mode, file, *args):
550        """spawnle(mode, file, *args, env) -> integer
551
552Execute file with arguments from args in a subprocess with the
553supplied environment.
554If mode == P_NOWAIT return the pid of the process.
555If mode == P_WAIT return the process's exit code if it exits normally;
556otherwise return -SIG, where SIG is the signal that killed it. """
557        env = args[-1]
558        return spawnve(mode, file, args[:-1], env)
559
560if _exists("spawnvp"):
561    # At the moment, Windows doesn't implement spawnvp[e],
562    # so it won't have spawnlp[e] either.
563    def spawnlp(mode, file, *args):
564        """spawnlp(mode, file, *args, env) -> integer
565
566Execute file (which is looked for along $PATH) with arguments from
567args in a subprocess with the supplied environment.
568If mode == P_NOWAIT return the pid of the process.
569If mode == P_WAIT return the process's exit code if it exits normally;
570otherwise return -SIG, where SIG is the signal that killed it. """
571        return spawnvp(mode, file, args)
572
573    def spawnlpe(mode, file, *args):
574        """spawnlpe(mode, file, *args, env) -> integer
575
576Execute file (which is looked for along $PATH) with arguments from
577args in a subprocess with the supplied environment.
578If mode == P_NOWAIT return the pid of the process.
579If mode == P_WAIT return the process's exit code if it exits normally;
580otherwise return -SIG, where SIG is the signal that killed it. """
581        env = args[-1]
582        return spawnvpe(mode, file, args[:-1], env)
583
584
585    __all__.extend(["spawnlp","spawnlpe","spawnv", "spawnve","spawnvp",
586                    "spawnvpe","spawnl","spawnle",])
587
588
589# Supply popen2 etc. (for Unix)
590if _exists("fork"):
591    if not _exists("popen2"):
592        def popen2(cmd, mode="t", bufsize=-1):
593            import popen2
594            stdout, stdin = popen2.popen2(cmd, bufsize)
595            return stdin, stdout
596        __all__.append("popen2")
597
598    if not _exists("popen3"):
599        def popen3(cmd, mode="t", bufsize=-1):
600            import popen2
601            stdout, stdin, stderr = popen2.popen3(cmd, bufsize)
602            return stdin, stdout, stderr
603        __all__.append("popen3")
604
605    if not _exists("popen4"):
606        def popen4(cmd, mode="t", bufsize=-1):
607            import popen2
608            stdout, stdin = popen2.popen4(cmd, bufsize)
609            return stdin, stdout
610        __all__.append("popen4")
611
612import copy_reg as _copy_reg
613
614def _make_stat_result(tup, dict):
615    return stat_result(tup, dict)
616
617def _pickle_stat_result(sr):
618    (type, args) = sr.__reduce__()
619    return (_make_stat_result, args)
620
621try:
622    _copy_reg.pickle(stat_result, _pickle_stat_result, _make_stat_result)
623except NameError: # stat_result may not exist
624    pass
625
626def _make_statvfs_result(tup, dict):
627    return statvfs_result(tup, dict)
628
629def _pickle_statvfs_result(sr):
630    (type, args) = sr.__reduce__()
631    return (_make_statvfs_result, args)
632
633try:
634    _copy_reg.pickle(statvfs_result, _pickle_statvfs_result,
635                     _make_statvfs_result)
636except NameError: # statvfs_result may not exist
637    pass
638