From: <pj...@us...> - 2009-10-19 22:02:54
|
Revision: 6874 http://jython.svn.sourceforge.net/jython/?rev=6874&view=rev Author: pjenvey Date: 2009-10-19 22:02:41 +0000 (Mon, 19 Oct 2009) Log Message: ----------- o pull posix bits out of os into their own module o further pull some of the slower to initialize bits out of posix into a Java _posix (_nt on Windows) module. this speeds up startup. eventually we should move more if not everything there o adapt 2.6's os.py: - hide exec* - we don't need to use set/get/putenv for the environ dict wrapper - our stat_result can be pickled, remove the copy_reg workaround - re-add some 2.5isms Modified Paths: -------------- trunk/jython/CoreExposed.includes trunk/jython/Lib/grp.py trunk/jython/Lib/os.py trunk/jython/Lib/posix.py trunk/jython/Lib/pwd.py trunk/jython/Lib/select.py trunk/jython/Lib/subprocess.py trunk/jython/Lib/test/test_import_jy.py trunk/jython/src/org/python/core/Py.java trunk/jython/src/org/python/core/io/FileIO.java trunk/jython/src/org/python/core/io/StreamIO.java trunk/jython/src/org/python/core/util/FileUtil.java trunk/jython/src/org/python/modules/Setup.java trunk/jython/src/org/python/util/jython.java Added Paths: ----------- trunk/jython/Lib/nt.py trunk/jython/src/org/python/modules/posix/ trunk/jython/src/org/python/modules/posix/OS.java trunk/jython/src/org/python/modules/posix/PosixModule.java trunk/jython/src/org/python/modules/posix/PyStatResult.java trunk/jython/src/org/python/modules/posix/PythonPOSIXHandler.java Modified: trunk/jython/CoreExposed.includes =================================================================== --- trunk/jython/CoreExposed.includes 2009-10-19 21:56:07 UTC (rev 6873) +++ trunk/jython/CoreExposed.includes 2009-10-19 22:02:41 UTC (rev 6874) @@ -61,6 +61,7 @@ org/python/modules/_weakref/ReferenceType.class org/python/modules/operator$PyAttrGetter.class org/python/modules/operator$PyItemGetter.class +org/python/modules/posix/PyStatResult.class org/python/modules/random/PyRandom.class org/python/modules/thread/PyLocal.class org/python/modules/time/PyTimeTuple.class Modified: trunk/jython/Lib/grp.py =================================================================== --- trunk/jython/Lib/grp.py 2009-10-19 21:56:07 UTC (rev 6873) +++ trunk/jython/Lib/grp.py 2009-10-19 22:02:41 UTC (rev 6874) @@ -17,7 +17,7 @@ __all__ = ['getgrgid', 'getgrnam', 'getgrall'] -from os import _name, _posix +from os import _name, _posix_impl if _name == 'nt': raise ImportError, 'grp module not supported on Windows' @@ -50,7 +50,7 @@ Return the group database entry for the given numeric group ID. If id is not valid, raise KeyError. """ - entry = _posix.getgrgid(uid) + entry = _posix_impl.getgrgid(uid) if not entry: raise KeyError(uid) return struct_group(entry) @@ -62,7 +62,7 @@ Return the group database entry for the given group name. If name is not valid, raise KeyError. """ - entry = _posix.getgrnam(name) + entry = _posix_impl.getgrnam(name) if not entry: raise KeyError(name) return struct_group(entry) @@ -76,7 +76,7 @@ """ groups = [] while True: - group = _posix.getgrent() + group = _posix_impl.getgrent() if not group: break groups.append(struct_group(group)) Added: trunk/jython/Lib/nt.py =================================================================== --- trunk/jython/Lib/nt.py (rev 0) +++ trunk/jython/Lib/nt.py 2009-10-19 22:02:41 UTC (rev 6874) @@ -0,0 +1,2 @@ +from posix import __all__ +from posix import * Modified: trunk/jython/Lib/os.py =================================================================== --- trunk/jython/Lib/os.py 2009-10-19 21:56:07 UTC (rev 6873) +++ trunk/jython/Lib/os.py 2009-10-19 22:02:41 UTC (rev 6874) @@ -38,8 +38,9 @@ except AttributeError: return [n for n in dir(module) if n[0] != '_'] -if 'posix' in _names: - name = 'posix' +name = 'java' +if '_posix' in _names: + _name = 'posix' linesep = '\n' from posix import * try: @@ -52,8 +53,8 @@ __all__.extend(_get_exports_list(posix)) del posix -elif 'nt' in _names: - name = 'nt' +elif '_nt' in _names: + _name = 'nt' linesep = '\r\n' from nt import * try: @@ -66,8 +67,8 @@ __all__.extend(_get_exports_list(nt)) del nt -elif 'os2' in _names: - name = 'os2' +elif '_os2' in _names: + _name = 'os2' linesep = '\r\n' from os2 import * try: @@ -84,8 +85,8 @@ __all__.extend(_get_exports_list(os2)) del os2 -elif 'ce' in _names: - name = 'ce' +elif '_ce' in _names: + _name = 'ce' linesep = '\r\n' from ce import * try: @@ -99,8 +100,8 @@ __all__.extend(_get_exports_list(ce)) del ce -elif 'riscos' in _names: - name = 'riscos' +elif '_riscos' in _names: + _name = 'riscos' linesep = '\n' from riscos import * try: @@ -304,90 +305,97 @@ except NameError: environ = {} -def execl(file, *args): - """execl(file, *args) +def _exists(name): + # CPython eval's the name, whereas looking in __all__ works for + # Jython and is much faster + return name in __all__ - Execute the executable file with argument list args, replacing the - current process. """ - execv(file, args) +if _exists('execv'): -def execle(file, *args): - """execle(file, *args, env) + def execl(file, *args): + """execl(file, *args) - Execute the executable file with argument list args and - environment env, replacing the current process. """ - env = args[-1] - execve(file, args[:-1], env) + Execute the executable file with argument list args, replacing the + current process. """ + execv(file, args) -def execlp(file, *args): - """execlp(file, *args) + def execle(file, *args): + """execle(file, *args, env) - Execute the executable file (which is searched for along $PATH) - with argument list args, replacing the current process. """ - execvp(file, args) + Execute the executable file with argument list args and + environment env, replacing the current process. """ + env = args[-1] + execve(file, args[:-1], env) -def execlpe(file, *args): - """execlpe(file, *args, env) + def execlp(file, *args): + """execlp(file, *args) - 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) + Execute the executable file (which is searched for along $PATH) + with argument list args, replacing the current process. """ + execvp(file, args) -def execvp(file, args): - """execp(file, args) + def execlpe(file, *args): + """execlpe(file, *args, env) - 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) + 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 execvpe(file, args, env): - """execvpe(file, args, env) + def execvp(file, args): + """execp(file, args) - 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) + 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) -__all__.extend(["execl","execle","execlp","execlpe","execvp","execvpe"]) + def execvpe(file, args, env): + """execvpe(file, args, env) -def _execvpe(file, args, env=None): - if env is not None: - func = execve - argrest = (args, env) - else: - func = execv - argrest = (args,) - env = environ + 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) - 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 + __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 @@ -405,10 +413,10 @@ def unsetenv(key): putenv(key, "") - if name == "riscos": + 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 + 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): @@ -417,26 +425,11 @@ 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 __delitem__(self, key): + del self.data[key.upper()] def has_key(self, key): return key.upper() in self.data def __contains__(self, key): @@ -462,64 +455,14 @@ 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) - - 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"): @@ -655,7 +598,7 @@ # Supply popen2 etc. (for Unix) -if _exists("fork"): +if sys.platform.startswith('java') or _exists("fork"): if not _exists("popen2"): def popen2(cmd, mode="t", bufsize=-1): """Execute the shell command 'cmd' in a sub-process. On UNIX, 'cmd' @@ -664,10 +607,6 @@ 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 warnings - msg = "os.popen2 is deprecated. Use the subprocess module." - warnings.warn(msg, DeprecationWarning, stacklevel=2) - import subprocess PIPE = subprocess.PIPE p = subprocess.Popen(cmd, shell=isinstance(cmd, basestring), @@ -684,10 +623,6 @@ 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 warnings - msg = "os.popen3 is deprecated. Use the subprocess module." - warnings.warn(msg, DeprecationWarning, stacklevel=2) - import subprocess PIPE = subprocess.PIPE p = subprocess.Popen(cmd, shell=isinstance(cmd, basestring), @@ -704,10 +639,6 @@ 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 warnings - msg = "os.popen4 is deprecated. Use the subprocess module." - warnings.warn(msg, DeprecationWarning, stacklevel=2) - import subprocess PIPE = subprocess.PIPE p = subprocess.Popen(cmd, shell=isinstance(cmd, basestring), @@ -716,33 +647,6 @@ return p.stdin, p.stdout __all__.append("popen4") -import copy_reg as _copy_reg - -def _make_stat_result(tup, dict): - return stat_result(tup, dict) - -def _pickle_stat_result(sr): - (type, args) = sr.__reduce__() - return (_make_stat_result, args) - -try: - _copy_reg.pickle(stat_result, _pickle_stat_result, _make_stat_result) -except NameError: # stat_result may not exist - pass - -def _make_statvfs_result(tup, dict): - return statvfs_result(tup, dict) - -def _pickle_statvfs_result(sr): - (type, args) = sr.__reduce__() - return (_make_statvfs_result, args) - -try: - _copy_reg.pickle(statvfs_result, _pickle_statvfs_result, - _make_statvfs_result) -except NameError: # statvfs_result may not exist - pass - if not _exists("urandom"): def urandom(n): """urandom(n) -> str @@ -754,10 +658,8 @@ _urandomfd = open("/dev/urandom", O_RDONLY) except (OSError, IOError): raise NotImplementedError("/dev/urandom (or equivalent) not found") - try: - bs = b"" - while n - len(bs) >= 1: - bs += read(_urandomfd, n - len(bs)) - finally: - close(_urandomfd) - return bs + bytes = "" + while len(bytes) < n: + bytes += read(_urandomfd, n - len(bytes)) + close(_urandomfd) + return bytes Modified: trunk/jython/Lib/posix.py =================================================================== --- trunk/jython/Lib/posix.py 2009-10-19 21:56:07 UTC (rev 6873) +++ trunk/jython/Lib/posix.py 2009-10-19 22:02:41 UTC (rev 6874) @@ -1,235 +1,47 @@ -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']) - +This module provides access to operating system functionality that is +standardized by the C Standard and the POSIX standard (a thinly +disguised Unix interface). Refer to the library manual and +corresponding Unix manual entries for more information on calls. +""" +try: + import _posix + from _posix import * +except: + import _nt as _posix + from _nt import * 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']] - ] - ) +__all__ = _posix.__all__[:] +__all__.extend(['_exit', 'access', 'chdir', 'chmod', 'close', 'environ', + 'fdopen', 'fsync', 'ftruncate', 'getcwd', 'getcwdu', 'getenv', + 'getpid', 'isatty', 'listdir', 'lseek', 'lstat', 'mkdir', + 'open', 'popen', 'putenv', 'read', 'remove', 'rename', 'rmdir', + 'stat', 'strerror', 'system', 'umask', 'unlink', 'unsetenv', + 'urandom', 'utime', 'write']) -def get_os_type(): - """Return the name of the type of the underlying OS. +_name = _posix.__name__[1:] - 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: +# For urandom +urandom_source = None - _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), - ) +# Lazily loaded path module +_path = None - 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) @@ -257,12 +69,13 @@ 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): + global _path + if not _stat.S_ISDIR(stat(path).st_mode): raise OSError(errno.ENOTDIR, strerror(errno.ENOTDIR), path) - sys.setCurrentWorkingDir(realpath) + if _path is None: + import os + _path = os.path + sys.setCurrentWorkingDir(_path.realpath(path)) def listdir(path): """listdir(path) -> list_of_strings @@ -289,7 +102,7 @@ abs_path = sys.getPath(path) if not File(abs_path).exists(): raise OSError(errno.ENOENT, strerror(errno.ENOENT), path) - _posix.chmod(abs_path, mode) + _posix_impl.chmod(abs_path, mode) def mkdir(path, mode='ignored'): """mkdir(path [, mode=0777]) @@ -298,7 +111,7 @@ The optional parameter is currently ignored. """ - # XXX: use _posix.mkdir when we can get the real errno upon failure + # XXX: use _posix_impl.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(): @@ -308,31 +121,6 @@ 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) @@ -351,33 +139,6 @@ 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) @@ -390,31 +151,6 @@ 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 @@ -475,7 +211,7 @@ """ abs_path = sys.getPath(path) try: - return stat_result.from_jnastat(_posix.stat(abs_path)) + return _from_jnastat(_posix_impl.stat(abs_path)) except NotImplementedError: pass f = File(abs_path) @@ -501,7 +237,7 @@ """ abs_path = sys.getPath(path) try: - return stat_result.from_jnastat(_posix.lstat(abs_path)) + return _from_jnastat(_posix_impl.lstat(abs_path)) except NotImplementedError: pass f = File(sys.getPath(path)) @@ -524,7 +260,7 @@ # 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())) + f = File(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)) @@ -556,7 +292,7 @@ else: raise TypeError('utime() arg 2 must be a tuple (atime, mtime)') - _posix.utimes(path, atimeval, mtimeval) + _posix_impl.utimes(path, atimeval, mtimeval) def _to_timeval(seconds): """Convert seconds (with a fraction) from epoch to a 2 item tuple of @@ -647,8 +383,9 @@ 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 creating: + # raises ENOENT if it doesn't exist + stat(filename) if not writing: if updating: @@ -678,7 +415,8 @@ try: fchannel = RandomAccessFile(sys.getPath(filename), 'rws').getChannel() except FileNotFoundException, fnfe: - if path.isdir(filename): + #if path.isdir(filename): + if _stat.S_ISDIR(stat(filename).st_mode): raise OSError(errno.EISDIR, strerror(errno.EISDIR)) raise OSError(errno.ENOENT, strerror(errno.ENOENT), filename) return FileIO(fchannel, mode) @@ -757,51 +495,6 @@ 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 @@ -809,139 +502,8 @@ """ 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) @@ -968,14 +530,14 @@ Create a hard link to a file. """ - _posix.link(sys.getPath(src), sys.getPath(dst)) + _posix_impl.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)) + _posix_impl.symlink(src, sys.getPath(dst)) def readlink(path): """readlink(path) -> path @@ -983,61 +545,61 @@ Return a string representing the path to which the symbolic link points. """ - return _posix.readlink(sys.getPath(path)) + return _posix_impl.readlink(sys.getPath(path)) def getegid(): """getegid() -> egid Return the current process's effective group id.""" - return _posix.getegid() + return _posix_impl.getegid() def geteuid(): """geteuid() -> euid Return the current process's effective user id.""" - return _posix.geteuid() + return _posix_impl.geteuid() def getgid(): """getgid() -> gid Return the current process's group id.""" - return _posix.getgid() + return _posix_impl.getgid() def getlogin(): """getlogin() -> string Return the actual login name.""" - return _posix.getlogin() + return _posix_impl.getlogin() def getpgrp(): """getpgrp() -> pgrp Return the current process group id.""" - return _posix.getpgrp() + return _posix_impl.getpgrp() def getppid(): """getppid() -> ppid Return the parent's process id.""" - return _posix.getppid() + return _posix_impl.getppid() def getuid(): """getuid() -> uid Return the current process's user id.""" - return _posix.getuid() + return _posix_impl.getuid() def setpgrp(): """setpgrp() Make this process a session leader.""" - return _posix.setpgrp() + return _posix_impl.setpgrp() def setsid(): """setsid() Call the system call setsid().""" - return _posix.setsid() + return _posix_impl.setsid() # This implementation of fork partially works on # Jython. Diagnosing what works, what doesn't, and fixing it is @@ -1049,13 +611,13 @@ # # Fork a child process. # Return 0 to child process and PID of child to parent process.""" - # return _posix.fork() + # return _posix_impl.fork() def kill(pid, sig): """kill(pid, sig) Kill a process with a signal.""" - return _posix.kill(pid, sig) + return _posix_impl.kill(pid, sig) def wait(): """wait() -> (pid, status) @@ -1063,7 +625,7 @@ Wait for completion of a child process.""" status = jarray.zeros(1, 'i') - res_pid = _posix.wait(status) + res_pid = _posix_impl.wait(status) if res_pid == -1: raise OSError(status[0], strerror(status[0])) return res_pid, status[0] @@ -1073,7 +635,7 @@ Wait for completion of a given child process.""" status = jarray.zeros(1, 'i') - res_pid = _posix.waitpid(pid, status, options) + res_pid = _posix_impl.waitpid(pid, status, options) if res_pid == -1: raise OSError(status[0], strerror(status[0])) return res_pid, status[0] @@ -1117,7 +679,7 @@ """getpid() -> pid Return the current process id.""" - return _posix.getpid() + return _posix_impl.getpid() def isatty(fileno): """isatty(fd) -> bool @@ -1137,10 +699,10 @@ raise NotImplemented('Integer file descriptor compatibility only ' 'available for stdin, stdout and stderr (0-2)') - return _posix.isatty(fd) + return _posix_impl.isatty(fd) if isinstance(fileno, FileDescriptor): - return _posix.isatty(fileno) + return _posix_impl.isatty(fileno) if not isinstance(fileno, IOBase): raise TypeError('a file descriptor is required') @@ -1151,16 +713,23 @@ """umask(new_mask) -> old_mask Set the current numeric umask and return the previous umask.""" - return _posix.umask(int(new_mask)) + return _posix_impl.umask(int(new_mask)) - -from java.security import SecureRandom -urandom_source = None - def urandom(n): global urandom_source if urandom_source is None: + from java.security import SecureRandom urandom_source = SecureRandom() buffer = jarray.zeros(n, 'b') urandom_source.nextBytes(buffer) return buffer.tostring() + +def _from_jnastat(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 stat_result(results) Modified: trunk/jython/Lib/pwd.py =================================================================== --- trunk/jython/Lib/pwd.py 2009-10-19 21:56:07 UTC (rev 6873) +++ trunk/jython/Lib/pwd.py 2009-10-19 22:02:41 UTC (rev 6874) @@ -10,7 +10,7 @@ __all__ = ['getpwuid', 'getpwnam', 'getpwall'] -from os import _name, _posix +from os import _name, _posix_impl if _name == 'nt': raise ImportError, 'pwd module not supported on Windows' @@ -44,7 +44,7 @@ Return the password database entry for the given numeric user ID. See pwd.__doc__ for more on password database entries. """ - entry = _posix.getpwuid(uid) + entry = _posix_impl.getpwuid(uid) if not entry: raise KeyError(uid) return struct_passwd(entry) @@ -57,7 +57,7 @@ Return the password database entry for the given user name. See pwd.__doc__ for more on password database entries. """ - entry = _posix.getpwnam(name) + entry = _posix_impl.getpwnam(name) if not entry: raise KeyError(name) return struct_passwd(entry) @@ -72,7 +72,7 @@ """ entries = [] while True: - entry = _posix.getpwent() + entry = _posix_impl.getpwent() if not entry: break entries.append(struct_passwd(entry)) Modified: trunk/jython/Lib/select.py =================================================================== --- trunk/jython/Lib/select.py 2009-10-19 21:56:07 UTC (rev 6873) +++ trunk/jython/Lib/select.py 2009-10-19 22:02:41 UTC (rev 6874) @@ -180,7 +180,7 @@ class poll_object_cache: def __init__(self): - self.is_windows = os.get_os_type() == 'nt' + self.is_windows = os._name == 'nt' if self.is_windows: self.poll_object_queue = Queue.Queue() import atexit Modified: trunk/jython/Lib/subprocess.py =================================================================== --- trunk/jython/Lib/subprocess.py 2009-10-19 21:56:07 UTC (rev 6873) +++ trunk/jython/Lib/subprocess.py 2009-10-19 22:02:41 UTC (rev 6874) @@ -620,11 +620,7 @@ _cmdline2listimpl = lambda args: [args] _escape_args = lambda args: args - os_info = os._os_map.get(os._name) - if os_info is None: - os_info = os._os_map.get('posix') - - for shell_command in os_info[1]: + for shell_command in os._get_shell_commands(): executable = shell_command[0] if not os.path.isabs(executable): import distutils.spawn Modified: trunk/jython/Lib/test/test_import_jy.py =================================================================== --- trunk/jython/Lib/test/test_import_jy.py 2009-10-19 21:56:07 UTC (rev 6873) +++ trunk/jython/Lib/test/test_import_jy.py 2009-10-19 22:02:41 UTC (rev 6874) @@ -100,8 +100,8 @@ def test_override(self): modname = os.path.__name__ tests = [ - ("import os.path" , "('os.path', None, -1, 'os')" ), - ("import os.path as path2", "('os.path', None, -1, 'os')" ), + ("import os.path" , "('os.path', None, -1, '_posix')" ), + ("import os.path as path2", "('os.path', None, -1, '_posix')" ), ("from os.path import *" , "('os.path', ('*',), -1, '%s')" % modname), ("from os.path import join", Modified: trunk/jython/src/org/python/core/Py.java =================================================================== --- trunk/jython/src/org/python/core/Py.java 2009-10-19 21:56:07 UTC (rev 6873) +++ trunk/jython/src/org/python/core/Py.java 2009-10-19 22:02:41 UTC (rev 6874) @@ -21,6 +21,7 @@ import java.util.Set; import org.python.antlr.base.mod; +import com.kenai.constantine.Constant; import com.kenai.constantine.platform.Errno; import java.util.ArrayList; import java.util.List; @@ -102,6 +103,12 @@ return new PyException(Py.OSError, message); } + public static PyException OSError(Constant errno, String filename) { + PyObject args = new PyTuple(Py.newInteger(errno.value()), Py.newString(errno.toString()), + Py.newString(filename)); + return new PyException(Py.OSError, args); + } + public static PyObject NotImplementedError; public static PyException NotImplementedError(String message) { return new PyException(Py.NotImplementedError, message); @@ -163,15 +170,14 @@ return new PyException(Py.IOError, message); } - public static PyException IOError(Errno errno) { - PyObject args = new PyTuple(Py.newInteger(errno.value()), - Py.newString(errno.description())); + public static PyException IOError(Constant errno) { + PyObject args = new PyTuple(Py.newInteger(errno.value()), Py.newString(errno.toString())); return new PyException(Py.IOError, args); } - public static PyException IOError(Errno errno, String filename) { - PyObject args = new PyTuple(Py.newInteger(errno.value()), - Py.newString(errno.description()), Py.newString(filename)); + public static PyException IOError(Constant errno, String filename) { + PyObject args = new PyTuple(Py.newInteger(errno.value()), Py.newString(errno.toString()), + Py.newString(filename)); return new PyException(Py.IOError, args); } Modified: trunk/jython/src/org/python/core/io/FileIO.java =================================================================== --- trunk/jython/src/org/python/core/io/FileIO.java 2009-10-19 21:56:07 UTC (rev 6873) +++ trunk/jython/src/org/python/core/io/FileIO.java 2009-10-19 22:02:41 UTC (rev 6874) @@ -16,8 +16,8 @@ import com.kenai.constantine.platform.Errno; import org.jruby.ext.posix.util.Platform; import org.python.core.Py; -import org.python.core.util.FileUtil; import org.python.core.util.RelativeFile; +import org.python.modules.posix.PosixModule; /** * Raw I/O implementation for OS files. @@ -222,7 +222,8 @@ return false; } try { - return FileUtil.isatty(file != null ? file.getFD() : fileOutputStream.getFD()); + return PosixModule.getPOSIX().isatty(file != null + ? file.getFD() : fileOutputStream.getFD()); } catch (IOException e) { return false; } Modified: trunk/jython/src/org/python/core/io/StreamIO.java =================================================================== --- trunk/jython/src/org/python/core/io/StreamIO.java 2009-10-19 21:56:07 UTC (rev 6873) +++ trunk/jython/src/org/python/core/io/StreamIO.java 2009-10-19 22:02:41 UTC (rev 6874) @@ -17,7 +17,7 @@ import java.nio.channels.WritableByteChannel; import org.python.core.Py; -import org.python.core.util.FileUtil; +import org.python.modules.posix.PosixModule; /** * Raw I/O implementation for simple streams. @@ -231,7 +231,7 @@ return false; } - return FileUtil.isatty(fd); + return PosixModule.getPOSIX().isatty(fd); } @Override Modified: trunk/jython/src/org/python/core/util/FileUtil.java =================================================================== --- trunk/jython/src/org/python/core/util/FileUtil.java 2009-10-19 21:56:07 UTC (rev 6873) +++ trunk/jython/src/org/python/core/util/FileUtil.java 2009-10-19 22:02:41 UTC (rev 6874) @@ -64,14 +64,4 @@ } return out.toByteArray(); } - - public static boolean isatty(FileDescriptor fd) { - try { - return imp.load("os").__getattr__("isatty").__call__(Py.java2py(fd)).__nonzero__(); - } catch (PyException e) { - // Weak isatty check copied from jna-posix JavaPOSIX class - return fd == FileDescriptor.in || fd == FileDescriptor.out || fd == FileDescriptor.err; - } - } - } Modified: trunk/jython/src/org/python/modules/Setup.java =================================================================== --- trunk/jython/src/org/python/modules/Setup.java 2009-10-19 21:56:07 UTC (rev 6873) +++ trunk/jython/src/org/python/modules/Setup.java 2009-10-19 22:02:41 UTC (rev 6874) @@ -1,6 +1,8 @@ // Copyright (c) Corporation for National Research Initiatives package org.python.modules; +import org.python.modules.posix.PosixModule; + // This is sort of analogous to CPython's Modules/Setup file. Use this to // specify additional builtin modules. @@ -56,6 +58,7 @@ "_systemrestart", "_ast:org.python.antlr.ast.AstModule", "_marshal", - "_threading:org.python.modules._threading._threading" + "_threading:org.python.modules._threading._threading", + "_" + PosixModule.getOSName() + ":org.python.modules.posix.PosixModule" }; } Added: trunk/jython/src/org/python/modules/posix/OS.java =================================================================== --- trunk/jython/src/org/python/modules/posix/OS.java (rev 0) +++ trunk/jython/src/org/python/modules/posix/OS.java 2009-10-19 22:02:41 UTC (rev 6874) @@ -0,0 +1,90 @@ +/* Copyright (c) Jython Developers */ +package org.python.modules.posix; + +import java.lang.reflect.Method; + +import org.python.core.PyObject; +import org.python.core.PySystemState; + +/** + * A Marker tagging what OS we're running on, with some accompanying information about + * that platform. + */ +enum OS { + NT("Windows", new String[] {"cmd.exe", "/c"}, new String[] {"command.com", "/c"}), + POSIX(new String[] {"/bin/sh", "-c"}); + + /** An array of potential shell commands this platform may use. */ + private final String[][] shellCommands; + + /** + * Name to match against os.name System property for identification + * (os.name.startswith(pattern)). Defaults to name(). + */ + private final String pattern; + + OS(String pattern, String[]... shellCommands) { + this.shellCommands = shellCommands; + this.pattern = pattern != null ? pattern : name(); + } + + OS(String[]... shellCommands) { + this(null, shellCommands); + } + + String getModuleName() { + return name().toLowerCase(); + } + + String[][] getShellCommands() { + return shellCommands; + } + + /** + * Hide module level functions defined in the PosixModule dict not applicable to this + * OS, identified by the PosixModule.Hide annotation. + * + * @param dict The PosixModule module dict + */ + void hideFunctions(PyObject dict) { + for (Method method: PosixModule.class.getDeclaredMethods()) { + if (isHidden(method)) { + dict.__setitem__(method.getName(), null); + } + } + } + + /** + * Determine if method should be hidden for this OS. + * + * @param method a PosixModule Method + * @return true if should be hidden + */ + private boolean isHidden(Method method) { + if (method.isAnnotationPresent(PosixModule.Hide.class)) { + for (OS os : method.getAnnotation(PosixModule.Hide.class).value()) { + if (os == this) { + return true; + } + } + } + return false; + } + + /** + * Return the OS we're running on. + */ + static OS getOS() { + String osName = PySystemState.registry.getProperty("python.os"); + if (osName == null) { + osName = System.getProperty("os.name"); + } + + for (OS os : OS.values()) { + if (osName.startsWith(os.pattern)) { + return os; + } + } + return OS.POSIX; + } +} Added: trunk/jython/src/org/python/modules/posix/PosixModule.java =================================================================== --- trunk/jython/src/org/python/modules/posix/PosixModule.java (rev 0) +++ trunk/jython/src/org/python/modules/posix/PosixModule.java 2009-10-19 22:02:41 UTC (rev 6874) @@ -0,0 +1,115 @@ +/* Copyright (c) Jython Developers */ +package org.python.modules.posix; + +import com.kenai.constantine.Constant; +import com.kenai.constantine.ConstantSet; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import org.jruby.ext.posix.JavaPOSIX; +import org.jruby.ext.posix.POSIX; +import org.jruby.ext.posix.POSIXFactory; + +import org.python.core.ClassDictInit; +import org.python.core.Py; +import org.python.core.PyList; +import org.python.core.PyObject; +import org.python.core.PyString; +import org.python.core.PyTuple; + +/** + * The underlying _posix or _nt module, named depending on the platform. + * + * This currently contains only some of the basics of the posix/nt modules (which are + * implemented in Python). In particular things like the PythonPOSIXHandler that are + * slower to instantiate and thus would affect startup time. + * + * Eventually more if not all of the pure Python module should end up here. + */ +public class PosixModule implements ClassDictInit { + + public static final PyString __doc__ = new PyString( + "This module provides access to operating system functionality that is\n" + + "standardized by the C Standard and the POSIX standard (a thinly\n" + + "disguised Unix interface). Refer to the library manual and\n" + + "corresponding Unix manual entries for more information on calls."); + + /** Current OS information. */ + private static OS os = OS.getOS(); + + /** Platform specific POSIX services. */ + private static POSIX posix = POSIXFactory.getPOSIX(new PythonPOSIXHandler(), true); + + private static final String[] openFlags = + {"O_RDONLY", "O_WRONLY", "O_RDWR", "O_APPEND", "O_SYNC", "O_CREAT", "O_TRUNC", "O_EXCL"}; + + public static void classDictInit(PyObject dict) { + dict.__setitem__("__name__", new PyString("_" + os.getModuleName())); + dict.__setitem__("__doc__", __doc__); + + // os.open flags, only expose what we support + ConstantSet openFlagConstants = ConstantSet.getConstantSet("OpenFlags"); + for (String openFlag : openFlags) { + dict.__setitem__(openFlag, Py.newInteger(openFlagConstants.getValue(openFlag))); + } + // os.access constants + dict.__setitem__("F_OK", Py.Zero); + dict.__setitem__("X_OK", Py.newInteger(1 << 0)); + dict.__setitem__("W_OK", Py.newInteger(1 << 1)); + ... [truncated message content] |