From: <pj...@us...> - 2009-10-19 21:56:29
|
Revision: 6873 http://jython.svn.sourceforge.net/jython/?rev=6873&view=rev Author: pjenvey Date: 2009-10-19 21:56:07 +0000 (Mon, 19 Oct 2009) Log Message: ----------- move os.py -> posix.py, in prep. for separating the posix bits from it os.py from: http://svn.python.org/projects/python/branches/release26-maint/Lib/os.py@75144 Added Paths: ----------- trunk/jython/Lib/os.py trunk/jython/Lib/posix.py Removed Paths: ------------- trunk/jython/Lib/os.py trunk/jython/Lib/posix.py Deleted: trunk/jython/Lib/os.py =================================================================== --- trunk/jython/Lib/os.py 2009-10-19 21:26:09 UTC (rev 6872) +++ trunk/jython/Lib/os.py 2009-10-19 21:56:07 UTC (rev 6873) @@ -1,1166 +0,0 @@ -r"""OS routines for Java, with some attempts to support NT, and Posix -functionality. - -This exports: - - all functions from posix, nt, dos, os2, mac, or ce, e.g. unlink, stat, etc. - - os.path is one of the modules posixpath, ntpath, macpath, or dospath - - os.name is 'posix', 'nt', 'dos', 'os2', 'mac', 'ce' or 'riscos' - - os.curdir is a string representing the current directory ('.' or ':') - - os.pardir is a string representing the parent directory ('..' or '::') - - os.sep is the (or a most common) pathname separator ('/' or ':' or '\\') - - os.altsep is the alternate pathname separator (None or '/') - - os.pathsep is the component separator used in $PATH etc - - os.linesep is the line separator in text files ('\r' or '\n' or '\r\n') - - os.defpath is the default search path for executables - -Programs that import and use 'os' stand a better chance of being -portable between different platforms. Of course, they must then -only use functions that are defined by all platforms (e.g., unlink -and opendir), and leave all pathname manipulation to os.path -(e.g., split and join). -""" - -# CPython os.py __all__ -__all__ = ["altsep", "curdir", "pardir", "sep", "pathsep", "linesep", - "defpath", "name", "path", - "SEEK_SET", "SEEK_CUR", "SEEK_END"] - -# Would come from the posix/nt/etc. modules on CPython -__all__.extend(['EX_OK', 'F_OK', 'O_APPEND', 'O_CREAT', 'O_EXCL', 'O_RDONLY', - 'O_RDWR', 'O_SYNC', 'O_TRUNC', 'O_WRONLY', 'R_OK', 'SEEK_CUR', - 'SEEK_END', 'SEEK_SET', 'W_OK', 'X_OK', '_exit', 'access', - 'altsep', 'chdir', 'chmod', 'close', 'curdir', 'defpath', - 'environ', 'error', 'fdopen', 'fsync', 'getcwd', 'getcwdu', - 'getenv', 'getpid', 'isatty', 'linesep', 'listdir', 'lseek', - 'lstat', 'makedirs', 'mkdir', 'name', 'open', 'pardir', 'path', - 'pathsep', 'popen', 'popen2', 'popen3', 'popen4', 'putenv', - 'read', 'remove', 'removedirs', 'rename', 'renames', 'rmdir', - 'sep', 'stat', 'stat_result', 'strerror', 'system', 'unlink', - 'unsetenv', 'utime', 'walk', 'write']) - -import errno -import jarray -import java.lang.System -import time -import stat as _stat -import sys -from java.io import File -from org.python.core.io import FileDescriptors, FileIO, IOBase -from org.python.core.Py import newString as asPyString - -try: - from org.python.constantine.platform import Errno -except ImportError: - from com.kenai.constantine.platform import Errno - -# Mapping of: os._name: [name list, shell command list] -_os_map = dict(nt=[ - ['Windows'], - [['cmd.exe', '/c'], ['command.com', '/c']] - ], - posix=[ - [], # posix is a fallback, instead of matching names - [['/bin/sh', '-c']] - ] - ) - -def get_os_type(): - """Return the name of the type of the underlying OS. - - Returns a value suitable for the os.name variable (though not - necessarily intended to be for os.name Jython). This value may be - overwritten in the Jython registry. - """ - os_name = sys.registry.getProperty('python.os') - if os_name: - return asPyString(os_name) - - os_name = asPyString(java.lang.System.getProperty('os.name')) - os_type = None - for type, (patterns, shell_commands) in _os_map.iteritems(): - for pattern in patterns: - if os_name.startswith(pattern): - # determine the shell_command later, when it's needed: - # it requires os.path (which isn't setup yet) - return type - return 'posix' - -name = 'java' -# WARNING: _name is private: for Jython internal usage only! user code -# should *NOT* use it -_name = get_os_type() - -try: - from org.python.posix import JavaPOSIX, POSIXHandler, POSIXFactory -except ImportError: - from org.jruby.ext.posix import JavaPOSIX, POSIXHandler, POSIXFactory - -class PythonPOSIXHandler(POSIXHandler): - def error(self, error, msg): - err = getattr(errno, error.name(), None) - if err is None: - raise OSError('%s: %s' % (error, asPyString(msg))) - raise OSError(err, strerror(err), asPyString(msg)) - def unimplementedError(self, method_name): - raise NotImplementedError(method_name) - def warn(self, warning_id, msg, rest): - pass # XXX implement - def isVerbose(self): - return False - def getCurrentWorkingDirectory(self): - return File(getcwdu()) - def getEnv(self): - return ['%s=%s' % (key, val) for key, val in environ.iteritems()] - def getInputStream(self): - return getattr(java.lang.System, 'in') # XXX handle resetting - def getOutputStream(self): - return java.lang.System.out # XXX handle resetting - def getPID(self): - return 0 - def getErrorStream(self): - return java.lang.System.err # XXX handle resetting - -_posix = POSIXFactory.getPOSIX(PythonPOSIXHandler(), True) -_native_posix = not isinstance(_posix, JavaPOSIX) - -if _name == 'nt': - import ntpath as path -else: - import posixpath as path - -sys.modules['os.path'] = _path = path -from os.path import curdir, pardir, sep, pathsep, defpath, extsep, altsep, devnull -linesep = java.lang.System.getProperty('line.separator') - -# open for reading only -O_RDONLY = 0x0 -# open for writing only -O_WRONLY = 0x1 -# open for reading and writing -O_RDWR = 0x2 - -# set append mode -O_APPEND = 0x8 -# synchronous writes -O_SYNC = 0x80 - -# create if nonexistant -O_CREAT = 0x200 -# truncate to zero length -O_TRUNC = 0x400 -# error if already exists -O_EXCL = 0x800 - -# seek variables -SEEK_SET = 0 -SEEK_CUR = 1 -SEEK_END = 2 - -# test for existence of file -F_OK = 0 -# test for execute or search permission -X_OK = 1<<0 -# test for write permission -W_OK = 1<<1 -# test for read permission -R_OK = 1<<2 - -# successful termination -EX_OK = 0 - -# Java class representing the size of a time_t. internal use, lazily set -_time_t = None - -class stat_result: - - _stat_members = ( - ('st_mode', _stat.ST_MODE), - ('st_ino', _stat.ST_INO), - ('st_dev', _stat.ST_DEV), - ('st_nlink', _stat.ST_NLINK), - ('st_uid', _stat.ST_UID), - ('st_gid', _stat.ST_GID), - ('st_size', _stat.ST_SIZE), - ('st_atime', _stat.ST_ATIME), - ('st_mtime', _stat.ST_MTIME), - ('st_ctime', _stat.ST_CTIME), - ) - - def __init__(self, results): - if len(results) != 10: - raise TypeError("stat_result() takes an a 10-sequence") - for (name, index) in stat_result._stat_members: - self.__dict__[name] = results[index] - - @classmethod - def from_jnastat(cls, s): - results = [] - for meth in (s.mode, s.ino, s.dev, s.nlink, s.uid, s.gid, s.st_size, - s.atime, s.mtime, s.ctime): - try: - results.append(meth()) - except NotImplementedError: - results.append(0) - return cls(results) - - def __getitem__(self, i): - if i < 0 or i > 9: - raise IndexError(i) - return getattr(self, stat_result._stat_members[i][0]) - - def __setitem__(self, x, value): - raise TypeError("object doesn't support item assignment") - - def __setattr__(self, name, value): - if name in [x[0] for x in stat_result._stat_members]: - raise TypeError(name) - raise AttributeError("readonly attribute") - - def __len__(self): - return 10 - - def __cmp__(self, other): - if not isinstance(other, stat_result): - return 1 - return cmp(self.__dict__, other.__dict__) - - def __repr__(self): - return repr(tuple(self.__dict__[member[0]] for member - in stat_result._stat_members)) - -error = OSError - -def _exit(n=0): - """_exit(status) - - Exit to the system with specified status, without normal exit - processing. - """ - java.lang.System.exit(n) - -def getcwd(): - """getcwd() -> path - - Return a string representing the current working directory. - """ - return asPyString(sys.getCurrentWorkingDir()) - -def getcwdu(): - """getcwd() -> path - - Return a unicode string representing the current working directory. - """ - return sys.getCurrentWorkingDir() - -def chdir(path): - """chdir(path) - - Change the current working directory to the specified path. - """ - realpath = _path.realpath(path) - if not _path.exists(realpath): - raise OSError(errno.ENOENT, strerror(errno.ENOENT), path) - if not _path.isdir(realpath): - raise OSError(errno.ENOTDIR, strerror(errno.ENOTDIR), path) - sys.setCurrentWorkingDir(realpath) - -def listdir(path): - """listdir(path) -> list_of_strings - - Return a list containing the names of the entries in the directory. - - path: path of directory to list - - The list is in arbitrary order. It does not include the special - entries '.' and '..' even if they are present in the directory. - """ - l = File(sys.getPath(path)).list() - if l is None: - raise OSError(0, 'No such directory', path) - return [asPyString(entry) for entry in l] - -def chmod(path, mode): - """chmod(path, mode) - - Change the access permissions of a file. - """ - # XXX no error handling for chmod in jna-posix - # catch not found errors explicitly here, for now - abs_path = sys.getPath(path) - if not File(abs_path).exists(): - raise OSError(errno.ENOENT, strerror(errno.ENOENT), path) - _posix.chmod(abs_path, mode) - -def mkdir(path, mode='ignored'): - """mkdir(path [, mode=0777]) - - Create a directory. - - The optional parameter is currently ignored. - """ - # XXX: use _posix.mkdir when we can get the real errno upon failure - fp = File(sys.getPath(path)) - if not fp.mkdir(): - if fp.isDirectory() or fp.isFile(): - err = errno.EEXIST - else: - err = 0 - msg = strerror(err) if err else "couldn't make directory" - raise OSError(err, msg, path) - -def makedirs(path, mode='ignored'): - """makedirs(path [, mode=0777]) - - Super-mkdir; create a leaf directory and all intermediate ones. - - Works like mkdir, except that any intermediate path segment (not - just the rightmost) will be created if it does not exist. - The optional parameter is currently ignored. - """ - sys_path = sys.getPath(path) - if File(sys_path).mkdirs(): - return - - # if making a /x/y/z/., java.io.File#mkdirs inexplicably fails. So we need - # to force it - - # need to use _path instead of path, because param is hiding - # os.path module in namespace! - head, tail = _path.split(sys_path) - if tail == curdir: - if File(_path.join(head)).mkdirs(): - return - - raise OSError(0, "couldn't make directories", path) - -def remove(path): - """remove(path) - - Remove a file (same as unlink(path)). - """ - if not File(sys.getPath(path)).delete(): - raise OSError(0, "couldn't delete file", path) - -unlink = remove - -def rename(path, newpath): - """rename(old, new) - - Rename a file or directory. - """ - if not File(sys.getPath(path)).renameTo(File(sys.getPath(newpath))): - raise OSError(0, "couldn't rename file", path) - -#XXX: copied from CPython 2.5.1 -def renames(old, new): - """renames(old, new) - - Super-rename; create directories as necessary and delete any left - empty. Works like rename, except creation of any intermediate - directories needed to make the new pathname good is attempted - first. After the rename, directories corresponding to rightmost - path segments of the old name will be pruned way until either the - whole path is consumed or a nonempty directory is found. - - Note: this function can fail with the new directory structure made - if you lack permissions needed to unlink the leaf directory or - file. - - """ - head, tail = path.split(new) - if head and tail and not path.exists(head): - makedirs(head) - rename(old, new) - head, tail = path.split(old) - if head and tail: - try: - removedirs(head) - except error: - pass - -def rmdir(path): - """rmdir(path) - - Remove a directory.""" - f = File(sys.getPath(path)) - if not f.exists(): - raise OSError(errno.ENOENT, strerror(errno.ENOENT), path) - elif not f.isDirectory(): - raise OSError(errno.ENOTDIR, strerror(errno.ENOTDIR), path) - elif not f.delete(): - raise OSError(0, "couldn't delete directory", path) - -#XXX: copied from CPython 2.5.1 -def removedirs(name): - """removedirs(path) - - Super-rmdir; remove a leaf directory and empty all intermediate - ones. Works like rmdir except that, if the leaf directory is - successfully removed, directories corresponding to rightmost path - segments will be pruned away until either the whole path is - consumed or an error occurs. Errors during this latter phase are - ignored -- they generally mean that a directory was not empty. - - """ - rmdir(name) - head, tail = path.split(name) - if not tail: - head, tail = path.split(head) - while head and tail: - try: - rmdir(head) - except error: - break - head, tail = path.split(head) - -__all__.extend(['makedirs', 'renames', 'removedirs']) - -def strerror(code): - """strerror(code) -> string - - Translate an error code to a message string. - """ - if not isinstance(code, (int, long)): - raise TypeError('an integer is required') - constant = Errno.valueOf(code) - if constant is Errno.__UNKNOWN_CONSTANT__: - return 'Unknown error: %d' % code - if constant.name() == constant.description(): - # XXX: have constantine handle this fallback - # Fake constant or just lacks a description, fallback to Linux's - try: - from org.python.constantine.platform.linux import Errno as LinuxErrno - except ImportError: - from com.kenai.constantine.platform.linux import Errno as LinuxErrno - constant = getattr(LinuxErrno, constant.name(), None) - if not constant: - return 'Unknown error: %d' % code - return asPyString(constant.toString()) - -def access(path, mode): - """access(path, mode) -> True if granted, False otherwise - - Use the real uid/gid to test for access to a path. Note that most - operations will use the effective uid/gid, therefore this routine can - be used in a suid/sgid environment to test if the invoking user has the - specified access to the path. The mode argument can be F_OK to test - existence, or the inclusive-OR of R_OK, W_OK, and X_OK. - """ - if not isinstance(mode, (int, long)): - raise TypeError('an integer is required') - - f = File(sys.getPath(path)) - result = True - if not f.exists(): - result = False - if mode & R_OK and not f.canRead(): - result = False - if mode & W_OK and not f.canWrite(): - result = False - if mode & X_OK: - # NOTE: always False without jna-posix stat - try: - result = (stat(path).st_mode & _stat.S_IEXEC) != 0 - except OSError: - result = False - return result - -def stat(path): - """stat(path) -> stat result - - Perform a stat system call on the given path. - - The Java stat implementation only returns a small subset of - the standard fields: size, modification time and change time. - """ - abs_path = sys.getPath(path) - try: - return stat_result.from_jnastat(_posix.stat(abs_path)) - except NotImplementedError: - pass - f = File(abs_path) - if not f.exists(): - raise OSError(errno.ENOENT, strerror(errno.ENOENT), path) - size = f.length() - mtime = f.lastModified() / 1000.0 - mode = 0 - if f.isDirectory(): - mode = _stat.S_IFDIR - elif f.isFile(): - mode = _stat.S_IFREG - if f.canRead(): - mode = mode | _stat.S_IREAD - if f.canWrite(): - mode = mode | _stat.S_IWRITE - return stat_result((mode, 0, 0, 0, 0, 0, size, mtime, mtime, 0)) - -def lstat(path): - """lstat(path) -> stat result - - Like stat(path), but do not follow symbolic links. - """ - abs_path = sys.getPath(path) - try: - return stat_result.from_jnastat(_posix.lstat(abs_path)) - except NotImplementedError: - pass - f = File(sys.getPath(path)) - # XXX: jna-posix implements similar link detection in - # JavaFileStat.calculateSymlink, fallback to that instead when not - # native - abs_parent = f.getAbsoluteFile().getParentFile() - if not abs_parent: - # root isn't a link - return stat(path) - can_parent = abs_parent.getCanonicalFile() - - if can_parent.getAbsolutePath() == abs_parent.getAbsolutePath(): - # The parent directory's absolute path is canonical.. - if f.getAbsolutePath() != f.getCanonicalPath(): - # but the file's absolute and canonical paths differ (a - # link) - return stat_result((_stat.S_IFLNK, 0, 0, 0, 0, 0, 0, 0, 0, 0)) - - # The parent directory's path is not canonical (one of the parent - # directories is a symlink). Build a new path with the parent's - # canonical path and compare the files - f = File(_path.join(can_parent.getAbsolutePath(), f.getName())) - if f.getAbsolutePath() != f.getCanonicalPath(): - return stat_result((_stat.S_IFLNK, 0, 0, 0, 0, 0, 0, 0, 0, 0)) - - # Not a link, only now can we determine if it exists (because - # File.exists() returns False for dead links) - if not f.exists(): - raise OSError(errno.ENOENT, strerror(errno.ENOENT), path) - return stat(path) - -def utime(path, times): - """utime(path, (atime, mtime)) - utime(path, None) - - Set the access and modification time of the file to the given values. - If the second form is used, set the access and modification times to the - current time. - - Due to Java limitations, on some platforms only the modification time - may be changed. - """ - if path is None: - raise TypeError('path must be specified, not None') - - if times is None: - atimeval = mtimeval = None - elif isinstance(times, tuple) and len(times) == 2: - atimeval = _to_timeval(times[0]) - mtimeval = _to_timeval(times[1]) - else: - raise TypeError('utime() arg 2 must be a tuple (atime, mtime)') - - _posix.utimes(path, atimeval, mtimeval) - -def _to_timeval(seconds): - """Convert seconds (with a fraction) from epoch to a 2 item tuple of - seconds, microseconds from epoch as longs - """ - global _time_t - if _time_t is None: - from java.lang import Integer, Long - try: - from org.python.posix.util import Platform - except ImportError: - from org.jruby.ext.posix.util import Platform - _time_t = Integer if Platform.IS_32_BIT else Long - - try: - floor = long(seconds) - except TypeError: - raise TypeError('an integer is required') - if not _time_t.MIN_VALUE <= floor <= _time_t.MAX_VALUE: - raise OverflowError('long int too large to convert to int') - - # usec can't exceed 1000000 - usec = long((seconds - floor) * 1e6) - if usec < 0: - # If rounding gave us a negative number, truncate - usec = 0 - return floor, usec - -def close(fd): - """close(fd) - - Close a file descriptor (for low level IO). - """ - rawio = FileDescriptors.get(fd) - _handle_oserror(rawio.close) - -def fdopen(fd, mode='r', bufsize=-1): - """fdopen(fd [, mode='r' [, bufsize]]) -> file_object - - Return an open file object connected to a file descriptor. - """ - rawio = FileDescriptors.get(fd) - if (len(mode) and mode[0] or '') not in 'rwa': - raise ValueError("invalid file mode '%s'" % mode) - if rawio.closed(): - raise OSError(errno.EBADF, strerror(errno.EBADF)) - - try: - fp = FileDescriptors.wrap(rawio, mode, bufsize) - except IOError: - raise OSError(errno.EINVAL, strerror(errno.EINVAL)) - return fp - -def ftruncate(fd, length): - """ftruncate(fd, length) - - Truncate a file to a specified length. - """ - rawio = FileDescriptors.get(fd) - try: - rawio.truncate(length) - except Exception, e: - raise IOError(errno.EBADF, strerror(errno.EBADF)) - -def lseek(fd, pos, how): - """lseek(fd, pos, how) -> newpos - - Set the current position of a file descriptor. - """ - rawio = FileDescriptors.get(fd) - return _handle_oserror(rawio.seek, pos, how) - -def open(filename, flag, mode=0777): - """open(filename, flag [, mode=0777]) -> fd - - Open a file (for low level IO). - """ - reading = flag & O_RDONLY - writing = flag & O_WRONLY - updating = flag & O_RDWR - creating = flag & O_CREAT - - truncating = flag & O_TRUNC - exclusive = flag & O_EXCL - sync = flag & O_SYNC - appending = flag & O_APPEND - - if updating and writing: - raise OSError(errno.EINVAL, strerror(errno.EINVAL), filename) - - if not creating and not path.exists(filename): - raise OSError(errno.ENOENT, strerror(errno.ENOENT), filename) - - if not writing: - if updating: - writing = True - else: - reading = True - - if truncating and not writing: - # Explicitly truncate, writing will truncate anyway - FileIO(filename, 'w').close() - - if exclusive and creating: - try: - if not File(sys.getPath(filename)).createNewFile(): - raise OSError(errno.EEXIST, strerror(errno.EEXIST), - filename) - except java.io.IOException, ioe: - raise OSError(ioe) - - mode = '%s%s%s%s' % (reading and 'r' or '', - (not appending and writing) and 'w' or '', - (appending and (writing or updating)) and 'a' or '', - updating and '+' or '') - - if sync and (writing or updating): - from java.io import FileNotFoundException, RandomAccessFile - try: - fchannel = RandomAccessFile(sys.getPath(filename), 'rws').getChannel() - except FileNotFoundException, fnfe: - if path.isdir(filename): - raise OSError(errno.EISDIR, strerror(errno.EISDIR)) - raise OSError(errno.ENOENT, strerror(errno.ENOENT), filename) - return FileIO(fchannel, mode) - - return FileIO(filename, mode) - -def read(fd, buffersize): - """read(fd, buffersize) -> string - - Read a file descriptor. - """ - from org.python.core.util import StringUtil - rawio = FileDescriptors.get(fd) - buf = _handle_oserror(rawio.read, buffersize) - return asPyString(StringUtil.fromBytes(buf)) - -def write(fd, string): - """write(fd, string) -> byteswritten - - Write a string to a file descriptor. - """ - from java.nio import ByteBuffer - from org.python.core.util import StringUtil - rawio = FileDescriptors.get(fd) - return _handle_oserror(rawio.write, - ByteBuffer.wrap(StringUtil.toBytes(string))) - -def _handle_oserror(func, *args, **kwargs): - """Translate exceptions into OSErrors""" - try: - return func(*args, **kwargs) - except: - raise OSError(errno.EBADF, strerror(errno.EBADF)) - -def system(command): - """system(command) -> exit_status - - Execute the command (a string) in a subshell. - """ - import subprocess - return subprocess.call(command, shell=True) - -def popen(command, mode='r', bufsize=-1): - """popen(command [, mode='r' [, bufsize]]) -> pipe - - Open a pipe to/from a command returning a file object. - """ - import subprocess - if mode == 'r': - proc = subprocess.Popen(command, bufsize=bufsize, shell=True, - stdout=subprocess.PIPE) - return _wrap_close(proc.stdout, proc) - elif mode == 'w': - proc = subprocess.Popen(command, bufsize=bufsize, shell=True, - stdin=subprocess.PIPE) - return _wrap_close(proc.stdin, proc) - else: - raise OSError(errno.EINVAL, strerror(errno.EINVAL)) - -# Helper for popen() -- a proxy for a file whose close waits for the process -class _wrap_close(object): - def __init__(self, stream, proc): - self._stream = stream - self._proc = proc - def close(self): - self._stream.close() - returncode = self._proc.wait() - if returncode == 0: - return None - if _name == 'nt': - return returncode - else: - return returncode - def __getattr__(self, name): - return getattr(self._stream, name) - def __iter__(self): - return iter(self._stream) - -# os module versions of the popen# methods have different return value -# order than popen2 functions - -def popen2(cmd, mode="t", bufsize=-1): - """Execute the shell command cmd in a sub-process. - - On UNIX, 'cmd' may be a sequence, in which case arguments will be - passed directly to the program without shell intervention (as with - os.spawnv()). If 'cmd' is a string it will be passed to the shell - (as with os.system()). If 'bufsize' is specified, it sets the - buffer size for the I/O pipes. The file objects (child_stdin, - child_stdout) are returned. - """ - import popen2 - stdout, stdin = popen2.popen2(cmd, bufsize) - return stdin, stdout - -def popen3(cmd, mode="t", bufsize=-1): - """Execute the shell command 'cmd' in a sub-process. - - On UNIX, 'cmd' may be a sequence, in which case arguments will be - passed directly to the program without shell intervention - (as with os.spawnv()). If 'cmd' is a string it will be passed - to the shell (as with os.system()). If 'bufsize' is specified, - it sets the buffer size for the I/O pipes. The file objects - (child_stdin, child_stdout, child_stderr) are returned. - """ - import popen2 - stdout, stdin, stderr = popen2.popen3(cmd, bufsize) - return stdin, stdout, stderr - -def popen4(cmd, mode="t", bufsize=-1): - """Execute the shell command 'cmd' in a sub-process. - - On UNIX, 'cmd' may be a sequence, in which case arguments will be - passed directly to the program without shell intervention - (as with os.spawnv()). If 'cmd' is a string it will be passed - to the shell (as with os.system()). If 'bufsize' is specified, - it sets the buffer size for the I/O pipes. The file objects - (child_stdin, child_stdout_stderr) are returned. - """ - import popen2 - stdout, stdin = popen2.popen4(cmd, bufsize) - return stdin, stdout - -def getlogin(): - """getlogin() -> string - - Return the actual login name. - """ - return java.lang.System.getProperty("user.name") - -#XXX: copied from CPython's release23-maint branch revision 56502 -def walk(top, topdown=True, onerror=None): - """Directory tree generator. - - For each directory in the directory tree rooted at top (including top - itself, but excluding '.' and '..'), yields a 3-tuple - - dirpath, dirnames, filenames - - dirpath is a string, the path to the directory. dirnames is a list of - the names of the subdirectories in dirpath (excluding '.' and '..'). - filenames is a list of the names of the non-directory files in dirpath. - Note that the names in the lists are just names, with no path components. - To get a full path (which begins with top) to a file or directory in - dirpath, do os.path.join(dirpath, name). - - If optional arg 'topdown' is true or not specified, the triple for a - directory is generated before the triples for any of its subdirectories - (directories are generated top down). If topdown is false, the triple - for a directory is generated after the triples for all of its - subdirectories (directories are generated bottom up). - - When topdown is true, the caller can modify the dirnames list in-place - (e.g., via del or slice assignment), and walk will only recurse into the - subdirectories whose names remain in dirnames; this can be used to prune - the search, or to impose a specific order of visiting. Modifying - dirnames when topdown is false is ineffective, since the directories in - dirnames have already been generated by the time dirnames itself is - generated. - - By default errors from the os.listdir() call are ignored. If - optional arg 'onerror' is specified, it should be a function; it - will be called with one argument, an os.error instance. It can - report the error to continue with the walk, or raise the exception - to abort the walk. Note that the filename is available as the - filename attribute of the exception object. - - Caution: if you pass a relative pathname for top, don't change the - current working directory between resumptions of walk. walk never - changes the current directory, and assumes that the client doesn't - either. - - Example: - - from os.path import join, getsize - for root, dirs, files in walk('python/Lib/email'): - print root, "consumes", - print sum([getsize(join(root, name)) for name in files]), - print "bytes in", len(files), "non-directory files" - if 'CVS' in dirs: - dirs.remove('CVS') # don't visit CVS directories - """ - - from os.path import join, isdir, islink - - # We may not have read permission for top, in which case we can't - # get a list of the files the directory contains. os.path.walk - # always suppressed the exception then, rather than blow up for a - # minor reason when (say) a thousand readable directories are still - # left to visit. That logic is copied here. - try: - # Note that listdir and error are globals in this module due - # to earlier import-*. - names = listdir(top) - except error, err: - if onerror is not None: - onerror(err) - return - - dirs, nondirs = [], [] - for name in names: - if isdir(join(top, name)): - dirs.append(name) - else: - nondirs.append(name) - - if topdown: - yield top, dirs, nondirs - for name in dirs: - path = join(top, name) - if not islink(path): - for x in walk(path, topdown, onerror): - yield x - if not topdown: - yield top, dirs, nondirs - -__all__.append("walk") - -environ = sys.getEnviron() - -if _name in ('os2', 'nt'): # Where Env Var Names Must Be UPPERCASE - import UserDict - - # But we store them as upper case - class _Environ(UserDict.IterableUserDict): - def __init__(self, environ): - UserDict.UserDict.__init__(self) - data = self.data - for k, v in environ.items(): - data[k.upper()] = v - def __setitem__(self, key, item): - self.data[key.upper()] = item - def __getitem__(self, key): - return self.data[key.upper()] - def __delitem__(self, key): - del self.data[key.upper()] - def has_key(self, key): - return key.upper() in self.data - def __contains__(self, key): - return key.upper() in self.data - def get(self, key, failobj=None): - return self.data.get(key.upper(), failobj) - def update(self, dict=None, **kwargs): - if dict: - try: - keys = dict.keys() - except AttributeError: - # List of (key, value) - for k, v in dict: - self[k] = v - else: - # got keys - # cannot use items(), since mappings - # may not have them. - for k in keys: - self[k] = dict[k] - if kwargs: - self.update(kwargs) - def copy(self): - return dict(self) - - environ = _Environ(environ) - -def putenv(key, value): - """putenv(key, value) - - Change or add an environment variable. - """ - environ[key] = value - -def unsetenv(key): - """unsetenv(key) - - Delete an environment variable. - """ - if key in environ: - del environ[key] - -def getenv(key, default=None): - """Get an environment variable, return None if it doesn't exist. - The optional second argument can specify an alternate default.""" - return environ.get(key, default) - -if _name == 'posix': - def link(src, dst): - """link(src, dst) - - Create a hard link to a file. - """ - _posix.link(sys.getPath(src), sys.getPath(dst)) - - def symlink(src, dst): - """symlink(src, dst) - - Create a symbolic link pointing to src named dst. - """ - _posix.symlink(src, sys.getPath(dst)) - - def readlink(path): - """readlink(path) -> path - - Return a string representing the path to which the symbolic link - points. - """ - return _posix.readlink(sys.getPath(path)) - - def getegid(): - """getegid() -> egid - - Return the current process's effective group id.""" - return _posix.getegid() - - def geteuid(): - """geteuid() -> euid - - Return the current process's effective user id.""" - return _posix.geteuid() - - def getgid(): - """getgid() -> gid - - Return the current process's group id.""" - return _posix.getgid() - - def getlogin(): - """getlogin() -> string - - Return the actual login name.""" - return _posix.getlogin() - - def getpgrp(): - """getpgrp() -> pgrp - - Return the current process group id.""" - return _posix.getpgrp() - - def getppid(): - """getppid() -> ppid - - Return the parent's process id.""" - return _posix.getppid() - - def getuid(): - """getuid() -> uid - - Return the current process's user id.""" - return _posix.getuid() - - def setpgrp(): - """setpgrp() - - Make this process a session leader.""" - return _posix.setpgrp() - - def setsid(): - """setsid() - - Call the system call setsid().""" - return _posix.setsid() - - # This implementation of fork partially works on - # Jython. Diagnosing what works, what doesn't, and fixing it is - # left for another day. In any event, this would only be - # marginally useful. - - # def fork(): - # """fork() -> pid - # - # Fork a child process. - # Return 0 to child process and PID of child to parent process.""" - # return _posix.fork() - - def kill(pid, sig): - """kill(pid, sig) - - Kill a process with a signal.""" - return _posix.kill(pid, sig) - - def wait(): - """wait() -> (pid, status) - - Wait for completion of a child process.""" - - status = jarray.zeros(1, 'i') - res_pid = _posix.wait(status) - if res_pid == -1: - raise OSError(status[0], strerror(status[0])) - return res_pid, status[0] - - def waitpid(pid, options): - """waitpid(pid, options) -> (pid, status) - - Wait for completion of a given child process.""" - status = jarray.zeros(1, 'i') - res_pid = _posix.waitpid(pid, status, options) - if res_pid == -1: - raise OSError(status[0], strerror(status[0])) - return res_pid, status[0] - - def fdatasync(fd): - """fdatasync(fildes) - - force write of file with filedescriptor to disk. - does not force update of metadata. - """ - _fsync(fd, False) - - __all__.extend(['link', 'symlink', 'readlink', 'getegid', 'geteuid', - 'getgid', 'getlogin', 'getpgrp', 'getppid', 'getuid', - 'setpgrp', 'setsid', 'kill', 'wait', 'waitpid', - 'fdatasync']) - -def fsync(fd): - """fsync(fildes) - - force write of file with filedescriptor to disk. - """ - _fsync(fd, True) - -def _fsync(fd, metadata): - """Internal fsync impl""" - rawio = FileDescriptors.get(fd) - rawio.checkClosed() - - from java.nio.channels import FileChannel - channel = rawio.getChannel() - if not isinstance(channel, FileChannel): - raise OSError(errno.EINVAL, strerror(errno.EINVAL)) - - try: - channel.force(metadata) - except java.io.IOException, ioe: - raise OSError(ioe) - -def getpid(): - """getpid() -> pid - - Return the current process id.""" - return _posix.getpid() - -def isatty(fileno): - """isatty(fd) -> bool - - Return True if the file descriptor 'fd' is an open file descriptor - connected to the slave end of a terminal.""" - from java.io import FileDescriptor - - if isinstance(fileno, int): - if fileno == 0: - fd = getattr(FileDescriptor, 'in') - elif fileno == 1: - fd = FileDescriptor.out - elif fileno == 2: - fd = FileDescriptor.err - else: - raise NotImplemented('Integer file descriptor compatibility only ' - 'available for stdin, stdout and stderr (0-2)') - - return _posix.isatty(fd) - - if isinstance(fileno, FileDescriptor): - return _posix.isatty(fileno) - - if not isinstance(fileno, IOBase): - raise TypeError('a file descriptor is required') - - return fileno.isatty() - -def umask(new_mask): - """umask(new_mask) -> old_mask - - Set the current numeric umask and return the previous umask.""" - return _posix.umask(int(new_mask)) - - -from java.security import SecureRandom -urandom_source = None - -def urandom(n): - global urandom_source - if urandom_source is None: - urandom_source = SecureRandom() - buffer = jarray.zeros(n, 'b') - urandom_source.nextBytes(buffer) - return buffer.tostring() Added: trunk/jython/Lib/os.py =================================================================== --- trunk/jython/Lib/os.py (rev 0) +++ trunk/jython/Lib/os.py 2009-10-19 21:56:07 UTC (rev 6873) @@ -0,0 +1,763 @@ +r"""OS routines for Mac, NT, or Posix depending on what system we're on. + +This exports: + - all functions from posix, nt, os2, or ce, e.g. unlink, stat, etc. + - os.path is one of the modules posixpath, or ntpath + - os.name is 'posix', 'nt', 'os2', 'ce' or 'riscos' + - os.curdir is a string representing the current directory ('.' or ':') + - os.pardir is a string representing the parent directory ('..' or '::') + - os.sep is the (or a most common) pathname separator ('/' or ':' or '\\') + - os.extsep is the extension separator ('.' or '/') + - os.altsep is the alternate pathname separator (None or '/') + - os.pathsep is the component separator used in $PATH etc + - os.linesep is the line separator in text files ('\r' or '\n' or '\r\n') + - os.defpath is the default search path for executables + - os.devnull is the file path of the null device ('/dev/null', etc.) + +Programs that import and use 'os' stand a better chance of being +portable between different platforms. Of course, they must then +only use functions that are defined by all platforms (e.g., unlink +and opendir), and leave all pathname manipulation to os.path +(e.g., split and join). +""" + +#' + +import sys, errno + +_names = sys.builtin_module_names + +# Note: more names are added to __all__ later. +__all__ = ["altsep", "curdir", "pardir", "sep", "extsep", "pathsep", "linesep", + "defpath", "name", "path", "devnull", + "SEEK_SET", "SEEK_CUR", "SEEK_END"] + +def _get_exports_list(module): + try: + return list(module.__all__) + except AttributeError: + return [n for n in dir(module) if n[0] != '_'] + +if 'posix' in _names: + name = 'posix' + linesep = '\n' + from posix import * + try: + from posix import _exit + except ImportError: + pass + import posixpath as path + + import posix + __all__.extend(_get_exports_list(posix)) + del posix + +elif 'nt' in _names: + name = 'nt' + linesep = '\r\n' + from nt import * + try: + from nt import _exit + except ImportError: + pass + import ntpath as path + + import nt + __all__.extend(_get_exports_list(nt)) + del nt + +elif 'os2' in _names: + name = 'os2' + linesep = '\r\n' + from os2 import * + try: + from os2 import _exit + except ImportError: + pass + if sys.version.find('EMX GCC') == -1: + import ntpath as path + else: + import os2emxpath as path + from _emx_link import link + + import os2 + __all__.extend(_get_exports_list(os2)) + del os2 + +elif 'ce' in _names: + name = 'ce' + linesep = '\r\n' + from ce import * + try: + from ce import _exit + except ImportError: + pass + # We can use the standard Windows path. + import ntpath as path + + import ce + __all__.extend(_get_exports_list(ce)) + del ce + +elif 'riscos' in _names: + name = 'riscos' + linesep = '\n' + from riscos import * + try: + from riscos import _exit + except ImportError: + pass + import riscospath as path + + import riscos + __all__.extend(_get_exports_list(riscos)) + del riscos + +else: + raise ImportError, 'no os specific module found' + +sys.modules['os.path'] = path +from os.path import (curdir, pardir, sep, pathsep, defpath, extsep, altsep, + devnull) + +del _names + +# Python uses fixed values for the SEEK_ constants; they are mapped +# to native constants if necessary in posixmodule.c +SEEK_SET = 0 +SEEK_CUR = 1 +SEEK_END = 2 + +#' + +# Super directory utilities. +# (Inspired by Eric Raymond; the doc strings are mostly his) + +def makedirs(name, mode=0777): + """makedirs(path [, mode=0777]) + + Super-mkdir; create a leaf directory and all intermediate ones. + Works like mkdir, except that any intermediate path segment (not + just the rightmost) will be created if it does not exist. This is + recursive. + + """ + head, tail = path.split(name) + if not tail: + head, tail = path.split(head) + if head and tail and not path.exists(head): + try: + makedirs(head, mode) + except OSError, e: + # be happy if someone already created the path + if e.errno != errno.EEXIST: + raise + if tail == curdir: # xxx/newdir/. exists if xxx/newdir exists + return + mkdir(name, mode) + +def removedirs(name): + """removedirs(path) + + Super-rmdir; remove a leaf directory and all empty intermediate + ones. Works like rmdir except that, if the leaf directory is + successfully removed, directories corresponding to rightmost path + segments will be pruned away until either the whole path is + consumed or an error occurs. Errors during this latter phase are + ignored -- they generally mean that a directory was not empty. + + """ + rmdir(name) + head, tail = path.split(name) + if not tail: + head, tail = path.split(head) + while head and tail: + try: + rmdir(head) + except error: + break + head, tail = path.split(head) + +def renames(old, new): + """renames(old, new) + + Super-rename; create directories as necessary and delete any left + empty. Works like rename, except creation of any intermediate + directories needed to make the new pathname good is attempted + first. After the rename, directories corresponding to rightmost + path segments of the old name will be pruned way until either the + whole path is consumed or a nonempty directory is found. + + Note: this function can fail with the new directory structure made + if you lack permissions needed to unlink the leaf directory or + file. + + """ + head, tail = path.split(new) + if head and tail and not path.exists(head): + makedirs(head) + rename(old, new) + head, tail = path.split(old) + if head and tail: + try: + removedirs(head) + except error: + pass + +__all__.extend(["makedirs", "removedirs", "renames"]) + +def walk(top, topdown=True, onerror=None, followlinks=False): + """Directory tree generator. + + For each directory in the directory tree rooted at top (including top + itself, but excluding '.' and '..'), yields a 3-tuple + + dirpath, dirnames, filenames + + dirpath is a string, the path to the directory. dirnames is a list of + the names of the subdirectories in dirpath (excluding '.' and '..'). + filenames is a list of the names of the non-directory files in dirpath. + Note that the names in the lists are just names, with no path components. + To get a full path (which begins with top) to a file or directory in + dirpath, do os.path.join(dirpath, name). + + If optional arg 'topdown' is true or not specified, the triple for a + directory is generated before the triples for any of its subdirectories + (directories are generated top down). If topdown is false, the triple + for a directory is generated after the triples for all of its + subdirectories (directories are generated bottom up). + + When topdown is true, the caller can modify the dirnames list in-place + (e.g., via del or slice assignment), and walk will only recurse into the + subdirectories whose names remain in dirnames; this can be used to prune + the search, or to impose a specific order of visiting. Modifying + dirnames when topdown is false is ineffective, since the directories in + dirnames have already been generated by the time dirnames itself is + generated. + + By default errors from the os.listdir() call are ignored. If + optional arg 'onerror' is specified, it should be a function; it + will be called with one argument, an os.error instance. It can + report the error to continue with the walk, or raise the exception + to abort the walk. Note that the filename is available as the + filename attribute of the exception object. + + By default, os.walk does not follow symbolic links to subdirectories on + systems that support them. In order to get this functionality, set the + optional argument 'followlinks' to true. + + Caution: if you pass a relative pathname for top, don't change the + current working directory between resumptions of walk. walk never + changes the current directory, and assumes that the client doesn't + either. + + Example: + + import os + from os.path import join, getsize + for root, dirs, files in os.walk('python/Lib/email'): + print root, "consumes", + print sum([getsize(join(root, name)) for name in files]), + print "bytes in", len(files), "non-directory files" + if 'CVS' in dirs: + dirs.remove('CVS') # don't visit CVS directories + """ + + from os.path import join, isdir, islink + + # We may not have read permission for top, in which case we can't + # get a list of the files the directory contains. os.path.walk + # always suppressed the exception then, rather than blow up for a + # minor reason when (say) a thousand readable directories are still + # left to visit. That logic is copied here. + try: + # Note that listdir and error are globals in this module due + # to earlier import-*. + names = listdir(top) + except error, err: + if onerror is not None: + onerror(err) + return + + dirs, nondirs = [], [] + for name in names: + if isdir(join(top, name)): + dirs.append(name) + else: + nondirs.append(name) + + if topdown: + yield top, dirs, nondirs + for name in dirs: + path = join(top, name) + if followlinks or not islink(path): + for x in walk(path, topdown, onerror, followlinks): + yield x + if not topdown: + yield top, dirs, nondirs + +__all__.append("walk") + +# Make sure os.environ exists, at least +try: + environ +except NameError: + environ = {} + +def execl(file, *args): + """execl(file, *args) + + Execute the executable file with argument list args, replacing the + current process. """ + execv(file, args) + +def execle(file, *args): + """execle(file, *args, env) + + Execute the executable file with argument list args and + environment env, replacing the current process. """ + env = args[-1] + execve(file, args[:-1], env) + +def execlp(file, *args): + """execlp(file, *args) + + Execute the executable file (which is searched for along $PATH) + with argument list args, replacing the current process. """ + execvp(file, args) + +def execlpe(file, *args): + """execlpe(file, *args, env) + + Execute the executable file (which is searched for along $PATH) + with argument list args and environment env, replacing the current + process. """ + env = args[-1] + execvpe(file, args[:-1], env) + +def execvp(file, args): + """execp(file, args) + + Execute the executable file (which is searched for along $PATH) + with argument list args, replacing the current process. + args may be a list or tuple of strings. """ + _execvpe(file, args) + +def execvpe(file, args, env): + """execvpe(file, args, env) + + Execute the executable file (which is searched for along $PATH) + with argument list args and environment env , replacing the + current process. + args may be a list or tuple of strings. """ + _execvpe(file, args, env) + +__all__.extend(["execl","execle","execlp","execlpe","execvp","execvpe"]) + +def _execvpe(file, args, env=None): + if env is not None: + func = execve + argrest = (args, env) + else: + func = execv + argrest = (args,) + env = environ + + head, tail = path.split(file) + if head: + func(file, *argrest) + return + if 'PATH' in env: + envpath = env['PATH'] + else: + envpath = defpath + PATH = envpath.split(pathsep) + saved_exc = None + saved_tb = None + for dir in PATH: + fullname = path.join(dir, file) + try: + func(fullname, *argrest) + except error, e: + tb = sys.exc_info()[2] + if (e.errno != errno.ENOENT and e.errno != errno.ENOTDIR + and saved_exc is None): + saved_exc = e + saved_tb = tb + if saved_exc: + raise error, saved_exc, saved_tb + raise error, e, tb + +# Change environ to automatically call putenv() if it exists +try: + # This will fail if there's no putenv + putenv +except NameError: + pass +else: + import UserDict + + # Fake unsetenv() for Windows + # not sure about os2 here but + # I'm guessing they are the same. + + if name in ('os2', 'nt'): + def unsetenv(key): + putenv(key, "") + + if name == "riscos": + # On RISC OS, all env access goes through getenv and putenv + from riscosenviron import _Environ + elif name in ('os2', 'nt'): # Where Env Var Names Must Be UPPERCASE + # But we store them as upper case + class _Environ(UserDict.IterableUserDict): + def __init__(self, environ): + UserDict.UserDict.__init__(self) + data = self.data + for k, v in environ.items(): + data[k.upper()] = v + def __setitem__(self, key, item): + putenv(key, item) + self.data[key.upper()] = item + def __getitem__(self, key): + return self.data[key.upper()] + try: + unsetenv + except NameError: + def __delitem__(self, key): + del self.data[key.upper()] + else: + def __delitem__(self, key): + unsetenv(key) + del self.data[key.upper()] + def clear(self): + for key in self.data.keys(): + unsetenv(key) + del self.data[key] + def pop(self, key, *args): + unsetenv(key) + return self.data.pop(key.upper(), *args) + def has_key(self, key): + return key.upper() in self.data + def __contains__(self, key): + return key.upper() in self.data + def get(self, key, failobj=None): + return self.data.get(key.upper(), failobj) + def update(self, dict=None, **kwargs): + if dict: + try: + keys = dict.keys() + except AttributeError: + # List of (key, value) + for k, v in dict: + self[k] = v + else: + # got keys + # cannot use items(), since mappings + # may not have them. + for k in keys: + self[k] = dict[k] + if kwargs: + self.update(kwargs) + def copy(self): + return dict(self) + + else: # Where Env Var Names Can Be Mixed Case + class _Environ(UserDict.IterableUserDict): + def __init__(self, environ): + UserDict.UserDict.__init__(self) + self.data = environ + def __setitem__(self, key, item): + putenv(key, item) + self.data[key] = item + def update(self, dict=None, **kwargs): + if dict: + try: + keys = dict.keys() + except AttributeError: + # List of (key, value) + for k, v in dict: + self[k] = v + else: + # got keys + # cannot use items(), since mappings + # may not have them. + for k in keys: + self[k] = dict[k] + if kwargs: + self.update(kwargs) + try: + unsetenv + except NameError: + pass + else: + def __delitem__(self, key): + unsetenv(key) + del self.data[key] + def clear(self): + for key in self.data.keys(): + unsetenv(key) + del self.data[key] + def pop(self, key, *args): + unsetenv(key) + return self.data.pop(key, *args) + def copy(self): + return dict(self) + + + environ = _Environ(environ) + +def getenv(key, default=None): + """Get an environment variable, return None if it doesn't exist. + The optional second argument can specify an alternate default.""" + return environ.get(key, default) +__all__.append("getenv") + +def _exists(name): + try: + eval(name) + return True + except NameError: + return False + +# Supply spawn*() (probably only for Unix) +if _exists("fork") and not _exists("spawnv") and _exists("execv"): + + P_WAIT = 0 + P_NOWAIT = P_NOWAITO = 1 + + # XXX Should we support P_DETACH? I suppose it could fork()**2 + # and close the std I/O streams. Also, P_OVERLAY is the same + # as execv*()? + + def _spawnvef(mode, file, args, env, func): + # Internal helper; func is the exec*() function to use + pid = fork() + if not pid: + # Child + try: + if env is None: + func(file, args) + else: + func(file, args, env) + except: + _exit(127) + else: + # Parent + if mode == P_NOWAIT: + return pid # Caller is responsible for waiting! + while 1: + wpid, sts = waitpid(pid, 0) + if WIFSTOPPED(sts): + continue + elif WIFSIGNALED(sts): + return -WTERMSIG(sts) + elif WIFEXITED(sts): + return WEXITSTATUS(sts) + else: + raise error, "Not stopped, signaled or exited???" + + def spawnv(mode, file, args): + """spawnv(mode, file, args) -> integer + +Execute file with arguments from args in a subprocess. +If mode == P_NOWAIT return the pid of the process. +If mode == P_WAIT return the process's exit code if it exits normally; +otherwise return -SIG, where SIG is the signal that killed it. """ + return _spawnvef(mode, file, args, None, execv) + + def spawnve(mode, file, args, env): + """spawnve(mode, file, args, env) -> integer + +Execute file with arguments from args in a subprocess with the +specified environment. +If mode == P_NOWAIT return the pid of the process. +If mode == P_WAIT return the process's exit code if it exits normally; +otherwise return -SIG, where SIG is the signal that killed it. """ + return _spawnvef(mode, file, args, env, execve) + + # Note: spawnvp[e] is't currently supported on Windows + + def spawnvp(mode, file, args): + """spawnvp(mode, file, args) -> integer + +Execute file (which is looked for along $PATH) with arguments from +args in a subprocess. +If mode == P_NOWAIT return the pid of the process. +If mode == P_WAIT return the process's exit code if it exits normally; +otherwise return -SIG, where SIG is the signal that killed it. """ + return _spawnvef(mode, file, args, None, execvp) + + def spawnvpe(mode, file, args, env): + """spawnvpe(mode, file, args, env) -> integer + +Execute file (which is looked for along $PATH) with arguments from +args in a subprocess with the supplied environment. +If mode == P_NOWAIT return the pid of the process. +If mode == P_WAIT return the process's exit code if it exits normally; +otherwise return -SIG, where SIG is the signal that killed it. """ + return _spawnvef(mode, file, args, env, execvpe) + +if _exists("spawnv"): + # These aren't supplied by the basic Windows code + # but can be easily implemented in Python + + def spawnl(mode, file, *args): + """spawnl(mode, file, *args) -> integer + +Execute file with arguments from args in a subprocess. +If mode == P_NOWAIT return the pid of the process. +If mode == P_WAIT return the process's exit code if it exits normally; +otherwise return -SIG, where SIG is the signal that killed it. """ + return spawnv(mode, file, args) + + def spawnle(mode, file, *args): + """spawnle(mode, file, *args, env) -> integer + +Execute file with arguments from args in a subprocess with the +supplied environment. +If mode == P_NOWAIT return the pid of the process. +If mode == P_WAIT return the process's exit code if it exits normally; +otherwise return -SIG, where SIG is the signal that killed it. """ + env = args[-1] + return spawnve(mode, file, args[:-1], env) + + + __all__.exte... [truncated message content] |