HOPS
HOPS class reference
MHO_PyConfigurePath.hh
Go to the documentation of this file.
1 #ifndef MHO_PyConfigurePath_HH__
2  #define MHO_PyConfigurePath_HH__
3 
4  #include <sstream>
5  #include <string>
6 
8  #include "MHO_Message.hh"
9 
10  //pybind11 stuff to interface with python
11  #include <pybind11/embed.h>
12  #include <pybind11/pybind11.h>
13 namespace py = pybind11;
14 
15 namespace hops
16 {
17 
26 static void configure_pypath()
27 {
28  if(Py_IsInitialized() == 0)
29  {
30  //the internal python interpreter has not been started, bail out
31  msg_warn("python_bindings", "python interpreter not running/initialized, cannot configure path " << eom);
32  }
33  else
34  {
35  //make sure our python plugin directories are in our search paths
36  //only do this once on a per-executable level, since these settings are global
37  //(e.g. we don't want each individual class messing with the search paths)
38  std::stringstream pyss;
39  pyss << "import sys\n";
40  //the default plugins dir lives at <install_prefix>/plugin_scripts (resolved at runtime)
41  std::string default_path = MHO_DirectoryInterface::GetHopsInstallPrefix();
42  if(default_path.empty())
43  {
44  msg_warn("python_bindings",
45  "could not determine HOPS install prefix; using relative path for default plugins directory" << eom);
46  default_path = ".";
47  }
48  default_path += "/plugin_scripts";
49  if(default_path.back() != '/')
50  {
51  default_path.push_back('/');
52  }
53  msg_info("main", "adding HOPS_DEFAULT_PLUGINS_DIR to search path: " << default_path << eom);
54  pyss << "sys.path.append(\"" << default_path << "\") \n";
55 
56  //Also add the install tree's python module dir so the embedded interpreter
57  //can import the compiled pyMHO_* bindings without the user having to source
58  //hops_pypath.sh first.
59 #ifdef HOPS_PYTHON_SITE_SUBDIR
60  {
61  std::string site_dir = MHO_DirectoryInterface::GetHopsInstallPrefix();
62  if(!site_dir.empty())
63  {
64  if(site_dir.back() != '/')
65  {
66  site_dir.push_back('/');
67  }
68  site_dir += HOPS_PYTHON_SITE_SUBDIR;
69  msg_info("main", "adding HOPS python module dir to search path: " << site_dir << eom);
70  pyss << "sys.path.insert(0, \"" << site_dir << "\")\n";
71  }
72  }
73 #endif
74 
75  const char* user_plugin_env = std::getenv("HOPS_USER_PLUGINS_DIR");
76  if(user_plugin_env != nullptr)
77  {
78  std::string user_specified_path = std::string(user_plugin_env);
79  if(user_specified_path.back() != '/')
80  {
81  user_specified_path.push_back('/');
82  }
83  msg_info("main", "adding HOPS_USER_PLUGINS_DIR to search path: " << user_specified_path << eom);
84  pyss << "sys.path.append(\"" << user_specified_path << "\") \n";
85  }
86 
87  //this ensures that python 'print' statements get flushed roughly in sync with when they are called
88  //instead of (strangely) at the end of the program
89  pyss << "sys.stdout.reconfigure(line_buffering=True)\n";
90 
91  //now lets make sure pyMHO_Containers and pyMHO_Operators are always present
92  pyss << "import pyMHO_Containers\n";
93  pyss << "import pyMHO_Operators\n";
94  pyss << "import pyMHO_Calibration\n";
95 
96  //IMPORTANT...if we create additional bindings libraries, we should import them here,
97  //otherwise if a user tries to write a plugin but fails to import what they need, they
98  //will encounter a cryptic error of the form:
99  //terminate called after throwing an instance of 'pybind11::cast_error'
100  // what(): Unable to convert call argument '0' of type '<...something...>' to Python object
101  //Aborted (core dumped)
102 
103  py::exec(pyss.str().c_str());
104  }
105 }
106 
107 } // namespace hops
108 
109 #endif
#define msg_warn(xKEY, xCONTENT)
Definition: MHO_Message.hh:248
#define msg_info(xKEY, xCONTENT)
Definition: MHO_Message.hh:268
static std::string GetHopsInstallPrefix()
Returns the absolute path of the HOPS install prefix, determined at runtime from the on-disk location...
Definition: MHO_DirectoryInterface.cc:73
Definition: MHO_AdhocFlagging.hh:18