From jython-checkins at python.org Mon May 4 23:24:12 2015 From: jython-checkins at python.org (jeff.allen) Date: Mon, 04 May 2015 21:24:12 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_test=5Fimport_runs_on_Windo?= =?utf-8?q?ws=2E_Fixes_=233210=2E?= Message-ID: <20150504212412.8151.84543@psf.io> https://hg.python.org/jython/rev/85f7eda810b2 changeset: 7699:85f7eda810b2 user: Jeff Allen date: Mon Apr 20 18:36:05 2015 +0100 summary: test_import runs on Windows. Fixes #3210. files: Lib/test/symlink_support.py | 3 ++- NEWS | 1 + src/org/python/modules/posix/PosixModule.java | 8 +++++++- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/Lib/test/symlink_support.py b/Lib/test/symlink_support.py --- a/Lib/test/symlink_support.py +++ b/Lib/test/symlink_support.py @@ -13,7 +13,8 @@ try: symlink(TESTFN, symlink_path) can = True - except (OSError, NotImplementedError, AttributeError): + except (OSError, NotImplementedError, AttributeError, TypeError): + # Not allowed, not implemented, or symlink is None. can = False else: os.remove(symlink_path) diff --git a/NEWS b/NEWS --- a/NEWS +++ b/NEWS @@ -7,6 +7,7 @@ - [ 2326 ] Java's weakly consistent iteration of ConcurrentMap is compatible with mutation - [ 1572 ] sys-package-mgr console messages silenced by default. Thanks to Emmanuel Jannetti. - [ 2332 ] jython -m test.regrtest -e now finds the tests it should. + - [ 2310 ] test_import runs on Windows (and passes with 4 skips). Jython 2.7rc2 Bugs fixed 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 @@ -307,10 +307,16 @@ public static PyString __doc__chmod = new PyString( "chmod(path, mode)\n\n" + "Change the access permissions of a file."); + public static void chmod(PyObject path, int mode) { if (os == OS.NT) { try { - if (!absolutePath(path).toFile().setWritable((mode & FileStat.S_IWUSR) != 0)) { + // We can only allow/deny write access (not read & execute) + boolean writable = (mode & FileStat.S_IWUSR) != 0; + File f = absolutePath(path).toFile(); + if (!f.exists()) { + throw Py.OSError(Errno.ENOENT, path); + } else if (!f.setWritable(writable)) { throw Py.OSError(Errno.EPERM, path); } } catch (SecurityException ex) { -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Mon May 4 23:24:13 2015 From: jython-checkins at python.org (jeff.allen) Date: Mon, 04 May 2015 21:24:13 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Increment_the_API_version_?= =?utf-8?q?=28see_=232158=29_=26_enable_detailed_error_messages=2E?= Message-ID: <20150504212413.7808.89844@psf.io> https://hg.python.org/jython/rev/cb5bc04f17d1 changeset: 7703:cb5bc04f17d1 user: Jeff Allen date: Mon May 04 11:16:59 2015 +0100 summary: Increment the API version (see #2158) & enable detailed error messages. Forces recompilation from source where old $py.class files may contain incorrectly-generated import calls. When only a compiled file is found, long-lost meaningful ImportError messages have been re-enabled. files: src/org/python/core/imp.java | 17 +++++++++-------- 1 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/org/python/core/imp.java b/src/org/python/core/imp.java --- a/src/org/python/core/imp.java +++ b/src/org/python/core/imp.java @@ -28,7 +28,7 @@ private static final String UNKNOWN_SOURCEFILE = ""; - private static final int APIVersion = 36; + private static final int APIVersion = 37; public static final int NO_MTIME = -1; @@ -208,7 +208,7 @@ String sourceName, String compiledName, long mtime, CodeImport source) { CodeData data = null; try { - data = readCodeData(name, fp, testing, mtime); + data = readCodeData(compiledName, fp, testing, mtime); } catch (IOException ioe) { if (!testing) { throw Py.ImportError(ioe.getMessage() + "[name=" + name + ", source=" + sourceName @@ -264,8 +264,8 @@ if (testing) { return null; } else { - throw Py.ImportError("invalid api version(" + api + " != " + APIVersion + ") in: " - + name); + String fmt = "compiled unit contains version %d code (%d required): %.200s"; + throw Py.ImportError(String.format(fmt, api, APIVersion, name)); } } if (testing && mtime != NO_MTIME) { @@ -639,9 +639,9 @@ Py.writeDebug(IMPORT_LOG, "trying precompiled " + compiledFile.getPath()); long classTime = compiledFile.lastModified(); if (classTime >= pyTime) { - PyObject ret = - createFromPyClass(modName, makeStream(compiledFile), true, - displaySourceName, displayCompiledName, pyTime); + PyObject ret = createFromPyClass(modName, makeStream(compiledFile), // + true, // OK to fail here as we have the source + displaySourceName, displayCompiledName, pyTime); if (ret != null) { return ret; } @@ -656,7 +656,8 @@ // If no source, try loading precompiled Py.writeDebug(IMPORT_LOG, "trying precompiled with no source " + compiledFile.getPath()); if (compiledFile.isFile() && caseok(compiledFile, compiledName)) { - return createFromPyClass(modName, makeStream(compiledFile), true, + return createFromPyClass(modName, makeStream(compiledFile), // + false, // throw ImportError here if this fails displaySourceName, displayCompiledName, NO_MTIME, CodeImport.compiled_only); } } catch (SecurityException e) { -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Mon May 4 23:24:13 2015 From: jython-checkins at python.org (jeff.allen) Date: Mon, 04 May 2015 21:24:13 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Add_test/symlink=5Fsupport?= =?utf-8?q?=2Epy_from_lib-python_to_Lib_=28unchanged=29=2E?= Message-ID: <20150504212412.8946.36867@psf.io> https://hg.python.org/jython/rev/0880c395a7ae changeset: 7698:0880c395a7ae parent: 7686:5e12eb29a6bb user: Jeff Allen date: Mon Apr 20 11:04:14 2015 +0100 summary: Add test/symlink_support.py from lib-python to Lib (unchanged). Added unchanged, so we can easily see the change when it comes. files: Lib/test/symlink_support.py | 100 ++++++++++++++++++++++++ 1 files changed, 100 insertions(+), 0 deletions(-) diff --git a/Lib/test/symlink_support.py b/Lib/test/symlink_support.py new file mode 100644 --- /dev/null +++ b/Lib/test/symlink_support.py @@ -0,0 +1,100 @@ +import os +import unittest +import platform + +from test.test_support import TESTFN + +def can_symlink(): + # cache the result in can_symlink.prev_val + prev_val = getattr(can_symlink, 'prev_val', None) + if prev_val is not None: + return prev_val + symlink_path = TESTFN + "can_symlink" + try: + symlink(TESTFN, symlink_path) + can = True + except (OSError, NotImplementedError, AttributeError): + can = False + else: + os.remove(symlink_path) + can_symlink.prev_val = can + return can + +def skip_unless_symlink(test): + """Skip decorator for tests that require functional symlink""" + ok = can_symlink() + msg = "Requires functional symlink implementation" + return test if ok else unittest.skip(msg)(test) + +def _symlink_win32(target, link, target_is_directory=False): + """ + Ctypes symlink implementation since Python doesn't support + symlinks in windows yet. Borrowed from jaraco.windows project. + """ + import ctypes.wintypes + CreateSymbolicLink = ctypes.windll.kernel32.CreateSymbolicLinkW + CreateSymbolicLink.argtypes = ( + ctypes.wintypes.LPWSTR, + ctypes.wintypes.LPWSTR, + ctypes.wintypes.DWORD, + ) + CreateSymbolicLink.restype = ctypes.wintypes.BOOLEAN + + def format_system_message(errno): + """ + Call FormatMessage with a system error number to retrieve + the descriptive error message. + """ + # first some flags used by FormatMessageW + ALLOCATE_BUFFER = 0x100 + ARGUMENT_ARRAY = 0x2000 + FROM_HMODULE = 0x800 + FROM_STRING = 0x400 + FROM_SYSTEM = 0x1000 + IGNORE_INSERTS = 0x200 + + # Let FormatMessageW allocate the buffer (we'll free it below) + # Also, let it know we want a system error message. + flags = ALLOCATE_BUFFER | FROM_SYSTEM + source = None + message_id = errno + language_id = 0 + result_buffer = ctypes.wintypes.LPWSTR() + buffer_size = 0 + arguments = None + bytes = ctypes.windll.kernel32.FormatMessageW( + flags, + source, + message_id, + language_id, + ctypes.byref(result_buffer), + buffer_size, + arguments, + ) + # note the following will cause an infinite loop if GetLastError + # repeatedly returns an error that cannot be formatted, although + # this should not happen. + handle_nonzero_success(bytes) + message = result_buffer.value + ctypes.windll.kernel32.LocalFree(result_buffer) + return message + + def handle_nonzero_success(result): + if result == 0: + value = ctypes.windll.kernel32.GetLastError() + strerror = format_system_message(value) + raise WindowsError(value, strerror) + + target_is_directory = target_is_directory or os.path.isdir(target) + handle_nonzero_success(CreateSymbolicLink(link, target, target_is_directory)) + +symlink = os.symlink if hasattr(os, 'symlink') else ( + _symlink_win32 if platform.system() == 'Windows' else None +) + +def remove_symlink(name): + # On Windows, to remove a directory symlink, one must use rmdir + try: + os.rmdir(name) + except OSError: + os.remove(name) -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Mon May 4 23:24:12 2015 From: jython-checkins at python.org (jeff.allen) Date: Mon, 04 May 2015 21:24:12 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Formatting_changes_=28white?= =?utf-8?q?space_only=29_to_import-related_files=2E?= Message-ID: <20150504212412.1933.58138@psf.io> https://hg.python.org/jython/rev/8362eac6b151 changeset: 7700:8362eac6b151 user: Jeff Allen date: Mon Apr 27 18:50:38 2015 +0100 summary: Formatting changes (whitespace only) to import-related files. files: Lib/test/test_import_pep328.py | 63 +- src/org/python/compiler/CodeCompiler.java | 571 ++++----- src/org/python/core/imp.java | 533 ++++---- 3 files changed, 569 insertions(+), 598 deletions(-) diff --git a/Lib/test/test_import_pep328.py b/Lib/test/test_import_pep328.py --- a/Lib/test/test_import_pep328.py +++ b/Lib/test/test_import_pep328.py @@ -48,12 +48,12 @@ class TestImportStatement(unittest.TestCase): """Test the 'import' and 'from ... import' statements - + This class tests, how the compiler calls the '__import__'-function for various forms of the 'import' and 'from ... import' statements. """ - + AI = "from __future__ import absolute_import ;" def importFunction(*args): @@ -73,15 +73,15 @@ g = {} try: exec statement in g, l - except TestImportStatementError,e: + except TestImportStatementError, e: self.assert_(e.globals is g, "globals is changed") self.assert_(e.locals is l, "locals is changed") return e self.fail("Expected a TestImportStatementError") - + def testFromDotsOnly(self): dots = '' - for i in range(1,10): + for i in range(1, 10): dots += '.' a = self.runImport("from %s import (A,B)" % (dots,)) self.assertEqual(a.len, 5) @@ -91,7 +91,7 @@ def testFromDotsOnlyAs(self): dots = '' - for i in range(1,10): + for i in range(1, 10): dots += '.' a = self.runImport("from %s import A as B" % (dots,)) self.assertEqual(a.len, 5) @@ -101,7 +101,7 @@ def testFromDotsAndName(self): dots = '' - for i in range(1,10): + for i in range(1, 10): dots += '.' a = self.runImport("from %sX import A" % (dots,)) self.assertEqual(a.len, 5) @@ -111,14 +111,14 @@ def testFromDotsAndDotedName(self): dots = '' - for i in range(1,10): + for i in range(1, 10): dots += '.' a = self.runImport("from %sX.Y import A" % (dots,)) self.assertEqual(a.len, 5) self.assertEqual(a.name, "X.Y") self.assertEqual(a.fromlist, ('A',)) self.assertEqual(a.level, i) - + def testAbsoluteFromDotedNameAs(self): a = self.runImport(self.AI + "from X.Y import A as B") self.assertEqual(a.len, 5) @@ -158,7 +158,7 @@ self.assertEqual(a.name, "X.Y") self.assertEqual(a.fromlist, None) self.assertEqual(a.level, 0) - + def testRelativeOrAbsoluteImportName(self): a = self.runImport("import X") self.assertEqual(a.name, "X") @@ -184,13 +184,13 @@ class TestImportFunction(unittest.TestCase): """Test the '__import__' function - + This class tests, how the '__import__'-function resolves module names. It uses the 'meta_path' hook, to intercept the actual module loading. - + Module Structure: - + Top \---- X package | \-- Y package @@ -198,27 +198,26 @@ | | \-- Z2 module | \-- Y2 package \---- X2 module - + """ nameX = "TestImportFunctionX" - def setUp(self): self.modX = imp.new_module(self.nameX) self.modX.__path__ = ['X'] - - self.modX2 = imp.new_module(self.nameX+"2") - self.modY = imp.new_module(self.nameX+".Y") + + self.modX2 = imp.new_module(self.nameX + "2") + self.modY = imp.new_module(self.nameX + ".Y") self.modY.__path__ = ['X/Y'] - self.modY2 = imp.new_module(self.nameX+".Y2") + self.modY2 = imp.new_module(self.nameX + ".Y2") self.modY2.__path__ = ['X/Y'] - self.modZ1 = imp.new_module(self.nameX+".Y.Z1") - self.modZ2 = imp.new_module(self.nameX+".Y.Z2") + self.modZ1 = imp.new_module(self.nameX + ".Y.Z1") + self.modZ2 = imp.new_module(self.nameX + ".Y.Z2") self.expected = "something_completely_different" sys.meta_path.insert(0, self) - + def tearDown(self): try: sys.meta_path.remove(self) @@ -227,40 +226,44 @@ for k in sys.modules.keys(): if k.startswith(self.nameX): del sys.modules[k] - + def importX(self): sys.modules[self.modX.__name__] = self.modX + def importX2(self): sys.modules[self.modX2.__name__] = self.modX2 + def importY(self): self.importX() sys.modules[self.modY.__name__] = self.modY self.modX.Y = self.modY + def importY2(self): self.importX() sys.modules[self.modY2.__name__] = self.modY2 self.modX.Y2 = self.modY2 + def importZ1(self): self.importY() sys.modules[self.modZ1.__name__] = self.modZ1 self.modY.Z1 = self.modZ1 + def top(self): if sys.modules.has_key("__main__"): return sys.modules["__main__"].__dict__ return globals() - def find_module(self, fullname, path=None): if self.expected and self.expected != fullname: return None self.fullname = fullname self.path = path return self - + def load_module(self, fullname): self.assertEqual(fullname, self.fullname) raise TestImportFunctionError() - + def runImport(self, expected, name, globals, fromlist=None, level=None): self.expected = expected if isinstance(globals, types.ModuleType): @@ -269,11 +272,11 @@ if level is not None: __import__(name, globals, None, fromlist, level) else: - __import__(name, globals, None, fromlist) + __import__(name, globals, None, fromlist) except TestImportFunctionError: return self.fail("Expected a TestImportFunctionError") - + def testRelativeOrAbsolute_top_X2_1(self): self.runImport(None, self.modX2.__name__, self.top()) self.assertEqual(self.fullname, self.modX2.__name__) @@ -284,7 +287,6 @@ self.assertEqual(self.fullname, self.modX2.__name__) self.assertEqual(self.path, None) - def testRelativeOrAbsolute_top_Y_1(self): self.importX() self.runImport(None, self.modY.__name__, self.top()) @@ -297,7 +299,6 @@ self.assertEqual(self.fullname, self.modY.__name__) self.assertEqual(self.path, ['X']) - def testAbsolute_top_X2(self): self.runImport(None, self.modX2.__name__, globals(), None, 0) self.assertEqual(self.fullname, self.modX2.__name__) @@ -356,7 +357,7 @@ def testRelative_Z1_Y2(self): self.importZ1() self.runImport(None, "", self.modZ1, ["Y2"], 2) - self.assertEqual(self.fullname, self.modX.__name__+".Y2") + self.assertEqual(self.fullname, self.modX.__name__ + ".Y2") self.assertEqual(self.path, ['X']) def testRelative_Z1_X2(self): diff --git a/src/org/python/compiler/CodeCompiler.java b/src/org/python/compiler/CodeCompiler.java --- a/src/org/python/compiler/CodeCompiler.java +++ b/src/org/python/compiler/CodeCompiler.java @@ -126,12 +126,11 @@ private Vector