-
Notifications
You must be signed in to change notification settings - Fork 80
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
Make Python import Java types using import
#1525
Comments
@jmao-denver I found a couple useful tidbits when I was looking into something similar, in particular:
It suggests looking into Import Hooks: https://www.python.org/dev/peps/pep-0302/ |
PEP 302 is very old, and I'm assuming still the low level way of how things work. I'd see of PEP 451 is more relevant; and would also see if other libraries are doing it, and if there are any more modern / organized ways of setting it up. |
@mofojed @devinrsmith @chipkent, thanks for all the useful info. I tried something really simple with the finder approach Chip discovered, but it doesn't look promising without some further work. What I found out is that |
https://jpype.readthedocs.io/en/latest/userguide.html uses this too - I bet we can look at how they do it to see if the same way would work for us. |
Please note you will also need something like the support classes under https://github.com/jpype-project/jpype/tree/master/native/java/org/jpype/pkg The Python portion that you identified is not difficult, but if you want to get the listing of what should be in the contents of the packages, that requires probing on the Java side. In Java, you can interrogate a class using reflection to find its contents, but it is much harder to interrogate a package to find out what classes it contains. To find that you have to use a combination of the jar and jrt filesystems. It gets complicated when you consider the transition from Java 8 to Java 9+ and the added complexity of multiple release jars requires additional special cases. There are also rare cases such as jars that don't contain an zip index which are impossible to get a listing of classes from. There is also a special pattern which is required if you want to determine if a class is public. We used to include private classes in the index, but that leads to lots of security exceptions when probed. They don't make this one easy as the flags for public are after then constant table and there is no index to skip directly to the flags. Thus you have to decode the whole table first. If you have questions just poke me as I am the main author of JPype and all these support classes that JPype uses. Though it does sound a bit like I am helping a competitor. Though as JPype is currently only Python to Java and not the reverse there may be a good reason to use jpy here. If you are interesting in helping to finish the JPype Java to Python bridge (which makes Python a first class language in Java) I am always looking for help. |
I'm definitely interested to learn more about JPype. I believe we researched it years ago, but we needed support both ways. JPype popped up in my RSS reader via https://blog.codecentric.de/en/2021/11/java-classes-python/, and thought it was timely given some of the things we are working on right now. Thanks for the input @Thrameos! |
Yes JPype is primarily one way. It is possible for Java to call Python but only if Python creates an instance of an Java Interface. Its primary claim to fame is that it presents Java to Python with customizers such that all Java code appears as Python and supports duck typed compatibility for everything down to the buffer level (fast transfer to and from). As my main use is for scientific coding speed and native look were critical. It even does stuff like exposing Java documentation in Python. About the only features it is missing are integration of stub generation and integration of IO such that Java can operate on a Python file concept. There is an experimental branch called epypj which is a reverse bridge. It uses Java ASM to create Java versions of Python classes, basically synthesizing Java code backed by Python on the fly. It adds all of the Python types as mixins based on their capabilities. So if something is a Python iterable it appears as a Java iterable and so forth. I even set it up so that you can write customizers for specific classes like pyplot to make it more Java native. It does this through a complete Python FFI (Foreign Function Interface) for the Python backend in Java so any C Python code can be called from within Java (assuming the address for the function was registered). Thus it isn't so much allowing access to Python, but making Python appear as Java code (with a bunch of casting because weak Python objects returned in Java must be cast to the type to expose the additional functionality). Unfortunately I never could get other contributors to help with the challenging part of writing the required test bench and packaging so that epypj can be used in the same way as jpy. The JPype code structure is strictly as a Python module so it isn't really geared to work with something like maven. I can launch a Python shell from within Java call anything in Java from that shell, and can create Python types in Java code and pass them back an forth, but before it can be a release product it would need to comprehensive testing of all the code paths, and with a complete FFI that means many hundreds of potential interactions. My employer also put a damper by refusing to sign the Python contributor agreement so I can't contribute back hooks and improvements that would make the task easier. The other significant issue is that of memory management. When operating in one direction it is difficult though not impossible to create memory reference loops in which a Java resource is holding a Python resource which is holding a Java resource. These sorts of loops are irresolvable under the JNI and CPython API. Java GC can't call through CPython visitor to discover that something is a circular reference, and CPython can't see Java held Python resources. Thus both language have items which are stuck with positive reference counts. Thus the bidirectional bridge is useable but the restrictions to avoid memory issues require that avoiding storing a resource which is a container in the other language. I spent a great deal of time looking through the protocols for Java RMI to see if there were ways to treat Python reference counting as a remote protocol for the Java GC, but never reached a conclusion. |
Here is another JPY-like project, it also supports the syntax that we like. https://github.com/ninia/jep/wiki/Getting-Started |
This talk may be helpful for the implementation. |
The issue is not the python import system. That is easy (see jpype/imports.py). Simply implement the findspec methods and import your wrapper classes. The challenging part is determining what objects belong in a java imported package. If you stick to only named objects (no wildcards), then just checking for existance and wrapping is fine. If you want wildcards, statics, and enums on import, then you will need some java support classes to probe. |
Release notes https://github.com/deephaven/web-client-ui/releases/tag/v0.49.1 ### Bug Fixes * Copy did not work from embedded iframes ([#1528](deephaven/web-client-ui#1528)) ([3549a33](deephaven/web-client-ui@3549a33)), closes [#1527](deephaven/web-client-ui#1527) * Dehydration of class components ([#1535](deephaven/web-client-ui#1535)) ([3e834de](deephaven/web-client-ui@3e834de)), closes [#1534](deephaven/web-client-ui#1534) * inconsistent drag for webkit ([#1518](deephaven/web-client-ui#1518)) ([cd5408c](deephaven/web-client-ui@cd5408c)), closes [#1360](deephaven/web-client-ui#1360) * Render tables partitioned by non-string columns ([#1533](deephaven/web-client-ui#1533)) ([585b2ff](deephaven/web-client-ui@585b2ff)), closes [#1441](deephaven/web-client-ui#1441) * Right clicking with a custom context menu open should open another context menu ([#1526](deephaven/web-client-ui#1526)) ([bd08e1f](deephaven/web-client-ui@bd08e1f)), closes [#1525](deephaven/web-client-ui#1525) # [0.49.0](deephaven/web-client-ui@v0.48.0...v0.49.0) (2023-09-15) ### Bug Fixes * Plugin peer dependencies do not get versions from lerna ([#1517](deephaven/web-client-ui#1517)) ([322f6ff](deephaven/web-client-ui@322f6ff)) * Table overflow button has lower priority than grid tokens ([#1510](deephaven/web-client-ui#1510)) ([32e6d20](deephaven/web-client-ui@32e6d20)), closes [#1480](deephaven/web-client-ui#1480) ### Code Refactoring * Improve table saver to always use the correct service worker ([#1515](deephaven/web-client-ui#1515)) ([2488e52](deephaven/web-client-ui@2488e52)), closes [#766](deephaven/web-client-ui#766) ### Features * Update go to row panel's row number with cursorRow ([#1508](deephaven/web-client-ui#1508)) ([23ab5cc](deephaven/web-client-ui@23ab5cc)), closes [#1406](deephaven/web-client-ui#1406) ### BREAKING CHANGES * `TableSaver` now expects the service worker to send it a complete URL for download instead of just a file name. DHE will need to adjust its `serviceWorker.js` to incorporate the same changes from this PR. Co-authored-by: deephaven-internal <deephaven-internal@users.noreply.github.com>
PR #1450 is attempting to address the need for Java types in Python without forcing users to touch
jpy
. During the discussions on this PR, it became clear that importing Java types via Python's import statement, without the explicit use ofjpy
, would be a superior solution. Some research into the subject makes the strategy look viable.The proposed syntax is something like:
To make this feature work, we need to hook into Python's import statements. These documents indicate that it is possible.
https://realpython.com/python-import/#finders-and-loaders
https://docs.python.org/3/library/importlib.html
https://www.python.org/dev/peps/pep-0302/
https://www.python.org/dev/peps/pep-0451/
The text was updated successfully, but these errors were encountered: