|
| 1 | +//===------------ pythonexec.hpp - Python/C++ Interoperability ------------===// |
| 2 | +// |
| 3 | +// Licensed under the Apache License v2.0. |
| 4 | +// SPDX-License-Identifier: Apache-2.0 |
| 5 | +// |
| 6 | +// The full license is in the file LICENSE, distributed with this software. |
| 7 | +// |
| 8 | +//===----------------------------------------------------------------------===// |
| 9 | +// |
| 10 | +// This file defines the Python/C++ interoperability in which two cells within |
| 11 | +// the same notebook can be in a either language. |
| 12 | +// |
| 13 | +//===----------------------------------------------------------------------===// |
| 14 | + |
| 15 | +#include "Python.h" |
| 16 | + |
| 17 | +#include "pythonexec.hpp" |
| 18 | +#include "../xparser.hpp" |
| 19 | + |
| 20 | +#include <cstddef> |
| 21 | +#include <fstream> |
| 22 | +#include <iostream> |
| 23 | +#include <sstream> |
| 24 | +#include <string> |
| 25 | +#include <vector> |
| 26 | + |
| 27 | +namespace xcpp { |
| 28 | +static PyObject *gMainDict = 0; |
| 29 | + |
| 30 | +void pythonexec::startup() { |
| 31 | + static bool isInitialized = false; |
| 32 | + if (isInitialized) |
| 33 | + return; |
| 34 | + |
| 35 | + Py_Initialize(); |
| 36 | + |
| 37 | + PyRun_SimpleString("import sys\nprint(sys.path)"); |
| 38 | + |
| 39 | + // Import cppyy module |
| 40 | + PyObject* cppyyModule = PyImport_ImportModule("cppyy"); |
| 41 | + if (!cppyyModule) { |
| 42 | + PyErr_Print(); |
| 43 | + Py_Finalize(); |
| 44 | + return; // Handle import error as needed |
| 45 | + } |
| 46 | + |
| 47 | + PyObject* mainModule = PyImport_AddModule("__main__"); |
| 48 | + PyObject_SetAttrString(mainModule, "cppyy", cppyyModule); |
| 49 | + Py_XDECREF(cppyyModule); |
| 50 | + isInitialized = true; |
| 51 | + // gMainDict = PyModule_GetDict(mainModule); |
| 52 | + // Py_INCREF(gMainDict); |
| 53 | + // if (!gMainDict) |
| 54 | + // printf("Could not add module __main__"); |
| 55 | + |
| 56 | + |
| 57 | + // // Retrieve the dictionary of cppyy module |
| 58 | + // PyObject* cppyyDict = PyModule_GetDict(cppyyModule); |
| 59 | + // Py_DECREF(cppyyModule); |
| 60 | + // if (!cppyyDict) { |
| 61 | + // PyErr_Print(); |
| 62 | + // Py_Finalize(); |
| 63 | + // return; // Handle retrieval error as needed |
| 64 | + // } |
| 65 | + |
| 66 | + // // Add cppyyDict to gMainDict (if needed for further usage) |
| 67 | + // PyDict_Update(gMainDict, cppyyDict); |
| 68 | + |
| 69 | + // Py_DECREF(cppyyDict); |
| 70 | + // PyRun_SimpleString("import cppyy"); |
| 71 | +} |
| 72 | + |
| 73 | +argparser pythonexec::get_options() { |
| 74 | + argparser argpars{"python", "Start executing Python Cell"}; |
| 75 | + return argpars; |
| 76 | +} |
| 77 | + |
| 78 | +void pythonexec::execute(std::string &line, std::string &cell) { |
| 79 | + // std::istringstream iss(line); |
| 80 | + // std::vector<std::string> results((std::istream_iterator<std::string>(iss)), |
| 81 | + // std::istream_iterator<std::string>()); |
| 82 | + startup(); |
| 83 | + |
| 84 | +// auto argpars = get_options(); |
| 85 | +// argpars.parse(line); |
| 86 | + |
| 87 | + std::string code; |
| 88 | + |
| 89 | + code += cell; |
| 90 | + if (trim(code).empty()) |
| 91 | + return; |
| 92 | + // PyRun_SimpleString( |
| 93 | + // "globals_copy_lists = " |
| 94 | + // "globals().copy()\nfirst_dict_ints={k:globals_copy_lists[k] for k in " |
| 95 | + // "set(globals_copy_lists) if type(globals_copy_lists[k]) == " |
| 96 | + // "int}\nfirst_dict_lists={k:globals_copy_lists[k] for k in " |
| 97 | + // "set(globals_copy_lists) if type(globals_copy_lists[k]) == list}"); |
| 98 | + |
| 99 | + // PyRun_SimpleString("tmp = globals().copy()\nvars = [f'int {k} = {v};' for |
| 100 | + // k,v in tmp.items() if type(v) == int and not k.startswith('_') and k!='tmp' |
| 101 | + // and k!='In' and k!='Out' and k!='sys' and not hasattr(v, |
| 102 | + // '__call__')]\nprint(vars)"); PyRun_SimpleString("b = |
| 103 | + // globals().copy()\nnew_ints = ' '.join([f'int {k} = {b[k]};' for k in set(b) |
| 104 | + // - set(first_dict) if type(b[k]) == int])\nprint('new_ints: ', new_ints)"); |
| 105 | + |
| 106 | + Cpp::BeginStdStreamCapture(Cpp::kStdErr); |
| 107 | + Cpp::BeginStdStreamCapture(Cpp::kStdOut); |
| 108 | + |
| 109 | + PyRun_SimpleString(code.c_str()); |
| 110 | + |
| 111 | + std::cout << Cpp::EndStdStreamCapture(); |
| 112 | + std::cerr << Cpp::EndStdStreamCapture(); |
| 113 | + |
| 114 | + // PyObject* objectsRepresentation = PyObject_Repr(gMainDict); |
| 115 | + // const char* s = PyUnicode_AsUTF8(objectsRepresentation); |
| 116 | + // printf("REPR of global dict: %s\n", s); |
| 117 | +} |
| 118 | + |
| 119 | +void pythonexec::update_python_dict_var(const char *name, int value) { |
| 120 | + if (!gMainDict) |
| 121 | + startup(); |
| 122 | + PyObject *s; |
| 123 | + s = PyLong_FromLong(value); |
| 124 | + PyDict_SetItemString(gMainDict, name, s); |
| 125 | + Py_DECREF(s); |
| 126 | +} |
| 127 | + |
| 128 | +void pythonexec::update_python_dict_var_vector(const char *name, |
| 129 | + std::vector<int> &data) { |
| 130 | + if (!gMainDict) |
| 131 | + startup(); |
| 132 | + PyObject *listObj = PyList_New(data.size()); |
| 133 | + if (!listObj) |
| 134 | + throw std::logic_error("Unable to allocate memory for Python list"); |
| 135 | + for (unsigned int i = 0; i < data.size(); i++) { |
| 136 | + PyObject *num = PyLong_FromLong((int)data[i]); |
| 137 | + if (!num) { |
| 138 | + Py_DECREF(listObj); |
| 139 | + throw std::logic_error("Unable to allocate memory for Python list"); |
| 140 | + } |
| 141 | + PyList_SET_ITEM(listObj, i, num); |
| 142 | + } |
| 143 | + PyDict_SetItemString(gMainDict, name, listObj); |
| 144 | +} |
| 145 | + |
| 146 | +// check python globals |
| 147 | +void pythonexec::check_python_globals() { |
| 148 | + if (!Py_IsInitialized()) |
| 149 | + return; |
| 150 | + // execute the command |
| 151 | + PyRun_SimpleString("print(globals())"); |
| 152 | +} |
| 153 | + |
| 154 | +// execute a python comand |
| 155 | +void pythonexec::exec_python_simple_command(const std::string code) { |
| 156 | + if (!Py_IsInitialized()) |
| 157 | + return; |
| 158 | + // execute the command |
| 159 | + PyRun_SimpleString(code.c_str()); |
| 160 | +} |
| 161 | + |
| 162 | +std::string pythonexec::transfer_python_ints_utility() { |
| 163 | + if (!Py_IsInitialized()) |
| 164 | + return " "; |
| 165 | + // transfer ints utility |
| 166 | + PyRun_SimpleString( |
| 167 | + "def getNewInts():\n glob_ints_utils = globals().copy()\n new_ints " |
| 168 | + "= ' '.join([f'int {k} = {glob_ints_utils[k]};' for k in " |
| 169 | + "set(glob_ints_utils) - set(first_dict_ints) if type(glob_ints_utils[k]) " |
| 170 | + "== int])\n return new_ints"); |
| 171 | + PyObject *ints_result = |
| 172 | + PyObject_CallFunction(PyDict_GetItemString(gMainDict, "getNewInts"), 0); |
| 173 | + if (!ints_result) { |
| 174 | + printf("Could not retrieve Python integers!\n"); |
| 175 | + return " "; |
| 176 | + } else { |
| 177 | + std::string newPythonInts = PyUnicode_AsUTF8(ints_result); |
| 178 | + // printf("new ints %s\n", PyUnicode_AsUTF8(ints_result)); |
| 179 | + Py_DECREF(ints_result); |
| 180 | + return newPythonInts; |
| 181 | + } |
| 182 | +} |
| 183 | + |
| 184 | +std::string pythonexec::transfer_python_lists_utility() { |
| 185 | + if (!Py_IsInitialized()) |
| 186 | + return " "; |
| 187 | + // transfer lists utility |
| 188 | + PyRun_SimpleString("def getNewLists():\n l = globals().copy()\n " |
| 189 | + "new_lists = ' '.join([f'int {k}() = {l[k]};' for k in " |
| 190 | + "set(l) - set(first_dict_lists) if type(l[k]) == " |
| 191 | + "list]).replace('[','{').replace(']','}').replace('(','[')" |
| 192 | + ".replace(')',']')\n return new_lists"); |
| 193 | + PyObject *lists_result = |
| 194 | + PyObject_CallFunction(PyDict_GetItemString(gMainDict, "getNewLists"), 0); |
| 195 | + if (!lists_result) { |
| 196 | + printf("Could not retrieve Python lists!\n"); |
| 197 | + return " "; |
| 198 | + } else { |
| 199 | + std::string newPythonLists = PyUnicode_AsUTF8(lists_result); |
| 200 | + Py_DECREF(lists_result); |
| 201 | + return newPythonLists; |
| 202 | + } |
| 203 | +} |
| 204 | + |
| 205 | +bool pythonexec::python_check_for_initialisation() { |
| 206 | + if (!Py_IsInitialized()) |
| 207 | + return false; |
| 208 | + return true; |
| 209 | +} |
| 210 | +} // namespace xcpp |
0 commit comments