BornAgain  1.18.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 scattering at grazing incidence
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 
19 #include "Base/Utils/PythonCore.h"
21 
22 namespace
23 {
24 
25 std::string error_description(const std::string& title)
26 {
27  std::stringstream buf;
28  buf << title << "\n";
29  buf << PyEmbeddedUtils::pythonStackTrace() << "\n";
30  return buf.str();
31 }
32 
33 } // namespace
34 
35 std::unique_ptr<MultiLayer> PyImport::createFromPython(const std::string& script,
36  const std::string& functionName,
37  const std::string& path)
38 {
40 
41  PyObject* pCompiledFn = Py_CompileString(script.c_str(), "", Py_file_input);
42  if (!pCompiledFn)
43  throw std::runtime_error(error_description("Can't compile snippet"));
44 
45  // create a module
46  PyObject* pModule = PyImport_ExecCodeModule((char*)"test", pCompiledFn);
47  if (!pModule) {
48  Py_DecRef(pCompiledFn);
49  throw std::runtime_error(error_description("Can't exec module"));
50  }
51 
52  // locate the "get_simulation" function (it's an attribute of the module)
53  PyObject* pAddFn = PyObject_GetAttrString(pModule, functionName.c_str());
54  if (!pAddFn)
55  throw std::runtime_error("Can't locate compiled function");
56 
57  PyObject* instance = PyObject_CallFunctionObjArgs(pAddFn, NULL);
58  if (!instance) {
59  Py_DecRef(pAddFn);
60  Py_DecRef(pModule);
61  Py_DecRef(pCompiledFn);
62  throw std::runtime_error(error_description("Can't call function"));
63  }
64 
65  // clean up
66  Py_DecRef(pAddFn);
67  Py_DecRef(pModule);
68  Py_DecRef(pCompiledFn);
69 
70  void* argp1 = 0;
71  swig_type_info* pTypeInfo = SWIG_TypeQuery("MultiLayer *");
72 
73  const int res = SWIG_ConvertPtr(instance, &argp1, pTypeInfo, 0);
74  if (!SWIG_IsOK(res)) {
75  Py_DecRef(instance);
76  throw std::runtime_error("SWIG failed to extract a MultiLayer.");
77  }
78 
79  MultiLayer* multilayer = reinterpret_cast<MultiLayer*>(argp1);
80  std::unique_ptr<MultiLayer> result(multilayer->clone());
81 
82  Py_DecRef(instance);
83 
84  return result;
85 }
86 
87 std::vector<std::string> PyImport::listOfFunctions(const std::string& script,
88  const std::string& path)
89 {
91 
92  PyObject* pCompiledFn = Py_CompileString(script.c_str(), "", Py_file_input);
93  if (!pCompiledFn)
94  throw std::runtime_error(error_description("Can't compile snippet"));
95 
96  // create a module
97  PyObject* pModule = PyImport_ExecCodeModule((char*)"test", pCompiledFn);
98  if (!pModule) {
99  Py_DecRef(pCompiledFn);
100  throw std::runtime_error(error_description("Can't exec module"));
101  }
102 
103  PyObject* dict = PyModule_GetDict(pModule);
104  if (!dict)
105  throw std::runtime_error("Can't get dictionary from module");
106 
107  std::vector<std::string> result;
108  PyObject *key, *value;
109  Py_ssize_t pos = 0;
110  while (PyDict_Next(dict, &pos, &key, &value)) {
111  if (PyCallable_Check(value)) {
112  std::string func_name = PyEmbeddedUtils::toString(key);
113  if (func_name.find("__") == std::string::npos)
114  result.push_back(func_name);
115  }
116  }
117 
118  Py_DecRef(dict);
119  Py_DecRef(pModule);
120  Py_DecRef(pCompiledFn);
121 
122  return result;
123 }
124 
125 #endif // BORNAGAIN_PYTHON
Defines class MultiLayer.
Defines PyEmbeddedUtils namespace.
Defines PyImport namespace.
_object PyObject
Definition: PyObject.h:20
Includes python header and takes care of warnings.
Our sample model: a stack of layers one below the other.
Definition: MultiLayer.h:42
MultiLayer * clone() const final override
Returns a clone of multilayer with clones of all layers and interfaces between layers.
Definition: MultiLayer.cpp:36
std::string toString(PyObject *obj)
Converts PyObject into string, if possible, or throws exception.
std::string pythonStackTrace()
Returns string representing python stack trace.
void import_bornagain(const std::string &path="")
Imports BornAgain from given location. If path is empty, tries to rely on PYTHONPATH.
std::vector< std::string > listOfFunctions(const std::string &script, const std::string &path="")
Returns list of functions defined in the script.
Definition: PyImport.cpp:87
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:35
std::string error_description(const std::string &title)
Definition: PyImport.cpp:25