1 #include <../../nrnconf.h>
18 #include <nanobind/nanobind.h>
20 namespace nb = nanobind;
29 nanobind::gil_scoped_acquire
lock{};
38 nanobind::gil_scoped_acquire
lock{};
45 Fprintf(stderr,
"%s\n", mes.c_str());
48 if (PyErr_Occurred()) {
107 nb::object
p = nb::steal(PyObject_CallObject(callable.ptr(), tup.ptr()));
109 printf(
"PyObject_CallObject callable\n");
110 PyObject_Print(callable, stdout, 0);
112 PyObject_Print(args, stdout, 0);
147 auto head = nb::borrow(pn->
po_);
149 nanobind::gil_scoped_acquire
lock{};
150 if (pn->
type_ == 0) {
159 if (strcmp(sym->
name,
"_") == 0) {
162 tail = head.attr(sym->
name);
173 for (
i = 0;
i < nindex; ++
i) {
174 nb::object arg = nb::steal(
nrnpy_hoc_pop(
"isfunc py2n_component"));
188 if (mes.is_valid()) {
189 Fprintf(stderr,
"%s\n", mes.c_str());
192 if (PyErr_Occurred()) {
202 "%d dimensional python objects "
203 "can't be accessed from hoc with var._[i1][i2]... syntax. "
204 "Must use var._[i1]._[i2]... hoc syntax.",
229 double d =
static_cast<double>(nb::float_(
result));
253 if (
type == NUMBER) {
254 poright = nb::steal(PyFloat_FromDouble(
hoc_xpop()));
256 poright = nb::steal(Py_BuildValue(
"s", *
hoc_strpop()));
262 hoc_execerror(
"Cannot assign that type to PythonObject", (
char*) 0);
265 assert(o == stack_value.get());
271 err = PyObject_SetAttrString(poleft.ptr(), sym->
name, poright.ptr());
272 }
else if (nindex == 1) {
275 auto key = nb::steal(PyLong_FromDouble(
hoc_xpop()));
277 if (strcmp(sym->
name,
"_") == 0) {
278 a = nb::borrow(poleft);
280 a = nb::steal(PyObject_GetAttrString(poleft.ptr(), sym->
name));
283 err = PyObject_SetItem(a.ptr(),
key.ptr(), poright.ptr());
289 "%d dimensional python objects "
290 "can't be accessed from hoc with var._[i1][i2]... syntax. "
291 "Must use var._[i1]._[i2]... hoc syntax.",
301 if (nb::tuple::check_(po)) {
302 nb::object args = po[1];
303 if (!nb::tuple::check_(args)) {
304 args = nb::make_tuple(args);
319 nanobind::gil_scoped_acquire
lock{};
323 auto po = nb::steal(Py_BuildValue(
"(OO)",
pc.ptr(), pv.ptr()));
327 if (mes.is_valid()) {
328 Fprintf(stderr,
"%s\n", mes.c_str());
331 if (PyErr_Occurred()) {
336 return static_cast<double>(nb::float_(r));
340 nanobind::gil_scoped_acquire
lock{};
345 if (mes.is_valid()) {
346 std::string tmp =
"Python Callback failed [hoccommand_exec]:\n";
350 if (PyErr_Occurred()) {
358 nanobind::gil_scoped_acquire
lock{};
364 strncpy(
buf, str.c_str(), size);
365 buf[size - 1] =
'\0';
368 if (mes.is_valid()) {
369 Fprintf(stderr,
"%s\n", mes.c_str());
372 if (PyErr_Occurred()) {
381 nanobind::gil_scoped_acquire
lock{};
383 nb::tuple args = nb::make_tuple(
type, x, y,
key);
387 if (mes.is_valid()) {
388 Fprintf(stderr,
"%s\n", mes.c_str());
391 if (PyErr_Occurred()) {
399 nanobind::gil_scoped_acquire
lock{};
401 auto args = nb::steal(PyTuple_New((Py_ssize_t)
narg));
405 for (
int i = 0;
i <
narg; ++
i) {
411 if (PyTuple_SetItem(args.ptr(), (Py_ssize_t) (
narg -
i - 1), item.release().ptr()) != 0) {
416 nb::tuple r = nb::make_tuple(po, args);
425 nanobind::gil_scoped_acquire
lock{};
428 for (
int i = 0;
i <
narg; ++
i) {
442 if (mes.is_valid()) {
443 Fprintf(stderr,
"%s\n", mes.c_str());
445 if (PyErr_Occurred()) {
459 rval =
static_cast<double>(nb::float_(r));
469 nb::gil_scoped_acquire
lock{};
471 if (nb::sequence::check_(po[0]) || nb::mapping::check_(po[0])) {
472 return nb::cast<double>(po[0][po[1]]);
474 return nb::cast<double>(po[0].attr(po[1]));
479 nb::gil_scoped_acquire
lock{};
481 if (nb::sequence::check_(po[0]) || nb::mapping::check_(po[0])) {
484 po[0].attr(po[1]) = x;
489 nb::gil_scoped_acquire
lock{};
491 auto name = nb::cast<std::string>(po[0].attr(po[1]));
492 if (*cpp &&
name == *cpp) {
498 *cpp =
new char[
name.size() + 1];
499 strcpy(*cpp,
name.c_str());
510 nb::module_
pickle = nb::module_::import_(
"pickle");
514 hoc_execerror(
"Neither Python cPickle nor pickle are available", 0);
526 auto r = nb::borrow<nb::bytes>(
dumps(nb::borrow(
p)));
527 if (!r && PyErr_Occurred()) {
531 return std::vector<char>(r.c_str(), r.c_str() + r.size());
543 static nb::object
unpickle(
const char*
s, std::size_t len) {
544 return loads(nb::bytes(
s, len));
547 static nb::object
unpickle(
const std::vector<char>&
s) {
562 if (PyErr_Occurred() && PyErr_ExceptionMatches(PyExc_Exception)) {
563 PyObject *ptype, *pvalue, *ptraceback;
564 PyErr_Fetch(&ptype, &pvalue, &ptraceback);
565 PyErr_NormalizeException(&ptype, &pvalue, &ptraceback);
567 auto type = nb::steal(ptype);
568 auto value = nb::steal(pvalue);
569 auto traceback = nb::steal(ptraceback);
578 traceback = nb::none();
580 nb::module_ pyth_module = nb::module_::import_(
"neuron");
582 nb::callable pyth_func = pyth_module.attr(
"format_exception");
584 py_str = nb::str(pyth_func(
type,
value, traceback));
593 Fprintf(stderr,
"nrnpyerr_str failed\n");
606 nb::bytes ps(fname.data(), fname.size());
608 auto callable = nb::borrow<nb::callable>(
loads(ps));
612 for (
int i = 0;
i <
narg; ++
i) {
616 nb::object
result = callable(*args);
619 if (mes.is_valid()) {
620 Fprintf(stderr, fmt::format(
"{}\n", mes.c_str()).c_str());
623 if (PyErr_Occurred()) {
636 displ[
i + 1] = displ[
i] + cnts[
i];
642 const std::vector<int>&
cnt,
643 const std::vector<int>& displ) {
645 for (
int i = 0;
i <
cnt.size(); ++
i) {
647 plist.append(nb::none());
661 std::vector<int> rcnt(
np);
663 nrnmpi_int_allgather_inplace(rcnt.data(), 1);
664 auto rdispl =
mk_displ(rcnt.data());
665 std::vector<char> rbuf(rdispl[
np]);
667 nrnmpi_char_allgatherv(sbuf.data(), rbuf.data(), rcnt.data(), rdispl.data());
669 return char2pylist(rbuf, rcnt, rdispl).release().ptr();
677 int scnt =
static_cast<int>(sbuf.size());
678 std::vector<int> rcnt;
682 nrnmpi_int_gather(&scnt, rcnt.data(), 1,
root);
683 std::vector<int> rdispl;
684 std::vector<char> rbuf;
687 rbuf.resize(rdispl[
np]);
690 nrnmpi_char_gatherv(sbuf.data(), scnt, rbuf.data(), rcnt.data(), rdispl.data(),
root);
692 nb::object pdest = nb::none();
696 return pdest.release().ptr();
702 std::vector<char>
buf{};
706 cnt =
static_cast<int>(
buf.size());
717 pdest = nb::borrow(psrc);
719 return pdest.release().ptr();
733 if (!PyList_Check(psrc.ptr())) {
736 if (PyList_Size(psrc.ptr()) !=
np) {
748 auto pdest = nb::borrow(PyList_GetItem(psrc.ptr(), 0));
765 pdest = nb::steal(PyList_New(1));
766 PyList_SetItem(pdest.ptr(), 0, psrc.release().ptr());
783 }
else if (
type != 1 &&
type != 5) {
785 if (root < 0 || root >=
np) {
790 }
else if (
type == 4) {
799 std::vector<char>
s{};
800 std::vector<int> scnt{};
812 const std::vector<char> b =
pickle(
p.ptr());
814 s.insert(std::end(
s), std::begin(b), std::end(b));
816 scnt.push_back(
static_cast<int>(b.size()));
828 std::vector<int> ones(
np, 1);
829 auto sdispl =
mk_displ(ones.data());
830 std::vector<int> rcnt(
np);
832 scnt.data(), ones.data(), sdispl.data(), rcnt.data(), ones.data(), sdispl.data());
836 auto rdispl =
mk_displ(rcnt.data());
838 pdest = nb::make_tuple(sdispl[
np], rdispl[
np]);
840 std::vector<char> r(rdispl[
np] + 1);
841 nrnmpi_char_alltoallv(
842 s.data(), scnt.data(), sdispl.data(), r.data(), rcnt.data(), rdispl.data());
851 nrnmpi_int_scatter(scnt.data(), &rcnt, 1,
root);
852 std::vector<char> r(rcnt + 1);
853 std::vector<int> sdispl;
859 nrnmpi_char_scatterv(
s.data(), scnt.data(), sdispl.data(), r.data(), rcnt,
root);
893 return PyEval_SaveThread();
896 PyEval_RestoreThread(g);
907 delete static_cast<Py2Nrn*
>(
v);
static void nrnmpi_int_alltoallv(const int *s, const int *scnt, const int *sdispl, int *r, int *rcnt, int *rdispl)
static neuron::unique_cstr as_ascii(PyObject *python_string)
static neuron::unique_cstr get_pyerr()
A RAII wrapper for C-style strings.
char * release()
Releases ownership of the string.
void class2oc(const char *, ctor_f *cons, dtor_f *destruct, Member_func *, Member_ret_obj_func *, Member_ret_str_func *)
static double interp(double frac, double x1, double x2)
void hoc_pushstr(char **d)
void hoc_execerr_ext(const char *fmt,...)
printf style specification of hoc_execerror message.
Object * hoc_new_object(Symbol *symtemp, void *v)
char ** hoc_temp_charptr(void)
void hoc_obj_ref(Object *obj)
char * hoc_object_name(Object *ob)
Symbol * hoc_lookup(const char *)
void hoc_push_object(Object *d)
TmpObject hoc_pop_object()
Object ** hoc_objgetarg(int)
void hoc_execerror(const char *s1, const char *s2)
handle_interface< non_owning_identifier< storage > > handle
Non-owning handle to a Mechanism instance.
int const size_t const size_t n
Symbol * nrnpy_pyobj_sym_
int nrnpy_numbercheck(PyObject *po)
Object ** hoc_objpop()
Pop pointer to object pointer and return top elem from stack.
int hoc_stack_type()
Get the type of the top entry.
void hoc_tobj_unref(Object **)
PyObject * hocobj_call_arg(int i)
Object * nrnpy_po2ho(PyObject *po)
PyObject * nrnpy_ho2po(Object *o)
PyObject * nrnpy_hoc_pop(const char *mes)
NPySecObj * newpysechelp(Section *sec)
std::vector< char > call_picklef(const std::vector< char > &fname, int narg)
static int guigetstr(Object *ho, char **cpp)
static double func_call(Object *ho, int narg, int *err)
static std::vector< char > pickle(PyObject *p)
static double guigetval(Object *ho)
static neuron::unique_cstr nrnpyerr_str()
Full python traceback error message returned as string.
static Object * pickle2po(const std::vector< char > &s)
static nb::object nrnpy_pyCallObject(nb::callable, nb::object)
void nrnpython_reg_real_nrnpy_hoc_cpp(neuron::python::impl_ptrs *ptrs)
static void grphcmdtool(Object *ho, int type, double x, double y, int key)
static void py2n_component(Object *ob, Symbol *sym, int nindex, int isfunc)
static int hoccommand_exec(Object *ho)
static nb::object hoccommand_exec_help1(nb::object po)
NRN_EXPORT void nrnpython_reg_real(neuron::python::impl_ptrs *ptrs)
Populate NEURON state with information from a specific Python.
Object * nrnpy_pyobject_in_obj(PyObject *po)
static std::vector< char > po2pickle(Object *ho)
static double praxis_efun(Object *ho, Object *v)
static void restore_thread(PyThreadState *g)
static void p_destruct(void *v)
void nrnpython_reg_real_nrnpython_cpp(neuron::python::impl_ptrs *ptrs)
static int pysame(Object *o1, Object *o2)
static PyThreadState * save_thread()
static std::vector< int > mk_displ(int *cnts)
static nb::object unpickle(const char *s, std::size_t len)
static PyObject * main_module
static void * opaque_obj2pyobj(Object *ho)
PyObject * nrnpy_hoc2pyobject(Object *ho)
static nb::callable loads
static nb::callable dumps
static PyObject * main_namespace
static Object * py_alltoall_type(int size, int type)
static void guisetval(Object *ho, double x)
static Object * callable_with_args(Object *ho, int narg)
static void call_python_with_section(Object *pyact, Section *sec)
static nb::list char2pylist(const std::vector< char > &buf, const std::vector< int > &cnt, const std::vector< int > &displ)
int nrnpy_ho_eq_po(Object *ho, PyObject *po)
static void * p_cons(Object *)
static int hoccommand_exec_strret(Object *ho, char *buf, int size)
static void hpoasgn(Object *o, int type)
static nb::object hoccommand_exec_help(Object *ho)
bool is_python_string(PyObject *python_string)
HOC interpreter function declarations (included by hocdec.h)
static Object ** py_gather(void *)
static void nrnmpi_char_broadcast(char *, int, int)
static Object ** py_broadcast(void *)
static void nrnmpi_int_broadcast(int *, int, int)
static Object ** py_allgather(void *)
Collection of pointers to functions with python-version-specific implementations.
void(* cmdtool)(Object *, int type, double x, double y, int kd)
int(* guigetstr)(Object *, char **)
std::vector< char >(* call_picklef)(const std::vector< char > &, int narg)
Object *(* callable_with_args)(Object *, int narg)
PyThreadState *(* save_thread)()
void(* hpoasgn)(Object *, int)
std::vector< char >(* po2pickle)(Object *)
void(* restore_thread)(PyThreadState *)
int(* hoccommand_exec_strret)(Object *, char *, int)
void *(* opaque_obj2pyobj)(Object *)
double(* guigetval)(Object *)
Object *(* po2ho)(PyObject *)
PyObject *(* ho2po)(Object *)
void(* py2n_component)(Object *, Symbol *, int, int)
double(* call_func)(Object *, int, int *)
void(* guisetval)(Object *, double)
int(* pysame)(Object *o1, Object *o2)
Object *(* mpi_alltoall_type)(int, int)
double(* praxis_efun)(Object *pycallable, Object *hvec)
int(* hoccommand_exec)(Object *)
Object *(* pickle2po)(const std::vector< char > &)
void(* call_python_with_section)(Object *, Section *)
int Fprintf(FILE *stream, const char *fmt, Args... args)