Skip to content

Commit 88f7c58

Browse files
committed
[GR-65587] Create helper to access os.environ from builtins and use it.
PullRequest: graalpython/3829
2 parents cf0daec + 9ee169e commit 88f7c58

File tree

6 files changed

+164
-78
lines changed

6 files changed

+164
-78
lines changed
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
# Copyright (c) 2025, 2025, Oracle and/or its affiliates. All rights reserved.
2+
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
3+
#
4+
# The Universal Permissive License (UPL), Version 1.0
5+
#
6+
# Subject to the condition set forth below, permission is hereby granted to any
7+
# person obtaining a copy of this software, associated documentation and/or
8+
# data (collectively the "Software"), free of charge and under any and all
9+
# copyright rights in the Software, and any and all patent rights owned or
10+
# freely licensable by each licensor hereunder covering either (i) the
11+
# unmodified Software as contributed to or provided by such licensor, or (ii)
12+
# the Larger Works (as defined below), to deal in both
13+
#
14+
# (a) the Software, and
15+
#
16+
# (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if
17+
# one is included with the Software each a "Larger Work" to which the Software
18+
# is contributed by such licensors),
19+
#
20+
# without restriction, including without limitation the rights to copy, create
21+
# derivative works of, display, perform, and distribute the Software and make,
22+
# use, sell, offer for sale, import, export, have made, and have sold the
23+
# Software and the Larger Work(s), and to sublicense the foregoing rights on
24+
# either these or other terms.
25+
#
26+
# This license is subject to the following condition:
27+
#
28+
# The above copyright notice and either this complete permission notice or at a
29+
# minimum a reference to the UPL must be included in all copies or substantial
30+
# portions of the Software.
31+
#
32+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
33+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
34+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
35+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
36+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
37+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
38+
# SOFTWARE.
39+
40+
41+
def test_sysconfig():
42+
import os, sysconfig
43+
os.environ["PATH"] += os.pathsep + r" : \ " + os.pathsep;
44+
sysconfig.get_config_vars()
45+
# must not fail

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

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -67,16 +67,12 @@
6767
import static com.oracle.graal.python.util.PythonUtils.toTruffleStringUncached;
6868
import static com.oracle.graal.python.util.PythonUtils.tsLiteral;
6969

