BornAgain  1.19.0
Simulate and fit neutron and x-ray scattering at grazing incidence
PyImport.cpp
Go to the documentation of this file.
1 // ************************************************************************************************
2 //
3 // BornAgain: simulate and fit reflection and scattering
4 //
5 //! @file Sample/Multilayer/PyImport.cpp
6 //! @brief Implements PyImport namespace
7 //!
8 //! @homepage http://www.bornagainproject.org
9 //! @license GNU General Public License v3 or higher (see COPYING)
10 //! @copyright Forschungszentrum Jülich GmbH 2018
11 //! @authors Scientific Computing Group at MLZ (see CITATION, AUTHORS)
12 //
13 // ************************************************************************************************
14 
15 #ifdef BORNAGAIN_PYTHON
16 
18 #include "Base/Py/PyCore.h"
19 #include "Base/Py/PyUtils.h"
21 
22 namespace {
23 
24 std::string error_description(const std::string& title)
25 {
26  std::stringstream buf;
27  buf << title << "\n";
28  buf << PyUtils::pythonStackTrace() << "\n";
29  return buf.str();
30 }
31 
32 } // namespace
33 
34 std::unique_ptr<MultiLayer> PyImport::createFromPython(const std::string& script,
35  const std::string& functionName,
36  const std::string& path)
37 {
39 
40  PyObject* pCompiledFn = Py_CompileString(script.c_str(), "", Py_file_input);
41  if (!pCompiledFn)
42  throw std::runtime_error(error_description("Can't compile snippet"));
43 
44  // create a module
45  PyObject* pModule = PyImport_ExecCodeModule((char*)"test", pCompiledFn);
46  if (!pModule) {
47  Py_DecRef(pCompiledFn);
48  throw std::runtime_error(error_description("Can't exec module"));
49  }
50 
51  // locate the "get_simulation" function (it's an attribute of the module)
52  PyObject* pAddFn = PyObject_GetAttrString(pModule, functionName.c_str());
53  if (!pAddFn)
54  throw std::runtime_error("Can't locate compiled function");
55 
56  PyObject* instance = PyObject_CallFunctionObjArgs(pAddFn, NULL);
57  if (!instance) {
58  Py_DecRef(pAddFn);
59  Py_DecRef(pModule);
60  Py_DecRef(pCompiledFn);
61  throw std::runtime_error(error_description("Can't call function"));
62  }
63 
64  // clean up
65  Py_DecRef(pAddFn);
66  Py_DecRef(pModule);
67  Py_DecRef(pCompiledFn);
68 
69  void* argp1 = 0;
70  swig_type_info* pTypeInfo = SWIG_TypeQuery("MultiLayer *");
71 
72  const int res = SWIG_ConvertPtr(instance, &argp1, pTypeInfo, 0);
73  if (!SWIG_IsOK(res)) {
74  Py_DecRef(instance);
75  throw std::runtime_error("SWIG failed to extract a MultiLayer.");
76  }
77 
78  MultiLayer* multilayer = reinterpret_cast<MultiLayer*>(argp1);
79  std::unique_ptr<MultiLayer> result(multilayer->clone());
80 
81  Py_DecRef(instance);
82 
83  return result;
84 }
85 
86 std::vector<std::string> PyImport::listOfFunctions(const std::string& script,
87  const std::string& path)
88 {
90 
91  PyObject* pCompiledFn = Py_CompileString(script.c_str(), "", Py_file_input);
92  if (!pCompiledFn)
93  throw std::runtime_error(error_description("Can't compile snippet"));
94 
95  // create a module
96  PyObject* pModule = PyImport_ExecCodeModule((char*)"test", pCompiledFn);
97  if (!pModule) {
98  Py_DecRef(pCompiledFn);
99  throw std::runtime_error(error_description("Can't exec module"));
100  }
101 
102  PyObject* dict = PyModule_GetDict(pModule);
103  if (!dict)
104  throw std::runtime_error("Can't get dictionary from module");
105 
106  std::vector<std::string> result;
107  PyObject *key, *value;
108  Py_ssize_t pos = 0;
109  while (PyDict_Next(dict, &pos, &key, &value)) {
110  if (PyCallable_Check(value)) {
111  std::string func_name = PyUtils::toString(key);
112  if (func_name.find("__") == std::string::npos)
113  result.push_back(func_name);
114  }
115  }
116 
117  Py_DecRef(dict);
118  Py_DecRef(pModule);
119  Py_DecRef(pCompiledFn);
120 
121  return result;
122 }
123 
124 #endif // BORNAGAIN_PYTHON
Defines class MultiLayer.
Includes python header and takes care of warnings.
Defines PyImport namespace.
_object PyObject
Definition: PyObject.h:25
Defines PyUtils namespace.
Our sample model: a stack of layers one below the other.
Definition: MultiLayer.h:41
MultiLayer * clone() const final
Returns a clone of this ISampleNode object.
Definition: MultiLayer.cpp:36
std::vector< std::string > listOfFunctions(const std::string &script, const std::string &path="")
Returns list of functions defined in the script.
Definition: PyImport.cpp:86
std::unique_ptr< MultiLayer > createFromPython(const std::string &script, const std::string &functionName, const std::string &path="")
Creates a multi layer by running python code in embedded interpreter.
Definition: PyImport.cpp:34
std::string toString(PyObject *obj)
Converts PyObject into string, if possible, or throws exception.
Definition: PyUtils.cpp:24
std::string pythonStackTrace()
Returns string representing python stack trace.
Definition: PyUtils.cpp:132
void import_bornagain(const std::string &path="")
Imports BornAgain from given location. If path is empty, tries to rely on PYTHONPATH.
Definition: PyUtils.cpp:71