Flow123d  jenkins-Flow123d-linux-release-multijob-282
python_loader.cc
Go to the documentation of this file.
1 /*
2  * python_loader.cc
3  *
4  * Created on: Aug 31, 2012
5  * Author: jb
6  */
7 
8 
9 #ifdef HAVE_PYTHON
10 
11 #include "system/python_loader.hh"
12 #include "global_defs.h"
13 #include "system/system.hh"
14 #include <string>
15 #include <iostream>
16 #include <fstream>
17 #include <sstream>
18 
19 using namespace std;
20 
21 void PythonLoader::initialize(const std::string &python_home)
22 {
23  static internal::PythonRunning _running(python_home);
24 }
25 
26 
27 PyObject * PythonLoader::load_module_from_file(const std::string& fname) {
28  initialize();
29 
30  // don't know direct way how to load module form file, so we read it into string and use load_module_from_string
31  std::ifstream file_stream( fname.c_str() );
32  // check correct openning
33  INPUT_CHECK(! file_stream.fail(), "Can not open input file '%s'.\n", fname.c_str() );
34  file_stream.exceptions ( ifstream::failbit | ifstream::badbit );
35 
36  std::stringstream buffer;
37  buffer << file_stream.rdbuf();
38 
39  string module_name;
40  unsigned int pos = fname.rfind("/");
41  if (pos != string::npos)
42  module_name = fname.substr(pos+1);
43  else
44  module_name = fname;
45 
46  // cout << "python module: " << module_name <<endl;
47  // DBGMSG("%s\n", buffer.str().c_str());
48  // TODO: use exceptions and catch it here to produce shorter and more precise error message
49  return load_module_from_string(module_name, buffer.str() );
50 }
51 
52 
53 
54 PyObject * PythonLoader::load_module_from_string(const std::string& module_name, const std::string& source_string) {
55  initialize();
56 
57  // for unknown reason module name is non-const, so we have to make char * copy
58  char * tmp_name = new char[ module_name.size() + 2 ];
59  strcpy( tmp_name, module_name.c_str() );
60  PyObject * compiled_string = Py_CompileString( source_string.c_str(), "flow123d_python_loader", Py_file_input );
61  if (! compiled_string) {
62  PyErr_Print();
63  std::cerr << "Error: Can not compile python string:\n'" << source_string << std::endl;
64  }
65  PyObject * result = PyImport_ExecCodeModule(tmp_name, compiled_string);
66 
67  if (result == NULL) {
68  PyErr_Print();
69  std::cerr << "Error: Can not load python module '" << module_name << "' from string:" << std::endl;
70  std::cerr << source_string << std::endl;
71  }
72 
73  delete[] tmp_name;
74  return result;
75 }
76 
77 
78 
79 wstring to_py_string(const string &str) {
80  wchar_t wbuff[ str.size() ];
81  size_t wstr_size = mbstowcs( wbuff, str.c_str(), str.size() );
82  return wstring( wbuff, wstr_size );
83 }
84 
85 string from_py_string(const wstring &wstr) {
86  char buff[ wstr.size() ];
87  size_t str_size = wcstombs( buff, wstr.c_str(), wstr.size() );
88  return string( buff, str_size );
89 }
90 
91 // currently we support only Python 2.7
92 //
93 #if PYTHONLIBS_VERSION_MAJOR<3
94  #define to_py_string string
95  #define from_py_string string
96  #define PY_STRING string
97 #else
98  #define PY_STRING wstring
99 #endif
100 
101 #define STR_EXPAND(tok) #tok
102 #define STR(tok) string(STR_EXPAND(tok))
103 
104 namespace internal {
105 
106 PythonRunning::PythonRunning(const std::string& program_name)
107 {
108 #ifdef PYTHON_PREFIX
109  static PY_STRING _python_program_name = to_py_string(program_name);
110  Py_SetProgramName( &(_python_program_name[0]) );
111  PY_STRING full_program_name = Py_GetProgramFullPath();
112  cout << "full program name: " << from_py_string(full_program_name) << std::endl;
113 
114  size_t pos = full_program_name.rfind( to_py_string("flow123d") );
115  DBGMSG("pos: %d\n", pos);
116  ASSERT(pos != PY_STRING::npos, "non flow123d binary");
117  PY_STRING full_flow_prefix=full_program_name.substr(0,pos-string("/bin/").size() );
118  cout << "full flow prefix: " << from_py_string(full_flow_prefix) << std::endl;
119  PY_STRING default_py_prefix(to_py_string(STR(PYTHON_PREFIX)));
120  cout << "default py prefix: " << from_py_string(default_py_prefix) << std::endl;
121 
122  static PY_STRING our_py_home(full_flow_prefix + ":" +default_py_prefix);
123  Py_SetPythonHome( &(our_py_home[0]) );
124 
125  /*
126  Py_GetPath();
127 
128  static PY_STRING our_py_path;
129  string python_subdir("/lib/python" + STR(PYTHONLIBS_VERSION_MAJOR) + "." + STR(PYTHONLIBS_VERSION_MINOR));
130  our_py_path+=full_flow_prefix + to_py_string( python_subdir + "/:");
131  our_py_path+=full_flow_prefix + to_py_string( python_subdir + "/plat-cygwin:");
132  our_py_path+=full_flow_prefix + to_py_string( python_subdir + "/lib-dynload:");
133  our_py_path+=default_py_prefix + to_py_string( python_subdir + "/lib-dynload:");
134  our_py_path+=default_py_prefix + to_py_string( python_subdir + "/lib-dynload:");
135  our_py_path+=default_py_prefix + to_py_string( python_subdir + "/lib-dynload:");
136 
137  Py_SetPath(our_py_path);
138  //our_py_path+=full_flow_prefix + to_py_string( python_subdir);
139 
140 // string prefix = ;
141  */
142  cout << "Python path: " << from_py_string( Py_GetPath() ) << std::endl;
143  cout << "Python home: " << from_py_string( Py_GetPythonHome() ) << std::endl;
144  cout << "Python prefix: " << from_py_string( Py_GetPrefix() ) << std::endl;
145  cout << "Python exec prefix: " << from_py_string( Py_GetExecPrefix() ) << std::endl;
146 
147  // 1. set program name
148  // 2. get prefix
149  // 3. get python full path
150  // 4. extract prefix from the full path
151  // 5. substitute the prefix in python path
152  // 6. set python path (suppress its computation during Py_Initialize)
153  /*
154  wchar_t wbuf[ python_home.size() ];
155  size_t num_chars = mbstowcs( wbuf, python_home.c_str(), python_home.size() );
156  static wstring _python_home_storage( wbuf, num_chars ); // permanent non-const storage required
157 
158  std::wcout << "new python home: " << _python_home_storage << std::endl;
159 
160  Py_SetProgramName( &(_python_home_storage[0]) );
161 
162  char buff[ 1024 ];
163  num_chars = wcstombs(buff, Py_GetPath(), 256);
164  buff[1024]=0;
165  string str(buff, num_chars);
166  std::cout << "Python path: " << str << std::endl;
167 
168 
169 
170  wchar_t wbuf[ python_home.size() ];
171  size_t num_chars = mbstowcs( wbuf, python_home.c_str(), python_home.size() );
172  static wstring _python_home_storage( wbuf, num_chars ); // permanent non-const storage required
173 
174  std::wcout << "new python home: " << _python_home_storage << std::endl;
175 
176  Py_SetProgramName( &(_python_home_storage[0]) );
177 
178  char buff[ 1024 ];
179  num_chars = wcstombs(buff, Py_GetPath(), 1024);
180  //std::cout << "num chars: " << num_chars << std::endl;
181  std::cout << "Python path: " << buff << std::endl;
182  //num_chars = wcstombs(buff, Py_GetPythonHome(), 1024);
183  //std::cout << "Python home: " << buff << std::endl;
184  num_chars = wcstombs(buff, Py_GetProgramName(), 1024);
185  std::cout << "Python prog. name: " << buff << std::endl;
186  num_chars = wcstombs(buff, Py_GetPrefix(), 1024);
187  std::cout << "Python prefix: " << buff << std::endl;
188  num_chars = wcstombs(buff, Py_GetProgramFullPath(), 1024);
189  std::cout << "Python full: " << buff << std::endl;
190 */
191 #endif
192  Py_Initialize();
193 }
194 
195 
196 
197 PythonRunning::~PythonRunning() {
198  Py_Finalize();
199 }
200 
201 } // close namespace internal
202 
203 #endif // HAVE_PYTHON
#define DBGMSG(...)
Definition: global_defs.h:196
Global macros to enhance readability and debugging, general constants.
#define ASSERT(...)
Definition: global_defs.h:121
#define INPUT_CHECK(i,...)
Debugging macros.
Definition: global_defs.h:61