70-
import java.io.File;
7170
import java.io.IOException;
7271
import java.io.InputStreamReader;
7372
import java.io.PrintWriter;
7473
import java.lang.management.ManagementFactory;
7574
import java.lang.reflect.Method;
7675
import java.nio.charset.StandardCharsets;
77-
import java.nio.file.Files;
78-
import java.nio.file.Path;
79-
import java.nio.file.Paths;
8076
import java.util.Arrays;
8177
import java.util.List;
8278
import java.util.logging.Level;
@@ -130,6 +126,7 @@
130126
import com.oracle.graal.python.builtins.objects.str.PString;
131127
import com.oracle.graal.python.builtins.objects.str.StringUtils;
132128
import com.oracle.graal.python.builtins.objects.tuple.PTuple;
129+
import com.oracle.graal.python.lib.OsEnvironGetNode;
133130
import com.oracle.graal.python.lib.PyObjectCallMethodObjArgs;
134131
import com.oracle.graal.python.lib.PyObjectGetItem;
135132
import com.oracle.graal.python.nodes.ErrorMessages;
@@ -631,14 +628,22 @@ private static PKeyword[] fromToolchain() {
631628

632629
private static int which() {
633630
CompilerAsserts.neverPartOfCompilation();
634-
String path = System.getenv("PATH");
631+
Env env = PythonContext.get(null).getEnv();
632+
TruffleString tspath = OsEnvironGetNode.executeUncached(T_PATH);
633+
if (tspath == null) {
634+
return -1;
635+
}
636+
String path = tspath.toJavaStringUncached();
635637
if (path != null) {
636638
for (int i = 0; i < C_COMPILER_PRECEDENCE.length; i++) {
637639
int last = 0;
638-
for (int j = path.indexOf(File.pathSeparatorChar); j != -1; j = path.indexOf(File.pathSeparatorChar, last)) {
639-
Path resolvedProgramName = Paths.get(path.substring(last, j)).resolve(C_COMPILER_PRECEDENCE[i]);
640-
if (Files.isExecutable(resolvedProgramName)) {
641-
return i;
640+
for (int j = path.indexOf(env.getPathSeparator()); j != -1; j = path.indexOf(env.getPathSeparator(), last)) {
641+
try {
642+
if (env.getPublicTruffleFile(path.substring(last, j)).resolve(C_COMPILER_PRECEDENCE[i]).isExecutable()) {
643+
return i;
644+
}
645+
} catch (UnsupportedOperationException | IllegalArgumentException e) {
646+
// skip
642647
}
643648
/*
644649
* next start is the char after the separator because we have "path0:path1"
@@ -902,6 +907,7 @@ TruffleString doit(VirtualFrame frame,
902907
@Builtin(name = "java_assert", minNumOfPositionalArgs = 0)
903908
@GenerateNodeFactory
904909
abstract static class JavaAssertNode extends PythonBuiltinNode {
910+
@SuppressWarnings("all")
905911
@Specialization
906912
Object doit() {
907913
boolean assertOn = false;
@@ -1017,7 +1023,7 @@ abstract static class GetPythonHomePaths extends PythonBuiltinNode {
10171023
@Specialization
10181024
TruffleString get() {
10191025
PythonContext context = getContext();
1020-
TruffleString sep = TruffleString.fromJavaStringUncached(File.pathSeparator, TS_ENCODING);
1026+
TruffleString sep = TruffleString.fromJavaStringUncached(context.getEnv().getPathSeparator(), TS_ENCODING);
10211027
return context.getStdlibHome().concatUncached(sep, TS_ENCODING, false).concatUncached(context.getCoreHome(), TS_ENCODING, false);
10221028
}
10231029
}
@@ -1096,6 +1102,7 @@ Object foreignNumberList(Object number) {
10961102
return new ForeignNumberList(number);
10971103
}
10981104

1105+
@SuppressWarnings("static-method")
10991106
@ExportLibrary(value = InteropLibrary.class, delegateTo = "number")
11001107
static final class ForeignNumberList implements TruffleObject {
11011108
final Object number;
@@ -1140,7 +1147,7 @@ Object foreignWrapper(Object object) {
11401147
return new ForeignWrapper(object);
11411148
}
11421149

1143-
@SuppressWarnings("unused")
1150+
@SuppressWarnings({"unused", "static-method"})
11441151
@ExportLibrary(value = InteropLibrary.class, delegateTo = "object")
11451152
static final class ForeignWrapper implements TruffleObject {
11461153
final Object object;

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

Lines changed: 2 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,6 @@
111111
import static com.oracle.graal.python.nodes.ErrorMessages.WARN_IGNORE_UNIMPORTABLE_BREAKPOINT_S;
112112
import static com.oracle.graal.python.nodes.SpecialAttributeNames.T___;
113113
import static com.oracle.graal.python.nodes.SpecialAttributeNames.T___MODULE__;
114-
import static com.oracle.graal.python.nodes.SpecialMethodNames.T_GET;
115114
import static com.oracle.graal.python.nodes.SpecialMethodNames.T___SIZEOF__;
116115
import static com.oracle.graal.python.nodes.StringLiterals.T_BACKSLASHREPLACE;
117116
import static com.oracle.graal.python.nodes.StringLiterals.T_BASE_PREFIX;
@@ -189,6 +188,7 @@
189188
import com.oracle.graal.python.builtins.objects.tuple.PTuple;
190189
import com.oracle.graal.python.builtins.objects.tuple.StructSequence;
191190
import com.oracle.graal.python.builtins.objects.tuple.TupleBuiltins;
191+
import com.oracle.graal.python.lib.OsEnvironGetNode;
192192
import com.oracle.graal.python.lib.PyExceptionInstanceCheckNode;
193193
import com.oracle.graal.python.lib.PyFloatAsDoubleNode;
194194
import com.oracle.graal.python.lib.PyFloatCheckExactNode;
@@ -222,7 +222,6 @@
222222
import com.oracle.graal.python.nodes.function.builtins.clinic.ArgumentClinicProvider;
223223
import com.oracle.graal.python.nodes.object.BuiltinClassProfiles.IsBuiltinObjectProfile;
224224
import com.oracle.graal.python.nodes.object.GetClassNode;
225-
import com.oracle.graal.python.nodes.util.CannotCastException;
226225
import com.oracle.graal.python.nodes.util.CastToTruffleStringNode;
227226
import com.oracle.graal.python.nodes.util.ExceptionStateNodes.GetCaughtExceptionNode;
228227
import com.oracle.graal.python.runtime.PosixSupportLibrary;
@@ -1703,38 +1702,21 @@ static Object doHook(VirtualFrame frame, PythonModule sys, Object obj,
17031702
@GenerateNodeFactory
17041703
abstract static class BreakpointHookNode extends PythonBuiltinNode {
17051704
static final TruffleString T_VAL_PDB_SETTRACE = tsLiteral("pdb.set_trace");
1706-
static final TruffleString T_MOD_OS = tsLiteral("os");
1707-
static final TruffleString T_ATTR_ENVIRON = tsLiteral("environ");
1708-
1709-
private static TruffleString getEnvVar(VirtualFrame frame, Node inliningTarget, PyImportImport importNode,
1710-
PyObjectGetAttr getAttr, PyObjectCallMethodObjArgs callMethodObjArgs,
1711-
CastToTruffleStringNode castToStringNode) {
1712-
Object os = importNode.execute(frame, inliningTarget, T_MOD_OS);
1713-
final Object environ = getAttr.execute(frame, inliningTarget, os, T_ATTR_ENVIRON);
1714-
Object var = callMethodObjArgs.execute(frame, inliningTarget, environ, T_GET, T_PYTHONBREAKPOINT);
1715-
try {
1716-
return castToStringNode.execute(inliningTarget, var);
1717-
} catch (CannotCastException cce) {
1718-
return null;
1719-
}
1720-
}
17211705

17221706
@Specialization
17231707
Object doHook(VirtualFrame frame, Object[] args, PKeyword[] keywords,
17241708
@Bind("this") Node inliningTarget,
17251709
@Cached CallNode callNode,
17261710
@Cached PyObjectGetAttr getAttr,
17271711
@Cached PyImportImport importNode,
1728-
@Cached PyObjectCallMethodObjArgs callMethodObjArgs,
17291712
@Cached IsBuiltinObjectProfile attrErrorProfile,
1730-
@Cached CastToTruffleStringNode castToStringNode,
17311713
@Cached BuiltinFunctions.IsInstanceNode isInstanceNode,
17321714
@Cached WarningsModuleBuiltins.WarnNode warnNode,
17331715
@Cached TruffleString.CodePointLengthNode codePointLengthNode,
17341716
@Cached TruffleString.CodePointAtIndexNode codePointAtIndexNode,
17351717
@Cached TruffleString.LastIndexOfCodePointNode lastIndexOfCodePointNode,
17361718
@Cached TruffleString.SubstringNode substringNode) {
1737-
TruffleString hookName = getEnvVar(frame, inliningTarget, importNode, getAttr, callMethodObjArgs, castToStringNode);
1719+
TruffleString hookName = OsEnvironGetNode.executeUncached(T_PYTHONBREAKPOINT);
17381720
if (hookName == null || hookName.isEmpty()) {
17391721
hookName = T_VAL_PDB_SETTRACE;
17401722
}

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/ssl/SSLContextBuiltins.java

Lines changed: 9 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,6 @@
4545
import static com.oracle.graal.python.builtins.PythonBuiltinClassType.TypeError;
4646
import static com.oracle.graal.python.builtins.PythonBuiltinClassType.ValueError;
4747
import static com.oracle.graal.python.builtins.modules.SSLModuleBuiltins.LOGGER;
48-
import static com.oracle.graal.python.nodes.BuiltinNames.T_NT;
49-
import static com.oracle.graal.python.nodes.BuiltinNames.T_POSIX;
5048
import static com.oracle.graal.python.nodes.ErrorMessages.S;
5149
import static com.oracle.graal.python.util.PythonUtils.toTruffleStringUncached;
5250
import static com.oracle.graal.python.util.PythonUtils.tsLiteral;
@@ -89,26 +87,23 @@
8987
import com.oracle.graal.python.builtins.CoreFunctions;
9088
import com.oracle.graal.python.builtins.PythonBuiltinClassType;
9189
import com.oracle.graal.python.builtins.PythonBuiltins;
92-
import com.oracle.graal.python.builtins.PythonOS;
9390
import com.oracle.graal.python.builtins.modules.SSLModuleBuiltins;
9491
import com.oracle.graal.python.builtins.objects.PNone;
9592
import com.oracle.graal.python.builtins.objects.buffer.PythonBufferAccessLibrary;
9693
import com.oracle.graal.python.builtins.objects.bytes.PBytes;
9794
import com.oracle.graal.python.builtins.objects.bytes.PBytesLike;
98-
import com.oracle.graal.python.builtins.objects.common.HashingStorage;
99-
import com.oracle.graal.python.builtins.objects.common.HashingStorageNodes.HashingStorageGetItem;
10095
import com.oracle.graal.python.builtins.objects.common.SequenceStorageNodes.ToByteArrayNode;
10196
import com.oracle.graal.python.builtins.objects.dict.PDict;
10297
import com.oracle.graal.python.builtins.objects.exception.OSErrorEnum;
10398
import com.oracle.graal.python.builtins.objects.function.PKeyword;
10499
import com.oracle.graal.python.builtins.objects.list.PList;
105-
import com.oracle.graal.python.builtins.objects.module.PythonModule;
106100
import com.oracle.graal.python.builtins.objects.socket.PSocket;
107101
import com.oracle.graal.python.builtins.objects.ssl.CertUtils.NeedsPasswordException;
108102
import com.oracle.graal.python.builtins.objects.ssl.CertUtils.NoCertificateFoundException;
109103
import com.oracle.graal.python.builtins.objects.str.StringNodes;
110104
import com.oracle.graal.python.builtins.objects.type.TpSlots;
111105
import com.oracle.graal.python.builtins.objects.type.TypeNodes;
106+
import com.oracle.graal.python.lib.OsEnvironGetNode;
112107
import com.oracle.graal.python.lib.PyCallableCheckNode;
113108
import com.oracle.graal.python.lib.PyNumberAsSizeNode;
114109
import com.oracle.graal.python.lib.PyNumberIndexNode;
@@ -119,7 +114,6 @@
119114
import com.oracle.graal.python.nodes.PGuards;
120115
import com.oracle.graal.python.nodes.PNodeWithContext;
121116
import com.oracle.graal.python.nodes.PRaiseNode;
122-
import com.oracle.graal.python.nodes.attributes.GetAttributeNode;
123117
import com.oracle.graal.python.nodes.call.CallNode;
124118
import com.oracle.graal.python.nodes.function.PythonBuiltinBaseNode;
125119
import com.oracle.graal.python.nodes.function.builtins.PythonBinaryBuiltinNode;
@@ -145,7 +139,6 @@
145139
import com.oracle.truffle.api.dsl.Cached.Shared;
146140
import com.oracle.truffle.api.dsl.Fallback;
147141
import com.oracle.truffle.api.dsl.GenerateNodeFactory;
148-
import com.oracle.truffle.api.dsl.NeverDefault;
149142
import com.oracle.truffle.api.dsl.NodeFactory;
150143
import com.oracle.truffle.api.dsl.Specialization;
151144
import com.oracle.truffle.api.frame.VirtualFrame;
@@ -156,8 +149,6 @@
156149
@CoreFunctions(extendClasses = PythonBuiltinClassType.PSSLContext)
157150
public final class SSLContextBuiltins extends PythonBuiltins {
158151

159-
private static final TruffleString T_ENVIRON = tsLiteral("environ");
160-
161152
public static final TpSlots SLOTS = SSLContextBuiltinsSlotsGen.SLOTS;
162153

163154
@Override
@@ -618,27 +609,15 @@ static Object pha(@SuppressWarnings("unused") PSSLContext self) {
618609
@Builtin(name = "set_default_verify_paths", minNumOfPositionalArgs = 1)
619610
@GenerateNodeFactory
620611
abstract static class SetDefaultVerifyPathsNode extends PythonUnaryBuiltinNode {
612+
static final TruffleString T_SSL_CERT_FILE = tsLiteral("SSL_CERT_FILE");
613+
static final TruffleString T_SSL_CERT_DIR = tsLiteral("SSL_CERT_DIR");
614+
621615
@Specialization
622616
Object set(VirtualFrame frame, PSSLContext self,
623617
@Bind("this") Node inliningTarget,
624-
@Cached PyUnicodeFSDecoderNode asPath,
625-
@Cached("createEnvironLookup()") GetAttributeNode getAttribute,
626-
@Cached HashingStorageGetItem getItem,
627-
@Cached("createCertFileKey()") PBytes certFileKey,
628-
@Cached("createCertDirKey()") PBytes certDirKey,
629-
@Cached TruffleString.ToJavaStringNode toJavaStringNode) {
630-
631-
PythonModule posix;
632-
if (PythonOS.getPythonOS() == PythonOS.PLATFORM_WIN32) {
633-
posix = getContext().lookupBuiltinModule(T_NT);
634-
} else {
635-
posix = getContext().lookupBuiltinModule(T_POSIX);
636-
}
637-
PDict environ = (PDict) getAttribute.executeObject(frame, posix);
638-
HashingStorage storage = environ.getDictStorage();
639-
640-
TruffleFile file = toTruffleFile(frame, asPath, getItem.execute(frame, inliningTarget, storage, certFileKey), toJavaStringNode);
641-
TruffleFile path = toTruffleFile(frame, asPath, getItem.execute(frame, inliningTarget, storage, certDirKey), toJavaStringNode);
618+
@Cached PyUnicodeFSDecoderNode asPath) {
619+
TruffleFile file = toTruffleFile(frame, asPath, OsEnvironGetNode.executeUncached(T_SSL_CERT_FILE));
620+
TruffleFile path = toTruffleFile(frame, asPath, OsEnvironGetNode.executeUncached(T_SSL_CERT_DIR));
642621
if (file != null || path != null) {
643622
LOGGER.fine(() -> String.format("set_default_verify_paths file: %s. path: %s", file != null ? file.getPath() : "None", path != null ? path.getPath() : "None"));
644623
try {
@@ -653,30 +632,13 @@ Object set(VirtualFrame frame, PSSLContext self,
653632
return PNone.NONE;
654633
}
655634

656-
@NeverDefault
657-
@TruffleBoundary
658-
protected PBytes createCertFileKey() {
659-
return PFactory.createBytes(PythonLanguage.get(null), "SSL_CERT_FILE".getBytes());
660-
}
661-
662-
@NeverDefault
663-
@TruffleBoundary
664-
protected PBytes createCertDirKey() {
665-
return PFactory.createBytes(PythonLanguage.get(null), "SSL_CERT_DIR".getBytes());
666-
}
667-
668-
@NeverDefault
669-
protected static GetAttributeNode createEnvironLookup() {
670-
return GetAttributeNode.create(T_ENVIRON);
671-
}
672-
673-
private TruffleFile toTruffleFile(VirtualFrame frame, PyUnicodeFSDecoderNode asPath, Object path, TruffleString.ToJavaStringNode toJavaStringNode) throws PException {
635+
private TruffleFile toTruffleFile(VirtualFrame frame, PyUnicodeFSDecoderNode asPath, TruffleString path) throws PException {
674636
if (path == null) {
675637
return null;
676638
}
677639
TruffleFile file;
678640
try {
679-
file = getContext().getEnv().getPublicTruffleFile(toJavaStringNode.execute(asPath.execute(frame, path)));
641+
file = getContext().getEnv().getPublicTruffleFile(asPath.execute(frame, path).toJavaStringUncached());
680642
if (!file.exists()) {
681643
return null;
682644
}

0 commit comments

Comments
 (0)