ninia / jep

Embed Python in Java
Other
1.31k stars 149 forks source link

Initial Implementation of PyBuiltins #467

Closed bsteffensmeier closed 1 year ago

bsteffensmeier commented 1 year ago

This provides an interface to expose the functionality of the Python builtin module to Java using the Jep proxy functionality.

We have supported the proxy functionality for a long time but the only way for developers using Jep to use it is to write their own interface to use with the proxy. With this PR I am proposing that Jep can provide and maintain some interfaces for some standard Python objects to work with the Jep proxy functionality.

This PR exposes the builtin module because in some examples and tests I have written I have wanted a convenient way to access a few of these in Java and for others I can envision use cases where it might be helpful.

  1. I think things like type() and isinstance() will be very helpful for type checking a PyObject in java.
  2. compile(), eval() and exec() would be useful if anyone wants to build advanced interpreters beyond what Jep provides.
  3. I included dict() because it would be a convenient way to get a globals /locals dict for exec().
  4. I included the other collection types in case someone had a similar use cases where they needed to construct a Python collection directly.

I did not include functions that I didn't think would be particularly useful from Java, For example Java has it's own math library for doing abs and pow.

One of the important things to look at in the PR is the class of all the arguments and return types because often the proxy functionality would work equally well if we just used Object or PyObject everywhere. In places where certain types are required by the python functions I tried to be more specific and I tried to choose PyObject vs. Object based off what I thought made the most sense. The reason this is important is because if we need to change a return type or argument type in a future version of Jep then it could break backwards compatibility. Maintaining backwards compatibility is one of the major downsides to offering this type of support within Jep as opposed to requiring developers to create the interfaces themselves or offering them in a separate library.

It's also worth mentioning that everything PyBuiltins does could easily be done with Interpreter.invoke() or Interpreter.getValue() so this adds no new functionality to Jep, however I feel PyBuiltins provides a more object oriented way of accessing the functionality that will be more convenient for some Java developers using Jep.

bsteffensmeier commented 1 year ago

In addition to addressing the comments from @ndjensen I have also switched some of the arg types to be more specific classes. I have received feedback that the use of Object everywhere makes it hard to understand what type of java objects are actually OK to pass into the methods. My original justification for using Object is that it makes it more powerful to allow any Object that the jep conversion could make the right type. After further discussion I think it is more important that this class be something Java developers can understand easily. Advanced users who want to use more exotic conversions can easily extend the interface and overload any method to except other types of Objects. It would also be relatively simple for jep to change to less specific arguments in the future since it would remain compatible but switching to more specific args later would break things so this seems like a more conservative approach for an initial implementation,