[Jython-checkins] jython: (Trivial) documentation additions and code clarity around PyJavaType.java.
jeff.allen
jython-checkins at python.org
Sun Apr 28 12:03:43 EDT 2019
https://hg.python.org/jython/rev/e233f3fc6fde
changeset: 8238:e233f3fc6fde
user: Jeff Allen <ja.py at farowl.co.uk>
date: Mon Apr 22 10:50:32 2019 +0100
summary:
(Trivial) documentation additions and code clarity around PyJavaType.java.
files:
src/org/python/core/PyJavaType.java | 43 ++++++--
src/org/python/core/PyMethodDescr.java | 8 +-
src/org/python/core/PyReflectedConstructor.java | 27 +++--
src/org/python/core/PyReflectedFunction.java | 8 +-
src/org/python/core/ReflectedArgs.java | 48 +++++----
5 files changed, 87 insertions(+), 47 deletions(-)
diff --git a/src/org/python/core/PyJavaType.java b/src/org/python/core/PyJavaType.java
--- a/src/org/python/core/PyJavaType.java
+++ b/src/org/python/core/PyJavaType.java
@@ -1,3 +1,5 @@
+// Copyright (c)2019 Jython Developers.
+// Licensed to PSF under a Contributor Agreement.
package org.python.core;
import org.python.core.util.StringUtil;
@@ -465,14 +467,17 @@
}
}
}
- // Methods must be in resolution order. See issue #2391 for detail.
+ // Methods must be in resolution order. See issue bjo #2391 for detail.
Arrays.sort(methods, new MethodComparator(new ClassComparator()));
- // Add methods, also accumulating them in reflectedFuncs, and spotting Java Bean members.
+ /* Add methods, also accumulating them in reflectedFuncs, and spotting Java Bean members. */
ArrayList<PyReflectedFunction> reflectedFuncs = new ArrayList<>(methods.length);
Map<String, PyBeanProperty> props = Generic.map();
Map<String, PyBeanEvent<?>> events = Generic.map();
+
+ // First pass skip inherited (and certain "ignored") methods.
addMethods(baseClass, reflectedFuncs, props, events, methods);
+ // Add inherited and previously ignored methods
addInheritedMethods(reflectedFuncs, methods);
// Add fields declared on this type
@@ -625,10 +630,11 @@
}
/**
- * Process the given class for methods defined on the target class itself (the
- * <code>fromClass</code>), rather than inherited.
- *
- * This is exclusively a helper method for {@link #init(Set)}.
+ * Add descriptors to this type's dictionary ({@code __dict__}) for methods defined on the
+ * target class itself (the {@code fromClass}), where not inherited. One descriptor is created
+ * for each simple name and a signature for every method with that simple name is added to the
+ * descriptor. See also {@link #addInheritedMethods(List, Method[])}. This is exclusively a
+ * helper method for {@link #init(Set)}.
*
* @param baseClass ancestor of the target class
* @param reflectedFuncs to which reflected functions are added for further processing
@@ -642,7 +648,6 @@
boolean isInAwt = name.startsWith("java.awt.") && name.indexOf('.', 9) == -1;
- // First pass skip inherited (and certain "ignored") methods.
for (Method meth : methods) {
if (!declaredHere(baseClass, meth) || ignore(meth)) {
continue;
@@ -663,10 +668,12 @@
PyReflectedFunction reflfunc = (PyReflectedFunction) dict.__finditem__(nmethname);
if (reflfunc == null) {
+ // A new descriptor is required
reflfunc = new PyReflectedFunction(meth);
reflectedFuncs.add(reflfunc);
dict.__setitem__(nmethname, reflfunc);
} else {
+ // A descriptor for the same simple name exists: add a signature to it.
reflfunc.addMethod(meth);
}
@@ -752,15 +759,29 @@
}
/**
- * Process the given class for methods inherited from ancestor classes.
- *
- * This is exclusively a helper method for {@link #init(Set)}.
+ * Add descriptors to this type's dictionary ({@code __dict__}) for methods inherited from
+ * ancestor classes. This is exclusively a helper method for {@link #init(Set)}.
+ * <p>
+ * Python finds an inherited method by looking in the dictionaries of types along the MRO. This
+ * is does not directly emulate the signature polymorphism of Java. Even though the entries of
+ * the MRO include the {@code PyType}s of the Java ancestors of this class, each type's
+ * dictionary is keyed on the simple name of the method. For the present class, and at the point
+ * where this method is called, any method defined on this class has created a descriptor entry
+ * for that method name (see {@link #addMethods(Class, List, Map, Map, Method[])}), but only for
+ * the signatures defined directly in this class. If any method of the same simple name is
+ * inherited in Java from a super-class, it is now shadowed by this entry as far as Python is
+ * concerned. The purpose of this method is to add the shadowed method signatures.
+ * <p>
+ * For example {@code AbstractCollection<E>} defines {@code add(E)}, and {@code AbstractList<E>}
+ * inherits it but also defines {@code add(int, E)} (giving control of the insertion point).
+ * When {@link #addMethods(Class, List, Map, Map, Method[])} completes, the "add" descriptor in
+ * {@code type(AbstractList)}, represents only {@code add(int, E)}, and we must add the
+ * inherited signature for {@code add(E)}.
*
* @param reflectedFuncs to which reflected functions are added for further processing
* @param methods of the target class
*/
private void addInheritedMethods(List<PyReflectedFunction> reflectedFuncs, Method[] methods) {
- // Add inherited and previously ignored methods
for (Method meth : methods) {
String nmethname = normalize(meth.getName());
PyReflectedFunction reflfunc = (PyReflectedFunction) dict.__finditem__(nmethname);
diff --git a/src/org/python/core/PyMethodDescr.java b/src/org/python/core/PyMethodDescr.java
--- a/src/org/python/core/PyMethodDescr.java
+++ b/src/org/python/core/PyMethodDescr.java
@@ -1,3 +1,5 @@
+// Copyright (c)2019 Jython Developers.
+// Licensed to PSF under a Contributor Agreement.
package org.python.core;
import org.python.expose.ExposedGet;
@@ -17,7 +19,7 @@
minargs = func.info.getMinargs();
maxargs = func.info.getMaxargs();
meth = func;
- meth.setInfo(this);
+ meth.setInfo(this); // XXX Why modify func.info each time used?
}
@ExposedGet(name = "__doc__")
@@ -25,10 +27,12 @@
return meth.getDoc();
}
+ @Override
public int getMaxargs() {
return maxargs;
}
+ @Override
public int getMinargs() {
return minargs;
}
@@ -54,6 +58,7 @@
return meth.bind(args[0]).__call__(actualArgs, kwargs);
}
+ @Override
public PyException unexpectedCall(int nargs, boolean keywords) {
return PyBuiltinCallable.DefaultInfo.unexpectedCall(nargs, keywords, name, minargs,
maxargs);
@@ -78,6 +83,7 @@
*
* @return a name String
*/
+ @Override
@ExposedGet(name = "__name__")
public String getName() {
return name;
diff --git a/src/org/python/core/PyReflectedConstructor.java b/src/org/python/core/PyReflectedConstructor.java
--- a/src/org/python/core/PyReflectedConstructor.java
+++ b/src/org/python/core/PyReflectedConstructor.java
@@ -1,4 +1,6 @@
// Copyright (c) Corporation for National Research Initiatives
+// Copyright (c)2019 Jython Developers.
+// Licensed to PSF under a Contributor Agreement.
package org.python.core;
import java.lang.reflect.Constructor;
@@ -40,7 +42,7 @@
// Check for a matching constructor to call
if (nargs > 0) { // PyArgsKeywordsCall signature, if present, is the first
if (argslist[0].matches(null, args, keywords, callData)) {
- method = argslist[0].data;
+ method = argslist[0].method;
consumes_keywords = argslist[0].flags == ReflectedArgs.PyArgsKeywordsCall;
} else {
allArgs = args;
@@ -52,7 +54,7 @@
}
for (; i < nargs; i++) {
if (argslist[i].matches(null, args, Py.NoKeywords, callData)) {
- method = argslist[i].data;
+ method = argslist[i].method;
break;
}
}
@@ -116,7 +118,7 @@
}
ReflectedCallData callData = new ReflectedCallData();
Object method = null;
-
+
// If we have keyword args, there are two ways this can be handled;
// a) we find a constructor that takes keyword args, and use it.
// b) we don't, in which case we strip the keyword args, and pass the
@@ -129,25 +131,25 @@
boolean usingKeywordArgsCtor = false;
if (nkeywords > 0) {
// We have keyword args.
-
+
// Look for a constructor; the ReflectedArgs#matches() method exits early in the case
// where keyword args are used
int n = nargs;
for (int i = 0; i < n; i++) {
rargs = argslist[i];
if (rargs.matches(null, args, keywords, callData)) {
- method = rargs.data;
+ method = rargs.method;
break;
}
}
-
+
if (method != null) {
// Constructor found that will accept the keyword args
usingKeywordArgsCtor = true;
} else {
// No constructor found that will take keyword args
-
- // Remove the keyword args
+
+ // Remove the keyword args
args = new PyObject[allArgs.length - nkeywords];
System.arraycopy(allArgs, 0, args, 0, args.length);
@@ -155,7 +157,7 @@
for (int i = 0; i < n; i++) {
rargs = argslist[i];
if (rargs.matches(null, args, Py.NoKeywords, callData)) {
- method = rargs.data;
+ method = rargs.method;
break;
}
}
@@ -166,12 +168,12 @@
for (int i = 0; i < n; i++) {
rargs = argslist[i];
if (rargs.matches(null, args, Py.NoKeywords, callData)) {
- method = rargs.data;
+ method = rargs.method;
break;
}
}
}
-
+
// Throw an error if no valid set of arguments
if (method == null) {
throwError(callData.errArg, args.length, false, false);
@@ -217,8 +219,9 @@
msg += " " + sup.getName();
}
throw Py.TypeError(msg);
- } else
+ } else {
throw Py.JavaError(e);
+ }
} catch (Throwable t) {
throw Py.JavaError(t);
}
diff --git a/src/org/python/core/PyReflectedFunction.java b/src/org/python/core/PyReflectedFunction.java
--- a/src/org/python/core/PyReflectedFunction.java
+++ b/src/org/python/core/PyReflectedFunction.java
@@ -1,4 +1,6 @@
// Copyright (c) Corporation for National Research Initiatives
+// Copyright (c)2019 Jython Developers.
+// Licensed to PSF under a Contributor Agreement.
package org.python.core;
import java.lang.reflect.Method;
@@ -169,7 +171,7 @@
throwError(callData.errArg, args.length, self != null, keywords.length != 0);
}
Object cself = callData.self;
- Method m = (Method)match.data;
+ Method m = (Method)match.method;
// If this is a direct call to a Java class instance method with a PyProxy instance as the
// arg, use the super__ version to actually route this through the method on the class.
@@ -344,7 +346,9 @@
public int traverse(Visitproc visit, Object arg) {
if (__module__ != null) {
int res = visit.visit(__module__, arg);
- if (res != 0) return res;
+ if (res != 0) {
+ return res;
+ }
}
return __doc__ != null ? visit.visit(__doc__, arg) : 0;
}
diff --git a/src/org/python/core/ReflectedArgs.java b/src/org/python/core/ReflectedArgs.java
--- a/src/org/python/core/ReflectedArgs.java
+++ b/src/org/python/core/ReflectedArgs.java
@@ -1,10 +1,18 @@
// Copyright (c) Corporation for National Research Initiatives
+// Copyright (c)2019 Jython Developers.
+// Licensed to PSF under a Contributor Agreement.
package org.python.core;
+import java.lang.reflect.Member;
+
+/** Map the signature of a method to the {@code Method} itself, within the context of a given simple name. This is used in support of signature polymorphism in Java methods and constructors reflected into Python. **/
public class ReflectedArgs {
+
+ /** The types of arguments defining this signature (key) */
public Class<?>[] args;
- public Object data;
+ /** The specific method (or constructor). */
+ public Member method;
public Class<?> declaringClass;
@@ -20,21 +28,21 @@
public static final int PyArgsKeywordsCall = 2;
- public ReflectedArgs(Object data, Class<?>[] args, Class<?> declaringClass, boolean isStatic) {
- this(data, args, declaringClass, isStatic, false);
+ public ReflectedArgs(Member method, Class<?>[] args, Class<?> declaringClass, boolean isStatic) {
+ this(method, args, declaringClass, isStatic, false);
}
- public ReflectedArgs(Object data, Class<?>[] args, Class<?> declaringClass, boolean isStatic, boolean isVarArgs) {
- this.data = data;
+ public ReflectedArgs(Member method, Class<?>[] args, Class<?> declaringClass, boolean isStatic,
+ boolean isVarArgs) {
+ this.method = method;
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
-
+ // only used for varargs matching; it should be added after the unboxed form
+ this.isVarArgs = isVarArgs;
if (args.length == 1 && args[0] == PyObject[].class) {
this.flags = PyArgsCall;
- } else if (args.length == 2 && args[0] == PyObject[].class
- && args[1] == String[].class) {
+ } else if (args.length == 2 && args[0] == PyObject[].class && args[1] == String[].class) {
this.flags = PyArgsKeywordsCall;
} else {
this.flags = StandardCall;
@@ -52,8 +60,8 @@
// if (isStatic ? self != null : self == null) return Py.NoConversion;
/* Ugly code to handle mismatch in static vs. instance functions... */
/*
- * Will be very inefficient in cases where static and instance functions
- * both exist with same names and number of args
+ * Will be very inefficient in cases where static and instance functions both exist with
+ * same names and number of args
*/
if (this.isStatic) {
if (self != null) {
@@ -136,7 +144,7 @@
for (int i = 0; i < n; i++) {
PyObject pyArg = pyArgs[i];
- Class targetClass = this.args[i];
+ Class<?> targetClass = this.args[i];
Object javaArg = pyArg.__tojava__(targetClass);
javaArgs[i] = javaArg;
if (javaArg == Py.NoConversion) {
@@ -153,13 +161,11 @@
private PyObject[] ensureBoxedVarargs(PyObject[] pyArgs, int n) {
if (pyArgs.length == 0) {
// If there are no args return an empty list
- return new PyObject[]{new PyList()};
+ return new PyObject[] {new PyList()};
}
PyObject lastArg = pyArgs[pyArgs.length - 1];
- if (lastArg instanceof PySequenceList ||
- lastArg instanceof PyArray ||
- lastArg instanceof PyXRange ||
- lastArg instanceof PyIterator) {
+ if (lastArg instanceof PySequenceList || lastArg instanceof PyArray
+ || lastArg instanceof PyXRange || lastArg instanceof PyIterator) {
// NOTE that the check is against PySequenceList, not PySequence,
// because certain Java <=> Python semantics currently require this
// additional strictness. Perhaps this can be relaxed.
@@ -236,9 +242,8 @@
}
/*
- * Returns 0 iff arg1 == arg2 Returns +/-1 iff arg1 and arg2 are
- * unimportantly different Returns +/-2 iff arg1 and arg2 are significantly
- * different
+ * Returns 0 iff arg1 == arg2 Returns +/-1 iff arg1 and arg2 are unimportantly different Returns
+ * +/-2 iff arg1 and arg2 are significantly different
*/
public static int compare(Class<?> arg1, Class<?> arg2) {
int p1 = precedence(arg1);
@@ -320,7 +325,8 @@
@Override
public String toString() {
- String s = declaringClass + ", static=" + isStatic + ", varargs=" + isVarArgs + ",flags=" + flags + ", " + data + "\n";
+ String s = declaringClass + ", static=" + isStatic + ", varargs=" + isVarArgs + ",flags="
+ + flags + ", " + method + "\n";
s = s + "\t(";
for (Class<?> arg : args) {
s += arg.getName() + ", ";
--
Repository URL: https://hg.python.org/jython
More information about the Jython-checkins
mailing list