Skip to content

Commit 0629b84

Browse files
committed
[GR-15672] [GR-14782] Extend polyglot API support
PullRequest: graalpython/546
2 parents f8ae3fe + 2f734b3 commit 0629b84

File tree

6 files changed

+98
-10
lines changed

6 files changed

+98
-10
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,12 @@
33
This changelog summarizes major changes between GraalVM versions of the Python
44
language runtime. The main focus is on user-observable behavior of the engine.
55

6+
## Version 20.0.0 beta 2
7+
8+
* Add `java.add_to_classpath` API to dynamically extend the host class path
9+
* Allow write access to main module bindings for embedder
10+
* Swap arguments for `polyglot.export_value` to use the more natural (name, value) order and deprecate the previous argument order.
11+
612
## Version 20.0.0 beta 1
713

814
* Update Python standard library files to Python 3.7.3

graalpython/com.oracle.graal.python.test/src/com/oracle/graal/python/test/interop/JavaInteropTest.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -501,6 +501,14 @@ public void accessJavaObjectGetters() throws IOException {
501501
"True <class 'bool'>\n" +
502502
"c <class 'str'>\n", out.toString("UTF-8"));
503503
}
504+
505+
@Test
506+
public void writableBindings() {
507+
context.getBindings("python").putMember("javaObj", 42);
508+
Value javaObj = context.eval("python", "javaObj");
509+
assertTrue(javaObj.isNumber());
510+
assertEquals(javaObj.asInt(), 42);
511+
}
504512
}
505513

506514
@RunWith(Parameterized.class)

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/PythonLanguage.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -458,7 +458,7 @@ protected Iterable<Scope> findTopScopes(PythonContext context) {
458458
ArrayList<Scope> scopes = new ArrayList<>();
459459
if (context.getBuiltins() != null) {
460460
// false during initialization
461-
scopes.add(Scope.newBuilder("__main__", scopeFromObject(context.getMainModule())).build());
461+
scopes.add(Scope.newBuilder("__main__", context.getMainModule()).build());
462462
scopes.add(Scope.newBuilder("builtins", scopeFromObject(context.getBuiltins())).build());
463463
}
464464
return scopes;

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/JavaModuleBuiltins.java

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,17 +48,22 @@
4848
import com.oracle.graal.python.builtins.Builtin;
4949
import com.oracle.graal.python.builtins.CoreFunctions;
5050
import com.oracle.graal.python.builtins.PythonBuiltins;
51+
import com.oracle.graal.python.builtins.objects.PNone;
5152
import com.oracle.graal.python.builtins.objects.str.PString;
5253
import com.oracle.graal.python.nodes.function.PythonBuiltinBaseNode;
54+
import com.oracle.graal.python.nodes.function.PythonBuiltinNode;
5355
import com.oracle.graal.python.nodes.function.builtins.PythonBinaryBuiltinNode;
5456
import com.oracle.graal.python.nodes.function.builtins.PythonUnaryBuiltinNode;
57+
import com.oracle.graal.python.nodes.util.CastToStringNode;
5558
import com.oracle.graal.python.runtime.PythonCore;
5659
import com.oracle.graal.python.runtime.exception.PythonErrorType;
5760
import com.oracle.truffle.api.TruffleLanguage.Env;
61+
import com.oracle.truffle.api.dsl.Cached;
5862
import com.oracle.truffle.api.dsl.Fallback;
5963
import com.oracle.truffle.api.dsl.GenerateNodeFactory;
6064
import com.oracle.truffle.api.dsl.NodeFactory;
6165
import com.oracle.truffle.api.dsl.Specialization;
66+
import com.oracle.truffle.api.frame.VirtualFrame;
6267
import com.oracle.truffle.api.interop.TruffleObject;
6368

6469
@CoreFunctions(defineModule = "java")
@@ -106,6 +111,28 @@ Object type(PString name) {
106111
}
107112
}
108113

