JeVois  1.22
JeVois Smart Embedded Machine Vision Toolkit
Share this page:
Loading...
Searching...
No Matches
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// ####################################################################################################
28jevois::PythonWrapper::PythonWrapper(std::string const & path)
29{
30 pythonload(path);
31}
32
33// ####################################################################################################
34void 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(\"" JEVOIS_ROOT_PATH "/lib\")\n" // To find libjevois[pro]
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// ####################################################################################################
85boost::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// ####################################################################################################
92boost::python::object & jevois::PythonWrapper::mainModule()
93{ return itsMainModule; }
94
95// ####################################################################################################
96boost::python::object & jevois::PythonWrapper::mainNamespace()
97{ return itsMainNamespace; }
98
99// ####################################################################################################
101{ return itsConstructionError; }
102
103// ####################################################################################################
105{
106 // This does not work, the dynamic cast fails. Looks like it is too late here to do it, see
107 // https://stackoverflow.com/questions/59973782/dynamic-cast-in-destructor
108
109 // Our parent class will have to do the un-registering...
110 /*
111 std::lock_guard<std::mutex> _(itsMtx);
112
113 // If we are sibling of a Component, unregister our instance with Engine:
114 if (itsInstance.is_none() == false)
115 {
116 jevois::Component * comp = dynamic_cast<jevois::Component *>(this);
117 if (comp) comp->engine()->unRegisterPythonComponent(comp);
118 }
119 */
120}
#define JEVOIS_OPENCV_PYTHON_PATH
Definition Config.H:120
#define JEVOIS_CONFIG_PATH
Base path for config files.
Definition Config.H:79
#define JEVOIS_ROOT_PATH
Root path for runtime jevois config files, videomappings.cfg, modules, etc.
Definition Config.H:73
A component of a model hierarchy.
Definition Component.H:182
boost::python::object & mainModule()
Get the main module.
PythonWrapper()
Default constructor. Will need to call pythonload() later.
void pythonload(std::string const &path)
Init from path if default constructor was used.
boost::python::object & pyinst()
Get the python class pyinst, or throw if construction error occurred (e.g., file not found)
std::string const & constructionError() const
Get the construction error if any, or empty string.
virtual ~PythonWrapper()
Destructor.
boost::python::object & mainNamespace()
Get the main namespace.
std::string getPythonExceptionString(boost::python::error_already_set &)
Python exception translation to string so we can print the traceback to our serlog stream.