Skip to content

Commit 7181ef6

Browse files
eregonansalond
authored andcommitted
[GR-56099] Merge master in 24.1 release branch
PullRequest: graalpython/3426
2 parents 12cdd53 + 843f55c commit 7181ef6

File tree

37 files changed

+594
-441
lines changed

37 files changed

+594
-441
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ language runtime. The main focus is on user-observable behavior of the engine.
1313
* In Jython emulation mode we now magically fall back to calling Java getters or setters when using Python attribute access for non-visible properties. This can help migrating away from Jython if you relied on this behavior.
1414
* The option `python.EmulateJython` to enable Jython emulation is now marked as stable, and can thus be relied upon in production.
1515
* Fixed parsing of pyvenv.cfg according to PEP 405, which is required to use [uv](https://github.com/astral-sh/uv?tab=readme-ov-file#uv) generated venvs with GraalPy.
16+
* Use https://www.graalvm.org/python/wheels/ as the default value for the `--extra-index-url` pip option. This will make it easy for users to install GraalPy binary wheels in the future.
1617

1718
## Version 24.0.0
1819
* We now provide a collection of recipes in the form of GitHub Actions to build popular native extensions on GraalPy. These provide a reproducible way for the community to build native extensions for GraalPy with the correct dependencies. See scripts/wheelbuilder/README.md for details.

ci.jsonnet

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
{ "overlay": "9d0f6e553533cf857ff21d485094ece21f9e7771" }
1+
{ "overlay": "d304553512c0373cbe1fb5586546fc02068efd29" }

graalpython/com.oracle.graal.python.cext/modules/_sqlite/connection.c

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -199,10 +199,8 @@ pysqlite_connection_init_impl(pysqlite_Connection *self, PyObject *database,
199199
// Create and configure SQLite database object.
200200
sqlite3 *db;
201201
int rc;
202-
// GraalPy change: workaround for GR-51314, revert to CPython original once fixed
203-
char* cstr = PyBytes_AS_STRING(bytes);
204202
Py_BEGIN_ALLOW_THREADS
205-
rc = sqlite3_open_v2(cstr, &db,
203+
rc = sqlite3_open_v2(PyBytes_AS_STRING(bytes), &db,
206204
SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE |
207205
(uri ? SQLITE_OPEN_URI : 0), NULL);
208206
if (rc == SQLITE_OK) {

graalpython/com.oracle.graal.python.cext/src/dictobject.c

Lines changed: 57 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -2074,7 +2074,6 @@ PyDict_Clear(PyObject *op)
20742074
}
20752075
ASSERT_CONSISTENT(mp);
20762076
}
2077-
#endif // GraalPy change
20782077

20792078
/* Internal version of PyDict_Next that returns a hash value in addition
20802079
* to the key and value.
@@ -2085,30 +2084,65 @@ int
20852084
_PyDict_Next(PyObject *op, Py_ssize_t *ppos, PyObject **pkey,
20862085
PyObject **pvalue, Py_hash_t *phash)
20872086
{
2088-
// GraalPy change: different implementation
2089-
PyObject *tresult = GraalPyTruffleDict_Next(op, *ppos);
2090-
if (tresult == NULL) {
2091-
if(pkey != NULL) {
2092-
*pkey = NULL;
2093-
}
2094-
if(pvalue != NULL) {
2095-
*pvalue = NULL;
2096-
}
2097-
return 0;
2098-
}
2099-
if (pkey != NULL) {
2100-
*pkey = PyTuple_GetItem(tresult, 0);
2101-
}
2102-
if (pvalue != NULL) {
2103-
*pvalue = PyTuple_GetItem(tresult, 1);
2104-
}
2105-
if (phash != NULL) {
2106-
*phash = PyLong_AsSsize_t(PyTuple_GetItem(tresult, 2));
2107-
}
2108-
*ppos = PyLong_AsSsize_t(PyTuple_GetItem(tresult, 3));
2109-
Py_DECREF(tresult);
2087+
Py_ssize_t i;
2088+
PyDictObject *mp;
2089+
PyObject *key, *value;
2090+
Py_hash_t hash;
2091+
2092+
if (!PyDict_Check(op))
2093+
return 0;
2094+
mp = (PyDictObject *)op;
2095+
i = *ppos;
2096+
if (mp->ma_values) {
2097+
assert(mp->ma_used <= SHARED_KEYS_MAX_SIZE);
2098+
if (i < 0 || i >= mp->ma_used)
2099+
return 0;
2100+
int index = get_index_from_order(mp, i);
2101+
value = mp->ma_values->values[index];
2102+
2103+
key = DK_UNICODE_ENTRIES(mp->ma_keys)[index].me_key;
2104+
hash = unicode_get_hash(key);
2105+
assert(value != NULL);
2106+
}
2107+
else {
2108+
Py_ssize_t n = mp->ma_keys->dk_nentries;
2109+
if (i < 0 || i >= n)
2110+
return 0;
2111+
if (DK_IS_UNICODE(mp->ma_keys)) {
2112+
PyDictUnicodeEntry *entry_ptr = &DK_UNICODE_ENTRIES(mp->ma_keys)[i];
2113+
while (i < n && entry_ptr->me_value == NULL) {
2114+
entry_ptr++;
2115+
i++;
2116+
}
2117+
if (i >= n)
2118+
return 0;
2119+
key = entry_ptr->me_key;
2120+
hash = unicode_get_hash(entry_ptr->me_key);
2121+
value = entry_ptr->me_value;
2122+
}
2123+
else {
2124+
PyDictKeyEntry *entry_ptr = &DK_ENTRIES(mp->ma_keys)[i];
2125+
while (i < n && entry_ptr->me_value == NULL) {
2126+
entry_ptr++;
2127+
i++;
2128+
}
2129+
if (i >= n)
2130+
return 0;
2131+
key = entry_ptr->me_key;
2132+
hash = entry_ptr->me_hash;
2133+
value = entry_ptr->me_value;
2134+
}
2135+
}
2136+
*ppos = i+1;
2137+
if (pkey)
2138+
*pkey = key;
2139+
if (pvalue)
2140+
*pvalue = value;
2141+
if (phash)
2142+
*phash = hash;
21102143
return 1;
21112144
}
2145+
#endif // GraalPy change
21122146

21132147
/*
21142148
* Iterate over a dict. Use like so:

graalpython/com.oracle.graal.python.processor/src/com/oracle/graal/python/processor/ArgumentClinicProcessor.java

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* The Universal Permissive License (UPL), Version 1.0
@@ -90,11 +90,7 @@ public class ArgumentClinicProcessor extends AbstractProcessor {
9090

9191
@Override
9292
public Set<String> getSupportedAnnotationTypes() {
93-
HashSet<String> vals = new HashSet<>();
94-
vals.add(ArgumentClinic.class.getName());
95-
vals.add(ArgumentsClinic.class.getName());
96-
vals.add(ClinicConverterFactory.class.getName());
97-
return vals;
93+
return Set.of(ArgumentClinic.class.getName(), ArgumentsClinic.class.getName(), ClinicConverterFactory.class.getName());
9894
}
9995

10096
@Override
@@ -105,7 +101,7 @@ public SourceVersion getSupportedSourceVersion() {
105101
@Override
106102
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
107103
if (roundEnv.processingOver()) {
108-
return false;
104+
return true;
109105
}
110106
try {
111107
ConverterFactory.initBuiltins(processingEnv.getElementUtils());

graalpython/com.oracle.graal.python.processor/src/com/oracle/graal/python/processor/CApiBuiltinsProcessor.java

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -168,15 +168,17 @@ private static final class CApiBuiltinDesc {
168168
public final String name;
169169
public final VariableElement[] arguments;
170170
public final VariableElement returnType;
171+
public final boolean acquireGil;
171172
public final String call;
172173
public final String factory;
173174
public int id;
174175

175-
public CApiBuiltinDesc(Element origin, String name, VariableElement returnType, VariableElement[] arguments, String call, String factory) {
176+
public CApiBuiltinDesc(Element origin, String name, VariableElement returnType, VariableElement[] arguments, boolean acquireGil, String call, String factory) {
176177
this.origin = origin;
177178
this.name = name;
178179
this.returnType = returnType;
179180
this.arguments = arguments;
181+
this.acquireGil = acquireGil;
180182
this.call = call;
181183
this.factory = factory;
182184
}
@@ -356,11 +358,12 @@ private void addCApiBuiltins(RoundEnvironment re, List<CApiBuiltinDesc> javaBuil
356358
name = builtinName;
357359
}
358360
var ret = findValue(builtin, "ret", VariableElement.class);
361+
boolean acquireGil = findValue(builtin, "acquireGil", Boolean.class);
359362
String call = name(findValue(builtin, "call", VariableElement.class));
360363
// boolean inlined = findValue(builtin, "inlined", Boolean.class);
361364
VariableElement[] args = findValues(builtin, "args", VariableElement.class).toArray(new VariableElement[0]);
362365
if (((TypeElement) element).getQualifiedName().toString().equals("com.oracle.graal.python.builtins.objects.cext.capi.CApiFunction.Dummy")) {
363-
additionalBuiltins.add(new CApiBuiltinDesc(element, builtinName, ret, args, call, null));
366+
additionalBuiltins.add(new CApiBuiltinDesc(element, builtinName, ret, args, acquireGil, call, null));
364367
} else {
365368
if (!isValidReturnType(ret)) {
366369
processingEnv.getMessager().printError(
@@ -387,7 +390,7 @@ private void addCApiBuiltins(RoundEnvironment re, List<CApiBuiltinDesc> javaBuil
387390
genName += "NodeGen";
388391
}
389392
verifyNodeClass(((TypeElement) element), builtin);
390-
javaBuiltins.add(new CApiBuiltinDesc(element, name, ret, args, call, genName));
393+
javaBuiltins.add(new CApiBuiltinDesc(element, name, ret, args, acquireGil, call, genName));
391394
}
392395
}
393396
}
@@ -634,7 +637,7 @@ private void generateBuiltinRegistry(List<CApiBuiltinDesc> javaBuiltins) throws
634637
for (var builtin : javaBuiltins) {
635638
String argString = Arrays.stream(builtin.arguments).map(b -> "ArgDescriptor." + b).collect(Collectors.joining(", "));
636639
lines.add(" public static final CApiBuiltinExecutable " + builtin.name + " = new CApiBuiltinExecutable(\"" + builtin.name + "\", CApiCallPath." + builtin.call + ", ArgDescriptor." +
637-
builtin.returnType + ", new ArgDescriptor[]{" + argString + "}, " + builtin.id + ");");
640+
builtin.returnType + ", new ArgDescriptor[]{" + argString + "}, " + builtin.acquireGil + ", " + builtin.id + ");");
638641
}
639642
lines.add("");
640643
lines.add(" public static final CApiBuiltinExecutable[] builtins = {");
@@ -836,7 +839,7 @@ private void checkImports(List<CApiBuiltinDesc> builtins) throws IOException {
836839
@SuppressWarnings({"try", "unused"})
837840
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment re) {
838841
if (re.processingOver()) {
839-
return false;
842+
return true;
840843
}
841844

842845
List<CApiBuiltinDesc> javaBuiltins = new ArrayList<>();

graalpython/com.oracle.graal.python.processor/src/com/oracle/graal/python/processor/GenerateEnumConstantsProcessor.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* The Universal Permissive License (UPL), Version 1.0
@@ -74,7 +74,7 @@ public SourceVersion getSupportedSourceVersion() {
7474
@SuppressWarnings({"try", "unused"})
7575
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment re) {
7676
if (re.processingOver()) {
77-
return false;
77+
return true;
7878
}
7979
Set<? extends Element> annotatedElements = re.getElementsAnnotatedWith(GenerateEnumConstants.class);
8080
for (Element el : annotatedElements) {

graalpython/com.oracle.graal.python.processor/src/com/oracle/graal/python/processor/SlotsProcessor.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ public SourceVersion getSupportedSourceVersion() {
8787
@Override
8888
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
8989
if (roundEnv.processingOver()) {
90-
return false;
90+
return true;
9191
}
9292
try {
9393
doProcess(roundEnv);

graalpython/com.oracle.graal.python.shell/src/com/oracle/graal/python/shell/GraalPythonMain.java

Lines changed: 48 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@
3030
import java.io.File;
3131
import java.io.FileDescriptor;
3232
import java.io.FileOutputStream;
33-
import java.io.IOError;
3433
import java.io.IOException;
3534
import java.io.InputStream;
3635
import java.io.OutputStream;
@@ -717,8 +716,7 @@ protected void launch(Builder contextBuilder) {
717716
// the user did not explicitly pass some options that would be otherwise loaded from
718717
// pyvenv.cfg. Notable usage of this feature is GraalPython venvs which generate a
719718
// launcher script that passes those options explicitly without relying on pyvenv.cfg
720-
boolean tryVenvCfg = !hasContextOptionSetViaCommandLine("SysPrefix") &&
721-
!hasContextOptionSetViaCommandLine("PythonHome") &&
719+
boolean tryVenvCfg = !hasContextOptionSetViaCommandLine("PythonHome") &&
722720
getEnv("GRAAL_PYTHONHOME") == null;
723721
if (tryVenvCfg) {
724722
findAndApplyVenvCfg(contextBuilder, executable);
@@ -872,14 +870,16 @@ private static String toAbsolutePath(String executable) {
872870
return Paths.get(executable).toAbsolutePath().toString();
873871
}
874872

873+
// Rough equivalent of CPython's pyvenv.cfg logic in Modules/getpath.py
875874
private void findAndApplyVenvCfg(Builder contextBuilder, String executable) {
876-
Path binDir;
875+
Path executablePath;
877876
try {
878-
binDir = Paths.get(executable).getParent();
877+
executablePath = Paths.get(executable);
879878
} catch (InvalidPathException e) {
880-
log("cannot determine the parent directory of the executable");
879+
log("cannot determine path of the executable");
881880
return;
882881
}
882+
Path binDir = executablePath.getParent();
883883
if (binDir == null) {
884884
log("parent directory of the executable does not exist");
885885
return;
@@ -907,36 +907,52 @@ private void findAndApplyVenvCfg(Builder contextBuilder, String executable) {
907907
}
908908
String name = parts[0].trim();
909909
if (name.equals("home")) {
910-
Path homeProperty = Paths.get(parts[1].trim());
911-
/*
912-
* (tfel): According to PEP 405, the home key is the directory of the Python
913-
* executable from which this virtual environment was created, that is, it
914-
* usually ends with "/bin" on a Unix system. On Windows, the base Python should
915-
* be in the top-level directory or under "\Scripts". To support running from
916-
* Maven artifacts where we don't have a working executable, we patched our
917-
* shipped venv module to set the home path without a "/bin" or "\\Scripts"
918-
* suffix, so we explicitly check for those two subfolder cases and otherwise
919-
* assume the home key is directly pointing to the Python home.
920-
*/
921-
if (homeProperty.endsWith("bin") || homeProperty.endsWith("Scripts")) {
922-
homeProperty = homeProperty.getParent();
923-
}
924910
try {
925-
contextBuilder.option("python.PythonHome", homeProperty.toString());
926-
} catch (NullPointerException ex) {
911+
Path homeProperty = Paths.get(parts[1].trim());
912+
Path graalpyHome = homeProperty;
913+
/*
914+
* (tfel): According to PEP 405, the home key is the directory of the Python
915+
* executable from which this virtual environment was created, that is, it
916+
* usually ends with "/bin" on a Unix system. On Windows, the base Python
917+
* should be in the top-level directory or under "\Scripts". To support
918+
* running from Maven artifacts where we don't have a working executable, we
919+
* patched our shipped venv module to set the home path without a "/bin" or
920+
* "\\Scripts" suffix, so we explicitly check for those two subfolder cases
921+
* and otherwise assume the home key is directly pointing to the Python
922+
* home.
923+
*/
924+
if (graalpyHome.endsWith("bin") || graalpyHome.endsWith("Scripts")) {
925+
graalpyHome = graalpyHome.getParent();
926+
}
927+
contextBuilder.option("python.PythonHome", graalpyHome.toString());
928+
/*
929+
* First try to resolve symlinked executables, since that may be more
930+
* accurate than assuming the executable in 'home'.
931+
*/
932+
Path baseExecutable = null;
933+
try {
934+
Path realPath = executablePath.toRealPath();
935+
if (!realPath.equals(executablePath.toAbsolutePath())) {
936+
baseExecutable = realPath;
937+
}
938+
} catch (IOException ex) {
939+
// Ignore
940+
}
941+
if (baseExecutable == null) {
942+
baseExecutable = homeProperty.resolve(executablePath.getFileName());
943+
}
944+
if (Files.exists(baseExecutable)) {
945+
contextBuilder.option("python.BaseExecutable", baseExecutable.toString());
946+
/*
947+
* This is needed to support the legacy GraalVM layout where the
948+
* executable is a symlink into the 'languages' directory.
949+
*/
950+
contextBuilder.option("python.PythonHome", baseExecutable.getParent().getParent().toString());
951+
}
952+
} catch (NullPointerException | InvalidPathException ex) {
927953
// NullPointerException covers the possible null result of getParent()
928954
warn("Could not set PYTHONHOME according to the pyvenv.cfg file.");
929955
}
930-
String sysPrefix = null;
931-
try {
932-
sysPrefix = venvCfg.getParent().toAbsolutePath().toString();
933-
} catch (IOError | NullPointerException ex) {
934-
// NullPointerException covers the possible null result of getParent()
935-
warn("Could not set the sys.prefix according to the pyvenv.cfg file.");
936-
}
937-
if (sysPrefix != null) {
938-
contextBuilder.option("python.SysPrefix", sysPrefix);
939-
}
940956
break;
941957
}
942958
}

