aboutsummaryrefslogtreecommitdiffstats
path: root/library/python/runtime_py3/main/main.c
diff options
context:
space:
mode:
authornkozlovskiy <nmk@ydb.tech>2023-09-29 12:24:06 +0300
committernkozlovskiy <nmk@ydb.tech>2023-09-29 12:41:34 +0300
commite0e3e1717e3d33762ce61950504f9637a6e669ed (patch)
treebca3ff6939b10ed60c3d5c12439963a1146b9711 /library/python/runtime_py3/main/main.c
parent38f2c5852db84c7b4d83adfcb009eb61541d1ccd (diff)
downloadydb-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.c209
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);
+}