I am trying to use the boost.python library in order to get data from the Python skyfield API, but I am having trouble printing out the data. The program runs, but I get this error: "Error in Python: <class 'TypeError'>: 'NoneType' object is not callable"
The correct output should show something like this: 10h 47m 56.24s +09deg 03' 23.1" 2.33251 au
I am using the first code example from this website as a reference: https://rhodesmill.org/skyfield/
If you have any ideas on how to get the data to correctly output, please let me know!
Here is my code so far:
#include <iostream>
#include <boost/python.hpp>
#include <Python.h>
namespace py = boost::python;
std::string parse_python_exception();
int main()
{
Py_Initialize(); //Initializes the Python interpreter
//Imports the __main__ module and extracts the namespace
//This creates a blank 'canvas' upon which we can call Python code
py::object main_module = py::import("__main__");
//Loads the dictionary object from the main module
py::object main_namespace = main_module.attr("__dict__");
try
{
//Imports
py::exec("from skyfield.api import load");
py::object skyfield_mod = py::import("skyfield.api");
py::object skyfield_load = skyfield_mod.attr("load");
py::object skyfield_load_timescale = skyfield_load.attr("timescale");
py::exec("print('This program computes the current position of Mars in the sky')", main_namespace);
py::object ts = skyfield_load_timescale();
py::object ts_now = ts.attr("now");
py::object t = ts_now();
py::object planets = skyfield_load("de421.bsp");
py::object earth = planets["earth"];
py::object mars = planets["mars"];
py::object earth_at = earth.attr("at");
py::object earth_at_observe = earth_at(t).attr("observe");
py::object m_earth_at_observe = earth_at_observe(mars);
py::object astrometric = m_earth_at_observe;
py::object ra, dec, distance = astrometric.attr("radec");
py::object m_ra = ra();
py::object m_dec = dec();
py::object m_distance = distance();
py::exec("print(m_ra)", main_namespace);
}
catch (boost::python::error_already_set const&)
{
std::string perror_str = parse_python_exception();
std::cout << "Error in Python: " << perror_str << std::endl;
}
}
// Parses the value of the active python exception
// NOTE SHOULD NOT BE CALLED IF NO EXCEPTION
std::string parse_python_exception() {
PyObject* type_ptr = NULL, * value_ptr = NULL, * traceback_ptr = NULL;
// Fetch the exception info from the Python C API
PyErr_Fetch(&type_ptr, &value_ptr, &traceback_ptr);
// Fallback error
std::string ret("Unfetchable Python error");
// If the fetch got a type pointer, parse the type into the exception string
if (type_ptr != NULL) {
py::handle<> h_type(type_ptr);
py::str type_pstr(h_type);
// Extract the string from the boost::python object
py::extract<std::string> e_type_pstr(type_pstr);
// If a valid string extraction is available, use it
// otherwise use fallback
if (e_type_pstr.check())
ret = e_type_pstr();
else
ret = "Unknown exception type";
}
// Do the same for the exception value (the stringification of the exception)
if (value_ptr != NULL) {
py::handle<> h_val(value_ptr);
py::str a(h_val);
py::extract<std::string> returned(a);
if (returned.check())
ret += ": " + returned();
else
ret += std::string(": Unparseable Python error: ");
}
// Parse lines from the traceback using the Python traceback module
if (traceback_ptr != NULL) {
py::handle<> h_tb(traceback_ptr);
// Load the traceback module and the format_tb function
py::object tb(py::import("traceback"));
py::object fmt_tb(tb.attr("format_tb"));
// Call format_tb to get a list of traceback strings
py::object tb_list(fmt_tb(h_tb));
// Join the traceback strings into a single string
py::object tb_str(py::str("\n").join(tb_list));
// Extract the string, check the extraction, and fallback in necessary
py::extract<std::string> returned(tb_str);
if (returned.check())
ret += ": " + returned();
else
ret += std::string(": Unparseable Python traceback");
}
return ret;
}