Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Overriding constructors for classes inheriting from Java #367

Open
msalman-abid opened this issue Nov 9, 2023 · 5 comments · Fixed by #368
Open

Overriding constructors for classes inheriting from Java #367

msalman-abid opened this issue Nov 9, 2023 · 5 comments · Fixed by #368

Comments

@msalman-abid
Copy link
Contributor

As of the latest version (23.1.0), GraalPy does not support overriding constructors for Python classes that inherit from Java.

The example below throws an error when we try to create a custom Exception wrapper in Python:

package my.pack;

import org.graalvm.polyglot.Value;
import org.graalvm.polyglot.Context;

public class Main {

    static Context context = Context.newBuilder().allowAllAccess(true).build();
    static Value clz;

    public static void main(String[] args) {
        context.eval("python", """
            import java
            class ParseException(java.lang.Exception):
                def __init__(self, message):
                    self.__super__(message)
            """);

        clz = context.getBindings("python").getMember("ParseException");
        Value obj = clz.newInstance("Hello from Java");
    }
}

Result

// error
Exception in thread "main" TypeError: ParseException.__init__() missing 1 required positional argument: 'message'
        at org.graalvm.sdk/org.graalvm.polyglot.Value.newInstance(Value.java:933)
        at my.pack.Main.main(Main.java:18)
@msimacek
Copy link
Contributor

Yes, it's a known limitation, because we need to have already created the Java object by the time we call __init__, so we can pass it as self. Java constructors are not like __init__, you can't call them on an already existing object. We should mention it in the documentation. If all you need is to have a python exception subclass, then don't implement __init__ at all. The arguments get passed to the Java constructor implicitly. Example:

import java
class ParseException(java.lang.Exception):
  pass
print(ParseException("my message").getMessage())

@msalman-abid
Copy link
Contributor Author

I see, thanks for the explanation. Is this a hard limitation, or will this be addressed in the a future release?
If it will remain as-is, an update in the docs will be helpful

@msimacek
Copy link
Contributor

Calling the constructor from __init__ is a hard limitation, Java just doesn't allow calling a constructor on an existing instance. However, what we could do is to allow overriding __new__. Something like this:

class MyException(java.lang.Exception):
  def __new__(cls):
    return cls.__constructor__("my message")

This currently doesn't work, I made up the __constructor__ method. But I think we could make it work.

@msalman-abid
Copy link
Contributor Author

Will this then be addressed in some upcoming release? We can keep this issue open if required for tracking purposes, and not close it even if #368 is merged

@msimacek
Copy link
Contributor

Let's keep it open, I want to do the __new__ overriding I mentioned earlier.

@msimacek msimacek reopened this Nov 20, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants