GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: bindings/python/parsers/python/model.cpp Lines: 23 27 85.2 %
Date: 2022-07-05 08:28:44 Branches: 42 92 45.7 %

Line Branch Exec Source
1
//
2
// Copyright (c) 2016-2020 CNRS INRIA
3
//
4
5
#include "pinocchio/parsers/python.hpp"
6
7
#include <iostream>
8
#include <Python.h>
9
#include <boost/shared_ptr.hpp>
10
#include <boost/version.hpp>
11
#include <boost/algorithm/string/predicate.hpp>
12
13
// Boost 1.58
14
#if BOOST_VERSION / 100 % 1000 == 58
15
#include <fstream>
16
#endif
17
18
namespace pinocchio
19
{
20
  namespace python
21
  {
22
    namespace bp = boost::python;
23
24
1
    Model buildModel(const std::string & filename, const std::string & model_name)
25
    {
26
1
      Py_Initialize();
27
28

2
      bp::object main_module = bp::import("__main__");
29
      // Get a dict for the global namespace to exec further python code with
30


2
      bp::dict globals = bp::extract<bp::dict>(main_module.attr("__dict__"));
31
32
      // We need to link to the pinocchio PyWrap. We delegate the dynamic loading to the python interpreter.
33

2
      bp::object cpp_module( (bp::handle<>(bp::borrowed(PyImport_AddModule("libpinocchio_pywrap")))) );
34
35
      // That's it, you can exec your python script, starting with a model you
36
      // can update as you want.
37
      try
38
      {
39
// Boost 1.58
40
#if BOOST_VERSION / 100 % 1000 == 58
41
        // Avoid a segv with exec_file
42
        // See: https://github.com/boostorg/python/pull/15
43
        std::ifstream t(filename.c_str());
44
        std::stringstream buffer;
45
        buffer << t.rdbuf();
46
        bp::exec(buffer.str().c_str(), globals);
47
#else // default implementation
48


1
        bp::exec_file((bp::str)filename, globals);
49
#endif
50
      }
51
      catch (bp::error_already_set & e)
52
      {
53
        PyErr_PrintEx(0);
54
      }
55
56
1
      Model model;
57
      try
58
      {
59

1
        bp::object obj_model = globals[model_name];
60

1
        model = bp::extract<Model>(obj_model);
61
      }
62
      catch (bp::error_already_set & e)
63
      {
64
        PyErr_PrintEx(0);
65
      }
66
67
      // close the interpreter
68
      // cf. https://github.com/numpy/numpy/issues/8097
69
#if PY_MAJOR_VERSION < 3
70
      Py_Finalize();
71
#else
72
73
1
      PyObject * poMainModule = PyImport_AddModule("__main__");
74
1
      PyObject * poAttrList = PyObject_Dir(poMainModule);
75
1
      PyObject * poAttrIter = PyObject_GetIter(poAttrList);
76
      PyObject * poAttrName;
77
78

21
      while ((poAttrName = PyIter_Next(poAttrIter)) != NULL)
79
      {
80


40
        std::string oAttrName = PyUnicode_AS_DATA(poAttrName);
81
82
        // Make sure we don't delete any private objects.
83


20
        if (!boost::starts_with(oAttrName, "__") || !boost::ends_with(oAttrName, "__"))
84
        {
85
20
          PyObject * poAttr = PyObject_GetAttr(poMainModule, poAttrName);
86
87
          // Make sure we don't delete any module objects.
88

20
          if (poAttr && poAttr->ob_type != poMainModule->ob_type)
89
17
            PyObject_SetAttr(poMainModule, poAttrName, NULL);
90
20
          Py_DecRef(poAttr);
91
        }
92
20
        Py_DecRef(poAttrName);
93
      }
94
1
      Py_DecRef(poAttrIter);
95
1
      Py_DecRef(poAttrList);
96
#endif
97
98
2
      return model;
99
    }
100
  } // namespace python
101
} // namespace pinocchio