Skip to content

Commit f53f81a

Browse files
committed
added graalpy-micronaut-embedding project
1 parent 88c9d78 commit f53f81a

File tree

7 files changed

+408
-3
lines changed

7 files changed

+408
-3
lines changed

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,5 +88,5 @@ graalpython/com.oracle.graal.python.test/src/tests/patched_package/src/patched_p
8888
graalpython/com.oracle.graal.python.test.integration/target
8989
graalpython/graalpy-maven-plugin/target
9090
graalpython/graalpy-archetype-polyglot-app/target
91-
graalpython/graalpy-archetype-polyglot-app/target
91+
graalpython/graalpy-micronaut-embedding/target
9292
pom-mx.xml

graalpython/graalpy-maven-plugin/src/main/java/org/graalvm/python/maven/plugin/ManageResourcesMojo.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -438,8 +438,8 @@ private static Artifact getGraalPyArtifact(MavenProject project) throws MojoExec
438438
}
439439

440440
private static boolean isPythonArtifact(Artifact a) {
441-
return POLYGLOT_GROUP_ID.equals(a.getGroupId()) &&
442-
(PYTHON_COMMUNITY_ARTIFACT_ID.equals(a.getArtifactId()) || PYTHON_ARTIFACT_ID.equals(a.getArtifactId()));
441+
return (POLYGLOT_GROUP_ID.equals(a.getGroupId()) || GRAALPY_GROUP_ID.equals(a.getGroupId())) &&
442+
(PYTHON_COMMUNITY_ARTIFACT_ID.equals(a.getArtifactId()) || PYTHON_ARTIFACT_ID.equals(a.getArtifactId()));
443443
}
444444

