26 #include <boost/filesystem/operations.hpp>
28 #include <opencog/util/Config.h>
29 #include <opencog/util/exceptions.h>
30 #include <opencog/util/Logger.h>
31 #include <opencog/util/misc.h>
32 #include <opencog/util/oc_assert.h>
39 #include "opencog/atomspace_api.h"
44 using namespace opencog;
58 #define NO_COMPILER_FLAGS NULL
85 "/usr/local/share/opencog/python",
86 "/usr/share/opencog/python",
93 PROJECT_BINARY_DIR
"/opencog/cython",
94 PROJECT_SOURCE_DIR
"/opencog/python",
95 PROJECT_SOURCE_DIR
"/tests/cython",
129 static const char* paths[
134 char* cwd = getcwd(NULL, 0);
135 bool in_project =
false;
136 if (0 == strncmp(PROJECT_SOURCE_DIR, cwd, strlen(PROJECT_SOURCE_DIR)) or
137 0 == strncmp(PROJECT_BINARY_DIR, cwd, strlen(PROJECT_BINARY_DIR)))
145 for (
unsigned i=0; i < nproj-1; i++) {
152 for (
unsigned i=0; i < ndefp-1; i++) {
175 PyObject* pySysPath = PySys_GetObject((
char*)
"path");
178 for (
int i = 0; config_paths[i] != NULL; ++i)
181 stat(config_paths[i], &finfo);
183 if (S_ISDIR(finfo.st_mode))
185 PyObject* pyModulePath = PyBytes_FromString(config_paths[i]);
186 PyList_Append(pySysPath, pyModulePath);
187 Py_DECREF(pyModulePath);
192 if (config().has(
"PYTHON_EXTENSION_DIRS"))
194 std::vector<string> pythonpaths;
196 tokenize(config()[
"PYTHON_EXTENSION_DIRS"],
197 std::back_inserter(pythonpaths),
", ");
199 for (std::vector<string>::const_iterator it = pythonpaths.begin();
200 it != pythonpaths.end(); ++it)
203 stat(it->c_str(), &finfo);
204 if (S_ISDIR(finfo.st_mode))
206 PyObject* pyModulePath = PyBytes_FromString(it->c_str());
207 PyList_Append(pySysPath, pyModulePath);
208 Py_DECREF(pyModulePath);
211 "Could not find custom python extension directory: %s ",
212 __FUNCTION__, it->c_str() );
220 if (logger().isDebugEnabled())
222 logger().debug(
"Python 'sys.path' after OpenCog config adds is:");
223 Py_ssize_t pathSize = PyList_Size(pySysPath);
224 for (
int i = 0; i < pathSize; i++)
226 PyObject* pySysPathLine = PyList_GetItem(pySysPath, i);
227 const char* sysPathCString = PyString_AsString(pySysPathLine);
228 logger().debug(
" %2d > %s", i, sysPathCString);
236 import_opencog__atomspace();
244 if (NULL == py_atomspace) {
246 logger().warn(
"PythonEval::%s Failed to load the "
247 "opencog.atomspace module", __FUNCTION__);
254 if (NULL != get_path_as_string)
255 logger().info(
"Python 'sys.path' after OpenCog config adds is: " +
256 get_path_as_string());
260 return (NULL != py_atomspace);
267 PyGILState_STATE gstate = PyGILState_UNLOCKED;
269 logger().debug(
"[global_python_initialize] Start");
274 throw opencog::RuntimeException(TRACE_INFO,
275 "Python initializer global_python_init() called twice.");
282 if (Py_IsInitialized()) {
287 gstate = PyGILState_Ensure();
295 PyEval_InitThreads();
300 static const char *argv0 =
"cogserver";
301 PySys_SetArgv(1, (
char **) &argv0);
304 logger().debug(
"[global_python_initialize] Adding OpenCog sys.path "
322 PyGILState_Release(gstate);
324 PyEval_ReleaseLock();
326 logger().debug(
"[global_python_initialize] Finish");
331 logger().debug(
"[global_python_finalize] Start");
340 logger().debug(
"[global_python_finalize] Finish");
347 throw (RuntimeException(TRACE_INFO,
348 "Can't create more than one PythonEval singleton instance!"));
368 if (config().has(
"PYTHON_PRELOAD_FUNCTIONS")) {
369 string preloadDirectory = config()[
"PYTHON_PRELOAD_FUNCTIONS"];
376 logger().info(
"PythonEval::%s destructor", __FUNCTION__);
379 PyGILState_STATE gstate;
380 gstate = PyGILState_Ensure();
393 PyGILState_Release(gstate);
425 #define CHECK_SINGLETON
426 #ifdef CHECK_SINGLETON
430 throw RuntimeException(TRACE_INFO,
431 "Trying to re-initialize python interpreter with different\n"
432 "AtomSpace ptr! Current ptr=%p New ptr=%p\n",
454 PyGILState_STATE gstate;
455 gstate = PyGILState_Ensure();
471 PyObject* pyRootDictionary = PyModule_GetDict(
_pyRootModule);
473 PyDict_SetItemString(pyRootDictionary,
"ATOMSPACE", pyAtomSpaceObject);
474 Py_DECREF(pyAtomSpaceObject);
485 PyGILState_Release(gstate);
487 logger().info(
"PythonEval::%s Finished initialising python evaluator.",
497 if (NULL == py_atomspace) {
498 logger().error(
"PythonEval::%s Failed to load the"
499 "opencog.atomspace module", __FUNCTION__);
512 PyObject * pyAtomSpace = py_atomspace(atomspace);
515 if (PyErr_Occurred())
518 logger().error(
"PythonEval::%s Failed to get atomspace "
519 "wrapped with python object", __FUNCTION__);
527 if (!PyDict_Check(obj))
530 PyObject *pyKey, *pyKeys;
533 pyKeys = PyDict_Keys(obj);
534 for (
int i = 0; i < PyList_Size(pyKeys); i++) {
537 pyKey = PyList_GetItem(pyKeys, i);
538 char* c_name = PyBytes_AsString(pyKey);
539 printf(
"%s\n", c_name);
555 std::string& errorMessage)
557 PyObject *pyErrorType, *pyError, *pyTraceback, *pyErrorString;
558 std::stringstream errorStringStream;
561 PyErr_Fetch(&pyErrorType, &pyError, &pyTraceback);
564 errorStringStream <<
"Python error ";
566 errorStringStream <<
"in " << function_name;
568 pyErrorString = PyObject_Str(pyError);
569 char* pythonErrorString = PyString_AsString(pyErrorString);
570 if (pythonErrorString) {
571 errorStringStream <<
": " << pythonErrorString <<
".";
573 errorStringStream <<
": Undefined Error";
578 Py_DECREF(pyErrorType);
580 Py_DECREF(pyErrorString);
582 Py_DECREF(pyTraceback);
585 errorStringStream <<
": Undefined Error";
587 errorMessage = errorStringStream.str();
600 PyObject *pyRootDictionary, *pyResult;
602 pyResult = PyRun_StringFlags(command, Py_file_input, pyRootDictionary,
611 PyObject* pyFunctionCode;
612 PyObject* pyArgumentCount;
616 pyFunctionCode = PyObject_GetAttrString(pyFunction,
"func_code");
617 if (pyFunctionCode) {
618 pyArgumentCount = PyObject_GetAttrString(pyFunctionCode,
"co_argcount");
619 if (pyArgumentCount) {
620 argumentCount = PyInt_AsLong(pyArgumentCount);
622 Py_DECREF(pyFunctionCode);
630 Py_DECREF(pyFunctionCode);
631 Py_DECREF(pyArgumentCount);
633 return argumentCount;
642 std::string& functionName)
645 std::string moduleName;
648 int index = moduleFunction.find_first_of(
'.');
651 functionName = moduleFunction;
652 moduleName =
"__main__";
654 moduleName = moduleFunction.substr(0, index);
656 functionName = moduleFunction.substr(index+1);
671 std::lock_guard<std::recursive_mutex> lck(
_mtx);
673 PyObject *pyError, *pyModule, *pyUserFunc, *pyReturnValue = NULL;
675 std::string functionName;
676 std::string errorString;
679 PyGILState_STATE gstate;
680 gstate = PyGILState_Ensure();
687 PyGILState_Release(gstate);
688 logger().error(
"Python module for '%s' not found!", moduleFunction.c_str());
689 throw (RuntimeException(TRACE_INFO,
"Python module for '%s' not found!",
690 moduleFunction.c_str()));
694 pyDict = PyModule_GetDict(pyModule);
695 pyUserFunc = PyDict_GetItemString(pyDict, functionName.c_str());
702 PyGILState_Release(gstate);
703 logger().error(
"Python function '%s' not found!", moduleFunction.c_str());
704 throw (RuntimeException(TRACE_INFO,
"Python function '%s' not found!",
705 moduleFunction.c_str()));
710 Py_INCREF(pyUserFunc);
713 if (!PyCallable_Check(pyUserFunc)) {
714 Py_DECREF(pyUserFunc);
715 PyGILState_Release(gstate);
716 logger().error(
"Python user function '%s' not callable!",
717 moduleFunction.c_str());
718 throw (RuntimeException(TRACE_INFO,
719 "Python function '%s' not callable!", moduleFunction.c_str()));
725 PyGILState_Release(gstate);
726 throw (RuntimeException(TRACE_INFO,
727 "Python function '%s' error missing 'func_code'!",
728 moduleFunction.c_str()));
732 if (arguments->
getType() != LIST_LINK) {
733 PyGILState_Release(gstate);
734 throw RuntimeException(TRACE_INFO,
735 "Expecting arguments to be a ListLink!");
738 int actualArgumentCount = linkArguments->getArity();
741 if (expectedArgumentCount != actualArgumentCount) {
742 PyGILState_Release(gstate);
743 throw (RuntimeException(TRACE_INFO,
744 "Python function '%s' which expects '%d arguments,"
745 " called with %d arguments!", moduleFunction.c_str(),
746 expectedArgumentCount, actualArgumentCount
752 PyObject* pyArguments = PyTuple_New(actualArgumentCount);
754 const HandleSeq& argumentHandles = linkArguments->getOutgoingSet();
756 for (HandleSeq::const_iterator it = argumentHandles.begin();
757 it != argumentHandles.end(); ++it) {
760 PyObject* pyAtom = py_atom(it->value(), pyAtomSpace);
761 PyTuple_SetItem(pyArguments, tupleItem, pyAtom);
768 Py_DECREF(pyAtomSpace);
771 pyReturnValue = PyObject_CallObject(pyUserFunc, pyArguments);
777 Py_DECREF(pyUserFunc);
778 Py_DECREF(pyArguments);
781 pyError = PyErr_Occurred();
786 PyGILState_Release(gstate);
787 throw RuntimeException(TRACE_INFO, errorString.c_str());
794 PyGILState_Release(gstate);
796 return pyReturnValue;
801 std::lock_guard<std::recursive_mutex> lck(
_mtx);
813 PyGILState_STATE gstate;
814 gstate = PyGILState_Ensure();
817 PyObject* pyAtomUUID = PyObject_CallMethod(pyReturnAtom, (
char*)
"handle_uuid",
821 PyObject* pyError = PyErr_Occurred();
822 if (pyError || !pyAtomUUID) {
823 PyGILState_Release(gstate);
824 throw RuntimeException(TRACE_INFO,
825 "Python function '%s' did not return Atom!", func.c_str());
829 uuid =
static_cast<unsigned long>(PyLong_AsLong(pyAtomUUID));
832 Py_DECREF(pyReturnAtom);
833 Py_DECREF(pyAtomUUID);
836 PyGILState_Release(gstate);
840 throw RuntimeException(TRACE_INFO,
841 "Python function '%s' did not return Atom!", func.c_str());
853 std::lock_guard<std::recursive_mutex> lck(
_mtx);
860 if (NULL == pyTruthValue) {
861 throw RuntimeException(TRACE_INFO,
862 "Python function '%s' did not return TruthValue!",
867 PyGILState_STATE gstate = PyGILState_Ensure();
871 PyObject *pyTruthValuePtrPtr = PyObject_CallMethod(pyTruthValue,
872 (
char*)
"truth_value_ptr_object", NULL);
875 PyObject *pyError = PyErr_Occurred();
876 if (pyError or !pyTruthValuePtrPtr) {
877 PyGILState_Release(gstate);
878 throw RuntimeException(TRACE_INFO,
879 "Python function '%s' did not return TruthValue!",
886 (PyLong_AsVoidPtr(pyTruthValuePtrPtr));
894 Py_DECREF(pyTruthValuePtrPtr);
895 Py_DECREF(pyTruthValue);
898 PyGILState_Release(gstate);
904 std::lock_guard<std::recursive_mutex> lck(
_mtx);
906 PyObject* pyError = NULL;
907 PyObject *pyCatcher = NULL;
908 PyObject *pyOutput = NULL;
910 bool errorRunningScript;
911 std::string errorString;
914 PyGILState_STATE gstate;
915 gstate = PyGILState_Ensure();
917 PyRun_SimpleString(
"_opencog_output_stream = StringIO.StringIO()\n"
918 "_python_output_stream = sys.stdout\n"
919 "sys.stdout = _opencog_output_stream\n"
920 "sys.stderr = _opencog_output_stream\n");
929 pyError = PyErr_Occurred();
934 errorRunningScript =
false;
936 "_opencog_output_stream");
937 pyOutput = PyObject_CallMethod(pyCatcher, (
char*)
"getvalue", NULL);
938 result = PyBytes_AsString(pyOutput);
941 Py_DECREF(pyCatcher);
946 errorRunningScript =
true;
954 PyRun_SimpleString(
"sys.stdout = _python_output_stream\n"
955 "sys.stderr = _python_output_stream\n"
956 "_opencog_output_stream.close()\n");
959 PyGILState_Release(gstate);
963 if (errorRunningScript) {
964 logger().warn() << errorString;
966 throw (RuntimeException(TRACE_INFO, errorString.c_str()));
975 PyObject* pyPathString = PyBytes_FromString(path.c_str());
986 Py_DECREF(pyPathString);
993 PyObject* pyFromList)
1005 string fileName, moduleName;
1008 fileName = file.filename().c_str();
1009 moduleName = fileName.substr(0, fileName.length()-3);
1011 logger().info(
" importing Python module: " + moduleName);
1014 PyObject* pyModule = PyImport_ImportModuleLevel((
char*) moduleName.c_str(),
1020 PyObject* pyModuleDictionary = PyModule_GetDict(pyModule);
1024 PyDict_SetItemString(pyModuleDictionary,
"ATOMSPACE",
1029 Py_DECREF(pyAtomSpaceObject);
1034 Py_INCREF(pyModule);
1037 PyModule_AddObject(
_pyRootModule, moduleName.c_str(), pyModule);
1045 if(PyErr_Occurred())
1047 logger().warn() <<
"Couldn't import '" << moduleName <<
"' module";
1058 vector<boost::filesystem::path> files;
1059 vector<boost::filesystem::path> pyFiles;
1062 copy(boost::filesystem::directory_iterator(directory),
1063 boost::filesystem::directory_iterator(), back_inserter(files));
1064 for(vector<boost::filesystem::path>::const_iterator it(files.begin());
1065 it != files.end(); ++it) {
1066 if(it->extension() == boost::filesystem::path(
".py"))
1067 pyFiles.push_back(*it);
1083 PyObject* pyFromList = PyList_New(0);
1086 for(vector<boost::filesystem::path>::const_iterator it(pyFiles.begin());
1087 it != pyFiles.end(); ++it)
1091 Py_DECREF(pyFromList);
1116 PyObject* pyFromList = PyList_New(0);
1118 Py_DECREF(pyFromList);
1127 if (
'/' == pathString[0]) {
1132 bool did_load =
false;
1134 for (
int i = 0; config_paths[i] != NULL; ++i) {
1135 std::string abspath = config_paths[i];
1137 abspath += pathString;
1142 stat(abspath.c_str(), &finfo);
1143 if (S_ISDIR(finfo.st_mode) or S_ISREG(finfo.st_mode)) {
1150 Logger::Level btl = logger().getBackTraceLevel();
1151 logger().setBackTraceLevel(Logger::Level::NONE);
1152 logger().error() <<
"Failed to load python module \'" << pathString
1153 <<
"\', searched directories:";
1154 for (
int i = 0; config_paths[i] != NULL; ++i) {
1155 logger().error() <<
"Directory: " << config_paths[i];
1157 logger().setBackTraceLevel(btl);
1163 logger().info(
"Adding Python module (or directory): " + pathString);
1166 PyGILState_STATE gstate;
1167 gstate = PyGILState_Ensure();
1170 stat(pathString.c_str(), &finfo);
1172 if (S_ISDIR(finfo.st_mode))
1174 else if (S_ISREG(finfo.st_mode))
1177 logger().error() <<
"Python module path \'" << pathString
1178 <<
"\' can't be found";
1181 PyGILState_Release(gstate);
1196 std::string part = partial_expr.substr(0,
1197 partial_expr.find_last_not_of(
" \t\n\r") + 1);
1199 size_t cmnt = part.find(
'#');
1200 if (std::string::npos != cmnt)
1201 part = part.substr(0, cmnt);
1206 size_t part_size = part.size();
1207 if (0 == part_size and 0 < partial_expr.size())
goto wait_for_more;
1209 if (0 < part_size) c = part[0];
1211 logger().debug(
"[PythonEval] get line:\n%s\n", partial_expr.c_str());
1216 size_t open = std::count(part.begin(), part.end(),
'(');
1217 size_t clos = std::count(part.begin(), part.end(),
')');
1219 if (0 < _paren_count)
goto wait_for_more;
1225 if (
' ' == c or
'\t' == c)
goto wait_for_more;
1229 if (0 < part_size and part.find_last_of(
":\\") + 1 == part_size)
1234 logger().info(
"[PythonEval] eval_expr:\n%s",
_input_line.c_str());
1246 catch (
const RuntimeException &e)
static bool already_initialized
const int ABSOLUTE_IMPORTS_ONLY
static const char ** get_module_paths()
int argument_count(PyObject *pyFunction)
std::vector< Handle > HandleSeq
a list of handles
const int MISSING_FUNC_CODE
virtual std::string poll_result()
void add_modules_from_abspath(std::string path)
std::shared_ptr< TruthValue > TruthValuePtr
std::string apply_script(const std::string &script)
void build_python_error_message(const char *function_name, std::string &errorMessage)
PyObject * module_for_function(const std::string &moduleFunction, std::string &functionName)
void add_modules_from_path(std::string path)
#define NO_COMPILER_FLAGS
std::shared_ptr< Link > LinkPtr
void print_dictionary(PyObject *)
void global_python_finalize()
void add_module_file(const boost::filesystem::path &file)
static PythonEval & instance(AtomSpace *atomspace=NULL)
static void delete_singleton_instance()
void initialize_python_objects_and_imports(void)
void add_to_sys_path(std::string path)
static bool try_to_load_modules(const char **config_paths)
unsigned long UUID
UUID == Universally Unique Identifier.
void import_module(const boost::filesystem::path &file, PyObject *pyFromList)
Handle apply(AtomSpace *, const std::string &func, Handle varargs)
const int SIMPLE_STRING_SUCCESS
static const char * DEFAULT_PYTHON_MODULE_PATHS[]
std::map< std::string, PyObject * > _modules
const char * NO_FUNCTION_NAME
static LinkPtr LinkCast(const Handle &h)
static void create_singleton_instance(AtomSpace *)
PyObject * atomspace_py_object(AtomSpace *)
void add_module_directory(const boost::filesystem::path &directory)
static const char * PROJECT_PYTHON_MODULE_PATHS[]
virtual void eval_expr(const std::string &)
const int SIMPLE_STRING_FAILURE
void global_python_initialize()
TruthValuePtr apply_tv(AtomSpace *, const std::string &func, Handle varargs)
static bool initialized_outside_opencog
static PythonEval * singletonInstance
static std::recursive_mutex _mtx
PyObject * call_user_function(const std::string &func, Handle varargs)
void execute_string(const char *command)
const int NO_SIGNAL_HANDLERS