[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