diff --git a/ci.jsonnet b/ci.jsonnet index 48bf915fd3..7d5f235fe3 100644 --- a/ci.jsonnet +++ b/ci.jsonnet @@ -1 +1 @@ -{ "overlay": "840dea7f9575e2e96e2143685751932513fd0c78" } +{ "overlay": "16d0e566573ebdcf380bf6f309c02724baf4172b" } diff --git a/graalpython/com.oracle.graal.python.cext/include/cpython/tupleobject.h b/graalpython/com.oracle.graal.python.cext/include/cpython/tupleobject.h index ef3d3c3790..a5bb3fba3b 100644 --- a/graalpython/com.oracle.graal.python.cext/include/cpython/tupleobject.h +++ b/graalpython/com.oracle.graal.python.cext/include/cpython/tupleobject.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2020, 2024, Oracle and/or its affiliates. +/* Copyright (c) 2020, 2025, Oracle and/or its affiliates. * Copyright (C) 1996-2020 Python Software Foundation * * Licensed under the PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2 @@ -39,14 +39,14 @@ PyAPI_FUNC(PyObject *) _PyTuple_GET_ITEM(PyObject *, Py_ssize_t); // GraalPy-specific PyAPI_FUNC(PyObject **) PyTruffleTuple_GetItems(PyObject *op); -/* Function *only* to be used to fill in brand new tuples */ -static inline void -PyTuple_SET_ITEM(PyObject *op, Py_ssize_t index, PyObject *value) { +// GraalPy change: Export PyTuple_SET_ITEM as regular API function to use in PyO3 and others +PyAPI_FUNC(void) PyTuple_SET_ITEM(PyObject*, Py_ssize_t, PyObject*); + +/* Inline function to be used in the PyTuple_SET_ITEM macro. */ +static inline void graalpy_tuple_set_item(PyObject *op, Py_ssize_t index, PyObject *value) { PyTruffleTuple_GetItems(op)[index] = value; } -#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 < 0x030b0000 #define PyTuple_SET_ITEM(op, index, value) \ - PyTuple_SET_ITEM(_PyObject_CAST(op), index, _PyObject_CAST(value)) -#endif + graalpy_tuple_set_item(_PyObject_CAST(op), (index), _PyObject_CAST(value)) PyAPI_FUNC(void) _PyTuple_DebugMallocStats(FILE *out); diff --git a/graalpython/com.oracle.graal.python.cext/include/object.h b/graalpython/com.oracle.graal.python.cext/include/object.h index 7d88c22cb1..a427c70040 100644 --- a/graalpython/com.oracle.graal.python.cext/include/object.h +++ b/graalpython/com.oracle.graal.python.cext/include/object.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2018, 2024, Oracle and/or its affiliates. +/* Copyright (c) 2018, 2025, Oracle and/or its affiliates. * Copyright (C) 1996-2020 Python Software Foundation * * Licensed under the PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2 @@ -124,7 +124,9 @@ typedef struct { // Test if the 'x' object is the 'y' object, the same as "x is y" in Python. PyAPI_FUNC(int) Py_Is(PyObject *x, PyObject *y); +#if 0 // GraalPy change #define Py_Is(x, y) ((x) == (y)) +#endif // GraalPy change PyAPI_FUNC(Py_ssize_t) PyTruffle_REFCNT(PyObject *ob); diff --git a/graalpython/com.oracle.graal.python.cext/src/object.c b/graalpython/com.oracle.graal.python.cext/src/object.c index 9ad7908e8a..d467aac946 100644 --- a/graalpython/com.oracle.graal.python.cext/src/object.c +++ b/graalpython/com.oracle.graal.python.cext/src/object.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2018, 2024, Oracle and/or its affiliates. +/* Copyright (c) 2018, 2025, Oracle and/or its affiliates. * Copyright (C) 1996-2022 Python Software Foundation * * Licensed under the PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2 @@ -2507,7 +2507,12 @@ Py_XNewRef(PyObject *obj) // for the stable ABI. int Py_Is(PyObject *x, PyObject *y) { +#if 0 // GraalPy change return (x == y); +#else + return (x == y) || + (points_to_py_handle_space(x) && points_to_py_handle_space(y) && GraalPyTruffle_Is(x, y)); +#endif } int Py_IsNone(PyObject *x) diff --git a/graalpython/com.oracle.graal.python.cext/src/tupleobject.c b/graalpython/com.oracle.graal.python.cext/src/tupleobject.c index 007bab220d..4e6f9c2a50 100644 --- a/graalpython/com.oracle.graal.python.cext/src/tupleobject.c +++ b/graalpython/com.oracle.graal.python.cext/src/tupleobject.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2018, 2024, Oracle and/or its affiliates. +/* Copyright (c) 2018, 2025, Oracle and/or its affiliates. * Copyright (C) 1996-2022 Python Software Foundation * * Licensed under the PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2 @@ -1424,3 +1424,9 @@ _PyTuple_GET_ITEM(PyObject* a, Py_ssize_t b) { } return NULL; // an exception has happend during transtion } + +#undef PyTuple_SET_ITEM +// Export PyTuple_SET_ITEM as regular API function to use in PyO3 and others +void PyTuple_SET_ITEM(PyObject* op, Py_ssize_t index, PyObject* value) { + graalpy_tuple_set_item(op, index, value); +} diff --git a/graalpython/com.oracle.graal.python.cext/src/unicodeobject.c b/graalpython/com.oracle.graal.python.cext/src/unicodeobject.c index 42699b743a..852906637e 100644 --- a/graalpython/com.oracle.graal.python.cext/src/unicodeobject.c +++ b/graalpython/com.oracle.graal.python.cext/src/unicodeobject.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2018, 2024, Oracle and/or its affiliates. +/* Copyright (c) 2018, 2025, Oracle and/or its affiliates. * Copyright (C) 1996-2020 Python Software Foundation * * Licensed under the PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2 @@ -6220,16 +6220,17 @@ _PyUnicode_DecodeRawUnicodeEscapeStateful(const char *s, Py_XDECREF(exc); return NULL; } - +#endif // GraalPy change PyObject * PyUnicode_DecodeRawUnicodeEscape(const char *s, Py_ssize_t size, const char *errors) { - return _PyUnicode_DecodeRawUnicodeEscapeStateful(s, size, errors, NULL); + return PyUnicode_Decode(s, size, "raw_unicode_escape", errors); + // return _PyUnicode_DecodeRawUnicodeEscapeStateful(s, size, errors, NULL); } - +#if 0 // GraalPy change PyObject * PyUnicode_AsRawUnicodeEscapeString(PyObject *unicode) { diff --git a/graalpython/com.oracle.graal.python.frozen/freeze_modules.py b/graalpython/com.oracle.graal.python.frozen/freeze_modules.py index c08d654cd6..11212e9233 100644 --- a/graalpython/com.oracle.graal.python.frozen/freeze_modules.py +++ b/graalpython/com.oracle.graal.python.frozen/freeze_modules.py @@ -1,4 +1,4 @@ -# Copyright (c) 2021, 2024, Oracle and/or its affiliates. +# Copyright (c) 2021, 2025, Oracle and/or its affiliates. # Copyright (C) 1996-2020 Python Software Foundation # # Licensed under the PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2 @@ -105,13 +105,15 @@ def add_graalpython_core(): l.append("polyglot.arrow : polyglot.arrow = " + os.path.join(lib_graalpython, "modules/_polyglot_arrow.py")) for name in [ "modules/_sysconfigdata", + "modules/_polyglot", + "modules/_polyglot_datetime", + "modules/_polyglot_time", ]: modname = os.path.basename(name) modpath = os.path.join(lib_graalpython, f"{name}.py") l.append(f"{modname} : {modname} = {modpath}") for name in [ "__graalpython__", - "_polyglot", "_sre", "_sysconfig", "_weakref", @@ -119,6 +121,7 @@ def add_graalpython_core(): "java", "pip_hook", "unicodedata", + "_nt", ]: modname = f"graalpy.{os.path.basename(name)}" modpath = os.path.join(lib_graalpython, f"{name}.py") @@ -495,7 +498,7 @@ def lower_camel_case(str): # write frozen files FROZEN_MODULES_HEADER = """/* - * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -588,19 +591,27 @@ def write_frozen_module_file(file, modules): if os.path.exists(file): with open(file, "r", encoding="utf-8", newline=os.linesep) as f: content = f.read() + if os.linesep != "\n": + if content.replace(os.linesep, "\n") == content: + # Windows file has Unix line endings + linesep = "\n" + else: + linesep = os.linesep + else: + linesep = "\n" stat_result = os.stat(file) atime, mtime = stat_result.st_atime, stat_result.st_mtime else: content = None os.makedirs(os.path.dirname(file), exist_ok=True) - with open(file, "w", encoding="utf-8", newline=os.linesep) as out_file: + with open(file, "w", encoding="utf-8", newline=linesep) as out_file: out_file.write(FROZEN_MODULES_HEADER) out_file.write("\n\n") write_frozen_modules_map(out_file, modules) out_file.write("\n") write_frozen_lookup(out_file, modules) out_file.write("}\n") - with open(file, "r", encoding="utf-8", newline=os.linesep) as f: + with open(file, "r", encoding="utf-8", newline=linesep) as f: new_content = f.read() if new_content == content: # set mtime to the old one, if we didn't change anything diff --git a/graalpython/com.oracle.graal.python.shell/src/com/oracle/graal/python/shell/GraalPythonMain.java b/graalpython/com.oracle.graal.python.shell/src/com/oracle/graal/python/shell/GraalPythonMain.java index f7838f7d5e..a2c0dd21f1 100644 --- a/graalpython/com.oracle.graal.python.shell/src/com/oracle/graal/python/shell/GraalPythonMain.java +++ b/graalpython/com.oracle.graal.python.shell/src/com/oracle/graal/python/shell/GraalPythonMain.java @@ -778,9 +778,6 @@ protected void launch(Builder contextBuilder) { contextBuilder.option("python.IntMaxStrDigits", Integer.toString(intMaxStrDigits)); } contextBuilder.option("python.DontWriteBytecodeFlag", Boolean.toString(dontWriteBytecode)); - if (verboseFlag) { - contextBuilder.option("log.python.level", "INFO"); - } contextBuilder.option("python.QuietFlag", Boolean.toString(quietFlag)); contextBuilder.option("python.NoUserSiteFlag", Boolean.toString(noUserSite)); contextBuilder.option("python.NoSiteFlag", Boolean.toString(noSite)); @@ -843,6 +840,8 @@ protected void launch(Builder contextBuilder) { } catch (PolyglotException e) { if (e.isExit()) { rc = e.getExitStatus(); + } else { + throw e; } } catch (NoSuchFileException e) { printFileNotFoundException(e); @@ -929,54 +928,70 @@ private void findAndApplyVenvCfg(Builder contextBuilder, String executable) { continue; } String name = parts[0].trim(); - if (name.equals("home")) { - try { - Path homeProperty = Paths.get(parts[1].trim()); - Path graalpyHome = homeProperty; - /* - * (tfel): According to PEP 405, the home key is the directory of the Python - * executable from which this virtual environment was created, that is, it - * usually ends with "/bin" on a Unix system. On Windows, the base Python - * should be in the top-level directory or under "\Scripts". To support - * running from Maven artifacts where we don't have a working executable, we - * patched our shipped venv module to set the home path without a "/bin" or - * "\\Scripts" suffix, so we explicitly check for those two subfolder cases - * and otherwise assume the home key is directly pointing to the Python - * home. - */ - if (graalpyHome.endsWith("bin") || graalpyHome.endsWith("Scripts")) { - graalpyHome = graalpyHome.getParent(); - } - contextBuilder.option("python.PythonHome", graalpyHome.toString()); - /* - * First try to resolve symlinked executables, since that may be more - * accurate than assuming the executable in 'home'. - */ - Path baseExecutable = null; + switch (name) { + case "home": try { - Path realPath = executablePath.toRealPath(); - if (!realPath.equals(executablePath.toAbsolutePath())) { - baseExecutable = realPath; + Path homeProperty = Paths.get(parts[1].trim()); + Path graalpyHome = homeProperty; + /* + * (tfel): According to PEP 405, the home key is the directory of the + * Python executable from which this virtual environment was created, + * that is, it usually ends with "/bin" on a Unix system. On Windows, + * the base Python should be in the top-level directory or under + * "\Scripts". To support running from Maven artifacts where we don't + * have a working executable, we patched our shipped venv module to set + * the home path without a "/bin" or "\\Scripts" suffix, so we + * explicitly check for those two subfolder cases and otherwise assume + * the home key is directly pointing to the Python home. + */ + if (graalpyHome.endsWith("bin") || graalpyHome.endsWith("Scripts")) { + graalpyHome = graalpyHome.getParent(); } - } catch (IOException ex) { - // Ignore - } - if (baseExecutable == null) { - baseExecutable = homeProperty.resolve(executablePath.getFileName()); - } - if (Files.exists(baseExecutable)) { - contextBuilder.option("python.BaseExecutable", baseExecutable.toString()); + contextBuilder.option("python.PythonHome", graalpyHome.toString()); /* - * This is needed to support the legacy GraalVM layout where the - * executable is a symlink into the 'languages' directory. + * First try to resolve symlinked executables, since that may be more + * accurate than assuming the executable in 'home'. */ - contextBuilder.option("python.PythonHome", baseExecutable.getParent().getParent().toString()); + Path baseExecutable = null; + try { + Path realPath = executablePath.toRealPath(); + if (!realPath.equals(executablePath.toAbsolutePath())) { + baseExecutable = realPath; + } + } catch (IOException ex) { + // Ignore + } + if (baseExecutable == null) { + baseExecutable = homeProperty.resolve(executablePath.getFileName()); + } + if (Files.exists(baseExecutable)) { + contextBuilder.option("python.BaseExecutable", baseExecutable.toString()); + /* + * This is needed to support the legacy GraalVM layout where the + * executable is a symlink into the 'languages' directory. + */ + contextBuilder.option("python.PythonHome", baseExecutable.getParent().getParent().toString()); + } + } catch (NullPointerException | InvalidPathException ex) { + // NullPointerException covers the possible null result of getParent() + warn("Could not set PYTHONHOME according to the pyvenv.cfg file."); } - } catch (NullPointerException | InvalidPathException ex) { - // NullPointerException covers the possible null result of getParent() - warn("Could not set PYTHONHOME according to the pyvenv.cfg file."); - } - break; + break; + case "venvlauncher_command": + if (!hasContextOptionSetViaCommandLine("VenvlauncherCommand")) { + contextBuilder.option("python.VenvlauncherCommand", parts[1].trim()); + } + break; + case "base-prefix": + if (!hasContextOptionSetViaCommandLine("SysBasePrefix")) { + contextBuilder.option("python.SysBasePrefix", parts[1].trim()); + } + break; + case "base-executable": + if (!hasContextOptionSetViaCommandLine("BaseExecutable")) { + contextBuilder.option("python.BaseExecutable", parts[1].trim()); + } + break; } } } catch (IOException ex) { diff --git a/graalpython/com.oracle.graal.python.test.integration/pom.xml b/graalpython/com.oracle.graal.python.test.integration/pom.xml index bad3f27502..6251cedd21 100644 --- a/graalpython/com.oracle.graal.python.test.integration/pom.xml +++ b/graalpython/com.oracle.graal.python.test.integration/pom.xml @@ -64,7 +64,7 @@ Additionally, one can change the polyglot artifacts version with 17 17 UTF-8 - 25.0.0 + 24.2.1 diff --git a/graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_tuple.py b/graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_tuple.py index 3570a698fb..c696d5828f 100644 --- a/graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_tuple.py +++ b/graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_tuple.py @@ -1,4 +1,4 @@ -# Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # The Universal Permissive License (UPL), Version 1.0 @@ -151,14 +151,15 @@ class TestPyTuple(CPyExtTestCase): ((1, 2, 3), -1, []), ((1, 2, 3), 3, str), ), - code="""PyObject* wrap_PyTuple_SetItem(PyObject* original, Py_ssize_t index, PyObject* value) { + code=""" + PyObject* wrap_PyTuple_SetItem(PyObject* original, Py_ssize_t index, PyObject* value) { Py_ssize_t size = PyTuple_Size(original); if (size < 0) return NULL; PyObject* tuple = PyTuple_New(size); if (!tuple) return NULL; - for (int i = 0; i < size; i++) { + for (int i = 0; i < size / 2; i++) { PyObject* item = PyTuple_GetItem(original, i); if (!item) { Py_DECREF(tuple); @@ -167,6 +168,22 @@ class TestPyTuple(CPyExtTestCase): Py_INCREF(item); PyTuple_SET_ITEM(tuple, i, item); } + + #ifdef GRAALVM_PYTHON + // test that we also have it as API function on GraalPy + #undef PyTuple_SET_ITEM + #endif + + for (int i = size / 2; i < size; i++) { + PyObject* item = PyTuple_GetItem(original, i); + if (!item) { + Py_DECREF(tuple); + return NULL; + } + Py_INCREF(item); + PyTuple_SET_ITEM(tuple, i, item); + } + Py_INCREF(value); if (PyTuple_SetItem(tuple, index, value) < 0) { Py_DECREF(tuple); diff --git a/graalpython/com.oracle.graal.python.test/src/tests/standalone/gradle/build/build.gradle b/graalpython/com.oracle.graal.python.test/src/tests/standalone/gradle/build/build.gradle index c9b31ffe75..2dfdd3f5ce 100644 --- a/graalpython/com.oracle.graal.python.test/src/tests/standalone/gradle/build/build.gradle +++ b/graalpython/com.oracle.graal.python.test/src/tests/standalone/gradle/build/build.gradle @@ -1,6 +1,6 @@ plugins { id "application" - id 'org.graalvm.python' version '25.0.0' + id 'org.graalvm.python' version '24.2.1' id "org.graalvm.buildtools.native" version "0.10.2" } diff --git a/graalpython/com.oracle.graal.python.test/src/tests/standalone/gradle/build/build.gradle.kts b/graalpython/com.oracle.graal.python.test/src/tests/standalone/gradle/build/build.gradle.kts index ee72dfe3de..8ccf16421d 100644 --- a/graalpython/com.oracle.graal.python.test/src/tests/standalone/gradle/build/build.gradle.kts +++ b/graalpython/com.oracle.graal.python.test/src/tests/standalone/gradle/build/build.gradle.kts @@ -1,6 +1,6 @@ plugins { application - id("org.graalvm.python") version "25.0.0" + id("org.graalvm.python") version "24.2.1" id("org.graalvm.buildtools.native") version "0.10.2" } diff --git a/graalpython/com.oracle.graal.python.test/src/tests/standalone/jbang/EmptyPIPComments.j b/graalpython/com.oracle.graal.python.test/src/tests/standalone/jbang/EmptyPIPComments.j index 098695dccb..08561a0c15 100644 --- a/graalpython/com.oracle.graal.python.test/src/tests/standalone/jbang/EmptyPIPComments.j +++ b/graalpython/com.oracle.graal.python.test/src/tests/standalone/jbang/EmptyPIPComments.j @@ -1,6 +1,6 @@ ///usr/bin/env jbang "$0" "$@" ; exit $? -//DEPS org.graalvm.python:jbang:${env.GRAALPY_VERSION:25.0.0} +//DEPS org.graalvm.python:jbang:${env.GRAALPY_VERSION:24.2.1} //PIP // one blank after PIP //PIP diff --git a/graalpython/com.oracle.graal.python.test/src/tests/standalone/jbang/EmptyPythonResourceComment.j b/graalpython/com.oracle.graal.python.test/src/tests/standalone/jbang/EmptyPythonResourceComment.j index 89f5758c5e..31330e96fd 100644 --- a/graalpython/com.oracle.graal.python.test/src/tests/standalone/jbang/EmptyPythonResourceComment.j +++ b/graalpython/com.oracle.graal.python.test/src/tests/standalone/jbang/EmptyPythonResourceComment.j @@ -1,6 +1,6 @@ ///usr/bin/env jbang "$0" "$@" ; exit $? -//DEPS org.graalvm.python:jbang:${env.GRAALPY_VERSION:25.0.0} +//DEPS org.graalvm.python:jbang:${env.GRAALPY_VERSION:24.2.1} //PYTHON_RESOURCES_DIRECTORY public class EmptyPythonResourceComment { diff --git a/graalpython/com.oracle.graal.python.test/src/tests/standalone/jbang/EmptyPythonResourceCommentWithBlanks.j b/graalpython/com.oracle.graal.python.test/src/tests/standalone/jbang/EmptyPythonResourceCommentWithBlanks.j index fcb93bdc33..6f71f88213 100644 --- a/graalpython/com.oracle.graal.python.test/src/tests/standalone/jbang/EmptyPythonResourceCommentWithBlanks.j +++ b/graalpython/com.oracle.graal.python.test/src/tests/standalone/jbang/EmptyPythonResourceCommentWithBlanks.j @@ -1,6 +1,6 @@ ///usr/bin/env jbang "$0" "$@" ; exit $? -//DEPS org.graalvm.python:jbang:${env.GRAALPY_VERSION:25.0.0} +//DEPS org.graalvm.python:jbang:${env.GRAALPY_VERSION:24.2.1} // resource dir with blanks //PYTHON_RESOURCES_DIRECTORY diff --git a/graalpython/com.oracle.graal.python.test/src/tests/standalone/jbang/NoPackagesResourcesDir.j b/graalpython/com.oracle.graal.python.test/src/tests/standalone/jbang/NoPackagesResourcesDir.j index c2255aca6c..24a4866b26 100644 --- a/graalpython/com.oracle.graal.python.test/src/tests/standalone/jbang/NoPackagesResourcesDir.j +++ b/graalpython/com.oracle.graal.python.test/src/tests/standalone/jbang/NoPackagesResourcesDir.j @@ -1,6 +1,6 @@ ///usr/bin/env jbang "$0" "$@" ; exit $? -//DEPS org.graalvm.python:jbang:${env.GRAALPY_VERSION:25.0.0} +//DEPS org.graalvm.python:jbang:${env.GRAALPY_VERSION:24.2.1} //PYTHON_RESOURCES_DIRECTORY python-resources public class NoPackagesResourcesDir { diff --git a/graalpython/com.oracle.graal.python.test/src/tests/standalone/jbang/TwoPythonResourceComments.j b/graalpython/com.oracle.graal.python.test/src/tests/standalone/jbang/TwoPythonResourceComments.j index 3bd4381f51..ab31f0a738 100644 --- a/graalpython/com.oracle.graal.python.test/src/tests/standalone/jbang/TwoPythonResourceComments.j +++ b/graalpython/com.oracle.graal.python.test/src/tests/standalone/jbang/TwoPythonResourceComments.j @@ -1,6 +1,6 @@ ///usr/bin/env jbang "$0" "$@" ; exit $? -//DEPS org.graalvm.python:jbang:${env.GRAALPY_VERSION:25.0.0} +//DEPS org.graalvm.python:jbang:${env.GRAALPY_VERSION:24.2.1} //PYTHON_RESOURCES_DIRECTORY //PYTHON_RESOURCES_DIRECTORY diff --git a/graalpython/com.oracle.graal.python.test/src/tests/standalone/test_gradle_plugin.py b/graalpython/com.oracle.graal.python.test/src/tests/standalone/test_gradle_plugin.py index 2b15001db5..b50be878dc 100644 --- a/graalpython/com.oracle.graal.python.test/src/tests/standalone/test_gradle_plugin.py +++ b/graalpython/com.oracle.graal.python.test/src/tests/standalone/test_gradle_plugin.py @@ -133,6 +133,8 @@ def check_gradle_generated_app(self, community): cmd = gradlew_cmd + ["build"] out, return_code = util.run_cmd(cmd, self.env, cwd=target_dir, logger=log) util.check_ouput("BUILD SUCCESS", out, logger=log) + util.check_ouput("Virtual filesystem is deployed to default resources directory", out, logger=log) + util.check_ouput("This can cause conflicts if used with other Java libraries that also deploy GraalPy virtual filesystem", out, logger=log) self.check_filelist(target_dir, log) cmd = gradlew_cmd + ["nativeCompile"] @@ -413,7 +415,7 @@ def check_gradle_python_resources_dir_and_external_dir_error(self): gradle_cmd = util.get_gradle_wrapper(target_dir, self.env) cmd = gradle_cmd + ["graalPyResources"] out, return_code = util.run_cmd(cmd, self.env, cwd=target_dir) - util.check_ouput("Cannot set both 'externalDirectory' and 'resourcesDirectory' at the same time", out) + util.check_ouput("Cannot set both 'externalDirectory' and 'resourceDirectory' at the same time", out) assert return_code != 0, out @@ -478,6 +480,8 @@ def check_gradle_namespaced_vfs(self): app1_gradle_cmd = util.get_gradle_wrapper(app1_dir, self.env) out, return_code = util.run_cmd(app1_gradle_cmd + ['publishToMavenLocal'], self.env, cwd=app1_dir) + util.check_ouput("Virtual filesystem is deployed to default resources directory", out, contains=False) + util.check_ouput("This can cause conflicts if used with other Java libraries that also deploy GraalPy virtual filesystem", out, contains=False) assert return_code == 0, out app2_gradle_cmd = util.get_gradle_wrapper(app2_dir, self.env) @@ -677,11 +681,11 @@ def setUpClass(cls): cls.build_file_name = "build.gradle.kts" cls.settings_file_name = "settings.gradle.kts" - @unittest.skipUnless(util.is_gradle_plugin_test_enabled, "ENABLE_GRADLE_PLUGIN_UNITTESTS is not true") + @unittest.skipUnless(util.is_gradle_plugin_long_running_test_enabled, "ENABLE_GRADLE_PLUGIN_LONG_RUNNING_UNITTESTS is not true") def test_gradle_generated_app(self): self.check_gradle_generated_app(community=True) - @unittest.skipUnless(util.is_gradle_plugin_test_enabled, "ENABLE_GRADLE_PLUGIN_UNITTESTS is not true") + @unittest.skipUnless(util.is_gradle_plugin_long_running_test_enabled, "ENABLE_GRADLE_PLUGIN_LONG_RUNNING_UNITTESTS is not true") def test_gradle_generated_app_external_resources(self): self.check_gradle_generated_app_external_resources() @@ -701,7 +705,7 @@ def test_gradle_check_home(self): def test_gradle_empty_packages(self): self.check_gradle_empty_packages() - @unittest.skipUnless(util.is_gradle_plugin_test_enabled, "ENABLE_GRADLE_PLUGIN_UNITTESTS is not true") + @unittest.skipUnless(util.is_gradle_plugin_long_running_test_enabled, "ENABLE_GRADLE_PLUGIN_LONG_RUNNING_UNITTESTS is not true") def test_gradle_namespaced_vfs(self): self.check_gradle_namespaced_vfs() diff --git a/graalpython/com.oracle.graal.python.test/src/tests/standalone/test_maven_plugin.py b/graalpython/com.oracle.graal.python.test/src/tests/standalone/test_maven_plugin.py index 4b2cdb5c04..5c4f9e34cb 100644 --- a/graalpython/com.oracle.graal.python.test/src/tests/standalone/test_maven_plugin.py +++ b/graalpython/com.oracle.graal.python.test/src/tests/standalone/test_maven_plugin.py @@ -115,6 +115,8 @@ def check_generated_app(self, use_default_vfs_path, use_utils_pkg=False): cmd = mvnw_cmd + ["package", "-Pnative", "-DmainClass=it.pkg.GraalPy"] out, return_code = util.run_cmd(cmd, self.env, cwd=target_dir) util.check_ouput("BUILD SUCCESS", out) + util.check_ouput("Virtual filesystem is deployed to default resources directory", out, contains=use_default_vfs_path) + util.check_ouput("This can cause conflicts if used with other Java libraries that also deploy GraalPy virtual filesystem.", out, contains=use_default_vfs_path) # check fileslist.txt fl_path = os.path.join(target_dir, "target", "classes", vfs_prefix, "fileslist.txt") diff --git a/graalpython/com.oracle.graal.python.test/src/tests/test_dict.py b/graalpython/com.oracle.graal.python.test/src/tests/test_dict.py index c30e983979..d56456c79c 100644 --- a/graalpython/com.oracle.graal.python.test/src/tests/test_dict.py +++ b/graalpython/com.oracle.graal.python.test/src/tests/test_dict.py @@ -1,4 +1,4 @@ -# Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # The Universal Permissive License (UPL), Version 1.0 @@ -1267,3 +1267,13 @@ def test_dict_values_eq(): d1 = {1: 1, 2: 2, 4: 4} assert d1.values() != d1.values() +def test_removing_attr_from_economic_map(): + class Test: + pass + + o = Test() + o.foo = 1 + o.__dict__[42] = 10 + del o.foo + + assert "foo" not in o.__dict__ diff --git a/graalpython/com.oracle.graal.python.test/src/tests/test_interop.py b/graalpython/com.oracle.graal.python.test/src/tests/test_interop.py index 8533ed3835..6ea5c7e6f6 100644 --- a/graalpython/com.oracle.graal.python.test/src/tests/test_interop.py +++ b/graalpython/com.oracle.graal.python.test/src/tests/test_interop.py @@ -1,4 +1,4 @@ -# Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # The Universal Permissive License (UPL), Version 1.0 @@ -150,7 +150,7 @@ def t(obj): # ForeignInstantiable self.assertEqual(t((e for e in [1])), polyglot.ForeignIteratorIterable) self.assertEqual(t(iter([1])), polyglot.ForeignIteratorIterable) - self.assertEqual(t(object), polyglot.ForeignExecutableClass) + self.assertEqual(t(object), polyglot.ForeignClassExecutable) self.assertEqual(t(None), polyglot.ForeignNone) self.assertEqual(t(1), polyglot.ForeignNumber) self.assertEqual(t("abc"), polyglot.ForeignString) @@ -471,10 +471,19 @@ def test_java_import_from_jar(self): os.unlink(tempname) def test_java_class(self): - from java.lang import Integer, Number, NumberFormatException - self.assertEqual(type(Integer).mro(), [polyglot.ForeignClass, polyglot.ForeignInstantiable, polyglot.ForeignAbstractClass, polyglot.ForeignObject, object]) + from java.lang import Number, NumberFormatException + from java.util import ArrayList + self.assertEqual(type(ArrayList).mro(), [polyglot.ForeignClass, polyglot.ForeignAbstractClass, polyglot.ForeignInstantiable, polyglot.ForeignObject, object]) self.assertEqual(type(Number).mro(), [polyglot.ForeignAbstractClass, polyglot.ForeignObject, object]) - self.assertEqual(type(NumberFormatException).mro(), [polyglot.ForeignClass, polyglot.ForeignInstantiable, polyglot.ForeignAbstractClass, polyglot.ForeignObject, object]) + self.assertEqual(type(NumberFormatException).mro(), [polyglot.ForeignClass, polyglot.ForeignAbstractClass, polyglot.ForeignInstantiable, polyglot.ForeignObject, object]) + + from java.util import ArrayList + l = ArrayList() + assert isinstance(l, ArrayList) + self.assertEqual(getattr(ArrayList, 'class'), l.getClass()) + + with self.assertRaisesRegex(TypeError, "ForeignInstantiable.__call__\(\) got an unexpected keyword argument 'kwarg'"): + ArrayList(kwarg=42) def test_java_exceptions(self): # TODO: more tests @@ -1040,7 +1049,9 @@ def test_java_map(self): h.__init__(a=1, b=2) assert h == {'a': 1, 'b': 2} - with self.assertRaisesRegex(TypeError, 'invalid instantiation of foreign object'): + # Because it tries to call ForeignDict.__call__, but ForeignDict is not executable/instantiable, + # so it resolves to type.__call__, which cannot create a ForeignDict + with self.assertRaisesRegex(TypeError, "descriptor requires a 'dict' object but received a 'ForeignDict'"): type(h).fromkeys(['a', 'b'], 42) def test_java_iterator(self): diff --git a/graalpython/com.oracle.graal.python.test/src/tests/test_startup.py b/graalpython/com.oracle.graal.python.test/src/tests/test_startup.py new file mode 100644 index 0000000000..b17986a53c --- /dev/null +++ b/graalpython/com.oracle.graal.python.test/src/tests/test_startup.py @@ -0,0 +1,90 @@ +# Copyright (c) 2025, 2025, Oracle and/or its affiliates. All rights reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# The Universal Permissive License (UPL), Version 1.0 +# +# Subject to the condition set forth below, permission is hereby granted to any +# person obtaining a copy of this software, associated documentation and/or +# data (collectively the "Software"), free of charge and under any and all +# copyright rights in the Software, and any and all patent rights owned or +# freely licensable by each licensor hereunder covering either (i) the +# unmodified Software as contributed to or provided by such licensor, or (ii) +# the Larger Works (as defined below), to deal in both +# +# (a) the Software, and +# +# (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if +# one is included with the Software each a "Larger Work" to which the Software +# is contributed by such licensors), +# +# without restriction, including without limitation the rights to copy, create +# derivative works of, display, perform, and distribute the Software and make, +# use, sell, offer for sale, import, export, have made, and have sold the +# Software and the Larger Work(s), and to sublicense the foregoing rights on +# either these or other terms. +# +# This license is subject to the following condition: +# +# The above copyright notice and either this complete permission notice or at a +# minimum a reference to the UPL must be included in all copies or substantial +# portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +import unittest +import sys +import re +import subprocess +import platform + +# Both lists should remain as small as possible to avoid adding overhead to startup +expected_nosite_startup_modules = [ + '_frozen_importlib', + '_frozen_importlib_external', + 'builtins', + '__graalpython__', + '_weakref', + 'unicodedata', + '_sre', + '_sysconfig', + 'java', + 'pip_hook', +] + (['_nt'] if platform.system() == 'Windows' else []) + +expected_full_startup_modules = expected_nosite_startup_modules + [ + '_abc', + 'types', + '_weakrefset', + '_py_abc', + 'abc', + 'stat', + '_collections_abc', + 'genericpath', + *(['_winapi', 'ntpath'] if platform.system() == 'Windows' else ['posixpath']), + 'os', + '_sitebuiltins', + '_io', + 'io', + 'site', +] + +class StartupTests(unittest.TestCase): + @unittest.skipUnless(sys.implementation.name == 'graalpy', "GraalPy-specific test") + def test_startup_nosite(self): + result = subprocess.check_output([sys.executable, '--log.level=FINE', '-S', '-v', '-c', 'print("Hello")'], stderr=subprocess.STDOUT, text=True) + assert 'Hello' in result + imports = re.findall("import '(\S+)'", result) + self.assertEqual(expected_nosite_startup_modules, imports) + + @unittest.skipUnless(sys.implementation.name == 'graalpy', "GraalPy-specific test") + def test_startup_full(self): + result = subprocess.check_output([sys.executable, '--log.level=FINE', '-s', '-v', '-c', 'print("Hello")'], stderr=subprocess.STDOUT, text=True) + assert 'Hello' in result + imports = re.findall("import '(\S+)'", result) + self.assertEqual(expected_full_startup_modules, imports) diff --git a/graalpython/com.oracle.graal.python.test/src/tests/unittest_tags/test_strptime.txt b/graalpython/com.oracle.graal.python.test/src/tests/unittest_tags/test_strptime.txt index 019ffaf499..220ef38651 100644 --- a/graalpython/com.oracle.graal.python.test/src/tests/unittest_tags/test_strptime.txt +++ b/graalpython/com.oracle.graal.python.test/src/tests/unittest_tags/test_strptime.txt @@ -35,7 +35,8 @@ test.test_strptime.StrptimeTests.test_percent @ darwin-arm64,darwin-x86_64,linux test.test_strptime.StrptimeTests.test_second @ darwin-arm64,darwin-x86_64,linux-aarch64,linux-x86_64,win32-AMD64 test.test_strptime.StrptimeTests.test_strptime_exception_context @ darwin-arm64,darwin-x86_64,linux-aarch64,linux-x86_64,win32-AMD64 test.test_strptime.StrptimeTests.test_time @ darwin-arm64,darwin-x86_64,linux-aarch64,linux-x86_64,win32-AMD64 -test.test_strptime.StrptimeTests.test_timezone @ darwin-arm64,darwin-x86_64,win32-AMD64 +# Seems to be dependent on the actual time/date/timezone of the machine, at least on GraalPy. Needs investigation +!test.test_strptime.StrptimeTests.test_timezone test.test_strptime.StrptimeTests.test_unconverteddata @ darwin-arm64,darwin-x86_64,linux-aarch64,linux-x86_64,win32-AMD64 test.test_strptime.StrptimeTests.test_year @ darwin-arm64,darwin-x86_64,linux-aarch64,linux-x86_64,win32-AMD64 test.test_strptime.TimeRETests.test_blankpattern @ darwin-arm64,darwin-x86_64,linux-aarch64,linux-x86_64,win32-AMD64 diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/Python3Core.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/Python3Core.java index 633acb7e4c..6115cfbd48 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/Python3Core.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/Python3Core.java @@ -59,6 +59,9 @@ import java.util.ServiceLoader; import java.util.logging.Level; +import com.oracle.graal.python.builtins.objects.foreign.ForeignExecutableBuiltins; +import com.oracle.graal.python.builtins.objects.foreign.ForeignInstantiableBuiltins; +import com.oracle.graal.python.builtins.objects.foreign.ForeignIterableBuiltins; import org.graalvm.nativeimage.ImageInfo; import com.oracle.graal.python.PythonLanguage; @@ -245,6 +248,7 @@ import com.oracle.graal.python.builtins.objects.dict.PDict; import com.oracle.graal.python.builtins.objects.ellipsis.EllipsisBuiltins; import com.oracle.graal.python.builtins.objects.enumerate.EnumerateBuiltins; +import com.oracle.graal.python.builtins.objects.exception.AttributeErrorBuiltins; import com.oracle.graal.python.builtins.objects.exception.BaseExceptionBuiltins; import com.oracle.graal.python.builtins.objects.exception.BaseExceptionGroupBuiltins; import com.oracle.graal.python.builtins.objects.exception.ImportErrorBuiltins; @@ -259,6 +263,7 @@ import com.oracle.graal.python.builtins.objects.exception.UnicodeTranslateErrorBuiltins; import com.oracle.graal.python.builtins.objects.floats.FloatBuiltins; import com.oracle.graal.python.builtins.objects.floats.PFloat; +import com.oracle.graal.python.builtins.objects.foreign.ForeignAbstractClassBuiltins; import com.oracle.graal.python.builtins.objects.foreign.ForeignBooleanBuiltins; import com.oracle.graal.python.builtins.objects.foreign.ForeignNumberBuiltins; import com.oracle.graal.python.builtins.objects.foreign.ForeignObjectBuiltins; @@ -419,6 +424,11 @@ private static TruffleString[] initializeCoreFiles() { toTruffleStringUncached("_sysconfig"), toTruffleStringUncached("java"), toTruffleStringUncached("pip_hook"))); + if (PythonOS.getPythonOS() == PythonOS.PLATFORM_WIN32) { + coreFiles = new ArrayList<>(coreFiles); + coreFiles.add(toTruffleStringUncached("_nt")); + } + // add service loader defined python file extensions if (!ImageInfo.inImageRuntimeCode()) { ServiceLoader providers = ServiceLoader.load(PythonBuiltins.class, Python3Core.class.getClassLoader()); @@ -487,6 +497,10 @@ private static PythonBuiltins[] initializeBuiltins(boolean nativeAccessAllowed, new ForeignObjectBuiltins(), new ForeignNumberBuiltins(), new ForeignBooleanBuiltins(), + new ForeignAbstractClassBuiltins(), + new ForeignExecutableBuiltins(), + new ForeignInstantiableBuiltins(), + new ForeignIterableBuiltins(), new ListBuiltins(), new DictBuiltins(), new DictReprBuiltin(), @@ -563,6 +577,7 @@ private static PythonBuiltins[] initializeBuiltins(boolean nativeAccessAllowed, new GenericAliasIteratorBuiltins(), new com.oracle.graal.python.builtins.objects.types.UnionTypeBuiltins(), // exceptions + new AttributeErrorBuiltins(), new SystemExitBuiltins(), new ImportErrorBuiltins(), new StopIterationBuiltins(), @@ -1056,9 +1071,6 @@ public void run() { } } - // import polyglot decorators and special interop predefined behavior - loadFile(toTruffleStringUncached("_polyglot"), getContext().getCoreHomeOrFail()); - initialized = true; } } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/PythonBuiltinClassType.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/PythonBuiltinClassType.java index cc3d1de44a..02affaa5cd 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/PythonBuiltinClassType.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/PythonBuiltinClassType.java @@ -302,8 +302,12 @@ public enum PythonBuiltinClassType implements TruffleObject { // Foreign ForeignObject("ForeignObject", J_POLYGLOT, Flags.PUBLIC_BASE_WDICT, ForeignObjectBuiltins.SLOTS), - ForeignNumber("ForeignNumber", J_POLYGLOT, Flags.PUBLIC_BASE_WDICT, FOREIGNNUMBER_M_FLAGS, ForeignNumberBuiltins.SLOTS), - ForeignBoolean("ForeignBoolean", J_POLYGLOT, Flags.PUBLIC_BASE_WDICT, FOREIGNNUMBER_M_FLAGS, ForeignBooleanBuiltins.SLOTS), + ForeignNumber("ForeignNumber", J_POLYGLOT, ForeignObject, Flags.PUBLIC_BASE_WDICT, FOREIGNNUMBER_M_FLAGS, ForeignNumberBuiltins.SLOTS), + ForeignBoolean("ForeignBoolean", J_POLYGLOT, ForeignNumber, Flags.PUBLIC_BASE_WDICT, FOREIGNNUMBER_M_FLAGS, ForeignBooleanBuiltins.SLOTS), + ForeignAbstractClass("ForeignAbstractClass", J_POLYGLOT, ForeignObject, Flags.PUBLIC_BASE_WDICT), + ForeignExecutable("ForeignExecutable", J_POLYGLOT, ForeignObject, Flags.PUBLIC_BASE_WDICT), + ForeignInstantiable("ForeignInstantiable", J_POLYGLOT, ForeignObject, Flags.PUBLIC_BASE_WDICT), + ForeignIterable("ForeignIterable", J_POLYGLOT, ForeignObject, Flags.PUBLIC_BASE_WDICT), // bz2 BZ2Compressor("BZ2Compressor", "_bz2"), @@ -332,6 +336,7 @@ public enum PythonBuiltinClassType implements TruffleObject { PStringIO("StringIO", "_io", Flags.PUBLIC_BASE_WDICT), PBytesIO("BytesIO", "_io", Flags.PUBLIC_BASE_WDICT), PBytesIOBuf("_BytesIOBuffer", "_io", Flags.PRIVATE_BASE_WODICT), + PWindowsConsoleIO("_WindowsConsoleIO", "_io", Flags.PRIVATE_BASE_WODICT), PStatResult("stat_result", "os", Flags.PUBLIC_DERIVED_WODICT, TUPLE_M_FLAGS), PStatvfsResult("statvfs_result", "os", Flags.PUBLIC_DERIVED_WODICT, TUPLE_M_FLAGS), @@ -627,6 +632,11 @@ private static class Flags { this(name, module, module, flags); } + PythonBuiltinClassType(String name, String module, PythonBuiltinClassType base, Flags flags) { + this(name, module, module, flags); + this.base = base; + } + PythonBuiltinClassType(String name, String module, Flags flags, TpSlots slots) { this(name, module, module, flags, DEFAULT_M_FLAGS, slots); } @@ -639,6 +649,11 @@ private static class Flags { this(name, module, module, flags, methodsFlags, slots); } + PythonBuiltinClassType(String name, String module, PythonBuiltinClassType base, Flags flags, long methodsFlags, TpSlots slots) { + this(name, module, module, flags, methodsFlags, slots); + this.base = base; + } + PythonBuiltinClassType(String name, String publishInModule, String moduleName, Flags flags) { this(name, publishInModule, moduleName, flags, DEFAULT_M_FLAGS, TpSlots.createEmpty()); } @@ -837,9 +852,6 @@ public final Shape getInstanceShape(PythonLanguage lang) { Boolean.base = PInt; - ForeignNumber.base = ForeignObject; - ForeignBoolean.base = ForeignNumber; - PBaseExceptionGroup.base = PBaseException; SystemExit.base = PBaseException; KeyboardInterrupt.base = PBaseException; diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PolyglotModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PolyglotModuleBuiltins.java index 13843d5f67..49507f1a1e 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PolyglotModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PolyglotModuleBuiltins.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -113,6 +113,7 @@ import com.oracle.graal.python.nodes.interop.InteropBehaviorMethod; import com.oracle.graal.python.nodes.interop.PForeignToPTypeNode; import com.oracle.graal.python.nodes.object.GetForeignObjectClassNode; +import com.oracle.graal.python.nodes.statement.AbstractImportNode; import com.oracle.graal.python.nodes.truffle.PythonArithmeticTypes; import com.oracle.graal.python.nodes.util.CannotCastException; import com.oracle.graal.python.nodes.util.CastToJavaStringNode; @@ -161,6 +162,7 @@ public final class PolyglotModuleBuiltins extends PythonBuiltins { private static final TruffleString T_MODIFIABLE = tsLiteral("modifiable"); private static final TruffleString T_INVOKABLE = tsLiteral("invokable"); private static final TruffleString T_INTERNAL = tsLiteral("internal"); + private static final TruffleString T_INTERNAL_POLYGLOT_MODULE = tsLiteral("_polyglot"); @Override protected List> getNodeFactories() { @@ -189,6 +191,9 @@ public void postInitialize(Python3Core core) { super.postInitialize(core); GetForeignObjectClassNode.getUncached().defineSingleTraitClasses(); + + // import polyglot decorators which are defined in Python code + AbstractImportNode.importModule(T_INTERNAL_POLYGLOT_MODULE); } @Builtin(name = "import_value", minNumOfPositionalArgs = 1, parameterNames = {"name"}) diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixModuleBuiltins.java index edae5c6846..2d567ece0e 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixModuleBuiltins.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2024, Oracle and/or its affiliates. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. * Copyright (c) 2014, Regents of the University of California * * All rights reserved. @@ -366,15 +366,6 @@ public void postInitialize(Python3Core core) { if (PythonOS.getPythonOS() == PythonOS.PLATFORM_WIN32) { // XXX: Until we fix pip environ.setItem(toTruffleStringUncached("PIP_NO_CACHE_DIR"), toTruffleStringUncached("0")); - // XXX: Until we have working winapi and winreg modules for MSVC discovery - environ.setItem(toTruffleStringUncached("DISTUTILS_USE_SDK"), toTruffleStringUncached("1")); - if (getenv.get("MSSdk") == null) { - String sdkdir = getenv.get("WindowsSdkDir"); - if (sdkdir == null) { - sdkdir = "unset"; - } - environ.setItem(toTruffleStringUncached("MSSdk"), toTruffleStringUncached(sdkdir)); - } } PythonModule posix; if (PythonOS.getPythonOS() == PythonOS.PLATFORM_WIN32) { diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/TimeModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/TimeModuleBuiltins.java index 46bd74525e..6eec222635 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/TimeModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/TimeModuleBuiltins.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2024, Oracle and/or its affiliates. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. * Copyright (c) 2013, Regents of the University of California * * All rights reserved. @@ -49,6 +49,7 @@ import java.util.List; import java.util.TimeZone; +import com.oracle.graal.python.nodes.statement.AbstractImportNode; import org.graalvm.nativeimage.ImageInfo; import com.oracle.graal.python.annotations.ArgumentClinic; @@ -153,6 +154,7 @@ public final class TimeModuleBuiltins extends PythonBuiltins { public static final TruffleString T_DAYLIGHT = tsLiteral("daylight"); public static final TruffleString T_TIMEZONE = tsLiteral("timezone"); public static final TruffleString T_ALTZONE = tsLiteral("altzone"); + public static final TruffleString T_POLYGLOT_TIME = tsLiteral("_polyglot_time"); @Override protected List> getNodeFactories() { @@ -192,6 +194,9 @@ public void postInitialize(Python3Core core) { int rawOffsetSeconds = defaultTimeZone.getRawOffset() / -1000; timeModule.setAttribute(T_TIMEZONE, rawOffsetSeconds); timeModule.setAttribute(T_ALTZONE, rawOffsetSeconds - 3600); + + // register_interop_behavior() for time.struct_time + AbstractImportNode.importModule(T_POLYGLOT_TIME); } @TruffleBoundary diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextObjectBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextObjectBuiltins.java index 6ee8ff9172..b14d9f45e1 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextObjectBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextObjectBuiltins.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -129,6 +129,7 @@ import com.oracle.graal.python.nodes.classes.IsSubtypeNode; import com.oracle.graal.python.nodes.object.GetClassNode; import com.oracle.graal.python.nodes.object.GetOrCreateDictNode; +import com.oracle.graal.python.nodes.object.IsNode; import com.oracle.graal.python.nodes.util.CannotCastException; import com.oracle.graal.python.nodes.util.CastToJavaStringNode; import com.oracle.graal.python.nodes.util.CastToTruffleStringNode; @@ -739,4 +740,13 @@ static Object getDict(Object object, return getDict.execute(inliningTarget, object); } } + + @CApiBuiltin(ret = Int, args = {PyObject, PyObject}, call = Ignored) + abstract static class PyTruffle_Is extends CApiBinaryBuiltinNode { + @Specialization + static int isTrue(Object a, Object b, + @Cached IsNode isNode) { + return isNode.execute(a, b) ? 1 : 0; + } + } } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextTypeBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextTypeBuiltins.java index eea71e9ebd..a997a8a2aa 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextTypeBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/cext/PythonCextTypeBuiltins.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -228,20 +228,24 @@ static Object doIt(PythonAbstractNativeObject clazz, @CApiBuiltin(ret = ArgDescriptor.Void, args = {PyTypeObject}, call = Direct) abstract static class PyType_Modified extends CApiUnaryBuiltinNode { - @TruffleBoundary @Specialization - static Object doIt(PythonAbstractNativeObject clazz, + static Object doIt(PythonAbstractClass object, @Bind("this") Node inliningTarget) { - PythonContext context = PythonContext.get(inliningTarget); - CyclicAssumption nativeClassStableAssumption = context.getNativeClassStableAssumption(clazz, false); - if (nativeClassStableAssumption != null) { - nativeClassStableAssumption.invalidate("PyType_Modified(\"" + TypeNodes.GetNameNode.executeUncached(clazz).toJavaStringUncached() + "\") called"); + if (object instanceof PythonAbstractNativeObject clazz) { + PythonContext context = PythonContext.get(inliningTarget); + CyclicAssumption nativeClassStableAssumption = context.getNativeClassStableAssumption(clazz, false); + if (nativeClassStableAssumption != null) { + nativeClassStableAssumption.invalidate("PyType_Modified(\"" + TypeNodes.GetNameNode.executeUncached(clazz).toJavaStringUncached() + "\") called"); + } + MroSequenceStorage mroStorage = TypeNodes.GetMroStorageNode.executeUncached(clazz); + mroStorage.lookupChanged(); + // Reload slots from native, which also invalidates cached slot lookups + clazz.setTpSlots(TpSlots.fromNative(clazz, context)); + } else { + MroSequenceStorage mroStorage = TypeNodes.GetMroStorageNode.executeUncached(object); + mroStorage.lookupChanged(); } - MroSequenceStorage mroStorage = TypeNodes.GetMroStorageNode.executeUncached(clazz); - mroStorage.lookupChanged(); - // Reload slots from native, which also invalidates cached slot lookups - clazz.setTpSlots(TpSlots.fromNative(clazz, context)); return PNone.NO_VALUE; } } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/IOModuleBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/IOModuleBuiltins.java index 6cc698da4d..da35249a4e 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/IOModuleBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/io/IOModuleBuiltins.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -52,6 +52,7 @@ import static com.oracle.graal.python.builtins.PythonBuiltinClassType.PIncrementalNewlineDecoder; import static com.oracle.graal.python.builtins.PythonBuiltinClassType.PTextIOWrapper; import static com.oracle.graal.python.builtins.PythonBuiltinClassType.ValueError; +import static com.oracle.graal.python.builtins.PythonBuiltinClassType.PWindowsConsoleIO; import static com.oracle.graal.python.builtins.modules.WarningsModuleBuiltins.T_WARN; import static com.oracle.graal.python.builtins.modules.io.BufferedIOUtil.SEEK_CUR; import static com.oracle.graal.python.builtins.modules.io.BufferedIOUtil.SEEK_END; @@ -144,6 +145,7 @@ public void initialize(Python3Core core) { addBuiltinConstant("_warn", core.lookupBuiltinModule(T__WARNINGS).getAttribute(T_WARN)); if (PythonOS.getPythonOS() == PythonOS.PLATFORM_WIN32) { addBuiltinConstant("_os", core.lookupBuiltinModule(T_NT)); + addBuiltinConstant("_WindowsConsoleIO", PWindowsConsoleIO); } else { addBuiltinConstant("_os", core.lookupBuiltinModule(T_POSIX)); } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/CApiFunction.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/CApiFunction.java index 5909dc1427..97ad1090b1 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/CApiFunction.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/CApiFunction.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -504,6 +504,7 @@ public final class CApiFunction { @CApiBuiltin(name = "PyUnicode_DecodeLatin1", ret = PyObject, args = {ConstCharPtrAsTruffleString, Py_ssize_t, ConstCharPtrAsTruffleString}, call = CImpl) @CApiBuiltin(name = "PyUnicode_DecodeLocale", ret = PyObject, args = {ConstCharPtrAsTruffleString, ConstCharPtrAsTruffleString}, call = CImpl) @CApiBuiltin(name = "PyUnicode_DecodeLocaleAndSize", ret = PyObject, args = {ConstCharPtrAsTruffleString, Py_ssize_t, ConstCharPtrAsTruffleString}, call = CImpl) + @CApiBuiltin(name = "PyUnicode_DecodeRawUnicodeEscape", ret = PyObject, args = {ConstCharPtrAsTruffleString, Py_ssize_t, ConstCharPtrAsTruffleString}, call = CImpl) @CApiBuiltin(name = "PyUnicode_DecodeUTF16", ret = PyObject, args = {ConstCharPtrAsTruffleString, Py_ssize_t, ConstCharPtrAsTruffleString, INT_LIST}, call = CImpl) @CApiBuiltin(name = "PyUnicode_DecodeUTF16Stateful", ret = PyObject, args = {ConstCharPtrAsTruffleString, Py_ssize_t, ConstCharPtrAsTruffleString, INT_LIST, PY_SSIZE_T_PTR}, call = CImpl) @CApiBuiltin(name = "PyUnicode_DecodeUTF32", ret = PyObject, args = {ConstCharPtrAsTruffleString, Py_ssize_t, ConstCharPtrAsTruffleString, INT_LIST}, call = CImpl) @@ -942,7 +943,6 @@ public final class CApiFunction { @CApiBuiltin(name = "PyUnicode_BuildEncodingMap", ret = PyObject, args = {PyObject}, call = NotImplemented) @CApiBuiltin(name = "PyUnicode_CopyCharacters", ret = Py_ssize_t, args = {PyObject, Py_ssize_t, PyObject, Py_ssize_t, Py_ssize_t}, call = NotImplemented) @CApiBuiltin(name = "PyUnicode_DecodeCharmap", ret = PyObject, args = {ConstCharPtrAsTruffleString, Py_ssize_t, PyObject, ConstCharPtrAsTruffleString}, call = NotImplemented) - @CApiBuiltin(name = "PyUnicode_DecodeRawUnicodeEscape", ret = PyObject, args = {ConstCharPtrAsTruffleString, Py_ssize_t, ConstCharPtrAsTruffleString}, call = NotImplemented) @CApiBuiltin(name = "PyUnicode_DecodeUTF7", ret = PyObject, args = {ConstCharPtrAsTruffleString, Py_ssize_t, ConstCharPtrAsTruffleString}, call = NotImplemented) @CApiBuiltin(name = "PyUnicode_DecodeUTF7Stateful", ret = PyObject, args = {ConstCharPtrAsTruffleString, Py_ssize_t, ConstCharPtrAsTruffleString, PY_SSIZE_T_PTR}, call = NotImplemented) @CApiBuiltin(name = "PyUnicode_DecodeUnicodeEscape", ret = PyObject, args = {ConstCharPtrAsTruffleString, Py_ssize_t, ConstCharPtrAsTruffleString}, call = NotImplemented) diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/ExternalFunctionNodes.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/ExternalFunctionNodes.java index 18528ad4a6..3111ccef04 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/ExternalFunctionNodes.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/ExternalFunctionNodes.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -1309,7 +1309,7 @@ public MethNoargsRoot(PythonLanguage language, TruffleString name, boolean isSta @Override protected Object[] prepareCArguments(VirtualFrame frame) { - return new Object[]{readSelf(frame), PNone.NONE}; + return new Object[]{readSelf(frame), PNone.NO_VALUE}; } @Override diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/common/HashingCollectionNodes.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/common/HashingCollectionNodes.java index 55c4644dbe..ac120a2e3f 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/common/HashingCollectionNodes.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/common/HashingCollectionNodes.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -61,6 +61,7 @@ import com.oracle.graal.python.nodes.object.BuiltinClassProfiles.IsBuiltinObjectProfile; import com.oracle.graal.python.nodes.util.CastToTruffleStringNode; import com.oracle.graal.python.runtime.exception.PException; +import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.HostCompilerDirectives.InliningCutoff; import com.oracle.truffle.api.dsl.Bind; import com.oracle.truffle.api.dsl.Cached; @@ -121,8 +122,8 @@ abstract static class SetValueHashingStorageNode extends PNodeWithContext { @Specialization static HashingStorage doEconomicStorage(VirtualFrame frame, Node inliningTarget, EconomicMapStorage map, Object value, - @Cached ObjectHashMap.PutNode putNode, - @Cached InlinedLoopConditionProfile loopProfile) { + @Shared("putNode") @Cached ObjectHashMap.PutNode putNode, + @Shared("loopProfile") @Cached InlinedLoopConditionProfile loopProfile) { // We want to avoid calling __hash__() during map.put map.setValueForAllKeys(frame, inliningTarget, value, putNode, loopProfile); return map; @@ -134,14 +135,25 @@ static HashingStorage doGeneric(VirtualFrame frame, Node inliningTarget, Hashing @Cached HashingStorageSetItem setItem, @Cached HashingStorageGetIterator getIterator, @Cached HashingStorageIteratorNext itNext, - @Cached HashingStorageIteratorKey itKey) { + @Cached HashingStorageIteratorKey itKey, + @Shared("putNode") @Cached ObjectHashMap.PutNode putNode, + @Shared("loopProfile") @Cached InlinedLoopConditionProfile loopProfile) { HashingStorageIterator it = getIterator.execute(inliningTarget, map); - HashingStorage storage = map; while (itNext.execute(inliningTarget, map, it)) { - Object key = itKey.execute(inliningTarget, storage, it); - storage = setItem.execute(frame, inliningTarget, storage, key, value); + Object key = itKey.execute(inliningTarget, map, it); + HashingStorage newStorage = setItem.execute(frame, inliningTarget, map, key, value); + if (newStorage != map) { + // when the storage changes, the iterator state is not a reliable cursor + // anymore and we need to restart. + if (newStorage instanceof EconomicMapStorage mapStorage) { + mapStorage.setValueForAllKeys(frame, inliningTarget, value, putNode, loopProfile); + return mapStorage; + } else { + throw CompilerDirectives.shouldNotReachHere("We only generalize to EconomicMapStorage"); + } + } } - return storage; + return map; } protected static boolean isEconomicMapStorage(Object o) { diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/exception/AttributeErrorBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/exception/AttributeErrorBuiltins.java new file mode 100644 index 0000000000..02dfc38dd8 --- /dev/null +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/exception/AttributeErrorBuiltins.java @@ -0,0 +1,195 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * The Universal Permissive License (UPL), Version 1.0 + * + * Subject to the condition set forth below, permission is hereby granted to any + * person obtaining a copy of this software, associated documentation and/or + * data (collectively the "Software"), free of charge and under any and all + * copyright rights in the Software, and any and all patent rights owned or + * freely licensable by each licensor hereunder covering either (i) the + * unmodified Software as contributed to or provided by such licensor, or (ii) + * the Larger Works (as defined below), to deal in both + * + * (a) the Software, and + * + * (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if + * one is included with the Software each a "Larger Work" to which the Software + * is contributed by such licensors), + * + * without restriction, including without limitation the rights to copy, create + * derivative works of, display, perform, and distribute the Software and make, + * use, sell, offer for sale, import, export, have made, and have sold the + * Software and the Larger Work(s), and to sublicense the foregoing rights on + * either these or other terms. + * + * This license is subject to the following condition: + * + * The above copyright notice and either this complete permission notice or at a + * minimum a reference to the UPL must be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.oracle.graal.python.builtins.objects.exception; + +import static com.oracle.graal.python.nodes.SpecialMethodNames.J___GETSTATE__; +import static com.oracle.graal.python.nodes.SpecialMethodNames.J___INIT__; +import static com.oracle.graal.python.nodes.SpecialMethodNames.J___REDUCE__; +import static com.oracle.graal.python.util.PythonUtils.TS_ENCODING; +import static com.oracle.graal.python.util.PythonUtils.tsLiteral; + +import java.util.List; + +import com.oracle.graal.python.builtins.Builtin; +import com.oracle.graal.python.builtins.CoreFunctions; +import com.oracle.graal.python.builtins.PythonBuiltinClassType; +import com.oracle.graal.python.builtins.PythonBuiltins; +import com.oracle.graal.python.builtins.objects.PNone; +import com.oracle.graal.python.builtins.objects.common.EmptyStorage; +import com.oracle.graal.python.builtins.objects.common.HashingStorage; +import com.oracle.graal.python.builtins.objects.common.HashingStorageNodes; +import com.oracle.graal.python.builtins.objects.dict.PDict; +import com.oracle.graal.python.builtins.objects.function.PKeyword; +import com.oracle.graal.python.nodes.ErrorMessages; +import com.oracle.graal.python.nodes.PRaiseNode; +import com.oracle.graal.python.nodes.function.PythonBuiltinBaseNode; +import com.oracle.graal.python.nodes.function.builtins.PythonBinaryBuiltinNode; +import com.oracle.graal.python.nodes.function.builtins.PythonUnaryBuiltinNode; +import com.oracle.graal.python.nodes.function.builtins.PythonVarargsBuiltinNode; +import com.oracle.graal.python.nodes.object.GetClassNode; +import com.oracle.graal.python.nodes.object.GetDictIfExistsNode; +import com.oracle.graal.python.runtime.object.PythonObjectFactory; +import com.oracle.truffle.api.dsl.Bind; +import com.oracle.truffle.api.dsl.Cached; +import com.oracle.truffle.api.dsl.GenerateNodeFactory; +import com.oracle.truffle.api.dsl.NodeFactory; +import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.nodes.Node; +import com.oracle.truffle.api.profiles.InlinedLoopConditionProfile; +import com.oracle.truffle.api.strings.TruffleString; + +@CoreFunctions(extendClasses = PythonBuiltinClassType.AttributeError) +public final class AttributeErrorBuiltins extends PythonBuiltins { + + @Override + protected List> getNodeFactories() { + return AttributeErrorBuiltinsFactory.getFactories(); + } + + private static final int IDX_NAME = 0; + private static final int IDX_OBJ = 1; + private static final int NUM_ATTRS = IDX_OBJ + 1; + + private static final TruffleString T_NAME = tsLiteral("name"); + private static final TruffleString T_OBJ = tsLiteral("obj"); + + private static final BaseExceptionAttrNode.StorageFactory ATTR_FACTORY = (args, factory) -> new Object[NUM_ATTRS]; + + @Builtin(name = J___INIT__, minNumOfPositionalArgs = 1, takesVarArgs = true, takesVarKeywordArgs = true) + @GenerateNodeFactory + abstract static class InitNode extends PythonVarargsBuiltinNode { + + @Specialization + static Object init(PBaseException self, Object[] args, PKeyword[] kwargs, + @Bind Node inliningTarget, + @Cached BaseExceptionBuiltins.BaseExceptionInitNode baseExceptionInitNode, + @Cached TruffleString.EqualNode equalNameNode, + @Cached TruffleString.EqualNode equalObjNode, + @Cached InlinedLoopConditionProfile loopProfile, + @Cached PRaiseNode raiseNode) { + baseExceptionInitNode.execute(self, args); + Object[] attrs = new Object[NUM_ATTRS]; + loopProfile.profileCounted(inliningTarget, kwargs.length); + for (int i = 0; loopProfile.inject(inliningTarget, i < kwargs.length); i++) { + PKeyword kw = kwargs[i]; + TruffleString kwName = kw.getName(); + if (equalNameNode.execute(kwName, T_NAME, TS_ENCODING)) { + attrs[IDX_NAME] = kw.getValue(); + } else if (equalObjNode.execute(kwName, T_OBJ, TS_ENCODING)) { + attrs[IDX_OBJ] = kw.getValue(); + } else { + throw raiseNode.raise(PythonBuiltinClassType.TypeError, ErrorMessages.S_IS_AN_INVALID_ARG_FOR_S, kw.getName(), "AttributeError"); + } + } + self.setExceptionAttributes(attrs); + return PNone.NONE; + } + } + + @Builtin(name = "name", minNumOfPositionalArgs = 1, maxNumOfPositionalArgs = 2, isGetter = true, isSetter = true, allowsDelete = true, doc = "attribute name") + @GenerateNodeFactory + public abstract static class NameNode extends PythonBinaryBuiltinNode { + @Specialization + static Object generic(PBaseException self, Object value, + @Cached BaseExceptionAttrNode attrNode) { + return attrNode.execute(self, value, IDX_NAME, ATTR_FACTORY); + } + } + + @Builtin(name = "obj", minNumOfPositionalArgs = 1, maxNumOfPositionalArgs = 2, isGetter = true, isSetter = true, allowsDelete = true, doc = "object") + @GenerateNodeFactory + public abstract static class ObjNode extends PythonBinaryBuiltinNode { + @Specialization + static Object generic(PBaseException self, Object value, + @Cached BaseExceptionAttrNode attrNode) { + return attrNode.execute(self, value, IDX_OBJ, ATTR_FACTORY); + } + } + + @Builtin(name = J___GETSTATE__, minNumOfPositionalArgs = 1) + @GenerateNodeFactory + public abstract static class GetStateNode extends PythonUnaryBuiltinNode { + + @Specialization + static Object get(PBaseException self, + @Bind("this") Node inliningTarget, + @Cached BaseExceptionAttrNode attrNode, + @Cached GetDictIfExistsNode getDictIfExistsNode, + @Cached HashingStorageNodes.HashingStorageSetItem setHashingStorageItem, + @Cached HashingStorageNodes.HashingStorageCopy copyStorageNode, + @Cached PythonObjectFactory factory) { + PDict dict = getDictIfExistsNode.execute(self); + /* + * Note from CPython: We specifically are not pickling the obj attribute since there are + * many cases where it is unlikely to be picklable. + */ + Object name = attrNode.get(self, IDX_NAME, ATTR_FACTORY); + if (name != null) { + HashingStorage storage = (dict != null) ? copyStorageNode.execute(inliningTarget, dict.getDictStorage()) : EmptyStorage.INSTANCE; + storage = setHashingStorageItem.execute(inliningTarget, storage, T_NAME, name); + return factory.createDict(storage); + } else if (dict != null) { + return dict; + } else { + return PNone.NONE; + } + } + } + + @Builtin(name = J___REDUCE__, minNumOfPositionalArgs = 1) + @GenerateNodeFactory + public abstract static class ReduceNode extends PythonUnaryBuiltinNode { + + @Specialization + static Object reduce(VirtualFrame frame, PBaseException self, + @Bind("this") Node inliningTarget, + @Cached GetClassNode getClassNode, + @Cached ExceptionNodes.GetArgsNode getArgsNode, + @Cached GetStateNode getStateNode, + @Cached PythonObjectFactory factory) { + Object clazz = getClassNode.execute(inliningTarget, self); + Object args = getArgsNode.execute(inliningTarget, self); + Object state = getStateNode.execute(frame, self); + return factory.createTuple(new Object[]{clazz, args, state}); + } + } +} diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/foreign/ForeignAbstractClassBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/foreign/ForeignAbstractClassBuiltins.java new file mode 100644 index 0000000000..48cfd68373 --- /dev/null +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/foreign/ForeignAbstractClassBuiltins.java @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. + * Copyright (c) 2014, Regents of the University of California + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package com.oracle.graal.python.builtins.objects.foreign; + +import com.oracle.graal.python.builtins.Builtin; +import com.oracle.graal.python.builtins.CoreFunctions; +import com.oracle.graal.python.builtins.PythonBuiltinClassType; +import com.oracle.graal.python.builtins.PythonBuiltins; +import com.oracle.graal.python.nodes.function.PythonBuiltinBaseNode; +import com.oracle.graal.python.nodes.function.builtins.PythonBinaryBuiltinNode; +import com.oracle.graal.python.nodes.function.builtins.PythonUnaryBuiltinNode; +import com.oracle.graal.python.runtime.GilNode; +import com.oracle.graal.python.runtime.object.PythonObjectFactory; +import com.oracle.graal.python.util.PythonUtils; +import com.oracle.truffle.api.CompilerDirectives; +import com.oracle.truffle.api.dsl.Cached; +import com.oracle.truffle.api.dsl.GenerateNodeFactory; +import com.oracle.truffle.api.dsl.NodeFactory; +import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.interop.InteropLibrary; +import com.oracle.truffle.api.interop.UnsupportedMessageException; +import com.oracle.truffle.api.library.CachedLibrary; + +import java.util.List; + +import static com.oracle.graal.python.nodes.SpecialAttributeNames.J___BASES__; +import static com.oracle.graal.python.nodes.SpecialMethodNames.J___INSTANCECHECK__; + +/* + * NOTE: We are not using IndirectCallContext here in this file + * because it seems unlikely that these interop messages would call back to Python + * and that we would also need precise frame info for that case. + * Adding it shouldn't hurt peak, but might be a non-trivial overhead in interpreter. + */ +@CoreFunctions(extendClasses = PythonBuiltinClassType.ForeignAbstractClass) +public final class ForeignAbstractClassBuiltins extends PythonBuiltins { + @Override + protected List> getNodeFactories() { + return ForeignAbstractClassBuiltinsFactory.getFactories(); + } + + @Builtin(name = J___BASES__, minNumOfPositionalArgs = 1, isGetter = true, isSetter = false) + @GenerateNodeFactory + abstract static class BasesNode extends PythonUnaryBuiltinNode { + @Specialization + static Object getBases(Object self, + @Cached PythonObjectFactory factory) { + return factory.createTuple(PythonUtils.EMPTY_OBJECT_ARRAY); + } + } + + @Builtin(name = J___INSTANCECHECK__, minNumOfPositionalArgs = 2) + @GenerateNodeFactory + abstract static class InstancecheckNode extends PythonBinaryBuiltinNode { + @Specialization(limit = "3") + static Object check(Object self, Object instance, + @CachedLibrary("self") InteropLibrary lib, + @Cached GilNode gil) { + gil.release(true); + try { + return lib.isMetaInstance(self, instance); + } catch (UnsupportedMessageException e) { + throw CompilerDirectives.shouldNotReachHere(); + } finally { + gil.acquire(); + } + } + } + +} diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/foreign/ForeignExecutableBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/foreign/ForeignExecutableBuiltins.java new file mode 100644 index 0000000000..ea02d004c7 --- /dev/null +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/foreign/ForeignExecutableBuiltins.java @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. + * Copyright (c) 2014, Regents of the University of California + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package com.oracle.graal.python.builtins.objects.foreign; + +import static com.oracle.graal.python.nodes.SpecialMethodNames.J___CALL__; + +import java.util.List; + +import com.oracle.graal.python.PythonLanguage; +import com.oracle.graal.python.builtins.Builtin; +import com.oracle.graal.python.builtins.CoreFunctions; +import com.oracle.graal.python.builtins.PythonBuiltinClassType; +import com.oracle.graal.python.builtins.PythonBuiltins; +import com.oracle.graal.python.nodes.ErrorMessages; +import com.oracle.graal.python.nodes.PRaiseNode; +import com.oracle.graal.python.nodes.function.PythonBuiltinBaseNode; +import com.oracle.graal.python.nodes.function.PythonBuiltinNode; +import com.oracle.graal.python.nodes.interop.PForeignToPTypeNode; +import com.oracle.graal.python.runtime.ExecutionContext.IndirectCallContext; +import com.oracle.graal.python.runtime.GilNode; +import com.oracle.graal.python.runtime.IndirectCallData; +import com.oracle.graal.python.runtime.PythonContext; +import com.oracle.graal.python.runtime.exception.PythonErrorType; +import com.oracle.truffle.api.CompilerDirectives; +import com.oracle.truffle.api.dsl.Bind; +import com.oracle.truffle.api.dsl.Cached; +import com.oracle.truffle.api.dsl.GenerateNodeFactory; +import com.oracle.truffle.api.dsl.NodeFactory; +import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.interop.ArityException; +import com.oracle.truffle.api.interop.InteropLibrary; +import com.oracle.truffle.api.interop.UnsupportedMessageException; +import com.oracle.truffle.api.interop.UnsupportedTypeException; +import com.oracle.truffle.api.library.CachedLibrary; +import com.oracle.truffle.api.nodes.Node; + +@CoreFunctions(extendClasses = PythonBuiltinClassType.ForeignExecutable) +public final class ForeignExecutableBuiltins extends PythonBuiltins { + @Override + protected List> getNodeFactories() { + return ForeignExecutableBuiltinsFactory.getFactories(); + } + + @Builtin(name = J___CALL__, minNumOfPositionalArgs = 1, takesVarArgs = true) + @GenerateNodeFactory + public abstract static class CallNode extends PythonBuiltinNode { + @Specialization + static Object doInteropCall(VirtualFrame frame, Object callee, Object[] arguments, + @SuppressWarnings("unused") @Bind("this") Node inliningTarget, + @Cached("createFor(this)") IndirectCallData indirectCallData, + @CachedLibrary(limit = "4") InteropLibrary lib, + @Cached PForeignToPTypeNode toPTypeNode, + @Cached GilNode gil, + @Cached PRaiseNode.Lazy raiseNode) { + PythonLanguage language = PythonLanguage.get(inliningTarget); + PythonContext context = PythonContext.get(inliningTarget); + try { + Object state = IndirectCallContext.enter(frame, language, context, indirectCallData); + gil.release(true); + try { + return toPTypeNode.executeConvert(lib.execute(callee, arguments)); + } finally { + gil.acquire(); + IndirectCallContext.exit(frame, language, context, state); + } + } catch (ArityException | UnsupportedTypeException e) { + throw raiseNode.get(inliningTarget).raise(PythonErrorType.TypeError, ErrorMessages.INVALID_INSTANTIATION_OF_FOREIGN_OBJ); + } catch (UnsupportedMessageException e) { + throw CompilerDirectives.shouldNotReachHere(e); + } + } + } + +} diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/foreign/ForeignInstantiableBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/foreign/ForeignInstantiableBuiltins.java new file mode 100644 index 0000000000..d5b095145e --- /dev/null +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/foreign/ForeignInstantiableBuiltins.java @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. + * Copyright (c) 2014, Regents of the University of California + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package com.oracle.graal.python.builtins.objects.foreign; + +import static com.oracle.graal.python.nodes.SpecialMethodNames.J___CALL__; +import static com.oracle.graal.python.nodes.SpecialMethodNames.J___NEW__; + +import java.util.List; + +import com.oracle.graal.python.PythonLanguage; +import com.oracle.graal.python.builtins.Builtin; +import com.oracle.graal.python.builtins.CoreFunctions; +import com.oracle.graal.python.builtins.PythonBuiltinClassType; +import com.oracle.graal.python.builtins.PythonBuiltins; +import com.oracle.graal.python.nodes.ErrorMessages; +import com.oracle.graal.python.nodes.PRaiseNode; +import com.oracle.graal.python.nodes.function.PythonBuiltinBaseNode; +import com.oracle.graal.python.nodes.function.PythonBuiltinNode; +import com.oracle.graal.python.nodes.interop.PForeignToPTypeNode; +import com.oracle.graal.python.runtime.ExecutionContext.IndirectCallContext; +import com.oracle.graal.python.runtime.GilNode; +import com.oracle.graal.python.runtime.IndirectCallData; +import com.oracle.graal.python.runtime.PythonContext; +import com.oracle.graal.python.runtime.exception.PythonErrorType; +import com.oracle.truffle.api.CompilerDirectives; +import com.oracle.truffle.api.dsl.Bind; +import com.oracle.truffle.api.dsl.Cached; +import com.oracle.truffle.api.dsl.GenerateNodeFactory; +import com.oracle.truffle.api.dsl.NodeFactory; +import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.interop.ArityException; +import com.oracle.truffle.api.interop.InteropLibrary; +import com.oracle.truffle.api.interop.UnsupportedMessageException; +import com.oracle.truffle.api.interop.UnsupportedTypeException; +import com.oracle.truffle.api.library.CachedLibrary; +import com.oracle.truffle.api.nodes.Node; + +@CoreFunctions(extendClasses = PythonBuiltinClassType.ForeignInstantiable) +public final class ForeignInstantiableBuiltins extends PythonBuiltins { + @Override + protected List> getNodeFactories() { + return ForeignInstantiableBuiltinsFactory.getFactories(); + } + + @Builtin(name = J___NEW__, minNumOfPositionalArgs = 1, takesVarArgs = true) + @Builtin(name = J___CALL__, minNumOfPositionalArgs = 1, takesVarArgs = true) + @GenerateNodeFactory + public abstract static class CallNode extends PythonBuiltinNode { + @Specialization + static Object doInteropCall(VirtualFrame frame, Object callee, Object[] arguments, + @SuppressWarnings("unused") @Bind("this") Node inliningTarget, + @Cached("createFor(this)") IndirectCallData indirectCallData, + @CachedLibrary(limit = "4") InteropLibrary lib, + @Cached PForeignToPTypeNode toPTypeNode, + @Cached GilNode gil, + @Cached PRaiseNode.Lazy raiseNode) { + PythonLanguage language = PythonLanguage.get(inliningTarget); + PythonContext context = PythonContext.get(inliningTarget); + try { + Object state = IndirectCallContext.enter(frame, language, context, indirectCallData); + gil.release(true); + try { + return toPTypeNode.executeConvert(lib.instantiate(callee, arguments)); + } finally { + gil.acquire(); + IndirectCallContext.exit(frame, language, context, state); + } + } catch (ArityException | UnsupportedTypeException e) { + throw raiseNode.get(inliningTarget).raise(PythonErrorType.TypeError, ErrorMessages.INVALID_INSTANTIATION_OF_FOREIGN_OBJ); + } catch (UnsupportedMessageException e) { + throw CompilerDirectives.shouldNotReachHere(e); + } + } + } + +} diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/foreign/ForeignIterableBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/foreign/ForeignIterableBuiltins.java new file mode 100644 index 0000000000..647eee6b2f --- /dev/null +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/foreign/ForeignIterableBuiltins.java @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. + * Copyright (c) 2014, Regents of the University of California + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package com.oracle.graal.python.builtins.objects.foreign; + +import static com.oracle.graal.python.nodes.SpecialMethodNames.J___ITER__; + +import java.util.List; + +import com.oracle.graal.python.builtins.Builtin; +import com.oracle.graal.python.builtins.CoreFunctions; +import com.oracle.graal.python.builtins.PythonBuiltinClassType; +import com.oracle.graal.python.builtins.PythonBuiltins; +import com.oracle.graal.python.nodes.function.PythonBuiltinBaseNode; +import com.oracle.graal.python.nodes.function.builtins.PythonUnaryBuiltinNode; +import com.oracle.graal.python.nodes.interop.PForeignToPTypeNode; +import com.oracle.graal.python.runtime.GilNode; +import com.oracle.truffle.api.CompilerDirectives; +import com.oracle.truffle.api.dsl.Cached; +import com.oracle.truffle.api.dsl.GenerateNodeFactory; +import com.oracle.truffle.api.dsl.NodeFactory; +import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.interop.InteropLibrary; +import com.oracle.truffle.api.interop.UnsupportedMessageException; +import com.oracle.truffle.api.library.CachedLibrary; + +/* + * NOTE: We are not using IndirectCallContext here in this file + * because it seems unlikely that these interop messages would call back to Python + * and that we would also need precise frame info for that case. + * Adding it shouldn't hurt peak, but might be a non-trivial overhead in interpreter. + */ +@CoreFunctions(extendClasses = PythonBuiltinClassType.ForeignIterable) +public final class ForeignIterableBuiltins extends PythonBuiltins { + @Override + protected List> getNodeFactories() { + return ForeignIterableBuiltinsFactory.getFactories(); + } + + @Builtin(name = J___ITER__, minNumOfPositionalArgs = 1) + @GenerateNodeFactory + public abstract static class IterNode extends PythonUnaryBuiltinNode { + + @Specialization(limit = "3") + static Object doGeneric(Object object, + @CachedLibrary("object") InteropLibrary lib, + @Cached PForeignToPTypeNode convertNode, + @Cached GilNode gil) { + gil.release(true); + try { + return convertNode.executeConvert(lib.getIterator(object)); + } catch (UnsupportedMessageException e) { + throw CompilerDirectives.shouldNotReachHere(e); + } finally { + gil.acquire(); + } + } + } + +} diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/foreign/ForeignObjectBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/foreign/ForeignObjectBuiltins.java index 617458040f..ea386f7fed 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/foreign/ForeignObjectBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/foreign/ForeignObjectBuiltins.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2024, Oracle and/or its affiliates. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. * Copyright (c) 2014, Regents of the University of California * * All rights reserved. @@ -29,17 +29,10 @@ import static com.oracle.graal.python.builtins.PythonBuiltinClassType.AttributeError; import static com.oracle.graal.python.builtins.PythonBuiltinClassType.TypeError; import static com.oracle.graal.python.builtins.objects.str.StringUtils.simpleTruffleStringFormatUncached; -import static com.oracle.graal.python.nodes.SpecialAttributeNames.J___BASES__; -import static com.oracle.graal.python.nodes.SpecialAttributeNames.T___BASES__; -import static com.oracle.graal.python.nodes.SpecialMethodNames.J___CALL__; import static com.oracle.graal.python.nodes.SpecialMethodNames.J___DIR__; import static com.oracle.graal.python.nodes.SpecialMethodNames.J___HASH__; -import static com.oracle.graal.python.nodes.SpecialMethodNames.J___INSTANCECHECK__; -import static com.oracle.graal.python.nodes.SpecialMethodNames.J___ITER__; -import static com.oracle.graal.python.nodes.SpecialMethodNames.J___NEW__; import static com.oracle.graal.python.nodes.SpecialMethodNames.J___REPR__; import static com.oracle.graal.python.nodes.SpecialMethodNames.J___STR__; -import static com.oracle.graal.python.nodes.SpecialMethodNames.T___INSTANCECHECK__; import static com.oracle.graal.python.util.PythonUtils.TS_ENCODING; import java.util.List; @@ -53,7 +46,6 @@ import com.oracle.graal.python.builtins.PythonBuiltins; import com.oracle.graal.python.builtins.objects.PNone; import com.oracle.graal.python.builtins.objects.PythonAbstractObject; -import com.oracle.graal.python.builtins.objects.function.PKeyword; import com.oracle.graal.python.builtins.objects.object.ObjectBuiltins; import com.oracle.graal.python.builtins.objects.object.ObjectNodes; import com.oracle.graal.python.builtins.objects.type.TpSlots; @@ -65,35 +57,27 @@ import com.oracle.graal.python.nodes.attributes.LookupAttributeInMRONode; import com.oracle.graal.python.nodes.call.special.LookupAndCallUnaryNode; import com.oracle.graal.python.nodes.function.PythonBuiltinBaseNode; -import com.oracle.graal.python.nodes.function.PythonBuiltinNode; -import com.oracle.graal.python.nodes.function.builtins.PythonBinaryBuiltinNode; import com.oracle.graal.python.nodes.function.builtins.PythonUnaryBuiltinNode; import com.oracle.graal.python.nodes.interop.PForeignToPTypeNode; import com.oracle.graal.python.nodes.object.BuiltinClassProfiles.IsBuiltinObjectProfile; import com.oracle.graal.python.nodes.object.GetClassNode; -import com.oracle.graal.python.nodes.object.IsForeignObjectNode; import com.oracle.graal.python.nodes.util.CannotCastException; import com.oracle.graal.python.nodes.util.CastToJavaStringNode; -import com.oracle.graal.python.runtime.ExecutionContext.IndirectCallContext; import com.oracle.graal.python.runtime.GilNode; -import com.oracle.graal.python.runtime.IndirectCallData; import com.oracle.graal.python.runtime.PythonContext; import com.oracle.graal.python.runtime.PythonOptions; import com.oracle.graal.python.runtime.exception.PException; import com.oracle.graal.python.runtime.exception.PythonErrorType; import com.oracle.graal.python.runtime.object.PythonObjectFactory; -import com.oracle.graal.python.util.PythonUtils; import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.api.dsl.Bind; import com.oracle.truffle.api.dsl.Cached; import com.oracle.truffle.api.dsl.Cached.Shared; -import com.oracle.truffle.api.dsl.Fallback; import com.oracle.truffle.api.dsl.GenerateCached; import com.oracle.truffle.api.dsl.GenerateInline; import com.oracle.truffle.api.dsl.GenerateNodeFactory; import com.oracle.truffle.api.dsl.ImportStatic; -import com.oracle.truffle.api.dsl.NeverDefault; import com.oracle.truffle.api.dsl.NodeFactory; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.frame.VirtualFrame; @@ -108,7 +92,7 @@ import com.oracle.truffle.api.strings.TruffleString; /* - * NOTE: We are not using IndirectCallContext here in this file (except for CallNode) + * NOTE: We are not using IndirectCallContext here in this file * because it seems unlikely that these interop messages would call back to Python * and that we would also need precise frame info for that case. * Adding it shouldn't hurt peak, but might be a non-trivial overhead in interpreter. @@ -144,111 +128,6 @@ private static int hashCodeBoundary(Object self) { } } - @Builtin(name = J___ITER__, minNumOfPositionalArgs = 1) - @GenerateNodeFactory - public abstract static class IterNode extends PythonUnaryBuiltinNode { - - @Specialization(limit = "3") - static Object doGeneric(Object object, - @Cached PRaiseNode raiseNode, - @CachedLibrary("object") InteropLibrary lib, - @Cached PForeignToPTypeNode convertNode, - @Cached GilNode gil) { - gil.release(true); - try { - if (lib.hasIterator(object)) { - return convertNode.executeConvert(lib.getIterator(object)); - } - } catch (UnsupportedMessageException e) { - throw CompilerDirectives.shouldNotReachHere(e); - } finally { - gil.acquire(); - } - throw raiseNode.raise(TypeError, ErrorMessages.FOREIGN_OBJ_ISNT_ITERABLE); - } - } - - @Builtin(name = J___NEW__, minNumOfPositionalArgs = 1, takesVarArgs = true, takesVarKeywordArgs = true) - @GenerateNodeFactory - abstract static class NewNode extends PythonBuiltinNode { - @Specialization(guards = {"isForeignObjectNode.execute(inliningTarget, callee)", "!isNoValue(callee)", "keywords.length == 0"}, limit = "1") - static Object doInteropCall(Object callee, Object[] arguments, @SuppressWarnings("unused") PKeyword[] keywords, - @SuppressWarnings("unused") @Bind("this") Node inliningTarget, - @SuppressWarnings("unused") @Cached IsForeignObjectNode isForeignObjectNode, - @CachedLibrary(limit = "3") InteropLibrary lib, - @Cached PForeignToPTypeNode toPTypeNode, - @Cached GilNode gil, - @Cached PRaiseNode.Lazy raiseNode) { - gil.release(true); - try { - Object res = lib.instantiate(callee, arguments); - return toPTypeNode.executeConvert(res); - } catch (ArityException | UnsupportedTypeException | UnsupportedMessageException e) { - throw raiseNode.get(inliningTarget).raise(PythonErrorType.TypeError, ErrorMessages.INVALID_INSTANTIATION_OF_FOREIGN_OBJ); - } finally { - gil.acquire(); - } - } - - @Fallback - @SuppressWarnings("unused") - static Object doGeneric(Object callee, Object arguments, Object keywords, - @Cached PRaiseNode raiseNode) { - throw raiseNode.raise(PythonErrorType.TypeError, ErrorMessages.INVALID_INSTANTIATION_OF_FOREIGN_OBJ); - } - } - - @Builtin(name = J___CALL__, minNumOfPositionalArgs = 1, takesVarArgs = true, takesVarKeywordArgs = true) - @GenerateNodeFactory - public abstract static class CallNode extends PythonBuiltinNode { - public final Object executeWithArgs(VirtualFrame frame, Object callee, Object[] arguments) { - return execute(frame, callee, arguments, PKeyword.EMPTY_KEYWORDS); - } - - public abstract Object execute(VirtualFrame frame, Object callee, Object[] arguments, PKeyword[] keywords); - - @Specialization(guards = {"isForeignObjectNode.execute(inliningTarget, callee)", "!isNoValue(callee)", "keywords.length == 0"}, limit = "1") - static Object doInteropCall(VirtualFrame frame, Object callee, Object[] arguments, @SuppressWarnings("unused") PKeyword[] keywords, - @SuppressWarnings("unused") @Bind("this") Node inliningTarget, - @Cached("createFor(this)") IndirectCallData indirectCallData, - @SuppressWarnings("unused") @Cached IsForeignObjectNode isForeignObjectNode, - @CachedLibrary(limit = "4") InteropLibrary lib, - @Cached PForeignToPTypeNode toPTypeNode, - @Cached GilNode gil, - @Cached PRaiseNode.Lazy raiseNode) { - PythonLanguage language = PythonLanguage.get(inliningTarget); - PythonContext context = PythonContext.get(inliningTarget); - try { - Object state = IndirectCallContext.enter(frame, language, context, indirectCallData); - gil.release(true); - try { - if (lib.isExecutable(callee)) { - return toPTypeNode.executeConvert(lib.execute(callee, arguments)); - } else { - return toPTypeNode.executeConvert(lib.instantiate(callee, arguments)); - } - } finally { - gil.acquire(); - IndirectCallContext.exit(frame, language, context, state); - } - } catch (ArityException | UnsupportedTypeException | UnsupportedMessageException e) { - throw raiseNode.get(inliningTarget).raise(PythonErrorType.TypeError, ErrorMessages.INVALID_INSTANTIATION_OF_FOREIGN_OBJ); - } - } - - @Fallback - @SuppressWarnings("unused") - static Object doGeneric(Object callee, Object arguments, Object keywords, - @Cached PRaiseNode raiseNode) { - throw raiseNode.raise(PythonErrorType.TypeError, ErrorMessages.INVALID_INSTANTIATION_OF_FOREIGN_OBJ); - } - - @NeverDefault - public static CallNode create() { - return ForeignObjectBuiltinsFactory.CallNodeFactory.create(null); - } - } - @Slot(value = SlotKind.tp_getattro, isComplex = true) @GenerateNodeFactory abstract static class GetAttributeNode extends GetAttrBuiltinNode { @@ -497,47 +376,4 @@ protected TruffleString defaultConversion(VirtualFrame frame, InteropLibrary lib } } - @Builtin(name = J___BASES__, minNumOfPositionalArgs = 1, isGetter = true, isSetter = false) - @GenerateNodeFactory - @ImportStatic(PGuards.class) - abstract static class BasesNode extends PythonUnaryBuiltinNode { - @Specialization(limit = "3") - static Object getBases(Object self, - @Bind("this") Node inliningTarget, - @CachedLibrary("self") InteropLibrary lib, - @Cached PythonObjectFactory factory, - @Cached PRaiseNode.Lazy raiseNode) { - if (lib.isMetaObject(self)) { - return factory.createTuple(PythonUtils.EMPTY_OBJECT_ARRAY); - } else { - throw raiseNode.get(inliningTarget).raise(AttributeError, ErrorMessages.FOREIGN_OBJ_HAS_NO_ATTR_S, T___BASES__); - } - } - } - - @Builtin(name = J___INSTANCECHECK__, minNumOfPositionalArgs = 2) - @GenerateNodeFactory - @ImportStatic(PGuards.class) - abstract static class InstancecheckNode extends PythonBinaryBuiltinNode { - @Specialization(limit = "3") - static Object check(Object self, Object instance, - @Bind("this") Node inliningTarget, - @CachedLibrary("self") InteropLibrary lib, - @Cached GilNode gil, - @Cached PRaiseNode.Lazy raiseNode) { - if (lib.isMetaObject(self)) { - gil.release(true); - try { - return lib.isMetaInstance(self, instance); - } catch (UnsupportedMessageException e) { - throw CompilerDirectives.shouldNotReachHere(); - } finally { - gil.acquire(); - } - } else { - throw raiseNode.get(inliningTarget).raise(AttributeError, ErrorMessages.FOREIGN_OBJ_HAS_NO_ATTR_S, T___INSTANCECHECK__); - } - } - } - } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/itertools/TeeBuiltins.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/itertools/TeeBuiltins.java index 29fad45e82..69040f00c5 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/itertools/TeeBuiltins.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/itertools/TeeBuiltins.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -78,7 +78,6 @@ import com.oracle.graal.python.runtime.object.PythonObjectFactory; import com.oracle.truffle.api.dsl.Bind; import com.oracle.truffle.api.dsl.Cached; -import com.oracle.truffle.api.dsl.Cached.Shared; import com.oracle.truffle.api.dsl.GenerateNodeFactory; import com.oracle.truffle.api.dsl.ImportStatic; import com.oracle.truffle.api.dsl.NeverDefault; @@ -144,27 +143,21 @@ static Object iter(PTee self) { @Builtin(name = J___NEXT__, minNumOfPositionalArgs = 1) @GenerateNodeFactory public abstract static class NextNode extends PythonUnaryBuiltinNode { - @Specialization(guards = "self.getIndex() < LINKCELLS") - static Object next(VirtualFrame frame, PTee self, + @Specialization + static Object doIt(VirtualFrame frame, PTee self, @Bind("this") Node inliningTarget, - @Shared @Cached BuiltinFunctions.NextNode nextNode, - @Shared @Cached PRaiseNode.Lazy raiseNode) { + @Cached PythonObjectFactory factory, + @Cached InlinedConditionProfile indexConditionProfile, + @Cached BuiltinFunctions.NextNode nextNode, + @Cached PRaiseNode.Lazy raiseNode) { + if (indexConditionProfile.profile(inliningTarget, self.getIndex() >= LINKCELLS)) { + self.setDataObj(self.getDataobj().jumplink(factory)); + self.setIndex(0); + } Object value = self.getDataobj().getItem(frame, inliningTarget, self.getIndex(), nextNode, raiseNode); self.setIndex(self.getIndex() + 1); return value; } - - @Specialization(guards = "self.getIndex() >= LINKCELLS") - static Object nextNext(VirtualFrame frame, PTee self, - @Bind("this") Node inliningTarget, - @Shared @Cached BuiltinFunctions.NextNode nextNode, - @Cached PythonObjectFactory factory, - @Shared @Cached PRaiseNode.Lazy raiseNode) { - self.setDataObj(self.getDataobj().jumplink(factory)); - Object value = self.getDataobj().getItem(frame, inliningTarget, 0, nextNode, raiseNode); - self.setIndex(1); - return value; - } } @Builtin(name = J___REDUCE__, minNumOfPositionalArgs = 1) diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/module/FrozenModules.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/module/FrozenModules.java index ad7000fa5e..bef91e264c 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/module/FrozenModules.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/module/FrozenModules.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -218,8 +218,10 @@ private static final class Map { private static final PythonFrozenModule FROZEN_ONLY = new PythonFrozenModule("FROZEN_ONLY", null, false); private static final PythonFrozenModule POLYGLOT_ARROW = new PythonFrozenModule("POLYGLOT_ARROW", null, false); private static final PythonFrozenModule _SYSCONFIGDATA = new PythonFrozenModule("_SYSCONFIGDATA", null, false); + private static final PythonFrozenModule _POLYGLOT = new PythonFrozenModule("_POLYGLOT", null, false); + private static final PythonFrozenModule _POLYGLOT_DATETIME = new PythonFrozenModule("_POLYGLOT_DATETIME", null, false); + private static final PythonFrozenModule _POLYGLOT_TIME = new PythonFrozenModule("_POLYGLOT_TIME", null, false); private static final PythonFrozenModule GRAALPY___GRAALPYTHON__ = new PythonFrozenModule("GRAALPY___GRAALPYTHON__", null, false); - private static final PythonFrozenModule GRAALPY__POLYGLOT = new PythonFrozenModule("GRAALPY__POLYGLOT", null, false); private static final PythonFrozenModule GRAALPY__SRE = new PythonFrozenModule("GRAALPY__SRE", null, false); private static final PythonFrozenModule GRAALPY__SYSCONFIG = new PythonFrozenModule("GRAALPY__SYSCONFIG", null, false); private static final PythonFrozenModule GRAALPY__WEAKREF = new PythonFrozenModule("GRAALPY__WEAKREF", null, false); @@ -227,6 +229,7 @@ private static final class Map { private static final PythonFrozenModule GRAALPY_JAVA = new PythonFrozenModule("GRAALPY_JAVA", null, false); private static final PythonFrozenModule GRAALPY_PIP_HOOK = new PythonFrozenModule("GRAALPY_PIP_HOOK", null, false); private static final PythonFrozenModule GRAALPY_UNICODEDATA = new PythonFrozenModule("GRAALPY_UNICODEDATA", null, false); + private static final PythonFrozenModule GRAALPY__NT = new PythonFrozenModule("GRAALPY__NT", null, false); } public static final PythonFrozenModule lookup(String name) { @@ -595,10 +598,14 @@ public static final PythonFrozenModule lookup(String name) { return Map.POLYGLOT_ARROW; case "_sysconfigdata": return Map._SYSCONFIGDATA; + case "_polyglot": + return Map._POLYGLOT; + case "_polyglot_datetime": + return Map._POLYGLOT_DATETIME; + case "_polyglot_time": + return Map._POLYGLOT_TIME; case "graalpy.__graalpython__": return Map.GRAALPY___GRAALPYTHON__; - case "graalpy._polyglot": - return Map.GRAALPY__POLYGLOT; case "graalpy._sre": return Map.GRAALPY__SRE; case "graalpy._sysconfig": @@ -613,6 +620,8 @@ public static final PythonFrozenModule lookup(String name) { return Map.GRAALPY_PIP_HOOK; case "graalpy.unicodedata": return Map.GRAALPY_UNICODEDATA; + case "graalpy._nt": + return Map.GRAALPY__NT; default: return null; } diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/type/TpSlots.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/type/TpSlots.java index 497d8f0470..0685be32b0 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/type/TpSlots.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/type/TpSlots.java @@ -842,7 +842,7 @@ public static TpSlots fromNative(PythonAbstractNativeObject pythonClass, PythonC existingSlotWrapper = execWrapper; } else if (executable != null) { // This can happen for legacy slots where the delegate would be a PFunction - LOGGER.warning(() -> String.format("Unexpected executable for slot pointer: %s", executable)); + LOGGER.fine(() -> String.format("Unexpected executable for slot pointer: %s", executable)); } } catch (UnsupportedMessageException e) { throw new IllegalStateException(e); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/ErrorMessages.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/ErrorMessages.java index f15c1e4196..37dbb36db7 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/ErrorMessages.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/ErrorMessages.java @@ -334,7 +334,6 @@ public abstract class ErrorMessages { public static final TruffleString FAILED_TO_CONVERT_SEQ = tsLiteral("failed to convert sequence"); public static final TruffleString FLOAT_ARG_REQUIRED = tsLiteral("float argument required, not %p"); public static final TruffleString FOREIGN_OBJ_HAS_NO_ATTR_S = tsLiteral("foreign object has no attribute '%s'"); - public static final TruffleString FOREIGN_OBJ_ISNT_ITERABLE = tsLiteral("foreign object is not iterable"); public static final TruffleString FOREIGN_OBJ_ISNT_REVERSE_ITERABLE = tsLiteral("foreign object cannot be iterated in reverse"); public static final TruffleString FORMAT_REQUIRES_MAPPING = tsLiteral("format requires a mapping"); public static final TruffleString FORMAT_STR_CONTAINS_POS_FIELDS = tsLiteral("Format string contains positional fields"); diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/attributes/WriteAttributeToObjectNode.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/attributes/WriteAttributeToObjectNode.java index 012300b2b4..6ce3f2f5c1 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/attributes/WriteAttributeToObjectNode.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/attributes/WriteAttributeToObjectNode.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -50,6 +50,7 @@ import com.oracle.graal.python.builtins.objects.cext.structs.CFields; import com.oracle.graal.python.builtins.objects.cext.structs.CStructAccess; import com.oracle.graal.python.builtins.objects.common.HashingStorage; +import com.oracle.graal.python.builtins.objects.common.HashingStorageNodes; import com.oracle.graal.python.builtins.objects.common.HashingStorageNodes.HashingStorageSetItem; import com.oracle.graal.python.builtins.objects.dict.PDict; import com.oracle.graal.python.builtins.objects.object.PythonObject; @@ -188,7 +189,7 @@ private static boolean writeToDynamicStorageManagedClass(PythonManagedClass klas } // write to the dict: the basic specialization for non-classes - @Specialization(guards = {"dict != null", "!isManagedClass(object)"}) + @Specialization(guards = {"dict != null", "!isManagedClass(object)", "!isNoValue(value)"}) static boolean writeToDictNoType(@SuppressWarnings("unused") PythonObject object, TruffleString key, Object value, @Bind("this") Node inliningTarget, @SuppressWarnings("unused") @Shared("getDict") @Cached GetDictIfExistsNode getDict, @@ -199,7 +200,7 @@ static boolean writeToDictNoType(@SuppressWarnings("unused") PythonObject object } // write to the dict & PythonManagedClass -> requires calling onAttributeUpdate - @Specialization(guards = {"dict != null"}) + @Specialization(guards = {"dict != null", "!isNoValue(value)"}) boolean writeToDictBuiltinType(PythonBuiltinClass klass, TruffleString key, Object value, @Bind("this") Node inliningTarget, @SuppressWarnings("unused") @Shared("getDict") @Cached GetDictIfExistsNode getDict, @@ -216,7 +217,7 @@ boolean writeToDictBuiltinType(PythonBuiltinClass klass, TruffleString key, Obje } } - @Specialization(guards = {"dict != null"}) + @Specialization(guards = {"dict != null", "!isNoValue(value)"}) static boolean writeToDictClass(PythonClass klass, TruffleString key, Object value, @Bind("this") Node inliningTarget, @SuppressWarnings("unused") @Shared("getDict") @Cached GetDictIfExistsNode getDict, @@ -229,6 +230,36 @@ static boolean writeToDictClass(PythonClass klass, TruffleString key, Object val return writeToDictManagedClass(klass, dict, key, value, inliningTarget, callAttrUpdate, updateStorage, setHashingStorageItem, codePointLengthNode, codePointAtIndexNode); } + @Specialization(guards = {"dict != null", "isNoValue(value)", "!isPythonBuiltinClass(obj)"}) + static boolean deleteFromPythonObject(PythonObject obj, TruffleString key, Object value, + @Bind("this") Node inliningTarget, + @SuppressWarnings("unused") @Shared("getDict") @Cached GetDictIfExistsNode getDict, + @Bind("getDict.execute(obj)") PDict dict, + @Shared("callAttrUpdate") @Cached InlinedBranchProfile callAttrUpdate, + @Cached HashingStorageNodes.HashingStorageDelItem hashingStorageDelItem, + @Shared("cpLen") @Cached TruffleString.CodePointLengthNode codePointLengthNode, + @Shared("cpAtIndex") @Cached TruffleString.CodePointAtIndexNode codePointAtIndexNode) { + try { + HashingStorage dictStorage = dict.getDictStorage(); + return hashingStorageDelItem.execute(inliningTarget, dictStorage, key, dict); + } finally { + if (obj instanceof PythonManagedClass klass) { + if (!klass.canSkipOnAttributeUpdate(key, value, codePointLengthNode, codePointAtIndexNode)) { + callAttrUpdate.enter(inliningTarget); + klass.onAttributeUpdate(key, value); + } + } + } + } + + @Specialization(guards = {"dict != null", "isNoValue(value)"}) + static boolean deleteFromPythonBuiltinClass(PythonBuiltinClass klass, TruffleString key, Object value, + @Bind("this") Node inliningTarget, + @SuppressWarnings("unused") @Shared("getDict") @Cached GetDictIfExistsNode getDict, + @Bind("getDict.execute(klass)") PDict dict) { + throw PRaiseNode.raiseUncached(inliningTarget, TypeError, ErrorMessages.CANT_SET_ATTRIBUTE_R_OF_IMMUTABLE_TYPE_N, key, klass); + } + private static boolean writeToDictManagedClass(PythonManagedClass klass, PDict dict, TruffleString key, Object value, Node inliningTarget, InlinedBranchProfile callAttrUpdate, InlinedBranchProfile updateStorage, HashingStorageSetItem setHashingStorageItem, TruffleString.CodePointLengthNode codePointLengthNode, TruffleString.CodePointAtIndexNode codePointAtIndexNode) { diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/exception/TopLevelExceptionHandler.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/exception/TopLevelExceptionHandler.java index f20a4ea9cd..53f1fe05d0 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/exception/TopLevelExceptionHandler.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/exception/TopLevelExceptionHandler.java @@ -195,12 +195,7 @@ private AbstractTruffleException handlePythonException(AbstractTruffleException if (PythonOptions.isPExceptionWithJavaStacktrace(getPythonLanguage()) && e instanceof PException pe) { ExceptionUtils.printJavaStackTrace(pe); } - if (!getSourceSection().getSource().isInteractive()) { - if (getContext().isChildContext()) { - getContext().getChildContextData().setExitCode(1); - } - throw new PythonExitException(this, 1); - } + exit(1); } // Before we leave Python, format the message since outside the context if (e instanceof PException pe) { @@ -209,6 +204,15 @@ private AbstractTruffleException handlePythonException(AbstractTruffleException throw e; } + private void exit(int exitCode) { + if (!getSourceSection().getSource().isInteractive()) { + if (getContext().isChildContext()) { + getContext().getChildContextData().setExitCode(1); + } + throw new PythonExitException(this, exitCode); + } + } + private static boolean isSystemExit(PBaseException pythonException) { return IsBuiltinClassProfile.profileClassSlowPath(GetPythonObjectClassNode.executeUncached(pythonException), SystemExit); } @@ -227,6 +231,7 @@ private void handleJavaException(Throwable e) { if (PythonOptions.shouldPrintJavaStacktrace(getPythonLanguage(), e)) { e.printStackTrace(); } + exit(1); } } catch (UnsupportedMessageException unsupportedMessageException) { throw CompilerDirectives.shouldNotReachHere(); @@ -250,12 +255,12 @@ private void handleSystemExit(PBaseException pythonException) { int exitcode = getExitCode(pythonException); throw new PythonExitException(this, exitcode); } catch (CannotCastException e) { - // fall through - } - if (handleAlwaysRunExceptHook(theContext, pythonException)) { - throw new PythonExitException(this, 1); + if (handleAlwaysRunExceptHook(theContext, pythonException)) { + throw new PythonExitException(this, 1); + } else { + throw pythonException.getExceptionForReraise(pythonException.getTraceback()); + } } - throw pythonException.getExceptionForReraise(pythonException.getTraceback()); } @TruffleBoundary @@ -264,12 +269,12 @@ private Object handleChildContextExit(PBaseException pythonException) throws PEx try { return getExitCode(pythonException); } catch (CannotCastException cce) { - // fall through - } - if (handleAlwaysRunExceptHook(getContext(), pythonException)) { - return 1; + if (handleAlwaysRunExceptHook(getContext(), pythonException)) { + return 1; + } else { + throw pythonException.getExceptionForReraise(pythonException.getTraceback()); + } } - throw pythonException.getExceptionForReraise(pythonException.getTraceback()); } private static int getExitCode(PBaseException pythonException) throws CannotCastException { diff --git a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/object/GetForeignObjectClassNode.java b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/object/GetForeignObjectClassNode.java index b40c4afbcf..b7b041b290 100644 --- a/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/object/GetForeignObjectClassNode.java +++ b/graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/object/GetForeignObjectClassNode.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -87,21 +87,26 @@ public enum Trait { // The type field is only set for cases which are already implemented. // First in MRO + // Interop types first as they are the most concrete/specific types + NULL("None", PythonBuiltinClassType.PNone), BOOLEAN("Boolean", PythonBuiltinClassType.ForeignBoolean), NUMBER("Number", PythonBuiltinClassType.ForeignNumber), // int, float, complex STRING("String", PythonBuiltinClassType.PString), + EXCEPTION("Exception", PythonBuiltinClassType.PBaseException), + META_OBJECT("AbstractClass", PythonBuiltinClassType.ForeignAbstractClass), + + // Interop traits + EXECUTABLE("Executable", PythonBuiltinClassType.ForeignExecutable), + INSTANTIABLE("Instantiable", PythonBuiltinClassType.ForeignInstantiable), + + // Container traits/types must be last, see comment above // Hash before Array so that foreign dict+list prefers dict.[] HASH("Dict", PythonBuiltinClassType.PDict), // Array before Iterable so that foreign list+iterable prefers list.__iter__ ARRAY("List", PythonBuiltinClassType.PList), - EXCEPTION("Exception", PythonBuiltinClassType.PBaseException), - EXECUTABLE("Executable"), - INSTANTIABLE("Instantiable"), // Iterator before Iterable so that foreign iterator+iterable prefers iterator.__iter__ ITERATOR("Iterator", PythonBuiltinClassType.PIterator), - ITERABLE("Iterable"), - META_OBJECT("AbstractClass"), // PythonBuiltinClassType.PythonClass ? - NULL("None", PythonBuiltinClassType.PNone); + ITERABLE("Iterable", PythonBuiltinClassType.ForeignIterable); // Last in MRO public static final Trait[] VALUES = Trait.values(); @@ -111,10 +116,6 @@ public enum Trait { final int bit; final PythonBuiltinClassType type; - Trait(String name) { - this(name, null); - } - Trait(String name, PythonBuiltinClassType type) { this.name = name; this.bit = 1 << ordinal(); @@ -217,14 +218,14 @@ private PythonManagedClass resolvePolyglotForeignClass(int traits) { traitsList.add(classForTraits(trait.bit)); } - if (trait == Trait.INSTANTIABLE && Trait.META_OBJECT.isSet(traits)) { - // Deal with it when we are at trait META_OBJECT - } else if (trait == Trait.META_OBJECT) { + if (trait == Trait.META_OBJECT) { if (Trait.INSTANTIABLE.isSet(traits)) { nameBuilder.append("Class"); } else { nameBuilder.append("AbstractClass"); } + } else if (trait == Trait.INSTANTIABLE && Trait.META_OBJECT.isSet(traits)) { + // Dealt with above } else { nameBuilder.append(trait.name); } diff --git a/graalpython/graalpy-archetype-polyglot-app/pom.xml b/graalpython/graalpy-archetype-polyglot-app/pom.xml index d08b5631bb..e525172eb1 100644 --- a/graalpython/graalpy-archetype-polyglot-app/pom.xml +++ b/graalpython/graalpy-archetype-polyglot-app/pom.xml @@ -45,7 +45,7 @@ SOFTWARE. org.graalvm.python graalpy-archetype-polyglot-app - 25.0.0 + 24.2.1 http://www.graalvm.org/python Maven archetype providing a skeleton GraalPy - Java polyglot application. maven-archetype diff --git a/graalpython/graalpy-archetype-polyglot-app/src/main/resources/archetype-resources/pom.xml b/graalpython/graalpy-archetype-polyglot-app/src/main/resources/archetype-resources/pom.xml index eb03184b9f..e67d93e879 100644 --- a/graalpython/graalpy-archetype-polyglot-app/src/main/resources/archetype-resources/pom.xml +++ b/graalpython/graalpy-archetype-polyglot-app/src/main/resources/archetype-resources/pom.xml @@ -10,7 +10,7 @@ #set( $symbol_dollar = '$' ) - 25.0.0 + 24.2.1 python-community 0.10.4 17 diff --git a/graalpython/graalpy-jbang/examples/hello.java b/graalpython/graalpy-jbang/examples/hello.java index 2afc0c82b3..11049392fc 100644 --- a/graalpython/graalpy-jbang/examples/hello.java +++ b/graalpython/graalpy-jbang/examples/hello.java @@ -40,7 +40,7 @@ */ ///usr/bin/env jbang "$0" "$@" ; exit $? //JAVA 17+ -//DEPS org.graalvm.python:jbang:${env.GRAALPY_VERSION:25.0.0} +//DEPS org.graalvm.python:jbang:${env.GRAALPY_VERSION:24.2.1} // specify python packages and their versions as if used with pip //PIP termcolor==2.2 diff --git a/graalpython/graalpy-jbang/templates/graalpy-template.java.qute b/graalpython/graalpy-jbang/templates/graalpy-template.java.qute index 5258d8cb30..9a94477922 100644 --- a/graalpython/graalpy-jbang/templates/graalpy-template.java.qute +++ b/graalpython/graalpy-jbang/templates/graalpy-template.java.qute @@ -5,7 +5,7 @@ {/for} {#if dependencies.isEmpty()}// //DEPS {/if} {| -//DEPS org.graalvm.python:jbang:${env.GRAALPY_VERSION:25.0.0} +//DEPS org.graalvm.python:jbang:${env.GRAALPY_VERSION:24.2.1} // specify python packages and their versions as if used with pip //PIP termcolor==2.2 |} diff --git a/graalpython/graalpy-jbang/templates/graalpy-template_local_repo.java.qute b/graalpython/graalpy-jbang/templates/graalpy-template_local_repo.java.qute index 9db2304494..6b41f4e288 100644 --- a/graalpython/graalpy-jbang/templates/graalpy-template_local_repo.java.qute +++ b/graalpython/graalpy-jbang/templates/graalpy-template_local_repo.java.qute @@ -8,7 +8,7 @@ //REPOS mc=https://repo1.maven.org/maven2/ //REPOS local=file://{path_to_local_repo} {| -//DEPS org.graalvm.python:jbang:${env.GRAALPY_VERSION:25.0.0} +//DEPS org.graalvm.python:jbang:${env.GRAALPY_VERSION:24.2.1} // specify python packages and their versions as if used with pip //PIP termcolor==2.2 |} diff --git a/graalpython/graalpy-maven-plugin/pom.xml b/graalpython/graalpy-maven-plugin/pom.xml index 7a8715415f..5a8fe1acde 100644 --- a/graalpython/graalpy-maven-plugin/pom.xml +++ b/graalpython/graalpy-maven-plugin/pom.xml @@ -48,7 +48,7 @@ SOFTWARE. graalpy-maven-plugin maven-plugin - 25.0.0 + 24.2.1 http://www.graalvm.org/python graalpy-maven-plugin Handles python related resources in a maven GraalPy - Java polyglot application. @@ -57,7 +57,7 @@ SOFTWARE. 17 17 UTF-8 - 25.0.0 + 24.2.1 diff --git a/graalpython/graalpy-maven-plugin/src/main/java/org/graalvm/python/maven/plugin/ManageResourcesMojo.java b/graalpython/graalpy-maven-plugin/src/main/java/org/graalvm/python/maven/plugin/ManageResourcesMojo.java index bc2b69ceae..d81b78b861 100644 --- a/graalpython/graalpy-maven-plugin/src/main/java/org/graalvm/python/maven/plugin/ManageResourcesMojo.java +++ b/graalpython/graalpy-maven-plugin/src/main/java/org/graalvm/python/maven/plugin/ManageResourcesMojo.java @@ -145,7 +145,7 @@ public void execute() throws MojoExecutionException { } if (resourceDirectory == null) { - if (externalDirectory != null) { + if (externalDirectory == null) { getLog().info(String.format("Virtual filesystem is deployed to default resources directory '%s'. " + "This can cause conflicts if used with other Java libraries that also deploy GraalPy virtual filesystem. " + "Consider adding GRAALPY-VFS/${project.groupId}/${project.artifactId} to your pom.xml, " + @@ -162,7 +162,7 @@ public void execute() throws MojoExecutionException { getLog().warn("The GraalPy plugin configuration setting was deprecated and has no effect anymore.\n" + "For execution in jvm mode, the python language home is always available.\n" + "When building a native executable using GraalVM Native Image, then the full python language home is by default embedded into the native executable.\n" + - "For more details, please refer to the documentation of GraalVM Native Image options IncludeLanguageResources and CopyLanguageResources documentation."); + "For more details, please refer to the documentation of GraalVM Native Image options IncludeLanguageResources and CopyLanguageResources."); } manageVenv(); diff --git a/graalpython/lib-graalpython/_nt.py b/graalpython/lib-graalpython/_nt.py new file mode 100644 index 0000000000..4fbd2a2591 --- /dev/null +++ b/graalpython/lib-graalpython/_nt.py @@ -0,0 +1,54 @@ +# Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# The Universal Permissive License (UPL), Version 1.0 +# +# Subject to the condition set forth below, permission is hereby granted to any +# person obtaining a copy of this software, associated documentation and/or +# data (collectively the "Software"), free of charge and under any and all +# copyright rights in the Software, and any and all patent rights owned or +# freely licensable by each licensor hereunder covering either (i) the +# unmodified Software as contributed to or provided by such licensor, or (ii) +# the Larger Works (as defined below), to deal in both +# +# (a) the Software, and +# +# (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if +# one is included with the Software each a "Larger Work" to which the Software +# is contributed by such licensors), +# +# without restriction, including without limitation the rights to copy, create +# derivative works of, display, perform, and distribute the Software and make, +# use, sell, offer for sale, import, export, have made, and have sold the +# Software and the Larger Work(s), and to sublicense the foregoing rights on +# either these or other terms. +# +# This license is subject to the following condition: +# +# The above copyright notice and either this complete permission notice or at a +# minimum a reference to the UPL must be included in all copies or substantial +# portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +import nt + + +def _add_dll_directory(path): + import ctypes + return ctypes.windll.kernel32.AddDllDirectory(path) + + +def _remove_dll_directory(cookie): + import ctypes + return ctypes.windll.kernel32.RemoveDllDirectory(cookie) + + +nt._add_dll_directory = _add_dll_directory +nt._remove_dll_directory = _remove_dll_directory \ No newline at end of file diff --git a/graalpython/lib-graalpython/_polyglot.py b/graalpython/lib-graalpython/modules/_polyglot.py similarity index 67% rename from graalpython/lib-graalpython/_polyglot.py rename to graalpython/lib-graalpython/modules/_polyglot.py index caf9cebdc0..770575c8a8 100644 --- a/graalpython/lib-graalpython/_polyglot.py +++ b/graalpython/lib-graalpython/modules/_polyglot.py @@ -1,4 +1,4 @@ -# Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # The Universal Permissive License (UPL), Version 1.0 @@ -37,9 +37,7 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. -import datetime import polyglot -import time def interop_type(foreign_class, allow_method_overwrites=False): @@ -112,37 +110,6 @@ def wrapper(python_class): setattr(polyglot, "interop_behavior", interop_behavior) -def _date_time_tz(dt: datetime.datetime): - if dt.tzinfo is not None: - utcoffset = dt.tzinfo.utcoffset(dt) - return utcoffset.days * 3600 * 24 + utcoffset.seconds - raise polyglot.UnsupportedMessage - - -def _struct_time_tz(st: time.struct_time): - if st.tm_gmtoff is not None: - return st.tm_gmtoff - return st.tm_zone - - -polyglot.register_interop_behavior(datetime.time, - is_time=True, as_time=lambda d: (d.hour, d.minute, d.second, d.microsecond), - is_time_zone=lambda t: t.tzinfo is not None, as_time_zone=_date_time_tz) - -polyglot.register_interop_behavior(datetime.date, - is_date=True, as_date=lambda d: (d.year, d.month, d.day)) - -polyglot.register_interop_behavior(datetime.datetime, - is_date=True, as_date=lambda d: (d.year, d.month, d.day), - is_time=True, as_time=lambda d: (d.hour, d.minute, d.second, d.microsecond), - is_time_zone=lambda t: t.tzinfo is not None, as_time_zone=_date_time_tz) - -polyglot.register_interop_behavior(time.struct_time, - is_date=True, as_date=lambda t: (t.tm_year, t.tm_mon, t.tm_mday), - is_time=True, as_time=lambda t: (t.tm_hour, t.tm_min, t.tm_sec, 0), - is_time_zone=lambda t: t.tm_zone is not None or t.tm_gmtoff is not None, - as_time_zone=_struct_time_tz) - # loading arrow structures on demand def __getattr__(name): if name == "arrow": @@ -153,33 +120,3 @@ def __getattr__(name): setattr(polyglot, "__getattr__", __getattr__) setattr(polyglot, "__path__", ".") - -# example extending time.struct_time using the decorator wrapper -# -# @polyglot.interop_behavior(time.struct_time) -# class StructTimeInteropBehavior: -# @staticmethod -# def is_date(t): -# return True -# -# @staticmethod -# def as_date(t): -# return t.tm_year, t.tm_mon, t.tm_mday -# -# @staticmethod -# def is_time(t): -# return True -# -# @staticmethod -# def as_time(t): -# return t.tm_hour, t.tm_min, t.tm_sec, 0 -# -# @staticmethod -# def is_time_zone(t): -# return t.tm_zone is not None or t.tm_gmtoff is not None -# -# @staticmethod -# def as_time_zone(t): -# if t.tm_gmtoff is not None: -# return t.tm_gmtoff -# return t.tm_zone diff --git a/graalpython/lib-graalpython/modules/_polyglot_datetime.py b/graalpython/lib-graalpython/modules/_polyglot_datetime.py new file mode 100644 index 0000000000..80f73a74de --- /dev/null +++ b/graalpython/lib-graalpython/modules/_polyglot_datetime.py @@ -0,0 +1,60 @@ +# Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# The Universal Permissive License (UPL), Version 1.0 +# +# Subject to the condition set forth below, permission is hereby granted to any +# person obtaining a copy of this software, associated documentation and/or +# data (collectively the "Software"), free of charge and under any and all +# copyright rights in the Software, and any and all patent rights owned or +# freely licensable by each licensor hereunder covering either (i) the +# unmodified Software as contributed to or provided by such licensor, or (ii) +# the Larger Works (as defined below), to deal in both +# +# (a) the Software, and +# +# (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if +# one is included with the Software each a "Larger Work" to which the Software +# is contributed by such licensors), +# +# without restriction, including without limitation the rights to copy, create +# derivative works of, display, perform, and distribute the Software and make, +# use, sell, offer for sale, import, export, have made, and have sold the +# Software and the Larger Work(s), and to sublicense the foregoing rights on +# either these or other terms. +# +# This license is subject to the following condition: +# +# The above copyright notice and either this complete permission notice or at a +# minimum a reference to the UPL must be included in all copies or substantial +# portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +import datetime +import polyglot + +def _date_time_tz(dt: datetime.datetime): + if dt.tzinfo is not None: + utcoffset = dt.tzinfo.utcoffset(dt) + return utcoffset.days * 3600 * 24 + utcoffset.seconds + raise polyglot.UnsupportedMessage + + +polyglot.register_interop_behavior(datetime.time, + is_time=True, as_time=lambda d: (d.hour, d.minute, d.second, d.microsecond), + is_time_zone=lambda t: t.tzinfo is not None, as_time_zone=_date_time_tz) + +polyglot.register_interop_behavior(datetime.date, + is_date=True, as_date=lambda d: (d.year, d.month, d.day)) + +polyglot.register_interop_behavior(datetime.datetime, + is_date=True, as_date=lambda d: (d.year, d.month, d.day), + is_time=True, as_time=lambda d: (d.hour, d.minute, d.second, d.microsecond), + is_time_zone=lambda t: t.tzinfo is not None, as_time_zone=_date_time_tz) diff --git a/graalpython/lib-graalpython/modules/_polyglot_time.py b/graalpython/lib-graalpython/modules/_polyglot_time.py new file mode 100644 index 0000000000..ed4dc0fc54 --- /dev/null +++ b/graalpython/lib-graalpython/modules/_polyglot_time.py @@ -0,0 +1,84 @@ +# Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# The Universal Permissive License (UPL), Version 1.0 +# +# Subject to the condition set forth below, permission is hereby granted to any +# person obtaining a copy of this software, associated documentation and/or +# data (collectively the "Software"), free of charge and under any and all +# copyright rights in the Software, and any and all patent rights owned or +# freely licensable by each licensor hereunder covering either (i) the +# unmodified Software as contributed to or provided by such licensor, or (ii) +# the Larger Works (as defined below), to deal in both +# +# (a) the Software, and +# +# (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if +# one is included with the Software each a "Larger Work" to which the Software +# is contributed by such licensors), +# +# without restriction, including without limitation the rights to copy, create +# derivative works of, display, perform, and distribute the Software and make, +# use, sell, offer for sale, import, export, have made, and have sold the +# Software and the Larger Work(s), and to sublicense the foregoing rights on +# either these or other terms. +# +# This license is subject to the following condition: +# +# The above copyright notice and either this complete permission notice or at a +# minimum a reference to the UPL must be included in all copies or substantial +# portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +import time +import polyglot + + +def _struct_time_tz(st: time.struct_time): + if st.tm_gmtoff is not None: + return st.tm_gmtoff + return st.tm_zone + + +polyglot.register_interop_behavior(time.struct_time, + is_date=True, as_date=lambda t: (t.tm_year, t.tm_mon, t.tm_mday), + is_time=True, as_time=lambda t: (t.tm_hour, t.tm_min, t.tm_sec, 0), + is_time_zone=lambda t: t.tm_zone is not None or t.tm_gmtoff is not None, + as_time_zone=_struct_time_tz) + +# example extending time.struct_time using the decorator wrapper +# +# @polyglot.interop_behavior(time.struct_time) +# class StructTimeInteropBehavior: +# @staticmethod +# def is_date(t): +# return True +# +# @staticmethod +# def as_date(t): +# return t.tm_year, t.tm_mon, t.tm_mday +# +# @staticmethod +# def is_time(t): +# return True +# +# @staticmethod +# def as_time(t): +# return t.tm_hour, t.tm_min, t.tm_sec, 0 +# +# @staticmethod +# def is_time_zone(t): +# return t.tm_zone is not None or t.tm_gmtoff is not None +# +# @staticmethod +# def as_time_zone(t): +# if t.tm_gmtoff is not None: +# return t.tm_gmtoff +# return t.tm_zone diff --git a/graalpython/lib-graalpython/patches/metadata.toml b/graalpython/lib-graalpython/patches/metadata.toml index ac1ccb7262..855e1f8831 100644 --- a/graalpython/lib-graalpython/patches/metadata.toml +++ b/graalpython/lib-graalpython/patches/metadata.toml @@ -337,6 +337,11 @@ version = '== 3.10.5' patch = 'orjson-3.10.5.patch' license = 'Apache-2.0 OR MIT' +[[ormsgpack.rules]] +version = '>= 1.8.0, <= 1.9.1' +patch = 'ormsgpack-1.8.0-1.9.1.patch' +license = 'Apache-2.0 OR MIT' + [[overrides.rules]] version = '== 7.4.0' # Important: This patch esentially breaks the package, it's not upstreamable. The package relies on bytecode parsing @@ -476,6 +481,15 @@ version = ">= 4.8.0" patch = 'pymongo-4.8.0.patch' license = 'Apache-2.0' +[[PyMuPDF.rules]] +version = "== 1.25.4" +patch = "pymupdf.patch" +# That project is AGPL, so do not actually include *any* code of pymupdf in the patch, not even an +# empty line, in the diff context. The code we write in the patch is UPL - that is compatible with +# AGPL in the sense that if someone were to apply it and distribute *that*, our patch is now part +# of the AGPL'd codebase +license = 'UPL' + [[pyOpenSSL.rules]] # Pin this version to avoid pulling newer cryptography than we have patch for version = "== 23.2.0" diff --git a/graalpython/lib-graalpython/patches/ormsgpack-1.8.0-1.9.1.patch b/graalpython/lib-graalpython/patches/ormsgpack-1.8.0-1.9.1.patch new file mode 100644 index 0000000000..3a9542a058 --- /dev/null +++ b/graalpython/lib-graalpython/patches/ormsgpack-1.8.0-1.9.1.patch @@ -0,0 +1,364 @@ +diff --git a/src/deserialize/deserializer.rs b/src/deserialize/deserializer.rs +index 41cf7f1..99cd68e 100644 +--- a/src/deserialize/deserializer.rs ++++ b/src/deserialize/deserializer.rs +@@ -292,7 +292,10 @@ impl<'de> Deserializer<'de> { + marker => Err(Error::InvalidType(marker)), + }?; + let value = self.deserialize()?; ++ #[cfg(not(GraalPy))] + let pyhash = unsafe { (*key.as_ptr().cast::()).hash }; ++ #[cfg(GraalPy)] ++ let pyhash = unsafe { pyo3::ffi::PyObject_Hash(key.as_ptr()) }; + let _ = ffi!(_PyDict_SetItem_KnownHash( + dict_ptr, + key.as_ptr(), +@@ -471,7 +474,7 @@ impl<'de> Deserializer<'de> { + let ptr = ffi!(PyTuple_New(len as pyo3::ffi::Py_ssize_t)); + for i in 0..len { + let elem = self.deserialize_map_key()?; +- ffi!(PyTuple_SET_ITEM( ++ ffi!(PyTuple_SetItem( + ptr, + i as pyo3::ffi::Py_ssize_t, + elem.as_ptr() +diff --git a/src/ext.rs b/src/ext.rs +index b2573b4..9668d4f 100644 +--- a/src/ext.rs ++++ b/src/ext.rs +@@ -22,7 +22,7 @@ unsafe extern "C" fn ext_new( + ); + return null_mut(); + } +- let tag = PyTuple_GET_ITEM(args, 0); ++ let tag = PyTuple_GetItem(args, 0); + if PyLong_Check(tag) == 0 { + PyErr_SetString( + PyExc_TypeError, +@@ -30,7 +30,7 @@ unsafe extern "C" fn ext_new( + ); + return null_mut(); + } +- let data = PyTuple_GET_ITEM(args, 1); ++ let data = PyTuple_GetItem(args, 1); + if PyBytes_Check(data) == 0 { + PyErr_SetString( + PyExc_TypeError, +diff --git a/src/ffi.rs b/src/ffi.rs +index 4e5ddc3..20c9db4 100644 +--- a/src/ffi.rs ++++ b/src/ffi.rs +@@ -7,13 +7,16 @@ use std::ptr::NonNull; + #[allow(non_snake_case)] + #[inline(always)] + pub unsafe fn PyBytes_AS_STRING(op: *mut PyObject) -> *const c_char { +- &(*op.cast::()).ob_sval as *const c_char ++ #[cfg(not(any(PyPy, GraalPy, Py_LIMITED_API)))] ++ return &(*op.cast::()).ob_sval as *const c_char; ++ #[cfg(any(PyPy, GraalPy, Py_LIMITED_API))] ++ return crate::PyBytes_AsString(op); + } + + #[allow(non_snake_case)] + #[inline(always)] + pub unsafe fn PyBytes_GET_SIZE(op: *mut PyObject) -> Py_ssize_t { +- (*op.cast::()).ob_size ++ Py_SIZE(op) + } + + #[repr(C)] +@@ -63,11 +66,21 @@ pub fn pylong_is_positive(op: *mut PyObject) -> bool { + unsafe { (*(op as *mut PyLongObject)).long_value.lv_tag & SIGN_MASK == 0 } + } + +-#[cfg(not(Py_3_12))] ++#[cfg(not(any(Py_3_12, GraalPy)))] + pub fn pylong_is_positive(op: *mut PyObject) -> bool { + unsafe { (*(op as *mut PyVarObject)).ob_size > 0 } + } + ++extern "C" { ++ #[cfg(not(PyPy))] ++ pub fn _PyLong_Sign(v: *mut PyObject) -> c_int; ++} ++ ++#[cfg(GraalPy)] ++pub fn pylong_is_positive(op: *mut PyObject) -> bool { ++ unsafe { _PyLong_Sign(op) > 0 } ++} ++ + pub struct PyDictIter { + op: *mut PyObject, + pos: isize, +diff --git a/src/lib.rs b/src/lib.rs +index f10b1c4..1a9768b 100644 +--- a/src/lib.rs ++++ b/src/lib.rs +@@ -143,7 +143,7 @@ fn raise_unpackb_exception(msg: &str) -> *mut PyObject { + let err_msg = + PyUnicode_FromStringAndSize(msg.as_ptr() as *const c_char, msg.len() as isize); + let args = PyTuple_New(1); +- PyTuple_SET_ITEM(args, 0, err_msg); ++ PyTuple_SetItem(args, 0, err_msg); + PyErr_SetObject(typeref::MsgpackDecodeError, args); + Py_DECREF(args); + }; +@@ -199,10 +199,10 @@ pub unsafe extern "C" fn unpackb( + if !kwnames.is_null() { + let tuple_size = PyTuple_GET_SIZE(kwnames); + for i in 0..tuple_size { +- let arg = PyTuple_GET_ITEM(kwnames, i as Py_ssize_t); +- if arg == typeref::EXT_HOOK { ++ let arg = PyTuple_GetItem(kwnames, i as Py_ssize_t); ++ if PyUnicode_Compare(arg, typeref::EXT_HOOK) == 0 { + ext_hook = Some(NonNull::new_unchecked(*args.offset(num_args + i))); +- } else if arg == typeref::OPTION { ++ } else if PyUnicode_Compare(arg, typeref::OPTION) == 0 { + optsptr = Some(NonNull::new_unchecked(*args.offset(num_args + i))); + } else { + return raise_unpackb_exception("unpackb() got an unexpected keyword argument"); +@@ -247,15 +247,15 @@ pub unsafe extern "C" fn packb( + if !kwnames.is_null() { + let tuple_size = PyTuple_GET_SIZE(kwnames); + for i in 0..tuple_size { +- let arg = PyTuple_GET_ITEM(kwnames, i as Py_ssize_t); +- if arg == typeref::DEFAULT { ++ let arg = PyTuple_GetItem(kwnames, i as Py_ssize_t); ++ if PyUnicode_Compare(arg, typeref::DEFAULT) == 0 { + if unlikely!(default.is_some()) { + return raise_packb_exception( + "packb() got multiple values for argument: 'default'", + ); + } + default = Some(NonNull::new_unchecked(*args.offset(num_args + i))); +- } else if arg == typeref::OPTION { ++ } else if PyUnicode_Compare(arg, typeref::OPTION) == 0 { + if unlikely!(optsptr.is_some()) { + return raise_packb_exception( + "packb() got multiple values for argument: 'option'", +diff --git a/src/serialize/datetime.rs b/src/serialize/datetime.rs +index 63212d6..5ac2b2b 100644 +--- a/src/serialize/datetime.rs ++++ b/src/serialize/datetime.rs +@@ -61,9 +61,14 @@ pub struct Time { + + impl Time { + pub fn new(ptr: *mut pyo3::ffi::PyObject, opts: Opt) -> Result { ++ #[cfg(not(GraalPy))] + if unsafe { (*(ptr as *mut pyo3::ffi::PyDateTime_Time)).hastzinfo != 0 } { + return Err(TimeError::HasTimezone); + } ++ #[cfg(GraalPy)] ++ if unsafe { pyo3::ffi::PyDateTime_TIME_GET_TZINFO(ptr) != crate::typeref::NONE } { ++ return Err(TimeError::HasTimezone); ++ } + Ok(Time { + ptr: ptr, + opts: opts, +@@ -114,23 +119,28 @@ impl std::fmt::Display for DateTimeError { + } + + fn utcoffset(ptr: *mut pyo3::ffi::PyObject) -> Result { ++ #[cfg(not(GraalPy))] + if !unsafe { (*(ptr as *mut pyo3::ffi::PyDateTime_DateTime)).hastzinfo == 1 } { + return Ok(Offset::default()); + } + + let tzinfo = ffi!(PyDateTime_DATE_GET_TZINFO(ptr)); ++ #[cfg(GraalPy)] ++ if unsafe { tzinfo == crate::typeref::NONE } { ++ return Ok(Offset::default()); ++ } + let py_offset: *mut pyo3::ffi::PyObject; + if ffi!(PyObject_HasAttr(tzinfo, CONVERT_METHOD_STR)) == 1 { + // pendulum +- py_offset = ffi!(PyObject_CallMethodNoArgs(ptr, UTCOFFSET_METHOD_STR)); ++ py_offset = unsafe { pyo3::ffi::compat::PyObject_CallMethodNoArgs(ptr, UTCOFFSET_METHOD_STR) }; + } else if ffi!(PyObject_HasAttr(tzinfo, NORMALIZE_METHOD_STR)) == 1 { + // pytz +- let normalized = ffi!(PyObject_CallMethodOneArg(tzinfo, NORMALIZE_METHOD_STR, ptr)); +- py_offset = ffi!(PyObject_CallMethodNoArgs(normalized, UTCOFFSET_METHOD_STR)); ++ let normalized = ffi!(PyObject_CallMethodObjArgs(tzinfo, NORMALIZE_METHOD_STR, ptr, std::ptr::null_mut::())); ++ py_offset = unsafe { pyo3::ffi::compat::PyObject_CallMethodNoArgs(normalized, UTCOFFSET_METHOD_STR) }; + ffi!(Py_DECREF(normalized)); + } else if ffi!(PyObject_HasAttr(tzinfo, DST_STR)) == 1 { + // dateutil/arrow, datetime.timezone.utc +- py_offset = ffi!(PyObject_CallMethodOneArg(tzinfo, UTCOFFSET_METHOD_STR, ptr)); ++ py_offset = ffi!(PyObject_CallMethodObjArgs(tzinfo, UTCOFFSET_METHOD_STR, ptr, std::ptr::null_mut::())); + } else { + return Err(DateTimeError::LibraryUnsupported); + } +@@ -193,7 +203,10 @@ impl TimeLike for DateTime { + + impl DateTimeLike for DateTime { + fn has_tz(&self) -> bool { +- unsafe { (*(self.ptr as *mut pyo3::ffi::PyDateTime_DateTime)).hastzinfo == 1 } ++ #[cfg(not(GraalPy))] ++ return unsafe { (*(self.ptr as *mut pyo3::ffi::PyDateTime_DateTime)).hastzinfo == 1 }; ++ #[cfg(GraalPy)] ++ return unsafe { pyo3::ffi::PyDateTime_TIME_GET_TZINFO(self.ptr) != crate::typeref::NONE }; + } + + fn offset(&self) -> Offset { +diff --git a/src/serialize/numpy.rs b/src/serialize/numpy.rs +index afc5cdf..4d007bd 100644 +--- a/src/serialize/numpy.rs ++++ b/src/serialize/numpy.rs +@@ -392,8 +392,8 @@ impl NumpyDatetimeUnit { + fn from_pyobject(ptr: *mut PyObject) -> Self { + let dtype = ffi!(PyObject_GetAttr(ptr, DTYPE_STR)); + let descr = ffi!(PyObject_GetAttr(dtype, DESCR_STR)); +- let el0 = ffi!(PyList_GET_ITEM(descr, 0)); +- let descr_str = ffi!(PyTuple_GET_ITEM(el0, 1)); ++ let el0 = ffi!(PyList_GetItem(descr, 0)); ++ let descr_str = ffi!(PyTuple_GetItem(el0, 1)); + let uni = crate::unicode::unicode_to_str(descr_str).unwrap(); + if uni.len() < 5 { + return Self::NaT; +diff --git a/src/serialize/serializer.rs b/src/serialize/serializer.rs +index 309e6e1..6f7dec7 100644 +--- a/src/serialize/serializer.rs ++++ b/src/serialize/serializer.rs +@@ -864,7 +864,7 @@ impl Serialize for DictTupleKey { + let len = ffi!(PyTuple_GET_SIZE(self.ptr)) as usize; + let mut seq = serializer.serialize_seq(Some(len)).unwrap(); + for i in 0..len { +- let item = ffi!(PyTuple_GET_ITEM(self.ptr, i as isize)); ++ let item = ffi!(PyTuple_GetItem(self.ptr, i as isize)); + let value = DictKey::new(item, self.opts, self.recursion + 1); + seq.serialize_element(&value)?; + } +diff --git a/src/serialize/tuple.rs b/src/serialize/tuple.rs +index fa81cb6..9b66019 100644 +--- a/src/serialize/tuple.rs ++++ b/src/serialize/tuple.rs +@@ -41,7 +41,7 @@ impl Serialize for Tuple { + let len = ffi!(PyTuple_GET_SIZE(self.ptr)) as usize; + let mut seq = serializer.serialize_seq(Some(len)).unwrap(); + for i in 0..len { +- let item = ffi!(PyTuple_GET_ITEM(self.ptr, i as isize)); ++ let item = ffi!(PyTuple_GetItem(self.ptr, i as isize)); + let value = PyObject::new( + item, + self.opts, +diff --git a/src/serialize/writer.rs b/src/serialize/writer.rs +index a790bdd..35346d9 100644 +--- a/src/serialize/writer.rs ++++ b/src/serialize/writer.rs +@@ -27,7 +27,6 @@ impl BytesWriter { + pub fn finish(&mut self) -> NonNull { + unsafe { + std::ptr::write(self.buffer_ptr(), 0); +- (*self.bytes.cast::()).ob_size = self.len as Py_ssize_t; + self.resize(self.len); + NonNull::new_unchecked(self.bytes as *mut PyObject) + } +@@ -35,10 +34,14 @@ impl BytesWriter { + + fn buffer_ptr(&self) -> *mut u8 { + unsafe { +- std::mem::transmute::<*mut [c_char; 1], *mut u8>(std::ptr::addr_of_mut!( ++ #[cfg(not(GraalPy))] ++ return std::mem::transmute::<*mut [c_char; 1], *mut u8>(std::ptr::addr_of_mut!( + (*self.bytes).ob_sval + )) +- .add(self.len) ++ .add(self.len); ++ #[cfg(GraalPy)] ++ return std::mem::transmute::<*mut i8, *mut u8>(PyBytes_AsString(self.bytes.cast::())) ++ .add(self.len); + } + } + +diff --git a/src/unicode.rs b/src/unicode.rs +index 53aca09..552fa6c 100644 +--- a/src/unicode.rs ++++ b/src/unicode.rs +@@ -6,6 +6,7 @@ use pyo3::ffi::*; + + // see unicodeobject.h for documentation + ++#[cfg(not(GraalPy))] + pub fn unicode_from_str(buf: &str) -> *mut PyObject { + if buf.is_empty() { + ffi!(Py_INCREF(EMPTY_UNICODE)); +@@ -27,6 +28,13 @@ pub fn unicode_from_str(buf: &str) -> *mut PyObject { + } + } + ++#[cfg(GraalPy)] ++pub fn unicode_from_str(buf: &str) -> *mut PyObject { ++ unsafe { ++ PyUnicode_FromStringAndSize(buf.as_ptr() as *const i8, buf.len() as isize) ++ } ++} ++ + fn pyunicode_ascii(buf: &str) -> *mut PyObject { + unsafe { + let ptr = ffi!(PyUnicode_New(buf.len() as isize, 127)); +@@ -80,6 +88,7 @@ fn pyunicode_fourbyte(buf: &str, num_chars: usize) -> *mut PyObject { + + #[inline] + pub fn hash_str(op: *mut PyObject) -> Py_hash_t { ++ #[cfg(not(GraalPy))] + unsafe { + let data_ptr: *mut c_void = if (*op.cast::()).compact() == 1 + && (*op.cast::()).ascii() == 1 +@@ -92,7 +101,11 @@ pub fn hash_str(op: *mut PyObject) -> Py_hash_t { + (*(op as *mut PyASCIIObject)).length * ((*(op as *mut PyASCIIObject)).kind()) as isize; + let hash = _Py_HashBytes(data_ptr, num_bytes); + (*op.cast::()).hash = hash; +- hash ++ return hash; ++ } ++ #[cfg(GraalPy)] ++ unsafe { ++ return PyObject_Hash(op); + } + } + +@@ -109,19 +122,24 @@ pub fn unicode_to_str_via_ffi(op: *mut PyObject) -> Option<&'static str> { + + #[inline] + pub fn unicode_to_str(op: *mut PyObject) -> Option<&'static str> { ++ #[cfg(not(GraalPy))] + unsafe { + if unlikely!((*op.cast::()).compact() == 0) { +- unicode_to_str_via_ffi(op) ++ return unicode_to_str_via_ffi(op); + } else if (*op.cast::()).ascii() == 1 { + let ptr = op.cast::().offset(1) as *const u8; + let len = (*op.cast::()).length as usize; +- Some(str_from_slice!(ptr, len)) ++ return Some(str_from_slice!(ptr, len)); + } else if (*op.cast::()).utf8_length != 0 { + let ptr = (*op.cast::()).utf8 as *const u8; + let len = (*op.cast::()).utf8_length as usize; +- Some(str_from_slice!(ptr, len)) ++ return Some(str_from_slice!(ptr, len)); + } else { +- unicode_to_str_via_ffi(op) ++ return unicode_to_str_via_ffi(op); + } + } ++ #[cfg(GraalPy)] ++ unsafe { ++ return unicode_to_str_via_ffi(op); ++ } + } +diff --git a/src/util.rs b/src/util.rs +index 2bcc32d..89faf1a 100644 +--- a/src/util.rs ++++ b/src/util.rs +@@ -8,7 +8,7 @@ macro_rules! py_is { + + macro_rules! ob_type { + ($obj:expr) => { +- unsafe { (*($obj as *mut pyo3::ffi::PyObject)).ob_type } ++ unsafe { pyo3::ffi::Py_TYPE($obj as *mut pyo3::ffi::PyObject) } + }; + } + +-- +2.43.0 + diff --git a/graalpython/lib-graalpython/patches/pymupdf.patch b/graalpython/lib-graalpython/patches/pymupdf.patch new file mode 100644 index 0000000000..27869eccd6 --- /dev/null +++ b/graalpython/lib-graalpython/patches/pymupdf.patch @@ -0,0 +1,124 @@ +diff --git a/graalpy-config b/graalpy-config +new file mode 100755 +index 00000000..1f69f726 +--- /dev/null ++++ b/graalpy-config +@@ -0,0 +1,78 @@ ++#!/bin/sh ++ ++# Adapted from CPython but deferring to GraalPy ++ ++exit_with_usage () ++{ ++ echo "Usage: $0 --prefix|--exec-prefix|--includes|--libs|--cflags|--ldflags|--extension-suffix|--help|--abiflags|--configdir|--embed" ++ exit $1 ++} ++ ++if [ "$1" = "" ] ; then ++ exit_with_usage 1 ++fi ++ ++# Returns the actual prefix where this script was installed to. ++EXE=$(cd $(dirname "$0") && pwd -P) ++if which readlink >/dev/null 2>&1 ; then ++ if readlink -f "$RESULT" >/dev/null 2>&1; then ++ EXE=$(readlink -f "$RESULT") ++ fi ++fi ++EXE=$EXE/graalpy ++ ++if ! test -x "$EXE" ; then ++ EXE=graalpy ++fi ++ ++# Scan for --help or unknown argument. ++for ARG in $* ++do ++ case $ARG in ++ --help) ++ exit_with_usage 0 ++ ;; ++ --embed) ++ echo "graalpy-config does not print embedding flags" ++ exit 1 ++ ;; ++ --prefix|--exec-prefix|--includes|--libs|--cflags|--ldflags|--extension-suffix|--abiflags|--configdir) ++ ;; ++ *) ++ exit_with_usage 1 ++ ;; ++ esac ++done ++ ++for ARG in "$@" ++do ++ case "$ARG" in ++ --prefix) ++ $EXE -c "print(__import__('sysconfig').get_config_var('prefix'))" ++ ;; ++ --exec-prefix) ++ $EXE -c "print(__import__('sysconfig').get_config_var('exec_prefix'))" ++ ;; ++ --includes) ++ $EXE -c "from sysconfig import get_path; print('-I'+get_path('include'), '-I'+get_path('platinclude'))" ++ ;; ++ --cflags) ++ $EXE -c "import sysconfig as s; print('-I' + s.get_path('include'), '-I' + s.get_path('platinclude'), s.get_config_var('CFLAGS').replace('NDEBUG', 'DEBUG'), s.get_config_var('OPT').replace('NDEBUG', 'DEBUG'))" ++ ;; ++ --libs) ++ $EXE -c "import sysconfig as s; print('-L' + s.get_config_var('LIBDIR'))" ++ ;; ++ --ldflags) ++ $EXE -c "import sysconfig as s; print('-L' + s.get_config_var('LIBDIR'))" ++ ;; ++ --extension-suffix) ++ $EXE -c "import sysconfig as s; print(s.get_config_var('EXT_SUFFIX'))" ++ ;; ++ --abiflags) ++ $EXE -c "import sysconfig as s; print(s.get_config_var('ABIFLAGS'))" ++ ;; ++ --configdir) ++ echo "" ++ ;; ++esac ++done +diff --git a/setup.py b/setup.py +index 5fba2c97..3fe63b07 100755 +--- a/setup.py ++++ b/setup.py +@@ -1452,0 +1452,35 @@ ++if sys.implementation.name == "graalpy": ++ import os ++ import re ++ import subprocess ++ import shutil ++ import sysconfig ++ from pathlib import Path ++ ++ def build_wheel(wheel_directory, config_settings=None, metadata_directory=None): ++ wheel_directory = Path(wheel_directory).absolute() ++ sdir = Path(__file__).absolute().parent ++ python311 = shutil.which("python3.11") ++ if not python311: ++ raise RuntimeError("python3.11 must be available on the PATH for cross-compilation") ++ env = os.environ.copy() ++ env["PIPCL_PYTHON_CONFIG"] = str(sdir / "graalpy-config") ++ env["PYMUPDF_SETUP_PY_LIMITED_API"] = "1" ++ subprocess.run( ++ [python311, "setup.py", "bdist_wheel"], ++ env=env, ++ cwd=sdir, ++ check=True, ++ ) ++ wheels = list((sdir / 'dist').glob('*.whl')) ++ assert len(wheels) == 1, f"Expected 1 wheel, found {len(wheels)}" ++ wheel = wheels[0] ++ assert "-cp311-abi3" in wheel.name, f"Expected wheel to be for CPython 3.11 ABI 3, got {wheel.name}" ++ graalpy_ext_suffix = sysconfig.get_config_var("EXT_SUFFIX") ++ m = re.match(r"\.graalpy(\d+[^\-]*)-(\d+)", sysconfig.get_config_var("EXT_SUFFIX")) ++ gpver = m[1] ++ cpver = m[2] ++ graalpy_wheel_tag = f"graalpy{cpver}-graalpy{gpver}_{cpver}_native" ++ name = wheel.name.replace("cp311-abi3", graalpy_wheel_tag) ++ shutil.copyfile(wheel, wheel_directory / name) ++ return str(name) diff --git a/graalpython/lib-python/3/datetime.py b/graalpython/lib-python/3/datetime.py index e284a733ef..c564969464 100644 --- a/graalpython/lib-python/3/datetime.py +++ b/graalpython/lib-python/3/datetime.py @@ -2642,3 +2642,5 @@ def _name_from_offset(delta): # appropriate to maintain a single module level docstring and # remove the following line. from _datetime import __doc__ + +import _polyglot_datetime # GraalPy change: register interop behavior on datetime as soon as datetime is defined diff --git a/graalpython/org.graalvm.python.embedding.tools/src/org/graalvm/python/embedding/tools/vfs/VFSUtils.java b/graalpython/org.graalvm.python.embedding.tools/src/org/graalvm/python/embedding/tools/vfs/VFSUtils.java index 46637889eb..0a99df77eb 100644 --- a/graalpython/org.graalvm.python.embedding.tools/src/org/graalvm/python/embedding/tools/vfs/VFSUtils.java +++ b/graalpython/org.graalvm.python.embedding.tools/src/org/graalvm/python/embedding/tools/vfs/VFSUtils.java @@ -44,6 +44,7 @@ import java.io.FileWriter; import java.io.IOException; import java.nio.charset.StandardCharsets; +import java.nio.file.FileSystems; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; @@ -64,6 +65,107 @@ public final class VFSUtils { + /** + * Patterns which should be excluded by default, like .gitignore or SCM files. + *
    + *
  • Misc: **/*~, **/#*#, **/.#*, **/%*%, + * **/._*
  • + *
  • CVS: **/CVS, **/CVS/**, **/.cvsignore
  • + *
  • RCS: **/RCS, **/RCS/**
  • + *
  • SCCS: **/SCCS, **/SCCS/**
  • + *
  • VSSercer: **/vssver.scc
  • + *
  • MKS: **/project.pj
  • + *
  • SVN: **/.svn, **/.svn/**
  • + *
  • GNU: **/.arch-ids, **/.arch-ids/**
  • + *
  • Bazaar: **/.bzr, **/.bzr/**
  • + *
  • SurroundSCM: **/.MySCMServerInfo
  • + *
  • Mac: **/.DS_Store
  • + *
  • Serena Dimension: **/.metadata, **/.metadata/**
  • + *
  • Mercurial: **/.hg, **/.hg/**
  • + *
  • Git: **/.git, **/.git/**, **/.gitignore
  • + *
  • Bitkeeper: **/BitKeeper, **/BitKeeper/**, **/ChangeSet, + * **/ChangeSet/**
  • + *
  • Darcs: **/_darcs, **/_darcs/**, **/.darcsrepo, + * **/.darcsrepo/****/-darcs-backup*, **/.darcs-temp-mail + *
+ * + * + * The list is a copy of the one used in tools like the Maven JAR Plugin. @see DEFAULTEXCLUDES + */ + private static final String[] DEFAULT_EXCLUDES = { + // Miscellaneous typical temporary files + "**/*~", + "**/#*#", + "**/.#*", + "**/%*%", + "**/._*", + + // CVS + "**/CVS", + "**/CVS/**", + "**/.cvsignore", + + // RCS + "**/RCS", + "**/RCS/**", + + // SCCS + "**/SCCS", + "**/SCCS/**", + + // Visual SourceSafe + "**/vssver.scc", + + // MKS + "**/project.pj", + + // Subversion + "**/.svn", + "**/.svn/**", + + // Arch + "**/.arch-ids", + "**/.arch-ids/**", + + // Bazaar + "**/.bzr", + "**/.bzr/**", + + // SurroundSCM + "**/.MySCMServerInfo", + + // Mac + "**/.DS_Store", + + // Serena Dimensions Version 10 + "**/.metadata", + "**/.metadata/**", + + // Mercurial + "**/.hg", + "**/.hg/**", + + // git + "**/.git", + "**/.git/**", + "**/.gitignore", + + // BitKeeper + "**/BitKeeper", + "**/BitKeeper/**", + "**/ChangeSet", + "**/ChangeSet/**", + + // darcs + "**/_darcs", + "**/_darcs/**", + "**/.darcsrepo", + "**/.darcsrepo/**", + "**/-darcs-backup*", + "**/.darcs-temp-mail" + }; + public static final String VFS_ROOT = "org.graalvm.python.vfs"; public static final String VFS_VENV = "venv"; public static final String VFS_FILESLIST = "fileslist.txt"; @@ -152,23 +254,35 @@ public static void generateVFSFilesList(Path resourcesRoot, Path vfs, Set { - String entry = null; - if (Files.isDirectory(p)) { - String dirPath = makeDirPath(p.toAbsolutePath()); - entry = dirPath.substring(rootEndIdx); - } else if (Files.isRegularFile(p)) { - entry = p.toAbsolutePath().toString().substring(rootEndIdx); - } - if (entry != null) { - entry = normalizeResourcePath(entry); - if (!ret.add(entry) && duplicateHandler != null) { - duplicateHandler.accept(entry); + if (!shouldPathBeExcluded(p)) { + String entry = null; + if (Files.isDirectory(p)) { + String dirPath = makeDirPath(p.toAbsolutePath()); + entry = dirPath.substring(rootEndIdx); + } else if (Files.isRegularFile(p)) { + entry = p.toAbsolutePath().toString().substring(rootEndIdx); + } + if (entry != null) { + entry = normalizeResourcePath(entry); + if (!ret.add(entry) && duplicateHandler != null) { + duplicateHandler.accept(entry); + } } } }); } } + private static boolean shouldPathBeExcluded(Path path) { + for (String glob : DEFAULT_EXCLUDES) { + var matcher = FileSystems.getDefault().getPathMatcher("glob:" + glob); + if (matcher.matches(path)) { + return true; + } + } + return false; + } + private static String makeDirPath(Path p) { String ret = p.toString(); if (!ret.endsWith(File.separator)) { diff --git a/graalpython/org.graalvm.python.embedding/src/org/graalvm/python/embedding/GraalPyResources.java b/graalpython/org.graalvm.python.embedding/src/org/graalvm/python/embedding/GraalPyResources.java index 7efc01cd3a..fa26d06389 100644 --- a/graalpython/org.graalvm.python.embedding/src/org/graalvm/python/embedding/GraalPyResources.java +++ b/graalpython/org.graalvm.python.embedding/src/org/graalvm/python/embedding/GraalPyResources.java @@ -198,7 +198,12 @@ private GraalPyResources() { * location *
  • /org.graalvm.python.vfs/src - is set as the python sources location
  • * - *

    + *

    + * When the virtual filesystem is located in other than the default resource directory, + * {@code org.graalvm.python.vfs}, i.e., using Maven or Gradle option {@code resourceDirectory}, + * use {@link #contextBuilder(VirtualFileSystem)} and + * {@link VirtualFileSystem.Builder#resourceDirectory(String)} when building the + * {@link VirtualFileSystem}. * * @return a new {@link Context} instance * @since 24.2.0 @@ -233,6 +238,12 @@ public static Context createContext() { * } * } * + *

    + * When the virtual filesystem is located in other than the default resource directory, + * {@code org.graalvm.python.vfs}, i.e., using Maven or Gradle option {@code resourceDirectory}, + * use {@link #contextBuilder(VirtualFileSystem)} and + * {@link VirtualFileSystem.Builder#resourceDirectory(String)} when building the + * {@link VirtualFileSystem}. * * @see PythonOptions @@ -308,13 +319,14 @@ public static Context.Builder contextBuilder(VirtualFileSystem vfs) { /** * Creates a GraalPy context preconfigured with GraalPy and polyglot Context configuration - * options for use with resources located in a real filesystem. + * options for use with resources located in an external directory in real filesystem. *

    * Following resource paths are preconfigured: *

      - *
    • ${resourcesDirectory}/venv - is set as the python virtual environment + *
    • ${externalResourcesDirectory}/venv - is set as the python virtual + * environment location
    • + *
    • ${externalResourcesDirectory}/src - is set as the python sources * location
    • - *
    • ${resourcesDirectory}/src - is set as the python sources location
    • *
    *

    *

    @@ -343,19 +355,20 @@ public static Context.Builder contextBuilder(VirtualFileSystem vfs) { * *

    * - * @param resourcesDirectory the root directory with GraalPy specific embedding resources + * @param externalResourcesDirectory the root directory with GraalPy specific embedding + * resources * @return a new {@link org.graalvm.polyglot.Context.Builder} instance * @since 24.2.0 */ - public static Context.Builder contextBuilder(Path resourcesDirectory) { + public static Context.Builder contextBuilder(Path externalResourcesDirectory) { String execPath; if (VirtualFileSystemImpl.isWindows()) { - execPath = resourcesDirectory.resolve(VirtualFileSystemImpl.VFS_VENV).resolve("Scripts").resolve("python.exe").toAbsolutePath().toString(); + execPath = externalResourcesDirectory.resolve(VirtualFileSystemImpl.VFS_VENV).resolve("Scripts").resolve("python.exe").toAbsolutePath().toString(); } else { - execPath = resourcesDirectory.resolve(VirtualFileSystemImpl.VFS_VENV).resolve("bin").resolve("python").toAbsolutePath().toString(); + execPath = externalResourcesDirectory.resolve(VirtualFileSystemImpl.VFS_VENV).resolve("bin").resolve("python").toAbsolutePath().toString(); } - String srcPath = resourcesDirectory.resolve(VirtualFileSystemImpl.VFS_SRC).toAbsolutePath().toString(); + String srcPath = externalResourcesDirectory.resolve(VirtualFileSystemImpl.VFS_SRC).toAbsolutePath().toString(); return createContextBuilder(). // allow all IO access allowIO(IOAccess.ALL). @@ -437,8 +450,9 @@ public static Path getNativeExecutablePath() { * The structure of the created resource directory will stay the same like the embedded Python * resources structure: *
      - *
    • ${resourcesDirectory}/venv - the python virtual environment location
    • - *
    • ${resourcesDirectory}/src - the python sources location
    • + *
    • ${externalResourcesDirectory}/venv - the python virtual environment + * location
    • + *
    • ${externalResourcesDirectory}/src - the python sources location
    • *
    *

    *

    @@ -456,17 +470,17 @@ public static Path getNativeExecutablePath() { *

    * * @param vfs the {@link VirtualFileSystem} from which resources are to be extracted - * @param resourcesDirectory the target directory to extract the resources to + * @param externalResourcesDirectory the target directory to extract the resources to * @throws IOException if resources isn't a directory * @see #contextBuilder(Path) * @see VirtualFileSystem.Builder#resourceLoadingClass(Class) * * @since 24.2.0 */ - public static void extractVirtualFileSystemResources(VirtualFileSystem vfs, Path resourcesDirectory) throws IOException { - if (Files.exists(resourcesDirectory) && !Files.isDirectory(resourcesDirectory)) { - throw new IOException(String.format("%s has to be a directory", resourcesDirectory.toString())); + public static void extractVirtualFileSystemResources(VirtualFileSystem vfs, Path externalResourcesDirectory) throws IOException { + if (Files.exists(externalResourcesDirectory) && !Files.isDirectory(externalResourcesDirectory)) { + throw new IOException(String.format("%s has to be a directory", externalResourcesDirectory.toString())); } - vfs.impl.extractResources(resourcesDirectory); + vfs.impl.extractResources(externalResourcesDirectory); } } diff --git a/graalpython/org.graalvm.python.gradle.plugin/src/main/java/org/graalvm/python/GraalPyGradlePlugin.java b/graalpython/org.graalvm.python.gradle.plugin/src/main/java/org/graalvm/python/GraalPyGradlePlugin.java index f0ff56f0e1..0b964a9720 100644 --- a/graalpython/org.graalvm.python.gradle.plugin/src/main/java/org/graalvm/python/GraalPyGradlePlugin.java +++ b/graalpython/org.graalvm.python.gradle.plugin/src/main/java/org/graalvm/python/GraalPyGradlePlugin.java @@ -117,11 +117,11 @@ public void apply(Project project) { if (extension.getPythonResourcesDirectory().isPresent() && extension.getExternalDirectory().isPresent()) { throw new GradleException( - "Cannot set both 'externalDirectory' and 'resourcesDirectory' at the same time. " + + "Cannot set both 'externalDirectory' and 'resourceDirectory' at the same time. " + "New property 'externalDirectory' is a replacement for deprecated 'pythonResourcesDirectory'. " + "If you want to deploy the virtual environment into physical filesystem, use 'externalDirectory'. " + "The deployment of the external directory alongside the application is not handled by the GraalPy Maven plugin in such case." + - "If you wish to bundle the virtual filesystem in Java resources, use 'resourcesDirectory'. " + + "If you wish to bundle the virtual filesystem in Java resources, use 'resourceDirectory'. " + "For more details, please refer to https://www.graalvm.org/latest/reference-manual/python/Embedding-Build-Tools. "); } @@ -132,9 +132,9 @@ public void apply(Project project) { // Run the vfsFilesListTask conditionally only if 'externalDirectory' is not set if (!extension.getPythonResourcesDirectory().isPresent() && !extension.getExternalDirectory().isPresent()) { if (!extension.getResourceDirectory().isPresent()) { - proj.getLogger().info(String.format("Virtual filesystem is deployed to default resources directory '%s'. " + + proj.getLogger().warn(String.format("Virtual filesystem is deployed to default resources directory '%s'. " + "This can cause conflicts if used with other Java libraries that also deploy GraalPy virtual filesystem. " + - "Consider adding `resourcesDirectory = \"GRAALPY-VFS/${groupId}/${artifactId}\"` to your build.gradle script " + + "Consider adding `resourceDirectory = \"GRAALPY-VFS/${groupId}/${artifactId}\"` to your build.gradle script " + "(replace the placeholders with values specific to your project), " + "moving any existing sources from '%s' to '%s', and using VirtualFileSystem$Builder#resourceDirectory." + "For more details, please refer to https://www.graalvm.org/latest/reference-manual/python/Embedding-Build-Tools. ", @@ -192,7 +192,7 @@ private TaskProvider registerResourcesTask(Project project, Confi t.getLogger().warn("The GraalPy plugin pythonHome configuration setting was deprecated and has no effect anymore.\n" + "For execution in jvm mode, the python language home is always available.\n" + "When building a native executable using GraalVM Native Image, then the full python language home is by default embedded into the native executable.\n" + - "For more details, please refer to the documentation of GraalVM Native Image options IncludeLanguageResources and CopyLanguageResources documentation."); + "For more details, please refer to the documentation of GraalVM Native Image options IncludeLanguageResources and CopyLanguageResources."); } t.getPackages().set(extension.getPackages()); diff --git a/mx.graalpython/copyrights/overrides b/mx.graalpython/copyrights/overrides index 9b09b5c78f..1a30d74d25 100644 --- a/mx.graalpython/copyrights/overrides +++ b/mx.graalpython/copyrights/overrides @@ -617,7 +617,11 @@ graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/floats/FloatBuiltins.java,zippy.copyright graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/floats/PFloat.java,zippy.copyright graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/foreign/ForeignObjectBuiltins.java,zippy.copyright +graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/foreign/ForeignAbstractClassBuiltins.java,zippy.copyright graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/foreign/ForeignBooleanBuiltins.java,zippy.copyright +graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/foreign/ForeignExecutableBuiltins.java,zippy.copyright +graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/foreign/ForeignInstantiableBuiltins.java,zippy.copyright +graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/foreign/ForeignIterableBuiltins.java,zippy.copyright graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/foreign/ForeignNumberBuiltins.java,zippy.copyright graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/frame/FrameBuiltins.java,zippy.copyright graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/function/AbstractFunctionBuiltins.java,zippy.copyright diff --git a/mx.graalpython/mx_graalpython.py b/mx.graalpython/mx_graalpython.py index f86fdbf2a0..62542a46dd 100644 --- a/mx.graalpython/mx_graalpython.py +++ b/mx.graalpython/mx_graalpython.py @@ -170,6 +170,8 @@ def getArchivableResultsWithLib(self, *args, **kwargs): if os.path.isfile(os.path.join(os.path.abspath(p), "cl.exe")): mx.log("LIB and INCLUDE set, cl.exe on PATH, assuming this is a VS shell") os.environ["DISTUTILS_USE_SDK"] = "1" + if not os.environ.get("MSSdk"): + os.environ["MSSdk"] = os.environ.get("WindowsSdkDir", "unset") break else: mx.log("cl.exe not on PATH, not a VS shell") diff --git a/mx.graalpython/suite.py b/mx.graalpython/suite.py index 92ae8a88d7..d4269ffd74 100644 --- a/mx.graalpython/suite.py +++ b/mx.graalpython/suite.py @@ -9,7 +9,7 @@ "name": "graalpython", "versionConflictResolution": "latest", - "version": "25.0.0", + "version": "24.2.2", "graalpython:pythonVersion": "3.11.7", "release": False, "groupId": "org.graalvm.python", @@ -45,7 +45,7 @@ }, { "name": "sdk", - "version": "0f61c409358b6ecdb637d69410c8d3960b289e9c", + "version": "c9096be682f7aa67f5133fb098762e2152ff355f", "subdir": True, "urls": [ {"url": "https://github.com/oracle/graal", "kind": "git"}, @@ -53,7 +53,7 @@ }, { "name": "tools", - "version": "0f61c409358b6ecdb637d69410c8d3960b289e9c", + "version": "c9096be682f7aa67f5133fb098762e2152ff355f", "subdir": True, "urls": [ {"url": "https://github.com/oracle/graal", "kind": "git"}, @@ -61,7 +61,7 @@ }, { "name": "sulong", - "version": "0f61c409358b6ecdb637d69410c8d3960b289e9c", + "version": "c9096be682f7aa67f5133fb098762e2152ff355f", "subdir": True, "urls": [ {"url": "https://github.com/oracle/graal", "kind": "git"}, @@ -69,7 +69,7 @@ }, { "name": "regex", - "version": "0f61c409358b6ecdb637d69410c8d3960b289e9c", + "version": "c9096be682f7aa67f5133fb098762e2152ff355f", "subdir": True, "urls": [ {"url": "https://github.com/oracle/graal", "kind": "git"}, @@ -108,12 +108,12 @@ ], "digest": "sha512:16920fd41f398696c563417049472c0d81abb2d293ecb45bbbe97c12651669833e34eac238e2e4a6f8761ea58fb39806425d2741e88e8c3097fe2b5457ebf488", }, - "XZ-5.2.6": { + "XZ-5.6.2": { "urls": [ - "https://lafo.ssw.uni-linz.ac.at/pub/graal-external-deps/xz-5.2.6.tar.gz", + "https://lafo.ssw.uni-linz.ac.at/pub/graal-external-deps/xz-5.6.2.tar.gz", ], "packedResource": True, - "digest": "sha512:090958dd6c202c989746686094c86707ad4ae835026640080fc0a9d0fad699821b7d5cb3a67e6700661a0938818ba153662366f89ab8ec47e0bae4a3fe9b1961", + "digest": "sha512:c32c32c95e3541b906e0284e66a953ace677e0ce6af2084e7b122600047bf7542c1b0fabb5909b19ff79fba6def530be674df1c675b22a47a8d57f3f0b736a82", }, "BOUNCYCASTLE-PROVIDER": { "digest": "sha512:fb10c3c089921c8173ad285329f730e0e78de175d1b50b9bdd79c6a85a265af9b3331caa0c1ed57e5f47047319ce3b0f3bb5def0a3db9cccf2755cc95e145e52", @@ -636,10 +636,10 @@ "bin/", ], "cmakeConfig": { - "XZ_SRC": "", + "XZ_SRC": "", "XZ_VERSION_MAJOR": "5", - "XZ_VERSION_MINOR": "2", - "XZ_VERSION_PATCH": "6", + "XZ_VERSION_MINOR": "6", + "XZ_VERSION_PATCH": "2", }, "os_arch": { "windows": { @@ -654,7 +654,7 @@ }, }, "buildDependencies": [ - "XZ-5.2.6", + "XZ-5.6.2", ], }, diff --git a/mx.graalpython/verify_patches.py b/mx.graalpython/verify_patches.py index 1ebc371694..8aa4e84c10 100644 --- a/mx.graalpython/verify_patches.py +++ b/mx.graalpython/verify_patches.py @@ -1,4 +1,4 @@ -# Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # The Universal Permissive License (UPL), Version 1.0 @@ -45,6 +45,7 @@ # Approved license identifiers in SPDX "short identifier" format ALLOWED_LICENSES = { + 'UPL', # https://spdx.org/licenses/UPL-1.0.html 'MIT', # https://spdx.org/licenses/MIT.html 'BSD-3-Clause', # https://spdx.org/licenses/BSD-3-Clause.html 'BSD-2-Clause', # https://spdx.org/licenses/BSD-2-Clause.html diff --git a/scripts/wheelbuilder/build_wheels.py b/scripts/wheelbuilder/build_wheels.py index 605032e50d..b6a00c7cce 100644 --- a/scripts/wheelbuilder/build_wheels.py +++ b/scripts/wheelbuilder/build_wheels.py @@ -1,4 +1,4 @@ -# Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # The Universal Permissive License (UPL), Version 1.0 @@ -100,6 +100,10 @@ def create_venv(): subprocess.check_call([binary, "-m", "venv", "graalpy"]) print("Installing wheel with", pip, flush=True) subprocess.check_call([pip, "install", "wheel"]) + print("Installing paatch to provide patch.exe", flush=True) + p = subprocess.run([pip, "install", "paatch"]) + if p.returncode != 0: + print("Installing paatch failed, assuming a GNU patch compatible binary is on PATH", flush=True) return pip pFad - Phonifier reborn

    Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

    Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


    Alternative Proxies:

    Alternative Proxy

    pFad Proxy

    pFad v3 Proxy

    pFad v4 Proxy