diff --git a/.github/workflows/ccpp_windows.yml b/.github/workflows/ccpp_windows.yml index 6d160d83a0..169c61bae2 100644 --- a/.github/workflows/ccpp_windows.yml +++ b/.github/workflows/ccpp_windows.yml @@ -18,7 +18,7 @@ jobs: - uses: actions/setup-python@v5 with: - python-version: "3.13.2" + python-version: "3.14" - name: Install Inno-setup run: choco install InnoSetup diff --git a/CHANGELOG.md b/CHANGELOG.md index 344a03763e..1a5533ea99 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -34,6 +34,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - macOS Tahoe 26: CI setup and platform support. +- Python 3.14 support. + ### Changed - `jsondecode`: Significantly improved performance by integrating [simdjson](https://simdjson.org/), enabling faster and more efficient JSON parsing. diff --git a/modules/python_engine/src/cpp/PythonFileRunner.cpp b/modules/python_engine/src/cpp/PythonFileRunner.cpp index 7de1fc7fde..f72abdfbda 100644 --- a/modules/python_engine/src/cpp/PythonFileRunner.cpp +++ b/modules/python_engine/src/cpp/PythonFileRunner.cpp @@ -30,7 +30,7 @@ PythonFileRunner::runFile(const std::wstring& filename, const wstringVector& arg PyGILState_STATE gstate = NLSPyGILState_Ensure(); PyObject* obj = NLSPy_BuildValue("s", wstring_to_utf8(filename).c_str()); - FILE* file = NLS_Py_fopen_obj(obj, "r"); + FILE* file = NLS_Py_fopen(obj, "r"); NLSPy_DECREF(obj); if (file == NULL) { errorMessage = _W("Impossible to open file: ") + filename; diff --git a/modules/python_engine/src/cpp/PythonLibraryWrapper.cpp b/modules/python_engine/src/cpp/PythonLibraryWrapper.cpp index 71c3c3199f..cf512edfbe 100644 --- a/modules/python_engine/src/cpp/PythonLibraryWrapper.cpp +++ b/modules/python_engine/src/cpp/PythonLibraryWrapper.cpp @@ -27,6 +27,7 @@ PyObject* _Py_NoneStructPtr = nullptr; //============================================================================= static bool pythonLibraryLoaded = false; static Nelson::library_handle python3XX_handle = nullptr; +static std::string NLSPy_fopen_obj_symbol_name = "_Py_fopen_obj"; //============================================================================= static bool loadPythonSymbols(); @@ -108,7 +109,7 @@ using PROC_PyList_SetItem = int (*)(PyObject* ob1, Py_ssize_t sz, PyObject* ob2) using PROC_PyUnicode_DecodeFSDefault = PyObject* (*)(const char* s); using PROC_PyRun_SimpleFileExFlags = int (*)(FILE* fp, const char* filename, int closeit, PyCompilerFlags* flags); -using PROC_Py_fopen_obj = FILE* (*)(PyObject* path, const char* mode); +using PROC_Py_fopen = FILE* (*)(PyObject* path, const char* mode); using PROC_PyDict_Copy = PyObject* (*)(PyObject* mp); using PROC_PyDict_Clear = void (*)(PyObject* mp); using PROC_PyDict_Update = int (*)(PyObject* mp, PyObject* other); @@ -245,7 +246,15 @@ loadPythonSymbols() LOAD_PYTHON_SYMBOL(PyList_SetItem); LOAD_PYTHON_SYMBOL(PyUnicode_DecodeFSDefault); LOAD_PYTHON_SYMBOL(PyRun_SimpleFileExFlags); - LOAD_PYTHON_SYMBOL(_Py_fopen_obj); + //============================================================================= + // Python 3.14 and later: _Py_fopen + pythonSymbols[NLSPy_fopen_obj_symbol_name] = reinterpret_cast( + Nelson::get_function(python3XX_handle, NLSPy_fopen_obj_symbol_name)); + if (!pythonSymbols[NLSPy_fopen_obj_symbol_name]) { + NLSPy_fopen_obj_symbol_name = "Py_fopen"; + LOAD_PYTHON_SYMBOL(Py_fopen); + } + //============================================================================= LOAD_PYTHON_SYMBOL(PyDict_Copy); LOAD_PYTHON_SYMBOL(PyDict_Clear); LOAD_PYTHON_SYMBOL(PyDict_Update); @@ -788,9 +797,9 @@ NLSPyRun_SimpleFileExFlags(FILE* fp, const char* filename, int closeit, PyCompil } //============================================================================= FILE* -NLS_Py_fopen_obj(PyObject* path, const char* mode) +NLS_Py_fopen(PyObject* path, const char* mode) { - return reinterpret_cast(pythonSymbols["_Py_fopen_obj"])(path, mode); + return reinterpret_cast(pythonSymbols[NLSPy_fopen_obj_symbol_name])(path, mode); } //============================================================================= PyObject* diff --git a/modules/python_engine/src/cpp/PythonLibraryWrapper.hpp b/modules/python_engine/src/cpp/PythonLibraryWrapper.hpp index 9a952ac531..279567459f 100644 --- a/modules/python_engine/src/cpp/PythonLibraryWrapper.hpp +++ b/modules/python_engine/src/cpp/PythonLibraryWrapper.hpp @@ -275,7 +275,7 @@ int NLSPyRun_SimpleFileExFlags(FILE* fp, const char* filename, int closeit, PyCompilerFlags* flags); //============================================================================= FILE* -NLS_Py_fopen_obj(PyObject* path, const char* mode); +NLS_Py_fopen(PyObject* path, const char* mode); //============================================================================= PyObject* NLSPyDict_Copy(PyObject* mp);