JeVois  1.18
JeVois Smart Embedded Machine Vision Toolkit
Share this page:
PythonWrapper.C
Go to the documentation of this file.
1 // ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2 //
3 // JeVois Smart Embedded Machine Vision Toolkit - Copyright (C) 2022 by Laurent Itti, the University of Southern
4 // California (USC), and iLab at USC. See http://iLab.usc.edu and http://jevois.org for information about this project.
5 //
6 // This file is part of the JeVois Smart Embedded Machine Vision Toolkit. This program is free software; you can
7 // redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software
8 // Foundation, version 2. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
9 // without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
10 // License for more details. You should have received a copy of the GNU General Public License along with this program;
11 // if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
12 //
13 // Contact information: Laurent Itti - 3641 Watt Way, HNB-07A - Los Angeles, CA 90089-2520 - USA.
14 // Tel: +1 213 740 3527 - itti@pollux.usc.edu - http://iLab.usc.edu - http://jevois.org
15 // ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
16 /*! \file */
17 
20 #include <jevois/Core/Engine.H>
21 
22 // ####################################################################################################
24  itsConstructionError("Not operational yet because pythonload() was not called")
25 { }
26 
27 // ####################################################################################################
28 jevois::PythonWrapper::PythonWrapper(std::string const & path)
29 {
30  pythonload(path);
31 }
32 
33 // ####################################################################################################
34 void jevois::PythonWrapper::pythonload(std::string const & path)
35 {
36  std::lock_guard<std::mutex> _(itsMtx);
37 
38  itsConstructionError.clear();
39 
40  // Do not throw during construction, instead report construction errors later.
41  try
42  {
43  // Get the python interpreter going:
44  itsMainModule = boost::python::import("__main__");
45  itsMainNamespace = itsMainModule.attr("__dict__");
46 
47  // Import the module. Note that we import the whole directory:
48  size_t last_slash = path.rfind('/');
49  std::string const pydir = path.substr(0, last_slash);
50  std::string const pyclass = path.substr(last_slash + 1, path.length() - last_slash - 4); // strip trailing .py
51  std::string const execstr =
52  "import sys\n"
53  "sys.path.append(\"/usr/lib\")\n" // To find libjevois[pro] module in /usr/lib
54  "sys.path.append(\"" JEVOIS_CONFIG_PATH "\")\n" // To find pyjevois.py config
55  "sys.path.append(\"" JEVOIS_OPENCV_PYTHON_PATH "\")\n" // To find cv2 module
56  "sys.path.append(\"" + pydir + "\")\n" +
57  "import " + pyclass + "\n" +
58  "import importlib\n" +
59  "importlib.reload(" + pyclass + ")\n"; // reload so we are always fresh if file changed on SD card
60 
61  boost::python::exec(execstr.c_str(), itsMainNamespace, itsMainNamespace);
62 
63  // Create an instance of the python class defined in the file:
64  itsInstance = boost::python::eval((pyclass + "." + pyclass + "()").c_str(), itsMainNamespace, itsMainNamespace);
65 
66  // If we are sibling of Component, register our instance with Engine, used by dynamic parameters created in python:
67  jevois::Component * comp = dynamic_cast<jevois::Component *>(this);
68  if (comp) comp->engine()->registerPythonComponent(comp, itsInstance.ptr()->ob_type);
69  }
70  catch (boost::python::error_already_set & e)
71  {
72  itsConstructionError = "Initialization of " + path + " failed: " + jevois::getPythonExceptionString(e);
73  }
74  catch (std::exception const & e)
75  {
76  itsConstructionError = e.what();
77  }
78  catch (...)
79  {
80  itsConstructionError = "Unknown construction error";
81  }
82 }
83 
84 // ####################################################################################################
85 boost::python::object & jevois::PythonWrapper::pyinst()
86 {
87  if (itsConstructionError.empty() == false || itsInstance.is_none()) throw std::runtime_error(itsConstructionError);
88  return itsInstance;
89 }
90 
91 // ####################################################################################################
92 boost::python::object & jevois::PythonWrapper::mainModule()
93 { return itsMainModule; }
94 
95 // ####################################################################################################
96 boost::python::object & jevois::PythonWrapper::mainNamespace()
97 { return itsMainNamespace; }
98 
99 // ####################################################################################################
100 std::string const & jevois::PythonWrapper::constructionError() const
101 { return itsConstructionError; }
102 
103 // ####################################################################################################
105 {
106  std::lock_guard<std::mutex> _(itsMtx);
107 
108  // If we are sibling of a Component, unregister our instance with Engine:
109  if (itsInstance.is_none() == false)
110  {
111  jevois::Component * comp = dynamic_cast<jevois::Component *>(this);
112  if (comp) comp->engine()->unRegisterPythonComponent(comp);
113  }
114 }
jevois::PythonWrapper::PythonWrapper
PythonWrapper()
Default constructor. Will need to call pythonload() later.
Definition: PythonWrapper.C:23
jevois::PythonWrapper::pyinst
boost::python::object & pyinst()
Get the python class pyinst, or throw if construction error occurred (e.g., file not found)
Definition: PythonWrapper.C:85
jevois::Component
A component of a model hierarchy.
Definition: Component.H:181
jevois::PythonWrapper::mainModule
boost::python::object & mainModule()
Get the main module.
Definition: PythonWrapper.C:92
jevois::Engine::unRegisterPythonComponent
void unRegisterPythonComponent(Component *comp)
Unregister a component as linked to some python code, used by dynamic params created in python.
Definition: Engine.C:2732
jevois::PythonWrapper::mainNamespace
boost::python::object & mainNamespace()
Get the main namespace.
Definition: PythonWrapper.C:96
jevois::PythonWrapper::~PythonWrapper
virtual ~PythonWrapper()
Destructor.
Definition: PythonWrapper.C:104
Engine.H
jevois::Engine::registerPythonComponent
void registerPythonComponent(Component *comp, void *pyinst)
Register a component as linked to some python code, used by dynamic params created in python.
Definition: Engine.C:2722
jevois::Component::engine
Engine * engine() const
Get a handle to our Engine, or throw if we do not have an Engine as root ancestor.
Definition: Component.C:129
jevois::PythonWrapper::pythonload
void pythonload(std::string const &path)
Init from path if default constructor was used.
Definition: PythonWrapper.C:34
jevois::getPythonExceptionString
std::string getPythonExceptionString(boost::python::error_already_set &)
Python exception translation to string so we can print the traceback to our serlog stream.
Definition: PythonException.C:146
PythonException.H
PythonWrapper.H
jevois::PythonWrapper::constructionError
const std::string & constructionError() const
Get the construction error if any, or empty string.
Definition: PythonWrapper.C:100