Skip to content

Commit 08eaa6f

Browse files
committed
[GR-62585][GR-61949] Create troubleshooting document in user docs.
PullRequest: graalpython/3702
2 parents 06f88f4 + 7801764 commit 08eaa6f

File tree

5 files changed

+185
-13
lines changed

5 files changed

+185
-13
lines changed

docs/site/01-docs.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,5 +14,6 @@ permalink: docs/
1414
{% gfm_docs ../user/Embedding-Build-Tools.md %}
1515
{% gfm_docs ../user/Embedding-Permissions.md %}
1616
{% gfm_docs ../user/Tooling.md %}
17+
{% gfm_docs ../user/Troubleshooting.md %}
1718

1819
{% copy_assets ../user/assets %}

docs/user/Embedding-Build-Tools.md

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ required for embedding Python code in Java-based applications:
66
- *Third-party Python packages* installed by the plugin during the build according to the plugin configuration.
77

88
Apart from physically managing and deploying those files, it is also necessary to make them available in Python at runtime by configuring the **GraalPy Context** in your Java code accordingly.
9-
The [GraalPyResources](https://github.com/oracle/graalpython/blob/master/graalpython/org.graalvm.python.embedding/src/org/graalvm/python/embedding/utils/GraalPyResources.java) API provides factory methods to create a Context preconfigured for accessing Python, embedding relevant resources with a **Virtual Filesystem** or from a dedicated **external directory**.
9+
The [GraalPyResources](https://github.com/oracle/graalpython/blob/master/graalpython/org.graalvm.python.embedding/src/org/graalvm/python/embedding/GraalPyResources.java) API provides factory methods to create a Context preconfigured for accessing Python, embedding relevant resources with a **Virtual Filesystem** or from a dedicated **external directory**.
1010

1111
## Deployment
1212

@@ -26,7 +26,7 @@ User can choose relative Java resources path that will be made accessible in Pyt
2626
by default it is `org.graalvm.python.vfs`. All resources subdirectories with this path are merged during build and mapped to a configurable Virtual Filesystem mount point at the Python side, by default `/graalpy_vfs`.
2727
For example, a Python file with the real filesystem path `${project_resources_directory}/org.graalvm.python.vfs/src/foo/bar.py` will be accessible as `/graalpy_vfs/src/foo/bar.py` in Python.
2828

29-
Use the following [GraalPyResources](https://github.com/oracle/graalpython/blob/master/graalpython/org.graalvm.python.embedding/src/org/graalvm/python/embedding/utils/GraalPyResources.java)
29+
Use the following [GraalPyResources](https://github.com/oracle/graalpython/blob/master/graalpython/org.graalvm.python.embedding/src/org/graalvm/python/embedding/GraalPyResources.java)
3030
factory methods to create GraalPy Context preconfigured for the use of the Virtual Filesystem:
3131
* `GraalPyResources.createContext()`
3232
* `GraalPyResources.contextBuilder()`
@@ -48,18 +48,33 @@ at runtime using the `VirtualFileSystem$Builder#resourceDirectory` API.
4848
This is also the case of the default virtual filesystem location.
4949
When a resources directory is not a valid Java package name, such as the recommended "GRAALPY-VFS", the resources are not subject to the encapsulation rules and do not require additional module system configuration.*
5050

51+
#### Extracting files from Virtual Filesystem
52+
Normally, Virtual Filesystem resources are loaded like java resources, but there are cases when files need to be accessed
53+
outside the Truffle sandbox, e.g. Python C extension files which need to be accessed by the operating system loader.
54+
55+
By default, files which are of type `.so`, `.dylib`, `.pyd`, `.dll`, or `.ttf`, are automatically extracted to a temporary directory
56+
in the real filesystem when accessed for the first time and the Virtual Filesystem then delegates to those real files.
57+
58+
The default extract rule can be enhanced using the `VirtualFileSystem$Builder#extractFilter` API.
59+
60+
Alternatively, it is possible to extract all Python resources into a user-defined directory before creating a GraalPy
61+
context, and then configure the context to use that directory. Please refer to the following [GraalPyResources](https://github.com/oracle/graalpython/blob/master/graalpython/org.graalvm.python.embedding/src/org/graalvm/python/embedding/GraalPyResources.java)
62+
methods for more details:
63+
* `GraalPyResources.extractVirtualFileSystemResources(VirtualFileSystem vfs, Path externalResourcesDirectory)`
64+
* `GraalPyResourcescontextBuilder(Path externalResourcesDirectory)`
65+
5166
### External Directory
5267

5368
As an alternative to Java resources with the Virtual Filesystem, it is also possible to configure the Maven or Gradle plugin to manage the contents of an external directory, which will **not be embedded** as a Java resource into the resulting application.
5469
A user is then responsible for the deployment of such directory.
5570
Python code will access the files directly from the real filesystem.
5671

57-
Use the following [GraalPyResources](https://github.com/oracle/graalpython/blob/master/graalpython/org.graalvm.python.embedding/src/org/graalvm/python/embedding/utils/GraalPyResources.java) factory methods to create GraalPy Context preconfigured for the use of an external directory:
72+
Use the following [GraalPyResources](https://github.com/oracle/graalpython/blob/master/graalpython/org.graalvm.python.embedding/src/org/graalvm/python/embedding/GraalPyResources.java) factory methods to create GraalPy Context preconfigured for the use of an external directory:
5873
* `GraalPyResources.createContextBuilder(Path)`
5974

6075
## Conventions
6176

62-
The factory methods in [GraalPyResources](https://github.com/oracle/graalpython/blob/master/graalpython/org.graalvm.python.embedding/src/org/graalvm/python/embedding/utils/GraalPyResources.java) rely on the following conventions, where the `${root}` is either an external directory, or a Virtual System mount point on the Python side and Java resources directories, such as `${project_resources_directory}/org.graalvm.python.vfs`, on the real filesystem:
77+
The factory methods in [GraalPyResources](https://github.com/oracle/graalpython/blob/master/graalpython/org.graalvm.python.embedding/src/org/graalvm/python/embedding/GraalPyResources.java) rely on the following conventions, where the `${root}` is either an external directory, or a Virtual System mount point on the Python side and Java resources directories, such as `${project_resources_directory}/org.graalvm.python.vfs`, on the real filesystem:
6378
- `${root}/src`: used for Python application files. This directory will be configured as the default search path for Python module files (equivalent to `PYTHONPATH` environment variable).
6479
- `${root}/venv`: used for the Python virtual environment holding installed third-party Python packages.
6580
The Context will be configured as if it is executed from this virtual environment. Notably packages installed in this
@@ -161,7 +176,7 @@ For more information on managing Python packages, please refer to the descriptio
161176
the `graalPyLockFile` and `packages` fields in the [plugin configuration](#maven-plugin-configuration), as well as the [Python Dependency Management](#python-dependency-management) section
162177
above in this document.
163178

164-
## GraalPy Gradle Plugin
179+
## GraalPy Gradle Plugin
165180

166181
### Gradle Plugin Configuration
167182
The plugin must be added to the plugins section in the _build.gradle_ file.

docs/user/Troubleshooting.md

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
# GraalPy Troubleshooting
2+
3+
[[TOC]]
4+
5+
## GraalPy Embedding
6+
7+
#### VirtualFileSystem cannot load a file
8+
There are situations where a file cannot be loaded even though it is part of the Virtual Filesystem resources.
9+
GraalPy tries to prevent such situations by automatically [extracting](Embedding-Build-Tools.md#extracting-files-from-virtual-filesystem)
10+
some well known files to the real filesystem, but if you see an error like:
11+
```
12+
ImportError: cannot load /graalpy_vfs/venv/lib/python3.11/site-packages/_cffi_backend.graalpy250dev09433ef706-311-native-aarch64-darwin.so:
13+
NFIUnsatisfiedLinkError: dlopen(/graalpy_vfs/venv/lib/python3.11/site-packages/_cffi_backend.graalpy250dev09433ef706-311-native-aarch64-darwin.so, 0x0002):
14+
```
15+
then the default behavior did not work as intended.
16+
17+
Depending on how you [deploy Python resources](Embedding-Build-Tools.md#deployment) in your application, you can try one of the following:
18+
- if you need to package resources within your Jar or Native Image executable:
19+
- if the problematic file is not one of the following types: `.so`, `.dylib`, `.pyd`, `.dll`, or `.ttf`, which are extracted to
20+
the real filesystem by default, you can simply attempt to add it to the extraction filter using:
21+
```java
22+
VirtualFileSystem.Builder.extractFilter(filter);
23+
```
24+
- if the previous does not help, it is also possible to extract all Python resources into a user-defined directory before creating a GraalPy
25+
context, and then configure the context to use that directory:
26+
```java
27+
// extract the Python resources from the jar or native image into a given directory
28+
GraalPyResources.extractVirtualFileSystemResources(VirtualFileSystem.create(), externalResourceDirectoryPath);
29+
// create a GraalPy context configured with an external Python resource directory
30+
Context context = GraalPyResources.contextBuilder(externalResourceDirectoryPath).build();
31+
```
32+
- or if you're able to ship resources in a separate directory, you have to set the `externalDirectory` tag in
33+
[Maven](Embedding-Build-Tools.md#graalpy-maven-plugin) or `externalDirectory` field in [Gradle](Embedding-Build-Tools.md#graalpy-gradle-plugin)
34+
and also configure the GraalPy context to use that directory as well:
35+
```java
36+
// create a Context configured with an external Python resource directory
37+
Context context = GraalPyResources.contextBuilder(externalResourceDirectoryPath).build();
38+
```
39+
Please **note**, that if switching from Virtual FileSystem to an external directory, also all **user files** from the previous
40+
Virtual FileSystem resource root have to be moved into that directory as well.
41+
42+
For more details about the Python resources in GraalPy Embedding please refer to the [Embedding Build Tools](Embedding-Build-Tools.md) documentation.
43+
44+
For more details about GraalPy context and Virtual FileSystem configuration please refer to [GraalPyResources](https://github.com/oracle/graalpython/blob/master/graalpython/org.graalvm.python.embedding/src/org/graalvm/python/embedding/GraalPyResources.java) and
45+
[VirtualFileSystem](https://github.com/oracle/graalpython/blob/master/graalpython/org.graalvm.python.embedding/src/org/graalvm/python/embedding/VirtualFileSystem.java) javadoc.
46+
47+
#### Issues with GraalPy 'java' posix backend
48+
The Virtual FileSystem is built on the Truffle filesystem and relies on the GraalPy Java POSIX backend.
49+
Unfortunately, certain Python packages bypass Python's I/O and directly access files through their
50+
native extensions. If you encounter an error like:
51+
```
52+
NotImplementedError: 'PyObject_AsFileDescriptor' not supported when using 'java' posix backend
53+
```
54+
then you have to override the default `java` GraalPy backend option byt setting the `native` POSIX backend
55+
and completely omit the Virtual FileSystem at runtime.
56+
57+
Depending on how you [deploy Python resources](Embedding-Build-Tools.md#deployment) in your application,
58+
you can do one of the following:
59+
60+
- if you need to package Python resources within your Jar or Native Image executable, then:
61+
```java
62+
// extract the Python resources from the jar or native image into a given directory
63+
GraalPyResources.extractVirtualFileSystemResources(VirtualFileSystem.create(), externalResourceDirectoryPath);
64+
// create a Context.Builder configured with an external python resource directory
65+
Builder builder = GraalPyResources.contextBuilder(externalResourceDirectoryPath);
66+
// override the python.PosixModuleBackend option with "native"
67+
builder.option("python.PosixModuleBackend", "native");
68+
// create a context
69+
Context context = builder.build();
70+
```
71+
- or if you're able to ship Python resources in a separate directory, you have to set the `externalDirectory` tag in
72+
[Maven](Embedding-Build-Tools.md#graalpy-maven-plugin) or `externalDirectory` field in [Gradle](Embedding-Build-Tools.md#graalpy-gradle-plugin)
73+
and configure the GraalPy context accordingly:
74+
```java
75+
// create a Context.Builder configured with an external python resource directory
76+
Builder builder = GraalPyResources.contextBuilder(externalResourceDirectoryPath);
77+
// override the python.PosixModuleBackend option with "native"
78+
builder.option("python.PosixModuleBackend", "native");
79+
// create a context
80+
Context context = builder.build();
81+
```
82+
Please **note**, that if switching from Virtual FileSystem to an external directory, also all **user files** from the previous
83+
Virtual FileSystem resource root have to be moved into that directory as well.
84+
85+
For more details about the Python resources in GraalPy Embedding please refer to the [Embedding Build Tools](Embedding-Build-Tools.md) documentation.
86+
87+
For more details about GraalPy context and Virtual FileSystem configuration please refer to [GraalPyResources](https://github.com/oracle/graalpython/blob/master/graalpython/org.graalvm.python.embedding/src/org/graalvm/python/embedding/GraalPyResources.java) and
88+
[VirtualFileSystem](https://github.com/oracle/graalpython/blob/master/graalpython/org.graalvm.python.embedding/src/org/graalvm/python/embedding/VirtualFileSystem.java) javadoc.
89+
90+
### Maven and Gradle applications
91+
92+
#### ImportError reports "unknown location"
93+
A possible cause of an `ImportError` ending with `(unknown location)` when running a GraalPy Java Embedding project might be
94+
that an embedded Python package was built for a different operating system. If you see an error like the following:
95+
```
96+
ImportError: cannot import name 'exceptions' from 'cryptography.hazmat.bindings._rust' (unknown location)
97+
```
98+
You probably need to rebuild your project on the correct operating system before running it.
99+
100+
#### GraalVM JDK Compatibility
101+
To enable runtime compilation when running GraalPy from a Maven or Gradle application,
102+
you must use versions of GraalPy and the Polyglot API dependencies that are compatible
103+
with the specified GraalVM JDK version. If you see errors like the following:
104+
105+
```
106+
Your Java runtime '23.0.1+11-jvmci-b01' with compiler version '24.1.1' is incompatible with polyglot version '24.1.0'.
107+
```
108+
You need to keep the versions of your GraalPy and Polyglot dependencies according to the error message,
109+
so either upgrade the version of your JDK or your polyglot and GraalPy dependencies.
110+
111+
Note, this can also apply to cases when your dependencies are transitively pulled in by another artifact,
112+
e.g. micronaut-graalpy.
113+
114+
#### The following artifacts could not be resolved: org.graalvm.python:python-language-enterprise
115+
`python-language-enterprise` was discontinued, use `org.graalvm.polyglot:python` instead.
116+
117+
#### Issues with Meson build system when installing Python packages on OSX with Maven or Gradle GraalPy plugin
118+
Errors like the following:
119+
```
120+
../meson.build:1:0: ERROR: Failed running 'cython', binary or interpreter not executable.
121+
```
122+
123+
could be caused by the GraalPy launcher used internally by the Maven or Gradle GraalPy plugin
124+
for installing Python packages. Currently, there is no straightforward solution. However,
125+
a workaround is to set the Java system property graalpy.vfs.venvLauncher to a launcher from
126+
a downloaded [GraalPy](https://github.com/oracle/graalpython/releases/) distribution with a version
127+
matching the GraalPy Maven artifacts version.
128+
129+
e.g.
130+
```
131+
mvn package -Dgraalpy.vfs.venvLauncher={graalpy_directroy}/Contents/Home/bin/graalpy
132+
```
133+
134+
#### No language and polyglot implementation was found on the module-path.
135+
If you see an error like:
136+
```
137+
java.lang.IllegalStateException: No language and polyglot implementation was found on the module-path. Make sure at last one language is added to the module-path.
138+
```
139+
you are probably missing the python langauge dependency in your Maven of Gradle configuration file.
140+
You need to add either `org.graalvm.polyglot:python` or `org.graalvm.polyglot:python-community` to your dependencies.
141+

graalpython/org.graalvm.python.embedding/src/org/graalvm/python/embedding/GraalPyResources.java

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -76,10 +76,12 @@
7676
* </p>
7777
*
7878
* <p>
79-
* In order to make this work, it is necessary for those embedded resources to have their <b>root
80-
* directory</b> set to <code>/org.graalvm.python.vfs</code> which in python code will be mapped to
81-
* the virtual filesystem <b>mount point</b>, by default <code>/graalpy_vfs</code>. Refer to
82-
* {@link VirtualFileSystem.Builder} documentation for more details.
79+
* In order to make this work, it is necessary for those embedded resources to have a common
80+
* <b>resource root directory</b>. The default value is <code>/org.graalvm.python.vfs</code>,
81+
* however the recommended convention is to use {@code GRAALPY-VFS/{groupId}/{artifactId}}. This
82+
* root directory will then be in python code mapped to the virtual filesystem <b>mount point</b>,
83+
* by default <code>/graalpy_vfs</code>. Refer to
84+
* {@link VirtualFileSystem.Builder#resourceDirectory(String)} documentation for more details.
8385
* </p>
8486
*
8587
* <h3>External Directory</h3>
@@ -354,7 +356,13 @@ public static Context.Builder contextBuilder(VirtualFileSystem vfs) {
354356
* <code>/python/venv</code> (python virtual environment)</li>
355357
* </ul>
356358
* </p>
357-
*
359+
*
360+
* <p/>
361+
* When Maven or Gradle GraalPy plugin is used to build the virtual environment, it also has to
362+
* be configured to generate the virtual environment into the same directory using the
363+
* {@code <externalDirectory>} tag in Maven or the {@code externalDirectory} field in Gradle.
364+
* <p/>
365+
*
358366
* @param externalResourcesDirectory the root directory with GraalPy specific embedding
359367
* resources
360368
* @return a new {@link org.graalvm.polyglot.Context.Builder} instance

graalpython/org.graalvm.python.embedding/src/org/graalvm/python/embedding/VirtualFileSystem.java

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -119,10 +119,17 @@ private Builder() {
119119
* <p/>
120120
* User scripts, data files, and other resources that should be accessible in Python should
121121
* be put into this resource directory, e.g.,
122-
* {@code src/main/resources/org.graalvm.python.vfs} for the default value of this option
123-
* and assuming the usual layout of a Maven or Gradle project.
122+
* {@code src/main/resources/org.graalvm.python.vfs/src} where:
123+
* <ul>
124+
* <li>assuming the usual layout of a Maven or Gradle project then the
125+
* {@code src/main/resources/org.graalvm.python.vfs} prefix is the default value of the
126+
* {@code resourceDirectory} option</li>
127+
* <li>and the following {@code src} directory is the folder used by {@link GraalPyResources
128+
* convention} for Python application files and is configured as the default search path for
129+
* Python module files.</i>
130+
* </ul>
124131
* <p/>
125-
* When Maven and Gradle GraalPy plugin is used to build the virtual environment, it should
132+
* When Maven or Gradle GraalPy plugin is used to build the virtual environment, it should
126133
* be configured to generate the virtual environment into the same directory using the
127134
* {@code <resourceDirectory>} tag in Maven or the {@code resourceDirectory} field in
128135
* Gradle.

0 commit comments

Comments
 (0)