Skip to content

Commit

Permalink
Added initial support for subclassing Python classes.
Browse files Browse the repository at this point in the history
  • Loading branch information
freakboy3742 committed Dec 20, 2015
1 parent 1639560 commit e6226bc
Show file tree
Hide file tree
Showing 17 changed files with 1,323 additions and 210 deletions.
6 changes: 3 additions & 3 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ What it does:

* `import`, `from X import Y` and `from X import *` statements for Python code

* Subclassing Python classes

* Importing and using native Java APIs

* Implementing Java interfaces.
Expand All @@ -50,13 +52,11 @@ What it does:

It *doesn't* currently support (this list is incomplete):

* Subclassing Python classes

* Generators

* with statements

* ``exec()``/``eval()``
* ``exec()`` and ``eval()``

These things are all *possible* - it's just a matter of time
and development effort. The order listed here is a rough indicator of
Expand Down
4 changes: 4 additions & 0 deletions python/common/org/Python.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ public class Python {
org.Python.initializeModule(org.Python.class, builtins);
}

public static void debug(java.lang.Object msg, java.lang.String label) {
System.out.println("DEBUG " + label + ": " + msg);
}

public static void initializeModule(java.lang.Class cls, java.util.Map<java.lang.String, org.python.Object> attrs) {
// Iterate over every method in the class, and if the
// method is annotated for inclusion in the Python class,
Expand Down
2 changes: 1 addition & 1 deletion python/common/org/python/java/Function.java
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ public org.python.Object invoke(org.python.Object instance, org.python.Object []
target = instance.toObject();
}

// System.out.println("Native Function:" + this);
// System.out.println("Native Function:" + this.name);
// System.out.println(" instance: " + instance);
// System.out.println(" target: " + target);
// System.out.println(" args:");
Expand Down
13 changes: 2 additions & 11 deletions python/common/org/python/java/Object.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,6 @@


public class Object extends org.python.types.Object {
static
// public static org.python.Object convert(java.lang.Object java) {
// if (java instanceof java.lang.String) {
// return new org.python.types.Str((java.lang.String) java);
// } else {
// return new org.python.java.Object(java);
// }
// }

public java.lang.Object object;

Expand All @@ -26,12 +18,11 @@ public java.lang.Object toObject() {
}

public Object(java.lang.Object object) {
super(org.python.types.Type.Origin.JAVA, object.getClass());
this.object = object;
this(org.python.types.Type.Origin.JAVA, object);
}

public Object(org.python.types.Type.Origin origin, java.lang.Object object) {
super(org.python.types.Type.Origin.JAVA, object.getClass());
super(origin, object.getClass());
this.object = object;
}

Expand Down
3 changes: 2 additions & 1 deletion python/common/org/python/java/Type.java
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,9 @@ public org.python.Object invoke(org.python.Object [] args, java.util.Map<java.la
// System.out.println("NATIVE CONSTRUCTOR :" + this.klass + " " + this.origin);
// System.out.println("ARGS:");
// for (org.python.Object arg: args) {
// System.out.println(" " + arg);
// System.out.print(" " + arg + ",");
// }
// System.out.println();

// System.out.println("KWARGS:");
// for (java.lang.String argname: kwargs.keySet()) {
Expand Down
18 changes: 8 additions & 10 deletions python/common/org/python/types/Closure.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,15 @@ public class Closure extends org.python.types.Object {
void setValue(org.python.Object obj) {
}

// public Closure(
// java.util.List<org.python.Object> default_args,
// java.util.Map<java.lang.String, org.python.Object> default_kwargs
// ) {
// super();
// this.default_args = default_args;
// this.default_kwargs = default_kwargs;
// }
public Closure(org.python.Object [] args, java.util.Map<java.lang.String, org.python.Object> kwargs) {
super(args, kwargs);
}

public Closure() {
super();
@org.python.Method(
__doc__ = "Return repr(self)."
)
public org.python.Object __repr__() {
return new org.python.types.Str(String.format("<function %s at 0x%x>", this.typeName(), this.hashCode()));
}

}
57 changes: 35 additions & 22 deletions python/common/org/python/types/Function.java
Original file line number Diff line number Diff line change
Expand Up @@ -186,15 +186,6 @@ public org.python.Object __get__(org.python.Object instance, org.python.Object k
n_args += 1;
}

// If this is an instance, the first argument will be self; we don't
// need to pass this to the Java function.
if (this.origin == org.python.types.Type.Origin.BUILTIN || instance == null || instance instanceof org.python.types.Closure) {
first_arg = 0;
} else {
first_arg = 1;
pos_count -= 1;
n_args -= 1;
}
first_default = pos_count - this.default_args.size();
// System.out.println("nargs " + n_args);

Expand All @@ -204,10 +195,19 @@ public org.python.Object __get__(org.python.Object instance, org.python.Object k

java.lang.Object [] adjusted = new java.lang.Object [n_args];

for (int i = 0; i < pos_count; i++) {
java.lang.String varname = ((org.python.types.Str) varnames.get(i + first_arg)).value;
if (i < args.length) {
adjusted[i] = args[i];
// If this is an instance, the first argument will be self; we don't
// need to pass this to the Java function.
if (instance == null || !java.lang.reflect.Modifier.isStatic(method.getModifiers())) {
first_arg = 0;
} else {
first_arg = 1;
adjusted[0] = instance;
}

for (int i = first_arg; i < pos_count; i++) {
java.lang.String varname = ((org.python.types.Str) varnames.get(i)).value;
if (i < args.length + first_arg) {
adjusted[i] = args[i - first_arg];
org.python.Object value = kwargs.remove(varname);
if (value != null) {
throw new org.python.exceptions.TypeError(this.name + "() got multiple values for argument '" + varname + "'");
Expand All @@ -222,7 +222,7 @@ public org.python.Object __get__(org.python.Object instance, org.python.Object k
}

if ((flags & CO_VARARGS) != 0) {
adjusted[pos_count] = java.util.Arrays.copyOfRange(args, pos_count + first_arg, args.length);
adjusted[pos_count] = java.util.Arrays.copyOfRange(args, pos_count, args.length);
}

return adjusted;
Expand All @@ -234,14 +234,8 @@ public org.python.Object invoke(org.python.Object [] args, java.util.Map<java.la

public org.python.Object invoke(org.python.Object instance, org.python.Object [] args, java.util.Map<java.lang.String, org.python.Object> kwargs) {
try {
java.lang.Object target = null;
if (instance != null) {
target = instance.toObject();
}

// System.out.println("Function:" + this);
// System.out.println("Function:" + this.name);
// System.out.println(" instance: " + instance);
// System.out.println(" target: " + target);
// System.out.print(" args:");
// for (org.python.Object arg: args) {
// System.out.print(arg + ", ");
Expand All @@ -258,7 +252,26 @@ public org.python.Object invoke(org.python.Object instance, org.python.Object []
// else:

java.lang.Object [] adjusted_args = adjustArguments(instance, args, kwargs);
return (org.python.Object) this.method.invoke(target, adjusted_args);

// if (adjusted_args != null) {
// System.out.print("Adjusted args:");
// for (java.lang.Object arg: adjusted_args) {
// System.out.print(arg + ", ");
// }
// System.out.println();
// } else {
// System.out.println("No adjusted args");
// }

// Python methods are stored as static methods on the class, so
// the instance argument is passed in as a regular method argument,
// not as the implied Java register 0. Builtins and closure methods
// require the instance to be passed as the explicit instance.
if (java.lang.reflect.Modifier.isStatic(method.getModifiers())) {
return (org.python.Object) this.method.invoke(null, adjusted_args);
} else {
return (org.python.Object) this.method.invoke(instance, adjusted_args);
}
} catch (java.lang.IllegalAccessException e) {
throw new org.python.exceptions.RuntimeError("Illegal access to Java method " + this.method);
} catch (java.lang.reflect.InvocationTargetException e) {
Expand Down
23 changes: 19 additions & 4 deletions python/common/org/python/types/Object.java
Original file line number Diff line number Diff line change
Expand Up @@ -56,12 +56,27 @@ public Object() {
this(org.python.types.Type.Origin.PYTHON, null);
}

public Object(org.python.Object [] args, java.util.Map<java.lang.String, org.python.Object> kwargs) {
this(org.python.types.Type.Origin.PYTHON, null);

// System.out.println("CONSTRUCT OBJECT " + this.getClass());
org.python.Object init = this.__getattribute_null("__init__");
if (init != null) {
// System.out.println("CALL INIT ");
try {
((org.python.types.Method) init).invoke(args, kwargs);
} catch (ClassCastException e) {
throw new org.python.exceptions.RuntimeError(String.format("__init__ method of %s object is not callable", this.getClass()));
}
}
}

/**
* Proxy Java object methods onto their Python counterparts.
*/
public boolean equals(java.lang.Object other) {
try {
return ((org.python.types.Bool) this.__eq__((org.python.types.Object) other)).value;
return ((org.python.types.Bool) this.__eq__((org.python.Object) other)).value;
} catch (ClassCastException e) {
throw new org.python.exceptions.RuntimeError("Can't compare a Python object with non-Python object.");
}
Expand Down Expand Up @@ -260,7 +275,7 @@ public org.python.Object __getattribute__(java.lang.String name) {

public org.python.Object __getattribute_null(java.lang.String name) {
// Look for local instance attributes first
// System.out.println("GETATTRIBUTE " + name + " on " + this);
// System.out.println("GETATTRIBUTE " + name);
// System.out.println("ATTRS " + this.attrs);
org.python.Object value = this.attrs.get(name);
org.python.types.Type cls = (org.python.types.Type) this.attrs.get("__class__");
Expand All @@ -281,7 +296,7 @@ public org.python.Object __getattribute_null(java.lang.String name) {
}
}
}
// System.out.println("GETATTRIBUTE " + name + " on " + this + " = " + value);
// System.out.println("GETATTRIBUTE " + name + " = " + value);
// Post-process the value retrieved.
return value.__get__(this, cls);
}
Expand Down Expand Up @@ -314,7 +329,7 @@ public void __setattr__(java.lang.String name, org.python.Object value) {
}

public boolean __setattr_null(java.lang.String name, org.python.Object value) {
// System.out.println("SETATTR " + name + " = " + value);
// System.out.println("SETATTR " + name + " = " + value + " ");
org.python.types.Type cls = (org.python.types.Type) this.attrs.get("__class__");

// If the attribute already exists, then it's OK to set it.
Expand Down
Loading

0 comments on commit e6226bc

Please sign in to comment.