[Jython-checkins] jython: Support os.chdir for Unicode paths on Windows

jim.baker jython-checkins at python.org
Fri Feb 6 20:40:23 CET 2015


https://hg.python.org/jython/rev/8b2db200158f
changeset:   7572:8b2db200158f
user:        Jim Baker <jim.baker at rackspace.com>
date:        Fri Feb 06 12:40:17 2015 -0700
summary:
  Support os.chdir for Unicode paths on Windows

files:
  Lib/test/test_os_jy.py                        |  38 +++++++--
  Lib/test/test_support.py                      |   3 +-
  src/org/python/core/PyString.java             |   4 +-
  src/org/python/modules/posix/OS.java          |   2 +-
  src/org/python/modules/posix/PosixModule.java |  38 +++++++--
  5 files changed, 62 insertions(+), 23 deletions(-)


diff --git a/Lib/test/test_os_jy.py b/Lib/test/test_os_jy.py
--- a/Lib/test/test_os_jy.py
+++ b/Lib/test/test_os_jy.py
@@ -173,14 +173,26 @@
            
             # glob.glob builds on os.listdir; note that we don't use
             # Unicode paths in the arg to glob
-            self.assertEqual(glob.glob("unicode/*"), [u"unicode/中文"])
-            self.assertEqual(glob.glob("unicode/*/*"), [u"unicode/中文/首页"])
-            self.assertEqual(glob.glob("unicode/*/*/*"), [u"unicode/中文/首页/test.txt"])
+            self.assertEqual(
+                glob.glob(os.path.join("unicode", "*")),
+                [os.path.join(u"unicode", u"中文")])
+            self.assertEqual(
+                glob.glob(os.path.join("unicode", "*", "*")),
+                [os.path.join(u"unicode", u"中文", u"首页")])
+            self.assertEqual(
+                glob.glob(os.path.join("unicode", "*", "*", "*")),
+                [os.path.join(u"unicode", u"中文", u"首页", "test.txt")])
 
-            # Now use a Unicode path as well as the glob arg
-            self.assertEqual(glob.glob(u"unicode/*"), [u"unicode/中文"])
-            self.assertEqual(glob.glob(u"unicode/*/*"), [u"unicode/中文/首页"])
-            self.assertEqual(glob.glob(u"unicode/*/*/*"), [u"unicode/中文/首页/test.txt"])
+            # Now use a Unicode path as well as in the glob arg
+            self.assertEqual(
+                glob.glob(os.path.join(u"unicode", "*")),
+                [os.path.join(u"unicode", u"中文")])
+            self.assertEqual(
+                glob.glob(os.path.join(u"unicode", "*", "*")),
+                [os.path.join(u"unicode", u"中文", u"首页")])
+            self.assertEqual(
+                glob.glob(os.path.join(u"unicode", "*", "*", "*")),
+                [os.path.join(u"unicode", u"中文", u"首页", "test.txt")])
  
             # Verify Java integration. But we will need to construct
             # an absolute path since chdir doesn't work with Java
@@ -201,8 +213,8 @@
         try:
             installed_codes = dict(((normalize(code), code) for 
                                     code in subprocess.check_output(["locale", "-a"]).split()))
-        except subprocess.CalledProcessError:
-            unittest.skip("locale command not available, cannot test")
+        except (subprocess.CalledProcessError, OSError):
+            raise unittest.SkipTest("locale command not available, cannot test")
 
         if msg is None:
             msg = "One of %s tested locales is not installed" % (codes,)
@@ -231,7 +243,7 @@
         self.get_installed_locales(["tr_TR.UTF-8"], "Turkish locale not installed, cannot test")
         newenv = os.environ.copy()
         newenv["LC_ALL"] = "tr_TR.UTF-8"  # set to Turkish locale
