|
50 | 50 | import org.graalvm.polyglot.io.IOAccess;
|
51 | 51 |
|
52 | 52 | import java.io.File;
|
| 53 | +import java.io.IOException; |
53 | 54 | import java.nio.file.Path;
|
54 | 55 | import java.nio.file.Paths;
|
55 | 56 | import java.util.function.Predicate;
|
56 | 57 |
|
57 | 58 | /**
|
58 |
| - * This class provides utilities related to specific GraalPy resources used with GraalPy embedding |
| 59 | + * This class provides utilities related to GraalPy specific resources used in embedding |
59 | 60 | * scenarios.</br>
|
60 |
| - * |
61 | 61 | * <p>
|
62 |
| - * Resource file access during runtime is provided either: |
63 | 62 | * <ul>
|
64 |
| - * <li>from a virtual {@link FileSystem} - if distributed in a jar file or as a native image</li> |
65 |
| - * <li>or from a real filesystem</li> |
| 63 | + * <li>The GraalPy standard library</li> |
| 64 | + * <li>The python virtual environment providing third party python packages</li> |
| 65 | + * <li>Additional python files</li> |
| 66 | + * </ul> |
| 67 | + * </p> |
| 68 | + * |
| 69 | + * Resource files can be distributed either in a jar file or as part of a native image executable or |
| 70 | + * in an external filesystem directory. |
66 | 71 | * </ul>
|
67 | 72 | *
|
68 |
| - * <h3>Virtual File System usage</h3> Resource files in a virtual {@link FileSystem} are accessed as |
69 |
| - * a java resource located in a jar and expected to have the root directory |
70 |
| - * <code>/org.graalvm.python.vfs</code>, where: |
| 73 | + * <h3>Virtual File System</h3> |
| 74 | + * <p> |
| 75 | + * Resources distributed in one application file (either jar or native image) are accessed in |
| 76 | + * runtime through a virtual {@link FileSystem} and expected to have the root directory |
| 77 | + * <code>/org.graalvm.python.vfs</code>, where then:<br/> |
| 78 | + * </p> |
71 | 79 | * <ul>
|
72 |
| - * <li><code>/org.graalvm.python.vfs/home</code> - is a directory with the GraalPy standard |
| 80 | + * <li><code>/org.graalvm.python.vfs/home</code> - is the directory with the GraalPy standard |
73 | 81 | * library</li>
|
74 |
| - * <li><code>/org.graalvm.python.vfs/venv</code> - is a directory with a python virtual environment |
75 |
| - * holding third-party packages</li> |
76 |
| - * <li><code>/org.graalvm.python.vfs/src</code> - is a directory with additional user files - e.g. |
| 82 | + * <li><code>/org.graalvm.python.vfs/venv</code> - is the directory with a python virtual |
| 83 | + * environment holding third-party packages</li> |
| 84 | + * <li><code>/org.graalvm.python.vfs/src</code> - is the directory with additional user files - e.g. |
77 | 85 | * python sources files</li>
|
78 | 86 | * </ul>
|
79 | 87 | * </p>
|
| 88 | + * <b>Example</b> creating a GraalPy context configured for the usage with a virtual |
| 89 | + * {@link FileSystem}: |
| 90 | + * |
| 91 | + * <pre> |
| 92 | + * try (Context context = GraalPyResources.createContext()) { |
| 93 | + * context.eval("python", "print('Hello World')"); |
| 94 | + * } catch (PolyglotException e) { |
| 95 | + * if (e.isExit()) { |
| 96 | + * System.exit(e.getExitStatus()); |
| 97 | + * } else { |
| 98 | + * throw e; |
| 99 | + * } |
| 100 | + * } |
| 101 | + * </pre> |
| 102 | + * |
| 103 | + * In this example we: |
| 104 | + * <ul> |
| 105 | + * <li>create a GraalPy context preconfigured with a virtual {@link FileSystem}</li> |
| 106 | + * <li>use the context to invoke a python snippet</li> |
| 107 | + * </ul> |
80 | 108 | *
|
81 |
| - * <h3>Real File System usage</h3> Instead of distributing GraalPy embedding resources embedded in a |
82 |
| - * jar file, it is also possible to keep them a real filesystem directory with the same |
83 |
| - * sub-structure as in the case of a virtual {@link FileSystem}. |
| 109 | + * <h3>External resource directory</h3> |
| 110 | + * <p> |
| 111 | + * Instead of distributing GraalPy embedding resources embedded in one application file, it is also |
| 112 | + * possible to keep them in a external directory with the same sub-structure as in the case of a |
| 113 | + * virtual {@link FileSystem}: |
| 114 | + * </p> |
84 | 115 | * <ul>
|
85 |
| - * <li><code>{resourcesRootDirectory}/home</code> - is a directory with the GraalPy standard |
| 116 | + * <li><code>{resourcesRootDirectory}/home</code> - is the directory with the GraalPy standard |
86 | 117 | * library</li>
|
87 |
| - * <li><code>{resourcesRootDirectory}/venv</code> - is a directory with a python virtual environment |
88 |
| - * holding third-party packages</li> |
89 |
| - * <li><code>{resourcesRootDirectory}/src</code> - is a directory with additional user files - e.g. |
90 |
| - * python sources files</li> |
| 118 | + * <li><code>{resourcesRootDirectory}/venv</code> - is the directory with a python virtual |
| 119 | + * environment holding third-party packages</li> |
| 120 | + * <li><code>{resourcesRootDirectory}/src</code> - is the directory with additional user files - |
| 121 | + * e.g. python sources files</li> |
91 | 122 | * </ul>
|
| 123 | + * |
| 124 | + * <b>Example</b> creating a GraalPy context configured for the usage with an external resource |
| 125 | + * directory: |
| 126 | + * |
| 127 | + * <pre> |
| 128 | + * try (Context context = GraalPyResources.contextBuilder(Path.of("python")).build()) { |
| 129 | + * context.eval("python", "import mymodule; mymodule.print_hello_world()"); |
| 130 | + * } catch (PolyglotException e) { |
| 131 | + * if (e.isExit()) { |
| 132 | + * System.exit(e.getExitStatus()); |
| 133 | + * } else { |
| 134 | + * throw e; |
| 135 | + * } |
| 136 | + * } |
| 137 | + * </pre> |
| 138 | + * |
| 139 | + * In this example we: |
| 140 | + * <ul> |
| 141 | + * <li>create a GraalPy context which is preconfigured with GraalPy resources in an external |
| 142 | + * resource directory</li> |
| 143 | + * <li>use the context to import the python module <code>mymodule</code>, which should be either |
| 144 | + * located in <code>/python/src</code> or in a python package installed in <code>/python/venv</code> |
| 145 | + * (python virtual environment)</li> |
| 146 | + * </ul> |
| 147 | + * |
92 | 148 | */
|
93 | 149 | public class GraalPyResources {
|
94 | 150 |
|
@@ -141,10 +197,22 @@ public static Context.Builder contextBuilder(FileSystem fs) {
|
141 | 197 | * @param resourcesPath the root directory with GraalPy specific embedding resources
|
142 | 198 | */
|
143 | 199 | public static Context.Builder contextBuilder(Path resourcesPath) {
|
144 |
| - return createContextBuilder().allowIO(IOAccess.ALL). // |
145 |
| - option("python.Executable", resourcesPath.resolve(VirtualFileSystemImpl.VFS_VENV + "/bin/python").toAbsolutePath().toString()). // |
146 |
| - option("python.PythonHome", resourcesPath.resolve(VirtualFileSystemImpl.VFS_HOME).toAbsolutePath().toString()). // |
147 |
| - option("python.PythonPath", resourcesPath.resolve(VirtualFileSystemImpl.VFS_SRC).toAbsolutePath().toString()); |
| 200 | + String execPath = resourcesPath.resolve(VirtualFileSystemImpl.VFS_VENV + "/bin/python").toAbsolutePath().toString(); |
| 201 | + String homePath = resourcesPath.resolve(VirtualFileSystemImpl.VFS_HOME).toAbsolutePath().toString(); |
| 202 | + String srcPath = resourcesPath.resolve(VirtualFileSystemImpl.VFS_SRC).toAbsolutePath().toString(); |
| 203 | + return createContextBuilder(). |
| 204 | + // allow all IO access |
| 205 | + allowIO(IOAccess.ALL). |
| 206 | + // The sys.executable path, a virtual path that is used by the interpreter |
| 207 | + // to discover packages |
| 208 | + option("python.Executable", execPath).// |
| 209 | + // Set the python home to be read from the embedded resources |
| 210 | + option("python.PythonHome", homePath).// |
| 211 | + // Set python path to point to sources stored in |
| 212 | + // src/main/resources/org.graalvm.python.vfs/src |
| 213 | + option("python.PythonPath", srcPath). |
| 214 | + // pass the path to be executed |
| 215 | + option("python.InputFilePath", srcPath); |
148 | 216 | }
|
149 | 217 |
|
150 | 218 | private static Context.Builder createContextBuilder() {
|
@@ -306,6 +374,17 @@ public static String getMountPoint(FileSystem fs) {
|
306 | 374 |
|
307 | 375 | /**
|
308 | 376 | * Determines a native executable path if running in {@link ImageInfo#inImageRuntimeCode()}.
|
| 377 | + * <p> |
| 378 | + * <b>Example </b> creating a GraalPy context precofigured with an external resource directory |
| 379 | + * located next to a native image executable. |
| 380 | + * |
| 381 | + * <pre> |
| 382 | + * Path resourcesDir = GraalPyResources.getNativeExecutablePath().getParent().resolve("python"); |
| 383 | + * try (Context context = GraalPyResources.contextBuilder(resourcesDir).build()) { |
| 384 | + * context.eval("python", "print('hello world')"); |
| 385 | + * } |
| 386 | + * </pre> |
| 387 | + * </p> |
309 | 388 | *
|
310 | 389 | * @return the native executable path if it could be retrieved, otherwise <code>null</code>.
|
311 | 390 | */
|
|
0 commit comments