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