Flow123d  jenkins-Flow123d-windows32-release-multijob-28
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 * result = PyImport_ExecCodeModule(tmp_name,
61  Py_CompileString( source_string.c_str(), "flow123d_python_loader", Py_file_input ) );
62 
63  if (result == NULL) {
64  PyErr_Print();
65  std::cerr << "Error: Can not load python module '" << module_name << "' from string:" << std::endl;
66  std::cerr << source_string << std::endl;
67  }
68 
69  delete[] tmp_name;
70  return result;
71 }
72 
73 
74 
75 wstring to_py_string(const string &str) {
76  wchar_t wbuff[ str.size() ];
77  size_t wstr_size = mbstowcs( wbuff, str.c_str(), str.size() );
78  return wstring( wbuff, wstr_size );
79 }
80 
81 string from_py_string(const wstring &wstr) {
82  char buff[ wstr.size() ];
83  size_t str_size = wcstombs( buff, wstr.c_str(), wstr.size() );
84  return string( buff, str_size );
85 }
86 
87 // currently we support only Python 2.7
88 //
89 #if PYTHONLIBS_VERSION_MAJOR<3
90  #define to_py_string string
91  #define from_py_string string
92  #define PY_STRING string
93 #else
94  #define PY_STRING wstring
95 #endif
96 
97 #define STR_EXPAND(tok) #tok
98 #define STR(tok) string(STR_EXPAND(tok))
99 
100 namespace internal {
101 
102 PythonRunning::PythonRunning(const std::string& program_name)
103 {
104 #ifdef PYTHON_PREFIX
105  static PY_STRING _python_program_name = to_py_string(program_name);
106  Py_SetProgramName( &(_python_program_name[0]) );
107  PY_STRING full_program_name = Py_GetProgramFullPath();
108  cout << "full program name: " << from_py_string(full_program_name) << std::endl;
109 
110  size_t pos = full_program_name.rfind( to_py_string("flow123d") );
111  DBGMSG("pos: %d\n", pos);
112  ASSERT(pos != PY_STRING::npos, "non flow123d binary");
113  PY_STRING full_flow_prefix=full_program_name.substr(0,pos-string("/bin/").size() );
114  cout << "full flow prefix: " << from_py_string(full_flow_prefix) << std::endl;
115  PY_STRING default_py_prefix(to_py_string(STR(PYTHON_PREFIX)));
116  cout << "default py prefix: " << from_py_string(default_py_prefix) << std::endl;
117 
118  static PY_STRING our_py_home(full_flow_prefix + ":" +default_py_prefix);
119  Py_SetPythonHome( &(our_py_home[0]) );
120 
121  /*
122  Py_GetPath();
123 
124  static PY_STRING our_py_path;
125  string python_subdir("/lib/python" + STR(PYTHONLIBS_VERSION_MAJOR) + "." + STR(PYTHONLIBS_VERSION_MINOR));
126  our_py_path+=full_flow_prefix + to_py_string( python_subdir + "/:");
127  our_py_path+=full_flow_prefix + to_py_string( python_subdir + "/plat-cygwin:");
128  our_py_path+=full_flow_prefix + to_py_string( python_subdir + "/lib-dynload:");
129  our_py_path+=default_py_prefix + to_py_string( python_subdir + "/lib-dynload:");
130  our_py_path+=default_py_prefix + to_py_string( python_subdir + "/lib-dynload:");
131  our_py_path+=default_py_prefix + to_py_string( python_subdir + "/lib-dynload:");
132 
133  Py_SetPath(our_py_path);
134  //our_py_path+=full_flow_prefix + to_py_string( python_subdir);
135 
136 // string prefix = ;
137  */
138  cout << "Python path: " << from_py_string( Py_GetPath() ) << std::endl;
139  cout << "Python home: " << from_py_string( Py_GetPythonHome() ) << std::endl;
140  cout << "Python prefix: " << from_py_string( Py_GetPrefix() ) << std::endl;
141  cout << "Python exec prefix: " << from_py_string( Py_GetExecPrefix() ) << std::endl;
142 
143  // 1. set program name
144  // 2. get prefix
145  // 3. get python full path
146  // 4. extract prefix from the full path
147  // 5. substitute the prefix in python path
148  // 6. set python path (suppress its computation during Py_Initialize)
149  /*
150  wchar_t wbuf[ python_home.size() ];
151  size_t num_chars = mbstowcs( wbuf, python_home.c_str(), python_home.size() );
152  static wstring _python_home_storage( wbuf, num_chars ); // permanent non-const storage required
153 
154  std::wcout << "new python home: " << _python_home_storage << std::endl;
155 
156  Py_SetProgramName( &(_python_home_storage[0]) );
157 
158  char buff[ 1024 ];
159  num_chars = wcstombs(buff, Py_GetPath(), 256);
160  buff[1024]=0;
161  string str(buff, num_chars);
162  std::cout << "Python path: " << str << std::endl;
163 
164 
165 
166  wchar_t wbuf[ python_home.size() ];
167  size_t num_chars = mbstowcs( wbuf, python_home.c_str(), python_home.size() );
168  static wstring _python_home_storage( wbuf, num_chars ); // permanent non-const storage required
169 
170  std::wcout << "new python home: " << _python_home_storage << std::endl;
171 
172  Py_SetProgramName( &(_python_home_storage[0]) );
173 
174  char buff[ 1024 ];
175  num_chars = wcstombs(buff, Py_GetPath(), 1024);
176  //std::cout << "num chars: " << num_chars << std::endl;
177  std::cout << "Python path: " << buff << std::endl;
178  //num_chars = wcstombs(buff, Py_GetPythonHome(), 1024);
179  //std::cout << "Python home: " << buff << std::endl;
180  num_chars = wcstombs(buff, Py_GetProgramName(), 1024);
181  std::cout << "Python prog. name: " << buff << std::endl;
182  num_chars = wcstombs(buff, Py_GetPrefix(), 1024);
183  std::cout << "Python prefix: " << buff << std::endl;
184  num_chars = wcstombs(buff, Py_GetProgramFullPath(), 1024);
185  std::cout << "Python full: " << buff << std::endl;
186 */
187 #endif
188  Py_Initialize();
189 }
190 
191 
192 
193 PythonRunning::~PythonRunning() {
194  Py_Finalize();
195 }
196 
197 } // close namespace internal
198 
199 #endif // HAVE_PYTHON
#define DBGMSG(...)
Definition: global_defs.h:195
Global macros to enhance readability and debugging, general constants.
#define ASSERT(...)
Definition: global_defs.h:120
#define INPUT_CHECK(i,...)
Debugging macros.
Definition: global_defs.h:61