From: <zy...@us...> - 2008-02-26 19:36:22
|
Revision: 4181 http://jython.svn.sourceforge.net/jython/?rev=4181&view=rev Author: zyasoft Date: 2008-02-26 11:36:20 -0800 (Tue, 26 Feb 2008) Log Message: ----------- Merged revisions 4167-4180 via svnmerge from https://jython.svn.sourceforge.net/svnroot/jython/trunk/jython ........ r4167 | pjenvey | 2008-02-23 18:01:17 -0700 (Sat, 23 Feb 2008) | 5 lines set the Log server socket to non blocking instead of using cpython_compatibile_select. It seems to cause LogRecordStreamHandler.handle to read an unexpected 0 length chunk while cpython_compatibile_select switches blocking mode off (in a separate thread). this deadlocks the test ........ r4168 | pjenvey | 2008-02-23 18:15:38 -0700 (Sat, 23 Feb 2008) | 3 lines posixpath from http://svn.python.org/projects/python/branches/release25-maint/Lib/posixpath.py@59710 ........ r4169 | pjenvey | 2008-02-23 19:11:03 -0700 (Sat, 23 Feb 2008) | 3 lines test_posixpath from http://svn.python.org/projects/python/branches/release25-maint/Lib/test/test_posixpath.py@38937 ........ r4170 | pjenvey | 2008-02-23 19:38:21 -0700 (Sat, 23 Feb 2008) | 4 lines o fix samefile and _resolve_link to work on Jython via java.io.File o disable sameopenfile, samestat and ismount due to the lack of fstat and st_ino/st_dev ........ r4171 | pjenvey | 2008-02-23 20:27:58 -0700 (Sat, 23 Feb 2008) | 13 lines o gut javashell: - grab os.environ via System.getenv() instead of a subprocess. no longer need the 'python.environment' registry var. fixes 1895736 - move the underlying CPython-like os.name lookup to javaos, stored under os._name - move the platform's shell command lookup into subprocess (mapped in javaos) o remove javapath: use posixpath/ntpath (depending on os._name) instead fixes bugs (and their patches): 1648449 (1718975), 1717491 (1718450), 1879935 o use os.path.realpath instead of File.getCanonicalPath to lookup the value of cwd during chdir. fixes os.chdir('C:\DOCUME~1') resulting in a cwd of 'C:\Documents and Settings' instead of 'C:\DOCUME~1' o enable test_pep277 (windows only) now that ntpath is used ........ r4172 | pjenvey | 2008-02-23 20:36:04 -0700 (Sat, 23 Feb 2008) | 1 line discourage usage of os._name in a comment ........ r4173 | pjenvey | 2008-02-24 12:33:22 -0700 (Sun, 24 Feb 2008) | 3 lines ntpath from http://svn.python.org/projects/python/branches/release25-maint/Lib/ntpath.py@45631 ........ r4174 | pjenvey | 2008-02-24 12:57:22 -0700 (Sun, 24 Feb 2008) | 10 lines o avoid java.io.File (via PySystem.getPath) entirely in chdir: java.io.File doesn't consider '/' as absolute on Windows, for example. just plain realpath should give us the correct path anyway o ensure ntpath.abspath('\\') contains a drive letter since we lack nt._getfullpathname o fix posixpath.realpath('..') (_resolve_link actually) not taking cwd into account o disable ntpath.ismount so users don't expect it: we can't support it in posixpath ........ r4175 | pjenvey | 2008-02-24 20:56:07 -0700 (Sun, 24 Feb 2008) | 8 lines o fix long.__int__ overflowing on returning a long when its value is greater than MAX_LONG (fixes our 1st test_long special case, the 2nd was already fixed) o use BigInteger to parse the atoi string. it's slower than parseLong but lets us detect overflows immediately (we can opitimize this later). now only fallback to atol in PyString __int__ when atoi overflows o fallback to atol if atoi overflows in int_new (only for plain int, not subtypes) ........ r4176 | pjenvey | 2008-02-25 00:48:09 -0700 (Mon, 25 Feb 2008) | 3 lines import test_support with its fully qualified name, so its __name__ is 'test.test_support' which CPython 2.3's test_funcattrs expects ........ r4177 | pjenvey | 2008-02-25 00:50:11 -0700 (Mon, 25 Feb 2008) | 3 lines allow modification of func_defaults and sync test_funcattrs to: http://svn.python.org/projects/python/branches/release23-maint/Lib/test/test_funcattrs.py@31088 ........ r4178 | pjenvey | 2008-02-25 01:01:09 -0700 (Mon, 25 Feb 2008) | 1 line small change to more closely resemble CPython's code ........ r4179 | pjenvey | 2008-02-25 22:58:38 -0700 (Mon, 25 Feb 2008) | 5 lines bring in modulefinder, for modulefinder.AddPackagePath. some namespace packages (like paste) call it to help py2exe find modules. unfortunately the modulefinder scanner is broken as it relies on CPython bytecode; we could rewrite it later to use tokenize ........ r4180 | pjenvey | 2008-02-25 23:14:54 -0700 (Mon, 25 Feb 2008) | 1 line bring in dis and opcode, which we already stubbed out anyway, for modulefinder imports ........ Modified Paths: -------------- branches/utf16/CPythonLib.includes branches/utf16/Lib/javaos.py branches/utf16/Lib/javashell.py branches/utf16/Lib/subprocess.py branches/utf16/Lib/test/regrtest.py branches/utf16/Lib/test/test_chdir.py branches/utf16/Lib/test/test_funcattrs.py branches/utf16/Lib/test/test_javashell.py branches/utf16/Lib/test/test_logging.py branches/utf16/registry branches/utf16/src/org/python/core/PyFunction.java branches/utf16/src/org/python/core/PyInteger.java branches/utf16/src/org/python/core/PyLong.java branches/utf16/src/org/python/core/PySlice.java branches/utf16/src/org/python/core/PyString.java branches/utf16/src/org/python/core/PySystemState.java Added Paths: ----------- branches/utf16/Lib/ntpath.py branches/utf16/Lib/posixpath.py branches/utf16/Lib/test/test_posixpath.py Removed Paths: ------------- branches/utf16/Lib/dis.py branches/utf16/Lib/opcode.py branches/utf16/Lib/test/test_long.py Property Changed: ---------------- branches/utf16/ Property changes on: branches/utf16 ___________________________________________________________________ Name: svnmerge-integrated - /branches/modern:1-4083 /trunk/jython:1-4165 + /branches/modern:1-4083 /trunk/jython:1-4180 Modified: branches/utf16/CPythonLib.includes =================================================================== --- branches/utf16/CPythonLib.includes 2008-02-26 06:14:54 UTC (rev 4180) +++ branches/utf16/CPythonLib.includes 2008-02-26 19:36:20 UTC (rev 4181) @@ -39,6 +39,7 @@ difflib.py dircache.py dircmp.py +dis.py dospath.py dumbdbm.py exceptions.py @@ -74,12 +75,14 @@ mimetypes.py MimeWriter.py mimify.py +modulefinder.py multifile.py mutex.py netrc.py nntplib.py ntpath.py nturl2path.py +opcode.py optparse.py pdb.py pickle.py @@ -87,7 +90,6 @@ pipes.py poplib.py posixfile.py -posixpath.py pprint.py profile.py pstats.py Deleted: branches/utf16/Lib/dis.py =================================================================== --- branches/utf16/Lib/dis.py 2008-02-26 06:14:54 UTC (rev 4180) +++ branches/utf16/Lib/dis.py 2008-02-26 19:36:20 UTC (rev 4181) @@ -1 +0,0 @@ -# stub dis module added to allow imports Modified: branches/utf16/Lib/javaos.py =================================================================== --- branches/utf16/Lib/javaos.py 2008-02-26 06:14:54 UTC (rev 4180) +++ branches/utf16/Lib/javaos.py 2008-02-26 19:36:20 UTC (rev 4181) @@ -1,5 +1,5 @@ -r"""OS routines for Java, with some attempts to support DOS, NT, and -Posix functionality. +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. @@ -20,24 +20,85 @@ (e.g., split and join). """ -__all__ = ["altsep", "chdir", "curdir", "defpath", "environ", "getcwd", - "getenv", "getlogin", "linesep", "listdir", "mkdir", "name", - "pardir", "pathsep", "popen", "popen2", "popen3", "popen4", - "putenv","remove", "rename", "rmdir", "sep", "stat", "system", - "unlink", "utime"] +# 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', 'close', 'curdir', 'defpath', 'environ', + 'error', 'fdopen', 'getcwd', 'getenv', 'getlogin', '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 java.lang.System -import javapath as path import time import stat as _stat - +import sys from java.io import File from org.python.core.io import FileDescriptors -from UserDict import UserDict -import sys +# Mapping of: os._name: [name list, shell command list] +_os_map = dict(nt=[ + ['Windows 95', 'Windows 98', 'Windows ME', 'Windows NT', + 'Windows NT 4.0', 'WindowsNT', 'Windows 2000', 'Windows 2003', + 'Windows XP', 'Windows Vista'], + [['cmd.exe', '/c'], ['command.com', '/c']] + ], + + ce=[ + ['Windows CE'], + [['cmd.exe', '/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 str(os_name) + + os_name = str(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() + +if _name in ('nt', 'ce'): + 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 +linesep = java.lang.System.getProperty('line.separator') # open for reading only O_RDONLY = 0x0 @@ -119,26 +180,6 @@ error = OSError -name = 'java' # discriminate based on JDK version? -curdir = '.' # default to Posix for directory behavior, override below -pardir = '..' -sep = File.separator -altsep = None -pathsep = File.pathSeparator -defpath = '.' -linesep = java.lang.System.getProperty('line.separator') -if sep=='.': - extsep = '/' -else: - extsep = '.' -path.curdir = curdir -path.pardir = pardir -path.sep = sep -path.altsep = altsep -path.pathsep = pathsep -path.defpath = defpath -path.extsep = extsep - def _exit(n=0): """_exit(status) @@ -163,7 +204,7 @@ raise OSError(errno.ENOENT, errno.strerror(errno.ENOENT), path) if not _path.isdir(path): raise OSError(errno.ENOTDIR, errno.strerror(errno.ENOTDIR), path) - sys.setCurrentWorkingDir(path) + sys.setCurrentWorkingDir(_path.realpath(path)) def listdir(path): """listdir(path) -> list_of_strings @@ -350,7 +391,8 @@ 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 paths differ (a link) + # 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 @@ -511,116 +553,10 @@ except: raise OSError(errno.EBADF, errno.strerror(errno.EBADF)) -class LazyDict( UserDict ): - """A lazy-populating User Dictionary. - Lazy initialization is not thread-safe. - """ - def __init__( self, - dict=None, - populate=None, - keyTransform=None ): - """dict: starting dictionary of values - populate: function that returns the populated dictionary - keyTransform: function to normalize the keys (e.g., toupper/None) - """ - UserDict.__init__( self, dict ) - self._populated = 0 - self.__populateFunc = populate or (lambda: {}) - self._keyTransform = keyTransform or (lambda key: key) - - def __populate( self ): - if not self._populated: - # race condition - test, populate, set - # make sure you don't set _populated until __populateFunc completes... - self.data = self.__populateFunc() - self._populated = 1 - - ########## extend methods from UserDict by pre-populating - def __repr__(self): - self.__populate() - return UserDict.__repr__( self ) - def __cmp__(self, dict): - self.__populate() - return UserDict.__cmp__( self, dict ) - def __len__(self): - self.__populate() - return UserDict.__len__( self ) - def __getitem__(self, key): - self.__populate() - return UserDict.__getitem__( self, self._keyTransform(key) ) - def __setitem__(self, key, item): - self.__populate() - UserDict.__setitem__( self, self._keyTransform(key), item ) - def __delitem__(self, key): - self.__populate() - UserDict.__delitem__( self, self._keyTransform(key) ) - def clear(self): - self.__populate() - UserDict.clear( self ) - def copy(self): - self.__populate() - return UserDict.copy( self ) - def keys(self): - self.__populate() - return UserDict.keys( self ) - def items(self): - self.__populate() - return UserDict.items( self ) - def values(self): - self.__populate() - return UserDict.values( self ) - def has_key(self, key): - self.__populate() - return UserDict.has_key( self, self._keyTransform(key) ) - def __iter__(self): - self.__populate() - return iter( self.data ) - def update(self, dict): - self.__populate() - UserDict.update( self, dict ) - def get(self, key, failobj=None): - self.__populate() - return UserDict.get( self, self._keyTransform(key), failobj ) - def setdefault(self, key, failobj=None): - self.__populate() - return UserDict.setdefault( self, self._keyTransform(key), failobj ) - def popitem(self): - self.__populate() - return UserDict.popitem( self ) - def pop(self, *args): - self.__populate() - return UserDict.pop(self, *args) - def iteritems(self): - self.__populate() - return UserDict.iteritems(self) - def iterkeys(self): - self.__populate() - return UserDict.iterkeys(self) - def itervalues(self): - self.__populate() - return UserDict.itervalues(self) - def __contains__(self, key): - self.__populate() - return UserDict.__contains__(self, key) - -# Provide lazy environ, popen*, and system objects +# Provide lazy popen*, and system objects # Do these lazily, as most jython programs don't need them, # and they are very expensive to initialize -def _getEnvironment(): - import javashell - return javashell._shellEnv.environment - -environ = LazyDict( populate=_getEnvironment ) -putenv = environ.__setitem__ - -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) - def system( *args, **kwargs ): """system(command) -> exit_status @@ -779,4 +715,55 @@ __all__.append("walk") +environ = dict([(entry.getKey(), entry.getValue()) for \ + entry in java.lang.System.getenv().entrySet()]) +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): + for k, v in dict.items(): + self[k] = v + 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) Modified: branches/utf16/Lib/javashell.py =================================================================== --- branches/utf16/Lib/javashell.py 2008-02-26 06:14:54 UTC (rev 4180) +++ branches/utf16/Lib/javashell.py 2008-02-26 19:36:20 UTC (rev 4181) @@ -14,17 +14,13 @@ from java.io import InputStreamReader from java.io import BufferedReader from UserDict import UserDict -import distutils.spawn import jarray import os import string +import subprocess import sys import types -# circular dependency to let javaos import javashell lazily -# without breaking LazyDict out into a new top-level module -from javaos import LazyDict - __all__ = [ "shellexecute", "environ", "putenv", "getenv" ] def __warn( *args ): @@ -39,15 +35,13 @@ """Construct _ShellEnv instance. cmd: list of exec() arguments required to run a command in subshell, or None - getEnv: shell command to list environment variables, or None + getEnv: shell command to list environment variables, or None. + deprecated keyTransform: normalization function for environment keys, - such as 'string.upper', or None + such as 'string.upper', or None. deprecated. """ self.cmd = cmd - self.getEnv = getEnv - self.environment = LazyDict(populate=self._getEnvironment, - keyTransform=keyTransform) - self._keyTransform = self.environment._keyTransform + self.environment = os.environ def execute( self, cmd ): """Execute cmd in a shell, and return the java.lang.Process instance. @@ -56,10 +50,7 @@ """ shellCmd = self._formatCmd( cmd ) - if self.environment._populated: - env = self._formatEnvironment( self.environment ) - else: - env = None + env = self._formatEnvironment( self.environment ) try: p = Runtime.getRuntime().exec( shellCmd, env, File(os.getcwd()) ) return p @@ -74,9 +65,9 @@ """Format a command for execution in a shell.""" if self.cmd is None: msgFmt = "Unable to execute commands in subshell because shell" \ - " functionality not implemented for OS %s with shell" \ - " setting %s. Failed command=%s" - raise OSError( 0, msgFmt % ( _osType, _envType, cmd )) + " functionality not implemented for OS %s" \ + " Failed command=%s" + raise OSError( 0, msgFmt % ( os._name, cmd )) if isinstance(cmd, basestring): shellCmd = self.cmd + [cmd] @@ -92,112 +83,8 @@ lines.append( "%s=%s" % keyValue ) return lines - def _getEnvironment( self ): - """Get the environment variables by spawning a subshell. - This allows multi-line variables as long as subsequent lines do - not have '=' signs. - """ - env = {} - if self.getEnv: - try: - p = self.execute( self.getEnv ) - r = BufferedReader( InputStreamReader( p.getInputStream() ) ) - lines = [] - while True: - line = r.readLine() - if not line: - break - lines.append(line) - if '=' not in lines[0]: - __warn( - "Failed to get environment, getEnv command (%s) " \ - "did not print environment as key=value lines.\n" \ - "Output=%s" % ( self.getEnv, '\n'.join( lines ) ) - ) - return env +def _getOsType(): + return os._name - for line in lines: - try: - i = line.index( '=' ) - key = self._keyTransform(line[:i]) - value = line[i+1:] # remove = and end-of-line - except ValueError: - # found no '=', treat line as part of previous value - value = '%s\n%s' % ( value, line ) - env[ key ] = value - except OSError, ex: - __warn( "Failed to get environment, environ will be empty:", - ex ) - return env - -def _getOsType( os=None ): - """Select the OS behavior based on os argument, 'python.os' registry - setting and 'os.name' Java property. - os: explicitly select desired OS. os=None to autodetect, os='None' to - disable - """ - os = str(os or sys.registry.getProperty( "python.os" ) or \ - System.getProperty( "os.name" )) - - _osTypeMap = ( - ( "nt", ( 'nt', 'Windows NT', 'Windows NT 4.0', 'WindowsNT', - 'Windows 2000', 'Windows 2003', 'Windows XP', 'Windows CE', - 'Windows Vista' )), - ( "dos", ( 'dos', 'Windows 95', 'Windows 98', 'Windows ME' )), - ( "mac", ( 'mac', 'MacOS', 'Darwin' )), - ( "None", ( 'None', )), - ) - foundType = None - for osType, patterns in _osTypeMap: - for pattern in patterns: - if os.startswith( pattern ): - foundType = osType - break - if foundType: - break - if not foundType: - foundType = "posix" # default - posix seems to vary most widely - - return foundType - -def _getShellEnv(): - # default to None/empty for shell and environment behavior - shellCmd = None - envCmd = None - envTransform = None - - envType = sys.registry.getProperty("python.environment", "shell") - if envType == "shell": - osType = _getOsType() - - # override defaults based on osType - if osType == "nt": - shellCmd = ["cmd.exe", "/c"] - envCmd = "set" - envTransform = string.upper - elif osType == "dos": - shellCmd = ["command.com", "/c"] - envCmd = "set" - envTransform = string.upper - elif osType == "posix": - shellCmd = ["/bin/sh", "-c"] - envCmd = "env" - elif osType == "mac": - curdir = ':' # override Posix directories - pardir = '::' - elif osType == "None": - pass - # else: - # # may want a warning, but only at high verbosity: - # __warn( "Unknown os type '%s', using default behavior." % osType ) - - return _ShellEnv( shellCmd, envCmd, envTransform ) - -_shellEnv = _getShellEnv() -# The absolute path can only be determined (from environ's PATH) after -# _shellEnv is loaded (the os module references it) -if _shellEnv.cmd: - executable = _shellEnv.cmd[0] - if not os.path.isabs(executable): - _shellEnv.cmd[0] = distutils.spawn.find_executable(executable) +_shellEnv = _ShellEnv(subprocess.shell_command) shellexecute = _shellEnv.execute Copied: branches/utf16/Lib/ntpath.py (from rev 4180, trunk/jython/Lib/ntpath.py) =================================================================== --- branches/utf16/Lib/ntpath.py (rev 0) +++ branches/utf16/Lib/ntpath.py 2008-02-26 19:36:20 UTC (rev 4181) @@ -0,0 +1,521 @@ +# Module 'ntpath' -- common operations on WinNT/Win95 pathnames +"""Common pathname manipulations, WindowsNT/95 version. + +Instead of importing this module directly, import os and refer to this +module as os.path. +""" + +import java.io.File +import javaos +import os +import stat +import sys + +__all__ = ["normcase","isabs","join","splitdrive","split","splitext", + "basename","dirname","commonprefix","getsize","getmtime", + "getatime","getctime", "islink","exists","lexists","isdir","isfile", + "walk","expanduser","expandvars","normpath","abspath", + "splitunc","curdir","pardir","sep","pathsep","defpath","altsep", + "extsep","devnull","realpath","supports_unicode_filenames"] + +# strings representing various path-related bits and pieces +curdir = '.' +pardir = '..' +extsep = '.' +sep = '\\' +pathsep = ';' +altsep = '/' +defpath = '.;C:\\bin' +if 'ce' in sys.builtin_module_names: + defpath = '\\Windows' +elif 'os2' in sys.builtin_module_names: + # OS/2 w/ VACPP + altsep = '/' +devnull = 'nul' + +# Normalize the case of a pathname and map slashes to backslashes. +# Other normalizations (such as optimizing '../' away) are not done +# (this is done by normpath). + +def normcase(s): + """Normalize case of pathname. + + Makes all characters lowercase and all slashes into backslashes.""" + return s.replace("/", "\\").lower() + + +# Return whether a path is absolute. +# Trivial in Posix, harder on the Mac or MS-DOS. +# For DOS it is absolute if it starts with a slash or backslash (current +# volume), or if a pathname after the volume letter and colon / UNC resource +# starts with a slash or backslash. + +def isabs(s): + """Test whether a path is absolute""" + s = splitdrive(s)[1] + return s != '' and s[:1] in '/\\' + + +# Join two (or more) paths. + +def join(a, *p): + """Join two or more pathname components, inserting "\\" as needed""" + path = a + for b in p: + b_wins = 0 # set to 1 iff b makes path irrelevant + if path == "": + b_wins = 1 + + elif isabs(b): + # This probably wipes out path so far. However, it's more + # complicated if path begins with a drive letter: + # 1. join('c:', '/a') == 'c:/a' + # 2. join('c:/', '/a') == 'c:/a' + # But + # 3. join('c:/a', '/b') == '/b' + # 4. join('c:', 'd:/') = 'd:/' + # 5. join('c:/', 'd:/') = 'd:/' + if path[1:2] != ":" or b[1:2] == ":": + # Path doesn't start with a drive letter, or cases 4 and 5. + b_wins = 1 + + # Else path has a drive letter, and b doesn't but is absolute. + elif len(path) > 3 or (len(path) == 3 and + path[-1] not in "/\\"): + # case 3 + b_wins = 1 + + if b_wins: + path = b + else: + # Join, and ensure there's a separator. + assert len(path) > 0 + if path[-1] in "/\\": + if b and b[0] in "/\\": + path += b[1:] + else: + path += b + elif path[-1] == ":": + path += b + elif b: + if b[0] in "/\\": + path += b + else: + path += "\\" + b + else: + # path is not empty and does not end with a backslash, + # but b is empty; since, e.g., split('a/') produces + # ('a', ''), it's best if join() adds a backslash in + # this case. + path += '\\' + + return path + + +# Split a path in a drive specification (a drive letter followed by a +# colon) and the path specification. +# It is always true that drivespec + pathspec == p +def splitdrive(p): + """Split a pathname into drive and path specifiers. Returns a 2-tuple +"(drive,path)"; either part may be empty""" + if p[1:2] == ':': + return p[0:2], p[2:] + return '', p + + +# Parse UNC paths +def splitunc(p): + """Split a pathname into UNC mount point and relative path specifiers. + + Return a 2-tuple (unc, rest); either part may be empty. + If unc is not empty, it has the form '//host/mount' (or similar + using backslashes). unc+rest is always the input path. + Paths containing drive letters never have an UNC part. + """ + if p[1:2] == ':': + return '', p # Drive letter present + firstTwo = p[0:2] + if firstTwo == '//' or firstTwo == '\\\\': + # is a UNC path: + # vvvvvvvvvvvvvvvvvvvv equivalent to drive letter + # \\machine\mountpoint\directories... + # directory ^^^^^^^^^^^^^^^ + normp = normcase(p) + index = normp.find('\\', 2) + if index == -1: + ##raise RuntimeError, 'illegal UNC path: "' + p + '"' + return ("", p) + index = normp.find('\\', index + 1) + if index == -1: + index = len(p) + return p[:index], p[index:] + return '', p + + +# Split a path in head (everything up to the last '/') and tail (the +# rest). After the trailing '/' is stripped, the invariant +# join(head, tail) == p holds. +# The resulting head won't end in '/' unless it is the root. + +def split(p): + """Split a pathname. + + Return tuple (head, tail) where tail is everything after the final slash. + Either part may be empty.""" + + d, p = splitdrive(p) + # set i to index beyond p's last slash + i = len(p) + while i and p[i-1] not in '/\\': + i = i - 1 + head, tail = p[:i], p[i:] # now tail has no slashes + # remove trailing slashes from head, unless it's all slashes + head2 = head + while head2 and head2[-1] in '/\\': + head2 = head2[:-1] + head = head2 or head + return d + head, tail + + +# Split a path in root and extension. +# The extension is everything starting at the last dot in the last +# pathname component; the root is everything before that. +# It is always true that root + ext == p. + +def splitext(p): + """Split the extension from a pathname. + + Extension is everything from the last dot to the end. + Return (root, ext), either part may be empty.""" + + i = p.rfind('.') + if i<=max(p.rfind('/'), p.rfind('\\')): + return p, '' + else: + return p[:i], p[i:] + + +# Return the tail (basename) part of a path. + +def basename(p): + """Returns the final component of a pathname""" + return split(p)[1] + + +# Return the head (dirname) part of a path. + +def dirname(p): + """Returns the directory component of a pathname""" + return split(p)[0] + + +# Return the longest prefix of all list elements. + +def commonprefix(m): + "Given a list of pathnames, returns the longest common leading component" + if not m: return '' + s1 = min(m) + s2 = max(m) + n = min(len(s1), len(s2)) + for i in xrange(n): + if s1[i] != s2[i]: + return s1[:i] + return s1[:n] + + +# Get size, mtime, atime of files. + +def getsize(filename): + """Return the size of a file, reported by os.stat()""" + return os.stat(filename).st_size + +def getmtime(filename): + """Return the last modification time of a file, reported by os.stat()""" + return os.stat(filename).st_mtime + +def getatime(filename): + """Return the last access time of a file, reported by os.stat()""" + return os.stat(filename).st_atime + +def getctime(filename): + """Return the creation time of a file, reported by os.stat().""" + return os.stat(filename).st_ctime + +# Is a path a symbolic link? +# This will always return false on systems where posix.lstat doesn't exist. + +def islink(path): + """Test for symbolic link. On WindowsNT/95 always returns false""" + return False + + +# Does a path exist? + +def exists(path): + """Test whether a path exists""" + try: + st = os.stat(path) + except os.error: + return False + return True + +lexists = exists + + +# Is a path a dos directory? +# This follows symbolic links, so both islink() and isdir() can be true +# for the same path. + +def isdir(path): + """Test whether a path is a directory""" + try: + st = os.stat(path) + except os.error: + return False + return stat.S_ISDIR(st.st_mode) + + +# Is a path a regular file? +# This follows symbolic links, so both islink() and isdir() can be true +# for the same path. + +def isfile(path): + """Test whether a path is a regular file""" + try: + st = os.stat(path) + except os.error: + return False + return stat.S_ISREG(st.st_mode) + + +if javaos.name != 'java': + # Is a path a mount point? Either a root (with or without drive letter) + # or an UNC path with at most a / or \ after the mount point. + + def ismount(path): + """Test whether a path is a mount point (defined as root of drive)""" + unc, rest = splitunc(path) + if unc: + return rest in ("", "/", "\\") + p = splitdrive(path)[1] + return len(p) == 1 and p[0] in '/\\' + + __all__.append("ismount") + + +# Directory tree walk. +# For each directory under top (including top itself, but excluding +# '.' and '..'), func(arg, dirname, filenames) is called, where +# dirname is the name of the directory and filenames is the list +# of files (and subdirectories etc.) in the directory. +# The func may modify the filenames list, to implement a filter, +# or to impose a different order of visiting. + +def walk(top, func, arg): + """Directory tree walk with callback function. + + For each directory in the directory tree rooted at top (including top + itself, but excluding '.' and '..'), call func(arg, dirname, fnames). + dirname is the name of the directory, and fnames a list of the names of + the files and subdirectories in dirname (excluding '.' and '..'). func + may modify the fnames list in-place (e.g. via del or slice assignment), + and walk will only recurse into the subdirectories whose names remain in + fnames; this can be used to implement a filter, or to impose a specific + order of visiting. No semantics are defined for, or required of, arg, + beyond that arg is always passed to func. It can be used, e.g., to pass + a filename pattern, or a mutable object designed to accumulate + statistics. Passing None for arg is common.""" + + try: + names = os.listdir(top) + except os.error: + return + func(arg, top, names) + exceptions = ('.', '..') + for name in names: + if name not in exceptions: + name = join(top, name) + if isdir(name): + walk(name, func, arg) + + +# Expand paths beginning with '~' or '~user'. +# '~' means $HOME; '~user' means that user's home directory. +# If the path doesn't begin with '~', or if the user or $HOME is unknown, +# the path is returned unchanged (leaving error reporting to whatever +# function is called with the expanded path as argument). +# See also module 'glob' for expansion of *, ? and [...] in pathnames. +# (A function should also be defined to do full *sh-style environment +# variable expansion.) + +def expanduser(path): + """Expand ~ and ~user constructs. + + If user or $HOME is unknown, do nothing.""" + if path[:1] != '~': + return path + i, n = 1, len(path) + while i < n and path[i] not in '/\\': + i = i + 1 + if i == 1: + if 'HOME' in os.environ: + userhome = os.environ['HOME'] + elif not 'HOMEPATH' in os.environ: + return path + else: + try: + drive = os.environ['HOMEDRIVE'] + except KeyError: + drive = '' + userhome = join(drive, os.environ['HOMEPATH']) + else: + return path + return userhome + path[i:] + + +# Expand paths containing shell variable substitutions. +# The following rules apply: +# - no expansion within single quotes +# - no escape character, except for '$$' which is translated into '$' +# - ${varname} is accepted. +# - varnames can be made out of letters, digits and the character '_' +# XXX With COMMAND.COM you can use any characters in a variable name, +# XXX except '^|<>='. + +def expandvars(path): + """Expand shell variables of form $var and ${var}. + + Unknown variables are left unchanged.""" + if '$' not in path: + return path + import string + varchars = string.ascii_letters + string.digits + '_-' + res = '' + index = 0 + pathlen = len(path) + while index < pathlen: + c = path[index] + if c == '\'': # no expansion within single quotes + path = path[index + 1:] + pathlen = len(path) + try: + index = path.index('\'') + res = res + '\'' + path[:index + 1] + except ValueError: + res = res + path + index = pathlen - 1 + elif c == '$': # variable or '$$' + if path[index + 1:index + 2] == '$': + res = res + c + index = index + 1 + elif path[index + 1:index + 2] == '{': + path = path[index+2:] + pathlen = len(path) + try: + index = path.index('}') + var = path[:index] + if var in os.environ: + res = res + os.environ[var] + except ValueError: + res = res + path + index = pathlen - 1 + else: + var = '' + index = index + 1 + c = path[index:index + 1] + while c != '' and c in varchars: + var = var + c + index = index + 1 + c = path[index:index + 1] + if var in os.environ: + res = res + os.environ[var] + if c != '': + res = res + c + else: + res = res + c + index = index + 1 + return res + + +# Normalize a path, e.g. A//B, A/./B and A/foo/../B all become A\B. +# Previously, this function also truncated pathnames to 8+3 format, +# but as this module is called "ntpath", that's obviously wrong! + +def normpath(path): + """Normalize path, eliminating double slashes, etc.""" + path = path.replace("/", "\\") + prefix, path = splitdrive(path) + # We need to be careful here. If the prefix is empty, and the path starts + # with a backslash, it could either be an absolute path on the current + # drive (\dir1\dir2\file) or a UNC filename (\\server\mount\dir1\file). It + # is therefore imperative NOT to collapse multiple backslashes blindly in + # that case. + # The code below preserves multiple backslashes when there is no drive + # letter. This means that the invalid filename \\\a\b is preserved + # unchanged, where a\\\b is normalised to a\b. It's not clear that there + # is any better behaviour for such edge cases. + if prefix == '': + # No drive letter - preserve initial backslashes + while path[:1] == "\\": + prefix = prefix + "\\" + path = path[1:] + else: + # We have a drive letter - collapse initial backslashes + if path.startswith("\\"): + prefix = prefix + "\\" + path = path.lstrip("\\") + comps = path.split("\\") + i = 0 + while i < len(comps): + if comps[i] in ('.', ''): + del comps[i] + elif comps[i] == '..': + if i > 0 and comps[i-1] != '..': + del comps[i-1:i+1] + i -= 1 + elif i == 0 and prefix.endswith("\\"): + del comps[i] + else: + i += 1 + else: + i += 1 + # If the path is now empty, substitute '.' + if not prefix and not comps: + comps.append('.') + return prefix + "\\".join(comps) + + +# Return an absolute path. +try: + from nt import _getfullpathname + +except ImportError: # not running on Windows - mock up something sensible + def abspath(path): + """Return the absolute version of a path.""" + if not isabs(path): + path = join(os.getcwd(), path) + if not splitunc(path)[0] and not splitdrive(path)[0]: + # cwd lacks a UNC mount point, so it should have a drive + # letter (but lacks one): determine it + drive = splitdrive(java.io.File(path).getCanonicalPath())[0] + path = join(drive, path) + return normpath(path) + +else: # use native Windows method on Windows + def abspath(path): + """Return the absolute version of a path.""" + + if path: # Empty path must return current working directory. + try: + path = _getfullpathname(path) + except WindowsError: + pass # Bad path - return unchanged. + else: + path = os.getcwd() + return normpath(path) + +# realpath is a no-op on systems without islink support +realpath = abspath +# Win9x family and earlier have no Unicode filename support. +supports_unicode_filenames = (hasattr(sys, "getwindowsversion") and + sys.getwindowsversion()[3] >= 2) Deleted: branches/utf16/Lib/opcode.py =================================================================== --- branches/utf16/Lib/opcode.py 2008-02-26 06:14:54 UTC (rev 4180) +++ branches/utf16/Lib/opcode.py 2008-02-26 19:36:20 UTC (rev 4181) @@ -1 +0,0 @@ -# stub opcode module added to allow imports Copied: branches/utf16/Lib/posixpath.py (from rev 4180, trunk/jython/Lib/posixpath.py) =================================================================== --- branches/utf16/Lib/posixpath.py (rev 0) +++ branches/utf16/Lib/posixpath.py 2008-02-26 19:36:20 UTC (rev 4181) @@ -0,0 +1,495 @@ +"""Common operations on Posix pathnames. + +Instead of importing this module directly, import os and refer to +this module as os.path. The "os.path" name is an alias for this +module on Posix systems; on other systems (e.g. Mac, Windows), +os.path provides the same operations in a manner specific to that +platform, and is an alias to another module (e.g. macpath, ntpath). + +Some of this can actually be useful on non-Posix systems too, e.g. +for manipulation of the pathname component of URLs. +""" + +import java.io.File +import java.io.IOException +# XXX: os (org.python.modules.os) is broken when we're imported: look at +# javaos.name instead +import javaos +import os +import stat + +__all__ = ["normcase","isabs","join","splitdrive","split","splitext", + "basename","dirname","commonprefix","getsize","getmtime", + "getatime","getctime","islink","exists","lexists","isdir","isfile", + "walk","expanduser","expandvars","normpath","abspath", + "samefile", + "curdir","pardir","sep","pathsep","defpath","altsep","extsep", + "devnull","realpath","supports_unicode_filenames"] + +# strings representing various path-related bits and pieces +curdir = '.' +pardir = '..' +extsep = '.' +sep = '/' +pathsep = ':' +defpath = ':/bin:/usr/bin' +altsep = None +devnull = '/dev/null' + +# Normalize the case of a pathname. Trivial in Posix, string.lower on Mac. +# On MS-DOS this may also turn slashes into backslashes; however, other +# normalizations (such as optimizing '../' away) are not allowed +# (another function should be defined to do that). + +def normcase(s): + """Normalize case of pathname. Has no effect under Posix""" + return s + + +# Return whether a path is absolute. +# Trivial in Posix, harder on the Mac or MS-DOS. + +def isabs(s): + """Test whether a path is absolute""" + return s.startswith('/') + + +# Join pathnames. +# Ignore the previous parts if a part is absolute. +# Insert a '/' unless the first part is empty or already ends in '/'. + +def join(a, *p): + """Join two or more pathname components, inserting '/' as needed""" + path = a + for b in p: + if b.startswith('/'): + path = b + elif path == '' or path.endswith('/'): + path += b + else: + path += '/' + b + return path + + +# Split a path in head (everything up to the last '/') and tail (the +# rest). If the path ends in '/', tail will be empty. If there is no +# '/' in the path, head will be empty. +# Trailing '/'es are stripped from head unless it is the root. + +def split(p): + """Split a pathname. Returns tuple "(head, tail)" where "tail" is + everything after the final slash. Either part may be empty.""" + i = p.rfind('/') + 1 + head, tail = p[:i], p[i:] + if head and head != '/'*len(head): + head = head.rstrip('/') + return head, tail + + +# Split a path in root and extension. +# The extension is everything starting at the last dot in the last +# pathname component; the root is everything before that. +# It is always true that root + ext == p. + +def splitext(p): + """Split the extension from a pathname. Extension is everything from the + last dot to the end. Returns "(root, ext)", either part may be empty.""" + i = p.rfind('.') + if i<=p.rfind('/'): + return p, '' + else: + return p[:i], p[i:] + + +# Split a pathname into a drive specification and the rest of the +# path. Useful on DOS/Windows/NT; on Unix, the drive is always empty. + +def splitdrive(p): + """Split a pathname into drive and path. On Posix, drive is always + empty.""" + return '', p + + +# Return the tail (basename) part of a path. + +def basename(p): + """Returns the final component of a pathname""" + return split(p)[1] + + +# Return the head (dirname) part of a path. + +def dirname(p): + """Returns the directory component of a pathname""" + return split(p)[0] + + +# Return the longest prefix of all list elements. + +def commonprefix(m): + "Given a list of pathnames, returns the longest common leading component" + if not m: return '' + s1 = min(m) + s2 = max(m) + n = min(len(s1), len(s2)) + for i in xrange(n): + if s1[i] != s2[i]: + return s1[:i] + return s1[:n] + +# Get size, mtime, atime of files. + +def getsize(filename): + """Return the size of a file, reported by os.stat().""" + return os.stat(filename).st_size + +def getmtime(filename): + """Return the last modification time of a file, reported by os.stat().""" + return os.stat(filename).st_mtime + +def getatime(filename): + """Return the last access time of a file, reported by os.stat().""" + return os.stat(filename).st_atime + +def getctime(filename): + """Return the metadata change time of a file, reported by os.stat().""" + return os.stat(filename).st_ctime + +# Is a path a symbolic link? +# This will always return false on systems where os.lstat doesn't exist. + +def islink(path): + """Test whether a path is a symbolic link""" + try: + st = os.lstat(path) + except (os.error, AttributeError): + return False + return stat.S_ISLNK(st.st_mode) + + +# Does a path exist? +# This is false for dangling symbolic links. + +def exists(path): + """Test whether a path exists. Returns False for broken symbolic links""" + try: + st = os.stat(path) + except os.error: + return False + return True + + +# Being true for dangling symbolic links is also useful. + +def lexists(path): + """Test whether a path exists. Returns True for broken symbolic links""" + try: + st = os.lstat(path) + except os.error: + return False + return True + + +# Is a path a directory? +# This follows symbolic links, so both islink() and isdir() can be true +# for the same path. + +def isdir(path): + """Test whether a path is a directory""" + try: + st = os.stat(path) + except os.error: + return False + return stat.S_ISDIR(st.st_mode) + + +# Is a path a regular file? +# This follows symbolic links, so both islink() and isfile() can be true +# for the same path. + +def isfile(path): + """Test whether a path is a regular file""" + try: + st = os.stat(path) + except os.error: + return False + return stat.S_ISREG(st.st_mode) + + +# Are two filenames really pointing to the same file? + +if javaos.name == 'java': + def samefile(f1, f2): + """Test whether two pathnames reference the same actual file""" + canon1 = java.io.File(_ensure_str(f1)).getCanonicalPath() + canon2 = java.io.File(_ensure_str(f2)).getCanonicalPath() + return canon1 == canon2 +else: + def samefile(f1, f2): + """Test whether two pathnames reference the same actual file""" + s1 = os.stat(f1) + s2 = os.stat(f2) + return samestat(s1, s2) + + +# XXX: Plain Jython lacks fstat and st_ino/st_dev +if javaos.name != 'java': + # Are two open files really referencing the same file? + # (Not necessarily the same file descriptor!) + + def sameopenfile(fp1, fp2): + """Test whether two open file objects reference the same file""" + s1 = os.fstat(fp1) + s2 = os.fstat(fp2) + return samestat(s1, s2) + + + # Are two stat buffers (obtained from stat, fstat or lstat) + # describing the same file? + + def samestat(s1, s2): + """Test whether two stat buffers reference the same file""" + return s1.st_ino == s2.st_ino and \ + s1.st_dev == s2.st_dev + + + # Is a path a mount point? + # (Does this work for all UNIXes? Is it even guaranteed to work by Posix?) + + def ismount(path): + """Test whether a path is a mount point""" + try: + s1 = os.lstat(path) + s2 = os.lstat(join(path, '..')) + except os.error: + return False # It doesn't exist -- so not a mount point :-) + dev1 = s1.st_dev + dev2 = s2.st_dev + if dev1 != dev2: + return True # path/.. on a different device as path + ino1 = s1.st_ino + ino2 = s2.st_ino + if ino1 == ino2: + return True # path/.. is the same i-node as path + return False + + __all__.extend(["sameopenfile", "samestat", "ismount"]) + + +# Directory tree walk. +# For each directory under top (including top itself, but excluding +# '.' and '..'), func(arg, dirname, filenames) is called, where +# dirname is the name of the directory and filenames is the list +# of files (and subdirectories etc.) in the directory. +# The func may modify the filenames list, to implement a filter, +# or to impose a different order of visiting. + +def walk(top, func, arg): + """Directory tree walk with callback function. + + For each directory in the directory tree rooted at top (including top + itself, but excluding '.' and '..'), call func(arg, dirname, fnames). + dirname is the name of the directory, and fnames a list of the names of + the files and subdirectories in dirname (excluding '.' and '..'). func + may modify the fnames list in-place (e.g. via del or slice assignment), + and walk will only recurse into the subdirectories whose names remain in + fnames; this can be used to implement a filter, or to impose a specific + order of visiting. No semantics are defined for, or required of, arg, + beyond that arg is always passed to func. It can be used, e.g., to pass + a filename pattern, or a mutable object designed to accumulate + statistics. Passing None for arg is common.""" + + try: + names = os.listdir(top) + except os.error: + return + func(arg, top, names) + for name in names: + name = join(top, name) + try: + st = os.lstat(name) + except os.error: + continue + if stat.S_ISDIR(st.st_mode): + walk(name, func, arg) + + +# Expand paths beginning with '~' or '~user'. +# '~' means $HOME; '~user' means that user's home directory. +# If the path doesn't begin with '~', or if the user or $HOME is unknown, +# the path is returned unchanged (leaving error reporting to whatever +# function is called with the expanded path as argument). +# See also module 'glob' for expansion of *, ? and [...] in pathnames. +# (A function should also be defined to do full *sh-style environment +# variable expansion.) + +def expanduser(path): + """Expand ~ and ~user constructions. If user or $HOME is unknown, + do nothing.""" + if not path.startswith('~'): + return path + i = path.find('/', 1) + if i < 0: + i = len(path) + if i == 1: + if 'HOME' not in os.environ: + return path + else: + userhome = os.environ['HOME'] + else: + # XXX: Jython lacks the pwd module: '~user' isn't supported + return path + userhome = userhome.rstrip('/') + return userhome + path[i:] + + +# Expand paths containing shell variable substitutions. +# This expands the forms $variable and ${variable} only. +# Non-existent variables are left unchanged. + +_varprog = None + +def expandvars(path): + """Expand shell variables of form $var and ${var}. Unknown variables + are left unchanged.""" + global _varprog + if '$' not in path: + return path + if not _varprog: + import re + _varprog = re.compile(r'\$(\w+|\{[^}]*\})') + i = 0 + while True: + m = _varprog.search(path, i) + if not m: + break + i, j = m.span(0) + name = m.group(1) + if name.startswith('{') and name.endswith('}'): + name = name[1:-1] + if name in os.environ: + tail = path[j:] + path = path[:i] + os.environ[name] + i = len(path) + path += tail + else: + i = j + return path + + +# Normalize a path, e.g. A//B, A/./B and A/foo/../B all become A/B. +# It should be understood that this may change the meaning of the path +# if it contains symbolic links! + +def normpath(path): + """Normalize path, eliminating double slashes, etc.""" + if path == '': + return '.' + initial_slashes = path.startswith('/') + # POSIX allows one or two initial slashes, but treats three or more + # as single slash. + if (initial_slashes and + path.startswith('//') and not path.startswith('///')): + initial_slashes = 2 + comps = path.split('/') + new_comps = [] + for comp in comps: + if comp in ('', '.'): + continue + if (comp != '..' or (not initial_slashes and not new_comps) or + (new_comps and new_comps[-1] == '..')): + new_comps.append(comp) + elif new_comps: + new_comps.pop() + comps = new_comps + path = '/'.join(comps) + if initial_slashes: + path = '/'*initial_slashes + path + return path or '.' + + +def abspath(path): + """Return an absolute path.""" + if not isabs(path): + path = join(os.getcwd(), path) + return normpath(path) + + +# Return a canonical path (i.e. the absolute location of a file on the +# filesystem). + +def realpath(filename): + """Return the canonical path of the specified filename, eliminating any +symbolic links encountered in the path.""" + if isabs(filename): + bits = ['/'] + filename.split('/')[1:] + else: + bits = [''] + filename.split('/') + + for i in range(2, len(bits)+1): + component = join(*bits[0:i]) + # Resolve symbolic links. + if islink(component): + resolved = _resolve_link(component) + if resolved is None: + # Infinite loop -- return original component + rest of the path + return abspath(join(*([component] + bits[i:]))) + else: + newpath = join(*([resolved] + bits[i:])) + return realpath(newpath) + + return abspath(filename) + + +if javaos.name == 'java': + def _resolve_link(path): + """Internal helper function. Takes a path and follows symlinks + until we either arrive at something that isn't a symlink, or + encounter a path we've seen before (meaning that there's a loop). + """ + try: + return str(java.io.File(abspath(path)).getCanonicalPath()) + except java.io.IOException: + return None +else: + def _resolve_link(path): + """Internal helper function. Takes a path and follows symlinks + until we either arrive at something that isn't a symlink, or + encounter a path we've seen before (meaning that there's a loop). + """ + paths_seen = [] + while islink(path): + if path in paths_seen: + # Already seen this path, so we must have a symlink loop + return None + paths_seen.append(path) + # Resolve where the link points to + resolved = os.readlink(path) + if not isabs(resolved): + dir = dirname(path) + path = normpath(join(dir, resolved)) + else: + path = normpath(resolved) + return path + + +def _ensure_str(obj): + """Ensure obj is a string, otherwise raise a TypeError""" + if isinstance(obj, basestring): + return obj + raise TypeError('coercing to Unicode: need string or buffer, %s found' % \ + _type_name(obj)) + + +def _type_name(obj): + """Determine the appropriate type name of obj for display""" + TPFLAGS_HEAPTYPE = 1 << 9 + type_name = '' + obj_type = type(obj) + is_heap = obj_type.__flags__ & TPFLAGS_HEAPTYPE == TPFLAGS_HEAPTYPE + if not is_heap and obj_type.__module__ != '__builtin__': + type_name = '%s.' % obj_type.__module__ + type_name += obj_type.__name__ + return type_name + +supports_unicode_filenames = False Modified: branches/utf16/Lib/subprocess.py =================================================================== --- branches/utf16/Lib/subprocess.py 2008-02-26 06:14:54 UTC (rev 4180) +++ branches/utf16/Lib/subprocess.py 2008-02-26 19:36:20 UTC (rev 4181) @@ -397,7 +397,6 @@ error = IOError elif jython: import errno - import javashell import threading import java.io.File import java.io.FileDescriptor @@ -545,13 +544,45 @@ if jython: - if javashell._getOsType() in ('nt', 'dos'): - # Escape the command line arguments on Windows - escape_args = lambda args: [list2cmdline([arg]) for arg in args] - else: - escape_args = lambda args: args + # Escape the command line arguments with list2cmdline on Windows + escape_args_oses = ['nt', 'ce'] + escape_args = None + shell_command = None + def setup_platform(): + """Setup the shell command and the command line argument escape + function depending on the underlying platform + """ + global escape_args, shell_command + + if os._name in escape... [truncated message content] |