Python

About

The Python module allows to execute Python source code. This can be standard Python as well as the classes included in the "c4d" and "maxon" module.

The module's API is defined in the python.framework as well as lib_py.h.

Classes and Functions

Example Code

// This example function executes the given Python code.
#include "maxon/vm.h"
#include "maxon/cpython.h"
#include "c4d_general.h"
#include "lib_py.h"
//----------------------------------------------------------------------------------------
// Executes the given Python code.
// @param[in] sourceCode The source code to execute.
// @param[in] doc The BaseDocument to set "doc" and "op". If no BaseDocument is set, "doc" and "op" will not be defined.
// @return OK on success.
//----------------------------------------------------------------------------------------
static maxon::Result<void> ExecutePythonScript(maxon::String& sourceCode, BaseDocument* doc)
{
// check code
if (sourceCode.IsEmpty())
return maxon::IllegalArgumentError(MAXON_SOURCE_LOCATION);
const maxon::VirtualMachineRef& vm = MAXON_CPYTHON27VM();
const maxon::VirtualMachineScopeRef scope = vm.CreateScope() iferr_return;
// init script
iferr (scope.Init("Python Script"_s, sourceCode, maxon::ERRORHANDLING::PRINT, nullptr))
{
const String errorMessage = "Error on Init()"_s;
return maxon::UnknownError(MAXON_SOURCE_LOCATION, errorMessage);
}
// only set "doc" and "op" if a BaseDocument is set.
// another option would be to set both "doc" and "op" to None
if (doc != nullptr)
{
// set "doc" and "op" variables
auto python = maxon::Cast<maxon::py::CPythonLibraryRef>(vm.GetLibraryRef());
maxon::py::CPythonGil gil(python);
// the new Python API from python.framework is compatible with the legacy Python API from lib_py.h.
// here we temporarily create an old PythonLibrary instance because it can create a PyObject
// from a BaseDocument and BaseObject
PythonLibrary pyLib;
auto* pyObjectDoc = pyLib.ReturnGeListNode(doc, false);
if (pyObjectDoc == nullptr)
return maxon::UnexpectedError(MAXON_SOURCE_LOCATION);
auto* pyDoc = reinterpret_cast<maxon::py::NativePyObject*>(pyObjectDoc);
scope.Add("doc"_s, maxon::Data(pyDoc)) iferr_return;
python.CPy_Decref(pyDoc);
auto* pyObjectOp = op ? pyLib.ReturnGeListNode(op, false) : pyLib.ReturnPyNone();
if (pyObjectOp == nullptr)
return maxon::UnexpectedError(MAXON_SOURCE_LOCATION);
auto* pyOp = reinterpret_cast<maxon::py::NativePyObject*>(pyObjectOp);
scope.Add("op"_s, maxon::Data(pyOp)) iferr_return;
python.CPy_Decref(pyOp);
}
// set __name__ = __main__
scope.Add("__name__"_s, maxon::Data("__main__"_s)) iferr_return;
// stop all current threads which are potentially modifying the current document,
// since the active script might modify the currently active document
// executes the script and returns when it got executed.
// info: if the script causes an unexpected infinite loop, Execute() does not return
// and there is no way to stop from the outside.
iferr (scope.Execute())
{
const String errorMessage = "Error on Execute()"_s;
return maxon::UnknownError(MAXON_SOURCE_LOCATION, errorMessage);
}
return maxon::OK;
}