From jython-checkins at python.org Sat Feb 1 05:05:32 2020 From: jython-checkins at python.org (jeff.allen) Date: Sat, 01 Feb 2020 10:05:32 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Formatting_and_the_odd_typ?= =?utf-8?q?o_in_Map_and_Set_proxies?= Message-ID: <20200201100532.1.CD344665FD003EF0@mg.python.org> https://hg.python.org/jython/rev/fe9b60423d2d changeset: 8324:fe9b60423d2d user: Jeff Allen date: Sat Feb 01 08:46:58 2020 +0000 summary: Formatting and the odd typo in Map and Set proxies files: src/org/python/core/JavaProxyMap.java | 149 ++++++++----- src/org/python/core/JavaProxySet.java | 113 +++++++--- 2 files changed, 170 insertions(+), 92 deletions(-) diff --git a/src/org/python/core/JavaProxyMap.java b/src/org/python/core/JavaProxyMap.java --- a/src/org/python/core/JavaProxyMap.java +++ b/src/org/python/core/JavaProxyMap.java @@ -8,13 +8,14 @@ import java.util.Set; /** - * Proxy Java objects implementing java.util.List with Python methods - * corresponding to the standard list type + * Proxy Java objects implementing java.util.List with Python methods corresponding to the standard + * list type */ class JavaProxyMap { @Untraversable private static class MapMethod extends PyBuiltinMethodNarrow { + protected MapMethod(String name, int numArgs) { super(name, numArgs); } @@ -30,6 +31,7 @@ @Untraversable private static class MapClassMethod extends PyBuiltinClassMethodNarrow { + protected MapClassMethod(String name, int minArgs, int maxArgs) { super(name, minArgs, maxArgs); } @@ -108,12 +110,12 @@ /** Return Python {@code ValueError} that None is not allowed. */ private static RuntimeException nullException() { - return Py.ValueError( - "None is not allowed because underlying container cannot store a Java null."); + return Py.ValueError("None is not allowed: underlying container cannot store Java null."); } - /** Return Python {@code ValueError} that None is not allowed, or the {@code NullPointerException}, - * if in fact the value was not {@code None}. + /** + * Return Python {@code ValueError} that None is not allowed, or the + * {@code NullPointerException}, if in fact the value was not {@code None}. * * @param npe original exception * @param key possibly causing the problem @@ -122,7 +124,7 @@ */ private static RuntimeException nullException(NullPointerException npe, Object key, Object value) { - return (value == Py.None || value == Py.None) ? nullException() : npe; + return (key == Py.None || value == Py.None) ? nullException() : npe; } /* @@ -152,6 +154,7 @@ // Map doesn't extend Collection, so it needs its own version of len, iter and contains private static final PyBuiltinMethodNarrow mapLenProxy = new MapMethod("__len__", 0) { + @Override public PyObject __call__() { return Py.java2py(asMap().size()); @@ -169,7 +172,7 @@ boolean first = true; for (Map.Entry entry : asMap().entrySet()) { if (first) { - first=false; + first = false; } else { repr.append(", "); } @@ -186,12 +189,14 @@ } }; private static final PyBuiltinMethodNarrow mapEqProxy = new MapMethod("__eq__", 1) { + @Override public PyObject __call__(PyObject other) { return mapEq(self, other); } }; private static final PyBuiltinMethodNarrow mapNeProxy = new MapMethod("__ne__", 1) { + @Override public PyObject __call__(PyObject other) { // mapEq may return null if we don't know how to compare to other. @@ -204,36 +209,42 @@ } }; private static final PyBuiltinMethodNarrow mapLeProxy = new MapMethod("__le__", 1) { + @Override public PyObject __call__(PyObject other) { return mapLe(self, other); } }; private static final PyBuiltinMethodNarrow mapGeProxy = new MapMethod("__ge__", 1) { + @Override public PyObject __call__(PyObject other) { return (mapLe(self, other).__not__()).__or__(mapEq(self, other)); } }; private static final PyBuiltinMethodNarrow mapLtProxy = new MapMethod("__lt__", 1) { + @Override public PyObject __call__(PyObject other) { return mapLe(self, other).__and__(mapEq(self, other).__not__()); } }; private static final PyBuiltinMethodNarrow mapGtProxy = new MapMethod("__gt__", 1) { + @Override public PyObject __call__(PyObject other) { return mapLe(self, other).__not__(); } }; private static final PyBuiltinMethodNarrow mapIterProxy = new MapMethod("__iter__", 0) { + @Override public PyObject __call__() { return new JavaIterator(asMap().keySet()); } }; private static final PyBuiltinMethodNarrow mapContainsProxy = new MapMethod("__contains__", 1) { + @Override public PyObject __call__(PyObject obj) { return asMap().containsKey(tojava(obj)) ? Py.True : Py.False; @@ -264,6 +275,7 @@ }; private static final PyBuiltinMethodNarrow mapGetItemProxy = new MapMethod("__getitem__", 1) { + @Override public PyObject __call__(PyObject key) { Map map = asMap(); @@ -276,6 +288,7 @@ }; private static final PyBuiltinMethodNarrow mapPutProxy = new MapMethod("__setitem__", 2) { + @Override public PyObject __call__(PyObject key, PyObject value) { try { @@ -288,6 +301,7 @@ }; private static final PyBuiltinMethodNarrow mapRemoveProxy = new MapMethod("__delitem__", 1) { + @Override public PyObject __call__(PyObject key) { Map map = asMap(); @@ -301,10 +315,12 @@ }; private static final PyBuiltinMethodNarrow mapIterItemsProxy = new MapMethod("iteritems", 0) { + @Override public PyObject __call__() { final Iterator> entryIterator = asMap().entrySet().iterator(); return new PyIterator() { + @Override public PyObject __iternext__() { if (entryIterator.hasNext()) { @@ -319,10 +335,12 @@ }; private static final PyBuiltinMethodNarrow mapIterKeysProxy = new MapMethod("iterkeys", 0) { + @Override public PyObject __call__() { final Iterator keyIterator = asMap().keySet().iterator(); return new PyIterator() { + @Override public PyObject __iternext__() { if (keyIterator.hasNext()) { @@ -337,10 +355,12 @@ }; private static final PyBuiltinMethodNarrow mapIterValuesProxy = new MapMethod("itervalues", 0) { + @Override public PyObject __call__() { final Iterator valueIterator = asMap().values().iterator(); return new PyIterator() { + @Override public PyObject __iternext__() { if (valueIterator.hasNext()) { @@ -355,6 +375,7 @@ }; private static final PyBuiltinMethodNarrow mapHasKeyProxy = new MapMethod("has_key", 1) { + @Override public PyObject __call__(PyObject key) { return asMap().containsKey(tojava(key)) ? Py.True : Py.False; @@ -362,6 +383,7 @@ }; private static final PyBuiltinMethodNarrow mapKeysProxy = new MapMethod("keys", 0) { + @Override public PyObject __call__() { PyList keys = new PyList(); @@ -373,6 +395,7 @@ }; private static final PyBuiltinMethod mapValuesProxy = new MapMethod("values", 0) { + @Override public PyObject __call__() { PyList values = new PyList(); @@ -383,30 +406,33 @@ } }; - private static final PyBuiltinMethodNarrow mapSetDefaultProxy = new MapMethod("setdefault", 1, 2) { - @Override - public PyObject __call__(PyObject key) { - return __call__(key, Py.None); - } + private static final PyBuiltinMethodNarrow mapSetDefaultProxy = + new MapMethod("setdefault", 1, 2) { + + @Override + public PyObject __call__(PyObject key) { + return __call__(key, Py.None); + } - @Override - public PyObject __call__(PyObject pykey, PyObject _default) { - Map map = asMap(); - Object key = tojava(pykey); - try { - if (map.containsKey(key)) { - return Py.java2py(map.get(key)); - } else { - map.put(key, tojava(_default)); - return _default; + @Override + public PyObject __call__(PyObject pykey, PyObject _default) { + Map map = asMap(); + Object key = tojava(pykey); + try { + if (map.containsKey(key)) { + return Py.java2py(map.get(key)); + } else { + map.put(key, tojava(_default)); + return _default; + } + } catch (NullPointerException npe) { + throw nullException(npe, key, _default); + } } - } catch (NullPointerException npe) { - throw nullException(npe, key, _default); - } - } - }; + }; private static final PyBuiltinMethodNarrow mapPopProxy = new MapMethod("pop", 1, 2) { + @Override public PyObject __call__(PyObject key) { return __call__(key, null); @@ -427,6 +453,7 @@ }; private static final PyBuiltinMethodNarrow mapPopItemProxy = new MapMethod("popitem", 0) { + @Override public PyObject __call__() { Map map = asMap(); @@ -441,6 +468,7 @@ }; private static final PyBuiltinMethodNarrow mapItemsProxy = new MapMethod("items", 0) { + @Override public PyObject __call__() { PyList items = new PyList(); @@ -452,6 +480,7 @@ }; private static final PyBuiltinMethodNarrow mapCopyProxy = new MapMethod("copy", 0) { + @Override public PyObject __call__() { Map map = asMap(); @@ -547,49 +576,56 @@ 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 Py.TypeError(String.format(ERR_SEQ, 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)); + throw Py.ValueError(String.format(ERR_LENGTH, i, n)); } map.put(tojava(pair.__getitem__(0)), tojava(pair.__getitem__(1))); } } + + private static final String ERR_SEQ = + "cannot convert dictionary update element #%d to a sequence"; + private static final String ERR_LENGTH = + "dictionary update sequence element #%d has length %d; 2 is required"; }; - private static final PyBuiltinClassMethodNarrow mapFromKeysProxy = new MapClassMethod("fromkeys", 1, 2) { - @Override - public PyObject __call__(PyObject keys) { - return __call__(keys, null); - } + private static final PyBuiltinClassMethodNarrow mapFromKeysProxy = + new MapClassMethod("fromkeys", 1, 2) { + + @Override + public PyObject __call__(PyObject keys) { + return __call__(keys, null); + } - @Override - public PyObject __call__(PyObject keys, PyObject _default) { - Object defobj = tojava(_default); - Class> clazz; - try { - clazz = (Class>) asClass(); - Constructor> ctor = clazz.getDeclaredConstructor(); - Map theMap = ctor.newInstance(); - for (PyObject key : keys.asIterable()) { - theMap.put(tojava(key), defobj); + @Override + public PyObject __call__(PyObject keys, PyObject _default) { + Object defobj = tojava(_default); + Class> clazz; + try { + clazz = (Class>) asClass(); + Constructor> ctor = + clazz.getDeclaredConstructor(); + Map theMap = ctor.newInstance(); + for (PyObject key : keys.asIterable()) { + theMap.put(tojava(key), defobj); + } + return Py.java2py(theMap); + } catch (NullPointerException npe) { + throw nullException(); + } catch (ReflectiveOperationException | SecurityException + | IllegalArgumentException e) { + throw Py.JavaError(e); + } } - return Py.java2py(theMap); - } catch (NullPointerException npe) { - throw nullException(); - } catch (ReflectiveOperationException | SecurityException - | IllegalArgumentException e) { - throw Py.JavaError(e); - } - } - }; + }; static PyBuiltinMethod[] getProxyMethods() { + //@formatter:off return new PyBuiltinMethod[]{ mapLenProxy, // map IterProxy can conflict with Iterable.class; @@ -620,6 +656,7 @@ mapFromKeysProxy // class method }; + //@formatter:on } static PyBuiltinMethod[] getPostProxyMethods() { diff --git a/src/org/python/core/JavaProxySet.java b/src/org/python/core/JavaProxySet.java --- a/src/org/python/core/JavaProxySet.java +++ b/src/org/python/core/JavaProxySet.java @@ -65,8 +65,7 @@ } // All elements are equal so the sets are equal return Py.True; - } - else { + } else { // Being compared to something that is not a Python set final Object oj = other.getJavaProxy(); if (oj instanceof Set) { @@ -165,6 +164,7 @@ symDiff.removeAll(intersection); return symDiff; } + protected void symDiffUpdate(Collection other) { Set selfSet = asSet(); Set intersection = new HashSet<>(selfSet); @@ -176,6 +176,7 @@ @Untraversable private static class SetMethodVarargs extends SetMethod { + protected SetMethodVarargs(String name) { super(name, 0, -1); } @@ -187,22 +188,22 @@ @Override public PyObject __call__(PyObject obj) { - return __call__(new PyObject[]{obj}); + return __call__(new PyObject[] {obj}); } @Override public PyObject __call__(PyObject obj1, PyObject obj2) { - return __call__(new PyObject[]{obj1, obj2}); + return __call__(new PyObject[] {obj1, obj2}); } @Override public PyObject __call__(PyObject obj1, PyObject obj2, PyObject obj3) { - return __call__(new PyObject[]{obj1, obj2, obj3}); + return __call__(new PyObject[] {obj1, obj2, obj3}); } @Override public PyObject __call__(PyObject obj1, PyObject obj2, PyObject obj3, PyObject obj4) { - return __call__(new PyObject[]{obj1, obj2, obj3, obj4}); + return __call__(new PyObject[] {obj1, obj2, obj3, obj4}); } } @@ -214,7 +215,7 @@ private static Collection getJavaSet(PyObject self, String op, PyObject obj) { Collection items; if (isPySet(obj)) { - Set otherPySet = ((BaseSet)obj).getSet(); + Set otherPySet = ((BaseSet) obj).getSet(); items = new ArrayList<>(otherPySet.size()); for (PyObject pyobj : otherPySet) { items.add(pyobj.__tojava__(Object.class)); @@ -226,9 +227,9 @@ Set jSet = (Set) oj; items = jSet; } else { - throw Py.TypeError(String.format( - "unsupported operand type(s) for %s: '%.200s' and '%.200s'", - op, self.getType().fastGetName(), obj.getType().fastGetName())); + throw Py.TypeError( + String.format("unsupported operand type(s) for %s: '%.200s' and '%.200s'", + op, self.getType().fastGetName(), obj.getType().fastGetName())); } } return items; @@ -244,7 +245,7 @@ items = jCollection; } else if (oj instanceof Iterable) { items = new HashSet<>(); - for (Object item: (Iterable) oj) { + for (Object item : (Iterable) oj) { items.add(item); } } else { @@ -299,18 +300,21 @@ } private static final SetMethod cmpProxy = new SetMethod("__cmp__", 1) { + @Override public PyObject __call__(PyObject value) { throw Py.TypeError("cannot compare sets using cmp()"); } }; private static final SetMethod eqProxy = new SetMethod("__eq__", 1) { + @Override public PyObject __call__(PyObject other) { return isEqual(other); } }; private static final SetMethod neProxy = new SetMethod("__ne__", 1) { + @Override public PyObject __call__(PyObject other) { // isEqual may return null if we don't know how to compare to other. @@ -323,6 +327,7 @@ } }; private static final SetMethod ltProxy = new SetMethod("__lt__", 1) { + @Override public PyObject __call__(PyObject other) { return isEqual(other).__not__().__and__(Py.newBoolean(isSubset(other))); @@ -358,6 +363,7 @@ } private static final SetMethod gtProxy = new SetMethod("__gt__", 1) { + @Override public PyObject __call__(PyObject other) { return isEqual(other).__not__().__and__(Py.newBoolean(isSuperset(other))); @@ -365,28 +371,34 @@ }; private static final SetMethod isDisjointProxy = new SetMethod("isdisjoint", 1) { + @Override public PyObject __call__(PyObject other) { - return Py.newBoolean(intersect(new Collection[]{getJavaCollection(other)}).size() == 0); + Collection[] otherJava = new Collection[] {getJavaCollection(other)}; + return Py.newBoolean(intersect(otherJava).size() == 0); } }; private static final SetMethod differenceProxy = new SetMethodVarargs("difference") { + @Override public PyObject __call__(PyObject[] others) { return makePySet(difference(getCombinedJavaCollections(others))); } }; - private static final SetMethod differenceUpdateProxy = new SetMethodVarargs("difference_update") { - @Override - public PyObject __call__(PyObject[] others) { - differenceUpdate(getCombinedJavaCollections(others)); - return Py.None; - } - }; + private static final SetMethod differenceUpdateProxy = + new SetMethodVarargs("difference_update") { + + @Override + public PyObject __call__(PyObject[] others) { + differenceUpdate(getCombinedJavaCollections(others)); + return Py.None; + } + }; private static final SetMethod subProxy = new SetMethod("__sub__", 1) { + @Override public PyObject __call__(PyObject other) { return makePySet(difference(getJavaSet(self, "-", other))); @@ -394,6 +406,7 @@ }; private static final SetMethod isubProxy = new SetMethod("__isub__", 1) { + @Override public PyObject __call__(PyObject other) { differenceUpdate(getJavaSet(self, "-=", other)); @@ -402,51 +415,60 @@ }; private static final SetMethod intersectionProxy = new SetMethodVarargs("intersection") { + @Override public PyObject __call__(PyObject[] others) { return makePySet(intersect(getJavaCollections(others))); } }; - private static final SetMethod intersectionUpdateProxy = new SetMethodVarargs("intersection_update") { - @Override - public PyObject __call__(PyObject[] others) { - intersectUpdate(getJavaCollections(others)); - return Py.None; - } - }; + private static final SetMethod intersectionUpdateProxy = + new SetMethodVarargs("intersection_update") { + + @Override + public PyObject __call__(PyObject[] others) { + intersectUpdate(getJavaCollections(others)); + return Py.None; + } + }; private static final SetMethod andProxy = new SetMethod("__and__", 1) { + @Override public PyObject __call__(PyObject other) { - return makePySet(intersect(new Collection[]{getJavaSet(self, "&", other)})); + return makePySet(intersect(new Collection[] {getJavaSet(self, "&", other)})); } }; private static final SetMethod iandProxy = new SetMethod("__iand__", 1) { + @Override public PyObject __call__(PyObject other) { - intersectUpdate(new Collection[]{getJavaSet(self, "&=", other)}); + intersectUpdate(new Collection[] {getJavaSet(self, "&=", other)}); return self; } }; private static final SetMethod symDiffProxy = new SetMethod("symmetric_difference", 1) { + @Override public PyObject __call__(PyObject other) { return makePySet(symDiff(getJavaCollection(other))); } }; - private static final SetMethod symDiffUpdateProxy = new SetMethod("symmetric_difference_update", 1) { - @Override - public PyObject __call__(PyObject other) { - symDiffUpdate(getJavaCollection(other)); - return Py.None; - } - }; + private static final SetMethod symDiffUpdateProxy = + new SetMethod("symmetric_difference_update", 1) { + + @Override + public PyObject __call__(PyObject other) { + symDiffUpdate(getJavaCollection(other)); + return Py.None; + } + }; private static final SetMethod xorProxy = new SetMethod("__xor__", 1) { + @Override public PyObject __call__(PyObject other) { return makePySet(symDiff(getJavaSet(self, "^", other))); @@ -454,6 +476,7 @@ }; private static final SetMethod ixorProxy = new SetMethod("__ixor__", 1) { + @Override public PyObject __call__(PyObject other) { symDiffUpdate(getJavaSet(self, "^=", other)); @@ -462,6 +485,7 @@ }; private static final SetMethod unionProxy = new SetMethodVarargs("union") { + @Override public PyObject __call__(PyObject[] others) { return makePySet(union(getCombinedJavaCollections(others))); @@ -469,6 +493,7 @@ }; private static final SetMethod updateProxy = new SetMethodVarargs("update") { + @Override public PyObject __call__(PyObject[] others) { update(getCombinedJavaCollections(others)); @@ -477,6 +502,7 @@ }; private static final SetMethod orProxy = new SetMethod("__or__", 1) { + @Override public PyObject __call__(PyObject other) { return makePySet(union(getJavaSet(self, "|", other))); @@ -484,6 +510,7 @@ }; private static final SetMethod iorProxy = new SetMethod("__ior__", 1) { + @Override public PyObject __call__(PyObject other) { update(getJavaSet(self, "|=", other)); @@ -493,9 +520,11 @@ @Untraversable private static class CopyMethod extends SetMethod { + protected CopyMethod(String name) { super(name, 0); } + @Override public PyObject __call__() { return makePySet(asSet()); @@ -503,6 +532,7 @@ } private static final SetMethod deepcopyOverrideProxy = new SetMethod("__deepcopy__", 1) { + @Override public PyObject __call__(PyObject memo) { Set newSet = new HashSet<>(); @@ -516,6 +546,7 @@ }; private static final SetMethod reduceProxy = new SetMethod("__reduce__", 0) { + @Override public PyObject __call__() { PyObject args = new PyTuple(new PyList(new JavaIterator(asSet()))); @@ -528,20 +559,24 @@ }; private static final SetMethod containsProxy = new SetMethod("__contains__", 1) { + @Override public PyObject __call__(PyObject value) { return Py.newBoolean(asSet().contains(value.__tojava__(Object.class))); } }; private static final SetMethod hashProxy = new SetMethod("__hash__", 0) { + // in general, we don't know if this is really true or not @Override public PyObject __call__(PyObject value) { - throw Py.TypeError(String.format("unhashable type: '%.200s'", self.getType().fastGetName())); + throw Py.TypeError( + String.format("unhashable type: '%.200s'", self.getType().fastGetName())); } }; private static final SetMethod discardProxy = new SetMethod("discard", 1) { + @Override public PyObject __call__(PyObject value) { asSet().remove(value.__tojava__(Object.class)); @@ -549,6 +584,7 @@ } }; private static final SetMethod popProxy = new SetMethod("pop", 0) { + @Override public PyObject __call__() { Set selfSet = asSet(); @@ -568,6 +604,7 @@ } }; private static final SetMethod removeOverrideProxy = new SetMethod("remove", 1) { + @Override public PyObject __call__(PyObject value) { boolean removed = asSet().remove(value.__tojava__(Object.class)); @@ -579,6 +616,7 @@ }; static PyBuiltinMethod[] getProxyMethods() { + //@formatter:off return new PyBuiltinMethod[]{ cmpProxy, eqProxy, @@ -621,13 +659,16 @@ discardProxy, popProxy }; + //@formatter:on } static PyBuiltinMethod[] getPostProxyMethods() { + //@formatter:off return new PyBuiltinMethod[]{ deepcopyOverrideProxy, removeOverrideProxy }; + //@formatter:on } } -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Sun Feb 2 02:27:39 2020 From: jython-checkins at python.org (jeff.allen) Date: Sun, 02 Feb 2020 07:27:39 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Establish_java_environment?= =?utf-8?q?_in_test=5Fjython=5Finitializer_=28fixes_=232810=29?= Message-ID: <20200202072739.1.A88BED6E9A12B1CB@mg.python.org> https://hg.python.org/jython/rev/6d3659465010 changeset: 8326:6d3659465010 user: Adam Burke date: Sat Feb 01 16:06:08 2020 +0000 summary: Establish java environment in test_jython_initializer (fixes #2810) This change addresses a test failure observed in test_jython_initializer where the build Java is ahead of the default installed Java. We "inherit" java.home in the otherwise-stripped environment. files: Lib/test/test_jython_initializer.py | 1 + NEWS | 1 + 2 files changed, 2 insertions(+), 0 deletions(-) diff --git a/Lib/test/test_jython_initializer.py b/Lib/test/test_jython_initializer.py --- a/Lib/test/test_jython_initializer.py +++ b/Lib/test/test_jython_initializer.py @@ -12,6 +12,7 @@ fn = test_support.findfile('check_for_initializer_in_syspath.py') jar = test_support.findfile('syspath_initializer.jar') env = dict(CLASSPATH=jar, + JAVA_HOME=sys.registry['java.home'], PATH=os.environ.get('PATH', '')) if WINDOWS: diff --git a/NEWS b/NEWS --- a/NEWS +++ b/NEWS @@ -8,6 +8,7 @@ Jython 2.7.2b3 Bugs fixed + - [ 2810 ] NoSuchMethodError in test_jython_initializer (Java 10+) - [ 2808 ] lib2to3 test failures on Windows JDK 11 - [ 2846 ] Main module __name __ is not "__main__" under Java Scripting API - [ 2828 ] Update netty JARs to 4.1.45 -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Sun Feb 2 02:27:38 2020 From: jython-checkins at python.org (jeff.allen) Date: Sun, 02 Feb 2020 07:27:38 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Resolve_CRLF_line-endings_?= =?utf-8?q?in_updated_lib2to3_test=5Fparser_=28fixes_=232808=29?= Message-ID: <20200202072738.1.4F652FFFA91E9EAD@mg.python.org> https://hg.python.org/jython/rev/e81878891a4b changeset: 8325:e81878891a4b user: Adam Burke date: Sat Feb 01 14:40:32 2020 +0000 summary: Resolve CRLF line-endings in updated lib2to3 test_parser (fixes #2808) This change updates lib2to3 tests from the CPython stdlib, skipping where necessary. Rather than call out to the shell for diff (fails on Windows) we use a comparison function in Python, being careful to choose the mode rbU to deal with CRLF line endings. files: Lib/lib2to3/tests/test_parser.py | 185 ++++++++++++++++++- NEWS | 1 + 2 files changed, 178 insertions(+), 8 deletions(-) diff --git a/Lib/lib2to3/tests/test_parser.py b/Lib/lib2to3/tests/test_parser.py --- a/Lib/lib2to3/tests/test_parser.py +++ b/Lib/lib2to3/tests/test_parser.py @@ -11,12 +11,23 @@ # Testing imports from . import support from .support import driver, test_dir +from test import test_support + # Python imports +import binascii +import operator import os +import pickle +import shutil +import subprocess import sys +import tempfile +import types +import unittest # Local imports +from lib2to3.pgen2 import driver as pgen2_driver from lib2to3.pgen2 import tokenize from ..pgen2.parse import ParseError from lib2to3.pygram import python_symbols as syms @@ -31,6 +42,86 @@ self.assertEqual(t.children[1].children[0].type, syms.print_stmt) +class TestPgen2Caching(support.TestCase): + def test_load_grammar_from_txt_file(self): + pgen2_driver.load_grammar(support.grammar_path, save=False, force=True) + + @unittest.skipIf(test_support.is_jython, "Not a valid test for Jython") + def test_load_grammar_from_pickle(self): + # Make a copy of the grammar file in a temp directory we are + # guaranteed to be able to write to. + tmpdir = tempfile.mkdtemp() + try: + grammar_copy = os.path.join( + tmpdir, os.path.basename(support.grammar_path)) + shutil.copy(support.grammar_path, grammar_copy) + pickle_name = pgen2_driver._generate_pickle_name(grammar_copy) + + pgen2_driver.load_grammar(grammar_copy, save=True, force=True) + self.assertTrue(os.path.exists(pickle_name)) + + os.unlink(grammar_copy) # Only the pickle remains... + pgen2_driver.load_grammar(grammar_copy, save=False, force=False) + finally: + shutil.rmtree(tmpdir) + + @unittest.skipIf(test_support.is_jython, "Not a valid test for Jython") + @unittest.skipIf(sys.executable is None, 'sys.executable required') + def test_load_grammar_from_subprocess(self): + tmpdir = tempfile.mkdtemp() + tmpsubdir = os.path.join(tmpdir, 'subdir') + try: + os.mkdir(tmpsubdir) + grammar_base = os.path.basename(support.grammar_path) + grammar_copy = os.path.join(tmpdir, grammar_base) + grammar_sub_copy = os.path.join(tmpsubdir, grammar_base) + shutil.copy(support.grammar_path, grammar_copy) + shutil.copy(support.grammar_path, grammar_sub_copy) + pickle_name = pgen2_driver._generate_pickle_name(grammar_copy) + pickle_sub_name = pgen2_driver._generate_pickle_name( + grammar_sub_copy) + self.assertNotEqual(pickle_name, pickle_sub_name) + + # Generate a pickle file from this process. + pgen2_driver.load_grammar(grammar_copy, save=True, force=True) + self.assertTrue(os.path.exists(pickle_name)) + + # Generate a new pickle file in a subprocess with a most likely + # different hash randomization seed. + sub_env = dict(os.environ) + sub_env['PYTHONHASHSEED'] = 'random' + subprocess.check_call( + [sys.executable, '-c', """ +from lib2to3.pgen2 import driver as pgen2_driver +pgen2_driver.load_grammar(%r, save=True, force=True) + """ % (grammar_sub_copy,)], + env=sub_env) + self.assertTrue(os.path.exists(pickle_sub_name)) + + with open(pickle_name, 'rb') as pickle_f_1, \ + open(pickle_sub_name, 'rb') as pickle_f_2: + self.assertEqual( + pickle_f_1.read(), pickle_f_2.read(), + msg='Grammar caches generated using different hash seeds' + ' were not identical.') + finally: + shutil.rmtree(tmpdir) + + @unittest.skipIf(test_support.is_jython, "Not a valid test for Jython") + def test_load_packaged_grammar(self): + modname = __name__ + '.load_test' + class MyLoader: + def get_data(self, where): + return pickle.dumps({'elephant': 19}) + class MyModule(types.ModuleType): + __file__ = 'parsertestmodule' + __loader__ = MyLoader() + sys.modules[modname] = MyModule(modname) + self.addCleanup(operator.delitem, sys.modules, modname) + g = pgen2_driver.load_packaged_grammar(modname, 'Grammar.txt') + self.assertEqual(g.elephant, 19) + + class GrammarTest(support.TestCase): def validate(self, code): support.parse_string(code) @@ -44,6 +135,21 @@ raise AssertionError("Syntax shouldn't have been valid") +class TestMatrixMultiplication(GrammarTest): + @unittest.skipIf(test_support.is_jython, "Not supported yet") + def test_matrix_multiplication_operator(self): + self.validate("a @ b") + self.validate("a @= b") + + +class TestYieldFrom(GrammarTest): + @unittest.skipIf(test_support.is_jython, "Not supported yet") + def test_matrix_multiplication_operator(self): + self.validate("yield from x") + self.validate("(yield from x) + y") + self.invalid_syntax("yield from") + + class TestRaiseChanges(GrammarTest): def test_2x_style_1(self): self.validate("raise") @@ -72,8 +178,48 @@ def test_3x_style_invalid_4(self): self.invalid_syntax("raise E from") +# Modelled after Lib/test/test_grammar.py:TokenTests.test_funcdef issue2292 +# and Lib/test/text_parser.py test_list_displays, test_set_displays, +# test_dict_displays, test_argument_unpacking, ... changes. +class TestUnpackingGeneralizations(GrammarTest): + def test_mid_positional_star(self): + self.validate("""func(1, *(2, 3), 4)""") -# Adapated from Python 3's Lib/test/test_grammar.py:GrammarTests.testFuncdef + def test_double_star_dict_literal(self): + self.validate("""func(**{'eggs':'scrambled', 'spam':'fried'})""") + + def test_double_star_dict_literal_after_keywords(self): + self.validate("""func(spam='fried', **{'eggs':'scrambled'})""") + + def test_list_display(self): + self.validate("""[*{2}, 3, *[4]]""") + + @unittest.skipIf(test_support.is_jython, "No Jython support yet") + def test_set_display(self): + self.validate("""{*{2}, 3, *[4]}""") + + @unittest.skipIf(test_support.is_jython, "No Jython support yet") + def test_dict_display_1(self): + self.validate("""{**{}}""") + + @unittest.skipIf(test_support.is_jython, "No Jython support yet") + def test_dict_display_2(self): + self.validate("""{**{}, 3:4, **{5:6, 7:8}}""") + + @unittest.skipIf(test_support.is_jython, "No Jython support yet") + def test_argument_unpacking_1(self): + self.validate("""f(a, *b, *c, d)""") + + @unittest.skipIf(test_support.is_jython, "No Jython support yet") + def test_argument_unpacking_2(self): + self.validate("""f(**a, **b)""") + + @unittest.skipIf(test_support.is_jython, "No Jython support yet") + def test_argument_unpacking_3(self): + self.validate("""f(2, *a, *b, **b, **c, **d)""") + + +# Adaptated from Python 3's Lib/test/test_grammar.py:GrammarTests.testFuncdef class TestFunctionAnnotations(GrammarTest): def test_1(self): self.validate("""def f(x) -> list: pass""") @@ -162,15 +308,17 @@ for filepath in support.all_project_files(): with open(filepath, "rb") as fp: encoding = tokenize.detect_encoding(fp.readline)[0] - self.assertTrue(encoding is not None, - "can't detect encoding for %s" % filepath) + self.assertIsNotNone(encoding, + "can't detect encoding for %s" % filepath) with open(filepath, "r") as fp: source = fp.read() source = source.decode(encoding) tree = driver.parse_string(source) new = unicode(tree) - if diff(filepath, new, encoding): - self.fail("Idempotency failed: %s" % filepath) + diffResult = diff(filepath, new, encoding) + if diffResult: + self.fail("Idempotency failed: {} using {} encoding\n{}". + format(filepath,encoding,diffResult) ) def test_extended_unpacking(self): driver.parse_string("a, *b, c = x\n") @@ -212,12 +360,33 @@ self.validate(s) + def diff(fn, result, encoding): - "A diff the result and original file content independent of OS." + """Diff the result and original file content independent of OS. This + implementation is in Jython only. CPython 2.x calls out to the shell diff + command. CPython 3.x str equality behaviour is simpler and should allow + this test file to be replaced wholesale in Jython 3.x.""" r = iter(result.encode(encoding).splitlines(True)) - with open(fn, "rb") as f: + lineNumber = 0 + with open(fn, "rbU") as f: for line in f: + lineNumber += 1 rline = next(r) if rline != line: - return True + return "original line {}:\n{}\n differs from:\n{}\n{}". \ + format(lineNumber, line, rline, diffLine(line, rline) ) return False + +def diffLine(orig,result): + charNumber = 0 + for c in orig: + if c != result[charNumber]: + return "Lines differ at char {}: {} vs {} (of {} vs {})".format( + charNumber, + binascii.hexlify(c), + binascii.hexlify(result[charNumber]), + len(orig), + len(result) ) + charNumber += 1 + + diff --git a/NEWS b/NEWS --- a/NEWS +++ b/NEWS @@ -8,6 +8,7 @@ Jython 2.7.2b3 Bugs fixed + - [ 2808 ] lib2to3 test failures on Windows JDK 11 - [ 2846 ] Main module __name __ is not "__main__" under Java Scripting API - [ 2828 ] Update netty JARs to 4.1.45 - [ 2044 ] CVE-2013-2027 Current umask sets privileges of class files and cache -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Sun Feb 2 10:18:09 2020 From: jython-checkins at python.org (jeff.allen) Date: Sun, 02 Feb 2020 15:18:09 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Added_tag_v2=2E7=2E2b3_for?= =?utf-8?q?_changeset_6d3659465010?= Message-ID: <20200202151809.1.F231766701A3FC53@mg.python.org> https://hg.python.org/jython/rev/e7e08b7cd19d changeset: 8327:e7e08b7cd19d user: Jeff Allen date: Sun Feb 02 11:24:08 2020 +0000 summary: Added tag v2.7.2b3 for changeset 6d3659465010 files: .hgtags | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/.hgtags b/.hgtags --- a/.hgtags +++ b/.hgtags @@ -112,3 +112,4 @@ dfc49bafbe79566bd54c8d417829e001ff2316ea v2.7.2a1 328e162ec1178fb38b81b342f84c1268bf21d7fb v2.7.2b1 b9b60766cabebf007b7584ec21a69b3f58587525 v2.7.2b2 +6d3659465010fd2a8fb11a93953bae5bf9e9db80 v2.7.2b3 -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Sun Feb 23 10:13:31 2020 From: jython-checkins at python.org (jeff.allen) Date: Sun, 23 Feb 2020 15:13:31 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Allow_source-last-modified?= =?utf-8?q?_!=3D_=24py=2Eclass_mtime_=28addresses_=232862=29?= Message-ID: <20200223151331.1.ACCC619F03C9D56A@mg.python.org> https://hg.python.org/jython/rev/2a77fdc4417c changeset: 8329:2a77fdc4417c user: Jeff Allen date: Fri Feb 21 08:32:01 2020 +0000 summary: Allow source-last-modified != $py.class mtime (addresses #2862) We allow up to 2 seconds discrepancy in the logic that decides whether to re-compile .py source to $py.class files. This is to accommodate the rounding of last-modified time that occurs when storing and extracting files from a JAR, as during installation. We choose to round times down when JARring and allow 2 seconds positive difference in the check. This has benefits beyond #2862, in avoiding spurious recompilation, so is made a distinct commit. At the same time the implications of #2862 are arguably not addressed fully until the JAR cache is made user-local. files: Lib/test/test_import.py | 4 +- build.xml | 2 +- installer/src/java/org/python/util/install/JarInstaller.java | 9 ++-- src/org/python/core/imp.java | 17 ++++++++- 4 files changed, 22 insertions(+), 10 deletions(-) diff --git a/Lib/test/test_import.py b/Lib/test/test_import.py --- a/Lib/test/test_import.py +++ b/Lib/test/test_import.py @@ -142,9 +142,9 @@ # Write a Python file, make it read-only and import it with open(fname, 'w') as f: f.write("x = 'original'\n") - # Tweak the mtime of the source to ensure pyc gets updated later + # Tweak the mtime of the source 10s later to ensure compiled looks out of date s = os.stat(fname) - os.utime(fname, (s.st_atime, s.st_mtime-100000000)) + os.utime(fname, (s.st_atime, s.st_mtime+10000)) os.chmod(fname, 0400) m1 = __import__(TESTFN) self.assertEqual(m1.x, 'original') diff --git a/build.xml b/build.xml --- a/build.xml +++ b/build.xml @@ -1190,7 +1190,7 @@ building installer .jar file - + diff --git a/installer/src/java/org/python/util/install/JarInstaller.java b/installer/src/java/org/python/util/install/JarInstaller.java --- a/installer/src/java/org/python/util/install/JarInstaller.java +++ b/installer/src/java/org/python/util/install/JarInstaller.java @@ -49,7 +49,7 @@ *
  • generate the start scripts *
  • run ensurepip if selected * - * + * * @param targetDirectory * @param installationType */ @@ -102,8 +102,9 @@ } } // exclude build.xml when not installing source - if (!installationType.installSources() && zipEntryName.equals("build.xml")) + if (!installationType.installSources() && zipEntryName.equals("build.xml")) { exclude = true; + } // handle exclusion of core Lib files if (!exclude) { exclude = shouldExcludeFile(installationType, @@ -182,9 +183,9 @@ try { String command[]; if (Installation.isWindows()) { - command = new String[]{ bindir.resolve("jython.exe").toString(), "-m", "ensurepip" }; + command = new String[] {bindir.resolve("jython.exe").toString(), "-m", "ensurepip"}; } else { - command = new String[]{ Paths.get(".", "jython").toString(), "-m", "ensurepip"}; + command = new String[] {Paths.get(".", "jython").toString(), "-m", "ensurepip"}; } ChildProcess childProcess = new ChildProcess(command); childProcess.setCWD(bindir); diff --git a/src/org/python/core/imp.java b/src/org/python/core/imp.java --- a/src/org/python/core/imp.java +++ b/src/org/python/core/imp.java @@ -7,6 +7,7 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; +import java.util.Date; import java.util.Map; import java.util.concurrent.locks.ReentrantLock; import java.util.logging.Level; @@ -396,10 +397,16 @@ } } - // Check source-last-modified time fossilised in the class file against that expected + /* + * The source-last-modified time is fossilised in the class file. The source may have been + * installed from a JAR, and this will have resulted in rounding of the last-modified time + * down (see build.xml::jar-sources) to the nearest 2 seconds. + */ if (testing && sourceLastModified != NO_MTIME) { - long mtime = ar.getMTime(); - if (sourceLastModified != mtime) { + long diff = ar.getMTime() - sourceLastModified; + if (diff > 2000L) { // = 2000 milliseconds + logger.log(Level.FINE, "# {0} time is {1} ms later than source", + new Object[] {name, diff}); return null; } } @@ -925,6 +932,10 @@ if (ret != null) { return ret; } + } else { + logger.log(Level.FINE, + "# {0} dated ({1,date} {1,time,long}) < ({2,date} {2,time,long})", + new Object[] {name, new Date(classTime), new Date(pyTime)}); } } -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Sun Feb 23 10:13:31 2020 From: jython-checkins at python.org (jeff.allen) Date: Sun, 23 Feb 2020 15:13:31 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Relocate_cache_to_working_?= =?utf-8?q?directory_=28fixes_=232862=29?= Message-ID: <20200223151331.1.BC8A34C8AF5A2555@mg.python.org> https://hg.python.org/jython/rev/33ea06302061 changeset: 8330:33ea06302061 user: Jeff Allen date: Sun Feb 23 13:50:18 2020 +0000 summary: Relocate cache to working directory (fixes #2862) We no longer try to cache every user's JARs in the installation directory, ineffective since fix of #2044. Behaviour for applications that set an absolute location (or skip) is unchanged. files: .gitignore | 1 + .hgignore | 1 + Lib/test/test_httpservers.py | 5 +---- NEWS | 5 ++++- build.xml | 9 +++++++-- registry | 6 ++++-- src/org/python/core/PySystemState.java | 6 ++++-- 7 files changed, 22 insertions(+), 11 deletions(-) diff --git a/.gitignore b/.gitignore --- a/.gitignore +++ b/.gitignore @@ -39,6 +39,7 @@ build build2 cachedir +.jython_cache dist target diff --git a/.hgignore b/.hgignore --- a/.hgignore +++ b/.hgignore @@ -35,6 +35,7 @@ build build2 cachedir +.jython_cache dist publications reports diff --git a/Lib/test/test_httpservers.py b/Lib/test/test_httpservers.py --- a/Lib/test/test_httpservers.py +++ b/Lib/test/test_httpservers.py @@ -417,10 +417,7 @@ os.chdir(self.cwd) if self.pythonexe != sys.executable: os.remove(self.pythonexe) - os.remove(self.file1_path) - os.remove(self.file2_path) - os.rmdir(self.cgi_dir) - os.rmdir(self.parent_dir) + test_support.rmtree(self.parent_dir) finally: BaseTestCase.tearDown(self) diff --git a/NEWS b/NEWS --- a/NEWS +++ b/NEWS @@ -8,7 +8,7 @@ Jython 2.7.2b4 Bugs fixed - + - [ 2862 ] Jython fails on Linux for normal user when installed by root Jython 2.7.2b3 Bugs fixed @@ -122,6 +122,9 @@ - There is much improved support for locale, but as a backward-incompatible change, it is provided as an opt-in. Define property python.locale.control=settable on the command line or via the Jython registry, to enable. This may become the default in a later version. + - The default location of the Jython package cache has moved from the installation directory + to the current working directory and called ".jython_cache". Previously, Jython installed + system-wide either exposed the cache as world read-write (a security risk) or disabled it. Jython 2.7.2a1 Bugs fixed diff --git a/build.xml b/build.xml --- a/build.xml +++ b/build.xml @@ -157,6 +157,9 @@ + + + @@ -413,12 +416,14 @@ + + - + @@ -428,7 +433,7 @@ - + diff --git a/registry b/registry --- a/registry +++ b/registry @@ -15,8 +15,8 @@ # Set the directory to use for caches (currently just package information) # This directory should be writable by the user. If this is an absolute path it is used as given, -# otherwise it is interpreted relative to sys.prefix (typically the directory of this file). -python.cachedir = cachedir +# otherwise it is interpreted relative to the current working directory (at initialisation). +#python.cachedir = .jython_cache # Setting this property to true disables the package scan for the cachedir. # Please be aware that disabling this will break importing * from java packages @@ -24,6 +24,7 @@ # Properties to check for initializing and updating the package cache # Values shown here are those hard-coded in Jython's cache manager. + # Treat JARs on the classpath and (up to Java 8) in the JRE as a source of Python packages. #python.packages.paths = java.class.path, sun.boot.class.path # up to Java 8 #python.packages.paths = java.class.path # from Java 9 @@ -31,6 +32,7 @@ #python.packages.directories = java.ext.dirs # up to Java 8 #python.packages.directories # undefined from Java 9 + # DEPRECATED way to set the verbosity of messages output by Jython. If # specified, "python.verbose" will set logging level for "org.python" when # the runtime is initialised. It is better to use java.util.logging 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 @@ -62,7 +62,7 @@ private static final Logger logger = Logger.getLogger("org.python.core"); - protected static final String CACHEDIR_DEFAULT_NAME = "cachedir"; + private static final String CACHEDIR_DEFAULT_NAME = ".jython_cache"; public static final String JYTHON_JAR = "jython.jar"; public static final String JYTHON_DEV_JAR = "jython-dev.jar"; @@ -1270,9 +1270,11 @@ } cachedir = new File(props.getProperty(PYTHON_CACHEDIR, CACHEDIR_DEFAULT_NAME)); if (!cachedir.isAbsolute()) { - String prefixString = Py.fileSystemDecode(prefix); + String prefixString = props.getProperty("user.dir", ""); cachedir = new File(prefixString, cachedir.getPath()); + cachedir = cachedir.getAbsoluteFile(); } + logger.log(Level.CONFIG, "cache at {0}", cachedir); } private static void initPackages(Properties props) { -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Sun Feb 23 10:13:31 2020 From: jython-checkins at python.org (jeff.allen) Date: Sun, 23 Feb 2020 15:13:31 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Begin_to_identify_as_Jytho?= =?utf-8?q?n_2=2E7=2E2b4=2E?= Message-ID: <20200223151331.1.407E2F24A6315F8C@mg.python.org> https://hg.python.org/jython/rev/96bb13434427 changeset: 8328:96bb13434427 user: Jeff Allen date: Mon Feb 03 22:37:12 2020 +0000 summary: Begin to identify as Jython 2.7.2b4. files: NEWS | 4 ++++ build.gradle | 2 +- build.xml | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/NEWS b/NEWS --- a/NEWS +++ b/NEWS @@ -6,6 +6,10 @@ For more details of issue [ n ], please see https://hg.python.org/jython, or for tags [ GH-n ] see https://github.com/jythontools/jython +Jython 2.7.2b4 + Bugs fixed + + Jython 2.7.2b3 Bugs fixed - [ 2810 ] NoSuchMethodError in test_jython_initializer (Java 10+) diff --git a/build.gradle b/build.gradle --- a/build.gradle +++ b/build.gradle @@ -45,7 +45,7 @@ // Versions are specified in this grammar: // . ( . )? ( )? ( - )? -version = '2.7.2b3' +version = '2.7.2b4' // Valid examples (please preserve in comments): //version = '2.7.2a2' diff --git a/build.xml b/build.xml --- a/build.xml +++ b/build.xml @@ -109,7 +109,7 @@ - + -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Sun Feb 23 16:36:23 2020 From: jython-checkins at python.org (jeff.allen) Date: Sun, 23 Feb 2020 21:36:23 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Bouncy_Castle_JARs_work-ar?= =?utf-8?q?ound_=28docs-only_response_to_=232858=29?= Message-ID: <20200223213623.1.0559F208F0F9E106@mg.python.org> https://hg.python.org/jython/rev/941001c49dd3 changeset: 8332:941001c49dd3 user: Jeff Allen date: Sun Feb 23 17:46:57 2020 +0000 summary: Bouncy Castle JARs work-around (docs-only response to #2858) Shading the Bouncy Castle classes in our JAR makes them untrusted as a security provider. We document that to work around this, users provide the JARs directly. files: NEWS | 8 +++++++- 1 files changed, 7 insertions(+), 1 deletions(-) diff --git a/NEWS b/NEWS --- a/NEWS +++ b/NEWS @@ -8,6 +8,7 @@ Jython 2.7.2b4 Bugs fixed + - [ 2858 ] test_ssl failure due to embedding Bouncy Castle (doc change only) - [ GH-156 ] Race condition in PyStringMap keys method - [ 2862 ] Jython fails on Linux for normal user when installed by root @@ -124,8 +125,13 @@ provided as an opt-in. Define property python.locale.control=settable on the command line or via the Jython registry, to enable. This may become the default in a later version. - The default location of the Jython package cache has moved from the installation directory - to the current working directory and called ".jython_cache". Previously, Jython installed + to the current working directory and is called ".jython_cache". Previously, Jython installed system-wide either exposed the cache as world read-write (a security risk) or disabled it. + - BouncyCastle SSL support is incomplete as bundled. The Jython JAR is not signed, and may not + be trusted by your JVM as a security provider. This manifests as a PEMException: "Unable to + create OpenSSL PBDKF: PBKDF-OpenSSL SecretKeyFactory not available" during certain + operations. If this is a problem, place genuine BouncyCastle JARs on the class path, and + Jython will use those in preference to the classes we include. The slim JAR is not affected. Jython 2.7.2a1 Bugs fixed -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Sun Feb 23 16:36:23 2020 From: jython-checkins at python.org (jeff.allen) Date: Sun, 23 Feb 2020 21:36:23 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Avoid_deprecation_warnings?= =?utf-8?q?_=28and_other_tidying_up=29?= Message-ID: <20200223213623.1.F638DE33D2C46C69@mg.python.org> https://hg.python.org/jython/rev/6c6c57ca6320 changeset: 8333:6c6c57ca6320 user: Jeff Allen date: Sun Feb 23 20:56:43 2020 +0000 summary: Avoid deprecation warnings (and other tidying up) files: src/org/python/core/packagecache/CachedJarsPackageManager.java | 24 ++++----- src/org/python/expose/generate/ExposeTask.java | 11 +---- src/org/python/modules/posix/PythonPOSIXHandler.java | 16 ++++++- 3 files changed, 26 insertions(+), 25 deletions(-) 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 @@ -841,24 +841,20 @@ * before {@link #initCache}. cachedir is the cache repository directory, this is eventually * created. Returns true if dir works. */ - protected boolean useCacheDir(File aCachedir1) { - - if (aCachedir1 == null) { - return false; - } - + protected boolean useCacheDir(File cachedir) { try { - if (!aCachedir1.isDirectory() && aCachedir1.mkdirs() == false) { - warning("failed to create cache dir ''{0}''", aCachedir1); - return false; + if (cachedir != null) { + if (cachedir.isDirectory() || cachedir.mkdirs()) { + this.cachedir = cachedir; + return true; + } else { + warning("failed to create cache dir ''{0}''", cachedir); + } } } catch (AccessControlException ace) { - warning("Not permitted to access cache ''{0}'' ({1})", aCachedir1, ace.getMessage()); - return false; + warning("Not permitted to access cache ''{0}'' ({1})", cachedir, ace.getMessage()); } - - this.cachedir = aCachedir1; - return true; + return false; } } diff --git a/src/org/python/expose/generate/ExposeTask.java b/src/org/python/expose/generate/ExposeTask.java --- a/src/org/python/expose/generate/ExposeTask.java +++ b/src/org/python/expose/generate/ExposeTask.java @@ -8,8 +8,6 @@ import org.apache.tools.ant.BuildException; import org.objectweb.asm.ClassWriter; -import org.python.core.Py; -import org.python.core.Options; import org.python.util.GlobMatchingTask; public class ExposeTask extends GlobMatchingTask { @@ -32,14 +30,7 @@ log("Exposing 1 class"); } - // Quiet harmless unbootstrapped warnings during the expose process - int verbose = Options.verbose; - Options.verbose = Py.ERROR; - try { - expose(toExpose); - } finally { - Options.verbose = verbose; - } + expose(toExpose); } private void expose(Set toExpose) { diff --git a/src/org/python/modules/posix/PythonPOSIXHandler.java b/src/org/python/modules/posix/PythonPOSIXHandler.java --- a/src/org/python/modules/posix/PythonPOSIXHandler.java +++ b/src/org/python/modules/posix/PythonPOSIXHandler.java @@ -4,12 +4,14 @@ import java.io.File; import java.io.InputStream; import java.io.PrintStream; +import java.util.logging.Level; import jnr.constants.platform.Errno; import jnr.posix.POSIXHandler; import org.python.core.imp; import org.python.core.Options; +import org.python.core.PrePy; import org.python.core.Py; import org.python.core.PyObject; @@ -19,14 +21,17 @@ */ public class PythonPOSIXHandler implements POSIXHandler { + @Override public void error(Errno error, String extraData) { throw Py.OSError(error, Py.newStringOrUnicode(extraData)); } + @Override public void error(Errno error, String methodName, String extraData) { throw Py.OSError(error, Py.newStringOrUnicode(extraData)); } + @Override public void unimplementedError(String methodName) { if (methodName.startsWith("stat.")) { // Ignore unimplemented FileStat methods @@ -35,17 +40,22 @@ throw Py.NotImplementedError(methodName); } + @Override public void warn(WARNING_ID id, String message, Object... data) { } + @Override public boolean isVerbose() { - return Options.verbose >= Py.DEBUG; + // Verbose if the general threshold for logging is FINE or lower. + return PrePy.getLoggingLevel().intValue() <= Level.FINE.intValue(); } + @Override public File getCurrentWorkingDirectory() { return new File(Py.getSystemState().getCurrentWorkingDir()); } + @Override public String[] getEnv() { PyObject items = imp.load("os").__getattr__("environ").invoke("items"); String[] env = new String[items.__len__()]; @@ -56,18 +66,22 @@ return env; } + @Override public InputStream getInputStream() { return System.in; } + @Override public PrintStream getOutputStream() { return System.out; } + @Override public int getPID() { return 0; } + @Override public PrintStream getErrorStream() { return System.err; } -- Repository URL: https://hg.python.org/jython From jython-checkins at python.org Sun Feb 23 16:36:23 2020 From: jython-checkins at python.org (jeff.allen) Date: Sun, 23 Feb 2020 21:36:23 +0000 Subject: [Jython-checkins] =?utf-8?q?jython=3A_Fix_race_condition_in_PySt?= =?utf-8?q?ringMap_keys_method_=5BGH-156=5D?= Message-ID: <20200223213623.1.6ED8EA0E0178250A@mg.python.org> https://hg.python.org/jython/rev/57e47c817d26 changeset: 8331:57e47c817d26 user: Peter Holloway date: Sun Feb 23 16:09:30 2020 +0000 summary: Fix race condition in PyStringMap keys method [GH-156] If the map was modified during a call to keys(), the keyset would change size and cause an ArrayIndexOutOfBoundsException. This creates a copy of the keyset and uses that throughout the method. files: NEWS | 1 + src/org/python/core/PyStringMap.java | 5 +++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/NEWS b/NEWS --- a/NEWS +++ b/NEWS @@ -8,6 +8,7 @@ Jython 2.7.2b4 Bugs fixed + - [ GH-156 ] Race condition in PyStringMap keys method - [ 2862 ] Jython fails on Linux for normal user when installed by root Jython 2.7.2b3 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 @@ -637,9 +637,10 @@ @ExposedMethod(doc = BuiltinDocs.dict_keys_doc) final PyList stringmap_keys() { - PyObject[] keyArray = new PyObject[table.size()]; + Object[] keys = table.keySet().toArray(); + PyObject[] keyArray = new PyObject[keys.length]; int i = 0; - for (Object key : table.keySet()) { + for (Object key : keys) { keyArray[i++] = keyToPy(key); } return new PyList(keyArray); -- Repository URL: https://hg.python.org/jython