[ Web Proxy ]
URL:
Viewing: https://raw.githubusercontent.com/knowrob/knowrob/dev/include/knowrob/plugins/PluginModule.h [Back]  [Original]

/*
 * This file is part of KnowRob, please consult
 * https://github.com/knowrob/knowrob for license details.
 */

#ifndef KNOWROB_PLUGIN_MODULE_H_
#define KNOWROB_PLUGIN_MODULE_H_

#include 
#include 
#include 
#include 
#include 
#include "knowrob/plugins/PluginFactory.h"
#include "knowrob/integration/python/utils.h"
#include "knowrob/Logger.h"

namespace knowrob {
	/**
	 * A plugin module is a plugin factory that creates plugin objects
	 * that are implemented in Python code.
	 */
	template
	class PluginModule : public PluginFactory {
	public:
		/**
		 * @param modulePath the name or path of the Python module.
		 * @param pluginType the name of the plugin type.
		 */
		PluginModule(std::string_view modulePath, std::string_view pluginType)
				: modulePath_(knowrob::py::resolveModulePath(modulePath)),
				  pluginType_(pluginType) {
		}

		/**
		 * Cannot be copy-assigned.
		 */
		PluginModule(const PluginModule &) = delete;

		~PluginModule() override {
			unloadModule();
		}

		/**
		 * @return true if the module was loaded successfully.
		 */
		bool isLoaded() {
			return knowrob::py::call_with_gil([&] {
				return pyPluginType_ && !pyPluginType_.is_none();
			});
		}

		/**
		 * Unload the module from the Python interpreter.
		 */
		void unloadModule() {
			knowrob::py::gil_lock lock;
			pyModule_ = {};
			pyPluginType_ = {};
		}

		/**
		 * Try loading the module from filesystem.
		 * @return true on success.
		 */
		bool loadModule() {
			// try to make sure that the module can be imported.
			// the modules can be addressed either via an absolute path,
			// or via a relative path in the KnowRob project.
			std::filesystem::path modulePath(modulePath_);
			if (!std::filesystem::exists(modulePath)) {
				KB_ERROR("Module '{}' does not exist.", modulePath_.c_str());
				return false;
			}

			knowrob::py::gil_lock lock;
			try {
				// Make sure module can be imported by possibly extending the sys.path
				// of the Python interpreter.
				auto importString = knowrob::py::addToSysPath(modulePath);
				pyModule_ = boost::python::import(importString.c_str());
				if (pyModule_.is_none()) {
					KB_ERROR("Failed to import module '{}'.", modulePath_.c_str());
					return false;
				}
				pyPluginType_ = pyModule_.attr(pluginType_.c_str());
			} catch (const boost::python::error_already_set &) {
				throw PythonError();
			}
			return isLoaded();
		}

		// Override PluginFactory
		std::shared_ptr create(std::string_view pluginID) override {
			knowrob::py::gil_lock lock;
			try {
				boost::python::object pyReasoner = pyPluginType_();
				// extract the reasoner in appropriate type
				boost::python::extract extracted(pyReasoner);
				if (extracted.check()) {
					return std::make_shared(pluginID, PluginLanguage::PYTHON, extracted());
				} else {
					KB_ERROR("Failed to extract typed plugin from module '{}'", modulePath_.c_str());
				}
			} catch (const boost::python::error_already_set &) {
				throw PythonError();
			}
			KB_ERROR("Failed to create plugin from module '{}'", modulePath_.c_str());
			return {};
		}

		// Override PluginFactory
		std::string_view name() const override { return pluginType_; };

	protected:
		const std::string modulePath_;
		const std::string pluginType_;
		boost::python::object pyModule_;
		boost::python::object pyPluginType_;
	};
}

#endif //KNOWROB_REASONER_MODULE_H_

Web Proxy Viewer  |  New URL  |  Original Page