114+
@Builtin(name = "add_to_classpath", takesVarArgs = true, doc = "Add all arguments to the classpath.")
115+
@GenerateNodeFactory
116+
abstract static class AddToClassPathNode extends PythonBuiltinNode {
117+
@Specialization
118+
PNone add(VirtualFrame frame, Object[] args,
119+
@Cached CastToStringNode castToString) {
120+
Env env = getContext().getEnv();
121+
if (!env.isHostLookupAllowed()) {
122+
throw raise(PythonErrorType.NotImplementedError, "host access is not allowed");
123+
}
124+
for (Object arg : args) {
125+
String entry = castToString.execute(frame, arg);
126+
try {
127+
env.addToHostClassPath(env.getTruffleFile(entry));
128+
} catch (SecurityException e) {
129+
throw raise(TypeError, "invalid or unreadable classpath: '%s' - %m", entry, e);
130+
}
131+
}
132+
return PNone.NONE;
133+
}
134+
}
135+
109136
@Builtin(name = "is_function", minNumOfPositionalArgs = 1)
110137
@GenerateNodeFactory
111138
abstract static class IsFunctionNode extends PythonUnaryBuiltinNode {

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PolyglotModuleBuiltins.java

Lines changed: 54 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,11 @@ public abstract static class ImportNode extends PythonBuiltinNode {
119119
@Specialization
120120
@TruffleBoundary
121121
public Object importSymbol(String name) {
122-
Object object = getContext().getEnv().importSymbol(name);
122+
Env env = getContext().getEnv();
123+
if (!env.isPolyglotAccessAllowed()) {
124+
throw raise(PythonErrorType.NotImplementedError, "polyglot access is not allowed");
125+
}
126+
Object object = env.importSymbol(name);
123127
if (object == null) {
124128
return PNone.NONE;
125129
}
@@ -134,6 +138,9 @@ abstract static class EvalInteropNode extends PythonBuiltinNode {
134138
@Specialization
135139
Object evalString(@SuppressWarnings("unused") PNone path, String value, String langOrMimeType) {
136140
Env env = getContext().getEnv();
141+
if (!env.isPolyglotAccessAllowed()) {
142+
throw raise(PythonErrorType.NotImplementedError, "polyglot access is not allowed");
143+
}
137144
try {
138145
boolean mimeType = isMimeType(langOrMimeType);
139146
String lang = mimeType ? findLanguageByMimeType(env, langOrMimeType) : langOrMimeType;
@@ -159,6 +166,9 @@ private void raiseIfInternal(Env env, String lang) {
159166
@Specialization
160167
Object evalFile(String path, @SuppressWarnings("unused") PNone string, String langOrMimeType) {
161168
Env env = getContext().getEnv();
169+
if (!env.isPolyglotAccessAllowed()) {
170+
throw raise(PythonErrorType.NotImplementedError, "polyglot access is not allowed");
171+
}
162172
try {
163173
boolean mimeType = isMimeType(langOrMimeType);
164174
String lang = mimeType ? findLanguageByMimeType(env, langOrMimeType) : langOrMimeType;
@@ -179,6 +189,9 @@ Object evalFile(String path, @SuppressWarnings("unused") PNone string, String la
179189
@Specialization
180190
Object evalFile(String path, @SuppressWarnings("unused") PNone string, @SuppressWarnings("unused") PNone lang) {
181191
Env env = getContext().getEnv();
192+
if (!env.isPolyglotAccessAllowed()) {
193+
throw raise(PythonErrorType.NotImplementedError, "polyglot access is not allowed");
194+
}
182195
try {
183196
return getContext().getEnv().parse(Source.newBuilder(PythonLanguage.ID, env.getTruffleFile(path)).name(path).build()).call();
184197
} catch (IOException e) {
@@ -218,30 +231,59 @@ protected boolean isMimeType(String lang) {
218231
}
219232
}
220233

221-
@Builtin(name = "export_value", minNumOfPositionalArgs = 1, parameterNames = {"value", "name"})
234+
@Builtin(name = "export_value", minNumOfPositionalArgs = 1, parameterNames = {"name", "value"})
222235
@GenerateNodeFactory
223236
public abstract static class ExportSymbolNode extends PythonBuiltinNode {
224237
@Child private GetAttributeNode getNameAttributeNode;
225238
@Child private CastToStringNode castToStringNode;
226239

227-
@Specialization
240+
@Specialization(guards = "!isString(value)")
228241
@TruffleBoundary
229-
public Object exportSymbol(Object value, String name) {
230-
getContext().getEnv().exportSymbol(name, value);
242+
public Object exportSymbolKeyValue(String name, Object value) {
243+
Env env = getContext().getEnv();
244+
if (!env.isPolyglotAccessAllowed()) {
245+
throw raise(PythonErrorType.NotImplementedError, "polyglot access is not allowed");
246+
}
247+
env.exportSymbol(name, value);
231248
return value;
232249
}
233250

251+
@Specialization(guards = "!isString(value)")
252+
@TruffleBoundary
253+
public Object exportSymbolValueKey(Object value, String name) {
254+
PythonLanguage.getLogger().warning("[deprecation] polyglot.export_value(value, name) is deprecated " +
255+
"and will be removed. Please swap the arguments.");
256+
return exportSymbolKeyValue(name, value);
257+
}
258+
259+
@Specialization(guards = "isString(arg1)")
260+
@TruffleBoundary
261+
public Object exportSymbolAmbiguous(Object arg1, String arg2) {
262+
PythonLanguage.getLogger().warning("[deprecation] polyglot.export_value(str, str) is ambiguous. In the future, this will " +
263+
"default to using the first argument as the name and the second as value, but now it " +
264+
"uses the first argument as value and the second as the name.");
265+
return exportSymbolValueKey(arg1, arg2);
266+
}
267+
234268
@Specialization
235269
@TruffleBoundary
236270
public Object exportSymbol(PFunction fun, @SuppressWarnings("unused") PNone name) {
237-
getContext().getEnv().exportSymbol(fun.getName(), fun);
271+
Env env = getContext().getEnv();
272+
if (!env.isPolyglotAccessAllowed()) {
273+
throw raise(PythonErrorType.NotImplementedError, "polyglot access is not allowed");
274+
}
275+
env.exportSymbol(fun.getName(), fun);
238276
return fun;
239277
}
240278

241279
@Specialization
242280
@TruffleBoundary
243281
public Object exportSymbol(PBuiltinFunction fun, @SuppressWarnings("unused") PNone name) {
244-
getContext().getEnv().exportSymbol(fun.getName(), fun);
282+
Env env = getContext().getEnv();
283+
if (!env.isPolyglotAccessAllowed()) {
284+
throw raise(PythonErrorType.NotImplementedError, "polyglot access is not allowed");
285+
}
286+
env.exportSymbol(fun.getName(), fun);
245287
return fun;
246288
}
247289

@@ -280,7 +322,11 @@ protected static boolean isModule(Object o) {
280322

281323
@TruffleBoundary
282324
private void export(String name, Object obj) {
283-
getContext().getEnv().exportSymbol(name, obj);
325+
Env env = getContext().getEnv();
326+
if (!env.isPolyglotAccessAllowed()) {
327+
throw raise(PythonErrorType.NotImplementedError, "polyglot access is not allowed");
328+
}
329+
env.exportSymbol(name, obj);
284330
}
285331
}
286332

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/PythonAbstractObject.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@
5656
import com.oracle.graal.python.builtins.objects.function.PKeyword;
5757
import com.oracle.graal.python.builtins.objects.ints.PInt;
5858
import com.oracle.graal.python.builtins.objects.list.PList;
59+
import com.oracle.graal.python.builtins.objects.module.PythonModule;
5960
import com.oracle.graal.python.builtins.objects.object.PythonBuiltinObject;
6061
import com.oracle.graal.python.builtins.objects.object.PythonObject;
6162
import com.oracle.graal.python.builtins.objects.str.PString;
@@ -678,7 +679,7 @@ public boolean isImmutable(Object object,
678679
// 'type'
679680
if (object instanceof PythonBuiltinClass || object instanceof PythonBuiltinObject || PGuards.isNativeClass(object) || PGuards.isNativeObject(object)) {
680681
return true;
681-
} else if (object instanceof PythonClass) {
682+
} else if (object instanceof PythonClass || object instanceof PythonModule) {
682683
return false;
683684
} else {
684685
LazyPythonClass klass = getClass.execute(object);

0 commit comments

Comments
 (0)