From jython-checkins at python.org Thu Oct 1 20:17:57 2015 From: jython-checkins at python.org (jim.baker) Date: Thu, 01 Oct 2015 18:17:57 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Detail_why_NotImplemented_w?= =?utf-8?q?hen_calling_abstract_Java_methods?= Message-ID: <20151001181756.11696.59070@psf.io> https://hg.python.org/jython/rev/62f6901dc1ee changeset: 7737:62f6901dc1ee user: Jim Baker date: Thu Oct 01 13:15:43 2015 -0500 summary: Detail why NotImplemented when calling abstract Java methods Now provides the class of the object, the specific method that is NotImplemented, and the Java class or interface that defines the abstract method. Example: NotImplementedError: 'ResponseMock' object does not implement abstract method 'getStatus' from 'javax.servlet.http.HttpServletResponse' Fixes http://bugs.jython.org/issue2407 files: Lib/test/test_java_subclasses.py | 6 +++- src/org/python/compiler/ProxyCodeHelpers.java | 12 ++++++++++ src/org/python/compiler/ProxyMaker.java | 10 +++++--- 3 files changed, 22 insertions(+), 6 deletions(-) diff --git a/Lib/test/test_java_subclasses.py b/Lib/test/test_java_subclasses.py --- a/Lib/test/test_java_subclasses.py +++ b/Lib/test/test_java_subclasses.py @@ -404,7 +404,8 @@ # 3.x c = C() self.assertEqual(c.size(), 47) - with self.assertRaisesRegexp(NotImplementedError, r"^$"): + msg = r"^'C' object does not implement abstract method 'get' from 'java.util.AbstractList'$" + with self.assertRaisesRegexp(NotImplementedError, msg): C().get(42) def test_concrete_method(self): @@ -435,7 +436,8 @@ class C(Callable): pass - with self.assertRaisesRegexp(NotImplementedError, r"^$"): + msg = r"^'C' object does not implement abstract method 'call' from 'java.util.concurrent.Callable'$" + with self.assertRaisesRegexp(NotImplementedError, msg): C().call() diff --git a/src/org/python/compiler/ProxyCodeHelpers.java b/src/org/python/compiler/ProxyCodeHelpers.java --- a/src/org/python/compiler/ProxyCodeHelpers.java +++ b/src/org/python/compiler/ProxyCodeHelpers.java @@ -8,6 +8,7 @@ import org.objectweb.asm.Type; import org.python.core.Py; +import org.python.core.PyException; import org.python.core.PyMethod; import org.python.core.PyObject; import org.python.core.PyProxy; @@ -85,6 +86,17 @@ return ret; } + public static PyException notImplementedAbstractMethod( + PyProxy proxy, String name, String superClass) { + PyObject o = proxy._getPyInstance(); + String msg = String.format( + "'%.200s' object does not implement abstract method '%.200s' from '%.200s'", + o.getType().fastGetName(), + name, + superClass); + return Py.NotImplementedError(msg); + } + public static String mapClass(Class c) { String name = c.getName(); int index = name.indexOf("."); diff --git a/src/org/python/compiler/ProxyMaker.java b/src/org/python/compiler/ProxyMaker.java --- a/src/org/python/compiler/ProxyMaker.java +++ b/src/org/python/compiler/ProxyMaker.java @@ -388,10 +388,12 @@ code.pop(); // throw an exception if we cannot load a Python method for this abstract method - // note that the unreachable return is simply to simplify bytecode gen - code.ldc(""); - code.invokestatic(p(Py.class), "NotImplementedError", - sig(PyException.class, String.class)); + // note that the unreachable return is simply present to simplify bytecode gen + code.aload(0); + code.ldc(pyName); + code.ldc(declaringClass.getName()); + code.invokestatic("org/python/compiler/ProxyCodeHelpers", "notImplementedAbstractMethod", + makeSig($pyExc, $pyProxy, $str, $str)); code.checkcast(p(Throwable.class)); code.athrow(); -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Fri Oct 2 05:55:26 2015 From: jython-checkins at python.org (darjus.loktevic) Date: Fri, 02 Oct 2015 03:55:26 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Our_version_of_readline_sho?= =?utf-8?q?uld_respect_the_lack_of_existence_of_sys=2Eps2?= Message-ID: <20151002035525.9943.56093@psf.io> https://hg.python.org/jython/rev/9ab1523320de changeset: 7738:9ab1523320de user: darjus at uf8bc12998453542e0d23.syd10.amazon.com date: Fri Oct 02 13:43:44 2015 +1000 summary: Our version of readline should respect the lack of existence of sys.ps2 gracefully Fixes http://bugs.jython.org/issue2398 files: Lib/readline.py | 8 +++++++- 1 files changed, 7 insertions(+), 1 deletions(-) diff --git a/Lib/readline.py b/Lib/readline.py --- a/Lib/readline.py +++ b/Lib/readline.py @@ -116,7 +116,13 @@ start = _get_delimited(buffer, cursor)[0] delimited = buffer[start:cursor] - if _reader.prompt == sys.ps2 and (not delimited or delimited.isspace()): + try: + sys.ps2 + have_ps2 = True + except AttributeError: + have_ps2 = False + + if (have_ps2 and _reader.prompt == sys.ps2) and (not delimited or delimited.isspace()): # Insert tab (as expanded to 4 spaces), but only if if # preceding is whitespace/empty and in console # continuation; this is a planned featue for Python 3 per -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Fri Oct 2 14:59:32 2015 From: jython-checkins at python.org (darjus.loktevic) Date: Fri, 02 Oct 2015 12:59:32 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Fix_SyspathJavaLoader=2Eget?= =?utf-8?q?Resources_for_empty_resource_String?= Message-ID: <20151002125931.18053.3799@psf.io> https://hg.python.org/jython/rev/1d2db374fff9 changeset: 7739:1d2db374fff9 user: darjus at 60f81db49d06.ant.amazon.com date: Fri Oct 02 22:55:38 2015 +1000 summary: Fix SyspathJavaLoader.getResources for empty resource String files: src/org/python/core/SyspathJavaLoader.java | 20 +++++---- 1 files changed, 11 insertions(+), 9 deletions(-) diff --git a/src/org/python/core/SyspathJavaLoader.java b/src/org/python/core/SyspathJavaLoader.java --- a/src/org/python/core/SyspathJavaLoader.java +++ b/src/org/python/core/SyspathJavaLoader.java @@ -134,11 +134,9 @@ @Override protected URL findResource(String res) { PySystemState sys = Py.getSystemState(); - - if (res.charAt(0) == SLASH_CHAR) { - res = res.substring(1); - } - String entryRes = res; + + res = deslashResource(res); + String entryRes = res; if (File.separatorChar != SLASH_CHAR) { res = res.replace(SLASH_CHAR, File.separatorChar); entryRes = entryRes.replace(File.separatorChar, SLASH_CHAR); @@ -183,10 +181,8 @@ List resources = new ArrayList(); PySystemState sys = Py.getSystemState(); - - if (res.charAt(0) == SLASH_CHAR) { - res = res.substring(1); - } + + res = deslashResource(res); String entryRes = res; if (File.separatorChar != SLASH_CHAR) { res = res.replace(SLASH_CHAR, File.separatorChar); @@ -258,5 +254,11 @@ return new RelativeFile(dir, accum + ".class"); } + private static String deslashResource(String res) { + if (!res.isEmpty() && res.charAt(0) == SLASH_CHAR) { + res = res.substring(1); + } + return res; + } } -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Tue Oct 6 11:51:24 2015 From: jython-checkins at python.org (darjus.loktevic) Date: Tue, 06 Oct 2015 09:51:24 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_JavaSAXParser_was_missing_i?= =?utf-8?q?mplementation_for_skippedEntity=2C_fixed_+_test?= Message-ID: <20151006095124.7238.36171@psf.io> https://hg.python.org/jython/rev/51c2e62391f8 changeset: 7740:51c2e62391f8 user: Darjus Loktevic date: Tue Oct 06 20:42:47 2015 +1100 summary: JavaSAXParser was missing implementation for skippedEntity, fixed + test files: Lib/test/test_xml_sax_jy.py | 67 +++++++++++++++++ Lib/xml/sax/drivers2/drv_javasax.py | 4 + 2 files changed, 71 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_xml_sax_jy.py b/Lib/test/test_xml_sax_jy.py new file mode 100644 --- /dev/null +++ b/Lib/test/test_xml_sax_jy.py @@ -0,0 +1,67 @@ +import unittest +from test import test_support + +from StringIO import StringIO + +import xml.sax +import xml.sax.handler + + +class XmlHandler(xml.sax.ContentHandler): + + def __init__(self, root_node, connection): + self.connection = connection + self.nodes = [('root', root_node)] + self.current_text = '' + + def startElement(self, name, attrs): + self.current_text = '' + new_node = self.nodes[-1][1].startElement(name, attrs, self.connection) + if new_node is not None: + self.nodes.append((name, new_node)) + + def endElement(self, name): + self.nodes[-1][1].endElement(name, self.current_text, self.connection) + if self.nodes[-1][0] == name: + if hasattr(self.nodes[-1][1], 'endNode'): + self.nodes[-1][1].endNode(self.connection) + self.nodes.pop() + self.current_text = '' + + def characters(self, content): + self.current_text += content + + +class RootElement(object): + def __init__(self): + self.start_elements = [] + self.end_elements = [] + def startElement(self, name, attrs, connection): + self.start_elements.append([name, attrs, connection]) + + def endElement(self, name, value, connection): + self.end_elements.append([name, value, connection]) + + +class JavaSaxTestCase(unittest.TestCase): + + def test_javasax_with_skipEntity(self): + content = ']>error:&xxe;' + + root = RootElement() + handler = XmlHandler(root, root) + parser = xml.sax.make_parser() + parser.setContentHandler(handler) + parser.setFeature(xml.sax.handler.feature_external_ges, 0) + parser.parse(StringIO(content)) + + self.assertEqual('Message', root.start_elements[0][0]) + self.assertItemsEqual([['Message', 'error:', root]], root.end_elements) + + +def test_main(): + test_support.run_unittest(JavaSaxTestCase) + + +if __name__ == '__main__': + test_main() diff --git a/Lib/xml/sax/drivers2/drv_javasax.py b/Lib/xml/sax/drivers2/drv_javasax.py --- a/Lib/xml/sax/drivers2/drv_javasax.py +++ b/Lib/xml/sax/drivers2/drv_javasax.py @@ -237,6 +237,10 @@ def endEntity(self, name): pass # TODO + def skippedEntity(self, name): + pass + + def _fixTuple(nsTuple, frm, to): if isinstance(nsTuple, tuple) and len(nsTuple) == 2: nsUri, localName = nsTuple -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Tue Oct 6 11:52:09 2015 From: jython-checkins at python.org (darjus.loktevic) Date: Tue, 06 Oct 2015 09:52:09 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Add_out/_directory_to_=2Ehg?= =?utf-8?q?ignore?= Message-ID: <20151006095209.479.35659@psf.io> https://hg.python.org/jython/rev/1559735864ce changeset: 7741:1559735864ce user: Darjus Loktevic date: Tue Oct 06 20:52:01 2015 +1100 summary: Add out/ directory to .hgignore files: .hgignore | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/.hgignore b/.hgignore --- a/.hgignore +++ b/.hgignore @@ -31,3 +31,4 @@ cachedir dist profile.txt +out -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Wed Oct 7 06:26:09 2015 From: jython-checkins at python.org (darjus.loktevic) Date: Wed, 07 Oct 2015 04:26:09 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_jdk=5Fswitcher_is_not_suppo?= =?utf-8?q?rted_by_Travis_on_Mac_OS_X=2C_do_a_custom_matrix?= Message-ID: <20151007042608.475.60477@psf.io> https://hg.python.org/jython/rev/a2c20ef481d0 changeset: 7742:a2c20ef481d0 user: Darjus Loktevic date: Wed Oct 07 15:25:04 2015 +1100 summary: jdk_switcher is not supported by Travis on Mac OS X, do a custom matrix files: .travis.yml | 24 +++++++++++++++++++++--- 1 files changed, 21 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml --- a/.travis.yml +++ b/.travis.yml @@ -1,11 +1,29 @@ language: java -jdk: - - oraclejdk7 - - openjdk7 os: - linux - osx +env: + matrix: + - CUSTOM_JDK="default" + - CUSTOM_JDK="oraclejdk7" + - CUSTOM_JDK="openjdk7" + +matrix: + exclude: + # On OSX, run with default JDK only. + - os: osx + env: CUSTOM_JDK="oraclejdk7" + - os: osx + env: CUSTOM_JDK="openjdk7" + # On Linux, run with specific JDKs only. + - os: linux + env: CUSTOM_JDK="default" + +before_install: + - if [ "$TRAVIS_OS_NAME" == "osx" ]; then export JAVA_HOME=$(/usr/libexec/java_home); fi + - if [ "$TRAVIS_OS_NAME" == "linux" ]; then jdk_switcher use "$CUSTOM_JDK"; fi + script: ant && ant regrtest -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Wed Oct 7 06:35:04 2015 From: jython-checkins at python.org (darjus.loktevic) Date: Wed, 07 Oct 2015 04:35:04 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Declare_explicid_dependency?= =?utf-8?q?_on_ant_in_Travis?= Message-ID: <20151007043504.20775.99417@psf.io> https://hg.python.org/jython/rev/43a166b8cdbf changeset: 7743:43a166b8cdbf user: Darjus Loktevic date: Wed Oct 07 15:35:00 2015 +1100 summary: Declare explicid dependency on ant in Travis files: .travis.yml | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-) diff --git a/.travis.yml b/.travis.yml --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,7 @@ language: java +install: ant + os: - linux - osx -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Wed Oct 7 06:54:47 2015 From: jython-checkins at python.org (darjus.loktevic) Date: Wed, 07 Oct 2015 04:54:47 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Manually_install_ant_via_ho?= =?utf-8?q?mebrew_for_Mac_OS_X_Travis?= Message-ID: <20151007045446.464.90095@psf.io> https://hg.python.org/jython/rev/39fa8f188c32 changeset: 7744:39fa8f188c32 user: Darjus Loktevic date: Wed Oct 07 15:54:41 2015 +1100 summary: Manually install ant via homebrew for Mac OS X Travis files: .travis.yml | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-) diff --git a/.travis.yml b/.travis.yml --- a/.travis.yml +++ b/.travis.yml @@ -25,6 +25,8 @@ before_install: - if [ "$TRAVIS_OS_NAME" == "osx" ]; then export JAVA_HOME=$(/usr/libexec/java_home); fi + - if [ "$TRAVIS_OS_NAME" == "osx" ]; then brew update; fi + - if [ "$TRAVIS_OS_NAME" == "osx" ]; then brew install ant; fi - if [ "$TRAVIS_OS_NAME" == "linux" ]; then jdk_switcher use "$CUSTOM_JDK"; fi script: ant && ant regrtest -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Wed Oct 7 13:17:00 2015 From: jython-checkins at python.org (darjus.loktevic) Date: Wed, 07 Oct 2015 11:17:00 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Make_sys=2Eversion=5Finfo_a?= =?utf-8?q?_namedtuple_like_object=2E?= Message-ID: <20151007111659.97712.57242@psf.io> https://hg.python.org/jython/rev/9adfcf913dff changeset: 7745:9adfcf913dff user: Darjus Loktevic date: Wed Oct 07 22:16:54 2015 +1100 summary: Make sys.version_info a namedtuple like object. Fixes: http://bugs.jython.org/issue2380 files: CoreExposed.includes | 1 + src/org/python/core/PySystemState.java | 6 +- src/org/python/core/PyVersionInfo.java | 80 ++++++++++++++ 3 files changed, 84 insertions(+), 3 deletions(-) diff --git a/CoreExposed.includes b/CoreExposed.includes --- a/CoreExposed.includes +++ b/CoreExposed.includes @@ -49,6 +49,7 @@ org/python/core/PyTuple.class org/python/core/PyType.class org/python/core/PyUnicode.class +org/python/core/PyVersionInfo.class org/python/core/PyXRange.class org/python/core/stringlib/MarkupIterator.class org/python/core/stringlib/FieldNameIterator.class diff --git a/src/org/python/core/PySystemState.java b/src/org/python/core/PySystemState.java --- a/src/org/python/core/PySystemState.java +++ b/src/org/python/core/PySystemState.java @@ -73,7 +73,7 @@ | (Version.PY_MINOR_VERSION << 16) | (Version.PY_MICRO_VERSION << 8) | (Version.PY_RELEASE_LEVEL << 4) | (Version.PY_RELEASE_SERIAL << 0)); - public static final PyTuple version_info = getVersionInfo(); + public static final PyVersionInfo version_info = getVersionInfo(); public static final int maxunicode = 1114111; @@ -1071,7 +1071,7 @@ return Py.defaultSystemState; } - private static PyTuple getVersionInfo() { + private static PyVersionInfo getVersionInfo() { String s; if (Version.PY_RELEASE_LEVEL == 0x0A) { s = "alpha"; @@ -1087,7 +1087,7 @@ throw new RuntimeException("Illegal value for PY_RELEASE_LEVEL: " + Version.PY_RELEASE_LEVEL); } - return new PyTuple( + return new PyVersionInfo( Py.newInteger(Version.PY_MAJOR_VERSION), Py.newInteger(Version.PY_MINOR_VERSION), Py.newInteger(Version.PY_MICRO_VERSION), diff --git a/src/org/python/core/PyVersionInfo.java b/src/org/python/core/PyVersionInfo.java new file mode 100644 --- /dev/null +++ b/src/org/python/core/PyVersionInfo.java @@ -0,0 +1,80 @@ +package org.python.core; + +import org.python.expose.ExposedGet; +import org.python.expose.ExposedMethod; +import org.python.expose.ExposedNew; +import org.python.expose.ExposedType; + + at ExposedType(name = "sys.version_info", isBaseType = false) +public class PyVersionInfo extends PyTuple { + public static final PyType TYPE = PyType.fromClass(PyVersionInfo.class); + + @ExposedGet + public PyObject major, minor, micro, releaselevel, serial; + + @ExposedGet + public static final int n_sequence_fields = 5, n_fields = 5, n_unnamed_fields = 5; + + PyVersionInfo(PyObject... vals) { + super(TYPE, vals); + major = vals[0]; + minor = vals[1]; + micro = vals[2]; + releaselevel = vals[3]; + serial = vals[4]; + } + + @ExposedNew + final static PyObject version_info_new(PyNewWrapper new_, boolean init, PyType subtype, + PyObject[] args, String[] keywords) { + ArgParser ap = new ArgParser("version_info", args, keywords, new String[] {"tuple"}, 1); + PyObject obj = ap.getPyObject(0); + if (obj instanceof PyTuple) { + if (obj.__len__() != n_fields) { + String msg = String.format("version_info() takes a %s-sequence (%s-sequence given)", + n_fields, obj.__len__()); + throw Py.TypeError(msg); + } + // tuples are immutable, so we can just use its underlying array + return new PyVersionInfo(((PyTuple)obj).getArray()); + } + else { + PyList seq = new PyList(obj); + if (seq.__len__() != n_fields) { + String msg = String.format("version_info() takes a %s-sequence (%s-sequence given)", + n_fields, obj.__len__()); + throw Py.TypeError(msg); + } + return new PyVersionInfo((PyObject[])seq.__tojava__(PyObject[].class)); + } + } + + /** + * Used for pickling. + * + * @return a tuple of (class, tuple) + */ + @Override + public PyObject __reduce__() { + return version_info___reduce__(); + } + + @ExposedMethod + final PyObject version_info___reduce__() { + PyTuple newargs = __getnewargs__(); + return new PyTuple(getType(), newargs); + } + + @Override + public PyTuple __getnewargs__() { + return new PyTuple(new PyList(getArray())); + } + + @Override + public PyString __repr__() { + return (PyString) Py.newString( + TYPE.fastGetName() + "(" + + "major=%r, minor=%r, micro=%r, releaselevel=%r, serial=%r)").__mod__(this); + } + +} -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Fri Oct 9 05:25:14 2015 From: jython-checkins at python.org (darjus.loktevic) Date: Fri, 09 Oct 2015 03:25:14 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Upgrade_extlibs/jnr-*=2Ejar?= =?utf-8?q?=2C_fixes_http=3A//bugs=2Ejython=2Eorg/issue2405?= Message-ID: <20151009032513.18374.51071@psf.io> https://hg.python.org/jython/rev/571f2202410c changeset: 7746:571f2202410c user: Darjus Loktevic date: Fri Oct 09 14:24:55 2015 +1100 summary: Upgrade extlibs/jnr-*.jar, fixes http://bugs.jython.org/issue2405 files: build.xml | 12 ++++++------ extlibs/jnr-constants-0.8.6.jar | Bin extlibs/jnr-constants-0.8.8.jar | Bin extlibs/jnr-ffi-2.0.1.jar | Bin extlibs/jnr-ffi-2.0.4.jar | Bin extlibs/jnr-posix-3.0.17.jar | Bin extlibs/jnr-posix-3.0.9.jar | Bin 7 files changed, 6 insertions(+), 6 deletions(-) diff --git a/build.xml b/build.xml --- a/build.xml +++ b/build.xml @@ -173,10 +173,10 @@ - + - - + + @@ -618,10 +618,10 @@ - + - - + + diff --git a/extlibs/jnr-constants-0.8.6.jar b/extlibs/jnr-constants-0.8.6.jar deleted file mode 100644 index 0be41ffb6b2b9fab25df0f451125b74749b5a5c3..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 GIT binary patch [stripped] diff --git a/extlibs/jnr-constants-0.8.8.jar b/extlibs/jnr-constants-0.8.8.jar new file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..eee5ab879c62b3a5354ca8d2e9b9564b55122be0 GIT binary patch [stripped] diff --git a/extlibs/jnr-ffi-2.0.1.jar b/extlibs/jnr-ffi-2.0.1.jar deleted file mode 100644 index 52b6f3c0692a69b5ba9c20fb32b9fc8293810c67..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 GIT binary patch [stripped] diff --git a/extlibs/jnr-ffi-2.0.4.jar b/extlibs/jnr-ffi-2.0.4.jar new file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..2c916290018a7809471cbebafaae1a7d50ce2dab GIT binary patch [stripped] diff --git a/extlibs/jnr-posix-3.0.17.jar b/extlibs/jnr-posix-3.0.17.jar new file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..47694b9c819436d6f39633d13d1dc6c071ce4a33 GIT binary patch [stripped] diff --git a/extlibs/jnr-posix-3.0.9.jar b/extlibs/jnr-posix-3.0.9.jar deleted file mode 100644 index 182bdc4a34f160c8e165298576b740ffb95a1d81..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 GIT binary patch [stripped] -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Sat Oct 10 09:58:10 2015 From: jython-checkins at python.org (jeff.allen) Date: Sat, 10 Oct 2015 07:58:10 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_str=2Elower=2C_upper=2C_cap?= =?utf-8?q?italize=2C_title=2C_swapcase_become_ASCII=2E?= Message-ID: <20151010075810.2683.12552@psf.io> https://hg.python.org/jython/rev/81d319539b45 changeset: 7749:81d319539b45 user: Jeff Allen date: Wed Sep 30 08:34:24 2015 +0100 summary: str.lower, upper, capitalize, title, swapcase become ASCII. This follows up the fix for #2364, to correct the Unicode-ness in other these methods. Tests added for non-byte characters. Benchmarking of the code in islation shows it to be the same or faster. Other methods still need the same treatment (strip, for example). files: Lib/test/test_bytes_jy.py | 43 +++++++- src/org/python/core/PyString.java | 100 +++++++++++++---- 2 files changed, 116 insertions(+), 27 deletions(-) diff --git a/Lib/test/test_bytes_jy.py b/Lib/test/test_bytes_jy.py --- a/Lib/test/test_bytes_jy.py +++ b/Lib/test/test_bytes_jy.py @@ -1,3 +1,5 @@ +# -*- coding: utf-8 -*- +# # Tests against problems we have seen in Jython's implementation of # buffer, bytes, bytearray, and memoryview to prevent possible # regression as well as integration with Java. @@ -58,11 +60,11 @@ def checkequal(self, expected, obj, methodname, *args): "check that object.method() returns expected result" - for B in (bytearray,): # (bytes, bytearray): + for B in (bytes, bytearray): obj = B(obj) realresult = getattr(obj, methodname)() - grumble = "%r.%s() returned %s" % (obj, methodname, realresult) - self.assertIs(expected, realresult, grumble) + grumble = "%r.%s() returned %r" % (obj, methodname, realresult) + self.assertEqual(expected, realresult, grumble) # print grumble, 'x' if realresult != expected else '.' LOWER = b'\xe0\xe7\xe9\xff' # Uppercase in Latin-1 but not ascii @@ -114,6 +116,41 @@ self.checkequal(True, b'A' + c + b'Titlecased Line', 'istitle') self.checkequal(True, b'A ' + c + b' Titlecased Line', 'istitle') + # The following case-twiddling tests supplement string_tests for + # non-ascii examples, using characters that are upper/lower-case + # in latin-1 but uncased in ascii. + + def test_upper(self): + self.checkequal(b"WAS LOWER:" + self.LOWER, + b"was lower:" + self.LOWER, 'upper') + + def test_lower(self): + self.checkequal(b"was upper:" + self.UPPER, + b"WAS UPPER:" + self.UPPER, 'lower') + + def test_capitalize(self): + for c in self.LOWER: + self.checkequal(c + b"abcde", + c + b"AbCdE", 'capitalize') + + def test_swapcase(self): + self.checkequal(b"WAS lower:" + self.LOWER, + b"was LOWER:" + self.LOWER, 'swapcase') + self.checkequal(b"was UPPER:" + self.UPPER, + b"WAS upper:" + self.UPPER, 'swapcase') + + def test_title(self): + utitle = u"Le D?ner ? ?tretat" + title = utitle.encode('latin-1') + lower = utitle.lower().encode('latin-1') + upper = utitle.upper().encode('latin-1') + # Check we treat an accented character as un-cased (=space) + self.checkequal(u"Le D?Ner ? ?Tretat".encode('latin-1'), + lower, 'title') + self.checkequal(u"Le D?Ner ? ?Tretat".encode('latin-1'), + upper, 'title') + self.checkequal(u"Le D?Ner ? ?Tretat".encode('latin-1'), + title, 'title') def test_main(): test.test_support.run_unittest( 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 @@ -1050,7 +1050,21 @@ @ExposedMethod(doc = BuiltinDocs.str_lower_doc) final String str_lower() { - return getString().toLowerCase(Locale.ROOT); + String s = getString(); + int n = s.length(); + if (n == 1) { + // Special-case single byte string + char c = s.charAt(0); + return _isupper(c) ? String.valueOf((char)(c ^ SWAP_CASE)) : s; + } else { + // Copy chars to buffer, converting to lower-case. + char[] buf = new char[n]; + for (int i = 0; i < n; i++) { + char c = s.charAt(i); + buf[i] = _isupper(c) ? (char)(c ^ SWAP_CASE) : c; + } + return new String(buf); + } } public String upper() { @@ -1059,7 +1073,21 @@ @ExposedMethod(doc = BuiltinDocs.str_upper_doc) final String str_upper() { - return getString().toUpperCase(Locale.ROOT); + String s = getString(); + int n = s.length(); + if (n == 1) { + // Special-case single byte string + char c = s.charAt(0); + return _islower(c) ? String.valueOf((char)(c ^ SWAP_CASE)) : s; + } else { + // Copy chars to buffer, converting to upper-case. + char[] buf = new char[n]; + for (int i = 0; i < n; i++) { + char c = s.charAt(i); + buf[i] = _islower(c) ? (char)(c ^ SWAP_CASE) : c; + } + return new String(buf); + } } public String title() { @@ -1070,19 +1098,25 @@ final String str_title() { char[] chars = getString().toCharArray(); int n = chars.length; - boolean previous_is_cased = false; for (int i = 0; i < n; i++) { char ch = chars[i]; - if (previous_is_cased) { - chars[i] = Character.toLowerCase(ch); - } else { - chars[i] = Character.toTitleCase(ch); - } - - if (Character.isLowerCase(ch) || Character.isUpperCase(ch) || Character.isTitleCase(ch)) { + if (_isalpha(ch)) { + if (previous_is_cased) { + // Should be lower case + if (_isupper(ch)) { + chars[i] = (char)(ch ^ SWAP_CASE); + } + } else { + // Should be upper case + if (_islower(ch)) { + chars[i] = (char)(ch ^ SWAP_CASE); + } + } + // And this was a letter previous_is_cased = true; } else { + // This was not a letter previous_is_cased = false; } } @@ -1095,18 +1129,25 @@ @ExposedMethod(doc = BuiltinDocs.str_swapcase_doc) final String str_swapcase() { - char[] chars = getString().toCharArray(); - int n = chars.length; - for (int i = 0; i < n; i++) { - char c = chars[i]; - if (Character.isUpperCase(c)) { - chars[i] = Character.toLowerCase(c); - } else if (Character.isLowerCase(c)) { - chars[i] = Character.toUpperCase(c); + String s = getString(); + int n = s.length(); + if (n == 1) { + // Special-case single byte string + char c = s.charAt(0); + return _isalpha(c) ? String.valueOf((char)(c ^ SWAP_CASE)) : s; + } else { + // Copy chars to buffer, converting lower to upper case, upper to lower case. + char[] buf = new char[n]; + for (int i = 0; i < n; i++) { + char c = s.charAt(i); + buf[i] = _isalpha(c) ? (char)(c ^ SWAP_CASE) : c; } + return new String(buf); } - return new String(chars); - } + } + + // Bit to twiddle (XOR) for lowercase letter to uppercase and vice-versa. + private static final int SWAP_CASE = 0x20; /** * Equivalent of Python str.strip() with no argument, meaning strip whitespace. Any @@ -3071,11 +3112,22 @@ @ExposedMethod(doc = BuiltinDocs.str_capitalize_doc) final String str_capitalize() { - if (getString().length() == 0) { - return getString(); + String s = getString(); + int n = s.length(); + if (n == 0) { + return s; + } else { + char[] buf = new char[n]; + // At least one byte: if lower convert to upper case. + char c = s.charAt(0); + buf[0] = _islower(c) ? (char)(c ^ SWAP_CASE) : c; + // Copy the rest, converting to lower case. + for (int i = 1; i < n; i++) { + c = s.charAt(i); + buf[i] = _isupper(c) ? (char)(c ^ SWAP_CASE) : c; + } + return new String(buf); } - String first = getString().substring(0, 1).toUpperCase(); - return first.concat(getString().substring(1).toLowerCase()); } /** -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Sat Oct 10 09:58:10 2015 From: jython-checkins at python.org (jeff.allen) Date: Sat, 10 Oct 2015 07:58:10 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Trivial_formatting_ahead_of?= =?utf-8?q?_changes=2E?= Message-ID: <20151010075810.128854.68443@psf.io> https://hg.python.org/jython/rev/26d248c72b90 changeset: 7747:26d248c72b90 parent: 7735:7ebdc6c80d55 user: Jeff Allen date: Sun Sep 13 17:17:25 2015 +0100 summary: Trivial formatting ahead of changes. White space trimmed and @Override added. Braces to coding standard. files: Lib/test/test_os_jy.py | 24 +- src/org/python/core/Py.java | 66 +++++---- src/org/python/core/packagecache/CachedJarsPackageManager.java | 16 +- src/org/python/core/packagecache/PackageManager.java | 12 +- src/org/python/core/packagecache/PathPackageManager.java | 4 + src/org/python/core/packagecache/SysPackageManager.java | 11 + 6 files changed, 80 insertions(+), 53 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 @@ -100,7 +100,7 @@ pos = fd.tell() self.assertEqual(pos, x + 1, '[forward] after read: pos should be %d but is %d' % (x + 1, pos)) - + self.assertEqual(c, x) # read backward from the end @@ -116,7 +116,7 @@ pos = fd.tell() self.assertEqual(pos, x + 1, '[backward] after read: pos should be %d but is %d' % (x + 1, pos)) - + self.assertEqual(c, x) if x > 0: @@ -206,7 +206,7 @@ stdout=subprocess.PIPE, env=newenv) self.assertEqual(p.stdout.read().decode("utf-8"), u"??") - + def test_getcwd(self): with test_support.temp_cwd(name=u"tempcwd-??") as temp_cwd: p = subprocess.Popen([sys.executable, "-c", @@ -225,7 +225,7 @@ self.assertIs(type(chinese_path), unicode) home_path = os.path.join(chinese_path, u"??") os.makedirs(home_path) - + with open(os.path.join(home_path, "test.txt"), "w") as test_file: test_file.write("42\n") @@ -236,7 +236,7 @@ # Verify works with Unicode paths entries = os.listdir(chinese_path) self.assertIn(u"??", entries) - + # glob.glob builds on os.listdir; note that we don't use # Unicode paths in the arg to glob self.assertEqual( @@ -259,7 +259,7 @@ 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 # (except for subprocesses, like below in test_env) @@ -277,7 +277,7 @@ return code.strip().replace("-", "").lower() try: - installed_codes = dict(((normalize(code), code) for + installed_codes = dict(((normalize(code), code) for code in subprocess.check_output(["locale", "-a"]).split())) except (subprocess.CalledProcessError, OSError): raise unittest.SkipTest("locale command not available, cannot test") @@ -317,7 +317,7 @@ # 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 - # + # # Note that JVMs seem to have some latitude here however, so support # either for now. ["['i', u'\\u0131', 'I', u'\\u0130']\n", @@ -345,12 +345,12 @@ self.get_installed_locales("ja_JP.UTF-8") self.assertEqual( subprocess.check_output( - [sys.executable, + [sys.executable, "-J-Duser.country=JP", "-J-Duser.language=ja", "-c", "import time; print repr(time.strftime('%c', (2015, 3, 29, 14, 55, 13, 6, 88, 0)))"]), "'\\xe6\\x97\\xa5 3 29 14:55:13 2015'\n") - + class SystemTestCase(unittest.TestCase): @@ -423,7 +423,7 @@ self.assertEqual(os.readlink(source), target) self.assertEqual(os.readlink(unicode(source)), unicode(target)) self.assertIsInstance(os.readlink(unicode(source)), unicode) - + def test_readlink_non_symlink(self): """os.readlink of a non symbolic link should raise an error""" # test for http://bugs.jython.org/issue2292 @@ -447,7 +447,7 @@ def test_main(): test_support.run_unittest( - OSFileTestCase, + OSFileTestCase, OSDirTestCase, OSStatTestCase, OSWriteTestCase, diff --git a/src/org/python/core/Py.java b/src/org/python/core/Py.java --- a/src/org/python/core/Py.java +++ b/src/org/python/core/Py.java @@ -149,7 +149,7 @@ PyObject args = new PyTuple(Py.newInteger(value), PosixModule.strerror(value)); return new PyException(Py.OSError, args); } - + public static PyException OSError(Constant errno, PyObject filename) { int value = errno.intValue(); // see https://github.com/jruby/jruby/commit/947c661e46683ea82f8016dde9d3fa597cd10e56 @@ -450,7 +450,7 @@ public static void UnicodeWarning(String message) { warning(UnicodeWarning, message); } - + public static PyObject BytesWarning; public static void BytesWarning(String message) { warning(BytesWarning, message); @@ -906,36 +906,36 @@ " in sys.classLoader"); } return loadAndInitClass(name, classLoader); - } + } if (!syspathJavaLoaderRestricted) { try { classLoader = imp.getSyspathJavaLoader(); if (classLoader != null && reason != null) { writeDebug("import", "trying " + name + " as " + reason + " in SysPathJavaLoader"); - } + } } catch (SecurityException e) { syspathJavaLoaderRestricted = true; } - } + } if (syspathJavaLoaderRestricted) { classLoader = imp.getParentClassLoader(); if (classLoader != null && reason != null) { writeDebug("import", "trying " + name + " as " + reason + - " in Jython's parent class loader"); + " in Jython's parent class loader"); } - } + } if (classLoader != null) { try { return loadAndInitClass(name, classLoader); } catch (ClassNotFoundException cnfe) { // let the default classloader try // XXX: by trying another classloader that may not be on a - // parent/child relationship with the Jython's parent + // parent/child relationship with the Jython's parent // classsloader we are risking some nasty class loading - // problems (such as having two incompatible copies for - // the same class that is itself a dependency of two - // classes loaded from these two different class loaders) + // problems (such as having two incompatible copies for + // the same class that is itself a dependency of two + // classes loaded from these two different class loaders) } } if (reason != null) { @@ -944,7 +944,7 @@ } return loadAndInitClass(name, Thread.currentThread().getContextClassLoader()); } - + /** * Tries to find a Java class. * @param name Name of the Java class. @@ -966,18 +966,18 @@ } /** - * Tries to find a Java class. - * - * Unless {@link #findClass(String)}, it raises a JavaError + * Tries to find a Java class. + * + * Unless {@link #findClass(String)}, it raises a JavaError * if the class was found but there were problems loading it. * @param name Name of the Java class. * @param reason Reason for finding the class. Used for debugging messages. * @return The class, or null if it wasn't found - * @throws JavaError wrapping LinkageErrors/IllegalArgumentExceptions + * @throws JavaError wrapping LinkageErrors/IllegalArgumentExceptions * occurred when the class is found but can't be loaded. */ public static Class findClassEx(String name, String reason) { - try { + try { return findClassInternal(name, reason); } catch (ClassNotFoundException e) { return null; @@ -989,17 +989,18 @@ } // An alias to express intent (since boolean flags aren't exactly obvious). - // We *need* to initialize classes on findClass/findClassEx, so that import + // We *need* to initialize classes on findClass/findClassEx, so that import // statements can trigger static initializers private static Class loadAndInitClass(String name, ClassLoader loader) throws ClassNotFoundException { return Class.forName(name, true, loader); - } - - + } + + public static void initProxy(PyProxy proxy, String module, String pyclass, Object[] args) { - if (proxy._getPyInstance() != null) + if (proxy._getPyInstance() != null) { return; + } PyObject instance = (PyObject)(ThreadContext.initializingProxy.get()[0]); ThreadState ts = Py.getThreadState(); if (instance != null) { @@ -2153,7 +2154,7 @@ } return false; } - + checkClass(cls, "isinstance() arg 2 must be a class, type, or tuple of classes and types"); PyObject instCls = inst.__findattr__("__class__"); if (instCls == null) { @@ -2371,7 +2372,7 @@ * Utility-method to obtain the name (including absolute path) of the currently used * jython-jar-file. Usually this is jython.jar, but can also be jython-dev.jar or * jython-standalone.jar or something custom. - * + * * Note that it does not use system-specific seperator-chars, but always '/'. * * @return the full name of the jar file containing this class, null @@ -2455,8 +2456,10 @@ List pyClasses; public py2JyClassCacheItem(Class initClass, PyObject initPyClass) { - if (!initClass.isInterface()) throw - new IllegalArgumentException("cls must be an interface."); + if (!initClass.isInterface()) { + throw + new IllegalArgumentException("cls must be an interface."); + } interfaces = new ArrayList<>(1); pyClasses = new ArrayList<>(1); interfaces.add(initClass); @@ -2465,15 +2468,18 @@ public PyObject get(Class cls) { for (int i = 0; i < interfaces.size(); ++i) { - if (cls.isAssignableFrom(interfaces.get(i))) + if (cls.isAssignableFrom(interfaces.get(i))) { return pyClasses.get(i); + } } return null; } public void add(Class cls, PyObject pyCls) { - if (!cls.isInterface()) throw - new IllegalArgumentException("cls must be an interface."); + if (!cls.isInterface()) { + throw + new IllegalArgumentException("cls must be an interface."); + } interfaces.add(0, cls); pyClasses.add(0, pyCls); for (int i = interfaces.size()-1; i > 0; --i) { @@ -2532,7 +2538,7 @@ * It automatically converts {@code args} to {@link org.python.core.PyObject}s.
* For keyword-support use * {@link #newJavaObject(PyObject, Class, String[], Object...)}. - * + * * {@see #newJavaObject(PyObject, Class, PyObject[], String[])} * {@see #newJavaObject(PyObject, Class, String[], Object...)} * {@see #newJavaObject(PyModule, Class, Object...)} diff --git a/src/org/python/core/packagecache/CachedJarsPackageManager.java b/src/org/python/core/packagecache/CachedJarsPackageManager.java --- a/src/org/python/core/packagecache/CachedJarsPackageManager.java +++ b/src/org/python/core/packagecache/CachedJarsPackageManager.java @@ -157,7 +157,7 @@ private List[] createGenericStringListArray(){ return new List[] { Generic.list(), Generic.list() }; } - + // Extract all of the packages in a single jarfile private Map getZipPackages(InputStream jarin) throws IOException { Map[]> zipPackages = Generic.map(); @@ -280,8 +280,9 @@ } else { jarname = jarurl.getFile(); int slash = jarname.lastIndexOf('/'); - if (slash != -1) + if (slash != -1) { jarname = jarname.substring(slash + 1); + } } jarname = jarname.substring(0, jarname.length() - 4); @@ -421,7 +422,7 @@ String classes = kv.getValue(); // Make sure each package is not larger than 64k for (String part : splitString(classes, 65535)) { - // For each chunk, write the package name followed by the classes. + // For each chunk, write the package name followed by the classes. ostream.writeUTF(kv.getKey()); ostream.writeUTF(part); } @@ -441,11 +442,11 @@ /** * Split up a string into several chunks based on a certain size - * + * * The writeCacheFile method will use the writeUTF method on a - * DataOutputStream which only allows writing 64k chunks, so use + * DataOutputStream which only allows writing 64k chunks, so use * this utility method to split it up - * + * * @param str - The string to split up into chunks * @param maxLength - The max size a string should be * @return - An array of strings, each of which will not be larger than maxLength @@ -642,8 +643,9 @@ index += 1; } entry.cachefile = cachefile.getCanonicalPath(); - } else + } else { cachefile = new File(entry.cachefile); + } return new DataOutputStream(new BufferedOutputStream( new FileOutputStream(cachefile))); diff --git a/src/org/python/core/packagecache/PackageManager.java b/src/org/python/core/packagecache/PackageManager.java --- a/src/org/python/core/packagecache/PackageManager.java +++ b/src/org/python/core/packagecache/PackageManager.java @@ -97,8 +97,9 @@ for (PyObject name : dictKeys.asIterable()) { if (!cls.has_key(name)) { - if (exclpkgs && dict.get(name) instanceof PyJavaPackage) + if (exclpkgs && dict.get(name) instanceof PyJavaPackage) { continue; + } ret.append(name); } } @@ -139,8 +140,9 @@ } firstName = firstName.intern(); top = top.__findattr__(firstName); - if (top == null) + if (top == null) { return null; + } // ??pending: test for jpkg/jclass? name = lastName; } while (name != null); @@ -160,11 +162,13 @@ public PyJavaPackage makeJavaPackage(String name, String classes, String jarfile) { PyJavaPackage p = this.topLevelPackage; - if (name.length() != 0) + if (name.length() != 0) { p = p.addPackage(name, jarfile); + } - if (classes != null) + if (classes != null) { p.addPlaceholders(classes); + } return p; } diff --git a/src/org/python/core/packagecache/PathPackageManager.java b/src/org/python/core/packagecache/PathPackageManager.java --- a/src/org/python/core/packagecache/PathPackageManager.java +++ b/src/org/python/core/packagecache/PathPackageManager.java @@ -75,6 +75,7 @@ private boolean python; + @Override public boolean accept(File dir, String name) { if(name.endsWith(".py") || name.endsWith("$py.class") || name.endsWith("$_PyInner.class")) { python = true; @@ -193,6 +194,7 @@ /** * Add directory dir (if exists) to {@link #searchPath}. */ + @Override public void addDirectory(File dir) { try { if (dir.getPath().length() == 0) { @@ -235,6 +237,7 @@ } } + @Override public PyList doDir(PyJavaPackage jpkg, boolean instantiate, boolean exclpkgs) { PyList basic = basicDoDir(jpkg, instantiate, exclpkgs); @@ -245,6 +248,7 @@ return merge(basic, ret); } + @Override public boolean packageExists(String pkg, String name) { return packageExists(this.searchPath, pkg, name); } diff --git a/src/org/python/core/packagecache/SysPackageManager.java b/src/org/python/core/packagecache/SysPackageManager.java --- a/src/org/python/core/packagecache/SysPackageManager.java +++ b/src/org/python/core/packagecache/SysPackageManager.java @@ -17,18 +17,22 @@ */ public class SysPackageManager extends PathPackageManager { + @Override protected void message(String msg) { Py.writeMessage("*sys-package-mgr*", msg); } + @Override protected void warning(String warn) { Py.writeWarning("*sys-package-mgr*", warn); } + @Override protected void comment(String msg) { Py.writeComment("*sys-package-mgr*", msg); } + @Override protected void debug(String msg) { Py.writeDebug("*sys-package-mgr*", msg); } @@ -41,6 +45,7 @@ } } + @Override public void addJar(String jarfile, boolean cache) { addJarToPackages(new File(jarfile), cache); if (cache) { @@ -48,6 +53,7 @@ } } + @Override public void addJarDir(String jdir, boolean cache) { addJarDir(jdir, cache, cache); } @@ -111,6 +117,7 @@ } } + @Override public void notifyPackageImport(String pkg, String name) { if (pkg != null && pkg.length() > 0) { name = pkg + '.' + name; @@ -118,6 +125,7 @@ Py.writeComment("import", "'" + name + "' as java package"); } + @Override public Class findClass(String pkg, String name) { Class c = super.findClass(pkg, name); if (c != null) { @@ -126,6 +134,7 @@ return c; } + @Override public Class findClass(String pkg, String name, String reason) { if (pkg != null && pkg.length() > 0) { name = pkg + '.' + name; @@ -133,6 +142,7 @@ return Py.findClassEx(name, reason); } + @Override public PyList doDir(PyJavaPackage jpkg, boolean instantiate, boolean exclpkgs) { PyList basic = basicDoDir(jpkg, instantiate, exclpkgs); @@ -149,6 +159,7 @@ return merge(basic, ret); } + @Override public boolean packageExists(String pkg, String name) { if (packageExists(this.searchPath, pkg, name)) { return true; -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Sat Oct 10 09:58:11 2015 From: jython-checkins at python.org (jeff.allen) Date: Sat, 10 Oct 2015 07:58:11 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Allow_for_non-ascii_directo?= =?utf-8?q?ry_names_in_PathPackageManager=2C_fixes_=232397=2E?= Message-ID: <20151010075810.483.51563@psf.io> https://hg.python.org/jython/rev/b6180b5dc4c6 changeset: 7748:b6180b5dc4c6 user: Jeff Allen date: Sat Sep 19 10:57:49 2015 +0100 summary: Allow for non-ascii directory names in PathPackageManager, fixes #2397. This fixes a couple of places where the attempt to make a non-ascii PyString bytes us. One in a series involving paths. files: Lib/test/test_import_jy.py | 4 +- src/org/python/core/Py.java | 30 +++++++--- src/org/python/core/packagecache/PathPackageManager.java | 6 +- 3 files changed, 26 insertions(+), 14 deletions(-) diff --git a/Lib/test/test_import_jy.py b/Lib/test/test_import_jy.py --- a/Lib/test/test_import_jy.py +++ b/Lib/test/test_import_jy.py @@ -173,8 +173,8 @@ self.assertRaises(Exception, getattr, anygui, 'abc') def test_import_star(self): - self.assertEquals(subprocess.call([sys.executable, - test_support.findfile("import_star_from_java.py")]), 0) + self.assertEquals(0, subprocess.call( + [sys.executable, test_support.findfile("import_star_from_java.py")])) def test_selfreferential_classes(self): from org.python.tests.inbred import Metis diff --git a/src/org/python/core/Py.java b/src/org/python/core/Py.java --- a/src/org/python/core/Py.java +++ b/src/org/python/core/Py.java @@ -645,19 +645,31 @@ return new PyString(s); } - // Use if s may contain Unicode characters, - // but we prefer to return a PyString + /** + * Return a {@link PyString} for the given Java String, if it can be represented as + * US-ASCII, and a {@link PyUnicode} otherwise. + * + * @param s string content + * @return PyString or PyUnicode according to content of + * s. + */ public static PyString newStringOrUnicode(String s) { return newStringOrUnicode(Py.EmptyString, s); } - // Use when returning a PyString or PyUnicode is based on what "kind" is, - // but always fallback to PyUnicode if s contains Unicode characters. - public static PyString newStringOrUnicode(PyObject kind, String s) { - if (kind instanceof PyUnicode) { - return Py.newUnicode(s); - } - if (CharMatcher.ASCII.matchesAllOf(s)) { + /** + * Return a {@link PyString} for the given Java String, if it can be represented as + * US-ASCII and if a preceding object is not a PyUnicode, and a {@link PyUnicode} + * otherwise. In some contexts, we want the result to be a PyUnicode if some + * preceding result is a PyUnicode. + * + * @param precedent string of which the type sets a precedent + * @param s string content + * @return PyString or PyUnicode according to content of + * s. + */ + public static PyString newStringOrUnicode(PyObject precedent, String s) { + if (!(precedent instanceof PyUnicode) && CharMatcher.ASCII.matchesAllOf(s)) { return Py.newString(s); } else { return Py.newUnicode(s); diff --git a/src/org/python/core/packagecache/PathPackageManager.java b/src/org/python/core/packagecache/PathPackageManager.java --- a/src/org/python/core/packagecache/PathPackageManager.java +++ b/src/org/python/core/packagecache/PathPackageManager.java @@ -95,7 +95,7 @@ /** * Helper for {@link #doDir(PyJavaPackage,boolean,boolean)}. Scans for - * package jpkg content over the directories in path. Add to ret the founded + * package jpkg content over the directories in path. Add to ret the found * classes/pkgs. Filter out classes using {@link #filterByName},{@link #filterByAccess}. */ protected void doDir(PyList path, PyList ret, PyJavaPackage jpkg, @@ -142,7 +142,7 @@ } jname = jname.substring(0, jlen); - PyString name = new PyString(jname); + PyString name = Py.newStringOrUnicode(jname); if (filterByName(jname, pkgCand)) { continue; @@ -200,7 +200,7 @@ if (dir.getPath().length() == 0) { this.searchPath.append(Py.EmptyString); } else { - this.searchPath.append(new PyString(dir.getCanonicalPath())); + this.searchPath.append(Py.newStringOrUnicode(dir.getCanonicalPath())); } } catch (IOException e) { warning("skipping bad directory, '" + dir + "'"); -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Sat Oct 10 09:58:10 2015 From: jython-checkins at python.org (jeff.allen) Date: Sat, 10 Oct 2015 07:58:10 +0000 Subject: [Jython-checkins] =?utf-8?q?jython_=28merge_default_-=3E_default?= =?utf-8?q?=29=3A_Merge_to_trunk?= Message-ID: <20151010075810.20769.97550@psf.io> https://hg.python.org/jython/rev/d1b70df624e3 changeset: 7751:d1b70df624e3 parent: 7746:571f2202410c parent: 7750:897051aa79c7 user: Jeff Allen date: Sat Oct 10 08:57:37 2015 +0100 summary: Merge to trunk files: Lib/test/test_bytes_jy.py | 69 ++++++- Lib/test/test_import_jy.py | 4 +- Lib/test/test_os_jy.py | 24 +- Lib/test/test_unicode_jy.py | 62 +++++- src/org/python/core/Py.java | 96 +++++--- src/org/python/core/PyString.java | 100 +++++++-- src/org/python/core/packagecache/CachedJarsPackageManager.java | 16 +- src/org/python/core/packagecache/PackageManager.java | 12 +- src/org/python/core/packagecache/PathPackageManager.java | 10 +- src/org/python/core/packagecache/SysPackageManager.java | 11 + 10 files changed, 307 insertions(+), 97 deletions(-) diff --git a/Lib/test/test_bytes_jy.py b/Lib/test/test_bytes_jy.py --- a/Lib/test/test_bytes_jy.py +++ b/Lib/test/test_bytes_jy.py @@ -1,3 +1,5 @@ +# -*- coding: utf-8 -*- +# # Tests against problems we have seen in Jython's implementation of # buffer, bytes, bytearray, and memoryview to prevent possible # regression as well as integration with Java. @@ -58,11 +60,11 @@ def checkequal(self, expected, obj, methodname, *args): "check that object.method() returns expected result" - for B in (bytearray,): # (bytes, bytearray): + for B in (bytes, bytearray): obj = B(obj) realresult = getattr(obj, methodname)() - grumble = "%r.%s() returned %s" % (obj, methodname, realresult) - self.assertIs(expected, realresult, grumble) + grumble = "%r.%s() returned %r" % (obj, methodname, realresult) + self.assertEqual(expected, realresult, grumble) # print grumble, 'x' if realresult != expected else '.' LOWER = b'\xe0\xe7\xe9\xff' # Uppercase in Latin-1 but not ascii @@ -114,6 +116,67 @@ self.checkequal(True, b'A' + c + b'Titlecased Line', 'istitle') self.checkequal(True, b'A ' + c + b' Titlecased Line', 'istitle') + # The following case-twiddling tests supplement string_tests for + # non-ascii examples, using characters that are upper/lower-case + # in latin-1 but uncased in ascii. + + def test_upper(self): + self.checkequal(b"WAS LOWER:" + self.LOWER, + b"was lower:" + self.LOWER, 'upper') + + def test_lower(self): + self.checkequal(b"was upper:" + self.UPPER, + b"WAS UPPER:" + self.UPPER, 'lower') + + def test_capitalize(self): + for c in self.LOWER: + self.checkequal(c + b"abcde", + c + b"AbCdE", 'capitalize') + + def test_swapcase(self): + self.checkequal(b"WAS lower:" + self.LOWER, + b"was LOWER:" + self.LOWER, 'swapcase') + self.checkequal(b"was UPPER:" + self.UPPER, + b"WAS upper:" + self.UPPER, 'swapcase') + + def test_title(self): + utitle = u"Le D?ner ? ?tretat" + title = utitle.encode('latin-1') + lower = utitle.lower().encode('latin-1') + upper = utitle.upper().encode('latin-1') + # Check we treat an accented character as un-cased (=space) + self.checkequal(u"Le D?Ner ? ?Tretat".encode('latin-1'), + lower, 'title') + self.checkequal(u"Le D?Ner ? ?Tretat".encode('latin-1'), + upper, 'title') + self.checkequal(u"Le D?Ner ? ?Tretat".encode('latin-1'), + title, 'title') + + # *strip() tests to supplement string_tests with non-ascii examples, + # using characters that are spaces in latin-1 but not in ascii. + + def test_strip(self): + for c in self.SPACE: + # These should not be stripped at left or right because of c + sp = b" \t " + s = c + sp + b"hello" + sp + c + self.checkequal( s, s, 'strip') + self.checkequal( s, sp+s+sp, 'strip') + self.checkequal( sp+s, sp+s, 'rstrip') + self.checkequal( sp+s, sp+s+sp, 'rstrip') + self.checkequal( s+sp, s+sp, 'lstrip') + self.checkequal( s+sp, sp+s+sp, 'lstrip') + + def test_split(self): + for c in self.SPACE: + # These should not be split at c + s = b"AAA" + c + b"BBB" + self.assertEqual(1, len(s.split()), "split made in " + repr(s)) + self.assertEqual(1, len(s.rsplit()), "rsplit made in " + repr(s)) + s = bytearray(s) + self.assertEqual(1, len(s.split()), "split made in " + repr(s)) + self.assertEqual(1, len(s.rsplit()), "rsplit made in " + repr(s)) + def test_main(): test.test_support.run_unittest( diff --git a/Lib/test/test_import_jy.py b/Lib/test/test_import_jy.py --- a/Lib/test/test_import_jy.py +++ b/Lib/test/test_import_jy.py @@ -173,8 +173,8 @@ self.assertRaises(Exception, getattr, anygui, 'abc') def test_import_star(self): - self.assertEquals(subprocess.call([sys.executable, - test_support.findfile("import_star_from_java.py")]), 0) + self.assertEquals(0, subprocess.call( + [sys.executable, test_support.findfile("import_star_from_java.py")])) def test_selfreferential_classes(self): from org.python.tests.inbred import Metis 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 @@ -100,7 +100,7 @@ pos = fd.tell() self.assertEqual(pos, x + 1, '[forward] after read: pos should be %d but is %d' % (x + 1, pos)) - + self.assertEqual(c, x) # read backward from the end @@ -116,7 +116,7 @@ pos = fd.tell() self.assertEqual(pos, x + 1, '[backward] after read: pos should be %d but is %d' % (x + 1, pos)) - + self.assertEqual(c, x) if x > 0: @@ -206,7 +206,7 @@ stdout=subprocess.PIPE, env=newenv) self.assertEqual(p.stdout.read().decode("utf-8"), u"??") - + def test_getcwd(self): with test_support.temp_cwd(name=u"tempcwd-??") as temp_cwd: p = subprocess.Popen([sys.executable, "-c", @@ -225,7 +225,7 @@ self.assertIs(type(chinese_path), unicode) home_path = os.path.join(chinese_path, u"??") os.makedirs(home_path) - + with open(os.path.join(home_path, "test.txt"), "w") as test_file: test_file.write("42\n") @@ -236,7 +236,7 @@ # Verify works with Unicode paths entries = os.listdir(chinese_path) self.assertIn(u"??", entries) - + # glob.glob builds on os.listdir; note that we don't use # Unicode paths in the arg to glob self.assertEqual( @@ -259,7 +259,7 @@ 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 # (except for subprocesses, like below in test_env) @@ -277,7 +277,7 @@ return code.strip().replace("-", "").lower() try: - installed_codes = dict(((normalize(code), code) for + installed_codes = dict(((normalize(code), code) for code in subprocess.check_output(["locale", "-a"]).split())) except (subprocess.CalledProcessError, OSError): raise unittest.SkipTest("locale command not available, cannot test") @@ -317,7 +317,7 @@ # 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 - # + # # Note that JVMs seem to have some latitude here however, so support # either for now. ["['i', u'\\u0131', 'I', u'\\u0130']\n", @@ -345,12 +345,12 @@ self.get_installed_locales("ja_JP.UTF-8") self.assertEqual( subprocess.check_output( - [sys.executable, + [sys.executable, "-J-Duser.country=JP", "-J-Duser.language=ja", "-c", "import time; print repr(time.strftime('%c', (2015, 3, 29, 14, 55, 13, 6, 88, 0)))"]), "'\\xe6\\x97\\xa5 3 29 14:55:13 2015'\n") - + class SystemTestCase(unittest.TestCase): @@ -423,7 +423,7 @@ self.assertEqual(os.readlink(source), target) self.assertEqual(os.readlink(unicode(source)), unicode(target)) self.assertIsInstance(os.readlink(unicode(source)), unicode) - + def test_readlink_non_symlink(self): """os.readlink of a non symbolic link should raise an error""" # test for http://bugs.jython.org/issue2292 @@ -447,7 +447,7 @@ def test_main(): test_support.run_unittest( - OSFileTestCase, + OSFileTestCase, OSDirTestCase, OSStatTestCase, OSWriteTestCase, diff --git a/Lib/test/test_unicode_jy.py b/Lib/test/test_unicode_jy.py --- a/Lib/test/test_unicode_jy.py +++ b/Lib/test/test_unicode_jy.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- """Misc unicode tests -Made for Jython. +Made for Jython. (But it will run for CPython.) """ import itertools import random @@ -11,7 +11,6 @@ import unittest from StringIO import StringIO from test import test_support -from java.lang import StringBuilder class UnicodeTestCase(unittest.TestCase): @@ -108,6 +107,7 @@ def test_repr(self): self.assert_(isinstance('%r' % u'foo', str)) + @unittest.skipUnless(test_support.is_jython, "Specific to Jython") def test_unicode_lone_surrogate(self): # http://bugs.jython.org/issue2190 self.assertRaises(ValueError, unichr, 0xd800) @@ -167,7 +167,11 @@ ''' base = tuple(u'abcdefghijklmnopqrstuvwxyz') - supp = tuple(map(unichr, range(0x10000, 0x1000c))) + if sys.maxunicode < 0x10000: + # This is here to prevent error messages on a narrow CPython build. + supp = (u'NOT SUPPORTED',) + else: + supp = tuple(map(unichr, range(0x10000, 0x1000c))) used = sorted(set(base+supp)) def __init__(self, size=20, pred=None, ran=None): @@ -225,6 +229,7 @@ self.text = u''.join(self.ref) + at unittest.skipUnless(test_support.is_jython, "Specific to Jython") class UnicodeIndexMixTest(unittest.TestCase): # Test indexing where there may be more than one code unit per code point. # See Jython Issue #2100. @@ -368,6 +373,8 @@ def test_surrogate_validation(self): + from java.lang import StringBuilder + def insert_sb(text, c1, c2): # Insert code points c1, c2 in the text, as a Java StringBuilder sb = StringBuilder() @@ -845,6 +852,54 @@ self.assertRaises(ValueError, fmt.format, u"{0}", 10, 20, i=100) self.assertRaises(ValueError, fmt.format, u"{i}", 10, 20, i=100) +class UnicodeSpaceTest(unittest.TestCase): + # Test classification of characters as whitespace (some Jython divergence) + + def checkequal(self, expected, obj, methodname, *args): + "check that object.method() returns expected result" + realresult = getattr(obj, methodname)() + grumble = "%r.%s() returned %r" % (obj, methodname, realresult) + self.assertEqual(expected, realresult, grumble) + # print grumble, 'x' if realresult != expected else '.' + + # The set of Unicode characters that are spaces according to CPython 2.7.8 + SPACE = u'\t\n\x0b\x0c\r\x1c\x1d\x1e\x1f\x20\x85\xa0\u1680\u180e' + \ + u'\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a' + \ + u'\u2028\u2029\u202f\u205f\u3000' + if test_support.is_jython: + # Not whitespace in Jython based on java.lang.Character.isWhitespace. + # This test documents the divergence, until we decide to remove it. + for c in u'\x85\xa0\u2007\u202f': + SPACE = SPACE.replace(c, u'') + + def test_isspace(self): + for c in self.SPACE: + self.checkequal(True, c, 'isspace') + self.checkequal(True, u'\t' + c + u' ', 'isspace') + + # *strip() tests to supplement string_tests with non-ascii examples, + # using characters that are spaces in latin-1 but not in ascii. + + def test_strip(self): + for c in self.SPACE: + # These should be stripped of c at left or right + sp = u" " + c + u" " + h = u"hello" + s = sp + h + sp + self.checkequal( h, s, 'strip') + self.checkequal( h, c + s + c, 'strip') + self.checkequal( sp + h, s, 'rstrip') + self.checkequal( sp + h, s + c, 'rstrip') + self.checkequal( h + sp, s, 'lstrip') + self.checkequal( h + sp, c + s, 'lstrip') + + def test_split(self): + for c in self.SPACE: + # These should be split at c + s = u"AAA" + c + u"BBB" + self.assertEqual(2, len(s.split()), "no split made in " + repr(s)) + self.assertEqual(2, len(s.rsplit()), "no rsplit made in " + repr(s)) + def test_main(): test_support.run_unittest( @@ -854,6 +909,7 @@ UnicodeStdIOTestCase, UnicodeFormatStrTest, StringModuleUnicodeTest, + UnicodeSpaceTest, ) diff --git a/src/org/python/core/Py.java b/src/org/python/core/Py.java --- a/src/org/python/core/Py.java +++ b/src/org/python/core/Py.java @@ -149,7 +149,7 @@ PyObject args = new PyTuple(Py.newInteger(value), PosixModule.strerror(value)); return new PyException(Py.OSError, args); } - + public static PyException OSError(Constant errno, PyObject filename) { int value = errno.intValue(); // see https://github.com/jruby/jruby/commit/947c661e46683ea82f8016dde9d3fa597cd10e56 @@ -450,7 +450,7 @@ public static void UnicodeWarning(String message) { warning(UnicodeWarning, message); } - + public static PyObject BytesWarning; public static void BytesWarning(String message) { warning(BytesWarning, message); @@ -645,19 +645,31 @@ return new PyString(s); } - // Use if s may contain Unicode characters, - // but we prefer to return a PyString + /** + * Return a {@link PyString} for the given Java String, if it can be represented as + * US-ASCII, and a {@link PyUnicode} otherwise. + * + * @param s string content + * @return PyString or PyUnicode according to content of + * s. + */ public static PyString newStringOrUnicode(String s) { return newStringOrUnicode(Py.EmptyString, s); } - // Use when returning a PyString or PyUnicode is based on what "kind" is, - // but always fallback to PyUnicode if s contains Unicode characters. - public static PyString newStringOrUnicode(PyObject kind, String s) { - if (kind instanceof PyUnicode) { - return Py.newUnicode(s); - } - if (CharMatcher.ASCII.matchesAllOf(s)) { + /** + * Return a {@link PyString} for the given Java String, if it can be represented as + * US-ASCII and if a preceding object is not a PyUnicode, and a {@link PyUnicode} + * otherwise. In some contexts, we want the result to be a PyUnicode if some + * preceding result is a PyUnicode. + * + * @param precedent string of which the type sets a precedent + * @param s string content + * @return PyString or PyUnicode according to content of + * s. + */ + public static PyString newStringOrUnicode(PyObject precedent, String s) { + if (!(precedent instanceof PyUnicode) && CharMatcher.ASCII.matchesAllOf(s)) { return Py.newString(s); } else { return Py.newUnicode(s); @@ -906,36 +918,36 @@ " in sys.classLoader"); } return loadAndInitClass(name, classLoader); - } + } if (!syspathJavaLoaderRestricted) { try { classLoader = imp.getSyspathJavaLoader(); if (classLoader != null && reason != null) { writeDebug("import", "trying " + name + " as " + reason + " in SysPathJavaLoader"); - } + } } catch (SecurityException e) { syspathJavaLoaderRestricted = true; } - } + } if (syspathJavaLoaderRestricted) { classLoader = imp.getParentClassLoader(); if (classLoader != null && reason != null) { writeDebug("import", "trying " + name + " as " + reason + - " in Jython's parent class loader"); + " in Jython's parent class loader"); } - } + } if (classLoader != null) { try { return loadAndInitClass(name, classLoader); } catch (ClassNotFoundException cnfe) { // let the default classloader try // XXX: by trying another classloader that may not be on a - // parent/child relationship with the Jython's parent + // parent/child relationship with the Jython's parent // classsloader we are risking some nasty class loading - // problems (such as having two incompatible copies for - // the same class that is itself a dependency of two - // classes loaded from these two different class loaders) + // problems (such as having two incompatible copies for + // the same class that is itself a dependency of two + // classes loaded from these two different class loaders) } } if (reason != null) { @@ -944,7 +956,7 @@ } return loadAndInitClass(name, Thread.currentThread().getContextClassLoader()); } - + /** * Tries to find a Java class. * @param name Name of the Java class. @@ -966,18 +978,18 @@ } /** - * Tries to find a Java class. - * - * Unless {@link #findClass(String)}, it raises a JavaError + * Tries to find a Java class. + * + * Unless {@link #findClass(String)}, it raises a JavaError * if the class was found but there were problems loading it. * @param name Name of the Java class. * @param reason Reason for finding the class. Used for debugging messages. * @return The class, or null if it wasn't found - * @throws JavaError wrapping LinkageErrors/IllegalArgumentExceptions + * @throws JavaError wrapping LinkageErrors/IllegalArgumentExceptions * occurred when the class is found but can't be loaded. */ public static Class findClassEx(String name, String reason) { - try { + try { return findClassInternal(name, reason); } catch (ClassNotFoundException e) { return null; @@ -989,17 +1001,18 @@ } // An alias to express intent (since boolean flags aren't exactly obvious). - // We *need* to initialize classes on findClass/findClassEx, so that import + // We *need* to initialize classes on findClass/findClassEx, so that import // statements can trigger static initializers private static Class loadAndInitClass(String name, ClassLoader loader) throws ClassNotFoundException { return Class.forName(name, true, loader); - } - - + } + + public static void initProxy(PyProxy proxy, String module, String pyclass, Object[] args) { - if (proxy._getPyInstance() != null) + if (proxy._getPyInstance() != null) { return; + } PyObject instance = (PyObject)(ThreadContext.initializingProxy.get()[0]); ThreadState ts = Py.getThreadState(); if (instance != null) { @@ -2153,7 +2166,7 @@ } return false; } - + checkClass(cls, "isinstance() arg 2 must be a class, type, or tuple of classes and types"); PyObject instCls = inst.__findattr__("__class__"); if (instCls == null) { @@ -2371,7 +2384,7 @@ * Utility-method to obtain the name (including absolute path) of the currently used * jython-jar-file. Usually this is jython.jar, but can also be jython-dev.jar or * jython-standalone.jar or something custom. - * + * * Note that it does not use system-specific seperator-chars, but always '/'. * * @return the full name of the jar file containing this class, null @@ -2455,8 +2468,10 @@ List pyClasses; public py2JyClassCacheItem(Class initClass, PyObject initPyClass) { - if (!initClass.isInterface()) throw - new IllegalArgumentException("cls must be an interface."); + if (!initClass.isInterface()) { + throw + new IllegalArgumentException("cls must be an interface."); + } interfaces = new ArrayList<>(1); pyClasses = new ArrayList<>(1); interfaces.add(initClass); @@ -2465,15 +2480,18 @@ public PyObject get(Class cls) { for (int i = 0; i < interfaces.size(); ++i) { - if (cls.isAssignableFrom(interfaces.get(i))) + if (cls.isAssignableFrom(interfaces.get(i))) { return pyClasses.get(i); + } } return null; } public void add(Class cls, PyObject pyCls) { - if (!cls.isInterface()) throw - new IllegalArgumentException("cls must be an interface."); + if (!cls.isInterface()) { + throw + new IllegalArgumentException("cls must be an interface."); + } interfaces.add(0, cls); pyClasses.add(0, pyCls); for (int i = interfaces.size()-1; i > 0; --i) { @@ -2532,7 +2550,7 @@ * It automatically converts {@code args} to {@link org.python.core.PyObject}s.
* For keyword-support use * {@link #newJavaObject(PyObject, Class, String[], Object...)}. - * + * * {@see #newJavaObject(PyObject, Class, PyObject[], String[])} * {@see #newJavaObject(PyObject, Class, String[], Object...)} * {@see #newJavaObject(PyModule, Class, Object...)} 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 @@ -1050,7 +1050,21 @@ @ExposedMethod(doc = BuiltinDocs.str_lower_doc) final String str_lower() { - return getString().toLowerCase(Locale.ROOT); + String s = getString(); + int n = s.length(); + if (n == 1) { + // Special-case single byte string + char c = s.charAt(0); + return _isupper(c) ? String.valueOf((char)(c ^ SWAP_CASE)) : s; + } else { + // Copy chars to buffer, converting to lower-case. + char[] buf = new char[n]; + for (int i = 0; i < n; i++) { + char c = s.charAt(i); + buf[i] = _isupper(c) ? (char)(c ^ SWAP_CASE) : c; + } + return new String(buf); + } } public String upper() { @@ -1059,7 +1073,21 @@ @ExposedMethod(doc = BuiltinDocs.str_upper_doc) final String str_upper() { - return getString().toUpperCase(Locale.ROOT); + String s = getString(); + int n = s.length(); + if (n == 1) { + // Special-case single byte string + char c = s.charAt(0); + return _islower(c) ? String.valueOf((char)(c ^ SWAP_CASE)) : s; + } else { + // Copy chars to buffer, converting to upper-case. + char[] buf = new char[n]; + for (int i = 0; i < n; i++) { + char c = s.charAt(i); + buf[i] = _islower(c) ? (char)(c ^ SWAP_CASE) : c; + } + return new String(buf); + } } public String title() { @@ -1070,19 +1098,25 @@ final String str_title() { char[] chars = getString().toCharArray(); int n = chars.length; - boolean previous_is_cased = false; for (int i = 0; i < n; i++) { char ch = chars[i]; - if (previous_is_cased) { - chars[i] = Character.toLowerCase(ch); - } else { - chars[i] = Character.toTitleCase(ch); - } - - if (Character.isLowerCase(ch) || Character.isUpperCase(ch) || Character.isTitleCase(ch)) { + if (_isalpha(ch)) { + if (previous_is_cased) { + // Should be lower case + if (_isupper(ch)) { + chars[i] = (char)(ch ^ SWAP_CASE); + } + } else { + // Should be upper case + if (_islower(ch)) { + chars[i] = (char)(ch ^ SWAP_CASE); + } + } + // And this was a letter previous_is_cased = true; } else { + // This was not a letter previous_is_cased = false; } } @@ -1095,18 +1129,25 @@ @ExposedMethod(doc = BuiltinDocs.str_swapcase_doc) final String str_swapcase() { - char[] chars = getString().toCharArray(); - int n = chars.length; - for (int i = 0; i < n; i++) { - char c = chars[i]; - if (Character.isUpperCase(c)) { - chars[i] = Character.toLowerCase(c); - } else if (Character.isLowerCase(c)) { - chars[i] = Character.toUpperCase(c); + String s = getString(); + int n = s.length(); + if (n == 1) { + // Special-case single byte string + char c = s.charAt(0); + return _isalpha(c) ? String.valueOf((char)(c ^ SWAP_CASE)) : s; + } else { + // Copy chars to buffer, converting lower to upper case, upper to lower case. + char[] buf = new char[n]; + for (int i = 0; i < n; i++) { + char c = s.charAt(i); + buf[i] = _isalpha(c) ? (char)(c ^ SWAP_CASE) : c; } + return new String(buf); } - return new String(chars); - } + } + + // Bit to twiddle (XOR) for lowercase letter to uppercase and vice-versa. + private static final int SWAP_CASE = 0x20; /** * Equivalent of Python str.strip() with no argument, meaning strip whitespace. Any @@ -3071,11 +3112,22 @@ @ExposedMethod(doc = BuiltinDocs.str_capitalize_doc) final String str_capitalize() { - if (getString().length() == 0) { - return getString(); + String s = getString(); + int n = s.length(); + if (n == 0) { + return s; + } else { + char[] buf = new char[n]; + // At least one byte: if lower convert to upper case. + char c = s.charAt(0); + buf[0] = _islower(c) ? (char)(c ^ SWAP_CASE) : c; + // Copy the rest, converting to lower case. + for (int i = 1; i < n; i++) { + c = s.charAt(i); + buf[i] = _isupper(c) ? (char)(c ^ SWAP_CASE) : c; + } + return new String(buf); } - String first = getString().substring(0, 1).toUpperCase(); - return first.concat(getString().substring(1).toLowerCase()); } /** diff --git a/src/org/python/core/packagecache/CachedJarsPackageManager.java b/src/org/python/core/packagecache/CachedJarsPackageManager.java --- a/src/org/python/core/packagecache/CachedJarsPackageManager.java +++ b/src/org/python/core/packagecache/CachedJarsPackageManager.java @@ -157,7 +157,7 @@ private List[] createGenericStringListArray(){ return new List[] { Generic.list(), Generic.list() }; } - + // Extract all of the packages in a single jarfile private Map getZipPackages(InputStream jarin) throws IOException { Map[]> zipPackages = Generic.map(); @@ -280,8 +280,9 @@ } else { jarname = jarurl.getFile(); int slash = jarname.lastIndexOf('/'); - if (slash != -1) + if (slash != -1) { jarname = jarname.substring(slash + 1); + } } jarname = jarname.substring(0, jarname.length() - 4); @@ -421,7 +422,7 @@ String classes = kv.getValue(); // Make sure each package is not larger than 64k for (String part : splitString(classes, 65535)) { - // For each chunk, write the package name followed by the classes. + // For each chunk, write the package name followed by the classes. ostream.writeUTF(kv.getKey()); ostream.writeUTF(part); } @@ -441,11 +442,11 @@ /** * Split up a string into several chunks based on a certain size - * + * * The writeCacheFile method will use the writeUTF method on a - * DataOutputStream which only allows writing 64k chunks, so use + * DataOutputStream which only allows writing 64k chunks, so use * this utility method to split it up - * + * * @param str - The string to split up into chunks * @param maxLength - The max size a string should be * @return - An array of strings, each of which will not be larger than maxLength @@ -642,8 +643,9 @@ index += 1; } entry.cachefile = cachefile.getCanonicalPath(); - } else + } else { cachefile = new File(entry.cachefile); + } return new DataOutputStream(new BufferedOutputStream( new FileOutputStream(cachefile))); diff --git a/src/org/python/core/packagecache/PackageManager.java b/src/org/python/core/packagecache/PackageManager.java --- a/src/org/python/core/packagecache/PackageManager.java +++ b/src/org/python/core/packagecache/PackageManager.java @@ -97,8 +97,9 @@ for (PyObject name : dictKeys.asIterable()) { if (!cls.has_key(name)) { - if (exclpkgs && dict.get(name) instanceof PyJavaPackage) + if (exclpkgs && dict.get(name) instanceof PyJavaPackage) { continue; + } ret.append(name); } } @@ -139,8 +140,9 @@ } firstName = firstName.intern(); top = top.__findattr__(firstName); - if (top == null) + if (top == null) { return null; + } // ??pending: test for jpkg/jclass? name = lastName; } while (name != null); @@ -160,11 +162,13 @@ public PyJavaPackage makeJavaPackage(String name, String classes, String jarfile) { PyJavaPackage p = this.topLevelPackage; - if (name.length() != 0) + if (name.length() != 0) { p = p.addPackage(name, jarfile); + } - if (classes != null) + if (classes != null) { p.addPlaceholders(classes); + } return p; } diff --git a/src/org/python/core/packagecache/PathPackageManager.java b/src/org/python/core/packagecache/PathPackageManager.java --- a/src/org/python/core/packagecache/PathPackageManager.java +++ b/src/org/python/core/packagecache/PathPackageManager.java @@ -75,6 +75,7 @@ private boolean python; + @Override public boolean accept(File dir, String name) { if(name.endsWith(".py") || name.endsWith("$py.class") || name.endsWith("$_PyInner.class")) { python = true; @@ -94,7 +95,7 @@ /** * Helper for {@link #doDir(PyJavaPackage,boolean,boolean)}. Scans for - * package jpkg content over the directories in path. Add to ret the founded + * package jpkg content over the directories in path. Add to ret the found * classes/pkgs. Filter out classes using {@link #filterByName},{@link #filterByAccess}. */ protected void doDir(PyList path, PyList ret, PyJavaPackage jpkg, @@ -141,7 +142,7 @@ } jname = jname.substring(0, jlen); - PyString name = new PyString(jname); + PyString name = Py.newStringOrUnicode(jname); if (filterByName(jname, pkgCand)) { continue; @@ -193,12 +194,13 @@ /** * Add directory dir (if exists) to {@link #searchPath}. */ + @Override public void addDirectory(File dir) { try { if (dir.getPath().length() == 0) { this.searchPath.append(Py.EmptyString); } else { - this.searchPath.append(new PyString(dir.getCanonicalPath())); + this.searchPath.append(Py.newStringOrUnicode(dir.getCanonicalPath())); } } catch (IOException e) { warning("skipping bad directory, '" + dir + "'"); @@ -235,6 +237,7 @@ } } + @Override public PyList doDir(PyJavaPackage jpkg, boolean instantiate, boolean exclpkgs) { PyList basic = basicDoDir(jpkg, instantiate, exclpkgs); @@ -245,6 +248,7 @@ return merge(basic, ret); } + @Override public boolean packageExists(String pkg, String name) { return packageExists(this.searchPath, pkg, name); } diff --git a/src/org/python/core/packagecache/SysPackageManager.java b/src/org/python/core/packagecache/SysPackageManager.java --- a/src/org/python/core/packagecache/SysPackageManager.java +++ b/src/org/python/core/packagecache/SysPackageManager.java @@ -17,18 +17,22 @@ */ public class SysPackageManager extends PathPackageManager { + @Override protected void message(String msg) { Py.writeMessage("*sys-package-mgr*", msg); } + @Override protected void warning(String warn) { Py.writeWarning("*sys-package-mgr*", warn); } + @Override protected void comment(String msg) { Py.writeComment("*sys-package-mgr*", msg); } + @Override protected void debug(String msg) { Py.writeDebug("*sys-package-mgr*", msg); } @@ -41,6 +45,7 @@ } } + @Override public void addJar(String jarfile, boolean cache) { addJarToPackages(new File(jarfile), cache); if (cache) { @@ -48,6 +53,7 @@ } } + @Override public void addJarDir(String jdir, boolean cache) { addJarDir(jdir, cache, cache); } @@ -111,6 +117,7 @@ } } + @Override public void notifyPackageImport(String pkg, String name) { if (pkg != null && pkg.length() > 0) { name = pkg + '.' + name; @@ -118,6 +125,7 @@ Py.writeComment("import", "'" + name + "' as java package"); } + @Override public Class findClass(String pkg, String name) { Class c = super.findClass(pkg, name); if (c != null) { @@ -126,6 +134,7 @@ return c; } + @Override public Class findClass(String pkg, String name, String reason) { if (pkg != null && pkg.length() > 0) { name = pkg + '.' + name; @@ -133,6 +142,7 @@ return Py.findClassEx(name, reason); } + @Override public PyList doDir(PyJavaPackage jpkg, boolean instantiate, boolean exclpkgs) { PyList basic = basicDoDir(jpkg, instantiate, exclpkgs); @@ -149,6 +159,7 @@ return merge(basic, ret); } + @Override public boolean packageExists(String pkg, String name) { if (packageExists(this.searchPath, pkg, name)) { return true; -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Sat Oct 10 09:58:11 2015 From: jython-checkins at python.org (jeff.allen) Date: Sat, 10 Oct 2015 07:58:11 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Add_tests_defining_treatmen?= =?utf-8?q?t_of_whitespace_in_str_and_unicode=2E?= Message-ID: <20151010075810.18368.66332@psf.io> https://hg.python.org/jython/rev/897051aa79c7 changeset: 7750:897051aa79c7 user: Jeff Allen date: Thu Oct 01 20:51:43 2015 +0100 summary: Add tests defining treatment of whitespace in str and unicode. unicode & str share implementations of strip and split. This implementation is correct for str. It diverges from CPython where java.lang.Character.isWhitespace differs from unicode.isspace. This change set documents the (possibly acceptable) divergence. files: Lib/test/test_bytes_jy.py | 26 ++++++++++ Lib/test/test_unicode_jy.py | 62 +++++++++++++++++++++++- 2 files changed, 85 insertions(+), 3 deletions(-) diff --git a/Lib/test/test_bytes_jy.py b/Lib/test/test_bytes_jy.py --- a/Lib/test/test_bytes_jy.py +++ b/Lib/test/test_bytes_jy.py @@ -152,6 +152,32 @@ self.checkequal(u"Le D?Ner ? ?Tretat".encode('latin-1'), title, 'title') + # *strip() tests to supplement string_tests with non-ascii examples, + # using characters that are spaces in latin-1 but not in ascii. + + def test_strip(self): + for c in self.SPACE: + # These should not be stripped at left or right because of c + sp = b" \t " + s = c + sp + b"hello" + sp + c + self.checkequal( s, s, 'strip') + self.checkequal( s, sp+s+sp, 'strip') + self.checkequal( sp+s, sp+s, 'rstrip') + self.checkequal( sp+s, sp+s+sp, 'rstrip') + self.checkequal( s+sp, s+sp, 'lstrip') + self.checkequal( s+sp, sp+s+sp, 'lstrip') + + def test_split(self): + for c in self.SPACE: + # These should not be split at c + s = b"AAA" + c + b"BBB" + self.assertEqual(1, len(s.split()), "split made in " + repr(s)) + self.assertEqual(1, len(s.rsplit()), "rsplit made in " + repr(s)) + s = bytearray(s) + self.assertEqual(1, len(s.split()), "split made in " + repr(s)) + self.assertEqual(1, len(s.rsplit()), "rsplit made in " + repr(s)) + + def test_main(): test.test_support.run_unittest( ByteArraySubclassTest, diff --git a/Lib/test/test_unicode_jy.py b/Lib/test/test_unicode_jy.py --- a/Lib/test/test_unicode_jy.py +++ b/Lib/test/test_unicode_jy.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- """Misc unicode tests -Made for Jython. +Made for Jython. (But it will run for CPython.) """ import itertools import random @@ -11,7 +11,6 @@ import unittest from StringIO import StringIO from test import test_support -from java.lang import StringBuilder class UnicodeTestCase(unittest.TestCase): @@ -108,6 +107,7 @@ def test_repr(self): self.assert_(isinstance('%r' % u'foo', str)) + @unittest.skipUnless(test_support.is_jython, "Specific to Jython") def test_unicode_lone_surrogate(self): # http://bugs.jython.org/issue2190 self.assertRaises(ValueError, unichr, 0xd800) @@ -167,7 +167,11 @@ ''' base = tuple(u'abcdefghijklmnopqrstuvwxyz') - supp = tuple(map(unichr, range(0x10000, 0x1000c))) + if sys.maxunicode < 0x10000: + # This is here to prevent error messages on a narrow CPython build. + supp = (u'NOT SUPPORTED',) + else: + supp = tuple(map(unichr, range(0x10000, 0x1000c))) used = sorted(set(base+supp)) def __init__(self, size=20, pred=None, ran=None): @@ -225,6 +229,7 @@ self.text = u''.join(self.ref) + at unittest.skipUnless(test_support.is_jython, "Specific to Jython") class UnicodeIndexMixTest(unittest.TestCase): # Test indexing where there may be more than one code unit per code point. # See Jython Issue #2100. @@ -368,6 +373,8 @@ def test_surrogate_validation(self): + from java.lang import StringBuilder + def insert_sb(text, c1, c2): # Insert code points c1, c2 in the text, as a Java StringBuilder sb = StringBuilder() @@ -845,6 +852,54 @@ self.assertRaises(ValueError, fmt.format, u"{0}", 10, 20, i=100) self.assertRaises(ValueError, fmt.format, u"{i}", 10, 20, i=100) +class UnicodeSpaceTest(unittest.TestCase): + # Test classification of characters as whitespace (some Jython divergence) + + def checkequal(self, expected, obj, methodname, *args): + "check that object.method() returns expected result" + realresult = getattr(obj, methodname)() + grumble = "%r.%s() returned %r" % (obj, methodname, realresult) + self.assertEqual(expected, realresult, grumble) + # print grumble, 'x' if realresult != expected else '.' + + # The set of Unicode characters that are spaces according to CPython 2.7.8 + SPACE = u'\t\n\x0b\x0c\r\x1c\x1d\x1e\x1f\x20\x85\xa0\u1680\u180e' + \ + u'\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a' + \ + u'\u2028\u2029\u202f\u205f\u3000' + if test_support.is_jython: + # Not whitespace in Jython based on java.lang.Character.isWhitespace. + # This test documents the divergence, until we decide to remove it. + for c in u'\x85\xa0\u2007\u202f': + SPACE = SPACE.replace(c, u'') + + def test_isspace(self): + for c in self.SPACE: + self.checkequal(True, c, 'isspace') + self.checkequal(True, u'\t' + c + u' ', 'isspace') + + # *strip() tests to supplement string_tests with non-ascii examples, + # using characters that are spaces in latin-1 but not in ascii. + + def test_strip(self): + for c in self.SPACE: + # These should be stripped of c at left or right + sp = u" " + c + u" " + h = u"hello" + s = sp + h + sp + self.checkequal( h, s, 'strip') + self.checkequal( h, c + s + c, 'strip') + self.checkequal( sp + h, s, 'rstrip') + self.checkequal( sp + h, s + c, 'rstrip') + self.checkequal( h + sp, s, 'lstrip') + self.checkequal( h + sp, c + s, 'lstrip') + + def test_split(self): + for c in self.SPACE: + # These should be split at c + s = u"AAA" + c + u"BBB" + self.assertEqual(2, len(s.split()), "no split made in " + repr(s)) + self.assertEqual(2, len(s.rsplit()), "no rsplit made in " + repr(s)) + def test_main(): test_support.run_unittest( @@ -854,6 +909,7 @@ UnicodeStdIOTestCase, UnicodeFormatStrTest, StringModuleUnicodeTest, + UnicodeSpaceTest, ) -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Sun Oct 11 01:19:55 2015 From: jython-checkins at python.org (jeff.allen) Date: Sat, 10 Oct 2015 23:19:55 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Update_News_and_Acknowledge?= =?utf-8?q?ments_to_reflect_recent_changes=2E?= Message-ID: <20151010231954.20755.7830@psf.io> https://hg.python.org/jython/rev/8472b61639f2 changeset: 7753:8472b61639f2 user: Jeff Allen date: Sun Oct 11 00:11:59 2015 +0100 summary: Update News and Acknowledgements to reflect recent changes. files: ACKNOWLEDGMENTS | 1 + NEWS | 6 ++++++ 2 files changed, 7 insertions(+), 0 deletions(-) diff --git a/ACKNOWLEDGMENTS b/ACKNOWLEDGMENTS --- a/ACKNOWLEDGMENTS +++ b/ACKNOWLEDGMENTS @@ -161,6 +161,7 @@ Jason Madden Daniel Martin Richard Fearn + Adam Burke Local Variables: mode: indented-text diff --git a/NEWS b/NEWS --- a/NEWS +++ b/NEWS @@ -2,6 +2,12 @@ For more details, please see https://hg.python.org/jython +Jython 2.7.1b2 + Bugs fixed + - [ 2396 ] test_threading and others fail under Cygwin (sys.executable). + - [ 2397 ] test.test_os_jy fails on Windows due to non-byte PyString. + - [ 2405 ] os.getpid() is missing (JNR JARs updated). + Jython 2.7.1b1 Bugs fixed - [ 1423 ] Circular imports no longer cause RuntimeError. -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Sun Oct 11 01:19:55 2015 From: jython-checkins at python.org (jeff.allen) Date: Sat, 10 Oct 2015 23:19:55 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_sys=2Eexecutable_is_jython?= =?utf-8?q?=2Eexe_on_Cygwin_fixes_=232396_=28thanks_Adam_Burke=29=2E?= Message-ID: <20151010231954.18384.93080@psf.io> https://hg.python.org/jython/rev/b03890ba8504 changeset: 7752:b03890ba8504 user: Jeff Allen date: Sun Oct 11 00:01:05 2015 +0100 summary: sys.executable is jython.exe on Cygwin fixes #2396 (thanks Adam Burke). When the Unix-like launcher is used by Cygwin, we ensure that sys.executable specifies the .exe launcher, which it must be to launch a subprocess succesfully. files: src/shell/jython | 3 ++- 1 files changed, 2 insertions(+), 1 deletions(-) diff --git a/src/shell/jython b/src/shell/jython --- a/src/shell/jython +++ b/src/shell/jython @@ -98,7 +98,8 @@ # switch delimiter only after building a Unix style $CP CP_DELIMITER=";" CP=`cygpath -p -w "$CP"` - PRG=`cygpath -w "$PRG"` + # ensure sys.executable is the Windows executable wrapper + PRG=`cygpath -w "$PRG"`.exe fi # ----- Execute the requested command ----------------------------------------- -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Sun Oct 11 08:17:14 2015 From: jython-checkins at python.org (darjus.loktevic) Date: Sun, 11 Oct 2015 06:17:14 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Initial_support_for_SSLCont?= =?utf-8?q?ext?= Message-ID: <20151011061714.2687.96499@psf.io> https://hg.python.org/jython/rev/57e704347787 changeset: 7754:57e704347787 user: Darjus Loktevic date: Sun Oct 11 17:17:10 2015 +1100 summary: Initial support for SSLContext files: Lib/_sslcerts.py | 76 +++++----- Lib/ssl.py | 247 +++++++++++++++++++++++++++++++--- 2 files changed, 261 insertions(+), 62 deletions(-) diff --git a/Lib/_sslcerts.py b/Lib/_sslcerts.py --- a/Lib/_sslcerts.py +++ b/Lib/_sslcerts.py @@ -34,15 +34,16 @@ -def _get_ca_certs_trust_manager(ca_certs): +def _get_ca_certs_trust_manager(ca_certs=None): trust_store = KeyStore.getInstance(KeyStore.getDefaultType()) trust_store.load(None, None) num_certs_installed = 0 - with open(ca_certs) as f: - cf = CertificateFactory.getInstance("X.509") - for cert in cf.generateCertificates(BufferedInputStream(f)): - trust_store.setCertificateEntry(str(uuid.uuid4()), cert) - num_certs_installed += 1 + if ca_certs is not None: + with open(ca_certs) as f: + cf = CertificateFactory.getInstance("X.509") + for cert in cf.generateCertificates(BufferedInputStream(f)): + trust_store.setCertificateEntry(str(uuid.uuid4()), cert) + num_certs_installed += 1 tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()) tmf.init(trust_store) log.debug("Installed %s certificates", num_certs_installed, extra={"sock": "*"}) @@ -67,9 +68,13 @@ return _stringio_as_reader(private_key), _stringio_as_reader(certs) -def _get_openssl_key_manager(cert_file, key_file=None): +def _get_openssl_key_manager(cert_file=None, key_file=None, password=None, _key_store=None): + if password is None: + password = [] + paths = [key_file] if key_file else [] - paths.append(cert_file) + if cert_file: + paths.append(cert_file) # Go from Bouncy Castle API to Java's; a bit heavyweight for the Python dev ;) key_converter = JcaPEMKeyConverter().setProvider("BC") @@ -90,41 +95,23 @@ elif isinstance(obj, X509CertificateHolder): certs.append(cert_converter.getCertificate(obj)) - if not private_key: - from _socket import SSLError, SSL_ERROR_SSL - raise SSLError(SSL_ERROR_SSL, "No private key loaded") - key_store = KeyStore.getInstance(KeyStore.getDefaultType()) - key_store.load(None, None) - key_store.setKeyEntry(str(uuid.uuid4()), private_key, [], certs) + + if _key_store is None: + key_store = KeyStore.getInstance(KeyStore.getDefaultType()) + key_store.load(None, None) + + if cert_file is not None: + if not private_key: + from _socket import SSLError, SSL_ERROR_SSL + raise SSLError(SSL_ERROR_SSL, "No private key loaded") + + key_store.setKeyEntry(str(uuid.uuid4()), private_key, [], certs) + kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()) kmf.init(key_store, []) return kmf -def _get_ssl_context(keyfile, certfile, ca_certs): - if certfile is None and ca_certs is None: - log.debug("Using default SSL context", extra={"sock": "*"}) - return SSLContext.getDefault() - else: - log.debug("Setting up a specific SSL context for keyfile=%s, certfile=%s, ca_certs=%s", - keyfile, certfile, ca_certs, extra={"sock": "*"}) - if ca_certs: - # should support composite usage below - trust_managers = _get_ca_certs_trust_manager(ca_certs).getTrustManagers() - else: - trust_managers = None - if certfile: - key_managers = _get_openssl_key_manager(certfile, keyfile).getKeyManagers() - else: - key_managers = None - - # FIXME FIXME for performance, cache this lookup in the future - # to avoid re-reading files on every lookup - context = SSLContext.getInstance("SSL") - context.init(key_managers, trust_managers, None) - return context - - # CompositeX509KeyManager and CompositeX509TrustManager allow for mixing together Java built-in managers # with new managers to support Python ssl. # @@ -214,3 +201,16 @@ for trust_manager in self.trust_managers: certs.extend(trustManager.getAcceptedIssuers()) return certs + + +# To use with CERT_NONE +class NoVerifyX509TrustManager(X509TrustManager): + + def checkClientTrusted(self, chain, auth_type): + pass + + def checkServerTrusted(self, chain, auth_type): + pass + + def getAcceptedIssuers(self): + return None diff --git a/Lib/ssl.py b/Lib/ssl.py --- a/Lib/ssl.py +++ b/Lib/ssl.py @@ -1,5 +1,12 @@ import base64 +from collections import namedtuple import errno +from java.security.cert import CertificateFactory +import uuid +from java.io import BufferedInputStream +from java.security import KeyStore +from java.security.cert import CertificateParsingException +from javax.net.ssl import TrustManagerFactory import logging import os.path import textwrap @@ -27,7 +34,8 @@ SSL_ERROR_EOF, SSL_ERROR_INVALID_ERROR_CODE, error as socket_error) -from _sslcerts import _get_ssl_context +from _sslcerts import _get_openssl_key_manager, NoVerifyX509TrustManager +from _sslcerts import SSLContext as _JavaSSLContext from java.text import SimpleDateFormat from java.util import ArrayList, Locale, TimeZone @@ -35,7 +43,6 @@ from javax.naming.ldap import LdapName from javax.security.auth.x500 import X500Principal - log = logging.getLogger("_socket") @@ -47,11 +54,16 @@ CERT_NONE, CERT_OPTIONAL, CERT_REQUIRED = range(3) # Do not support PROTOCOL_SSLv2, it is highly insecure and it is optional -_, PROTOCOL_SSLv3, PROTOCOL_SSLv23, PROTOCOL_TLSv1 = range(4) +_, PROTOCOL_SSLv3, PROTOCOL_SSLv23, PROTOCOL_TLSv1, PROTOCOL_TLSv1_1, PROTOCOL_TLSv1_2 = range(6) _PROTOCOL_NAMES = { - PROTOCOL_SSLv3: 'SSLv3', + PROTOCOL_SSLv3: 'SSLv3', PROTOCOL_SSLv23: 'SSLv23', - PROTOCOL_TLSv1: 'TLSv1'} + PROTOCOL_TLSv1: 'TLSv1', + PROTOCOL_TLSv1_1: 'TLSv1.1', + PROTOCOL_TLSv1_2: 'TLSv1.2' +} + +OP_ALL, OP_NO_SSLv2, OP_NO_SSLv3, OP_NO_TLSv1 = range(4) _rfc2822_date_format = SimpleDateFormat("MMM dd HH:mm:ss yyyy z", Locale.US) _rfc2822_date_format.setTimeZone(TimeZone.getTimeZone("GMT")) @@ -59,11 +71,11 @@ _ldap_rdn_display_names = { # list from RFC 2253 "CN": "commonName", - "L": "localityName", + "L": "localityName", "ST": "stateOrProvinceName", - "O": "organizationName", + "O": "organizationName", "OU": "organizationalUnitName", - "C": "countryName", + "C": "countryName", "STREET": "streetAddress", "DC": "domainComponent", "UID": "userid" @@ -84,7 +96,6 @@ class SSLInitializer(ChannelInitializer): - def __init__(self, ssl_handler): self.ssl_handler = ssl_handler @@ -94,15 +105,35 @@ class SSLSocket(object): - - def __init__(self, sock, - keyfile, certfile, ca_certs, - do_handshake_on_connect, server_side): + + def __init__(self, sock, keyfile=None, certfile=None, server_side=False, cert_reqs=CERT_NONE, + ssl_version=PROTOCOL_SSLv23, ca_certs=None, + do_handshake_on_connect=True, suppress_ragged_eofs=True, ciphers=None, _context=None): + # TODO ^^ handle suppress_ragged_eofs self.sock = sock self.do_handshake_on_connect = do_handshake_on_connect self._sock = sock._sock # the real underlying socket - self.context = _get_ssl_context(keyfile, certfile, ca_certs) - self.engine = self.context.createSSLEngine() + self.context = _context + if _context is None: + self.context = SSLContext(ssl_version) + else: + if server_side and not certfile: + raise ValueError("certfile must be specified for server-side " + "operations") + if keyfile and not certfile: + raise ValueError("certfile must be specified") + if certfile and not keyfile: + keyfile = certfile + self._context = SSLContext(ssl_version) + self._context.verify_mode = cert_reqs + if ca_certs: + self._context.load_verify_locations(ca_certs) + if certfile: + self._context.load_cert_chain(certfile, keyfile) + if ciphers: + self._context.set_ciphers(ciphers) + + self.engine = self.context._createSSLEngine() self.server_side = server_side self.engine.setUseClientMode(not server_side) self.ssl_handler = None @@ -254,7 +285,7 @@ pycert = { "notAfter": _rfc2822_date_format.format(cert.getNotAfter()), "subject": rdns, - "subjectAltName": alt_names, + "subjectAltName": alt_names, } return pycert @@ -274,7 +305,6 @@ return suite, str(session.protocol), strength - # instantiates a SSLEngine, with the following things to keep in mind: # FIXME not yet supported @@ -284,10 +314,11 @@ @raises_java_exception def wrap_socket(sock, keyfile=None, certfile=None, server_side=False, cert_reqs=CERT_NONE, - ssl_version=None, ca_certs=None, do_handshake_on_connect=True, + ssl_version=PROTOCOL_SSLv23, ca_certs=None, do_handshake_on_connect=True, suppress_ragged_eofs=True, ciphers=None): + return SSLSocket( - sock, + sock, keyfile=keyfile, certfile=certfile, ca_certs=ca_certs, server_side=server_side, do_handshake_on_connect=do_handshake_on_connect) @@ -296,7 +327,6 @@ # some utility functions def cert_time_to_seconds(cert_time): - """Takes a date-time string in standard ASN1_print form ("MON DAY 24HOUR:MINUTE:SEC YEAR TIMEZONE") and return a Python time value in seconds past the epoch.""" @@ -304,11 +334,12 @@ import time return time.mktime(time.strptime(cert_time, "%b %d %H:%M:%S %Y GMT")) + PEM_HEADER = "-----BEGIN CERTIFICATE-----" PEM_FOOTER = "-----END CERTIFICATE-----" + def DER_cert_to_PEM_cert(der_cert_bytes): - """Takes a certificate in binary DER format and returns the PEM version of it as a string.""" @@ -323,8 +354,8 @@ base64.encodestring(der_cert_bytes) + PEM_FOOTER + '\n') + def PEM_cert_to_DER_cert(pem_cert_string): - """Takes a certificate in ASCII PEM format and returns the DER-encoded version of it as a byte sequence""" @@ -337,8 +368,8 @@ d = pem_cert_string.strip()[len(PEM_HEADER):-len(PEM_FOOTER)] return base64.decodestring(d) + def get_server_certificate(addr, ssl_version=PROTOCOL_SSLv3, ca_certs=None): - """Retrieve the certificate from the server at the specified address, and return it as a PEM-encoded string. If 'ca_certs' is specified, validate the server cert against it. @@ -356,13 +387,14 @@ s.close() return DER_cert_to_PEM_cert(dercert) + def get_protocol_name(protocol_code): return _PROTOCOL_NAMES.get(protocol_code, '') + # a replacement for the old socket.ssl function def sslwrap_simple(sock, keyfile=None, certfile=None): - """A replacement for the old socket.ssl function. Designed for compability with Python 2.5 and earlier. Will disappear in Python 3.0.""" @@ -385,11 +417,178 @@ def RAND_status(): return True + def RAND_egd(path): if os.path.abspath(str(path)) != path: raise TypeError("Must be an absolute path, but ignoring it regardless") + def RAND_add(bytes, entropy): pass +class Purpose(object): + """SSLContext purpose flags with X509v3 Extended Key Usage objects + """ + SERVER_AUTH = '1.3.6.1.5.5.7.3.1' + CLIENT_AUTH = '1.3.6.1.5.5.7.3.2' + + +class SSLContext(object): + _DN_TO_CPY = {'CN': 'commonName', 'O': 'commonOrganization', 'C': 'countryName', 'DC': 'domainComponent', + 'SN': 'surname', 'GN': 'givenName', 'OU': 'organizationalUnitName', 'ST': 'stateOrProvinceName', + 'L': 'localityName', 'SERIALNUMBER': 'serialNumber', 'EMAILADDRESS': 'emailAddress'} + + def __init__(self, protocol): + protocol_name = _PROTOCOL_NAMES[protocol] + if protocol == PROTOCOL_SSLv23: # darjus: at least my Java does not let me use v2 + protocol_name = 'SSL' + + self.protocol = protocol + self.check_hostname = False + self.options = OP_ALL + self.verify_flags = None + self.verify_mode = CERT_NONE + self._ciphers = None + + self._trust_store = KeyStore.getInstance(KeyStore.getDefaultType()) + self._trust_store.load(None, None) + + self._key_store = KeyStore.getInstance(KeyStore.getDefaultType()) + self._key_store.load(None, None) + + self._context = _JavaSSLContext.getInstance(protocol_name) + self._key_managers = None + + def wrap_socket(self, sock, server_side=False, + do_handshake_on_connect=True, + suppress_ragged_eofs=True, + server_hostname=None): + # FIXME do something about server_hostname + return SSLSocket(sock, keyfile=None, certfile=None, ca_certs=None, suppress_ragged_eofs=suppress_ragged_eofs, + do_handshake_on_connect=do_handshake_on_connect, server_side=server_side, _context=self) + + def _createSSLEngine(self): + trust_managers = [NoVerifyX509TrustManager()] + if self.verify_mode == CERT_REQUIRED: + tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()) + tmf.init(self._trust_store) + trust_managers = tmf.getTrustManagers() + + if self._key_managers is None: # get an e + self._context.init(_get_openssl_key_manager().getKeyManagers(), trust_managers, None) + else: + self._context.init(self._key_managers.getKeyManagers(), trust_managers, None) + + engine = self._context.createSSLEngine() + + if self._ciphers is not None: + engine.setEnabledCipherSuites(self._ciphers) + + return engine + + def cert_store_stats(self): + # TODO not sure if we can even get something similar from Java + return {} + + def load_cert_chain(self, certfile, keyfile=None, password=None): + self._key_managers = _get_openssl_key_manager(certfile, keyfile, password, _key_store=self._key_store) + + def set_ciphers(self, ciphers): + # TODO conversion from OpenSSL to http://www.iana.org/assignments/tls-parameters/tls-parameters.xml + # as Java knows no other + #self._ciphers = ciphers + pass + + def load_verify_locations(self, cafile=None, capath=None, cadata=None): + print cafile + if cafile is not None: + with open(cafile) as f: + self._load_certificates(f) + if capath is not None: + for fname in os.listdir(capath): + _, ext = os.path.splitext() + if ext.lower() == 'pem': + with open(os.path.join(capath, fname)) as f: + self._load_certificates(f) + if cadata is not None: + self._load_certificates(f) + + @raises_java_exception + def _load_certificates(self, f): + cf = CertificateFactory.getInstance("X.509") + try: + for cert in cf.generateCertificates(BufferedInputStream(f)): + self._trust_store.setCertificateEntry(str(uuid.uuid4()), cert) + except CertificateParsingException: + log.debug("Failed to parse certificate", exc_info=True) + raise + + def load_default_certs(self, purpose=None): + # TODO handle/support purpose + self.set_default_verify_paths() + + def set_default_verify_paths(self): + """ + Load a set of default "certification authority" (CA) certificates from a filesystem path defined when building + the OpenSSL library. Unfortunately, there's no easy way to know whether this method succeeds: no error is + returned if no certificates are to be found. When the OpenSSL library is provided as part of the operating + system, though, it is likely to be configured properly. + """ + # TODO not implemented, we want to use some default Java's loading method. + return None + + def set_alpn_protocols(self, protocols): + raise NotImplementedError() + + def set_npn_protocols(self, protocols): + raise NotImplementedError() + + def set_servername_callback(self, server_name_callback): + raise NotImplementedError() + + def load_dh_params(self, dhfile): + # TODO? + pass + + def set_ecdh_curve(self, curve_name): + # TODO? + pass + + def get_ca_certs(self, binary_form=False): + """get_ca_certs(binary_form=False) -> list of loaded certificate + + Returns a list of dicts with information of loaded CA certs. If the optional argument is True, + returns a DER-encoded copy of the CA certificate. + NOTE: Certificates in a capath directory aren't loaded unless they have been used at least once. + """ + if binary_form: + raise NotImplementedError() + + certs = [] + enumerator = self._trust_store.aliases() + while enumerator.hasMoreElements(): + alias = enumerator.next() + if self._trust_store.isCertificateEntry(alias): + cert = self._trust_store.getCertificate(alias) + issuer_info = self._parse_dn(cert.issuerDN) + subject_info = self._parse_dn(cert.subjectDN) + + cert_info = {'issuer': issuer_info, 'subject': subject_info} + for k in ('notBefore', 'serialNumber', 'notAfter', 'version'): + cert_info[k] = getattr(cert, k) + + certs.append(cert_info) + + return certs + + @classmethod + def _parse_dn(cls, dn): + try: + dn_dct = dict([iss.split('=', 1) for iss in unicode(dn).split(',')]) + except ValueError: + # FIXME CN=Starfield Root Certificate Authority - G2, O="Starfield Technologies, Inc.", + log.error("Failed to parse {}".format(dn), exc_info=True) + return tuple() + + return tuple((cls._DN_TO_CPY.get(key.strip(), 'unk'), val) for key, val in dn_dct.iteritems()) -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Sun Oct 11 09:27:22 2015 From: jython-checkins at python.org (darjus.loktevic) Date: Sun, 11 Oct 2015 07:27:22 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Fix_handling_of_multiargume?= =?utf-8?q?nt_exception_with_nonunicode_characters_when_calling?= Message-ID: <20151011072722.18360.62680@psf.io> https://hg.python.org/jython/rev/8fcc513944ef changeset: 7755:8fcc513944ef user: Darjus Loktevic date: Sun Oct 11 18:27:19 2015 +1100 summary: Fix handling of multiargument exception with nonunicode characters when calling __str__ Fixes http://bugs.jython.org/issue2331 files: src/org/python/core/exceptions.java | 11 +++++++---- 1 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/org/python/core/exceptions.java b/src/org/python/core/exceptions.java --- a/src/org/python/core/exceptions.java +++ b/src/org/python/core/exceptions.java @@ -269,15 +269,18 @@ PyObject errno = self.__findattr__("errno"); PyObject strerror = self.__findattr__("strerror"); PyObject filename = self.__findattr__("filename"); - String result; + PyString result; if (filename.__nonzero__()) { - result = String.format("[Errno %s] %s: %s", errno, strerror, filename.__repr__()); + result = Py.newString("[Errno %s] %s: %s"); + result = (PyString)result.__mod__(new PyTuple(errno, strerror, filename.__repr__())); + } else if (errno.__nonzero__() && strerror.__nonzero__()) { - result = String.format("[Errno %s] %s", errno, strerror); + result = Py.newString("[Errno %s] %s"); + result = (PyString)result.__mod__(new PyTuple(errno, strerror)); } else { return PyBaseException.TYPE.invoke("__str__", self, args, kwargs); } - return Py.newString(result); + return result; } public static PyObject EnvironmentError__reduce__(PyObject self, PyObject[] args, -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Mon Oct 12 05:44:47 2015 From: jython-checkins at python.org (frank.wierzbicki) Date: Mon, 12 Oct 2015 03:44:47 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Prepare_for_release=2E?= Message-ID: <20151012034447.7236.26378@psf.io> https://hg.python.org/jython/rev/6c0da6893570 changeset: 7756:6c0da6893570 user: Frank Wierzbicki date: Mon Oct 12 03:44:47 2015 +0000 summary: Prepare for release. files: README.txt | 4 ++-- build.xml | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/README.txt b/README.txt --- a/README.txt +++ b/README.txt @@ -1,8 +1,8 @@ Jython: Python for the Java Platform -Welcome to Jython 2.7.1 beta 1! +Welcome to Jython 2.7.1 beta 2! -This is the first beta release of the 2.7.1 version of Jython. Along with +This is the second beta release of the 2.7.1 version of Jython. Along with language and runtime compatibility with CPython 2.7.1, Jython 2.7 provides substantial support of the Python ecosystem. This includes built-in support of pip/setuptools (you can use with bin/pip) and a native launcher for Windows diff --git a/build.xml b/build.xml --- a/build.xml +++ b/build.xml @@ -84,11 +84,11 @@ - - + + - + @@ -412,7 +412,7 @@ - ======================= -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Mon Oct 12 05:46:51 2015 From: jython-checkins at python.org (frank.wierzbicki) Date: Mon, 12 Oct 2015 03:46:51 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Added_tag_v2=2E7=2E1b2_for_?= =?utf-8?q?changeset_6c0da6893570?= Message-ID: <20151012034651.128844.88083@psf.io> https://hg.python.org/jython/rev/315435b90915 changeset: 7757:315435b90915 user: Frank Wierzbicki date: Mon Oct 12 03:46:50 2015 +0000 summary: Added tag v2.7.1b2 for changeset 6c0da6893570 files: .hgtags | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/.hgtags b/.hgtags --- a/.hgtags +++ b/.hgtags @@ -99,3 +99,4 @@ 2f0b46abbe31275edc3257f54f8222fd37752d65 v2.7.1b1 2f0b46abbe31275edc3257f54f8222fd37752d65 v2.7.1b1 44403bccae2163186f8ab46b4a544a48e137bba6 v2.7.1b1 +6c0da6893570f3ae3cd37a33189cae954e2afebb v2.7.1b2 -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Fri Oct 16 21:21:14 2015 From: jython-checkins at python.org (jim.baker) Date: Fri, 16 Oct 2015 19:21:14 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Fix_typo_in_ACKNOWLEDGMENTS?= Message-ID: <20151016192114.75674.72381@psf.io> https://hg.python.org/jython/rev/624590c85f0f changeset: 7759:624590c85f0f user: Jim Baker date: Fri Oct 16 12:21:07 2015 -0700 summary: Fix typo in ACKNOWLEDGMENTS files: ACKNOWLEDGMENTS | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/ACKNOWLEDGMENTS b/ACKNOWLEDGMENTS --- a/ACKNOWLEDGMENTS +++ b/ACKNOWLEDGMENTS @@ -28,7 +28,7 @@ License from the Apache Software Foundation * Google Guava, licensed under an Apache 2.0 License from Google * ICU4J, licensed under a BSD license ("ICU License") from IBM and others -* Jar Jar Links, licensed uner the Apache 2.0 License from Tonic Systems +* Jar Jar Links, licensed under the Apache 2.0 License from Tonic Systems * Java Native Runtime, licensed under the Common Public License * JLine2, licensed under a BSD license * JUnit, licenseed under Eclipse Public License 1.0 from the JUnit project -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Fri Oct 16 21:30:49 2015 From: jython-checkins at python.org (jim.baker) Date: Fri, 16 Oct 2015 19:30:49 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Add_ICU4J_as_a_library_that?= =?utf-8?q?_Jython_uses_=28and_has_used_as_of_2=2E7b2=29?= Message-ID: <20151016192013.471.35623@psf.io> https://hg.python.org/jython/rev/b32a414ce924 changeset: 7758:b32a414ce924 user: Jim Baker date: Fri Oct 16 12:20:04 2015 -0700 summary: Add ICU4J as a library that Jython uses (and has used as of 2.7b2) files: ACKNOWLEDGMENTS | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/ACKNOWLEDGMENTS b/ACKNOWLEDGMENTS --- a/ACKNOWLEDGMENTS +++ b/ACKNOWLEDGMENTS @@ -27,6 +27,7 @@ * Apache Commons Compression and Xerces, licensed under an Apache 2.0 License from the Apache Software Foundation * Google Guava, licensed under an Apache 2.0 License from Google +* ICU4J, licensed under a BSD license ("ICU License") from IBM and others * Jar Jar Links, licensed uner the Apache 2.0 License from Tonic Systems * Java Native Runtime, licensed under the Common Public License * JLine2, licensed under a BSD license -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Sun Oct 18 03:41:33 2015 From: jython-checkins at python.org (darjus.loktevic) Date: Sun, 18 Oct 2015 01:41:33 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Regrtest_batch_script_for_W?= =?utf-8?q?indows_and_regrtest_output_improvements_=28committed?= Message-ID: <20151018014133.34039.52164@psf.io> https://hg.python.org/jython/rev/cec565535de3 changeset: 7760:cec565535de3 user: Adam Burke date: Sun Oct 18 12:39:45 2015 +1100 summary: Regrtest batch script for Windows and regrtest output improvements (committed by darjus@) files: Lib/test/regrtest.py | 73 ++++++++++++++++++---- src/shell/jython_regrtest.bat | 7 ++ 2 files changed, 67 insertions(+), 13 deletions(-) diff --git a/Lib/test/regrtest.py b/Lib/test/regrtest.py --- a/Lib/test/regrtest.py +++ b/Lib/test/regrtest.py @@ -500,7 +500,7 @@ os.system("leaks %d" % os.getpid()) if memo: - savememo(memo,good,bad,skipped) + savememo(memo,good,failures,bad,skips,skipped,allran,resource_denieds) sys.exit(surprises > 0) @@ -821,7 +821,7 @@ else: return "%d %ss" % (n, word) -def printlist(x, width=70, indent=4): +def printlist(x, width=70, indent=4, output_to=sys.stdout): """Print the elements of iterable x to stdout. Optional arg width (default 70) is the maximum line length. @@ -832,26 +832,36 @@ from textwrap import fill blanks = ' ' * indent # Print the sorted list: 'x' may be a '--random' list or a set() - print fill(' '.join(str(elt) for elt in sorted(x)), width, + print >> output_to, fill(' '.join(str(elt) for elt in sorted(x)), width, initial_indent=blanks, subsequent_indent=blanks) -def countsurprises(expected, actual, action, antiaction, allran, resource_denieds): +def countsurprises(expected, actual, action, antiaction, allran, resource_denieds, output_to=sys.stdout): """returns the number of items in actual that aren't in expected.""" - printlist(actual) + printlist(actual,output_to=output_to) if not expected.isvalid(): - print "Ask someone to teach regrtest.py about which tests are" - print "expected to %s on %s." % (action, sys.platform) + print >> output_to, "Ask someone to teach regrtest.py about which tests are" + print >> output_to, "expected to %s on %s." % (action, sys.platform) return 1#Surprising not to know what to expect.... good_surprise = expected.getexpected() - set(actual) if allran and good_surprise: - print count(len(good_surprise), 'test'), antiaction, 'unexpectedly:' - printlist(good_surprise) + print >> output_to, count(len(good_surprise), 'test'), antiaction, 'unexpectedly:' + printlist(good_surprise,output_to=output_to) bad_surprise = set(actual) - expected.getexpected() - set(resource_denieds) if bad_surprise: - print count(len(bad_surprise), action), "unexpected:" - printlist(bad_surprise) + print >> output_to, count(len(bad_surprise), action), "unexpected:" + printlist(bad_surprise,output_to=output_to) return len(bad_surprise) + +def skip_conditional_support(test_module,module_name): + try: + test_support.import_module(module_name) + except unittest.SkipTest: + return '\n' + test_module + return "" + + + # Map sys.platform to a string containing the basenames of tests # expected to be skipped on that platform. # @@ -1209,6 +1219,7 @@ test_capi test_cd test_cl + test_closuregen test_ctypes test_dl test_fcntl @@ -1259,9 +1270,11 @@ test_zipfile64 # Could rewrite these tests + test_descr test_epoll test_poll test_profile + test_struct # The following tests cause issues for tests that are subsequently run test_distutils @@ -1294,6 +1307,9 @@ test_sys_setprofile # revisit for GC test_sys_settrace # revisit for line jumping + + # Not yet Jython 3.x + test_lib2to3 """ } _expectations['freebsd5'] = _expectations['freebsd4'] @@ -1320,6 +1336,7 @@ test_dummy_threading test_eof test_frozen # not meaningful for Jython, although it is similar to Clamp singlejar + test_gc # test_gc_jy replaces this test_iterlen test_multibytecodec test_multibytecodec_support @@ -1344,6 +1361,26 @@ if ' ' in sys.executable: # http://bugs.python.org/issue1559298 _failures['java'] += '\ntest_popen' + if os._name != 'darwin': + _expectations['java'] += '\ntest__osx_support' + if os.name != 'posix': + _expectations['java'] += """ + test_commands + test_pipes""" + + + +# tests for modules which themselves test for compatability, based on +# additional installed libraries, etc +conditional_support = {'test_dbm':'dbm', + 'test_readline':'readline', + 'test_sax':'sax'} + +for test_module in conditional_support: + _expectations[_platform] += \ + skip_conditional_support(test_module,conditional_support[test_module]) + + class _ExpectedSkips: def __init__(self): @@ -1378,7 +1415,7 @@ if not sys.platform in ("mac", "darwin"): MAC_ONLY = ["test_macos", "test_macostools", "test_aepack", "test_plistlib", "test_scriptpackages", - "test_applesingle"] + "test_applesingle.pyingle"] for skip in MAC_ONLY: self.expected.add(skip) elif len(u'\0'.encode('unicode-internal')) == 4: @@ -1457,7 +1494,7 @@ self.expected = set(self.split_commented(s)) self.valid = True -def savememo(memo,good,bad,skipped): +def savememo(memo,good,failures,bad,skips,skipped,allran, resource_denieds): f = open(memo,'w') try: for n,l in [('good',good),('bad',bad),('skipped',skipped)]: @@ -1465,9 +1502,19 @@ for x in l: print >>f," %r," % x print >>f," ]" + print >>f, count(len(skipped), "test"), "skipped:" + countsurprises(skips, skipped, 'skip', 'ran', allran, resource_denieds,f) + print >>f, count(len(bad), "test"), "failed:" + countsurprises(failures, bad, 'fail', 'passed', allran, resource_denieds,f) + import platform + print >>f, "Platform: " + print >>f, " %r" % platform.platform() + print >>f, "Command line: " + print >>f, " %r" % sys.argv finally: f.close() + if __name__ == '__main__': # Remove regrtest.py's own directory from the module search path. This # prevents relative imports from working, and relative imports will screw diff --git a/src/shell/jython_regrtest.bat b/src/shell/jython_regrtest.bat new file mode 100644 --- /dev/null +++ b/src/shell/jython_regrtest.bat @@ -0,0 +1,7 @@ + + +set JY_PATH=%~dp0 + +%JY_PATH%\jython.exe -m test.regrtest -e -m regrtest_memo.txt + + -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Tue Oct 20 22:29:03 2015 From: jython-checkins at python.org (jeff.allen) Date: Tue, 20 Oct 2015 20:29:03 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Documentation_and_minor_imp?= =?utf-8?q?rovements_for_jython=5Fregrtest=2Ebat?= Message-ID: <20151020202857.117268.47765@psf.io> https://hg.python.org/jython/rev/9b3a8c5808a6 changeset: 7761:9b3a8c5808a6 user: Jeff Allen date: Tue Oct 20 19:58:47 2015 +0100 summary: Documentation and minor improvements for jython_regrtest.bat This follows up on #2393 but does not yet try to get right the list of expected failures necessary to exclude wholesale for a clean run. files: Lib/test/regrtest.py | 2 +- README.txt | 8 ++++++++ src/shell/jython_regrtest.bat | 11 ++++++----- 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/Lib/test/regrtest.py b/Lib/test/regrtest.py --- a/Lib/test/regrtest.py +++ b/Lib/test/regrtest.py @@ -1415,7 +1415,7 @@ if not sys.platform in ("mac", "darwin"): MAC_ONLY = ["test_macos", "test_macostools", "test_aepack", "test_plistlib", "test_scriptpackages", - "test_applesingle.pyingle"] + "test_applesingle"] for skip in MAC_ONLY: self.expected.add(skip) elif len(u'\0'.encode('unicode-internal')) == 4: diff --git a/README.txt b/README.txt --- a/README.txt +++ b/README.txt @@ -19,6 +19,14 @@ Java 7 to run. Please try this release out and report any bugs at http://bugs.jython.org +You can test your installation of Jython (not the standalone JAR) by running +the regression tests, with the command: + +jython -m test.regrtest -e -m regrtest_memo.txt + +For Windows, there is a simple script to do this: jython_regrtest.bat. In +either case, the memo file regrtest_memo.txt will be useful in the bug report +if you see test failures. The regression tests can take about half an hour. Please see ACKNOWLEDGMENTS for details about Jython's copyright, license, contributors, and mailing lists; and NEWS for detailed diff --git a/src/shell/jython_regrtest.bat b/src/shell/jython_regrtest.bat --- a/src/shell/jython_regrtest.bat +++ b/src/shell/jython_regrtest.bat @@ -1,7 +1,8 @@ + at echo off +rem Simple script (for Windows) that runs all the regression tests expected to pass. +rem It leaves a memo file regrtest_memo.txt that will be useful in a bug report. - +setlocal set JY_PATH=%~dp0 - -%JY_PATH%\jython.exe -m test.regrtest -e -m regrtest_memo.txt - - + at echo on +%JY_PATH%jython.exe -m test.regrtest -e -m regrtest_memo.txt -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Thu Oct 22 01:01:46 2015 From: jython-checkins at python.org (stefan.richthofer) Date: Wed, 21 Oct 2015 23:01:46 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Unified_PyDictionary_and_Py?= =?utf-8?q?_StringMap_under_a_common_abstract_class?= Message-ID: <20151021230141.27526.27007@psf.io> https://hg.python.org/jython/rev/02e8f41510f3 changeset: 7762:02e8f41510f3 user: Stefan Richthofer date: Thu Oct 22 01:01:24 2015 +0200 summary: Unified PyDictionary and Py StringMap under a common abstract class AbstractDict. This simplifies some JyNI-code and generally improves Jython's class structre and reduces need for case-distinctions. Also made the merge-function family public, adding the override-flag in the public API. This makes this API-part more consistent with CPython-API, also makin JyNI's dict-support more convenient. files: src/org/python/core/AbstractDict.java | 33 +++++ src/org/python/core/PyDictionary.java | 90 ++++++++++++++- src/org/python/core/PyStringMap.java | 90 ++++++++++++++- 3 files changed, 211 insertions(+), 2 deletions(-) diff --git a/src/org/python/core/AbstractDict.java b/src/org/python/core/AbstractDict.java new file mode 100644 --- /dev/null +++ b/src/org/python/core/AbstractDict.java @@ -0,0 +1,33 @@ +package org.python.core; + +import java.util.concurrent.ConcurrentMap; +import java.util.Collection; + +public abstract class AbstractDict extends PyObject { + + public AbstractDict(PyType type) { + super(type); + } + + public abstract void clear(); + public abstract AbstractDict copy(); + public abstract PyObject get(PyObject key); + public abstract PyObject get(PyObject key, PyObject defaultObj); + public abstract ConcurrentMap getMap(); + public abstract boolean has_key(PyObject key); + public abstract PyList items(); + public abstract PyObject iteritems(); + public abstract PyObject iterkeys(); + public abstract PyObject itervalues(); + public abstract PyList keys(); + public abstract void merge(PyObject other, boolean override); + public abstract void mergeFromKeys(PyObject other, PyObject keys, boolean override); + public abstract void mergeFromSeq(PyObject other, boolean override); + public abstract PyObject pop(PyObject key); + public abstract PyObject pop(PyObject key, PyObject defaultValue); + public abstract PyObject popitem(); + public abstract PyObject setdefault(PyObject key); + public abstract PyObject setdefault(PyObject key, PyObject failobj); + public abstract void update(PyObject other); + public abstract Collection values(); +} diff --git a/src/org/python/core/PyDictionary.java b/src/org/python/core/PyDictionary.java --- a/src/org/python/core/PyDictionary.java +++ b/src/org/python/core/PyDictionary.java @@ -27,7 +27,7 @@ * A builtin python dictionary. */ @ExposedType(name = "dict", doc = BuiltinDocs.dict_doc) -public class PyDictionary extends PyObject implements ConcurrentMap, Traverseproc { +public class PyDictionary extends AbstractDict implements ConcurrentMap, Traverseproc { public static final PyType TYPE = PyType.fromClass(PyDictionary.class); { @@ -520,6 +520,35 @@ } /** + * Merge another PyObject that supports keys() with this + * dict. + * + * @param other a PyObject with a keys() method + * @param override if true, the value from other is used on key-collision + */ + public void merge(PyObject other, boolean override) { + synchronized(internalMap) { + if (override) { + merge(other); + } else { + if (other instanceof PyDictionary) { + Set> entrySet = + ((PyDictionary)other).internalMap.entrySet(); + for (Map.Entry ent: entrySet) { + if (!internalMap.containsKey(ent.getKey())) { + internalMap.put(ent.getKey(), ent.getValue()); + } + } + } else if (other instanceof PyStringMap) { + mergeFromKeys(other, ((PyStringMap)other).keys(), override); + } else { + mergeFromKeys(other, other.invoke("keys"), override); + } + } + } + } + + /** * Merge another PyObject via its keys() method * * @param other a PyObject with a keys() method @@ -532,6 +561,27 @@ } /** + * Merge another PyObject via its keys() method + * + * @param other a PyObject with a keys() method + * @param keys the result of other's keys() method + * @param override if true, the value from other is used on key-collision + */ + public void mergeFromKeys(PyObject other, PyObject keys, boolean override) { + synchronized(internalMap) { + if (override) { + mergeFromKeys(other, keys); + } else { + for (PyObject key : keys.asIterable()) { + if (!dict___contains__(key)) { + dict___setitem__(key, other.__getitem__(key)); + } + } + } + } + } + + /** * Merge any iterable object producing iterable objects of length * 2 into this dict. * @@ -561,6 +611,44 @@ } /** + * Merge any iterable object producing iterable objects of length + * 2 into this dict. + * + * @param other another PyObject + * @param override if true, the value from other is used on key-collision + */ + public void mergeFromSeq(PyObject other, boolean override) { + synchronized(internalMap) { + if (override) { + mergeFromSeq(other); + } else { + PyObject pairs = other.__iter__(); + PyObject pair; + + for (int i = 0; (pair = pairs.__iternext__()) != null; i++) { + try { + pair = PySequence.fastSequence(pair, ""); + } catch(PyException pye) { + if (pye.match(Py.TypeError)) { + throw Py.TypeError(String.format("cannot convert dictionary update sequence " + + "element #%d to a sequence", i)); + } + throw pye; + } + int n; + if ((n = pair.__len__()) != 2) { + throw Py.ValueError(String.format("dictionary update sequence element #%d " + + "has length %d; 2 is required", i, n)); + } + if (!dict___contains__(pair.__getitem__(0))) { + dict___setitem__(pair.__getitem__(0), pair.__getitem__(1)); + } + } + } + } + } + + /** * Return this[key] if the key exist, otherwise insert key with * a None value and return None. * diff --git a/src/org/python/core/PyStringMap.java b/src/org/python/core/PyStringMap.java --- a/src/org/python/core/PyStringMap.java +++ b/src/org/python/core/PyStringMap.java @@ -24,7 +24,7 @@ * to PyObject unlike PyDictionary. */ @ExposedType(name = "stringmap", isBaseType = false) -public class PyStringMap extends PyObject implements Traverseproc { +public class PyStringMap extends AbstractDict implements Traverseproc { /** * TYPE computed lazily, PyStringMap is used early in the bootstrap process and @@ -410,6 +410,35 @@ } /** + * Merge another PyObject that supports keys() with this + * dict. + * + * @param other a PyObject with a keys() method + * @param override if true, the value from other is used on key-collision + */ + public void merge(PyObject other, boolean override) { + synchronized(table) { + if (override) { + merge(other); + } else { + if (other instanceof PyStringMap) { + Set> entrySet = + ((PyStringMap)other).table.entrySet(); + for (Map.Entry ent: entrySet) { + if (!table.containsKey(ent.getKey())) { + table.put(ent.getKey(), ent.getValue()); + } + } + } else if (other instanceof PyDictionary) { + mergeFromKeys(other, ((PyDictionary)other).keys(), override); + } else { + mergeFromKeys(other, other.invoke("keys"), override); + } + } + } + } + + /** * Merge another PyObject via its keys() method * * @param other a PyObject with a keys() method @@ -422,6 +451,27 @@ } /** + * Merge another PyObject via its keys() method + * + * @param other a PyObject with a keys() method + * @param keys the result of other's keys() method + * @param override if true, the value from other is used on key-collision + */ + public void mergeFromKeys(PyObject other, PyObject keys, boolean override) { + synchronized(table) { + if (override) { + mergeFromKeys(other, keys); + } else { + for (PyObject key : keys.asIterable()) { + if (!__contains__(key)) { + __setitem__(key, other.__getitem__(key)); + } + } + } + } + } + + /** * Merge any iterable object producing iterable objects of length * 2 into this dict. * @@ -451,6 +501,44 @@ } /** + * Merge any iterable object producing iterable objects of length + * 2 into this dict. + * + * @param other another PyObject + * @param override if true, the value from other is used on key-collision + */ + public void mergeFromSeq(PyObject other, boolean override) { + synchronized(table) { + if (override) { + mergeFromSeq(other); + } else { + PyObject pairs = other.__iter__(); + PyObject pair; + + for (int i = 0; (pair = pairs.__iternext__()) != null; i++) { + try { + pair = PySequence.fastSequence(pair, ""); + } catch(PyException pye) { + if (pye.match(Py.TypeError)) { + throw Py.TypeError(String.format("cannot convert dictionary update sequence " + + "element #%d to a sequence", i)); + } + throw pye; + } + int n; + if ((n = pair.__len__()) != 2) { + throw Py.ValueError(String.format("dictionary update sequence element #%d " + + "has length %d; 2 is required", i, n)); + } + if (!__contains__(pair.__getitem__(0))) { + __setitem__(pair.__getitem__(0), pair.__getitem__(1)); + } + } + } + } + } + + /** * Return this[key] if the key exist, otherwise insert key with a None value and return None. * * @param key -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Thu Oct 22 04:34:48 2015 From: jython-checkins at python.org (stefan.richthofer) Date: Thu, 22 Oct 2015 02:34:48 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Fixed_mro-issue_caused_by_l?= =?utf-8?q?ast_commit=2E_This_caused_e=2Eg=2E_test=5Fdescrtut_to_fail=2E?= Message-ID: <20151022023448.20759.85579@psf.io> https://hg.python.org/jython/rev/052ff7210e62 changeset: 7763:052ff7210e62 user: Stefan Richthofer date: Thu Oct 22 04:34:38 2015 +0200 summary: Fixed mro-issue caused by last commit. This caused e.g. test_descrtut to fail. files: src/org/python/core/PyDictionary.java | 2 +- src/org/python/core/PyDictionaryDerived.java | 3 ++- src/org/python/core/PyStringMap.java | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/org/python/core/PyDictionary.java b/src/org/python/core/PyDictionary.java --- a/src/org/python/core/PyDictionary.java +++ b/src/org/python/core/PyDictionary.java @@ -26,7 +26,7 @@ /** * A builtin python dictionary. */ - at ExposedType(name = "dict", doc = BuiltinDocs.dict_doc) + at ExposedType(name = "dict", base = PyObject.class, doc = BuiltinDocs.dict_doc) public class PyDictionary extends AbstractDict implements ConcurrentMap, Traverseproc { public static final PyType TYPE = PyType.fromClass(PyDictionary.class); diff --git a/src/org/python/core/PyDictionaryDerived.java b/src/org/python/core/PyDictionaryDerived.java --- a/src/org/python/core/PyDictionaryDerived.java +++ b/src/org/python/core/PyDictionaryDerived.java @@ -100,8 +100,9 @@ PyObject impl=self_type.lookup("__str__"); if (impl!=null) { PyObject res=impl.__get__(this,self_type).__call__(); - if (res instanceof PyString) + if (res instanceof PyString) { return(PyString)res; + } throw Py.TypeError("__str__"+" returned non-"+"string"+" (type "+res.getType().fastGetName()+")"); } return super.__str__(); diff --git a/src/org/python/core/PyStringMap.java b/src/org/python/core/PyStringMap.java --- a/src/org/python/core/PyStringMap.java +++ b/src/org/python/core/PyStringMap.java @@ -23,7 +23,7 @@ * Special fast dict implementation for __dict__ instances. Allows interned String keys in addition * to PyObject unlike PyDictionary. */ - at ExposedType(name = "stringmap", isBaseType = false) + at ExposedType(name = "stringmap", base = PyObject.class, isBaseType = false) public class PyStringMap extends AbstractDict implements Traverseproc { /** -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Tue Oct 27 00:55:56 2015 From: jython-checkins at python.org (jim.baker) Date: Tue, 27 Oct 2015 04:55:56 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_os=2Esystem_should_use_chan?= =?utf-8?q?ges_to_os=2Eenviron_in_subprocesses?= Message-ID: <20151027045556.32616.40016@psf.io> https://hg.python.org/jython/rev/cbdeff5f17f5 changeset: 7768:cbdeff5f17f5 user: Jim Baker date: Mon Oct 26 22:55:51 2015 -0600 summary: os.system should use changes to os.environ in subprocesses Fixes http://bugs.jython.org/issue2416 files: Lib/subprocess.py | 55 ++++++++++++++++------------- Lib/test/test_os_jy.py | 19 +++++++++- 2 files changed, 49 insertions(+), 25 deletions(-) diff --git a/Lib/subprocess.py b/Lib/subprocess.py --- a/Lib/subprocess.py +++ b/Lib/subprocess.py @@ -768,6 +768,31 @@ raise +if jython: + def _setup_env(env, builder_env): + """Carefully merge env with ProcessBuilder's only + overwriting key/values that differ + + System.getenv (Map) may be backed by + on UNIX platforms where these are really + bytes. ProcessBuilder's env inherits its contents and will + maintain those byte values (which may be butchered as + Strings) for the subprocess if they haven't been modified. + """ + # Determine what's safe to merge + merge_env = dict((key, value) for key, value in env.iteritems() + if key not in builder_env or + builder_env.get(key) != value) + + # Prune anything not in env + entries = builder_env.entrySet().iterator() + for entry in entries: + if entry.getKey() not in env: + entries.remove() + + builder_env.putAll(merge_env) + + class Popen(object): def __init__(self, args, bufsize=0, executable=None, stdin=None, stdout=None, stderr=None, @@ -1268,28 +1293,6 @@ return _CouplerThread(*args, **kwargs) - def _setup_env(self, env, builder_env): - """Carefully merge env with ProcessBuilder's only - overwriting key/values that differ - - System.getenv (Map) may be backed by - on UNIX platforms where these are really - bytes. ProcessBuilder's env inherits its contents and will - maintain those byte values (which may be butchered as - Strings) for the subprocess if they haven't been modified. - """ - # Determine what's safe to merge - merge_env = dict((key, value) for key, value in env.iteritems() - if key not in builder_env or - builder_env.get(key) != value) - - # Prune anything not in env - entries = builder_env.entrySet().iterator() - for entry in entries: - if entry.getKey() not in env: - entries.remove() - - builder_env.putAll(merge_env) def _execute_child(self, args, executable, preexec_fn, close_fds, @@ -1328,8 +1331,8 @@ builder.redirectError(java.lang.ProcessBuilder.Redirect.INHERIT) # os.environ may be inherited for compatibility with CPython - self._setup_env(dict(os.environ if env is None else env), - builder.environment()) + _setup_env(dict(os.environ if env is None else env), + builder.environment()) if cwd is None: cwd = os.getcwd() @@ -1888,11 +1891,15 @@ args = _escape_args(args) args = _shell_command + args cwd = os.getcwd() + + + builder = java.lang.ProcessBuilder(args) builder.directory(java.io.File(cwd)) builder.redirectInput(java.lang.ProcessBuilder.Redirect.INHERIT) builder.redirectOutput(java.lang.ProcessBuilder.Redirect.INHERIT) builder.redirectError(java.lang.ProcessBuilder.Redirect.INHERIT) + _setup_env(dict(os.environ), builder.environment()) try: return builder.start().waitFor() except (java.io.IOException, 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 @@ -359,7 +359,7 @@ # would fail with an import error due to creating a circular # import chain. This root cause is because the os module # imports the subprocess module for the system function; but - # the subprocess module imports from os. Verrifies that this + # the subprocess module imports from os. Verifies that this is # managed by making the import late; also verify the # monkeypatching optimization is successful by calling # os.system twice. @@ -371,6 +371,23 @@ .replace("\r", ""), # in case of running on Windows "42\n47\n") + def test_system_uses_os_environ(self): + """Writing to os.environ is made available as env vars in os.system subprocesses""" + # This test likely requires additional customization for + # environments like AS/400, but I do not have current access. + # Verifies fix for http://bugs.jython.org/issue2416 + if os._name == "nt": + echo_command = 'echo %TEST_ENVVAR%' + else: + echo_command = 'echo $TEST_ENVVAR' + with test_support.temp_cwd() as temp_cwd: + self.assertEqual( + subprocess.check_output( + [sys.executable, "-c", + "import os; os.environ['TEST_ENVVAR'] = 'works on 2.7.1+'; os.system('%s')" % echo_command])\ + .replace("\r", ""), # in case of running on Windows + "works on 2.7.1+\n") + @unittest.skipUnless(hasattr(os, 'link'), "os.link not available") class LinkTestCase(unittest.TestCase): -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Tue Oct 27 16:16:25 2015 From: jython-checkins at python.org (jim.baker) Date: Tue, 27 Oct 2015 20:16:25 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Remove_debugging_print_of_p?= =?utf-8?q?ath_to_CA_file?= Message-ID: <20151027201624.12551.91444@psf.io> https://hg.python.org/jython/rev/f18bea7d29dd changeset: 7769:f18bea7d29dd user: Jim Baker date: Tue Oct 27 14:14:50 2015 -0600 summary: Remove debugging print of path to CA file files: Lib/ssl.py | 1 - 1 files changed, 0 insertions(+), 1 deletions(-) diff --git a/Lib/ssl.py b/Lib/ssl.py --- a/Lib/ssl.py +++ b/Lib/ssl.py @@ -501,7 +501,6 @@ pass def load_verify_locations(self, cafile=None, capath=None, cadata=None): - print cafile if cafile is not None: with open(cafile) as f: self._load_certificates(f) -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Tue Oct 27 16:16:25 2015 From: jython-checkins at python.org (jim.baker) Date: Tue, 27 Oct 2015 20:16:25 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Upgrade_bundled_ensurepip_w?= =?utf-8?q?heels_for_pip=2C_setuptools_to_latest_upstream?= Message-ID: <20151027201625.10164.17831@psf.io> https://hg.python.org/jython/rev/b256a80cbbc5 changeset: 7770:b256a80cbbc5 user: Jim Baker date: Tue Oct 27 14:16:16 2015 -0600 summary: Upgrade bundled ensurepip wheels for pip, setuptools to latest upstream files: Lib/ensurepip/__init__.py | 4 ++-- Lib/ensurepip/_bundled/pip-1.6-py2.py3-none-any.whl | Bin Lib/ensurepip/_bundled/pip-7.1.2-py2.py3-none-any.whl | Bin Lib/ensurepip/_bundled/setuptools-14.3.2-py2.py3-none-any.whl | Bin Lib/ensurepip/_bundled/setuptools-18.4-py2.py3-none-any.whl | Bin NEWS | 7 +++++++ 6 files changed, 9 insertions(+), 2 deletions(-) diff --git a/Lib/ensurepip/__init__.py b/Lib/ensurepip/__init__.py --- a/Lib/ensurepip/__init__.py +++ b/Lib/ensurepip/__init__.py @@ -12,9 +12,9 @@ __all__ = ["version", "bootstrap"] -_SETUPTOOLS_VERSION = "14.3.2" +_SETUPTOOLS_VERSION = "18.4" -_PIP_VERSION = "1.6" +_PIP_VERSION = "7.1.2" # pip currently requires ssl support, so we try to provide a nicer # error message when that is missing (http://bugs.python.org/issue19744) diff --git a/Lib/ensurepip/_bundled/pip-1.6-py2.py3-none-any.whl b/Lib/ensurepip/_bundled/pip-1.6-py2.py3-none-any.whl deleted file mode 100644 index b5e29a60e34ef796748bf2c3179973235254e8c8..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 GIT binary patch [stripped] diff --git a/Lib/ensurepip/_bundled/pip-7.1.2-py2.py3-none-any.whl b/Lib/ensurepip/_bundled/pip-7.1.2-py2.py3-none-any.whl new file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..5e490155f0ca7f4ddb64c93c39fb2efb8795cd08 GIT binary patch [stripped] diff --git a/Lib/ensurepip/_bundled/setuptools-14.3.2-py2.py3-none-any.whl b/Lib/ensurepip/_bundled/setuptools-14.3.2-py2.py3-none-any.whl deleted file mode 100644 index f983456bab03556737d6e04ba0be960a18007641..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 GIT binary patch [stripped] diff --git a/Lib/ensurepip/_bundled/setuptools-18.4-py2.py3-none-any.whl b/Lib/ensurepip/_bundled/setuptools-18.4-py2.py3-none-any.whl new file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..9b94202d13594ef9b51815604bc4a37c3b64bd89 GIT binary patch [stripped] diff --git a/NEWS b/NEWS --- a/NEWS +++ b/NEWS @@ -2,6 +2,13 @@ For more details, please see https://hg.python.org/jython +Jython 2.7.1rc + Bugs fixed + - [ 2416 ] os.system does not use changes to os.environ in subprocesses + New Features + - Use latest upstream bundled wheels for ensurepip: pip (7.1.2), setuptools (18.4), + replacing wheels patched specifically for Jython + Jython 2.7.1b2 Bugs fixed - [ 2396 ] test_threading and others fail under Cygwin (sys.executable). -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Wed Oct 28 18:47:42 2015 From: jython-checkins at python.org (jim.baker) Date: Wed, 28 Oct 2015 22:47:42 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Support_UNC_paths_for_os=2E?= =?utf-8?q?utime=2E_Fixes_=232417=2E?= Message-ID: <20151028224736.494.89918@psf.io> https://hg.python.org/jython/rev/9427a38fa33d changeset: 7771:9427a38fa33d user: Jim Baker date: Wed Oct 28 16:47:30 2015 -0600 summary: Support UNC paths for os.utime. Fixes #2417. Use BasicFileAttributeView.setTimes (since Java 7) instead of posix.utime for implementing os.utime. As we have seen with other Posix functions that JNR Posix wraps, the wrapped utime function does not support UNC paths on Windows, but this equivalent Java functionality does. files: NEWS | 1 + src/org/python/modules/posix/PosixModule.java | 56 +++++---- 2 files changed, 32 insertions(+), 25 deletions(-) diff --git a/NEWS b/NEWS --- a/NEWS +++ b/NEWS @@ -4,6 +4,7 @@ Jython 2.7.1rc Bugs fixed + - [ 2417 ] os.utime fails on UNC network paths - [ 2416 ] os.system does not use changes to os.environ in subprocesses New Features - Use latest upstream bundled wheels for ensurepip: pip (7.1.2), setuptools (18.4), 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 @@ -13,18 +13,20 @@ import java.nio.channels.ClosedChannelException; import java.nio.channels.FileChannel; import java.nio.file.FileAlreadyExistsException; -import java.nio.file.FileSystems; import java.nio.file.Files; import java.nio.file.LinkOption; import java.nio.file.NotLinkException; import java.nio.file.NoSuchFileException; import java.nio.file.Path; import java.nio.file.Paths; +import java.nio.file.attribute.BasicFileAttributeView; import java.nio.file.attribute.BasicFileAttributes; import java.nio.file.attribute.DosFileAttributes; +import java.nio.file.attribute.FileTime; import java.security.SecureRandom; import java.util.Iterator; import java.util.Map; +import java.util.concurrent.TimeUnit; import jnr.constants.Constant; import jnr.constants.platform.Errno; @@ -973,41 +975,45 @@ "Set the access and modified time of the file to the given values. If the\n" + "second form is used, set the access and modified times to the current time."); public static void utime(PyObject path, PyObject times) { - long[] atimeval; - long[] mtimeval; + FileTime atime; + FileTime mtime; if (times == Py.None) { - atimeval = mtimeval = null; + // FIXME dynamically bind to java.time.Instant, available in Java 8, + // to potentially get higher resolution (nanosecond) time + atime = mtime = FileTime.from( + System.currentTimeMillis(), TimeUnit.MILLISECONDS); } else if (times instanceof PyTuple && times.__len__() == 2) { - atimeval = extractTimeval(times.__getitem__(0)); - mtimeval = extractTimeval(times.__getitem__(1)); + atime = getFileTime(times.__getitem__(0)); + mtime = getFileTime(times.__getitem__(1)); } else { throw Py.TypeError("utime() arg 2 must be a tuple (atime, mtime)"); } - if (posix.utimes(absolutePath(path).toString(), atimeval, mtimeval) < 0) { - throw errorFromErrno(path); + + try { + Files.getFileAttributeView(absolutePath(path), BasicFileAttributeView.class). + setTimes(mtime, atime, null); + } catch (NoSuchFileException ex) { + throw Py.OSError(Errno.ENOENT, path); + } catch (IOException ioe) { + throw Py.OSError(ioe); + } catch (SecurityException ex) { + throw Py.OSError(Errno.EACCES, path); } } - /** - * Convert seconds (with a possible fraction) from epoch to a 2 item array of seconds, - * microseconds from epoch as longs. - * - * @param seconds a PyObject number - * @return a 2 item long[] - */ - private static long[] extractTimeval(PyObject seconds) { - long[] timeval = new long[] {Platform.IS_32_BIT ? seconds.asInt() : seconds.asLong(), 0L}; - if (seconds instanceof PyFloat) { - // can't exceed 1000000 - long usec = (long)((seconds.asDouble() - timeval[0]) * 1e6); - if (usec < 0) { - // If rounding gave us a negative number, truncate - usec = 0; + private static FileTime getFileTime(PyObject seconds) { + try { + return FileTime.from( + (long) (seconds.__float__().asDouble() * 1e6), + TimeUnit.MICROSECONDS); + } catch (PyException pye) { + if (!pye.match(Py.AttributeError)) { + throw pye; + } else { + throw Py.TypeError("an integer or float is required"); } - timeval[1] = usec; } - return timeval; } public static PyString __doc__wait = new PyString( -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Wed Oct 28 20:14:15 2015 From: jython-checkins at python.org (darjus.loktevic) Date: Thu, 29 Oct 2015 00:14:15 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Update_ACKNOWLEDGMENTS?= Message-ID: <20151029000353.24887.71219@psf.io> https://hg.python.org/jython/rev/40eaac4c55de changeset: 7773:40eaac4c55de user: Darjus Loktevic date: Thu Oct 29 11:04:04 2015 +1100 summary: Update ACKNOWLEDGMENTS files: ACKNOWLEDGMENTS | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/ACKNOWLEDGMENTS b/ACKNOWLEDGMENTS --- a/ACKNOWLEDGMENTS +++ b/ACKNOWLEDGMENTS @@ -163,6 +163,7 @@ Daniel Martin Richard Fearn Adam Burke + Eric L Frederich Local Variables: mode: indented-text -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Wed Oct 28 20:14:15 2015 From: jython-checkins at python.org (darjus.loktevic) Date: Thu, 29 Oct 2015 00:14:15 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Coerce_anything_implementin?= =?utf-8?q?g_the_iteration_protocol_to_Java_arrays=3A?= Message-ID: <20151029000353.504.98049@psf.io> https://hg.python.org/jython/rev/359a0c95bc68 changeset: 7772:359a0c95bc68 user: Eric L Frederich date: Thu Oct 29 11:03:20 2015 +1100 summary: Coerce anything implementing the iteration protocol to Java arrays: https://github.com/jythontools/jython/pull/18 (committed by darjus@) files: Lib/test/test_coerce_jy.py | 30 ++++++++++++++++++ src/org/python/core/PyObject.java | 14 ++++++++ tests/java/javatests/Coercion.java | 6 +++ 3 files changed, 50 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_coerce_jy.py b/Lib/test/test_coerce_jy.py --- a/Lib/test/test_coerce_jy.py +++ b/Lib/test/test_coerce_jy.py @@ -4,6 +4,27 @@ """ import unittest from test import test_support +from javatests import Coercion +from collections import Sequence + +class MySeqClass1(Sequence): + def __init__(self, l): + self.l = l + def __getitem__(self, i): + return self.l[i] + def __len__(self): + return len(self.l) + +class MySeqClass2(object): + def __init__(self, l): + self.l = l + def __getitem__(self, i): + return self.l[i] + def __len__(self): + return len(self.l) + +class MySeqClass3(MySeqClass2): + pass class CoerceTestCase(unittest.TestCase): @@ -19,6 +40,15 @@ self.assertRaises(TypeError, float.__coerce__, None, 1) self.assertEqual(float.__coerce__(10.23, None), NotImplemented) + def test_sequence_coerce__(self): + l0 = ['a', 'b'] + l1 = MySeqClass1(['c', 'd']) + l2 = MySeqClass2(['e', 'f']) + l3 = MySeqClass3(['g', 'h']) + Coercion.string_array(l0) + Coercion.string_array(l1) + Coercion.string_array(l2) + Coercion.string_array(l3) def test_main(): test_support.run_unittest(CoerceTestCase) diff --git a/src/org/python/core/PyObject.java b/src/org/python/core/PyObject.java --- a/src/org/python/core/PyObject.java +++ b/src/org/python/core/PyObject.java @@ -364,6 +364,20 @@ } } } + if (c.isArray()) { + Class component = c.getComponentType(); + try { + int n = __len__(); + PyArray array = new PyArray(component, n); + for (int i = 0; i < n; i++) { + PyObject o = __getitem__(i); + array.set(i, o); + } + return array.getArray(); + } catch (Throwable t) { + // ok + } + } return Py.NoConversion; } diff --git a/tests/java/javatests/Coercion.java b/tests/java/javatests/Coercion.java new file mode 100644 --- /dev/null +++ b/tests/java/javatests/Coercion.java @@ -0,0 +1,6 @@ +package javatests; + +public class Coercion { + public static void string_array(String[] args) { + } +} -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Wed Oct 28 21:29:45 2015 From: jython-checkins at python.org (jim.baker) Date: Thu, 29 Oct 2015 01:29:45 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Correctly_set_startup_hook_?= =?utf-8?q?in_readline_module=2E_Fixes_=232338=2E?= Message-ID: <20151029012424.10178.73611@psf.io> https://hg.python.org/jython/rev/93c09145137e changeset: 7774:93c09145137e user: Jim Baker date: Wed Oct 28 19:24:17 2015 -0600 summary: Correctly set startup hook in readline module. Fixes #2338. files: Lib/readline.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/readline.py b/Lib/readline.py --- a/Lib/readline.py +++ b/Lib/readline.py @@ -95,7 +95,7 @@ _reader.redrawLine() def set_startup_hook(function=None): - _console.startup_hook = function + _console.startupHook = function def set_pre_input_hook(function=None): warn("set_pre_input_hook %s" % (function,), NotImplementedWarning, stacklevel=2) -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Fri Oct 30 17:07:20 2015 From: jython-checkins at python.org (jeff.allen) Date: Fri, 30 Oct 2015 21:07:20 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Add_skips_for_=232312_to_te?= =?utf-8?q?sts_and_other_tweaks_specific_to_Windows=2E?= Message-ID: <20151030210720.80228.91983@psf.io> https://hg.python.org/jython/rev/95e56da9e4d4 changeset: 7775:95e56da9e4d4 parent: 7761:9b3a8c5808a6 user: Jeff Allen date: Thu Oct 29 07:38:45 2015 +0000 summary: Add skips for #2312 to tests and other tweaks specific to Windows. This is part of a push to make regression tests run cleanly on Windows. The new test.test_support.is_jython_nt export makes it easier to express a Windows-specific skip in future. files: Lib/test/test_file2k.py | 3 ++- Lib/test/test_support.py | 15 ++++++++++----- Lib/test/test_sys.py | 4 +++- Lib/test/test_sys_jy.py | 7 ++++--- Lib/test/test_tarfile.py | 19 +++++++++++++++---- 5 files changed, 34 insertions(+), 14 deletions(-) diff --git a/Lib/test/test_file2k.py b/Lib/test/test_file2k.py --- a/Lib/test/test_file2k.py +++ b/Lib/test/test_file2k.py @@ -11,7 +11,7 @@ threading = None from test import test_support -from test.test_support import TESTFN, run_unittest +from test.test_support import TESTFN, run_unittest, is_jython, is_jython_nt from UserList import UserList class AutoFileTests(unittest.TestCase): @@ -711,6 +711,7 @@ finally: sys.stdout = save_stdout + @unittest.skipIf(is_jython_nt, "FIXME: utf-16 decode error, see issue 2312") def test_unicode(self): import subprocess 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 @@ -35,7 +35,8 @@ "verbose", "use_resources", "max_memuse", "record_original_stdout", "get_original_stdout", "unload", "unlink", "rmtree", "forget", "is_resource_enabled", "requires", "find_unused_port", "bind_port", - "fcmp", "have_unicode", "is_jython", "TESTFN", "HOST", "FUZZ", + "fcmp", "have_unicode", "is_jython", "is_jython_nt", + "TESTFN", "HOST", "FUZZ", "SAVEDCWD", "temp_cwd", "findfile", "sortdict", "check_syntax_error", "open_urlresource", "check_warnings", "check_py3k_warnings", "CleanImport", "EnvironmentVarGuard", "captured_output", @@ -47,6 +48,11 @@ "import_fresh_module", "threading_cleanup", "reap_children", "strip_python_stderr"] + +# We use these extensively in adapting the regression tests for Jython +is_jython = sys.platform.startswith('java') +is_jython_nt = is_jython and (os._name == 'nt') + class Error(Exception): """Base class for regression test exceptions.""" @@ -188,7 +194,7 @@ except KeyError: pass -if sys.platform.startswith("win") or (os.name == "java" and os._name == "nt"): +if sys.platform.startswith("win") or is_jython_nt: def _waitfor(func, pathname, waitall=False): # Peform the operation func(pathname) @@ -426,14 +432,13 @@ except NameError: have_unicode = False -is_jython = sys.platform.startswith('java') if is_jython: def make_jar_classloader(jar): import os from java.net import URL, URLClassLoader url = URL('jar:file:%s!/' % jar) - if os._name == 'nt': + if is_jython_nt: # URLJarFiles keep a cached open file handle to the jar even # after this ClassLoader is GC'ed, disallowing Windows tests # from removing the jar file from disk when finished with it @@ -447,7 +452,7 @@ return URLClassLoader([url]) # Filename used for testing -if os.name == 'java': +if is_jython: # Jython disallows @ in module names TESTFN = '$test' elif os.name == 'riscos': diff --git a/Lib/test/test_sys.py b/Lib/test/test_sys.py --- a/Lib/test/test_sys.py +++ b/Lib/test/test_sys.py @@ -251,12 +251,14 @@ self.assert_(vi[3] in ("alpha", "beta", "candidate", "final")) self.assert_(isinstance(vi[4], int)) + @unittest.skipIf(test.test_support.is_jython_nt, + "FIXME: fails probably due to issue 2312") def test_ioencoding(self): # from v2.7 test import subprocess,os env = dict(os.environ) # Test character: cent sign, encoded as 0x4A (ASCII J) in CP424, - # not representable in ASCII. + # not representable in ASCII, Unicode U+00a2. env["PYTHONIOENCODING"] = "cp424" p = subprocess.Popen([sys.executable, "-c", 'print unichr(0xa2)'], diff --git a/Lib/test/test_sys_jy.py b/Lib/test/test_sys_jy.py --- a/Lib/test/test_sys_jy.py +++ b/Lib/test/test_sys_jy.py @@ -7,6 +7,7 @@ import tempfile import unittest from test import test_support +from test.test_support import is_jython, is_jython_nt class SysTest(unittest.TestCase): @@ -22,7 +23,7 @@ self.assertEquals(str(e), "leaving now") def test_tuple_args(self): - "Exceptions raised unpacking tuple args have right line number" + # Exceptions raised unpacking tuple args have right line number def tuple_args( (x,y) ): pass try: tuple_args( 10 ) @@ -193,6 +194,7 @@ # Adapted from CPython 2.7 test_sys to exercise setting Jython registry # values related to encoding and error policy. + @unittest.skipIf(is_jython_nt, "FIXME: fails probably due to issue 2312") def test_ioencoding(self): # adapted from CPython v2.7 test_sys import subprocess, os env = dict(os.environ) @@ -243,9 +245,8 @@ class SysArgvTest(unittest.TestCase): - @unittest.skipIf(os._name == "nt", "FIXME should work on Windows") def test_unicode_argv(self): - """Unicode roundtrips successfully through sys.argv arguments""" + # Unicode roundtrips successfully through sys.argv arguments zhongwen = u'\u4e2d\u6587' with test_support.temp_cwd(name=u"tempcwd-%s" % zhongwen): p = subprocess.Popen( diff --git a/Lib/test/test_tarfile.py b/Lib/test/test_tarfile.py --- a/Lib/test/test_tarfile.py +++ b/Lib/test/test_tarfile.py @@ -6,11 +6,13 @@ import StringIO from hashlib import md5 import errno +import warnings import unittest import tarfile from test import test_support +from test.test_support import is_jython, is_jython_nt # Check for our compression modules. try: @@ -295,6 +297,7 @@ self.assertTrue(self.tar.getmembers()[-1].name == "misc/eof", "could not find all members") + @unittest.skipIf(is_jython_nt, "FIXME: fails trying to unlink() open file") def test_extract_hardlink(self): # Test hardlink extraction (e.g. bug #857297). with tarfile.open(tarname, errorlevel=1, encoding="iso8859-1") as tar: @@ -321,12 +324,13 @@ tar.extractall(TEMPDIR, directories) for tarinfo in directories: path = os.path.join(TEMPDIR, tarinfo.name) - if sys.platform != "win32": + if sys.platform != "win32" and not is_jython_nt: # Win32 has no support for fine grained permissions. self.assertEqual(tarinfo.mode & 0777, os.stat(path).st_mode & 0777) self.assertEqual(tarinfo.mtime, os.path.getmtime(path)) tar.close() + @unittest.skipIf(is_jython_nt, "FIXME: fails trying to unlink() open file") def test_init_close_fobj(self): # Issue #7341: Close the internal file object in the TarFile # constructor in case of an error. For the test we rely on @@ -834,7 +838,7 @@ self._test_pathname("foo" + os.sep + os.sep, "foo", dir=True) def test_abs_pathnames(self): - if sys.platform == "win32": + if sys.platform == "win32" or is_jython_nt: self._test_pathname("C:\\foo", "foo") else: self._test_pathname("/foo", "foo") @@ -974,10 +978,11 @@ self.assertTrue(data.count("\0") == tarfile.RECORDSIZE, "incorrect zero padding") + @unittest.skipIf(is_jython_nt, "requires posix-like os.umask()") def test_file_mode(self): # Test for issue #8464: Create files with correct # permissions. - if sys.platform == "win32" or not hasattr(os, "umask"): + if sys.platform == "win32" or is_jython_nt or not hasattr(os, "umask"): return if os.path.exists(tmpname): @@ -1590,6 +1595,8 @@ def test_main(): + if os.path.exists(TEMPDIR): + shutil.rmtree(TEMPDIR) os.makedirs(TEMPDIR) tests = [ @@ -1654,7 +1661,11 @@ test_support.run_unittest(*tests) finally: if os.path.exists(TEMPDIR): - shutil.rmtree(TEMPDIR) + try: + shutil.rmtree(TEMPDIR) + except OSError: + warnings.warn("Failed to remove "+TEMPDIR) + if __name__ == "__main__": test_main() -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Fri Oct 30 17:07:21 2015 From: jython-checkins at python.org (jeff.allen) Date: Fri, 30 Oct 2015 21:07:21 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Whitespace-only_changes_to_?= =?utf-8?q?build=2Exml_=28readability=29=2E?= Message-ID: <20151030210721.10178.54445@psf.io> https://hg.python.org/jython/rev/c5de2777ba74 changeset: 7776:c5de2777ba74 user: Jeff Allen date: Thu Oct 29 11:17:25 2015 +0000 summary: Whitespace-only changes to build.xml (readability). files: build.xml | 126 +++++++++++++++++++++++------------------ 1 files changed, 71 insertions(+), 55 deletions(-) diff --git a/build.xml b/build.xml --- a/build.xml +++ b/build.xml @@ -44,7 +44,7 @@ --------------------- See http://wiki.python.org/jython/JythonDeveloperGuide/HowToReleaseJython - + An example ant.properties file: ------------------------------- @@ -222,18 +222,20 @@ - + + + . Build environment for ${ant.project.name} @@ -306,7 +308,6 @@ - @@ -321,7 +322,7 @@ the tokens defined in Python.g (and cleans make the build slow) --> - + @@ -420,7 +421,7 @@ This is a snapshot build. It reflects the current development status. - + The readme text for the next release will be like: @@ -443,8 +444,7 @@ - + @@ -460,7 +460,7 @@ - + - - - + + + @@ -665,7 +665,7 @@ - + @@ -713,7 +713,7 @@ copy installer classes to ${dist.dir} - - + + @@ -913,8 +913,11 @@ - - + + + @@ -925,13 +928,16 @@ + + + @@ -952,6 +958,7 @@ + @@ -969,6 +976,7 @@ + @@ -990,6 +998,7 @@ + @@ -1013,40 +1022,46 @@ + + - + + + - - - - - - - - - - + + + + + + + + + + + - - - - - - - - - + + + + + + + + + @@ -1061,29 +1076,30 @@ - + - - + + - + creating ${bugtests.dir}/support_config.py -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Fri Oct 30 17:07:21 2015 From: jython-checkins at python.org (jeff.allen) Date: Fri, 30 Oct 2015 21:07:21 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Add_regrtest-file_target_to?= =?utf-8?q?_ant_build=2E?= Message-ID: <20151030210721.80222.73069@psf.io> https://hg.python.org/jython/rev/6e10b3ad1316 changeset: 7777:6e10b3ad1316 user: Jeff Allen date: Thu Oct 29 14:56:46 2015 +0000 summary: Add regrtest-file target to ant build. Target regrtest-file is like regrtest but reads the list of tests from a file with fixed name "regr.tests". The motivation is to explore why test results differ between ant regrtest and the prompt. Some bugs in regrtest.py argument processing are fixed. files: Lib/test/regrtest.py | 4 +- build.xml | 37 +++++++++++++++++++++++++++++-- 2 files changed, 36 insertions(+), 5 deletions(-) diff --git a/Lib/test/regrtest.py b/Lib/test/regrtest.py --- a/Lib/test/regrtest.py +++ b/Lib/test/regrtest.py @@ -217,11 +217,11 @@ try: opts, args = getopt.getopt(sys.argv[1:], 'hvqxsSrf:lu:t:TD:NLR:wM:em:j:', ['help', 'verbose', 'quiet', 'exclude', - 'single', 'slow', 'random', 'fromfile', + 'single', 'slow', 'random', 'fromfile=', 'findleaks', 'use=', 'threshold=', 'trace', 'coverdir=', 'nocoverdir', 'runleaks', 'huntrleaks=', 'verbose2', 'memlimit=', - 'expected', 'memo' + 'expected', 'memo=', 'junit-xml=' ]) except getopt.error, msg: usage(2, msg) diff --git a/build.xml b/build.xml --- a/build.xml +++ b/build.xml @@ -137,7 +137,6 @@ - @@ -469,9 +468,8 @@ --> + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Fri Oct 30 17:07:21 2015 From: jython-checkins at python.org (jeff.allen) Date: Fri, 30 Oct 2015 21:07:21 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Work_around_absence_of_real?= =?utf-8?q?_fileno=28=29_on_Windows_in_simpleHTTPServer=2E?= Message-ID: <20151030210721.21935.6136@psf.io> https://hg.python.org/jython/rev/ff10e4d0f1c8 changeset: 7778:ff10e4d0f1c8 user: Jeff Allen date: Thu Oct 29 16:18:04 2015 +0000 summary: Work around absence of real fileno() on Windows in simpleHTTPServer. files: Lib/SimpleHTTPServer.py | 6 +++++- 1 files changed, 5 insertions(+), 1 deletions(-) diff --git a/Lib/SimpleHTTPServer.py b/Lib/SimpleHTTPServer.py --- a/Lib/SimpleHTTPServer.py +++ b/Lib/SimpleHTTPServer.py @@ -90,7 +90,11 @@ return None self.send_response(200) self.send_header("Content-type", ctype) - fs = os.fstat(f.fileno()) if hasattr(os, 'fstat') else os.stat(path) + try: + fs = os.fstat(f.fileno()) + except OSError, AttributeError: + # Jython on Windows lands here when f.fileno() is invalid + fs = os.stat(path) self.send_header("Content-Length", str(fs[6])) self.send_header("Last-Modified", self.date_time_string(fs.st_mtime)) self.end_headers() -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Fri Oct 30 17:07:21 2015 From: jython-checkins at python.org (jeff.allen) Date: Fri, 30 Oct 2015 21:07:21 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Skip_failing_cases_in_test?= =?utf-8?q?=5Fchdir_=28Windows=29=2C_=232418_refers=2E?= Message-ID: <20151030210721.59807.45234@psf.io> https://hg.python.org/jython/rev/dde11c9199be changeset: 7779:dde11c9199be user: Jeff Allen date: Thu Oct 29 17:07:18 2015 +0000 summary: Skip failing cases in test_chdir (Windows), #2418 refers. files: Lib/test/test_chdir.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_chdir.py b/Lib/test/test_chdir.py --- a/Lib/test/test_chdir.py +++ b/Lib/test/test_chdir.py @@ -405,7 +405,7 @@ mod = sys.modules[mod_name] self.assertEqual(mod.__file__, mod_name + COMPILED_SUFFIX) - + at unittest.skipIf(test_support.is_jython_nt, "FIXME: failing on Windows: issue 2418") class SubprocessTestCase(BaseChdirTestCase): TEST_DIRS = 2 -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Fri Oct 30 17:07:22 2015 From: jython-checkins at python.org (jeff.allen) Date: Fri, 30 Oct 2015 21:07:22 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Permit_trailing_comments_in?= =?utf-8?q?_files_that_drive_regrtest_-f_=2E?= Message-ID: <20151030210722.24895.51755@psf.io> https://hg.python.org/jython/rev/790b41a2de56 changeset: 7781:790b41a2de56 user: Jeff Allen date: Thu Oct 29 21:58:43 2015 +0000 summary: Permit trailing comments in files that drive regrtest -f . This means a file can be created by dropping in lists from regrtest, where it is useful to annotate with issue numbers, etc.. files: Lib/test/regrtest.py | 19 +++++++++---------- 1 files changed, 9 insertions(+), 10 deletions(-) diff --git a/Lib/test/regrtest.py b/Lib/test/regrtest.py --- a/Lib/test/regrtest.py +++ b/Lib/test/regrtest.py @@ -347,9 +347,9 @@ tests = [] fp = open(fromfile) for line in fp: - guts = line.split() # assuming no test has whitespace in its name - if guts and not guts[0].startswith('#'): - tests.extend(guts) + # Potentially multiple names and a comment on one line of the file + trunc_line = line.split('#', 1)[0] + tests.extend(trunc_line.split()) fp.close() # Strip .py extensions. @@ -500,7 +500,7 @@ os.system("leaks %d" % os.getpid()) if memo: - savememo(memo,good,failures,bad,skips,skipped,allran,resource_denieds) + savememo(memo, good, failures, bad, skips, skipped, allran, resource_denieds) sys.exit(surprises > 0) @@ -1409,9 +1409,8 @@ for test_module in conditional_support: _expectations[_platform] += \ - skip_conditional_support(test_module,conditional_support[test_module]) + skip_conditional_support(test_module, conditional_support[test_module]) - class _ExpectedSkips: def __init__(self): @@ -1525,18 +1524,18 @@ self.expected = set(self.split_commented(s)) self.valid = True -def savememo(memo,good,failures,bad,skips,skipped,allran, resource_denieds): +def savememo(memo, good, failures, bad, skips, skipped, allran, resource_denieds): f = open(memo,'w') try: - for n,l in [('good',good),('bad',bad),('skipped',skipped)]: + for n,l in [('good',good), ('bad',bad), ('skipped',skipped)]: print >>f,"%s = [" % n for x in l: print >>f," %r," % x print >>f," ]" print >>f, count(len(skipped), "test"), "skipped:" - countsurprises(skips, skipped, 'skip', 'ran', allran, resource_denieds,f) + countsurprises(skips, skipped, 'skip', 'ran', allran, resource_denieds, f) print >>f, count(len(bad), "test"), "failed:" - countsurprises(failures, bad, 'fail', 'passed', allran, resource_denieds,f) + countsurprises(failures, bad, 'fail', 'passed', allran, resource_denieds, f) import platform print >>f, "Platform: " print >>f, " %r" % platform.platform() -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Fri Oct 30 17:07:22 2015 From: jython-checkins at python.org (jeff.allen) Date: Fri, 30 Oct 2015 21:07:22 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Suppress_failing_tests_in_r?= =?utf-8?q?egrtest_for_clean_run_on_Windows=2C_see_=232393=2E?= Message-ID: <20151030210722.80210.31732@psf.io> https://hg.python.org/jython/rev/1ca0ceed8789 changeset: 7780:1ca0ceed8789 user: Adam Burke date: Thu Oct 29 21:24:26 2015 +0000 summary: Suppress failing tests in regrtest for clean run on Windows, see #2393. Somewhat radical start. We should challenge these lists and look for more specific ways to omit the failing parts of tests instead and open issues where needed. (Committed by Jeff.) files: Lib/test/regrtest.py | 47 ++++++++++++++++++++++++++----- 1 files changed, 39 insertions(+), 8 deletions(-) diff --git a/Lib/test/regrtest.py b/Lib/test/regrtest.py --- a/Lib/test/regrtest.py +++ b/Lib/test/regrtest.py @@ -1204,7 +1204,8 @@ """, 'java': """ - # Not supportable on Java, or at least requires additional emulation in Jython + # Not supportable on Java, or at least requires additional emulation + # in Jython test__locale test__rawffi test_aepack @@ -1222,8 +1223,12 @@ test_closuregen test_ctypes test_dl + test_dummy_threading # skip unexpected; cannot import _newFunctionThread test_fcntl test_fork1 + # Rare failures depending on timing of Java gc + # If frequency increases should exclude + fix + reinclude + # test_gc test_gdb test_gdbm test_getargs2 @@ -1269,6 +1274,9 @@ test_winsound test_zipfile64 + # Not yet Jython 3.x + test_lib2to3 + # Could rewrite these tests test_descr test_epoll @@ -1289,11 +1297,25 @@ # Requires Python bytecode compilation support test_longexp + # No module named _multibytecodec + test_multibytecodec + + # No module named _testcapi + test_ucn + + # Requires servlet + test___all__ + # Nonreliable tests test_asynchat test_asyncore + test_logging + test_select test_select_new + # Rare failures observed on timing tests but often passes + test_threading + # Command line testing is hard for Jython to do, but revisit test_cmd_line_script @@ -1308,8 +1330,6 @@ test_sys_setprofile # revisit for GC test_sys_settrace # revisit for line jumping - # Not yet Jython 3.x - test_lib2to3 """ } _expectations['freebsd5'] = _expectations['freebsd4'] @@ -1333,21 +1353,32 @@ test_codecmaps_tw test_compiler test_dis - test_dummy_threading test_eof test_frozen # not meaningful for Jython, although it is similar to Clamp singlejar - test_gc # test_gc_jy replaces this test_iterlen - test_multibytecodec - test_multibytecodec_support test_peepholer test_pyclbr test_pyexpat test_stringprep test_threadsignals test_transformer - test_ucn test_zipimport + # fails on Windows standalone, probably shouldn't + test_file2k + test_httpservers + test_netrc + test_runpy + test_shutil # Operation not permitted errors + test_socket + test_sys + test_tarfile + test_urllib2 + test_zipfile + # fails on Windows standalone too, but more embarassing as java specific + test_os_jy + test_subprocess_jy + # passes standalone on Windows but fails in full regrtest + test_sys_jy """, } -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Fri Oct 30 17:07:27 2015 From: jython-checkins at python.org (jeff.allen) Date: Fri, 30 Oct 2015 21:07:27 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Protect_test=5Fglob_from_oc?= =?utf-8?q?casional_failure_on_Windows=2E?= Message-ID: <20151030210727.10176.41110@psf.io> https://hg.python.org/jython/rev/60c5479cd11f changeset: 7783:60c5479cd11f user: Jeff Allen date: Fri Oct 30 19:59:32 2015 +0000 summary: Protect test_glob from occasional failure on Windows. Another unlink() that occasionally fails. files: Lib/test/test_glob.py | 6 +++++- 1 files changed, 5 insertions(+), 1 deletions(-) diff --git a/Lib/test/test_glob.py b/Lib/test/test_glob.py --- a/Lib/test/test_glob.py +++ b/Lib/test/test_glob.py @@ -3,6 +3,7 @@ import shutil import sys import unittest +import warnings from test.test_support import run_unittest, TESTFN @@ -40,7 +41,10 @@ os.symlink(os.path.join('a', 'bcd'), self.norm('sym3')) def tearDown(self): - shutil.rmtree(self.tempdir) + try: + shutil.rmtree(self.tempdir) + except OSError: + warnings.warn("Failed to remove " + self.tempdir) def glob(self, *parts): if len(parts) == 1: -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Fri Oct 30 17:07:27 2015 From: jython-checkins at python.org (jeff.allen) Date: Fri, 30 Oct 2015 21:07:27 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Triage_of_regrtest=2Epy_exp?= =?utf-8?q?ected_skips_and_failures=2E?= Message-ID: <20151030210727.21931.67734@psf.io> https://hg.python.org/jython/rev/f5a185277bc4 changeset: 7782:f5a185277bc4 user: Jeff Allen date: Fri Oct 30 17:40:52 2015 +0000 summary: Triage of regrtest.py expected skips and failures. This is a spin-off from work on #2393, carefully distinguishing test skips (the _expectations variable) from _failures, according to experience with them on Windows 7x64 and Java 7 (1.7.0_60). YMMV. The intention is that failures be tracked as issues. Skips *may* be issues too. Also, that failures affecting a small proportion of a module be replaced by test_support.skipIf() decorators at module level. files: Lib/test/regrtest.py | 131 +++++++++++++----------------- 1 files changed, 55 insertions(+), 76 deletions(-) diff --git a/Lib/test/regrtest.py b/Lib/test/regrtest.py --- a/Lib/test/regrtest.py +++ b/Lib/test/regrtest.py @@ -1204,8 +1204,7 @@ """, 'java': """ - # Not supportable on Java, or at least requires additional emulation - # in Jython + # These always skip (e.g. fail to import a certain module). test__locale test__rawffi test_aepack @@ -1220,15 +1219,12 @@ test_capi test_cd test_cl - test_closuregen - test_ctypes + test_closuregen # cannot import name verify + test_ctypes # cannot import name verify test_dl - test_dummy_threading # skip unexpected; cannot import _newFunctionThread + test_dummy_threading # cannot import _newFunctionThread test_fcntl test_fork1 - # Rare failures depending on timing of Java gc - # If frequency increases should exclude + fix + reinclude - # test_gc test_gdb test_gdbm test_getargs2 @@ -1238,7 +1234,6 @@ test_imgfile test_ioctl test_kqueue - test_largefile test_linuxaudiodev test_macfs test_macostools @@ -1250,7 +1245,6 @@ test_openpty test_ossaudiodev test_parser - test_plistlib test_pty test_resource test_rgbimg @@ -1259,77 +1253,37 @@ test_strop test_structmembers test_sunaudiodev - test_sundry test_symtable test_tcl test_tk test_tools test_ttk_guionly test_ttk_textonly - test_unicode_file - test_wait3 - test_wait4 + test_unicode_file # cannot import name TESTFN_UNICODE + test_wait3 # os.fork not defined + test_wait4 # os.fork not defined test_wave test_winreg test_winsound - test_zipfile64 + test_zipfile64 # requires bogus resource "extralargefile" # Not yet Jython 3.x test_lib2to3 # Could rewrite these tests - test_descr - test_epoll - test_poll - test_profile - test_struct + test_descr # cannot import name verify + test_epoll # test works only on Linux 2.6 + test_poll # cannot import name TestSkipped + test_struct # cannot import name verify - # The following tests cause issues for tests that are subsequently run - test_distutils - test_email_codecs - test_io test_locale # Should fix these tests so they are not hardcoded for CPython pyc files test_compileall - test_pydoc + test_longexp # Requires Python bytecode compilation support - # Requires Python bytecode compilation support - test_longexp - - # No module named _multibytecodec - test_multibytecodec - - # No module named _testcapi - test_ucn - - # Requires servlet - test___all__ - - # Nonreliable tests - test_asynchat - test_asyncore - test_logging - test_select - test_select_new - - # Rare failures observed on timing tests but often passes - test_threading - - # Command line testing is hard for Jython to do, but revisit - test_cmd_line_script - - # Tests that should work with socket-reboot, but currently hang - test_ftplib - test_httplib - test_poplib - test_smtplib - test_socket_ssl - test_telnetlib - - test_sys_setprofile # revisit for GC - test_sys_settrace # revisit for line jumping - + test_multibytecodec # No module named _multibytecodec + test_ucn # No module named _testcapi """ } _expectations['freebsd5'] = _expectations['freebsd4'] @@ -1345,9 +1299,7 @@ test_codecencodings_iso2022 test_codecencodings_jp test_codecencodings_kr - test_codecencodings_tw test_codecmaps_cn - test_codecmaps_hk test_codecmaps_jp test_codecmaps_kr test_codecmaps_tw @@ -1359,26 +1311,53 @@ test_peepholer test_pyclbr test_pyexpat - test_stringprep + test_stringprep # UnicodeDecodeError test_threadsignals test_transformer test_zipimport + # fails on Windows standalone, probably shouldn't - test_file2k - test_httpservers - test_netrc - test_runpy - test_shutil # Operation not permitted errors - test_socket - test_sys - test_tarfile - test_urllib2 + test_netrc # KeyError: 'foo.domain.com' + test_runpy # OSError: unlink() + test_shutil # Operation not permitted errors + test_urllib2 # file not on local host (likely Windows only) test_zipfile + # fails on Windows standalone too, but more embarassing as java specific - test_os_jy + test_os_jy # Locale tests run and fail on Cygwin test_subprocess_jy - # passes standalone on Windows but fails in full regrtest - test_sys_jy + test_sys_jy # OSError handling wide-character filename + + test_asyncore + test_compileall + test_distutils + test_email_codecs + test_largefile # [Errno 9] Bad file descriptor + test_locale + test_profile + test_pydoc # Hangs with prompt (Windows) + test_select # Unconnected client socket should be selectable + test_sundry # ImportError: No module named audiodev + + test_sys_setprofile # revisit for GC + test_sys_settrace # revisit for line jumping + + # Unreliable tests + test_asynchat + test_gc # Rare failures depending on timing of Java gc + test_logging + test_select_new + test_socket # flakey (Windows) + test_tarfile # flakey (Windows) + test_threading + test_urllib2net # unexpected output makes this a failure to regrtest.py + + # Tests that should work with socket-reboot, but currently fail/hang + test_ftplib # NoSuchElementException ssl + test_httplib + test_poplib # 'NoneType' is not iterable + test_smtplib + """, } -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Fri Oct 30 17:07:27 2015 From: jython-checkins at python.org (jeff.allen) Date: Fri, 30 Oct 2015 21:07:27 +0000 Subject: [Jython-checkins] =?utf-8?q?jython_=28merge_default_-=3E_default?= =?utf-8?q?=29=3A_Merge_recent_regression_test_clean-up_to_trunk?= Message-ID: <20151030210727.10168.98958@psf.io> https://hg.python.org/jython/rev/e1455ac5ec63 changeset: 7784:e1455ac5ec63 parent: 7774:93c09145137e parent: 7783:60c5479cd11f user: Jeff Allen date: Fri Oct 30 21:00:04 2015 +0000 summary: Merge recent regression test clean-up to trunk files: Lib/SimpleHTTPServer.py | 6 +- Lib/test/regrtest.py | 137 ++++++++++++---------- Lib/test/test_chdir.py | 2 +- Lib/test/test_file2k.py | 3 +- Lib/test/test_glob.py | 6 +- Lib/test/test_support.py | 15 +- Lib/test/test_sys.py | 4 +- Lib/test/test_sys_jy.py | 7 +- Lib/test/test_tarfile.py | 19 ++- build.xml | 163 +++++++++++++++++--------- 10 files changed, 223 insertions(+), 139 deletions(-) diff --git a/Lib/SimpleHTTPServer.py b/Lib/SimpleHTTPServer.py --- a/Lib/SimpleHTTPServer.py +++ b/Lib/SimpleHTTPServer.py @@ -90,7 +90,11 @@ return None self.send_response(200) self.send_header("Content-type", ctype) - fs = os.fstat(f.fileno()) if hasattr(os, 'fstat') else os.stat(path) + try: + fs = os.fstat(f.fileno()) + except OSError, AttributeError: + # Jython on Windows lands here when f.fileno() is invalid + fs = os.stat(path) self.send_header("Content-Length", str(fs[6])) self.send_header("Last-Modified", self.date_time_string(fs.st_mtime)) self.end_headers() diff --git a/Lib/test/regrtest.py b/Lib/test/regrtest.py --- a/Lib/test/regrtest.py +++ b/Lib/test/regrtest.py @@ -217,11 +217,11 @@ try: opts, args = getopt.getopt(sys.argv[1:], 'hvqxsSrf:lu:t:TD:NLR:wM:em:j:', ['help', 'verbose', 'quiet', 'exclude', - 'single', 'slow', 'random', 'fromfile', + 'single', 'slow', 'random', 'fromfile=', 'findleaks', 'use=', 'threshold=', 'trace', 'coverdir=', 'nocoverdir', 'runleaks', 'huntrleaks=', 'verbose2', 'memlimit=', - 'expected', 'memo' + 'expected', 'memo=', 'junit-xml=' ]) except getopt.error, msg: usage(2, msg) @@ -347,9 +347,9 @@ tests = [] fp = open(fromfile) for line in fp: - guts = line.split() # assuming no test has whitespace in its name - if guts and not guts[0].startswith('#'): - tests.extend(guts) + # Potentially multiple names and a comment on one line of the file + trunc_line = line.split('#', 1)[0] + tests.extend(trunc_line.split()) fp.close() # Strip .py extensions. @@ -500,7 +500,7 @@ os.system("leaks %d" % os.getpid()) if memo: - savememo(memo,good,failures,bad,skips,skipped,allran,resource_denieds) + savememo(memo, good, failures, bad, skips, skipped, allran, resource_denieds) sys.exit(surprises > 0) @@ -1204,7 +1204,7 @@ """, 'java': """ - # Not supportable on Java, or at least requires additional emulation in Jython + # These always skip (e.g. fail to import a certain module). test__locale test__rawffi test_aepack @@ -1219,9 +1219,10 @@ test_capi test_cd test_cl - test_closuregen - test_ctypes + test_closuregen # cannot import name verify + test_ctypes # cannot import name verify test_dl + test_dummy_threading # cannot import _newFunctionThread test_fcntl test_fork1 test_gdb @@ -1233,7 +1234,6 @@ test_imgfile test_ioctl test_kqueue - test_largefile test_linuxaudiodev test_macfs test_macostools @@ -1245,7 +1245,6 @@ test_openpty test_ossaudiodev test_parser - test_plistlib test_pty test_resource test_rgbimg @@ -1254,62 +1253,37 @@ test_strop test_structmembers test_sunaudiodev - test_sundry test_symtable test_tcl test_tk test_tools test_ttk_guionly test_ttk_textonly - test_unicode_file - test_wait3 - test_wait4 + test_unicode_file # cannot import name TESTFN_UNICODE + test_wait3 # os.fork not defined + test_wait4 # os.fork not defined test_wave test_winreg test_winsound - test_zipfile64 + test_zipfile64 # requires bogus resource "extralargefile" + + # Not yet Jython 3.x + test_lib2to3 # Could rewrite these tests - test_descr - test_epoll - test_poll - test_profile - test_struct + test_descr # cannot import name verify + test_epoll # test works only on Linux 2.6 + test_poll # cannot import name TestSkipped + test_struct # cannot import name verify - # The following tests cause issues for tests that are subsequently run - test_distutils - test_email_codecs - test_io test_locale # Should fix these tests so they are not hardcoded for CPython pyc files test_compileall - test_pydoc + test_longexp # Requires Python bytecode compilation support - # Requires Python bytecode compilation support - test_longexp - - # Nonreliable tests - test_asynchat - test_asyncore - test_select_new - - # Command line testing is hard for Jython to do, but revisit - test_cmd_line_script - - # Tests that should work with socket-reboot, but currently hang - test_ftplib - test_httplib - test_poplib - test_smtplib - test_socket_ssl - test_telnetlib - - test_sys_setprofile # revisit for GC - test_sys_settrace # revisit for line jumping - - # Not yet Jython 3.x - test_lib2to3 + test_multibytecodec # No module named _multibytecodec + test_ucn # No module named _testcapi """ } _expectations['freebsd5'] = _expectations['freebsd4'] @@ -1325,29 +1299,65 @@ test_codecencodings_iso2022 test_codecencodings_jp test_codecencodings_kr - test_codecencodings_tw test_codecmaps_cn - test_codecmaps_hk test_codecmaps_jp test_codecmaps_kr test_codecmaps_tw test_compiler test_dis - test_dummy_threading test_eof test_frozen # not meaningful for Jython, although it is similar to Clamp singlejar - test_gc # test_gc_jy replaces this test_iterlen - test_multibytecodec - test_multibytecodec_support test_peepholer test_pyclbr test_pyexpat - test_stringprep + test_stringprep # UnicodeDecodeError test_threadsignals test_transformer - test_ucn test_zipimport + + # fails on Windows standalone, probably shouldn't + test_netrc # KeyError: 'foo.domain.com' + test_runpy # OSError: unlink() + test_shutil # Operation not permitted errors + test_urllib2 # file not on local host (likely Windows only) + test_zipfile + + # fails on Windows standalone too, but more embarassing as java specific + test_os_jy # Locale tests run and fail on Cygwin + test_subprocess_jy + test_sys_jy # OSError handling wide-character filename + + test_asyncore + test_compileall + test_distutils + test_email_codecs + test_largefile # [Errno 9] Bad file descriptor + test_locale + test_profile + test_pydoc # Hangs with prompt (Windows) + test_select # Unconnected client socket should be selectable + test_sundry # ImportError: No module named audiodev + + test_sys_setprofile # revisit for GC + test_sys_settrace # revisit for line jumping + + # Unreliable tests + test_asynchat + test_gc # Rare failures depending on timing of Java gc + test_logging + test_select_new + test_socket # flakey (Windows) + test_tarfile # flakey (Windows) + test_threading + test_urllib2net # unexpected output makes this a failure to regrtest.py + + # Tests that should work with socket-reboot, but currently fail/hang + test_ftplib # NoSuchElementException ssl + test_httplib + test_poplib # 'NoneType' is not iterable + test_smtplib + """, } @@ -1378,9 +1388,8 @@ for test_module in conditional_support: _expectations[_platform] += \ - skip_conditional_support(test_module,conditional_support[test_module]) + skip_conditional_support(test_module, conditional_support[test_module]) - class _ExpectedSkips: def __init__(self): @@ -1494,18 +1503,18 @@ self.expected = set(self.split_commented(s)) self.valid = True -def savememo(memo,good,failures,bad,skips,skipped,allran, resource_denieds): +def savememo(memo, good, failures, bad, skips, skipped, allran, resource_denieds): f = open(memo,'w') try: - for n,l in [('good',good),('bad',bad),('skipped',skipped)]: + for n,l in [('good',good), ('bad',bad), ('skipped',skipped)]: print >>f,"%s = [" % n for x in l: print >>f," %r," % x print >>f," ]" print >>f, count(len(skipped), "test"), "skipped:" - countsurprises(skips, skipped, 'skip', 'ran', allran, resource_denieds,f) + countsurprises(skips, skipped, 'skip', 'ran', allran, resource_denieds, f) print >>f, count(len(bad), "test"), "failed:" - countsurprises(failures, bad, 'fail', 'passed', allran, resource_denieds,f) + countsurprises(failures, bad, 'fail', 'passed', allran, resource_denieds, f) import platform print >>f, "Platform: " print >>f, " %r" % platform.platform() diff --git a/Lib/test/test_chdir.py b/Lib/test/test_chdir.py --- a/Lib/test/test_chdir.py +++ b/Lib/test/test_chdir.py @@ -405,7 +405,7 @@ mod = sys.modules[mod_name] self.assertEqual(mod.__file__, mod_name + COMPILED_SUFFIX) - + at unittest.skipIf(test_support.is_jython_nt, "FIXME: failing on Windows: issue 2418") class SubprocessTestCase(BaseChdirTestCase): TEST_DIRS = 2 diff --git a/Lib/test/test_file2k.py b/Lib/test/test_file2k.py --- a/Lib/test/test_file2k.py +++ b/Lib/test/test_file2k.py @@ -11,7 +11,7 @@ threading = None from test import test_support -from test.test_support import TESTFN, run_unittest +from test.test_support import TESTFN, run_unittest, is_jython, is_jython_nt from UserList import UserList class AutoFileTests(unittest.TestCase): @@ -711,6 +711,7 @@ finally: sys.stdout = save_stdout + @unittest.skipIf(is_jython_nt, "FIXME: utf-16 decode error, see issue 2312") def test_unicode(self): import subprocess diff --git a/Lib/test/test_glob.py b/Lib/test/test_glob.py --- a/Lib/test/test_glob.py +++ b/Lib/test/test_glob.py @@ -3,6 +3,7 @@ import shutil import sys import unittest +import warnings from test.test_support import run_unittest, TESTFN @@ -40,7 +41,10 @@ os.symlink(os.path.join('a', 'bcd'), self.norm('sym3')) def tearDown(self): - shutil.rmtree(self.tempdir) + try: + shutil.rmtree(self.tempdir) + except OSError: + warnings.warn("Failed to remove " + self.tempdir) def glob(self, *parts): if len(parts) == 1: 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 @@ -35,7 +35,8 @@ "verbose", "use_resources", "max_memuse", "record_original_stdout", "get_original_stdout", "unload", "unlink", "rmtree", "forget", "is_resource_enabled", "requires", "find_unused_port", "bind_port", - "fcmp", "have_unicode", "is_jython", "TESTFN", "HOST", "FUZZ", + "fcmp", "have_unicode", "is_jython", "is_jython_nt", + "TESTFN", "HOST", "FUZZ", "SAVEDCWD", "temp_cwd", "findfile", "sortdict", "check_syntax_error", "open_urlresource", "check_warnings", "check_py3k_warnings", "CleanImport", "EnvironmentVarGuard", "captured_output", @@ -47,6 +48,11 @@ "import_fresh_module", "threading_cleanup", "reap_children", "strip_python_stderr"] + +# We use these extensively in adapting the regression tests for Jython +is_jython = sys.platform.startswith('java') +is_jython_nt = is_jython and (os._name == 'nt') + class Error(Exception): """Base class for regression test exceptions.""" @@ -188,7 +194,7 @@ except KeyError: pass -if sys.platform.startswith("win") or (os.name == "java" and os._name == "nt"): +if sys.platform.startswith("win") or is_jython_nt: def _waitfor(func, pathname, waitall=False): # Peform the operation func(pathname) @@ -426,14 +432,13 @@ except NameError: have_unicode = False -is_jython = sys.platform.startswith('java') if is_jython: def make_jar_classloader(jar): import os from java.net import URL, URLClassLoader url = URL('jar:file:%s!/' % jar) - if os._name == 'nt': + if is_jython_nt: # URLJarFiles keep a cached open file handle to the jar even # after this ClassLoader is GC'ed, disallowing Windows tests # from removing the jar file from disk when finished with it @@ -447,7 +452,7 @@ return URLClassLoader([url]) # Filename used for testing -if os.name == 'java': +if is_jython: # Jython disallows @ in module names TESTFN = '$test' elif os.name == 'riscos': diff --git a/Lib/test/test_sys.py b/Lib/test/test_sys.py --- a/Lib/test/test_sys.py +++ b/Lib/test/test_sys.py @@ -251,12 +251,14 @@ self.assert_(vi[3] in ("alpha", "beta", "candidate", "final")) self.assert_(isinstance(vi[4], int)) + @unittest.skipIf(test.test_support.is_jython_nt, + "FIXME: fails probably due to issue 2312") def test_ioencoding(self): # from v2.7 test import subprocess,os env = dict(os.environ) # Test character: cent sign, encoded as 0x4A (ASCII J) in CP424, - # not representable in ASCII. + # not representable in ASCII, Unicode U+00a2. env["PYTHONIOENCODING"] = "cp424" p = subprocess.Popen([sys.executable, "-c", 'print unichr(0xa2)'], diff --git a/Lib/test/test_sys_jy.py b/Lib/test/test_sys_jy.py --- a/Lib/test/test_sys_jy.py +++ b/Lib/test/test_sys_jy.py @@ -7,6 +7,7 @@ import tempfile import unittest from test import test_support +from test.test_support import is_jython, is_jython_nt class SysTest(unittest.TestCase): @@ -22,7 +23,7 @@ self.assertEquals(str(e), "leaving now") def test_tuple_args(self): - "Exceptions raised unpacking tuple args have right line number" + # Exceptions raised unpacking tuple args have right line number def tuple_args( (x,y) ): pass try: tuple_args( 10 ) @@ -193,6 +194,7 @@ # Adapted from CPython 2.7 test_sys to exercise setting Jython registry # values related to encoding and error policy. + @unittest.skipIf(is_jython_nt, "FIXME: fails probably due to issue 2312") def test_ioencoding(self): # adapted from CPython v2.7 test_sys import subprocess, os env = dict(os.environ) @@ -243,9 +245,8 @@ class SysArgvTest(unittest.TestCase): - @unittest.skipIf(os._name == "nt", "FIXME should work on Windows") def test_unicode_argv(self): - """Unicode roundtrips successfully through sys.argv arguments""" + # Unicode roundtrips successfully through sys.argv arguments zhongwen = u'\u4e2d\u6587' with test_support.temp_cwd(name=u"tempcwd-%s" % zhongwen): p = subprocess.Popen( diff --git a/Lib/test/test_tarfile.py b/Lib/test/test_tarfile.py --- a/Lib/test/test_tarfile.py +++ b/Lib/test/test_tarfile.py @@ -6,11 +6,13 @@ import StringIO from hashlib import md5 import errno +import warnings import unittest import tarfile from test import test_support +from test.test_support import is_jython, is_jython_nt # Check for our compression modules. try: @@ -295,6 +297,7 @@ self.assertTrue(self.tar.getmembers()[-1].name == "misc/eof", "could not find all members") + @unittest.skipIf(is_jython_nt, "FIXME: fails trying to unlink() open file") def test_extract_hardlink(self): # Test hardlink extraction (e.g. bug #857297). with tarfile.open(tarname, errorlevel=1, encoding="iso8859-1") as tar: @@ -321,12 +324,13 @@ tar.extractall(TEMPDIR, directories) for tarinfo in directories: path = os.path.join(TEMPDIR, tarinfo.name) - if sys.platform != "win32": + if sys.platform != "win32" and not is_jython_nt: # Win32 has no support for fine grained permissions. self.assertEqual(tarinfo.mode & 0777, os.stat(path).st_mode & 0777) self.assertEqual(tarinfo.mtime, os.path.getmtime(path)) tar.close() + @unittest.skipIf(is_jython_nt, "FIXME: fails trying to unlink() open file") def test_init_close_fobj(self): # Issue #7341: Close the internal file object in the TarFile # constructor in case of an error. For the test we rely on @@ -834,7 +838,7 @@ self._test_pathname("foo" + os.sep + os.sep, "foo", dir=True) def test_abs_pathnames(self): - if sys.platform == "win32": + if sys.platform == "win32" or is_jython_nt: self._test_pathname("C:\\foo", "foo") else: self._test_pathname("/foo", "foo") @@ -974,10 +978,11 @@ self.assertTrue(data.count("\0") == tarfile.RECORDSIZE, "incorrect zero padding") + @unittest.skipIf(is_jython_nt, "requires posix-like os.umask()") def test_file_mode(self): # Test for issue #8464: Create files with correct # permissions. - if sys.platform == "win32" or not hasattr(os, "umask"): + if sys.platform == "win32" or is_jython_nt or not hasattr(os, "umask"): return if os.path.exists(tmpname): @@ -1590,6 +1595,8 @@ def test_main(): + if os.path.exists(TEMPDIR): + shutil.rmtree(TEMPDIR) os.makedirs(TEMPDIR) tests = [ @@ -1654,7 +1661,11 @@ test_support.run_unittest(*tests) finally: if os.path.exists(TEMPDIR): - shutil.rmtree(TEMPDIR) + try: + shutil.rmtree(TEMPDIR) + except OSError: + warnings.warn("Failed to remove "+TEMPDIR) + if __name__ == "__main__": test_main() diff --git a/build.xml b/build.xml --- a/build.xml +++ b/build.xml @@ -44,7 +44,7 @@ --------------------- See http://wiki.python.org/jython/JythonDeveloperGuide/HowToReleaseJython - + An example ant.properties file: ------------------------------- @@ -137,7 +137,6 @@ - @@ -222,18 +221,20 @@ - + + + . Build environment for ${ant.project.name} @@ -306,7 +307,6 @@ - @@ -321,7 +321,7 @@ the tokens defined in Python.g (and cleans make the build slow) --> - + @@ -420,7 +420,7 @@ This is a snapshot build. It reflects the current development status. - + The readme text for the next release will be like: @@ -443,8 +443,7 @@ - + @@ -460,7 +459,7 @@ - + + - - - - - + + + @@ -665,7 +663,7 @@ - + @@ -713,7 +711,7 @@ copy installer classes to ${dist.dir} - - + + @@ -913,8 +911,11 @@ - - + + + @@ -925,13 +926,16 @@ + + + @@ -952,6 +956,7 @@ + @@ -969,6 +974,7 @@ + @@ -990,6 +996,7 @@ + @@ -1013,40 +1020,79 @@ + + - + + + - - - - - - - - - - + + + + + + + + + + + - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -1061,29 +1107,30 @@ - + - - + + - + creating ${bugtests.dir}/support_config.py -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Sat Oct 31 01:39:19 2015 From: jython-checkins at python.org (stefan.richthofer) Date: Sat, 31 Oct 2015 05:39:19 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Shortened_and_improved_API_?= =?utf-8?q?for_easy_construction_of_Python-backed_Java_objects=2E?= Message-ID: <20151031053919.494.98145@psf.io> https://hg.python.org/jython/rev/b9c2c8001034 changeset: 7785:b9c2c8001034 user: Stefan Richthofer date: Sat Oct 31 06:39:07 2015 +0100 summary: Shortened and improved API for easy construction of Python-backed Java objects. files: src/org/python/core/JyAttribute.java | 12 +- src/org/python/core/Py.java | 84 ++++++++------- src/org/python/core/PyModule.java | 42 ++++++++ 3 files changed, 97 insertions(+), 41 deletions(-) diff --git a/src/org/python/core/JyAttribute.java b/src/org/python/core/JyAttribute.java --- a/src/org/python/core/JyAttribute.java +++ b/src/org/python/core/JyAttribute.java @@ -69,23 +69,29 @@ public static final byte WEAKREF_PENDING_GET_ATTR = 3; /** + * Only used internally by + * {@linkorg.python.core.Py#javaPyClass(PyObject, Class)} + */ + public static final byte PYCLASS_PY2JY_CACHE_ATTR = 4; + + /** * Used by {@link org.python.modules.gc}-module to mark cyclic * trash. Searching for cyclic trash is usually not required * by Jython. It is only done if gc-features are enabled that * mimic CPython behavior. */ - public static final byte GC_CYCLE_MARK_ATTR = 4; + public static final byte GC_CYCLE_MARK_ATTR = 5; /** * Used by {@link org.python.modules.gc}-module to mark * finalizable objects that might have been resurrected * during a delayed finalization process. */ - public static final byte GC_DELAYED_FINALIZE_CRITICAL_MARK_ATTR = 5; + public static final byte GC_DELAYED_FINALIZE_CRITICAL_MARK_ATTR = 6; public static final byte FINALIZE_TRIGGER_ATTR = Byte.MAX_VALUE; private static byte nonBuiltinAttrTypeOffset = Byte.MIN_VALUE+1; - private static byte nonBuiltinTransientAttrTypeOffset = 6; + private static byte nonBuiltinTransientAttrTypeOffset = 7; /** * Reserves and returns a new non-transient attr type for custom use. diff --git a/src/org/python/core/Py.java b/src/org/python/core/Py.java --- a/src/org/python/core/Py.java +++ b/src/org/python/core/Py.java @@ -15,6 +15,7 @@ import java.io.StreamCorruptedException; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; +import java.lang.ref.WeakReference; import java.net.URL; import java.net.URLDecoder; import java.sql.Date; @@ -22,9 +23,7 @@ import java.sql.Timestamp; import java.util.ArrayList; import java.util.Calendar; -import java.util.HashMap; import java.util.List; -import java.util.Map; import java.util.Set; import com.google.common.base.CharMatcher; @@ -2503,8 +2502,6 @@ } } - protected static Map py2JyClassCache = new HashMap<>(); - protected static PyObject ensureInterface(PyObject cls, Class interfce) { PyObject pjc = PyType.fromClass(interfce); if (Py.isSubClass(cls, pjc)) { @@ -2523,13 +2520,14 @@ * * @return a Python-class that extends {@code cls} and {@code interfce} */ - public static PyObject javaPyClass(PyObject cls, Class interfce) { - py2JyClassCacheItem cacheItem = py2JyClassCache.get(cls); + public static synchronized PyObject javaPyClass(PyObject cls, Class interfce) { + py2JyClassCacheItem cacheItem = (py2JyClassCacheItem) + JyAttribute.getAttr(cls, JyAttribute.PYCLASS_PY2JY_CACHE_ATTR); PyObject result; if (cacheItem == null) { result = ensureInterface(cls, interfce); cacheItem = new py2JyClassCacheItem(interfce, result); - py2JyClassCache.put(cls, cacheItem); + JyAttribute.setAttr(cls, JyAttribute.PYCLASS_PY2JY_CACHE_ATTR, cacheItem); } else { result = cacheItem.get(interfce); if (result == null) { @@ -2549,12 +2547,14 @@ * class on the fly.
* It automatically converts {@code args} to {@link org.python.core.PyObject}s.
* For keyword-support use - * {@link #newJavaObject(PyObject, Class, String[], Object...)}. + * {@link #newJ(PyObject, Class, String[], Object...)}. * - * {@see #newJavaObject(PyObject, Class, PyObject[], String[])} - * {@see #newJavaObject(PyObject, Class, String[], Object...)} - * {@see #newJavaObject(PyModule, Class, Object...)} - * {@see #newJavaObject(PyModule, Class, String[], Object...)} + * {@see #newJ(PyObject, Class, PyObject[], String[])} + * {@see #newJ(PyObject, Class, String[], Object...)} + * {@see #newJ(PyModule, Class, Object...)} + * {@see #newJ(PyModule, Class, String[], Object...)} + * {@see org.python.core.PyModule#newJ(Class, Object...)} + * {@see org.python.core.PyModule#newJ(Class, String[], Object...)} * * @param cls - the class to be instanciated * @param jcls - the Java-type to be returned @@ -2562,7 +2562,7 @@ * @return an instance of cls in form of the interface jcls */ @SuppressWarnings("unchecked") - public static T newJavaObject(PyObject cls, Class jcls, Object... args) { + public static T newJ(PyObject cls, Class jcls, Object... args) { PyObject cls2 = javaPyClass(cls, jcls); PyObject resultPy = cls2.__call__(Py.javas2pys(args)); return (T) resultPy.__tojava__(jcls); @@ -2577,10 +2577,12 @@ * class on the fly.
* {@code keywordss} are applied to the last {@code args} in the list. * - * {@see #newJavaObject(PyObject, Class, Object...)} - * {@see #newJavaObject(PyObject, Class, String[], Object...)} - * {@see #newJavaObject(PyModule, Class, Object...)} - * {@see #newJavaObject(PyModule, Class, String[], Object...)} + * {@see #newJ(PyObject, Class, Object...)} + * {@see #newJ(PyObject, Class, String[], Object...)} + * {@see #newJ(PyModule, Class, Object...)} + * {@see #newJ(PyModule, Class, String[], Object...)} + * {@see org.python.core.PyModule#newJ(Class, Object...)} + * {@see org.python.core.PyModule#newJ(Class, String[], Object...)} * * @param cls - the class to be instanciated * @param jcls - the Java-type to be returned @@ -2589,7 +2591,7 @@ * @return an instance of cls in form of the interface jcls */ @SuppressWarnings("unchecked") - public static T newJavaObject(PyObject cls, Class jcls, PyObject[] args, String[] keywords) { + public static T newJ(PyObject cls, Class jcls, PyObject[] args, String[] keywords) { PyObject cls2 = javaPyClass(cls, jcls); PyObject resultPy = cls2.__call__(args, keywords); return (T) resultPy.__tojava__(jcls); @@ -2605,10 +2607,12 @@ * It automatically converts {@code args} to {@link org.python.core.PyObject}s.
* {@code keywordss} are applied to the last {@code args} in the list. * - * {@see #newJavaObject(PyObject, Class, PyObject[], String[])} - * {@see #newJavaObject(PyObject, Class, Object...)} - * {@see #newJavaObject(PyModule, Class, Object...)} - * {@see #newJavaObject(PyModule, Class, String[], Object...)} + * {@see #newJ(PyObject, Class, PyObject[], String[])} + * {@see #newJ(PyObject, Class, Object...)} + * {@see #newJ(PyModule, Class, Object...)} + * {@see #newJ(PyModule, Class, String[], Object...)} + * {@see org.python.core.PyModule#newJ(Class, Object...)} + * {@see org.python.core.PyModule#newJ(Class, String[], Object...)} * * @param cls - the class to be instanciated * @param jcls - the Java-type to be returned @@ -2617,22 +2621,24 @@ * @return an instance of cls in form of the interface jcls */ @SuppressWarnings("unchecked") - public static T newJavaObject(PyObject cls, Class jcls, String[] keywords, Object... args) { + public static T newJ(PyObject cls, Class jcls, String[] keywords, Object... args) { PyObject cls2 = javaPyClass(cls, jcls); PyObject resultPy = cls2.__call__(Py.javas2pys(args), keywords); return (T) resultPy.__tojava__(jcls); } /** - * Works like {@link #newJavaObject(PyObject, Class, Object...)}, but looks + * Works like {@link #newJ(PyObject, Class, Object...)}, but looks * up the Python-class in the module-dict using the interface-name, i.e. * {@code jcls.getSimpleName()}.
- * For keywords-support use {@link #newJavaObject(PyModule, Class, String[], Object...)}. + * For keywords-support use {@link #newJ(PyModule, Class, String[], Object...)}. * - * {@see #newJavaObject(PyModule, Class, String[], Object...)} - * {@see #newJavaObject(PyObject, Class, PyObject[], String[])} - * {@see #newJavaObject(PyObject, Class, Object...)} - * {@see #newJavaObject(PyObject, Class, String[], Object...)} + * {@see #newJ(PyModule, Class, String[], Object...)} + * {@see #newJ(PyObject, Class, PyObject[], String[])} + * {@see #newJ(PyObject, Class, Object...)} + * {@see #newJ(PyObject, Class, String[], Object...)} + * {@see org.python.core.PyModule#newJ(Class, Object...)} + * {@see org.python.core.PyModule#newJ(Class, String[], Object...)} * * @param module the module containing the desired class * @param jcls Java-type of the desired clas, must have the same name @@ -2640,21 +2646,23 @@ * @return a new instance of the desired class */ @SuppressWarnings("unchecked") - public static T newJavaObject(PyModule module, Class jcls, Object... args) { + public static T newJ(PyModule module, Class jcls, Object... args) { PyObject cls = module.__getattr__(jcls.getSimpleName().intern()); - return newJavaObject(cls, jcls, args); + return newJ(cls, jcls, args); } /** - * Works like {@link #newJavaObject(PyObject, Class, String[], Object...)}, but looks + * Works like {@link #newJ(PyObject, Class, String[], Object...)}, but looks * up the Python-class in the module-dict using the interface-name, i.e. * {@code jcls.getSimpleName()}.
* {@code keywordss} are applied to the last {@code args} in the list. * - * {@see #newJavaObject(PyModule, Class, Object...)} - * {@see #newJavaObject(PyObject, Class, PyObject[], String[])} - * {@see #newJavaObject(PyObject, Class, Object...)} - * {@see #newJavaObject(PyObject, Class, String[], Object...)} + * {@see #newJ(PyModule, Class, Object...)} + * {@see #newJ(PyObject, Class, PyObject[], String[])} + * {@see #newJ(PyObject, Class, Object...)} + * {@see #newJ(PyObject, Class, String[], Object...)} + * {@see org.python.core.PyModule#newJ(Class, Object...)} + * {@see org.python.core.PyModule#newJ(Class, String[], Object...)} * * @param module the module containing the desired class * @param jcls Java-type of the desired class, must have the same name @@ -2663,9 +2671,9 @@ * @return a new instance of the desired class */ @SuppressWarnings("unchecked") - public static T newJavaObject(PyModule module, Class jcls, String[] keywords, Object... args) { + public static T newJ(PyModule module, Class jcls, String[] keywords, Object... args) { PyObject cls = module.__getattr__(jcls.getSimpleName().intern()); - return newJavaObject(cls, jcls, keywords, args); + return newJ(cls, jcls, keywords, args); } //----------------end of constructor-section------------------ } diff --git a/src/org/python/core/PyModule.java b/src/org/python/core/PyModule.java --- a/src/org/python/core/PyModule.java +++ b/src/org/python/core/PyModule.java @@ -205,6 +205,48 @@ } } + /** + * Delegates to {@link #newJ(PyModule, Class, Object...)}, .
+ * For keywords-support use {@link #newJ(Class, String[], Object...)}. + * + * {@see #newJ(Class, String[], Object...)} + * {@see org.python.core.Py#newJ(PyModule, Class, Object...)} + * {@see org.python.core.Py#newJ(PyModule, Class, String[], Object...)} + * {@see org.python.core.Py#newJ(PyObject, Class, PyObject[], String[])} + * {@see org.python.core.Py#newJ(PyObject, Class, Object...)} + * {@see org.python.core.Py#newJ(PyObject, Class, String[], Object...)} + * + * @param module the module containing the desired class + * @param jcls Java-type of the desired clas, must have the same name + * @param args constructor-arguments + * @return a new instance of the desired class + */ + @SuppressWarnings("unchecked") + public T newJ(Class jcls, Object... args) { + return Py.newJ(this, jcls, args); + } + + /** + * Delgates to {@link org.python.core.Py#newJ(PyModule, Class, String[], Object...)}.
+ * {@code keywordss} are applied to the last {@code args} in the list. + * + * {@see #newJ(Class, Object...)} + * {@see org.python.core.Py#newJ(PyModule, Class, Object...)} + * {@see org.python.core.Py#newJ(PyModule, Class, String[], Object...)} + * {@see org.python.core.Py#newJ(PyObject, Class, PyObject[], String[])} + * {@see org.python.core.Py#newJ(PyObject, Class, Object...)} + * {@see org.python.core.Py#newJ(PyObject, Class, String[], Object...)} + * + * @param jcls Java-type of the desired class, must have the same name + * @param keywords are applied to the last {@code args} in the list + * @param args constructor-arguments + * @return a new instance of the desired class + */ + @SuppressWarnings("unchecked") + public T newJ(Class jcls, String[] keywords, Object... args) { + return Py.newJ(this, jcls, keywords, args); + } + /* Traverseproc implementation */ @Override -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Sat Oct 31 01:56:24 2015 From: jython-checkins at python.org (stefan.richthofer) Date: Sat, 31 Oct 2015 05:56:24 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Removed_unused_WeakReferenc?= =?utf-8?q?e-import_in_Py=2Ejava=2E?= Message-ID: <20151031055623.8619.89655@psf.io> https://hg.python.org/jython/rev/3f1f31d53dc6 changeset: 7786:3f1f31d53dc6 user: Stefan Richthofer date: Sat Oct 31 06:56:14 2015 +0100 summary: Removed unused WeakReference-import in Py.java. files: src/org/python/core/Py.java | 1 - 1 files changed, 0 insertions(+), 1 deletions(-) diff --git a/src/org/python/core/Py.java b/src/org/python/core/Py.java --- a/src/org/python/core/Py.java +++ b/src/org/python/core/Py.java @@ -15,7 +15,6 @@ import java.io.StreamCorruptedException; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; -import java.lang.ref.WeakReference; import java.net.URL; import java.net.URLDecoder; import java.sql.Date; -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Sat Oct 31 04:00:15 2015 From: jython-checkins at python.org (jeff.allen) Date: Sat, 31 Oct 2015 08:00:15 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_List_expected_failures_by_O?= =?utf-8?q?S_platform_in_regrtest=2Epy_=28issue_=232419=29=2E?= Message-ID: <20151031080015.74099.3249@psf.io> https://hg.python.org/jython/rev/7b1ad371113e changeset: 7787:7b1ad371113e user: Jeff Allen date: Sat Oct 31 07:22:27 2015 +0000 summary: List expected failures by OS platform in regrtest.py (issue #2419). The selection of regression tests expected to pass is allowed to vary between platforms, to encourage curation of a clean set for each. files: Lib/test/regrtest.py | 26 +++++++++++++++----------- 1 files changed, 15 insertions(+), 11 deletions(-) diff --git a/Lib/test/regrtest.py b/Lib/test/regrtest.py --- a/Lib/test/regrtest.py +++ b/Lib/test/regrtest.py @@ -1292,7 +1292,7 @@ _expectations['freebsd8'] = _expectations['freebsd4'] _failures = { - 'java': + 'java': # Expected to fail on every OS """ test_codecencodings_cn test_codecencodings_hk @@ -1318,13 +1318,10 @@ # fails on Windows standalone, probably shouldn't test_netrc # KeyError: 'foo.domain.com' - test_runpy # OSError: unlink() test_shutil # Operation not permitted errors - test_urllib2 # file not on local host (likely Windows only) test_zipfile # fails on Windows standalone too, but more embarassing as java specific - test_os_jy # Locale tests run and fail on Cygwin test_subprocess_jy test_sys_jy # OSError handling wide-character filename @@ -1357,20 +1354,21 @@ test_httplib test_poplib # 'NoneType' is not iterable test_smtplib + """, + 'java.nt': # Expected to fail on Windows + """ + test_mailbox # fails miserably and ruins other tests + test_os_jy # Locale tests run and fail on Cygwin + test_popen # http://bugs.python.org/issue1559298 + test_runpy # OSError: unlink() + test_urllib2 # file not on local host (likely Windows only) """, } _platform = sys.platform if _platform[:4] == 'java': _platform = 'java' - if os._name == 'nt': - # XXX: Omitted for now because it fails so miserably and ruins - # other tests - _failures['java'] += '\ntest_mailbox' - if ' ' in sys.executable: - # http://bugs.python.org/issue1559298 - _failures['java'] += '\ntest_popen' if os._name != 'darwin': _expectations['java'] += '\ntest__osx_support' if os.name != 'posix': @@ -1501,8 +1499,14 @@ if _platform in _failures: s = _failures[_platform] self.expected = set(self.split_commented(s)) + if test_support.is_jython: + # There may be a key like java.nt with extra entries + s = _failures.get('java.' + os._name) + if s: + self.expected |= set(self.split_commented(s)) self.valid = True + def savememo(memo, good, failures, bad, skips, skipped, allran, resource_denieds): f = open(memo,'w') try: -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Sat Oct 31 12:44:22 2015 From: jython-checkins at python.org (jim.baker) Date: Sat, 31 Oct 2015 16:44:22 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Use_internal_methods_to_pre?= =?utf-8?q?vent_subclasses_of_set_causing_a_stack_overflow=2E?= Message-ID: <20151031164422.59793.61127@psf.io> https://hg.python.org/jython/rev/a7d1380c4594 changeset: 7788:a7d1380c4594 user: Jim Baker date: Sat Oct 31 10:44:15 2015 -0600 summary: Use internal methods to prevent subclasses of set causing a stack overflow. Fixes #2357. set.intersection_update and set.difference_update methods were defined in terms of terms of __iand__ and __isub__, which would cause a stack overflow if a subclass bound both method names to the same underying method. Fix by ensuring that the implementation of set.intersection_update and set.difference_update uses the corresponding internal method for set. files: Lib/test/test_set_jy.py | 85 ++++++++++++++++++++++ src/org/python/core/PySet.java | 4 +- 2 files changed, 87 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_set_jy.py b/Lib/test/test_set_jy.py --- a/Lib/test/test_set_jy.py +++ b/Lib/test/test_set_jy.py @@ -109,6 +109,90 @@ class TestJavaLinkedHashSet(TestJavaSet): thetype = LinkedHashSet +class SetSubclassCallsSuperMethods(set): + + # Used to verify all call paths where there is more than one way + # to call the super method, such as (union, __or__), etc + + def _valid_op_args(f): + def _screener(*args): + if len(args) != 2: + raise TypeError() + for arg in args: + if not (isinstance(arg, set) or isinstance(arg, frozenset)): + raise TypeError() + return f(*args) + return _screener + + def _call_for_side_effects(f): + def _mutating_convention(*args): + f(*args) + return None + return _mutating_convention + + def issubset(self, other): + return super(SetSubclassCallsSuperMethods, self).issubset(other) + + __le__ = issubset + + def issuperset(self, other): + return super(SetSubclassCallsSuperMethods, self).issuperset(other) + + __ge__ = issuperset + + def union(self, *others): + return super(SetSubclassCallsSuperMethods, self).union(*others) + + __or__ = _valid_op_args(union) + + def intersection(self, *others): + return super(SetSubclassCallsSuperMethods, self).intersection(*others) + + __and__ = _valid_op_args(intersection) + + def difference(self, *others): + return super(SetSubclassCallsSuperMethods, self).difference(*others) + + __sub__ = _valid_op_args(difference) + + def symmetric_difference(self, *others): + return super(SetSubclassCallsSuperMethods, self).symmetric_difference(*others) + + __xor__ = _valid_op_args(symmetric_difference) + + def _update(self, *others): + super(SetSubclassCallsSuperMethods, self).update(*others) + return self + + update = _call_for_side_effects(_update) + __ior__ = _update + + def _difference_update(self, *others): + super(SetSubclassCallsSuperMethods, self).difference_update(*others) + return self + + difference_update = _call_for_side_effects(_difference_update) + __isub__ = _difference_update + + def _intersection_update(self, *others): + super(SetSubclassCallsSuperMethods, self).intersection_update(*others) + return self + + intersection_update = _call_for_side_effects(_intersection_update) + __iand__ = _intersection_update + + def _symmetric_difference_update(self, other): + super(SetSubclassCallsSuperMethods, self).symmetric_difference_update(other) + return self + + symmetric_difference_update = _call_for_side_effects(_symmetric_difference_update) + __ixor__ = _symmetric_difference_update + + +class TestSetSubclassCallsSuperMethods(test_set.TestSet): + # verifies fix for http://bugs.jython.org/issue2357 + thetype = SetSubclassCallsSuperMethods + def test_main(): tests = [ @@ -116,6 +200,7 @@ SetInJavaTestCase, TestJavaHashSet, TestJavaLinkedHashSet, + TestSetSubclassCallsSuperMethods ] test_support.run_unittest(*tests) diff --git a/src/org/python/core/PySet.java b/src/org/python/core/PySet.java --- a/src/org/python/core/PySet.java +++ b/src/org/python/core/PySet.java @@ -306,7 +306,7 @@ for (PyObject other: args) { if (other instanceof BaseSet) { - __iand__(other); + set___iand__(other); } else { BaseSet set = (BaseSet)baseset_intersection(other); _set = set._set; @@ -343,7 +343,7 @@ for (PyObject other: args) { if (other instanceof BaseSet) { - __isub__(other); + set___isub__(other); } for (PyObject o : other.asIterable()) { if (__contains__(o)) { -- Repository URL: https://hg.python.org/jython