extern "C" { #include "pyinit.h" } #include #include // -------------------------------------------------- // See the CPython embedding docs for more info: // https://docs.python.org/3/extending/embedding.html // -------------------------------------------------- #define WASM_PYTHON_FUNC_DIR "/pyfuncs/" #define NATIVE_PYTHON_FUNC_DIR "/usr/local/code/faasm/func/" #define DEFAULT_MAIN_FUNC "faasm_main" /** * Returns the relevant Python entry function. We need to invoke different * functions depending on which Faasm function index we're dealing with. */ const char* getPythonFunctionName() { char* entryFunc = faasmGetPythonEntry(); if (strlen(entryFunc) == 0) { return DEFAULT_MAIN_FUNC; } else { return entryFunc; } } /** * Returns the working dir we need to be in to import the Python module * for the required function. */ const char* getPythonWorkingDir(const char* user, const char* funcName) { auto workingDir = new char[60]; #ifdef __wasm__ sprintf(workingDir, "%s%s/%s", WASM_PYTHON_FUNC_DIR, user, funcName); #else sprintf(workingDir, "%s%s", NATIVE_PYTHON_FUNC_DIR, user); #endif return workingDir; } /** * Returns the name of the python module to execute. If executing in wasm this * will be different to when executing natively. */ const char* getPythonModuleName(const char* funcName) { #ifdef __wasm__ return "function"; #else return funcName; #endif } /** * Initialise CPython using a Faasm zygote to avoid doing so repeatedly */ FAASM_ZYGOTE() { Py_InitializeEx(0); // 21/12/2022 - Numpy support is broken // setUpPyNumpy(); unsigned int preloadLibs = getConfFlag("PYTHON_PRELOAD"); if (preloadLibs == 1) { /* 21/12/2022 - Numpy support is broken PyObject* numpyModule = PyImport_ImportModule("numpy"); if (!numpyModule) { printf("\nFailed to import numpy\n"); } else { printf("\nPython initialised numpy\n"); } */ // Import pyfaasm PyObject* pyfaasmModule = PyImport_ImportModule("pyfaasm.core"); if (!pyfaasmModule) { printf("\nFailed to import pyfaasm\n"); } else { printf("\nPython initialised pyfaasm\n"); } } return 0; } int main(int argc, char* argv[]) { // With this line uncommented, this file can be run as a normal executable // for testing setEmulatedMessageFromJson(R"({"user": "python", "function": // "py_func", "py_user": "python", "py_func": "lang_test", "py_entry": // "faasm_main"})"); // Get details of the Faasm call char* user = faasmGetPythonUser(); char* funcName = faasmGetPythonFunc(); const char* pythonFuncName = getPythonFunctionName(); // Variables related to importing/ executing the Python module const char* workingDir = getPythonWorkingDir(user, funcName); const char* pythonModuleName = getPythonModuleName(funcName); // Add the directory to the Python path PyObject* sys = PyImport_ImportModule("sys"); PyObject* path = PyObject_GetAttrString(sys, "path"); PyList_Append(path, PyUnicode_FromString(workingDir)); // Final return value for this main function int outerReturnValue = 0; // Import the module PyObject* module = PyImport_ImportModule(pythonModuleName); if (module != nullptr) { PyObject* func = PyObject_GetAttrString(module, pythonFuncName); if (func && PyCallable_Check(func)) { // Note that chained functions take their input data as argument PyObject* pythonFuncArgs; PyObject* inputBytes; if (strcmp(pythonFuncName, DEFAULT_MAIN_FUNC) == 0) { // Default main function takes no argument pythonFuncArgs = nullptr; } else { // Get input for Faasm function long inputSize = faasmGetInputSize(); if (inputSize == 0) { // No input from Faasm inputBytes = PyBytes_FromStringAndSize("", 0); } else { // Read input into buffer auto rawInput = new uint8_t[inputSize]; faasmGetInput(rawInput, inputSize); // Convert to python bytes object and build arguments tuple inputBytes = PyBytes_FromStringAndSize((char*)rawInput, inputSize); } pythonFuncArgs = PyTuple_New(1); PyTuple_SetItem(pythonFuncArgs, 0, inputBytes); } // Execute the function PyObject* returnValue = PyObject_CallObject(func, pythonFuncArgs); // Clear up args if (pythonFuncArgs != nullptr) { Py_DECREF(pythonFuncArgs); Py_DECREF(inputBytes); } // Check return value and clear up if (returnValue != nullptr) { long r = PyLong_AsLong(returnValue); if (r == 0) { printf("Python call succeeded\n"); } else { printf("Python call failed (return value = %ld)\n", r); } outerReturnValue = (int)r; Py_DECREF(returnValue); } else { // Have to tidy up here as about to return PyErr_Print(); printf("Python call failed\n"); Py_DECREF(func); Py_DECREF(module); return 1; } } else { if (PyErr_Occurred()) { PyErr_Print(); } printf("Cannot find function \"%s\"\n", pythonFuncName); return 1; } Py_XDECREF(func); Py_DECREF(module); } else { PyErr_Print(); fprintf(stderr, "Failed to load \"%s\"\n", funcName); return 1; } Py_FinalizeEx(); return outerReturnValue; }