445445
private static Collection<Artifact> resolveProjectDependencies(MavenProject project) {
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!--
3+
Copyright (c) 2023, 2023, Oracle and/or its affiliates. All rights reserved.
4+
DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5+
6+
The Universal Permissive License (UPL), Version 1.0
7+
8+
Subject to the condition set forth below, permission is hereby granted to any
9+
person obtaining a copy of this software, associated documentation and/or
10+
data (collectively the "Software"), free of charge and under any and all
11+
copyright rights in the Software, and any and all patent rights owned or
12+
freely licensable by each licensor hereunder covering either (i) the
13+
unmodified Software as contributed to or provided by such licensor, or (ii)
14+
the Larger Works (as defined below), to deal in both
15+
16+
(a) the Software, and
17+
18+
(b) any piece of software and/or hardware listed in the lrgrwrks.txt file if
19+
one is included with the Software each a "Larger Work" to which the Software
20+
is contributed by such licensors),
21+
22+
without restriction, including without limitation the rights to copy, create
23+
derivative works of, display, perform, and distribute the Software and make,
24+
use, sell, offer for sale, import, export, have made, and have sold the
25+
Software and the Larger Work(s), and to sublicense the foregoing rights on
26+
either these or other terms.
27+
28+
This license is subject to the following condition:
29+
30+
The above copyright notice and either this complete permission notice or at a
31+
minimum a reference to the UPL must be included in all copies or substantial
32+
portions of the Software.
33+
34+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
35+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
36+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
37+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
38+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
39+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
40+
SOFTWARE.
41+
-->
42+
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
43+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
44+
45+
<modelVersion>4.0.0</modelVersion>
46+
47+
<groupId>org.graalvm.python</groupId>
48+
<artifactId>graalpy-micronaut-embedding</artifactId>
49+
<packaging>jar</packaging>
50+
<version>24.1.0</version>
51+
<url>http://www.graalvm.org/</url>
52+
<name>graalpy-micronaut-embedding</name>
53+
<description>Provides GraalPy integration with Micronaut</description>
54+
55+
<properties>
56+
<maven.compiler.target>17</maven.compiler.target>
57+
<maven.compiler.source>17</maven.compiler.source>
58+
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
59+
<graalpy.version>24.1.0</graalpy.version>
60+
<micronaut.version>4.0.5</micronaut.version>
61+
</properties>
62+
63+
<dependencies>
64+
<dependency>
65+
<groupId>io.micronaut</groupId>
66+
<artifactId>micronaut-aop</artifactId>
67+
<version>${micronaut.version}</version>
68+
</dependency>
69+
<dependency>
70+
<!-- adding this only to maven-compiler-plugin/annotationProcessorPaths
71+
isn't enough with mvn < 3.9.0 -->
72+
<groupId>io.micronaut</groupId>
73+
<artifactId>micronaut-inject-java</artifactId>
74+
<version>${micronaut.version}</version>
75+
<scope>provided</scope>
76+
</dependency>
77+
<dependency>
78+
<groupId>org.graalvm.python</groupId>
79+
<artifactId>python-community</artifactId>
80+
<version>${graalpy.version}</version>
81+
<type>pom</type>
82+
<scope>runtime</scope>
83+
</dependency>
84+
<dependency>
85+
<groupId>org.graalvm.python</groupId>
86+
<artifactId>python-embedding</artifactId>
87+
<version>${graalpy.version}</version>
88+
</dependency>
89+
</dependencies>
90+
91+
<build>
92+
<plugins>
93+
<plugin>
94+
<groupId>org.apache.maven.plugins</groupId>
95+
<artifactId>maven-compiler-plugin</artifactId>
96+
<configuration>
97+
<annotationProcessorPaths>
98+
<path>
99+
<groupId>io.micronaut</groupId>
100+
<artifactId>micronaut-inject-java</artifactId>
101+
<version>${micronaut.version}</version>
102+
</path>
103+
</annotationProcessorPaths>
104+
</configuration>
105+
</plugin>
106+
</plugins>
107+
</build>
108+
</project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
/*
2+
* Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* The Universal Permissive License (UPL), Version 1.0
6+
*
7+
* Subject to the condition set forth below, permission is hereby granted to any
8+
* person obtaining a copy of this software, associated documentation and/or
9+
* data (collectively the "Software"), free of charge and under any and all
10+
* copyright rights in the Software, and any and all patent rights owned or
11+
* freely licensable by each licensor hereunder covering either (i) the
12+
* unmodified Software as contributed to or provided by such licensor, or (ii)
13+
* the Larger Works (as defined below), to deal in both
14+
*
15+
* (a) the Software, and
16+
*
17+
* (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if
18+
* one is included with the Software each a "Larger Work" to which the Software
19+
* is contributed by such licensors),
20+
*
21+
* without restriction, including without limitation the rights to copy, create
22+
* derivative works of, display, perform, and distribute the Software and make,
23+
* use, sell, offer for sale, import, export, have made, and have sold the
24+
* Software and the Larger Work(s), and to sublicense the foregoing rights on
25+
* either these or other terms.
26+
*
27+
* This license is subject to the following condition:
28+
*
29+
* The above copyright notice and either this complete permission notice or at a
30+
* minimum a reference to the UPL must be included in all copies or substantial
31+
* portions of the Software.
32+
*
33+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
34+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
35+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
36+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
37+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
38+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
39+
* SOFTWARE.
40+
*/
41+
package org.graalvm.python.embedding.micronaut;
42+
43+
import io.micronaut.context.annotation.Factory;
44+
import jakarta.annotation.PreDestroy;
45+
import jakarta.inject.Singleton;
46+
import org.graalvm.polyglot.*;
47+
import org.graalvm.polyglot.io.IOAccess;
48+
import org.graalvm.python.embedding.vfs.VirtualFileSystem;
49+
import org.graalvm.polyglot.HostAccess;
50+
51+
import java.io.IOException;
52+
import java.time.Duration;
53+
import java.time.temporal.ChronoUnit;
54+
55+
@Factory
56+
@io.micronaut.context.annotation.Context
57+
public final class GraalPyContextFactory {
58+
59+
private Context context;
60+
61+
@Singleton
62+
Context createContext() {
63+
VirtualFileSystem vfs = VirtualFileSystem.create();
64+
context = Context.newBuilder()
65+
.allowExperimentalOptions(false)
66+
.allowAllAccess(false)
67+
.allowHostAccess(HostAccess.ALL)
68+
.allowIO(IOAccess.newBuilder()
69+
.allowHostSocketAccess(true)
70+
.fileSystem(vfs)
71+
.build())
72+
.allowCreateThread(true)
73+
.allowNativeAccess(true)
74+
.allowPolyglotAccess(PolyglotAccess.ALL)
75+
.option("python.PosixModuleBackend", "java")
76+
.option("python.DontWriteBytecodeFlag", "true")
77+
.option("python.VerboseFlag", System.getenv("PYTHONVERBOSE") != null ? "true" : "false")
78+
.option("log.python.level", System.getenv("PYTHONVERBOSE") != null ? "FINE" : "SEVERE")
79+
.option("python.WarnOptions", System.getenv("PYTHONWARNINGS") == null ? "" : System.getenv("PYTHONWARNINGS"))
80+
.option("python.AlwaysRunExcepthook", "true")
81+
.option("python.ForceImportSite", "true")
82+
.option("python.Executable", vfs.vfsVenvPath() + (VirtualFileSystem.isWindows() ? "\\Scripts\\python.exe" : "/bin/python"))
83+
.option("python.PythonHome", vfs.vfsHomePath())
84+
.option("engine.WarnInterpreterOnly", "false")
85+
.option("python.PythonPath", vfs.vfsProjPath())
86+
.build();
87+
context.initialize("python");
88+
return context;
89+
}
90+
91+
@PreDestroy
92+
void close() throws IOException {
93+
try {
94+
context.interrupt(Duration.of(5, ChronoUnit.SECONDS));
95+
context.close(true);
96+
} catch (Exception e) {
97+
// ignore
98+
} finally {
99+
context = null;
100+
}
101+
}
102+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
/*
2+
* Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* The Universal Permissive License (UPL), Version 1.0
6+
*
7+
* Subject to the condition set forth below, permission is hereby granted to any
8+
* person obtaining a copy of this software, associated documentation and/or
9+
* data (collectively the "Software"), free of charge and under any and all
10+
* copyright rights in the Software, and any and all patent rights owned or
11+
* freely licensable by each licensor hereunder covering either (i) the
12+
* unmodified Software as contributed to or provided by such licensor, or (ii)
13+
* the Larger Works (as defined below), to deal in both
14+
*
15+
* (a) the Software, and
16+
*
17+
* (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if
18+
* one is included with the Software each a "Larger Work" to which the Software
19+
* is contributed by such licensors),
20+
*
21+
* without restriction, including without limitation the rights to copy, create
22+
* derivative works of, display, perform, and distribute the Software and make,
23+
* use, sell, offer for sale, import, export, have made, and have sold the
24+
* Software and the Larger Work(s), and to sublicense the foregoing rights on
25+
* either these or other terms.
26+
*
27+
* This license is subject to the following condition:
28+
*
29+
* The above copyright notice and either this complete permission notice or at a
30+
* minimum a reference to the UPL must be included in all copies or substantial
31+
* portions of the Software.
32+
*
33+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
34+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
35+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
36+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
37+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
38+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
39+
* SOFTWARE.
40+
*/
41+
package org.graalvm.python.embedding.micronaut;
42+
43+
import io.micronaut.aop.InterceptorBean;
44+
import io.micronaut.aop.MethodInterceptor;
45+
import io.micronaut.aop.MethodInvocationContext;
46+
import io.micronaut.context.ApplicationContext;
47+
import io.micronaut.context.annotation.Prototype;
48+
import io.micronaut.context.exceptions.ConfigurationException;
49+
import io.micronaut.core.annotation.Nullable;
50+
import io.micronaut.core.type.Argument;
51+
import io.micronaut.inject.ArgumentInjectionPoint;
52+
import io.micronaut.inject.BeanDefinition;
53+
import io.micronaut.inject.InjectionPoint;
54+
import org.graalvm.polyglot.Context;
55+
import org.graalvm.polyglot.PolyglotException;
56+
import org.graalvm.polyglot.Value;
57+
import org.graalvm.python.embedding.micronaut.annotations.GraalPyModuleBean;
58+
59+
@InterceptorBean(GraalPyModuleBean.class)
60+
@Prototype
61+
class GraalPyModuleIntroduction implements MethodInterceptor<Object, Object> {
62+
63+
private static final String PYTHON = "python";
64+
private final Context graalPyContext;
65+
private final Value pythonModule;
66+
private volatile Object pythonModuleInterface;
67+
68+
GraalPyModuleIntroduction(Context graalPyContext,
69+
InjectionPoint<?> injectionPoint,
70+
ApplicationContext context) {
71+
this.graalPyContext = graalPyContext;
72+
if (injectionPoint instanceof ArgumentInjectionPoint<?,?> argumentInjectionPoint) {
73+
Argument<?> argument = argumentInjectionPoint.asArgument();
74+
Class<?> beanType = argument.getType();
75+
BeanDefinition<?> beanDefinition = context.getBeanDefinition(beanType);
76+
String moduleName = beanDefinition.stringValue(GraalPyModuleBean.class).get();
77+
if(moduleName == null) {
78+
throw new ConfigurationException("GraalPyModuleBean has no module name: " + beanDefinition);
79+
}
80+
this.pythonModule = graalPyContext.eval(PYTHON, "import " + moduleName + "; " + moduleName);
81+
} else {
82+
throw new ConfigurationException("GraalPyModule cannot be used at injection point: " + injectionPoint);
83+
}
84+
}
85+
86+
@Nullable
87+
@Override
88+
public Object intercept(MethodInvocationContext<Object, Object> context) {
89+
Class<?> type = context.getDeclaringType();
90+
if(pythonModuleInterface == null) {
91+
pythonModuleInterface = pythonModule.as(type);
92+
}
93+
return context.getExecutableMethod().invoke(
94+
pythonModuleInterface,
95+
context.getParameterValues()
96+
);
97+
}
98+
99+
}

0 commit comments

Comments
 (0)