NEURON
nrnpy_utils.cpp
Go to the documentation of this file.
1 #include "nrnpy_utils.h"
2 
3 #include <tuple>
4 #include <nanobind/nanobind.h>
5 
6 namespace nb = nanobind;
7 
8 inline std::tuple<nb::object, nb::object, nb::object> fetch_pyerr() {
9  PyObject* ptype = NULL;
10  PyObject* pvalue = NULL;
11  PyObject* ptraceback = NULL;
12  PyErr_Fetch(&ptype, &pvalue, &ptraceback);
13 
14  return std::make_tuple(nb::steal(ptype), nb::steal(pvalue), nb::steal(ptraceback));
15 }
16 
18  char* str_ = nullptr;
19  if (PyUnicode_Check(python_string)) {
20  auto py_bytes = nb::steal(PyUnicode_AsASCIIString(python_string));
21  if (py_bytes) {
22  str_ = strdup(PyBytes_AsString(py_bytes.ptr()));
23  if (!str_) { // errno is ENOMEM
24  PyErr_SetString(PyExc_MemoryError, "strdup in Py2NRNString");
25  }
26  }
27  } else if (PyBytes_Check(python_string)) {
28  str_ = strdup(PyBytes_AsString(python_string));
29  // assert(strlen(str_) == PyBytes_Size(python_string))
30  // not checking for embedded '\0'
31  if (!str_) { // errno is ENOMEM
32  PyErr_SetString(PyExc_MemoryError, "strdup in Py2NRNString");
33  }
34  } else { // Neither Unicode or PyBytes
35  PyErr_SetString(PyExc_TypeError, "Neither Unicode or PyBytes");
36  }
37 
38  return neuron::unique_cstr(str_);
39 }
40 
41 void Py2NRNString::set_pyerr(PyObject* type, const char* message) {
42  auto [err_type, err_value, err_traceback] = fetch_pyerr();
43 
44  if (err_value && err_type) {
45  auto umes = nb::steal(
46  PyUnicode_FromFormat("%s (Note: %S: %S)", message, err_type.ptr(), err_value.ptr()));
47  PyErr_SetObject(type, umes.ptr());
48  } else {
49  PyErr_SetString(type, message);
50  }
51 }
52 
54  // Must be called after an error happend.
55  char* str_ = nullptr;
56 
57  auto [ptype, pvalue, ptraceback] = fetch_pyerr();
58  if (pvalue) {
59  auto pstr = nb::steal(PyObject_Str(pvalue.ptr()));
60  if (pstr) {
61  const char* err_msg = PyUnicode_AsUTF8(pstr.ptr());
62  if (err_msg) {
63  str_ = strdup(err_msg);
64  } else {
65  str_ = strdup("get_pyerr failed at PyUnicode_AsUTF8");
66  }
67  } else {
68  str_ = strdup("get_pyerr failed at PyObject_Str");
69  }
70  } else {
71  str_ = strdup("get_pyerr failed at PyErr_Fetch");
72  }
73 
74  PyErr_Clear(); // in case could not turn pvalue into c_str.
75  return neuron::unique_cstr(str_);
76 }
static neuron::unique_cstr as_ascii(PyObject *python_string)
Definition: nrnpy_utils.cpp:17
static neuron::unique_cstr get_pyerr()
Definition: nrnpy_utils.cpp:53
static void set_pyerr(PyObject *type, const char *message)
Definition: nrnpy_utils.cpp:41
A RAII wrapper for C-style strings.
Definition: unique_cstr.hpp:18
short type
Definition: cabvars.h:10
_object PyObject
Definition: nrnpy.h:12
std::tuple< nb::object, nb::object, nb::object > fetch_pyerr()
Definition: nrnpy_utils.cpp:8
#define NULL
Definition: spdefs.h:105