graalpython/com.oracle.graal.python.test.integration/src/com/oracle/graal/python/test/integration/PythonTests.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2017, 2023, Oracle and/or its affiliates.
2+
* Copyright (c) 2017, 2024, Oracle and/or its affiliates.
33
* Copyright (c) 2013, Regents of the University of California
44
*
55
* All rights reserved.
@@ -44,7 +44,7 @@
4444
import org.graalvm.polyglot.PolyglotException;
4545
import org.graalvm.polyglot.Source;
4646
import org.graalvm.polyglot.Value;
47-
import org.junit.Assert;
47+
import org.hamcrest.MatcherAssert;
4848

4949
import com.oracle.graal.python.test.integration.advanced.BenchmarkTests;
5050

@@ -106,7 +106,7 @@ public static void assertLastLineErrorContains(String expected, String code) {
106106
PythonTests.runThrowableScript(new String[0], source, System.out, printStream);
107107
String[] output = byteArray.toString().split("\n");
108108
// ignore the traceback
109-
Assert.assertThat(output[output.length - 1], containsString(expected.trim()));
109+
MatcherAssert.assertThat(output[output.length - 1], containsString(expected.trim()));
110110
}
111111

112112
public static void assertPrintContains(String expected, String code) {

0 commit comments

Comments
 (0)