knowrob  2.1.0
A Knowledge Base System for Cognition-enabled Robots
PluginModule.h
Go to the documentation of this file.
1 /*
2  * This file is part of KnowRob, please consult
3  * https://github.com/knowrob/knowrob for license details.
4  */
5 
6 #ifndef KNOWROB_PLUGIN_MODULE_H_
7 #define KNOWROB_PLUGIN_MODULE_H_
8 
9 #include <string>
10 #include <memory>
11 #include <set>
12 #include <filesystem>
13 #include <boost/python.hpp>
14 #include "knowrob/plugins/PluginFactory.h"
15 #include "knowrob/integration/python/utils.h"
16 #include "knowrob/Logger.h"
17 
18 namespace knowrob {
23  template<class T>
24  class PluginModule : public PluginFactory<T> {
25  public:
30  PluginModule(std::string_view modulePath, std::string_view pluginType)
31  : modulePath_(knowrob::py::resolveModulePath(modulePath)),
32  pluginType_(pluginType) {
33  }
34 
38  PluginModule(const PluginModule &) = delete;
39 
40  ~PluginModule() override {
41  unloadModule();
42  }
43 
47  bool isLoaded() {
48  return knowrob::py::call_with_gil<bool>([&] {
49  return pyPluginType_ && !pyPluginType_.is_none();
50  });
51  }
52 
56  void unloadModule() {
58  pyModule_ = {};
59  pyPluginType_ = {};
60  }
61 
66  bool loadModule() {
67  // try to make sure that the module can be imported.
68  // the modules can be addressed either via an absolute path,
69  // or via a relative path in the KnowRob project.
70  std::filesystem::path modulePath(modulePath_);
71  if (!std::filesystem::exists(modulePath)) {
72  KB_ERROR("Module '{}' does not exist.", modulePath_.c_str());
73  return false;
74  }
75 
77  try {
78  // Make sure module can be imported by possibly extending the sys.path
79  // of the Python interpreter.
80  auto importString = knowrob::py::addToSysPath(modulePath);
81  pyModule_ = boost::python::import(importString.c_str());
82  if (pyModule_.is_none()) {
83  KB_ERROR("Failed to import module '{}'.", modulePath_.c_str());
84  return false;
85  }
86  pyPluginType_ = pyModule_.attr(pluginType_.c_str());
87  } catch (const boost::python::error_already_set &) {
88  throw PythonError();
89  }
90  return isLoaded();
91  }
92 
93  // Override PluginFactory
94  std::shared_ptr<NamedPlugin<T>> create(std::string_view pluginID) override {
96  try {
97  boost::python::object pyReasoner = pyPluginType_();
98  // extract the reasoner in appropriate type
99  boost::python::extract<std::shared_ptr<T>> extracted(pyReasoner);
100  if (extracted.check()) {
101  return std::make_shared<NamedPlugin<T>>(pluginID, PluginLanguage::PYTHON, extracted());
102  } else {
103  KB_ERROR("Failed to extract typed plugin from module '{}'", modulePath_.c_str());
104  }
105  } catch (const boost::python::error_already_set &) {
106  throw PythonError();
107  }
108  KB_ERROR("Failed to create plugin from module '{}'", modulePath_.c_str());
109  return {};
110  }
111 
112  // Override PluginFactory
113  std::string_view name() const override { return pluginType_; };
114 
115  protected:
116  const std::string modulePath_;
117  const std::string pluginType_;
118  boost::python::object pyModule_;
119  boost::python::object pyPluginType_;
120  };
121 }
122 
123 #endif //KNOWROB_REASONER_MODULE_H_
#define KB_ERROR
Definition: Logger.h:28
PluginModule(std::string_view modulePath, std::string_view pluginType)
Definition: PluginModule.h:30
PluginModule(const PluginModule &)=delete
boost::python::object pyModule_
Definition: PluginModule.h:118
std::shared_ptr< NamedPlugin< T > > create(std::string_view pluginID) override
Definition: PluginModule.h:94
const std::string pluginType_
Definition: PluginModule.h:117
const std::string modulePath_
Definition: PluginModule.h:113
boost::python::object pyPluginType_
Definition: PluginModule.h:119
~PluginModule() override
Definition: PluginModule.h:40
std::string_view name() const override
Definition: PluginModule.h:113
TermRule & string()
Definition: terms.cpp:63
std::string addToSysPath(const std::filesystem::path &modulePath)
Definition: utils.cpp:25
std::string resolveModulePath(std::string_view modulePath)
Definition: utils.cpp:13