Skip to content

Commit 0baa5fe

Browse files
committed
Document that we now give foreign objects a Python class corresponding to their interop traits
1 parent 11d963a commit 0baa5fe

File tree

3 files changed

+46
-4
lines changed

3 files changed

+46
-4
lines changed

CHANGELOG.md

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,17 @@ language runtime. The main focus is on user-observable behavior of the engine.
77
* Updated developer metadata of Maven artifacts.
88
* Added gradle plugin for polyglot embedding of Python packages into Java.
99
* When calling a method on a foreign object in Python code, Python methods are now prioritized over foreign members.
10+
* Added `polyglot.register_interop_type` and `@polyglot.interop_type` to define custom Python methods for a given foreign class/type. See [the documentation](https://github.com/oracle/graalpython/blob/master/docs/user/Interoperability.md#the-interoperability-extension-api) for more information.
11+
* Foreign objects are now given a Python class corresponding to their interop traits.
12+
** Foreign lists now inherit from Python `list`, foreign dictionaries from `dict`, foreign iterators from `iterator`, foreign exceptions from `BaseException` and foreign none/null from `NoneType`.
13+
** This means all Python methods of these types are available on the corresponding foreign objects, which behave as close as possible as if they were Python objects.
14+
** See [the documentation](https://github.com/oracle/graalpython/blob/master/docs/user/Interoperability.md#interacting-with-foreign-objects-from-python-scripts) for more information.
1015

1116
## Version 24.1.0
1217
* GraalPy is now considered stable for pure Python workloads. While many workloads involving native extension modules work, we continue to consider them experimental. You can use the command-line option `--python.WarnExperimentalFeatures` to enable warnings for such modules at runtime. In Java embeddings the warnings are enabled by default and you can suppress them by setting the context option 'python.WarnExperimentalFeatures' to 'false'.
1318
* Update to Python 3.11.7.
1419
* We now provide intrinsified `_pickle` module also in the community version.
15-
* `polyglot.eval` now raises more meaningful exceptions. Unavaliable languages raise `ValueError`. Exceptions from the polyglot language are raised directly as interop objects (typed as `polyglot.ForeignException`). The shortcut for executing python files without specifying language has been removed, use regular `eval` for executing Python code.
20+
* `polyglot.eval` now raises more meaningful exceptions. Unavailable languages raise `ValueError`. Exceptions from the polyglot language are raised directly as interop objects (typed as `polyglot.ForeignException`). The shortcut for executing python files without specifying language has been removed, use regular `eval` for executing Python code.
1621
* In Jython emulation mode we now magically fall back to calling Java getters or setters when using Python attribute access for non-visible properties. This can help migrating away from Jython if you relied on this behavior.
1722
* The option `python.EmulateJython` to enable Jython emulation is now marked as stable, and can thus be relied upon in production.
1823
* Fixed parsing of pyvenv.cfg according to PEP 405, which is required to use [uv](https://github.com/astral-sh/uv?tab=readme-ov-file#uv) generated venvs with GraalPy.
@@ -33,7 +38,7 @@ language runtime. The main focus is on user-observable behavior of the engine.
3338
* Add option `python.InitialLocale` to change the default locale. If not set, then Java Locale#getDefault is used.
3439
* `multiprocessing` module now uses the `spawn` method (creates new processes) by default. The formerly default method that uses threads and multiple Truffle contexts can be selected using `multiprocessing.set_start_method('graalpy')`.
3540
* `polyglot` module: add API to redefine Truffle interop messages for external / user defined types. For more details see [The Truffle Interoperability Extension API](docs/user/Interoperability.md).
36-
*Adding integration with jBang (https://www.jbang.dev/)
41+
* Adding integration with jBang (https://www.jbang.dev/)
3742
** running example via `jbang hello@oracle/graalpython` or `jbang hello@oracle/graalpython "print(1*4)"`
3843
** creating new script via: `jbang init --template=graalpy@oracle/graalpython myscript.java`
3944
** creating new script with local maven repo for testing: `jbang init --template=graalpy_local_repo@oracle/graalpython -Dpath_to_local_repo=/absolute/path/to/local/maven/repository myscript.java'

docs/user/Interoperability.md

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ In addition to the `type` built-in method, the `java` module exposes the followi
4242

4343
Built-in | Specification
4444
--- | ---
45-
`instanceof(obj, class)` | returns `True` if `obj` is an instance of `class` (`class` must be a foreign object class)
45+
`instanceof(obj, class)` | returns `True` if `obj` is an instance of `class` (`class` must be a foreign object class)
4646
`is_function(obj)` | returns `True` if `obj` is a Java host language function wrapped using interop
4747
`is_object(obj)` | returns `True` if `obj` if the argument is Java host language object wrapped using interop
4848
`is_symbol(obj)` | returns `True` if `obj` if the argument is a Java host symbol, representing the constructor and static members of a Java class, as obtained by `java.type`
@@ -59,6 +59,43 @@ assert java.instanceof(my_list, ArrayList)
5959

6060
See [Polyglot Programming](https://github.com/oracle/graal/blob/master/docs/reference-manual/polyglot-programming.md) and [Embed Languages](https://github.com/oracle/graal/blob/master/docs/reference-manual/embedding/embed-languages.md) for more information about interoperability with other programming languages.
6161

62+
## Interacting with foreign objects from Python scripts
63+
64+
Foreign objects are given a Python class corresponding to their interop traits:
65+
66+
```python
67+
from java.util import ArrayList, HashMap
68+
type(ArrayList()).mro() # => [<class 'polyglot.ForeignList'>, <class 'list'>, <class 'foreign'>, <class 'object'>]
69+
type(HashMap()).mro() # => [<class 'polyglot.ForeignDict'>, <class 'dict'>, <class 'foreign'>, <class 'object'>]
70+
```
71+
72+
This means all Python methods of these types are available on the corresponding foreign objects, which behave as close as possible as if they were Python objects:
73+
74+
```python
75+
from java.util import ArrayList, HashMap
76+
l = ArrayList()
77+
l.append(1) # l: [1]
78+
l.extend([2, 3]) # l: [1, 2, 3]
79+
l.add(4) # l: [1, 2, 3, 4] # we can still call Java methods, this is calling ArrayList#add
80+
l[1:3] # => [2, 3]
81+
l.pop(1) # => 2; l: [1, 3, 4]
82+
l.insert(1, 2) # l: [1, 2, 3, 4]
83+
l == [1, 2, 3, 4] # True
84+
85+
h = HashMap()
86+
h[1] = 2 # h: {1: 2}
87+
h.setdefault(3, 4) # h: {1: 2, 3: 4}
88+
h |= {3: 6} # {1: 2, 3: 6}
89+
h == {1: 2, 3: 6} # True
90+
```
91+
92+
Specifically:
93+
* Foreign lists inherit from Python `list`
94+
* Foreign dictionaries inherit from `dict`
95+
* Foreign iterators inherit from `iterator`
96+
* Foreign exceptions inherit from `BaseException`
97+
* Foreign none/null inherit from `NoneType`
98+
6299
## Interacting with other dynamic languages from Python scripts
63100

64101
More general, non-JVM specific interactions with other languages from Python scripts are achieved via the _polyglot_ API.

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/iterator/IteratorBuiltins.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -465,7 +465,7 @@ static int foreign(Object self,
465465
@Bind("this") Node inliningTarget,
466466
@Cached IsForeignObjectNode isForeignObjectNode,
467467
@CachedLibrary(limit = "getCallSiteInlineCacheMaxDepth()") InteropLibrary interop,
468-
@Cached(inline = false) GilNode gil) {
468+
@Cached GilNode gil) {
469469
gil.release(true);
470470
try {
471471
return interop.hasIteratorNextElement(self) ? 1 : 0;

0 commit comments

Comments
 (0)