From: <zy...@us...> - 2010-06-16 14:46:41
|
Revision: 7066 http://jython.svn.sourceforge.net/jython/?rev=7066&view=rev Author: zyasoft Date: 2010-06-16 14:46:34 +0000 (Wed, 16 Jun 2010) Log Message: ----------- Reflected method fixes: Fixes #1605 by having PyComplex#__tojava__ refuse to convert to anything but itself (restores old behavior before adding support for faux floats) Fixes #1615 by supporting varargs Java methods, so that a method marked as test(String...) can be called as either test("abc", "xyz") or, because it's reasonable in Java, test(["abc", "xyz"]) Modified Paths: -------------- trunk/jython/Lib/test/test_joverload.py trunk/jython/NEWS trunk/jython/src/org/python/core/PyComplex.java trunk/jython/src/org/python/core/PyReflectedFunction.java trunk/jython/src/org/python/core/ReflectedArgs.java Added Paths: ----------- trunk/jython/tests/java/javatests/Reflection.java Modified: trunk/jython/Lib/test/test_joverload.py =================================================================== --- trunk/jython/Lib/test/test_joverload.py 2010-06-15 06:34:16 UTC (rev 7065) +++ trunk/jython/Lib/test/test_joverload.py 2010-06-16 14:46:34 UTC (rev 7066) @@ -3,9 +3,12 @@ # (can be adapted to test alternative re-implemations even while they are developed # write a *Envl class and change/add to to_test for that) +import sys import unittest import java +from java.util import ArrayList +from javatests import JOverload, Reflection from org.python.core import PyReflectedFunction class PyReflFuncEnvl: @@ -25,7 +28,6 @@ meth_dict[name] = envl_class(name,[ m for m in meths if m.name == name ]) return meth_dict -from javatests import JOverload jo = JOverload() to_test = [extract_ov_meths(JOverload,PyReflFuncEnvl)] @@ -119,11 +121,55 @@ """) +class VarargsDispatchTests(unittest.TestCase): + + def test_strings(self): + t = Reflection.StringVarargs() + self.assertEqual(t.test("abc", "xyz"), + "String...:[abc, xyz]") + self.assertEqual(t.test("abc"), + "String...:[abc]") + self.assertEqual(t.test(), + "String...:[]") + + self.assertEqual(t.test(["abc", "xyz"]), + "String...:[abc, xyz]") + self.assertEqual(t.test(["abc"]), + "String...:[abc]") + self.assertEqual(t.test([]), + "String...:[]") + + + def test_lists(self): + t = Reflection.ListVarargs() + self.assertEqual(t.test(ArrayList([1,2,3]), ArrayList([4,5,6])), + "List...:[[1, 2, 3], [4, 5, 6]]") + self.assertEqual(t.test(ArrayList([1,2,3])), + "List...:[[1, 2, 3]]") + self.assertEqual(t.test(), + "List...:[]") + + self.assertEqual(t.test([ArrayList([1,2,3]), ArrayList([4,5,6])]), + "List...:[[1, 2, 3], [4, 5, 6]]") + self.assertEqual(t.test([ArrayList([1,2,3])]), + "List...:[[1, 2, 3]]") + self.assertEqual(t.test([]), + "List...:[]") + + +class ComplexOverloadingTests(unittest.TestCase): + + def test_complex(self): + o = Reflection.Overloaded() + self.assertEqual(o(2.), "class java.lang.Double=2.0") + self.assertEqual(o(1+2j), "class org.python.core.PyComplex=(1+2j)") + + + def printout(meth_dict,lbl,rng,args): for i in rng: print meth_dict['ov_%s%s' % (lbl,i)](jo,args) -import sys if __name__ == '__main__' and not sys.argv[1:] == ['break-out']: try: @@ -131,4 +177,4 @@ except ImportError: unittest.main() else: - test_support.run_unittest(OverloadedDispatchTests) + test_support.run_unittest(OverloadedDispatchTests, VarargsDispatchTests, ComplexOverloadingTests) Modified: trunk/jython/NEWS =================================================================== --- trunk/jython/NEWS 2010-06-15 06:34:16 UTC (rev 7065) +++ trunk/jython/NEWS 2010-06-16 14:46:34 UTC (rev 7066) @@ -2,6 +2,8 @@ Jython 2.5.2a1 Bugs Fixed + - [ 1615 ] Can't invoke Java method that takes a variable number of arguments with zero arguments + - [ 1605 ] float preference over PyComplex as arg to __call__ breaks logic - [ 1586 ] weakref reference count leak when kwargs are used - [ 1601 ] Can't serialize PyCode object - [ 1551 ] Java objects cannot be copied by the copy module Modified: trunk/jython/src/org/python/core/PyComplex.java =================================================================== --- trunk/jython/src/org/python/core/PyComplex.java 2010-06-15 06:34:16 UTC (rev 7065) +++ trunk/jython/src/org/python/core/PyComplex.java 2010-06-16 14:46:34 UTC (rev 7066) @@ -482,7 +482,17 @@ return _divmod(coerce(left), this).__finditem__(0); } + // Special case __tojava__ for bug 1605, since we broke it with our support for faux floats. + @Override + public Object __tojava__(Class<?> c) { + if (c.isInstance(this)) { + return this; + } + return Py.NoConversion; + } + + @Override public PyObject __truediv__(PyObject right) { return complex___truediv__(right); } Modified: trunk/jython/src/org/python/core/PyReflectedFunction.java =================================================================== --- trunk/jython/src/org/python/core/PyReflectedFunction.java 2010-06-15 06:34:16 UTC (rev 7065) +++ trunk/jython/src/org/python/core/PyReflectedFunction.java 2010-06-16 14:46:34 UTC (rev 7066) @@ -55,9 +55,10 @@ private ReflectedArgs makeArgs(Method m) { return new ReflectedArgs(m, - m.getParameterTypes(), - m.getDeclaringClass(), - Modifier.isStatic(m.getModifiers())); + m.getParameterTypes(), + m.getDeclaringClass(), + Modifier.isStatic(m.getModifiers()), + m.isVarArgs()); } public PyReflectedFunction copy() { Modified: trunk/jython/src/org/python/core/ReflectedArgs.java =================================================================== --- trunk/jython/src/org/python/core/ReflectedArgs.java 2010-06-15 06:34:16 UTC (rev 7065) +++ trunk/jython/src/org/python/core/ReflectedArgs.java 2010-06-16 14:46:34 UTC (rev 7066) @@ -10,6 +10,8 @@ public boolean isStatic; + public boolean isVarArgs; + public int flags; public static final int StandardCall = 0; @@ -19,10 +21,15 @@ public static final int PyArgsKeywordsCall = 2; public ReflectedArgs(Object data, Class<?>[] args, Class<?> declaringClass, boolean isStatic) { + this(data, args, declaringClass, isStatic, false); + } + + public ReflectedArgs(Object data, Class<?>[] args, Class<?> declaringClass, boolean isStatic, boolean isVarArgs) { this.data = data; this.args = args; this.declaringClass = declaringClass; this.isStatic = isStatic; + this.isVarArgs = isVarArgs; // only used for varargs matching; it should be added after the unboxed form if (args.length == 1 && args[0] == PyObject[].class) { this.flags = PyArgsCall; @@ -90,6 +97,38 @@ } int n = this.args.length; + + // if we have a varargs method AND the last PyObject is not a list/tuple + // we need to do box (wrap with an array) the last pyArgs.length - n args + // (which might be empty) + // + // examples: + // test(String... x) + // test(List... x) + // + // in this last example, don't worry if someone is overly clever in calling this, + // they can always write their own version of PyReflectedFunction and put it in the proxy + // if that's what they need to do ;) + + if (isVarArgs) { + if (pyArgs.length == 0 || !(pyArgs[pyArgs.length - 1] instanceof PySequenceList)) { + int non_varargs_len = n - 1; + if (pyArgs.length >= non_varargs_len) { + PyObject[] boxedPyArgs = new PyObject[n]; + for (int i = 0; i < non_varargs_len; i++) { + boxedPyArgs[i] = pyArgs[i]; + } + int varargs_len = pyArgs.length - non_varargs_len; + PyObject[] varargs = new PyObject[varargs_len]; + for (int i = 0; i < varargs_len; i++) { + varargs[i] = pyArgs[non_varargs_len + i]; + } + boxedPyArgs[non_varargs_len] = new PyList(varargs); + pyArgs = boxedPyArgs; + } + } + } + if (pyArgs.length != n) { return false; } @@ -111,8 +150,11 @@ Object[] javaArgs = callData.args; for (int i = 0; i < n; i++) { - if ((javaArgs[i] = pyArgs[i].__tojava__(this.args[i])) == Py.NoConversion) { - // Make error messages clearer + PyObject pyArg = pyArgs[i]; + Class targetClass = this.args[i]; + Object javaArg = pyArg.__tojava__(targetClass); + javaArgs[i] = javaArg; + if (javaArg == Py.NoConversion) { if (i > callData.errArg) { callData.errArg = i; } @@ -253,7 +295,7 @@ @Override public String toString() { - String s = declaringClass + ", " + isStatic + ", " + flags + ", " + data + "\n"; + String s = declaringClass + ", static=" + isStatic + ", varargs=" + isVarArgs + ",flags=" + flags + ", " + data + "\n"; s = s + "\t("; for (Class<?> arg : args) { s += arg.getName() + ", "; Added: trunk/jython/tests/java/javatests/Reflection.java =================================================================== --- trunk/jython/tests/java/javatests/Reflection.java (rev 0) +++ trunk/jython/tests/java/javatests/Reflection.java 2010-06-16 14:46:34 UTC (rev 7066) @@ -0,0 +1,44 @@ +package javatests; + +import java.util.Arrays; +import java.util.List; + +import org.python.core.Py; +import org.python.core.PyComplex; +import org.python.core.PyObject; + +public class Reflection { + + public static class StringVarargs { + + public String test(String... args) { + return "String...:" + Arrays.toString(args); + } + } + + public static class ListVarargs { + + public String test(List... args) { + return "List...:" + Arrays.toString(args); + } + } + + public static class Overloaded { + + public PyObject __call__(float x) { + return dump(x); + } + + public PyObject __call__(double x) { + return dump(x); + } + + public PyObject __call__(PyComplex x) { + return dump(x); + } + + private PyObject dump(Object o) { + return Py.newString(o.getClass() + "=" + o); + } + } +} This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |