Python: Added support for Python 3.11.

Python 3.8 added a new Python initialisation configuration API[0].

Python 3.11 marked the old API as deprecated resulting in the following
compiler warnings which we treat as errors, failing the build

src/python/nxt_python.c: In function ‘nxt_python_start’:
src/python/nxt_python.c:130:13: error: ‘Py_SetProgramName’ is deprecated [-Werror=deprecated-declarations]
  130 |             Py_SetProgramName(nxt_py_home);
      |             ^~~~~~~~~~~~~~~~~
In file included from /opt/python-3.11/include/python3.11/Python.h:94,
                 from src/python/nxt_python.c:7:
/opt/python-3.11/include/python3.11/pylifecycle.h:37:38: note: declared here
   37 | Py_DEPRECATED(3.11) PyAPI_FUNC(void) Py_SetProgramName(const wchar_t *);
      |                                      ^~~~~~~~~~~~~~~~~
src/python/nxt_python.c:134:13: error: ‘Py_SetPythonHome’ is deprecated [-Werror=deprecated-declarations]
  134 |             Py_SetPythonHome(nxt_py_home);
      |             ^~~~~~~~~~~~~~~~
/opt/python-3.11/include/python3.11/pylifecycle.h:40:38: note: declared here
   40 | Py_DEPRECATED(3.11) PyAPI_FUNC(void) Py_SetPythonHome(const wchar_t *);
      |                                      ^~~~~~~~~~~~~~~~
cc1: all warnings being treated as errors

We actually have a few config scenarios: Python < 3, Python >= 3.0 < 3.8
and for Python 3 we have two configs where we select one based on
virtual environment setup.

Factor out the Python 3 config initialisation into its own function.  We
actually create two functions, one for Python 3.8+ and one for older
Python 3.  We pick the right function to use at build time.

The new API also has error checking (where the old API doesn't) which we
handle.

[0]: https://peps.python.org/pep-0587/

Closes: <https://github.com/nginx/unit/issues/710>
[ Andrew: Expanded upon patch from @sandeep-gh ]
Signed-off-by: Andrew Clayton <a.clayton@nginx.com>
This commit is contained in:
Andrew Clayton
2022-11-17 21:56:58 +00:00
parent dfededabdc
commit 491d0f700f
2 changed files with 73 additions and 2 deletions

View File

@@ -43,6 +43,12 @@ prefer system crypto policy, instead of hardcoding a default.
</para> </para>
</change> </change>
<change type="feature">
<para>
compatibility with Python 3.11.
</para>
</change>
<change type="feature"> <change type="feature">
<para> <para>
njs support with the basic syntax of JS template literals. njs support with the basic syntax of JS template literals.

View File

@@ -22,6 +22,10 @@ typedef struct {
} nxt_py_thread_info_t; } nxt_py_thread_info_t;
#if PY_MAJOR_VERSION == 3
static nxt_int_t nxt_python3_init_config(nxt_int_t pep405);
#endif
static nxt_int_t nxt_python_start(nxt_task_t *task, static nxt_int_t nxt_python_start(nxt_task_t *task,
nxt_process_data_t *data); nxt_process_data_t *data);
static nxt_int_t nxt_python_set_target(nxt_task_t *task, static nxt_int_t nxt_python_set_target(nxt_task_t *task,
@@ -64,6 +68,63 @@ static nxt_py_thread_info_t *nxt_py_threads;
static nxt_python_proto_t nxt_py_proto; static nxt_python_proto_t nxt_py_proto;
#if PY_VERSION_HEX >= NXT_PYTHON_VER(3, 8)
static nxt_int_t
nxt_python3_init_config(nxt_int_t pep405)
{
PyStatus status;
PyConfig config;
PyConfig_InitIsolatedConfig(&config);
if (pep405) {
status = PyConfig_SetString(&config, &config.program_name,
nxt_py_home);
if (PyStatus_Exception(status)) {
goto pyinit_exception;
}
} else {
status =PyConfig_SetString(&config, &config.home, nxt_py_home);
if (PyStatus_Exception(status)) {
goto pyinit_exception;
}
}
status = Py_InitializeFromConfig(&config);
if (PyStatus_Exception(status)) {
goto pyinit_exception;
}
PyConfig_Clear(&config);
return NXT_OK;
pyinit_exception:
PyConfig_Clear(&config);
return NXT_ERROR;
}
#elif PY_MAJOR_VERSION == 3
static nxt_int_t
nxt_python3_init_config(nxt_int_t pep405)
{
if (pep405) {
Py_SetProgramName(nxt_py_home);
} else {
Py_SetPythonHome(nxt_py_home);
}
return NXT_OK;
}
#endif
static nxt_int_t static nxt_int_t
nxt_python_start(nxt_task_t *task, nxt_process_data_t *data) nxt_python_start(nxt_task_t *task, nxt_process_data_t *data)
{ {
@@ -127,11 +188,15 @@ nxt_python_start(nxt_task_t *task, nxt_process_data_t *data)
if (pep405) { if (pep405) {
mbstowcs(nxt_py_home, c->home, len); mbstowcs(nxt_py_home, c->home, len);
mbstowcs(nxt_py_home + len, bin_python, sizeof(bin_python)); mbstowcs(nxt_py_home + len, bin_python, sizeof(bin_python));
Py_SetProgramName(nxt_py_home);
} else { } else {
mbstowcs(nxt_py_home, c->home, len + 1); mbstowcs(nxt_py_home, c->home, len + 1);
Py_SetPythonHome(nxt_py_home); }
ret = nxt_python3_init_config(pep405);
if (nxt_slow_path(ret == NXT_ERROR)) {
nxt_alert(task, "Failed to initialise config");
return NXT_ERROR;
} }
#else #else