diff options
author | nkozlovskiy <nmk@ydb.tech> | 2023-09-29 12:24:06 +0300 |
---|---|---|
committer | nkozlovskiy <nmk@ydb.tech> | 2023-09-29 12:41:34 +0300 |
commit | e0e3e1717e3d33762ce61950504f9637a6e669ed (patch) | |
tree | bca3ff6939b10ed60c3d5c12439963a1146b9711 /library/python/runtime_py3/main/main.c | |
parent | 38f2c5852db84c7b4d83adfcb009eb61541d1ccd (diff) | |
download | ydb-e0e3e1717e3d33762ce61950504f9637a6e669ed.tar.gz |
add ydb deps
Diffstat (limited to 'library/python/runtime_py3/main/main.c')
-rw-r--r-- | library/python/runtime_py3/main/main.c | 209 |
1 files changed, 209 insertions, 0 deletions
diff --git a/library/python/runtime_py3/main/main.c b/library/python/runtime_py3/main/main.c new file mode 100644 index 0000000000..bf80678d26 --- /dev/null +++ b/library/python/runtime_py3/main/main.c @@ -0,0 +1,209 @@ +#include <Python.h> +#include <contrib/tools/python3/src/Include/internal/pycore_runtime.h> // _PyRuntime_Initialize() + +#include <stdlib.h> +#include <string.h> +#include <locale.h> + +char* GetPyMain(); +int IsYaIdeVenv(); + +static const char* env_entry_point = "Y_PYTHON_ENTRY_POINT"; +static const char* main_entry_point = ":main"; +static const char* env_bytes_warning = "Y_PYTHON_BYTES_WARNING"; + +#ifdef _MSC_VER +extern char** environ; + +void unsetenv(const char* name) { + const int n = strlen(name); + char** dst = environ; + for (char** src = environ; *src; src++) + if (strncmp(*src, name, n) || (*src)[n] != '=') + *dst++ = *src; + *dst = NULL; +} +#endif + +static int RunModule(const char* modname) +{ + PyObject *module, *runpy, *runmodule, *runargs, *result; + runpy = PyImport_ImportModule("runpy"); + if (runpy == NULL) { + fprintf(stderr, "Could not import runpy module\n"); + PyErr_Print(); + return -1; + } + runmodule = PyObject_GetAttrString(runpy, "_run_module_as_main"); + if (runmodule == NULL) { + fprintf(stderr, "Could not access runpy._run_module_as_main\n"); + PyErr_Print(); + Py_DECREF(runpy); + return -1; + } + module = PyUnicode_FromString(modname); + if (module == NULL) { + fprintf(stderr, "Could not convert module name to unicode\n"); + PyErr_Print(); + Py_DECREF(runpy); + Py_DECREF(runmodule); + return -1; + } + runargs = Py_BuildValue("(Oi)", module, 0); + if (runargs == NULL) { + fprintf(stderr, + "Could not create arguments for runpy._run_module_as_main\n"); + PyErr_Print(); + Py_DECREF(runpy); + Py_DECREF(runmodule); + Py_DECREF(module); + return -1; + } + result = PyObject_Call(runmodule, runargs, NULL); + if (result == NULL) { + PyErr_Print(); + } + Py_DECREF(runpy); + Py_DECREF(runmodule); + Py_DECREF(module); + Py_DECREF(runargs); + if (result == NULL) { + return -1; + } + Py_DECREF(result); + return 0; +} + +static int pymain(int argc, char** argv) { + if (IsYaIdeVenv()) { + return Py_BytesMain(argc, argv); + } + + PyStatus status = _PyRuntime_Initialize(); + if (PyStatus_Exception(status)) { + Py_ExitStatusException(status); + } + + int sts = 1; + char* entry_point_copy = NULL; + + PyConfig config; + PyConfig_InitPythonConfig(&config); + // Suppress errors from getpath.c + config.pathconfig_warnings = 0; + // Disable parsing command line arguments + config.parse_argv = 0; + + const char* bytes_warning = getenv(env_bytes_warning); + if (bytes_warning) { + config.bytes_warning = atoi(bytes_warning); + } + + if (argc > 0 && argv) { + status = PyConfig_SetBytesString(&config, &config.program_name, argv[0]); + if (PyStatus_Exception(status)) { + goto error; + } + + status = PyConfig_SetBytesArgv(&config, argc, argv); + if (PyStatus_Exception(status)) { + goto error; + } + } + + const char* entry_point = getenv(env_entry_point); + if (entry_point) { + entry_point_copy = strdup(entry_point); + if (!entry_point_copy) { + fprintf(stderr, "out of memory\n"); + goto error; + } + } else { + entry_point_copy = GetPyMain(); + } + + if (entry_point_copy == NULL) { + fprintf(stderr, "No entry point, did you forget PY_MAIN?\n"); + goto error; + } + + if (entry_point_copy && !strcmp(entry_point_copy, main_entry_point)) { + unsetenv(env_entry_point); + // Py_InitializeFromConfig freeze environ, so we need to finish all manipulations with environ before + } + + status = Py_InitializeFromConfig(&config); + + PyConfig_Clear(&config); + if (PyStatus_Exception(status)) { + Py_ExitStatusException(status); + } + + if (entry_point_copy && !strcmp(entry_point_copy, main_entry_point)) { + sts = Py_BytesMain(argc, argv); + free(entry_point_copy); + return sts; + } + + { + PyObject* module = PyImport_ImportModule("library.python.runtime_py3.entry_points"); + if (module == NULL) { + PyErr_Print(); + } else { + PyObject* res = PyObject_CallMethod(module, "run_constructors", NULL); + if (res == NULL) { + PyErr_Print(); + } else { + Py_DECREF(res); + } + Py_DECREF(module); + } + } + + const char* module_name = entry_point_copy; + const char* func_name = NULL; + + char* colon = strchr(entry_point_copy, ':'); + if (colon != NULL) { + colon[0] = '\0'; + func_name = colon + 1; + } + if (module_name[0] == '\0') { + module_name = "library.python.runtime_py3.entry_points"; + } + + if (!func_name) { + sts = RunModule(module_name); + } else { + PyObject* module = PyImport_ImportModule(module_name); + + if (module == NULL) { + PyErr_Print(); + } else { + PyObject* value = PyObject_CallMethod(module, func_name, NULL); + + if (value == NULL) { + PyErr_Print(); + } else { + Py_DECREF(value); + sts = 0; + } + + Py_DECREF(module); + } + } + + if (Py_FinalizeEx() < 0) { + sts = 120; + } + +error: + free(entry_point_copy); + return sts; +} + +int (*mainptr)(int argc, char** argv) = pymain; + +int main(int argc, char** argv) { + return mainptr(argc, argv); +} |