-        self.assertEqual(
+        self.assertIn(
             subprocess.check_output(
                 [sys.executable, "-c",
                  'print repr(["I".lower(), u"I".lower(), "i".upper(), u"i".upper()])'],
@@ -239,7 +251,11 @@
             # Should not convert str for 'i'/'I', but should convert
             # unicode if in Turkish locale; this behavior intentionally is
             # different than CPython; see also http://bugs.python.org/issue17252
-            "['i', u'\\u0131', 'I', u'\\u0130']\n")
+            # 
+            # Note that JVMs seem to have some latitude here however, so support
+            # either for now.
+            ["['i', u'\\u0131', 'I', u'\\u0130']\n",
+             "['i', u'i', 'I', u'I']\n"])
 
     def test_strptime_locale(self):
         # Verifies fix of http://bugs.jython.org/issue2261
diff --git a/Lib/test/test_support.py b/Lib/test/test_support.py
--- a/Lib/test/test_support.py
+++ b/Lib/test/test_support.py
@@ -189,7 +189,7 @@
     except KeyError:
         pass
 
-if sys.platform.startswith("win") or os.name == "java" and os._name == "nt":
+if sys.platform.startswith("win") or (os.name == "java" and os._name == "nt"):
     def _waitfor(func, pathname, waitall=False):
         # Peform the operation
         func(pathname)
@@ -220,6 +220,7 @@
             # Increase the timeout and try again
             time.sleep(timeout)
             timeout *= 2
+        print "Still cannot delete", pathname
         warnings.warn('tests may fail, delete still pending for ' + pathname,
                       RuntimeWarning, stacklevel=4)
 
diff --git a/src/org/python/core/PyString.java b/src/org/python/core/PyString.java
--- a/src/org/python/core/PyString.java
+++ b/src/org/python/core/PyString.java
@@ -1049,7 +1049,7 @@
 
     @ExposedMethod(doc = BuiltinDocs.str_lower_doc)
     final String str_lower() {
-        return getString().toLowerCase(Locale.ENGLISH);
+        return getString().toLowerCase(Locale.ROOT);
     }
 
     public String upper() {
@@ -1058,7 +1058,7 @@
 
     @ExposedMethod(doc = BuiltinDocs.str_upper_doc)
     final String str_upper() {
-        return getString().toUpperCase(Locale.ENGLISH);
+        return getString().toUpperCase(Locale.ROOT);
     }
 
     public String title() {
diff --git a/src/org/python/modules/posix/OS.java b/src/org/python/modules/posix/OS.java
--- a/src/org/python/modules/posix/OS.java
+++ b/src/org/python/modules/posix/OS.java
@@ -33,7 +33,7 @@
     }
 
     String getModuleName() {
-        return name().toLowerCase(Locale.ENGLISH);
+        return name().toLowerCase(Locale.ROOT);
     }
 
     String[][] getShellCommands() {
diff --git a/src/org/python/modules/posix/PosixModule.java b/src/org/python/modules/posix/PosixModule.java
--- a/src/org/python/modules/posix/PosixModule.java
+++ b/src/org/python/modules/posix/PosixModule.java
@@ -17,6 +17,7 @@
 import java.nio.file.LinkOption;
 import java.nio.file.NoSuchFileException;
 import java.nio.file.Path;
+import java.nio.file.attribute.BasicFileAttributes;
 import java.nio.file.attribute.DosFileAttributes;
 import java.security.SecureRandom;
 import java.util.Iterator;
@@ -85,9 +86,6 @@
     private static final int W_OK = 1 << 1;
     private static final int R_OK = 1 << 2;
 
-    /** os.path.realpath function for use by chdir. Lazily loaded. */
-    private static volatile PyObject realpath;
-
     /** Lazily initialzed singleton source for urandom. */
     private static class UrandomSource {
         static final SecureRandom INSTANCE = new SecureRandom();
@@ -282,14 +280,15 @@
         "Change the current working directory to the specified path.");
     public static void chdir(PyObject path) {
         // stat raises ENOENT for us if path doesn't exist
-        if (!posix.stat(absolutePath(path).toString()).isDirectory()) {
+        Path absolutePath = absolutePath(path);
+        if (!basicstat(path, absolutePath).isDirectory()) {
             throw Py.OSError(Errno.ENOTDIR, path);
         }
-
-        if (realpath == null) {
-            realpath = imp.load("os.path").__getattr__("realpath");
+        try {
+            Py.getSystemState().setCurrentWorkingDir(absolutePath.toRealPath().toString());
+        } catch (IOException ioe) {
+            throw Py.OSError(ioe);
         }
-        Py.getSystemState().setCurrentWorkingDir(realpath.__call__(path).asString());
     }
 
     public static PyString __doc__chmod = new PyString(
@@ -1122,6 +1121,23 @@
         }
     }
 
+    private static BasicFileAttributes basicstat(PyObject path, Path absolutePath) {
+        try {
+            BasicFileAttributes attributes = Files.readAttributes(absolutePath, BasicFileAttributes.class);
+            if (!attributes.isDirectory()) {
+                String pathStr = path.toString();
+                if (pathStr.endsWith(File.separator) || pathStr.endsWith("/")) {
+                    throw Py.OSError(Errno.ENOTDIR, path);
+                }
+            }
+            return attributes;
+        } catch (NoSuchFileException ex) {
+            throw Py.OSError(Errno.ENOENT, path);
+        } catch (IOException ioe) {
+            throw Py.OSError(Errno.EBADF, path);
+        }
+    }
+
     static class LstatFunction extends PyBuiltinFunctionNarrow {
         LstatFunction() {
             super("lstat", 1, 1,
@@ -1216,6 +1232,12 @@
             Path absolutePath = absolutePath(path);
             try {
                 DosFileAttributes attributes = Files.readAttributes(absolutePath, DosFileAttributes.class);
+                if (!attributes.isDirectory()) {
+                    String pathStr = path.toString();
+                    if (pathStr.endsWith(File.separator) || pathStr.endsWith("/")) {
+                        throw Py.OSError(Errno.ENOTDIR, path);
+                    }
+                }
                 int mode = attributes_to_mode(attributes);
                 String extension = com.google.common.io.Files.getFileExtension(absolutePath.toString());
                 if (extension.equals("bat") || extension.equals("cmd") || extension.equals("exe") || extension.equals("com")) {

-- 
Repository URL: https://hg.python.org/jython


More information about the Jython-checkins mailing list