NEURON
nrnpy_hoc.cpp
Go to the documentation of this file.
1 #include <nrnpython.h>
2 #include <structmember.h>
3 #include <InterViews/resource.h>
4 #include <nrnoc2iv.h>
5 #include <ocjump.h>
6 #include "ivocvect.h"
7 #include "oclist.h"
8 #include "ocfile.h"
9 #include <cstdint>
10 #include "nrniv_mf.h"
11 #include "nrnpy_utils.h"
12 #include "../nrniv/shapeplt.h"
13 #include <vector>
14 #include "nrnwrap_dlfcn.h"
15 
16 #if defined(NRNPYTHON_DYNAMICLOAD) && NRNPYTHON_DYNAMICLOAD > 0
17 // when compiled with different Python.h, force correct value
18 #undef NRNPYTHON_DYNAMICLOAD
19 #define NRNPYTHON_DYNAMICLOAD PY_MAJOR_VERSION
20 #endif
21 
22 extern PyTypeObject* psection_type;
23 
24 // copied from nrnpy_nrn
25 typedef struct {
26  PyObject_HEAD Section* sec_;
27  char* name_;
28  PyObject* cell_;
29 } NPySecObj;
30 
31 
32 #include "parse.hpp"
33 extern void (*nrnpy_sectionlist_helper_)(void*, Object*);
34 extern Object** (*nrnpy_gui_helper_)(const char*, Object*);
35 extern Object** (*nrnpy_gui_helper3_)(const char*, Object*, int);
36 extern char** (*nrnpy_gui_helper3_str_)(const char*, Object*, int);
37 extern double (*nrnpy_object_to_double_)(Object*);
38 extern void* (*nrnpy_get_pyobj)(Object* obj);
39 extern void (*nrnpy_restore_savestate)(int64_t, char*);
40 extern void (*nrnpy_store_savestate)(char** save_data, uint64_t* save_data_size);
41 extern void (*nrnpy_decref)(void* pyobj);
42 extern void lvappendsec_and_ref(void* sl, Section* sec);
43 extern Section* nrn_noerr_access();
44 extern void hoc_pushs(Symbol*);
45 extern double* hoc_evalpointer();
46 extern double cable_prop_eval(Symbol* sym);
47 extern void nrn_change_nseg(Section*, int);
50 extern Inst* hoc_pc;
51 extern void hoc_push_string();
52 extern char** hoc_strpop();
53 extern void hoc_objectvar();
54 extern Object* hoc_newobj1(Symbol*, int);
55 extern int ivoc_list_count(Object*);
56 extern Object** hoc_objpop();
58 extern void hoc_object_component();
59 extern int nrn_inpython_;
60 extern int hoc_stack_type();
61 extern void hoc_call();
63 extern void hoc_tobj_unref(Object**);
64 extern void hoc_unref_defer();
65 extern void sec_access_push();
66 extern PyObject* nrnpy_pushsec(PyObject*);
67 extern bool hoc_valid_stmt(const char*, Object*);
68 PyObject* nrnpy_nrn();
69 extern PyObject* nrnpy_cas(PyObject*, PyObject*);
70 extern PyObject* nrnpy_forall(PyObject*, PyObject*);
71 extern PyObject* nrnpy_newsecobj(PyObject*, PyObject*, PyObject*);
72 extern int section_object_seen;
73 extern Symbol* nrnpy_pyobj_sym_;
74 extern Symbol* nrn_child_sym;
75 extern int nrn_secref_nchild(Section*);
76 extern PyObject* nrnpy_hoc2pyobject(Object*);
77 PyObject* nrnpy_ho2po(Object*);
78 Object* nrnpy_po2ho(PyObject*);
79 extern Object* nrnpy_pyobject_in_obj(PyObject*);
80 static void pyobject_in_objptr(Object**, PyObject*);
81 extern IvocVect* (*nrnpy_vec_from_python_p_)(void*);
82 extern Object** (*nrnpy_vec_to_python_p_)(void*);
83 extern Object** (*nrnpy_vec_as_numpy_helper_)(int, double*);
84 extern Object* (*nrnpy_rvp_rxd_to_callable)(Object*);
85 extern "C" int nrnpy_set_vec_as_numpy(PyObject* (*p)(int, double*) ); // called by ctypes.
86 extern "C" int nrnpy_set_gui_callback(PyObject*);
87 extern double** nrnpy_setpointer_helper(PyObject*, PyObject*);
88 extern Symbol* ivoc_alias_lookup(const char* name, Object* ob);
89 class NetCon;
90 extern int nrn_netcon_weight(NetCon*, double**);
91 extern int nrn_matrix_dim(void*, int);
93 
94 extern PyObject* pmech_types; // Python map for name to Mechanism
95 extern PyObject* rangevars_; // Python map for name to Symbol
96 
97 extern int hoc_max_builtin_class_id;
98 extern int hoc_return_type_code;
99 
103 
104 // typestr returned by Vector.__array_interface__
105 // byteorder (first element) is modified at import time
106 // to reflect the system byteorder
107 // Allocate one extra character space in case we have a two character integer of
108 // bytes per double
109 // i.e. 16
110 static char array_interface_typestr[5] = "|f8";
111 
112 // static pointer to neurons.doc.get_docstring function initialized at import
113 // time
114 static PyObject* pfunc_get_docstring = NULL;
115 
116 // Methods unique to the HocTopLevelInterpreter type of HocObject
117 // follow the add_methods implementation of python3.6.2 in typeobject.c
118 // and the GenericGetAttr implementation in object.c
119 static PyObject* topmethdict = NULL;
120 static void add2topdict(PyObject*);
121 
122 static const char* hocobj_docstring = "class neuron.hoc.HocObject - Hoc Object wrapper";
123 
124 #if 1
125 #include <hoccontext.h>
126 #else
127 extern Object* hoc_thisobject;
128 #define HocTopContextSet \
129  if (hoc_thisobject) { \
130  abort(); \
131  } \
132  assert(hoc_thisobject == 0);
133 #define HocContextRestore /**/
134 #endif
135 
136 typedef struct {
137  PyObject_HEAD Object* ho_;
138  union {
139  double x_;
140  char* s_;
141  char** pstr_;
143  double* px_;
145  } u;
146  Symbol* sym_; // for functions and arrays
147  void* iteritem_; // enough info to carry out Iterator protocol
148  int nindex_; // number indices seen so far (or narg)
149  int* indices_; // one fewer than nindex_
151 } PyHocObject;
152 
153 static PyObject* rvp_plot = NULL;
154 static PyObject* plotshape_plot = NULL;
155 static PyObject* cpp2refstr(char** cpp);
156 static PyObject* get_mech_object_ = NULL;
157 static PyObject* nrnpy_rvp_pyobj_callback = NULL;
158 
159 PyTypeObject* hocobject_type;
160 static PyObject* hocobj_call(PyHocObject* self, PyObject* args, PyObject* kwrds);
161 
162 static PyObject* nrnexec(PyObject* self, PyObject* args) {
163  const char* cmd;
164  if (!PyArg_ParseTuple(args, "s", &cmd)) {
165  return NULL;
166  }
167  bool b = hoc_valid_stmt(cmd, 0);
168  return Py_BuildValue("i", b ? 1 : 0);
169 }
170 
171 static PyObject* hoc_ac(PyObject* self, PyObject* args) {
172  PyArg_ParseTuple(args, "|d", &hoc_ac_);
173  return Py_BuildValue("d", hoc_ac_);
174 }
175 
176 static PyMethodDef HocMethods[] = {
177  {"execute", nrnexec, METH_VARARGS, "Execute a hoc command, return 1 on success, 0 on failure."},
178  {"hoc_ac", hoc_ac, METH_VARARGS, "Get (or set) the scalar hoc_ac_."},
179  {NULL, NULL, 0, NULL}};
180 
181 static void hocobj_dealloc(PyHocObject* self) {
182  // printf("hocobj_dealloc %p\n", self);
183  if (self->ho_) {
184  hoc_obj_unref(self->ho_);
185  }
186  if (self->type_ == PyHoc::HocRefStr && self->u.s_) {
187  // delete [] self->u.s_;
188  free(self->u.s_);
189  }
190  if (self->type_ == PyHoc::HocRefObj && self->u.ho_) {
191  hoc_obj_unref(self->u.ho_);
192  }
193  if (self->indices_) {
194  delete[] self->indices_;
195  }
196  if (self->type_ == PyHoc::HocRefPStr && self->u.pstr_) {
197  // nothing deleted
198  }
199  ((PyObject*) self)->ob_type->tp_free((PyObject*) self);
200 
201  // Deferred deletion of HOC Objects is unnecessary when a HocObject is
202  // destroyed. And we would like to have prompt deletion if this HocObject
203  // wrapped a HOC Object whose refcount was 1.
204  hoc_unref_defer();
205 }
206 
207 static PyObject* hocobj_new(PyTypeObject* subtype, PyObject* args, PyObject* kwds) {
208  PyObject* subself;
209  subself = subtype->tp_alloc(subtype, 0);
210  // printf("hocobj_new %s %p\n", subtype->tp_name, subself);
211  if (subself == NULL) {
212  return NULL;
213  }
214  PyHocObject* self = (PyHocObject*) subself;
215  self->ho_ = NULL;
216  self->u.x_ = 0.;
217  self->sym_ = NULL;
218  self->indices_ = NULL;
219  self->nindex_ = 0;
220  self->type_ = PyHoc::HocTopLevelInterpreter;
221  self->iteritem_ = 0;
222  if (kwds && PyDict_Check(kwds)) {
223  PyObject* base = PyDict_GetItemString(kwds, "hocbase");
224  if (base) {
225  int ok = 0;
226  if (PyObject_TypeCheck(base, hocobject_type)) {
227  PyHocObject* hbase = (PyHocObject*) base;
228  if (hbase->type_ == PyHoc::HocFunction && hbase->sym_->type == TEMPLATE) {
229  // printf("hocobj_new base %s\n", hbase->sym_->name);
230  // remove the hocbase keyword since hocobj_call only allows
231  // the "sec" keyword argument
232  PyDict_DelItemString(kwds, "hocbase");
233  PyObject* r = hocobj_call(hbase, args, kwds);
234  if (!r) {
235  Py_DECREF(subself);
236  return NULL;
237  }
238  PyHocObject* rh = (PyHocObject*) r;
239  self->type_ = rh->type_;
240  self->ho_ = rh->ho_;
241  hoc_obj_ref(self->ho_);
242  Py_DECREF(r);
243  ok = 1;
244  }
245  }
246  if (!ok) {
247  Py_DECREF(subself);
248  PyErr_SetString(PyExc_TypeError, "HOC base class not valid");
249  return NULL;
250  }
251  }
252  }
253  return subself;
254 }
255 
256 static int hocobj_init(PyObject* subself, PyObject* args, PyObject* kwds) {
257 // printf("hocobj_init %s %p\n",
258 // ((PyTypeObject*)PyObject_Type(subself))->tp_name, subself);
259 #if 0
260  if (subself != NULL) {
261  PyHocObject* self = (PyHocObject*)subself;
262  if (self->ho_) { hoc_obj_unref(self->ho_); }
263  self->ho_ = NULL;
264  self->u.x_ = 0.;
265  self->sym_ = NULL;
266  self->indices_ = NULL;
267  self->nindex_ = 0;
268  self->type_ = 0;
269  }
270 #endif
271  return 0;
272 }
273 
274 static void pyobject_in_objptr(Object** op, PyObject* po) {
276  if (*op) {
277  hoc_obj_unref(*op);
278  }
279  *op = o;
280 }
281 
282 static PyObject* hocobj_name(PyObject* pself, PyObject* args) {
283  PyHocObject* self = (PyHocObject*) pself;
284  char buf[512], *cp;
285  buf[0] = '\0';
286  cp = buf;
287  PyObject* po;
288  if (self->type_ == PyHoc::HocObject) {
289  sprintf(cp, "%s", hoc_object_name(self->ho_));
290  } else if (self->type_ == PyHoc::HocFunction || self->type_ == PyHoc::HocArray) {
291  sprintf(cp,
292  "%s%s%s",
293  self->ho_ ? hoc_object_name(self->ho_) : "",
294  self->ho_ ? "." : "",
295  self->sym_->name);
296  if (self->type_ == PyHoc::HocArray) {
297  for (int i = 0; i < self->nindex_; ++i) {
298  sprintf(cp += strlen(cp), "[%d]", self->indices_[i]);
299  }
300  sprintf(cp += strlen(cp), "[?]");
301  } else {
302  sprintf(cp += strlen(cp), "()");
303  }
304  } else if (self->type_ == PyHoc::HocRefNum) {
305  sprintf(cp, "<hoc ref value %g>", self->u.x_);
306  } else if (self->type_ == PyHoc::HocRefStr) {
307  sprintf(cp, "<hoc ref str \"%s\">", self->u.s_);
308  } else if (self->type_ == PyHoc::HocRefPStr) {
309  sprintf(cp, "<hoc ref pstr \"%s\">", *self->u.pstr_);
310  } else if (self->type_ == PyHoc::HocRefObj) {
311  sprintf(cp, "<hoc ref value \"%s\">", hoc_object_name(self->u.ho_));
312  } else if (self->type_ == PyHoc::HocForallSectionIterator) {
313  sprintf(cp, "<all section iterator next>");
314  } else if (self->type_ == PyHoc::HocSectionListIterator) {
315  sprintf(cp, "<SectionList iterator>");
316  } else if (self->type_ == PyHoc::HocScalarPtr) {
317  sprintf(cp, "<pointer to hoc scalar %g>", self->u.px_ ? *self->u.px_ : -1e100);
318  } else if (self->type_ == PyHoc::HocArrayIncomplete) {
319  sprintf(cp, "<incomplete pointer to hoc array %s>", self->sym_->name);
320  } else {
321  sprintf(cp, "<TopLevelHocInterpreter>");
322  }
323  po = Py_BuildValue("s", buf);
324  return po;
325 }
326 
327 static PyObject* hocobj_repr(PyObject* p) {
328  return hocobj_name(p, NULL);
329 }
330 
331 static Inst* save_pc(Inst* newpc) {
332  Inst* savpc = hoc_pc;
333  hoc_pc = newpc;
334  return savpc;
335 }
336 
337 static int hocobj_pushargs(PyObject* args, std::vector<char*>& s2free) {
338  int i, narg = PyTuple_Size(args);
339  for (i = 0; i < narg; ++i) {
340  PyObject* po = PyTuple_GetItem(args, i);
341  // PyObject_Print(po, stdout, 0);
342  // printf(" pushargs %d\n", i);
343  if (nrnpy_numbercheck(po)) {
344  PyObject* pn = PyNumber_Float(po);
345  hoc_pushx(PyFloat_AsDouble(pn));
346  Py_XDECREF(pn);
347  } else if (is_python_string(po)) {
348  char** ts = hoc_temp_charptr();
349  Py2NRNString str(po, /* disable_release */ true);
350  if (str.err()) {
351  // Since Python error has been set, need to clear, or hoc_execerror
352  // printing with nrnpy_pr will generate a
353  // Exception ignored on calling ctypes callback function.
354  // So get the message, clear, and make the message
355  // part of the execerror.
356  *ts = str.get_pyerr();
357  s2free.push_back(*ts);
358  hoc_execerr_ext("python string arg cannot decode into c_str. Pyerr message: %s",
359  *ts);
360  }
361  *ts = str.c_str();
362  s2free.push_back(*ts);
363  hoc_pushstr(ts);
364  } else if (PyObject_TypeCheck(po, hocobject_type)) {
365  // The PyObject_TypeCheck above used to be PyObject_IsInstance. The
366  // problem with the latter is that it calls the __class__ method of
367  // the object which can raise an error for nrn.Section, nrn.Segment,
368  // etc. if the internal Section is invalid (Section.prop == NULL).
369  // That, in consequence, will generate an
370  // Exception ignored on calling ctypes callback function: <function nrnpy_pr
371  // thus obscuring the actual error, such as
372  // nrn.Segment associated with deleted internal Section.
373  PyHocObject* pho = (PyHocObject*) po;
374  PyHoc::ObjectType tp = pho->type_;
375  if (tp == PyHoc::HocObject) {
376  hoc_push_object(pho->ho_);
377  } else if (tp == PyHoc::HocRefNum) {
378  hoc_pushpx(&pho->u.x_);
379  } else if (tp == PyHoc::HocRefStr) {
380  hoc_pushstr(&pho->u.s_);
381  } else if (tp == PyHoc::HocRefObj) {
382  hoc_pushobj(&pho->u.ho_);
383  } else if (tp == PyHoc::HocScalarPtr) {
384  hoc_pushpx(pho->u.px_);
385  } else if (tp == PyHoc::HocRefPStr) {
386  hoc_pushstr(pho->u.pstr_);
387  } else {
388  // make a hoc python object and push that
389  Object* ob = NULL;
390  pyobject_in_objptr(&ob, po);
391  hoc_push_object(ob);
392  hoc_obj_unref(ob);
393  }
394  } else { // make a hoc PythonObject and push that?
395  Object* ob = NULL;
396  if (po != Py_None) {
397  pyobject_in_objptr(&ob, po);
398  }
399  hoc_push_object(ob);
400  hoc_obj_unref(ob);
401  }
402  }
403  return narg;
404 }
405 
406 static void hocobj_pushargs_free_strings(std::vector<char*>& s2free) {
407  std::vector<char*>::iterator it = s2free.begin();
408  for (; it != s2free.end(); ++it) {
409  if (*it) {
410  free(*it);
411  }
412  }
413  s2free.clear();
414 }
415 
416 static Symbol* getsym(char* name, Object* ho, int fail) {
417  Symbol* sym = 0;
418  if (ho) {
419  sym = hoc_table_lookup(name, ho->ctemplate->symtable);
420  if (!sym && strcmp(name, "delay") == 0) {
421  sym = hoc_table_lookup("del", ho->ctemplate->symtable);
422  } else if (!sym && ho->aliases) {
423  sym = ivoc_alias_lookup(name, ho);
424  }
425  } else {
427  if (!sym) {
429  }
430  }
431  if (sym && sym->type == UNDEF) {
432  sym = 0;
433  }
434  if (!sym && fail) {
435  char e[200];
436  sprintf(e, "'%s' is not a defined hoc variable name.", name);
437  PyErr_SetString(PyExc_LookupError, e);
438  }
439  return sym;
440 }
441 
442 // on entry the stack order is indices, args, object
443 // on exit all that is popped and the result is on the stack
444 // returns hoc_return_is_int if called on a builtin (i.e. 2 if bool, 1 if int, 0 otherwise)
445 static int component(PyHocObject* po) {
446  Inst fc[6];
447  int var_type = 0;
449  fc[0].sym = po->sym_;
450  fc[1].i = 0;
451  fc[2].i = 0;
452  fc[5].i = 0;
453  if (po->type_ == PyHoc::HocFunction) {
454  fc[2].i = po->nindex_;
455  fc[5].i = 1;
456  } else if (po->type_ == PyHoc::HocArray || po->type_ == PyHoc::HocArrayIncomplete) {
457  fc[1].i = po->nindex_;
458  }
459  Object* stack_value = hoc_obj_look_inside_stack(po->nindex_);
460  assert(stack_value == po->ho_);
461  fc[3].i = po->ho_->ctemplate->id;
462  fc[4].sym = po->sym_;
463  Inst* pcsav = save_pc(fc);
465  hoc_pc = pcsav;
466  // only return a type if we're calling a built-in (these are all registered first)
467  if (po->ho_->ctemplate->id <= hoc_max_builtin_class_id) {
468  var_type = hoc_return_type_code;
469  }
471  return (var_type);
472 }
473 
474 int nrnpy_numbercheck(PyObject* po) {
475  // PyNumber_Check can return 1 for things that should not reasonably
476  // be cast to float but should stay as python objects.
477  // e.g. numpy.arange(1,5) and 5J
478  // The complexity here is partly due to SAGE having its own
479  // number system, e.g. type(1) is <type 'sage.rings.integer.Integer'>
480  int rval = PyNumber_Check(po);
481  // but do not allow sequences
482  if (rval == 1 && po->ob_type->tp_as_sequence) {
483  rval = 0;
484  }
485  // or things that fail when float(po) fails. ARGGH! This
486  // is a lot more expensive than I would like.
487  if (rval == 1) {
488  PyObject* tmp = PyNumber_Float(po);
489  if (tmp) {
490  Py_DECREF(tmp);
491  } else {
492  PyErr_Clear();
493  rval = 0;
494  }
495  }
496  return rval;
497 }
498 
499 PyObject* nrnpy_ho2po(Object* o) {
500  // o may be NULLobject, or encapsulate a Python object (via
501  // the PythonObject class in hoc (see Py2Nrn in nrnpy_p2h.cpp),
502  // or be a native hoc class instance such as Graph.
503  // The return value is None, or the encapsulated PyObject or
504  // an encapsulating PyHocObject
505  PyObject* po;
506  if (!o) {
507  po = Py_BuildValue("");
508  } else if (o->ctemplate->sym == nrnpy_pyobj_sym_) {
509  po = nrnpy_hoc2pyobject(o);
510  Py_INCREF(po);
511  } else {
512  po = hocobj_new(hocobject_type, 0, 0);
513  ((PyHocObject*) po)->ho_ = o;
514  ((PyHocObject*) po)->type_ = PyHoc::HocObject;
515  hoc_obj_ref(o);
516  }
517  return po;
518 }
519 
520 Object* nrnpy_po2ho(PyObject* po) {
521  // po may be None, or encapsulate a hoc object (via the
522  // PyHocObject, or be a native Python instance such as [1,2,3]
523  // The return value is None, or the encapsulated hoc object,
524  // or a hoc object of type PythonObject that encapsulates the
525  // po.
526  Object* o;
527  if (po == Py_None) {
528  o = 0;
529  } else if (PyObject_TypeCheck(po, hocobject_type)) {
530  PyHocObject* pho = (PyHocObject*) po;
531  if (pho->type_ == PyHoc::HocObject) {
532  o = pho->ho_;
533  hoc_obj_ref(o);
534  } else if (pho->type_ == PyHoc::HocRefObj) {
535  o = pho->u.ho_;
536  hoc_obj_ref(o);
537  } else {
538  // all the rest encapsulate
539  o = nrnpy_pyobject_in_obj(po);
540  }
541  } else { // even if Python string or number
542  o = nrnpy_pyobject_in_obj(po);
543  }
544  return o;
545 }
546 
547 PyObject* nrnpy_hoc_pop() {
548  PyObject* result = 0;
549  Object* ho;
550  Object** d;
551  switch (hoc_stack_type()) {
552  case STRING:
553  result = Py_BuildValue("s", *hoc_strpop());
554  break;
555  case VAR: {
556  double* px = hoc_pxpop();
557  if (px) {
558  // unfortunately, this is nonsense if NMODL POINTER is pointing
559  // to something other than a double.
560  result = Py_BuildValue("d", *px);
561  } else {
562  PyErr_SetString(PyExc_AttributeError, "POINTER is NULL");
563  }
564  } break;
565  case NUMBER:
566  result = Py_BuildValue("d", hoc_xpop());
567  break;
568  case OBJECTVAR:
569  case OBJECTTMP:
570  d = hoc_objpop();
571  ho = *d;
572  // printf("Py2Nrn %p %p\n", ho->ctemplate->sym, nrnpy_pyobj_sym_);
573  result = nrnpy_ho2po(ho);
574  hoc_tobj_unref(d);
575  break;
576  default:
577  printf("nrnpy_hoc_pop error: stack type = %d\n", hoc_stack_type());
578  }
579  return result;
580 }
581 
582 static int set_final_from_stk(PyObject* po) {
583  int err = 0;
584  switch (hoc_stack_type()) {
585  case STRING:
586  char* s;
587  if (PyArg_Parse(po, "s", &s) == 1) {
589  } else {
590  err = 1;
591  }
592  break;
593  case VAR: {
594  double x;
595  double* px;
596  if (PyArg_Parse(po, "d", &x) == 1) {
597  px = hoc_pxpop();
598  if (px) {
599  // This is a future crash if NMODL POINTER is pointing
600  // to something other than a double.
601  *px = x;
602  } else {
603  PyErr_SetString(PyExc_AttributeError, "POINTER is NULL");
604  return -1;
605  }
606  } else {
607  err = 1;
608  }
609  } break;
610  case OBJECTVAR:
611  PyHocObject* pho;
612  if (PyArg_Parse(po, "O!", hocobject_type, &pho) == 1) {
613  Object** pobj = hoc_objpop();
614  if (pho->sym_) {
615  PyErr_SetString(PyExc_TypeError, "argument cannot be a hoc object intermediate");
616  return -1;
617  }
618  Object* ob = *pobj;
619  hoc_obj_ref(pho->ho_);
620  hoc_obj_unref(ob);
621  *pobj = pho->ho_;
622  } else {
623  err = 1;
624  }
625  break;
626  default:
627  printf("set_final_from_stk() error: stack type = %d\n", hoc_stack_type());
628  err = 1;
629  break;
630  }
631  return err;
632 }
633 
634 
635 static void* nrnpy_hoc_int_pop() {
636  return (void*) Py_BuildValue("i", (long) hoc_xpop());
637 }
638 
639 static void* nrnpy_hoc_bool_pop() {
640  return (void*) PyBool_FromLong((long) hoc_xpop());
641 }
642 
643 static void* fcall(void* vself, void* vargs) {
644  PyHocObject* self = (PyHocObject*) vself;
645  if (self->ho_) {
646  hoc_push_object(self->ho_);
647  }
648 
649  // TODO: this will still have some memory leaks in case of errors.
650  // see discussion in https://github.com/neuronsimulator/nrn/pull/1437
651  std::vector<char*> strings_to_free;
652 
653  int narg = hocobj_pushargs((PyObject*) vargs, strings_to_free);
654  int var_type;
655  if (self->ho_) {
656  self->nindex_ = narg;
657  var_type = component(self);
658  hocobj_pushargs_free_strings(strings_to_free);
659  switch (var_type) {
660  case 2:
661  return nrnpy_hoc_bool_pop();
662  case 1:
663  return nrnpy_hoc_int_pop();
664  default:
665  return (void*) nrnpy_hoc_pop();
666  }
667  }
668  if (self->sym_->type == BLTIN) {
669  if (narg != 1) {
670  hoc_execerror("must be one argument for", self->sym_->name);
671  }
672  double d = hoc_call_func(self->sym_, 1);
673  hoc_pushx(d);
674  } else if (self->sym_->type == TEMPLATE) {
675  Object* ho = hoc_newobj1(self->sym_, narg);
677  result->ho_ = ho;
678  result->type_ = PyHoc::HocObject;
679  hocobj_pushargs_free_strings(strings_to_free);
680  return result;
681  } else {
682  HocTopContextSet Inst fc[4];
683  // ugh. so a potential call of hoc_get_last_pointer_symbol will return nil.
684  fc[0].in = STOP;
685  fc[1].sym = self->sym_;
686  fc[2].i = narg;
687  fc[3].in = STOP;
688  Inst* pcsav = save_pc(fc + 1);
689  hoc_call();
690  hoc_pc = pcsav;
692  }
693  hocobj_pushargs_free_strings(strings_to_free);
694 
695  return (void*) nrnpy_hoc_pop();
696 }
697 
698 static PyObject* curargs_;
699 
700 PyObject* hocobj_call_arg(int i) {
701  return PyTuple_GetItem(curargs_, i);
702 }
703 
704 static PyObject* hocobj_call(PyHocObject* self, PyObject* args, PyObject* kwrds) {
705  // Hack to allow some python only methods to get the python args.
706  // without losing info about type bool, int, etc.
707  // eg pc.py_broadcast, pc.py_gather, pc.py_allgather
708  PyObject* prevargs_ = curargs_;
709  curargs_ = args;
710 
711  PyObject* section = 0;
712  PyObject* result;
713  if (kwrds && PyDict_Check(kwrds)) {
714 #if 0
715  PyObject* keys = PyDict_Keys(kwrds);
716  assert(PyList_Check(keys));
717  int n = PyList_Size(keys);
718  for (int i = 0; i < n; ++i) {
719  PyObject* key = PyList_GetItem(keys, i);
720  PyObject* value = PyDict_GetItem(kwrds, key);
721  printf("%s %s\n", PyUnicode_AsUTF8(key), PyUnicode_AsUTF8(PyObject_Str(value)));
722  }
723 #endif
724  section = PyDict_GetItemString(kwrds, "sec");
725  int num_kwargs = PyDict_Size(kwrds);
726  if (num_kwargs > 1) {
727  PyErr_SetString(PyExc_RuntimeError, "invalid keyword argument");
728  curargs_ = prevargs_;
729  return NULL;
730  }
731  if (section) {
732  if (PyObject_TypeCheck(section, psection_type)) {
733  Section* sec = ((NPySecObj*) section)->sec_;
734  if (!sec->prop) {
736  curargs_ = prevargs_;
737  return NULL;
738  }
739  nrn_pushsec(sec);
740  } else {
741  PyErr_SetString(PyExc_TypeError, "sec is not a Section");
742  curargs_ = prevargs_;
743  return NULL;
744  }
745  } else {
746  if (num_kwargs) {
747  PyErr_SetString(PyExc_RuntimeError, "invalid keyword argument");
748  curargs_ = prevargs_;
749  return NULL;
750  }
751  }
752  }
753  if (self->type_ == PyHoc::HocTopLevelInterpreter) {
754  result = nrnexec((PyObject*) self, args);
755  } else if (self->type_ == PyHoc::HocFunction) {
756  OcJump* oj;
757  oj = new OcJump();
758  if (oj) {
759  result = (PyObject*) oj->fpycall(fcall, (void*) self, (void*) args);
760  delete oj;
761  if (result == NULL) {
762  PyErr_SetString(PyExc_RuntimeError, "hocobj_call error");
763  }
764  } else {
765  result = (PyObject*) fcall((void*) self, (void*) args);
766  }
767  hoc_unref_defer();
768  } else {
769  PyErr_SetString(PyExc_TypeError, "object is not callable");
770  curargs_ = prevargs_;
771  return NULL;
772  }
773  if (section) {
774  nrn_popsec();
775  }
776  curargs_ = prevargs_;
777  return result;
778 }
779 
780 static Arrayinfo* hocobj_aray(Symbol* sym, Object* ho) {
781  if (!sym->arayinfo) {
782  return 0;
783  }
784  if (ho) { // objectdata or not?
785  int cplus = (ho->ctemplate->sym->subtype & (CPLUSOBJECT | JAVAOBJECT));
786  if (cplus) {
787  return sym->arayinfo;
788  } else {
789  return ho->u.dataspace[sym->u.oboff + 1].arayinfo;
790  }
791  } else {
792  if (sym->type == VAR &&
793  (sym->subtype == USERDOUBLE || sym->subtype == USERINT || sym->subtype == USERFLOAT)) {
794  return sym->arayinfo;
795  } else {
796  return hoc_top_level_data[sym->u.oboff + 1].arayinfo;
797  }
798  }
799 }
800 
801 static PyHocObject* intermediate(PyHocObject* po, Symbol* sym, int ix) {
803  if (po->ho_) {
804  ponew->ho_ = po->ho_;
805  hoc_obj_ref(po->ho_);
806  }
807  if (ix > -1) { // array, increase dimension by one
808  int j;
809  assert(po->sym_ == sym);
811  ponew->sym_ = sym;
812  ponew->nindex_ = po->nindex_ + 1;
813  ponew->type_ = po->type_;
814  ponew->indices_ = new int[ponew->nindex_];
815  for (j = 0; j < po->nindex_; ++j) {
816  ponew->indices_[j] = po->indices_[j];
817  }
818  ponew->indices_[po->nindex_] = ix;
819  } else { // make it an array (no indices yet)
820  ponew->sym_ = sym;
821  ponew->type_ = PyHoc::HocArray;
822  }
823  return ponew;
824 }
825 
826 // when called, nindex is 1 less than reality
827 static void hocobj_pushtop(PyHocObject* po, Symbol* sym, int ix) {
828  int i;
829  int n = po->nindex_++;
830  // printf("hocobj_pushtop n=%d", po->nindex_);
831  for (i = 0; i < n; ++i) {
832  hoc_pushx((double) po->indices_[i]);
833  // printf(" %d", po->indices_[i]);
834  }
835  hoc_pushx((double) ix);
836  // printf(" %d\n", ix);
837  if (sym) {
838  hoc_pushs(sym);
839  }
840 }
841 
842 static void hocobj_objectvar(Symbol* sym) {
843  Inst fc;
844  fc.sym = sym;
845  Inst* pcsav = save_pc(&fc);
846  hoc_objectvar();
847  hoc_pc = pcsav;
848 }
849 
850 static PyObject* hocobj_getsec(Symbol* sym) {
851  Inst fc;
852  fc.sym = sym;
853  Inst* pcsav = save_pc(&fc);
854  sec_access_push();
855  hoc_pc = pcsav;
856  PyObject* result = nrnpy_cas(0, 0);
857  nrn_popsec();
858  return result;
859 }
860 
861 // leave pointer on stack ready for get/set final
862 static void eval_component(PyHocObject* po, int ix) {
863  int j;
864  hoc_push_object(po->ho_);
865  hocobj_pushtop(po, 0, ix);
866  component(po);
867  --po->nindex_;
868 }
869 
870 extern "C" PyObject* nrn_hocobj_ptr(double* pd) {
871  PyObject* result = hocobj_new(hocobject_type, 0, 0);
872  PyHocObject* po = (PyHocObject*) result;
874  po->u.px_ = pd;
875  return result;
876 }
877 
878 int nrn_is_hocobj_ptr(PyObject* po, double*& pd) {
879  int ret = 0;
880  if (PyObject_TypeCheck(po, hocobject_type)) {
881  PyHocObject* hpo = (PyHocObject*) po;
882  if (hpo->type_ == PyHoc::HocScalarPtr) {
883  pd = hpo->u.px_;
884  ret = 1;
885  }
886  }
887  return ret;
888 }
889 
890 static void symlist2dict(Symlist* sl, PyObject* dict) {
891  PyObject* nn = Py_BuildValue("");
892  for (Symbol* s = sl->first; s; s = s->next) {
893  if (s->type == UNDEF) {
894  continue;
895  }
896  if (s->cpublic == 1 || sl == hoc_built_in_symlist || sl == hoc_top_level_symlist) {
897  if (strcmp(s->name, "del") == 0) {
898  PyDict_SetItemString(dict, "delay", nn);
899  } else {
900  PyDict_SetItemString(dict, s->name, nn);
901  }
902  }
903  }
904  Py_DECREF(nn);
905 }
906 
907 static int setup_doc_system() {
908  PyObject* pdoc;
909  if (pfunc_get_docstring) {
910  return 1;
911  }
912  pdoc = PyImport_ImportModule("neuron.doc");
913  if (pdoc == NULL) {
914  PyErr_SetString(PyExc_ImportError, "Failed to import neuron.doc documentation module.");
915  return 0;
916  }
917  pfunc_get_docstring = PyObject_GetAttrString(pdoc, "get_docstring");
918 
919  if (pfunc_get_docstring == NULL) {
920  PyErr_SetString(PyExc_AttributeError,
921  "neuron.doc module does not have attribute 'get_docstring'!");
922  return 0;
923  }
924  return 1;
925 }
926 
927 PyObject* toplevel_get(PyObject* subself, const char* n) {
928  PyHocObject* self = (PyHocObject*) subself;
929  PyObject* result = NULL;
930  if (self->type_ == PyHoc::HocTopLevelInterpreter) {
931  PyObject* descr = PyDict_GetItemString(topmethdict, n);
932  if (descr) {
933  Py_INCREF(descr);
934  descrgetfunc f = descr->ob_type->tp_descr_get;
935  assert(f);
936  result = f(descr, subself, (PyObject*) Py_TYPE(subself));
937  Py_DECREF(descr);
938  }
939  }
940  return result;
941 }
942 
943 // TODO: This function needs refactoring; there are too many exit points
944 static PyObject* hocobj_getattr(PyObject* subself, PyObject* pyname) {
945  PyHocObject* self = (PyHocObject*) subself;
946  if (self->type_ == PyHoc::HocObject && !self->ho_) {
947  PyErr_SetString(PyExc_TypeError, "not a compound type");
948  return NULL;
949  }
950 
951  PyObject* result = NULL;
952  int isptr = 0;
953  Py2NRNString name(pyname);
954  char* n = name.c_str();
955  if (!n) {
956  name.set_pyerr(PyExc_TypeError, "attribute name must be a string");
957  return NULL;
958  }
959 
960  Symbol* sym = getsym(n, self->ho_, 0);
961  if (!sym) {
962  if (self->type_ == PyHoc::HocObject && self->ho_->ctemplate->sym == nrnpy_pyobj_sym_) {
963  PyObject* p = nrnpy_hoc2pyobject(self->ho_);
964  return PyObject_GenericGetAttr(p, pyname);
965  }
966  if (self->type_ == PyHoc::HocTopLevelInterpreter) {
967  result = toplevel_get(subself, n);
968  if (result) {
969  return result;
970  }
971  }
972  if (strcmp(n, "__dict__") == 0) {
973  // all the public names
974  Symlist* sl = 0;
975  if (self->ho_) {
976  sl = self->ho_->ctemplate->symtable;
977  } else if (self->sym_ && self->sym_->type == TEMPLATE) {
978  sl = self->sym_->u.ctemplate->symtable;
979  }
980  PyObject* dict = PyDict_New();
981  if (sl) {
982  symlist2dict(sl, dict);
983  } else {
986  add2topdict(dict);
987  }
988 
989  // Is the self->ho_ a Vector? If so, add the __array_interface__ symbol
990 
991  if (is_obj_type(self->ho_, "Vector")) {
992  PyDict_SetItemString(dict, "__array_interface__", Py_None);
993  } else if (is_obj_type(self->ho_, "RangeVarPlot") ||
994  is_obj_type(self->ho_, "PlotShape")) {
995  PyDict_SetItemString(dict, "plot", Py_None);
996  }
997  return dict;
998  } else if (strncmp(n, "_ref_", 5) == 0) {
999  if (self->type_ > PyHoc::HocObject) {
1000  PyErr_SetString(PyExc_TypeError, "not a HocTopLevelInterpreter or HocObject");
1001  return NULL;
1002  }
1003  sym = getsym(n + 5, self->ho_, 0);
1004  if (!sym) {
1005  return PyObject_GenericGetAttr((PyObject*) subself, pyname);
1006  }
1007  if (sym->type == STRING) {
1009  if (self->type_ == PyHoc::HocTopLevelInterpreter) {
1011  } else if (self->type_ == PyHoc::HocObject && !self->ho_->ctemplate->constructor) {
1012  hoc_objectdata = self->ho_->u.dataspace;
1013  } else {
1015  assert(0);
1016  return NULL;
1017  }
1018  char** cpp = OPSTR(sym);
1020  result = cpp2refstr(cpp);
1021  return result;
1022  } else if (sym->type != VAR && sym->type != RANGEVAR && sym->type != VARALIAS) {
1023  char buf[200];
1024  sprintf(buf,
1025  "Hoc pointer error, %s is not a hoc variable or range variable or strdef",
1026  sym->name);
1027  PyErr_SetString(PyExc_TypeError, buf);
1028  return NULL;
1029  } else {
1030  isptr = 1;
1031  }
1032  } else if (is_obj_type(self->ho_, "Vector") && strcmp(n, "__array_interface__") == 0) {
1033  // return __array_interface__
1034  // printf("building array interface\n");
1035  Vect* v = (Vect*) self->ho_->u.this_pointer;
1036  int size = v->size();
1037  double* x = vector_vec(v);
1038 
1039  return Py_BuildValue("{s:(i),s:s,s:i,s:(N,O)}",
1040  "shape",
1041  size,
1042  "typestr",
1044  "version",
1045  3,
1046  "data",
1047  PyLong_FromVoidPtr(x),
1048  Py_True);
1049 
1050  } else if (is_obj_type(self->ho_, "RangeVarPlot") && strcmp(n, "plot") == 0) {
1051  return PyObject_CallFunctionObjArgs(rvp_plot, (PyObject*) self, NULL);
1052  } else if (is_obj_type(self->ho_, "PlotShape") && strcmp(n, "plot") == 0) {
1053  return PyObject_CallFunctionObjArgs(plotshape_plot, (PyObject*) self, NULL);
1054  } else if (strcmp(n, "__doc__") == 0) {
1055  if (setup_doc_system()) {
1056  PyObject* docobj = NULL;
1057  if (self->ho_) {
1058  docobj = Py_BuildValue("s s",
1059  self->ho_->ctemplate->sym->name,
1060  self->sym_ ? self->sym_->name : "");
1061  } else if (self->sym_) {
1062  // Symbol
1063  docobj = Py_BuildValue("s s", "", self->sym_->name);
1064  } else {
1065  // Base HocObject
1066 
1067  docobj = Py_BuildValue("s s", "", "");
1068  }
1069 
1070  result = PyObject_CallObject(pfunc_get_docstring, docobj);
1071  Py_DECREF(docobj);
1072  return result;
1073  } else {
1074  return NULL;
1075  }
1076  } else if (self->type_ == PyHoc::HocTopLevelInterpreter &&
1077  strncmp(n, "__nrnsec_0x", 11) == 0) {
1079  if (sec == NULL) {
1080  PyErr_SetString(PyExc_NameError, n);
1081  } else if (sec && sec->prop && sec->prop->dparam[PROP_PY_INDEX]._pvoid) {
1082  result = (PyObject*) sec->prop->dparam[PROP_PY_INDEX]._pvoid;
1083  Py_INCREF(result);
1084  } else {
1085  nrn_pushsec(sec);
1086  result = nrnpy_cas(NULL, NULL);
1087  nrn_popsec();
1088  }
1089  return result;
1090  } else if (self->type_ == PyHoc::HocTopLevelInterpreter && strncmp(n, "__pysec_", 8) == 0) {
1092  if (sec == NULL) {
1093  PyErr_SetString(PyExc_NameError, n);
1094  } else if (sec && sec->prop && sec->prop->dparam[PROP_PY_INDEX]._pvoid) {
1095  result = (PyObject*) sec->prop->dparam[PROP_PY_INDEX]._pvoid;
1096  Py_INCREF(result);
1097  } else {
1098  nrn_pushsec(sec);
1099  result = nrnpy_cas(NULL, NULL);
1100  nrn_popsec();
1101  }
1102  return result;
1103  } else {
1104  // ipython wants to know if there is a __getitem__
1105  // even though it does not use it.
1106  return PyObject_GenericGetAttr((PyObject*) subself, pyname);
1107  }
1108  }
1109  // printf("%s type=%d nindex=%d %s\n", self->sym_?self->sym_->name:"noname",
1110  // self->type_, self->nindex_, sym->name);
1111  // no hoc component for a hoc function
1112  // ie the sym has to be a component for the object returned by the function
1113  if (self->type_ == PyHoc::HocFunction) {
1114  PyErr_SetString(PyExc_TypeError,
1115  "No hoc method for a callable. Missing parentheses before the '.'?");
1116  return NULL;
1117  }
1118  if (self->type_ == PyHoc::HocArray) {
1119  PyErr_SetString(PyExc_TypeError, "Missing array index");
1120  return NULL;
1121  }
1122  if (self->ho_) { // use the component fork.
1123  result = hocobj_new(hocobject_type, 0, 0);
1124  PyHocObject* po = (PyHocObject*) result;
1125  po->ho_ = self->ho_;
1126  hoc_obj_ref(po->ho_);
1127  po->sym_ = sym;
1128  // evaluation deferred unless VAR,STRING,OBJECTVAR and not
1129  // an array
1130  int t = sym->type;
1131  if (t == VAR || t == STRING || t == OBJECTVAR || t == RANGEVAR || t == SECTION ||
1132  t == SECTIONREF || t == VARALIAS || t == OBJECTALIAS) {
1133  if (sym != nrn_child_sym && !ISARRAY(sym)) {
1134  hoc_push_object(po->ho_);
1135  nrn_inpython_ = 1;
1136  component(po);
1137  if (nrn_inpython_ == 2) { // error in component
1138  nrn_inpython_ = 0;
1139  PyErr_SetString(PyExc_TypeError, "No value");
1140  Py_DECREF(po);
1141  return NULL;
1142  }
1143  nrn_inpython_ = 0;
1144  Py_DECREF(po);
1145  if (t == SECTION || t == SECTIONREF) {
1146  section_object_seen = 0;
1147  result = nrnpy_cas(0, 0);
1148  nrn_popsec();
1149  return result;
1150  } else {
1151  if (isptr) {
1152  return nrn_hocobj_ptr(hoc_pxpop());
1153  } else {
1154  return nrnpy_hoc_pop();
1155  }
1156  }
1157  } else {
1158  if (isptr) {
1160  } else {
1161  po->type_ = PyHoc::HocArray;
1162  }
1163  return result;
1164  }
1165  } else {
1166  po->type_ = PyHoc::HocFunction;
1167  return result;
1168  }
1169  }
1170  // top level interpreter fork
1171  HocTopContextSet switch (sym->type) {
1172  case VAR: // double*
1173  if (!ISARRAY(sym)) {
1174  if (sym->subtype == USERINT) {
1175  result = Py_BuildValue("i", *(sym->u.pvalint));
1176  break;
1177  }
1178  if (sym->subtype == USERPROPERTY) {
1179  if (!nrn_noerr_access()) {
1180  PyErr_SetString(PyExc_TypeError, "Section access unspecified");
1181  break;
1182  }
1183  if (!isptr) {
1184  if (sym->u.rng.type == CABLESECTION) {
1185  result = Py_BuildValue("d", cable_prop_eval(sym));
1186  } else {
1187  result = Py_BuildValue("i", int(cable_prop_eval(sym)));
1188  }
1189  break;
1190  } else if (sym->u.rng.type != CABLESECTION) {
1191  PyErr_SetString(PyExc_TypeError, "Cannot be a reference");
1192  break;
1193  }
1194  }
1195  hoc_pushs(sym);
1196  hoc_evalpointer();
1197  if (isptr) {
1199  } else {
1200  result = Py_BuildValue("d", *hoc_pxpop());
1201  }
1202  } else {
1203  result = (PyObject*) intermediate(self, sym, -1);
1204  if (isptr) {
1206  } else {
1207  }
1208  }
1209  break;
1210  case STRING: // char*
1211  {
1212  Inst fc, *pcsav;
1213  fc.sym = sym;
1214  pcsav = save_pc(&fc);
1215  hoc_push_string();
1216  hoc_pc = pcsav;
1217  result = Py_BuildValue("s", *hoc_strpop());
1218  } break;
1219  case OBJECTVAR: // Object*
1220  if (!ISARRAY(sym)) {
1221  Inst fc, *pcsav;
1222  fc.sym = sym;
1223  pcsav = save_pc(&fc);
1224  hoc_objectvar();
1225  hoc_pc = pcsav;
1226  Object* ho = *hoc_objpop();
1227  result = nrnpy_ho2po(ho);
1228  } else {
1229  result = (PyObject*) intermediate(self, sym, -1);
1230  }
1231  break;
1232  case SECTION:
1233  if (!ISARRAY(sym)) {
1234  result = hocobj_getsec(sym);
1235  } else {
1236  result = (PyObject*) intermediate(self, sym, -1);
1237  }
1238  break;
1239  case PROCEDURE:
1240  case FUNCTION:
1241  case FUN_BLTIN:
1242  case BLTIN:
1243  case HOCOBJFUNCTION:
1244  case STRINGFUNC:
1245  case TEMPLATE:
1246  case OBJECTFUNC: {
1247  result = hocobj_new(hocobject_type, 0, 0);
1248  PyHocObject* po = (PyHocObject*) result;
1249  if (self->ho_) {
1250  po->ho_ = self->ho_;
1251  hoc_obj_ref(po->ho_);
1252  }
1253  po->type_ = PyHoc::HocFunction;
1254  po->sym_ = sym;
1255  // printf("function %s\n", po->sym_->name);
1256  break;
1257  }
1258  case SETPOINTERKEYWORD:
1259  result = toplevel_get(subself, n);
1260  break;
1261  default: // otherwise
1262  {
1263  if (PyDict_GetItemString(pmech_types, n)) {
1264  result = PyObject_CallFunction(get_mech_object_, "s", n);
1265  break;
1266  } else if (PyDict_GetItemString(rangevars_, n)) {
1267  PyErr_Format(PyExc_TypeError,
1268  "Cannot access %s directly; it is a range variable and may be accessed "
1269  "via a section or segment.",
1270  n);
1271  } else {
1272  PyErr_Format(PyExc_TypeError,
1273  "Cannot access %s (NEURON type %d) directly.",
1274  n,
1275  sym->type);
1276  break;
1277  }
1278  }
1279  }
1280  HocContextRestore return result;
1281 }
1282 
1283 static PyObject* hocobj_baseattr(PyObject* subself, PyObject* args) {
1284  PyObject* name;
1285  if (!PyArg_ParseTuple(args, "O", &name)) {
1286  return NULL;
1287  }
1288  return hocobj_getattr(subself, name);
1289 }
1290 
1291 static int refuse_to_look;
1292 static PyObject* hocobj_getattro(PyObject* subself, PyObject* name) {
1293  PyObject* result = 0;
1294  if ((PyTypeObject*) PyObject_Type(subself) != hocobject_type) {
1295  // printf("try generic %s\n", PyString_AsString(name));
1296  result = PyObject_GenericGetAttr(subself, name);
1297  if (result) {
1298  // printf("found generic %s\n", PyString_AsString(name));
1299  return result;
1300  } else {
1301  PyErr_Clear();
1302  }
1303  }
1304  if (!refuse_to_look) {
1305  result = hocobj_getattr(subself, name);
1306  }
1307  return result;
1308 }
1309 
1310 static int hocobj_setattro(PyObject* subself, PyObject* pyname, PyObject* value) {
1311  int err = 0;
1312  Inst* pcsav;
1313  Inst fc;
1314 
1315  int issub = ((PyTypeObject*) PyObject_Type(subself) != hocobject_type);
1316  if (issub) {
1317  // printf("try hasattr %s\n", PyString_AsString(name));
1318  refuse_to_look = 1;
1319  if (PyObject_HasAttr(subself, pyname)) {
1320  refuse_to_look = 0;
1321  // printf("found hasattr for %s\n", PyString_AsString(name));
1322  return PyObject_GenericSetAttr(subself, pyname, value);
1323  }
1324  refuse_to_look = 0;
1325  }
1326 
1327  PyHocObject* self = (PyHocObject*) subself;
1328  PyHocObject* po;
1329 
1330  if (self->type_ == PyHoc::HocObject && !self->ho_) {
1331  return 1;
1332  }
1333  Py2NRNString name(pyname);
1334  char* n = name.c_str();
1335  if (!n) {
1336  name.set_pyerr(PyExc_TypeError, "attribute name must be a string");
1337  return -1;
1338  }
1339  // printf("hocobj_setattro %s\n", n);
1340  Symbol* sym = getsym(n, self->ho_, 0);
1341  if (!sym) {
1342  if (issub) {
1343  return PyObject_GenericSetAttr(subself, pyname, value);
1344  } else if (!sym && self->type_ == PyHoc::HocObject &&
1345  self->ho_->ctemplate->sym == nrnpy_pyobj_sym_) {
1346  PyObject* p = nrnpy_hoc2pyobject(self->ho_);
1347  return PyObject_GenericSetAttr(p, pyname, value);
1348  } else if (strncmp(n, "_ref_", 5) == 0) {
1349  extern int nrn_pointer_assign(Prop*, Symbol*, PyObject*);
1350  Symbol* rvsym = getsym(n + 5, self->ho_, 0);
1351  if (rvsym && rvsym->type == RANGEVAR) {
1352  Prop* prop = ob2pntproc_0(self->ho_)->prop;
1353  if (!prop) {
1354  PyErr_SetString(PyExc_TypeError, "Point_process not located in a section");
1355  return -1;
1356  }
1357  err = nrn_pointer_assign(prop, rvsym, value);
1358  return err;
1359  }
1360  sym = getsym(n, self->ho_, 1);
1361  } else {
1362  sym = getsym(n, self->ho_, 1);
1363  }
1364  }
1365  if (!sym) {
1366  return -1;
1367  }
1368  if (self->ho_) { // use the component fork.
1369  PyObject* result = hocobj_new(hocobject_type, 0, 0);
1370  po = (PyHocObject*) result;
1371  po->ho_ = self->ho_;
1372  hoc_obj_ref(po->ho_);
1373  po->sym_ = sym;
1374  // evaluation deferred unless VAR,STRING,OBJECTVAR and not
1375  // an array
1376  int t = sym->type;
1377  if (t == VAR || t == STRING || t == OBJECTVAR || t == RANGEVAR || t == VARALIAS ||
1378  t == OBJECTALIAS) {
1379  if (!ISARRAY(sym)) {
1380  hoc_push_object(po->ho_);
1381  nrn_inpython_ = 1;
1382  component(po);
1383  if (nrn_inpython_ == 2) { // error in component
1384  nrn_inpython_ = 0;
1385  PyErr_SetString(PyExc_TypeError, "No value");
1386  Py_DECREF(po);
1387  return -1;
1388  }
1389  Py_DECREF(po);
1390  return set_final_from_stk(value);
1391  } else {
1392  char e[200];
1393  sprintf(e, "'%s' requires subscript for assignment", n);
1394  PyErr_SetString(PyExc_TypeError, e);
1395  Py_DECREF(po);
1396  return -1;
1397  }
1398  } else {
1399  PyErr_SetString(PyExc_TypeError, "not assignable");
1400  Py_DECREF(po);
1401  return -1;
1402  }
1403  }
1404  HocTopContextSet switch (sym->type) {
1405  case VAR: // double*
1406  if (ISARRAY(sym)) {
1407  PyErr_SetString(PyExc_TypeError, "wrong number of subscripts");
1408  err = -1;
1409  } else {
1410  if (sym->subtype == USERINT) {
1411  err = PyArg_Parse(value, "i", sym->u.pvalint) == 0;
1412  } else if (sym->subtype == USERPROPERTY) {
1413  if (!nrn_noerr_access()) {
1414  PyErr_SetString(PyExc_TypeError, "Section access unspecified");
1415  err = -1;
1416  break;
1417  }
1418  double x;
1419  if (sym->u.rng.type != CABLESECTION) {
1420  int i;
1421  if (PyArg_Parse(value, "i", &i) != 0 && i > 0 && i <= 32767) {
1422  x = double(i);
1423  } else {
1424  PyErr_SetString(PyExc_ValueError,
1425  "nseg must be an integer in range 1 to 32767");
1426  err = -1;
1427  }
1428  } else {
1429  err = PyArg_Parse(value, "d", &x) == 0;
1430  }
1431  if (!err) {
1432  cable_prop_assign(sym, &x, 0);
1433  }
1434  } else {
1435  hoc_pushs(sym);
1436  hoc_evalpointer();
1437  err = PyArg_Parse(value, "d", hoc_pxpop()) == 0;
1438  if (!err && sym->subtype == DYNAMICUNITS) {
1439  char mes[100];
1440  sprintf(mes,
1441  "Assignment to %s value of physical constant %s",
1442  _nrnunit_use_legacy_ ? "legacy" : "modern",
1443  sym->name);
1444  err = PyErr_WarnEx(PyExc_Warning, mes, 1);
1445  }
1446  }
1447  }
1448  break;
1449  case STRING: // char*
1450  fc.sym = sym;
1451  pcsav = save_pc(&fc);
1452  hoc_push_string();
1453  hoc_pc = pcsav;
1454  char* s;
1455  if (PyArg_Parse(value, "s", &s) == 1) {
1456  hoc_assign_str(hoc_strpop(), s);
1457  } else {
1458  err = 1;
1459  }
1460  break;
1461  case OBJECTVAR: // Object*
1462  {
1463  hocobj_objectvar(sym);
1464  Object** op;
1465  op = hoc_objpop();
1466  PyObject* po;
1467  PyHocObject* pho;
1468  if (PyArg_Parse(value, "O", &po) == 1) {
1469  if (po == Py_None) {
1470  hoc_obj_unref(*op);
1471  *op = 0;
1472  } else if (PyObject_TypeCheck(po, hocobject_type)) {
1473  pho = (PyHocObject*) po;
1474  if (pho->sym_) {
1475  PyErr_SetString(PyExc_TypeError,
1476  "argument cannot be a hoc object intermediate");
1477  err = -1;
1478  } else {
1479  hoc_obj_ref(pho->ho_);
1480  hoc_obj_unref(*op);
1481  *op = pho->ho_;
1482  }
1483  } else { // it is a PythonObject in hoc
1484  pyobject_in_objptr(op, po);
1485  }
1486  } else {
1487  err = 1;
1488  }
1489  break;
1490  }
1491  default:
1492  PyErr_SetString(PyExc_TypeError, "not assignable");
1493  err = -1;
1494  break;
1495  }
1496  HocContextRestore return err;
1497 }
1498 
1502 
1503 static int araylen(Arrayinfo* a, PyHocObject* po) {
1504  assert(a->nsub > po->nindex_);
1505  int n = 0;
1506  // Hoc Vector and Matrix are special cases because the sub[]
1507  // do not get filled in til just before hoc_araypt is called.
1508  // at least check the vector
1509  if (po->sym_ == sym_vec_x) {
1510  n = vector_capacity((IvocVect*) po->ho_->u.this_pointer);
1511  } else if (po->sym_ == sym_netcon_weight) {
1512  double* w;
1513  n = nrn_netcon_weight(static_cast<NetCon*>(po->ho_->u.this_pointer), &w);
1514  } else if (po->sym_ == nrn_child_sym) {
1515  n = nrn_secref_nchild((Section*) po->ho_->u.this_pointer);
1516  } else if (po->sym_ == sym_mat_x) {
1517  n = nrn_matrix_dim(po->ho_->u.this_pointer, po->nindex_);
1518  } else {
1519  n = a->sub[po->nindex_];
1520  }
1521  return n;
1522 }
1523 
1524 static int araychk(Arrayinfo* a, PyHocObject* po, int ix) {
1525  int n = araylen(a, po);
1526  if (ix < 0 || n <= ix) {
1527  // printf("ix=%d nsub=%d nindex=%d sub[nindex]=%d\n", ix, a->nsub,
1528  // po->nindex_, a->sub[po->nindex_]);
1529  char e[200];
1530  sprintf(e,
1531  "%s%s%s",
1532  po->ho_ ? hoc_object_name(po->ho_) : "",
1533  (po->ho_ && po->sym_) ? "." : "",
1534  po->sym_ ? po->sym_->name : "");
1535  PyErr_SetString(PyExc_IndexError, e);
1536  return -1;
1537  }
1538  return 0;
1539 }
1540 
1541 static Py_ssize_t hocobj_len(PyObject* self) {
1542  PyHocObject* po = (PyHocObject*) self;
1543  if (po->type_ == PyHoc::HocObject) {
1544  if (po->ho_->ctemplate == hoc_vec_template_) {
1545  return vector_capacity((Vect*) po->ho_->u.this_pointer);
1546  } else if (po->ho_->ctemplate == hoc_list_template_) {
1547  return ivoc_list_count(po->ho_);
1548  } else if (po->ho_->ctemplate == hoc_sectionlist_template_) {
1549  PyErr_SetString(PyExc_TypeError, "hoc.SectionList has no len()");
1550  return -1;
1551  }
1552  } else if (po->type_ == PyHoc::HocArray) {
1553  Arrayinfo* a = hocobj_aray(po->sym_, po->ho_);
1554  return araylen(a, po);
1555  } else if (po->sym_ && po->sym_->type == TEMPLATE) {
1556  return po->sym_->u.ctemplate->count;
1557  } else if (po->type_ == PyHoc::HocForallSectionIterator) {
1558  PyErr_SetString(PyExc_TypeError, "hoc all section iterator() has no len()");
1559  return -1;
1560  } else if (po->type_ == PyHoc::HocSectionListIterator) {
1561  PyErr_SetString(PyExc_TypeError, "hoc SectionList iterator() has no len()");
1562  return -1;
1563  }
1564  PyErr_SetString(PyExc_TypeError, "Most HocObject have no len()");
1565  return -1;
1566 }
1567 
1568 static int hocobj_nonzero(PyObject* self) {
1569  // printf("hocobj_nonzero\n");
1570  PyHocObject* po = (PyHocObject*) self;
1571  int b = 1;
1572  if (po->type_ == PyHoc::HocObject) {
1573  if (po->ho_->ctemplate == hoc_vec_template_) {
1574  b = vector_capacity((Vect*) po->ho_->u.this_pointer) > 0;
1575  } else if (po->ho_->ctemplate == hoc_list_template_) {
1576  b = ivoc_list_count(po->ho_) > 0;
1577  }
1578  } else if (po->type_ == PyHoc::HocArray) {
1579  Arrayinfo* a = hocobj_aray(po->sym_, po->ho_);
1580  b = araylen(a, po) > 0;
1581  } else if (po->sym_ && po->sym_->type == TEMPLATE) {
1582  b = 1; // prior behavior: po->sym_->u.ctemplate->count > 0;
1583  }
1584  return b;
1585 }
1586 
1587 PyObject* nrnpy_forall(PyObject* self, PyObject* args) {
1588  PyObject* po = hocobj_new(hocobject_type, 0, 0);
1589  PyHocObject* pho = (PyHocObject*) po;
1591  pho->u.its_ = PyHoc::Begin;
1592  pho->iteritem_ = section_list;
1593  return po;
1594 }
1595 
1596 static PyObject* hocobj_iter(PyObject* self) {
1597  // printf("hocobj_iter %p\n", self);
1598  PyHocObject* po = (PyHocObject*) self;
1599  if (po->type_ == PyHoc::HocObject) {
1600  if (po->ho_->ctemplate == hoc_vec_template_) {
1601  return PySeqIter_New(self);
1602  } else if (po->ho_->ctemplate == hoc_list_template_) {
1603  return PySeqIter_New(self);
1604  } else if (po->ho_->ctemplate == hoc_sectionlist_template_) {
1605  // need a clone of self so nested loops do not share iteritem_
1606  PyObject* po2 = nrnpy_ho2po(po->ho_);
1607  PyHocObject* pho2 = (PyHocObject*) po2;
1609  pho2->u.its_ = PyHoc::Begin;
1610  pho2->iteritem_ = ((hoc_Item*) po->ho_->u.this_pointer);
1611  return po2;
1612  }
1613  } else if (po->type_ == PyHoc::HocForallSectionIterator) {
1614  po->iteritem_ = section_list;
1615  po->u.its_ = PyHoc::Begin;
1616  Py_INCREF(self);
1617  return self;
1618  } else if (po->type_ == PyHoc::HocArray) {
1619  return PySeqIter_New(self);
1620  } else if (po->sym_ && po->sym_->type == TEMPLATE) {
1621  po->iteritem_ = po->sym_->u.ctemplate->olist->next;
1622  Py_INCREF(self);
1623  return self;
1624  }
1625  PyErr_SetString(PyExc_TypeError, "Not an iterable HocObject");
1626  return NULL;
1627 }
1628 
1630  hoc_Item* nextnext;
1631  hoc_Item* next;
1632  for (next = q->next; next != ql; next = nextnext) {
1633  nextnext = next->next;
1634  Section* sec = next->element.sec;
1635  if (sec->prop) { // valid
1636  break;
1637  }
1638  hoc_l_delete(next);
1639  section_unref(sec);
1640  }
1641  return next;
1642 }
1643 
1644 static PyObject* iternext_sl(PyHocObject* po, hoc_Item* ql) {
1645  // Note that the longstanding behavior of changing the currently
1646  // accessed section during iteration no longer takes place because
1647  // we cannot guarantee that an iterate will complete with state
1648  // PyHoc::Last and so the previous Section would have been left on the
1649  // hoc section stack.
1650 
1651  // Primarily the Section is pushed and the currently accessed python
1652  // Section is returned during sequential iteration over the list ql.
1653  // On re-entry here, the previous Section is popped.
1654  // The complexity is due to the possibility that the returned nrn_Section
1655  // may be deleted with h.delete_section(sec=nrn_Section). This would
1656  // invalidate the po->iteritem_ (point to freed memory) if it were
1657  // the iteritem of the current Section. Thus we choose to store
1658  // the next iteritem pointer in the list. Although not 100% safe, since
1659  // the user body of the iterator is allowed to delete_section an arbitary
1660  // subset of sections, the obvious work around, making a copy of ql,
1661  // is considered not worth it.
1662 
1663  // In this implementation, the first call to internext_sl starts out
1664  // in state PyHoc::Begin with po->iteritem_ == ql. If there is no valid
1665  // item, it sets po->iteritem_ = NULL and returns NULL. If there is
1666  // a valid item, it moves to state PyHoc::Last or PyHoc::NextNotLast
1667  // depending on whether there is a valid secitem following the current
1668  // item. The current section is pushed and currently accessed python
1669  // section is returned.
1670 
1671  // Thereafter, re-entry with po->iteritem_ == NULL, immediately
1672  // returns NULL.
1673 
1674  // Re-entry in state PyHoc::NextNotLast, pops the previously pushed Section,
1675  // sets sec to the current Section from po->iteritem_, and
1676  // sets po->iteritem_ to the next_valid_section. If there is no next_valid
1677  // section, then move to state PyHoc::Last.
1678  // Push the current section and return currently accessed python Section.
1679 
1680  // Re-entry in state PyHoc::Last just pops the current section, sets
1681  // po->iteritem_ = NULL, and returns NULL.
1682 
1683  if (po->iteritem_ == NULL) {
1684  return NULL;
1685  }
1686 
1687  if (po->u.its_ == PyHoc::Begin) {
1688  assert(po->iteritem_ == ql);
1689  hoc_Item* curitem = next_valid_secitem((hoc_Item*) (po->iteritem_), ql);
1690  if (curitem != ql) { // typical case, a valid current item
1691  Section* sec = curitem->element.sec;
1692  assert(sec->prop);
1693  // sec could be delete_section before return to internext.sl
1694  // which would invalidate curitem.
1695  // Not perfectly safe but leave po->iteritem_ as next valid
1696  // secitem after curitem.
1697  po->iteritem_ = next_valid_secitem(curitem, ql);
1698  if (po->iteritem_ == ql) {
1699  po->u.its_ = PyHoc::Last;
1700  } else {
1701  po->u.its_ = PyHoc::NextNotLast;
1702  }
1703  return (PyObject*) newpysechelp(sec);
1704  } else { // no valid current item so stop
1705  po->iteritem_ = NULL;
1706  return NULL;
1707  }
1708  } else if (po->u.its_ == PyHoc::NextNotLast) {
1709  // it would be a bug if po->iteritem_ (now the curitem) has been delete_section
1710  Section* sec = ((hoc_Item*) (po->iteritem_))->element.sec;
1711  if (!sec->prop) {
1712  // Handle an edge case where sec is a Python
1713  // Section and happens to have had as its only reference the
1714  // iteration variable on the previous iteration.
1715  // i.e. when sec is returned from the previous iteration, it will
1716  // be referenced by the iteration variable and the previous reference
1717  // will go to 0, thus invalidating po->iteritem_->element.sec->prop
1718  po->iteritem_ = next_valid_secitem((hoc_Item*) (po->iteritem_), ql);
1719  if (po->iteritem_ == ql) {
1720  po->u.its_ = PyHoc::Last;
1721  po->iteritem_ = NULL;
1722  return NULL;
1723  } else {
1724  sec = ((hoc_Item*) (po->iteritem_))->element.sec;
1725  }
1726  }
1727  assert(sec->prop);
1728  po->iteritem_ = next_valid_secitem((hoc_Item*) (po->iteritem_), ql);
1729  if (po->iteritem_ == ql) {
1730  po->u.its_ = PyHoc::Last;
1731  }
1732  return (PyObject*) newpysechelp(sec);
1733  } else if (po->u.its_ == PyHoc::Last) {
1734  po->iteritem_ = NULL;
1735  return NULL;
1736  }
1737  return NULL; // never get here as po->u.its_ is always a defined state.
1738 }
1739 
1740 static PyObject* hocobj_iternext(PyObject* self) {
1741  // printf("hocobj_iternext %p\n", self);
1742  PyHocObject* po = (PyHocObject*) self;
1743  if (po->type_ == PyHoc::HocSectionListIterator) {
1744  hoc_Item* ql = (hoc_Item*) po->ho_->u.this_pointer;
1745  return iternext_sl(po, ql);
1746  } else if (po->type_ == PyHoc::HocForallSectionIterator) {
1747  return iternext_sl(po, section_list);
1748  } else if (po->sym_->type == TEMPLATE) {
1749  hoc_Item* q = (hoc_Item*) po->iteritem_;
1750  if (q != po->sym_->u.ctemplate->olist) {
1751  po->iteritem_ = q->next;
1752  return nrnpy_ho2po(OBJ(q));
1753  }
1754  }
1755  return NULL;
1756 }
1757 
1758 /*
1759 Had better be an array. But the same ambiguity as with getattro
1760 in that we may return the final value or an intermediate (in the
1761 case where there is more than one dimension.) At least for now we
1762 only have to handle the OBJECTVAR and VAR case as a component and
1763 at the top level.
1764 */
1765 static PyObject* hocobj_getitem(PyObject* self, Py_ssize_t ix) {
1766  PyObject* result = NULL;
1767  PyHocObject* po = (PyHocObject*) self;
1768  if (po->type_ > PyHoc::HocArray && po->type_ != PyHoc::HocArrayIncomplete) {
1769  if (ix != 0 && po->type_ != PyHoc::HocScalarPtr) {
1770  PyErr_SetString(PyExc_IndexError, "index for hoc ref must be 0");
1771  return NULL;
1772  }
1773  if (po->type_ == PyHoc::HocScalarPtr) {
1774  result = Py_BuildValue("d", po->u.px_[ix]);
1775  } else if (po->type_ == PyHoc::HocRefNum) {
1776  result = Py_BuildValue("d", po->u.x_);
1777  } else if (po->type_ == PyHoc::HocRefStr) {
1778  result = Py_BuildValue("s", po->u.s_);
1779  } else if (po->type_ == PyHoc::HocRefPStr) {
1780  result = Py_BuildValue("s", *po->u.pstr_);
1781  } else {
1782  result = nrnpy_ho2po(po->u.ho_);
1783  }
1784  return result;
1785  }
1786  if (po->type_ == PyHoc::HocObject) { // might be in an iterator context
1787  if (po->ho_->ctemplate == hoc_vec_template_) {
1788  Vect* hv = (Vect*) po->ho_->u.this_pointer;
1789  if (ix < 0 || ix >= vector_capacity(hv)) {
1790  char e[200];
1791  sprintf(e, "%s", hoc_object_name(po->ho_));
1792  PyErr_SetString(PyExc_IndexError, e);
1793  return NULL;
1794  } else {
1795  return PyFloat_FromDouble(vector_vec(hv)[ix]);
1796  }
1797  } else if (po->ho_->ctemplate == hoc_list_template_) {
1798  OcList* hl = (OcList*) po->ho_->u.this_pointer;
1799  if (ix < 0 || ix >= hl->count()) {
1800  char e[200];
1801  sprintf(e, "%s", hoc_object_name(po->ho_));
1802  PyErr_SetString(PyExc_IndexError, e);
1803  return NULL;
1804  } else {
1805  return nrnpy_ho2po(hl->object(ix));
1806  }
1807  } else {
1808  PyErr_SetString(PyExc_TypeError, "unsubscriptable object");
1809  return NULL;
1810  }
1811  }
1812  if (!po->sym_) {
1813  // printf("unsubscriptable %s %d type=%d\n", hoc_object_name(po->ho_), ix,
1814  // po->type_);
1815  PyErr_SetString(PyExc_TypeError, "unsubscriptable object");
1816  return NULL;
1817  } else if (po->sym_->type == TEMPLATE) {
1818  hoc_Item *q, *ql = po->sym_->u.ctemplate->olist;
1819  Object* ob;
1820  ITERATE(q, ql) {
1821  ob = OBJ(q);
1822  if (ob->index == ix) {
1823  return nrnpy_ho2po(ob);
1824  }
1825  }
1826  char e[200];
1827  sprintf(e, "%s[%ld] instance does not exist", po->sym_->name, ix);
1828  PyErr_SetString(PyExc_IndexError, e);
1829  return NULL;
1830  }
1831  if (po->type_ != PyHoc::HocArray && po->type_ != PyHoc::HocArrayIncomplete) {
1832  char e[200];
1833  sprintf(e, "unsubscriptable object, type %d\n", po->type_);
1834  PyErr_SetString(PyExc_TypeError, e);
1835  return NULL;
1836  }
1837  Arrayinfo* a = hocobj_aray(po->sym_, po->ho_);
1838  if (araychk(a, po, ix)) {
1839  return NULL;
1840  }
1841  if (a->nsub - 1 > po->nindex_) { // another intermediate
1842  PyHocObject* ponew = intermediate(po, po->sym_, ix);
1843  result = (PyObject*) ponew;
1844  } else { // ready to evaluate
1845  if (po->ho_) {
1846  eval_component(po, ix);
1847  if (po->sym_->type == SECTION || po->sym_->type == SECTIONREF) {
1848  section_object_seen = 0;
1849  result = nrnpy_cas(0, 0);
1850  nrn_popsec();
1851  return result;
1852  } else {
1853  if (po->type_ == PyHoc::HocArrayIncomplete) {
1855  } else {
1856  result = nrnpy_hoc_pop();
1857  }
1858  }
1859  } else { // must be a top level intermediate
1860  HocTopContextSet switch (po->sym_->type) {
1861  case VAR:
1862  hocobj_pushtop(po, po->sym_, ix);
1863  hoc_evalpointer();
1864  --po->nindex_;
1865  if (po->type_ == PyHoc::HocArrayIncomplete) {
1866  assert(!po->u.px_);
1868  } else {
1869  result = Py_BuildValue("d", *hoc_pxpop());
1870  }
1871  break;
1872  case OBJECTVAR:
1873  hocobj_pushtop(po, 0, ix);
1874  hocobj_objectvar(po->sym_);
1875  --po->nindex_;
1877  break;
1878  case SECTION:
1879  hocobj_pushtop(po, 0, ix);
1880  result = hocobj_getsec(po->sym_);
1881  --po->nindex_;
1882  break;
1883  }
1885  }
1886  }
1887  return result;
1888 }
1889 
1890 static int hocobj_setitem(PyObject* self, Py_ssize_t i, PyObject* arg) {
1891  // printf("hocobj_setitem %d\n", i);
1892  int err = -1;
1893  PyHocObject* po = (PyHocObject*) self;
1894  if (po->type_ > PyHoc::HocArray) {
1895  if (po->type_ == PyHoc::HocArrayIncomplete) {
1896  PyErr_SetString(PyExc_TypeError, "incomplete hoc pointer");
1897  return -1;
1898  }
1899  if (i != 0 && po->type_ != PyHoc::HocScalarPtr) {
1900  PyErr_SetString(PyExc_IndexError, "index for hoc ref must be 0");
1901  return -1;
1902  }
1903  if (po->type_ == PyHoc::HocScalarPtr) {
1904  PyArg_Parse(arg, "d", po->u.px_ + i);
1905  } else if (po->type_ == PyHoc::HocRefNum) {
1906  PyArg_Parse(arg, "d", &po->u.x_);
1907  } else if (po->type_ == PyHoc::HocRefStr) {
1908  char* ts;
1909  PyArg_Parse(arg, "s", &ts);
1910  hoc_assign_str(&po->u.s_, ts);
1911  } else if (po->type_ == PyHoc::HocRefPStr) {
1912  char* ts;
1913  PyArg_Parse(arg, "s", &ts);
1914  hoc_assign_str(po->u.pstr_, ts);
1915  } else {
1916  PyObject* tp;
1917  PyArg_Parse(arg, "O", &tp);
1918  po->u.ho_ = nrnpy_po2ho(tp);
1919  }
1920  return 0;
1921  }
1922  if (po->ho_) {
1923  if (po->ho_->ctemplate == hoc_vec_template_) {
1924  Vect* vec = (Vect*) po->ho_->u.this_pointer;
1925  int vec_size = vector_capacity(vec);
1926  // allow Python style negative indices
1927  if (i < 0) {
1928  i += vec_size;
1929  }
1930  if (i >= vec_size || i < 0) {
1931  PyErr_SetString(PyExc_IndexError, "index out of bounds");
1932  return -1;
1933  }
1934  PyArg_Parse(arg, "d", vector_vec(vec) + i);
1935  return 0;
1936  }
1937  }
1938  if (!po->sym_ || po->type_ != PyHoc::HocArray) {
1939  PyErr_SetString(PyExc_TypeError, "unsubscriptable object");
1940  return -1;
1941  }
1942  Arrayinfo* a = hocobj_aray(po->sym_, po->ho_);
1943  if (a->nsub - 1 != po->nindex_) {
1944  PyErr_SetString(PyExc_TypeError, "wrong number of subscripts");
1945  return -1;
1946  }
1947  if (araychk(a, po, i)) {
1948  return -1;
1949  }
1950  if (po->ho_) {
1951  if (po->sym_->type == SECTION) {
1952  PyErr_SetString(PyExc_TypeError, "not assignable");
1953  } else {
1954  eval_component(po, i);
1955  err = set_final_from_stk(arg);
1956  }
1957  } else { // must be a top level intermediate
1958  HocTopContextSet switch (po->sym_->type) {
1959  case VAR:
1960  hocobj_pushtop(po, po->sym_, i);
1961  hoc_evalpointer();
1962  --po->nindex_;
1963  err = PyArg_Parse(arg, "d", hoc_pxpop()) != 1;
1964  break;
1965  case OBJECTVAR: {
1966  hocobj_pushtop(po, 0, i);
1967  hocobj_objectvar(po->sym_);
1968  --po->nindex_;
1969  Object** op;
1970  op = hoc_objpop();
1971  PyObject* pyo;
1972  if (PyArg_Parse(arg, "O", &pyo) == 1) {
1973  Object* ho = nrnpy_po2ho(pyo);
1974  hoc_obj_unref(*op);
1975  *op = ho;
1976  err = 0;
1977  } else {
1978  err = 1;
1979  }
1980  break;
1981  }
1982  default:
1983  PyErr_SetString(PyExc_TypeError, "not assignable");
1984  break;
1985  }
1987  }
1988  return err;
1989 }
1990 
1991 static PyObject* mkref(PyObject* self, PyObject* args) {
1992  PyObject* pa;
1994  if (PyArg_ParseTuple(args, "O", &pa) == 1) {
1996  if (nrnpy_numbercheck(pa)) {
1997  result->type_ = PyHoc::HocRefNum;
1998  PyObject* pn = PyNumber_Float(pa);
1999  result->u.x_ = PyFloat_AsDouble(pn);
2000  Py_XDECREF(pn);
2001  } else if (is_python_string(pa)) {
2002  result->type_ = PyHoc::HocRefStr;
2003  result->u.s_ = 0;
2004  Py2NRNString str(pa);
2005  if (str.err()) {
2006  str.set_pyerr(PyExc_TypeError, "string arg must have only ascii characters");
2007  Py_XDECREF(result);
2008  return NULL;
2009  }
2010  char* cpa = str.c_str();
2011  hoc_assign_str(&result->u.s_, cpa);
2012  } else {
2013  result->type_ = PyHoc::HocRefObj;
2014  result->u.ho_ = nrnpy_po2ho(pa);
2015  }
2016  return (PyObject*) result;
2017  }
2018  PyErr_SetString(PyExc_TypeError, "single arg must be number, string, or Object");
2019  return NULL;
2020 }
2021 
2022 static PyObject* cpp2refstr(char** cpp) {
2023  // If cpp is from a hoc_temp_charptr (see src/oc/code.cpp) then create a
2024  // HocRefStr and copy *cpp. Otherwise, assume it is from a hoc strdef
2025  // or a HocRefStr which is persistent over the life time of this returned
2026  // PyObject so that it is safe to create a HocRefPStr such that
2027  // u.pstr_ = cpp and it is not needed
2028  // for the HocRefPStr destructor to delete either u.pstr_ or *u.pstr_.
2029 
2030  assert(cpp && *cpp); // not really sure about the *cpp
2032  if (hoc_is_temp_charptr(cpp)) { // return HocRefStr HocObject.
2033  result->type_ = PyHoc::HocRefStr;
2034  result->u.s_ = 0;
2035  hoc_assign_str(&result->u.s_, *cpp);
2036  } else {
2037  result->type_ = PyHoc::HocRefPStr;
2038  result->u.pstr_ = cpp;
2039  }
2040  return (PyObject*) result;
2041 }
2042 
2043 static PyObject* setpointer(PyObject* self, PyObject* args) {
2044  PyObject *ref, *name, *pp, *result = NULL;
2045  if (PyArg_ParseTuple(args, "O!OO", hocobject_type, &ref, &name, &pp) == 1) {
2046  PyHocObject* href = (PyHocObject*) ref;
2047  double** ppd = 0;
2048  if (href->type_ != PyHoc::HocScalarPtr) {
2049  goto done;
2050  }
2051  if (PyObject_TypeCheck(pp, hocobject_type)) {
2052  PyHocObject* hpp = (PyHocObject*) pp;
2053  if (hpp->type_ != PyHoc::HocObject) {
2054  goto done;
2055  }
2056  Py2NRNString str(name);
2057  char* n = str.c_str();
2058  if (str.err()) {
2059  str.set_pyerr(PyExc_TypeError, "POINTER name can contain only ascii characters");
2060  return NULL;
2061  }
2062  Symbol* sym = getsym(n, hpp->ho_, 0);
2063  if (!sym || sym->type != RANGEVAR || sym->subtype != NRNPOINTER) {
2064  goto done;
2065  }
2066  Prop* prop = ob2pntproc_0(hpp->ho_)->prop;
2067  if (!prop) {
2068  PyErr_SetString(PyExc_TypeError, "Point_process not located in a section");
2069  return NULL;
2070  }
2071  ppd = &prop->dparam[sym->u.rng.index].pval;
2072  } else {
2073  ppd = nrnpy_setpointer_helper(name, pp);
2074  if (!ppd) {
2075  goto done;
2076  }
2077  }
2078  *ppd = href->u.px_;
2079  result = Py_None;
2080  Py_INCREF(result);
2081  }
2082 done:
2083  if (!result) {
2084  PyErr_SetString(PyExc_TypeError,
2085  "setpointer(_ref_hocvar, 'POINTER_name', point_process or "
2086  "nrn.Mechanism))");
2087  }
2088  return result;
2089 }
2090 
2091 static PyObject* hocobj_vptr(PyObject* pself, PyObject* args) {
2092  Object* ho = ((PyHocObject*) pself)->ho_;
2093  PyObject* po = NULL;
2094  if (ho) {
2095  po = Py_BuildValue("O", PyLong_FromVoidPtr(ho));
2096  }
2097  if (!po) {
2098  PyErr_SetString(PyExc_TypeError, "HocObject does not wrap a Hoc Object");
2099  }
2100  return po;
2101 }
2102 
2103 static long hocobj_hash(PyHocObject* self) {
2104  return castptr2long self->ho_;
2105 }
2106 
2107 PyObject* nrn_ptr_richcmp(void* self_ptr, void* other_ptr, int op) {
2108  bool result = false;
2109  switch (op) {
2110  case Py_LT:
2111  result = self_ptr < other_ptr;
2112  break;
2113  case Py_LE:
2114  result = self_ptr <= other_ptr;
2115  break;
2116  case Py_EQ:
2117  result = self_ptr == other_ptr;
2118  break;
2119  case Py_NE:
2120  result = self_ptr != other_ptr;
2121  break;
2122  case Py_GT:
2123  result = self_ptr > other_ptr;
2124  break;
2125  case Py_GE:
2126  result = self_ptr >= other_ptr;
2127  break;
2128  }
2129  if (result) {
2130  Py_RETURN_TRUE;
2131  }
2132  Py_RETURN_FALSE;
2133 }
2134 
2135 // TODO: unfortunately, this duplicates code from hocobj_same; consolidate?
2136 static PyObject* hocobj_richcmp(PyHocObject* self, PyObject* other, int op) {
2137  void* self_ptr = (void*) (self->ho_);
2138  void* other_ptr = (void*) other;
2139  bool are_equal = true;
2140  if (PyObject_TypeCheck(other, hocobject_type)) {
2141  if (((PyHocObject*) other)->type_ == self->type_) {
2142  switch (self->type_) {
2143  case PyHoc::HocRefNum:
2144  case PyHoc::HocRefStr:
2145  case PyHoc::HocRefObj:
2146  case PyHoc::HocRefPStr:
2147  /* only same objects can point to same h.ref */
2148  self_ptr = (void*) self;
2149  break;
2150  case PyHoc::HocFunction:
2151  if (self->ho_ != (void*) (((PyHocObject*) other)->ho_)) {
2152  if (op == Py_NE) {
2153  Py_RETURN_TRUE;
2154  } else if (op == Py_EQ) {
2155  Py_RETURN_FALSE;
2156  }
2157  /* different classes, comparing < or > doesn't make sense */
2158  PyErr_SetString(PyExc_TypeError, "this comparison is undefined");
2159  return NULL;
2160  }
2161  self_ptr = (void*) self->sym_;
2162  other_ptr = (void*) (((PyHocObject*) other)->sym_);
2163  break;
2164  case PyHoc::HocScalarPtr:
2165  self_ptr = self->u.px_;
2166  other_ptr = (void*) (((PyHocObject*) other)->u.px_);
2167  break;
2169  case PyHoc::HocArray:
2170  if (op != Py_EQ && op != Py_NE) {
2171  /* comparing partial arrays doesn't make sense */
2172  PyErr_SetString(PyExc_TypeError, "this comparison is undefined");
2173  return NULL;
2174  }
2175  if (self->ho_ != (void*) (((PyHocObject*) other)->ho_)) {
2176  /* different objects */
2177  other_ptr = (void*) (((PyHocObject*) other)->ho_);
2178  break;
2179  }
2180  if (self->nindex_ != (((PyHocObject*) other)->nindex_) ||
2181  self->sym_ != (((PyHocObject*) other)->sym_)) {
2182  if (op == Py_NE) {
2183  Py_RETURN_TRUE;
2184  }
2185  Py_RETURN_FALSE;
2186  }
2187  for (int i = 0; i < self->nindex_; i++) {
2188  if (self->indices_[i] != ((PyHocObject*) other)->indices_[i]) {
2189  are_equal = false;
2190  }
2191  }
2192  if (are_equal == (op == Py_EQ)) {
2193  Py_RETURN_TRUE;
2194  }
2195  Py_RETURN_FALSE;
2196  default:
2197  other_ptr = (void*) (((PyHocObject*) other)->ho_);
2198  }
2199  } else {
2200  if (op == Py_EQ) {
2201  Py_RETURN_FALSE;
2202  } else if (op == Py_NE) {
2203  Py_RETURN_TRUE;
2204  }
2205  /* different NEURON object types are incomperable besides for (in)equality */
2206  PyErr_SetString(PyExc_TypeError, "this comparison is undefined");
2207  return NULL;
2208  }
2209  }
2210  return nrn_ptr_richcmp(self_ptr, other_ptr, op);
2211 }
2212 
2213 static PyObject* hocobj_same(PyHocObject* pself, PyObject* args) {
2214  PyObject* po;
2215  if (PyArg_ParseTuple(args, "O", &po)) {
2216  if (PyObject_TypeCheck(po, hocobject_type)) {
2217  if (((PyHocObject*) po)->ho_ == pself->ho_) {
2218  Py_RETURN_TRUE;
2219  }
2220  }
2221  Py_RETURN_FALSE;
2222  }
2223  return NULL;
2224 }
2225 
2226 static char* double_array_interface(PyObject* po, long& stride) {
2227  void* data = 0;
2228  PyObject* pstride;
2229  PyObject* psize;
2230  if (PyObject_HasAttrString(po, "__array_interface__")) {
2231  PyObject* ai = PyObject_GetAttrString(po, "__array_interface__");
2232  Py2NRNString typestr(PyDict_GetItemString(ai, "typestr"));
2233  if (strcmp(typestr.c_str(), array_interface_typestr) == 0) {
2234  data = PyLong_AsVoidPtr(PyTuple_GetItem(PyDict_GetItemString(ai, "data"), 0));
2235  // printf("double_array_interface idata = %ld\n", idata);
2236  if (PyErr_Occurred()) {
2237  data = 0;
2238  }
2239  pstride = PyDict_GetItemString(ai, "strides");
2240  if (pstride == Py_None) {
2241  stride = 8;
2242  } else if (PyTuple_Check(pstride)) {
2243  if (PyTuple_Size(pstride) == 1) {
2244  psize = PyTuple_GetItem(pstride, 0);
2245  if (PyLong_Check(psize)) {
2246  stride = PyLong_AsLong(psize);
2247  } else if (PyInt_Check(psize)) {
2248  stride = PyInt_AS_LONG(psize);
2249 
2250  } else {
2251  PyErr_SetString(PyExc_TypeError,
2252  "array_interface stride element of invalid type.");
2253  data = 0;
2254  }
2255 
2256  } else
2257  data = 0; // don't handle >1 dimensions
2258  } else {
2259  PyErr_SetString(PyExc_TypeError, "array_interface stride object of invalid type.");
2260  data = 0;
2261  }
2262  }
2263  Py_DECREF(ai);
2264  }
2265  return static_cast<char*>(data);
2266 }
2267 
2269  Vect* hv = (Vect*) v;
2270  // printf("%s.from_array\n", hoc_object_name(hv->obj_));
2271  Object* ho = *hoc_objgetarg(1);
2272  if (ho->ctemplate->sym != nrnpy_pyobj_sym_) {
2273  hoc_execerror(hoc_object_name(ho), " is not a PythonObject");
2274  }
2275  PyObject* po = nrnpy_hoc2pyobject(ho);
2276  Py_INCREF(po);
2277  if (!PySequence_Check(po)) {
2278  if (!PyIter_Check(po)) {
2280  " does not support the Python Sequence or Iterator protocol");
2281  }
2282  PyObject* iterator = PyObject_GetIter(po);
2283  assert(iterator != NULL);
2284  int i = 0;
2285  PyObject* p;
2286  while ((p = PyIter_Next(iterator)) != NULL) {
2287  if (!PyNumber_Check(p)) {
2288  char buf[50];
2289  sprintf(buf, "item %d not a number", i);
2290  hoc_execerror(buf, 0);
2291  }
2292  hv->push_back(PyFloat_AsDouble(p));
2293  Py_DECREF(p);
2294  ++i;
2295  }
2296  Py_DECREF(iterator);
2297  } else {
2298  int size = PySequence_Size(po);
2299  // printf("size = %d\n", size);
2300  hv->resize(size);
2301  double* x = vector_vec(hv);
2302  long stride;
2303  char* y = double_array_interface(po, stride);
2304  if (y) {
2305  for (int i = 0, j = 0; i < size; ++i, j += stride) {
2306  x[i] = *(double*) (y + j);
2307  }
2308  } else {
2309  for (int i = 0; i < size; ++i) {
2310  PyObject* p = PySequence_GetItem(po, i);
2311  if (!PyNumber_Check(p)) {
2312  char buf[50];
2313  sprintf(buf, "item %d not a number", i);
2314  hoc_execerror(buf, 0);
2315  }
2316  x[i] = PyFloat_AsDouble(p);
2317  Py_DECREF(p);
2318  }
2319  }
2320  }
2321  Py_DECREF(po);
2322  return hv;
2323 }
2324 
2325 static PyObject* (*vec_as_numpy)(int, double*);
2326 extern "C" int nrnpy_set_vec_as_numpy(PyObject* (*p)(int, double*) ) {
2327  vec_as_numpy = p;
2328  return 0;
2329 }
2330 
2331 static PyObject* store_savestate_ = NULL;
2332 static PyObject* restore_savestate_ = NULL;
2333 
2334 
2335 static void nrnpy_store_savestate_(char** save_data, uint64_t* save_data_size) {
2336  if (store_savestate_) {
2337  // call store_savestate_ with no arguments to get a byte array that we can write out
2338  PyObject* args = PyTuple_New(0);
2339  PyObject* result = PyObject_CallObject(store_savestate_, args);
2340  Py_INCREF(result);
2341  Py_DECREF(args);
2342  if (result == NULL) {
2343  hoc_execerror("SaveState:", "Data store failure.");
2344  }
2345  // free any old data and make a copy
2346  if (*save_data) {
2347  delete[](*save_data);
2348  }
2349  *save_data_size = PyByteArray_Size(result);
2350  *save_data = new char[*save_data_size];
2351  memcpy(*save_data, PyByteArray_AsString(result), *save_data_size);
2352  Py_DECREF(result);
2353  } else {
2354  *save_data_size = 0;
2355  }
2356 }
2357 
2358 static void nrnpy_restore_savestate_(int64_t size, char* data) {
2359  if (restore_savestate_) {
2360  PyObject* args = PyTuple_New(1);
2361  PyObject* py_data = PyByteArray_FromStringAndSize(data, size);
2362  Py_INCREF(py_data);
2363  if (py_data == NULL) {
2364  hoc_execerror("SaveState:", "Data restore failure.");
2365  }
2366  // note: PyTuple_SetItem steals a ref to py_data
2367  PyTuple_SetItem(args, 0, py_data);
2368  PyObject* result = PyObject_CallObject(restore_savestate_, args);
2369  Py_DECREF(args);
2370  if (result == NULL) {
2371  hoc_execerror("SaveState:", "Data restore failure.");
2372  }
2373  } else {
2374  if (size) {
2375  hoc_execerror("SaveState:", "Missing data restore function.");
2376  }
2377  }
2378 }
2379 
2380 extern "C" int nrnpy_set_toplevel_callbacks(PyObject* rvp_plot0,
2381  PyObject* plotshape_plot0,
2382  PyObject* get_mech_object_0,
2383  PyObject* store_savestate,
2384  PyObject* restore_savestate) {
2385  rvp_plot = rvp_plot0;
2386  plotshape_plot = plotshape_plot0;
2387  get_mech_object_ = get_mech_object_0;
2388  store_savestate_ = store_savestate;
2389  restore_savestate_ = restore_savestate;
2392  return 0;
2393 }
2394 
2395 static PyObject* gui_callback = NULL;
2396 extern "C" int nrnpy_set_gui_callback(PyObject* new_gui_callback) {
2397  gui_callback = new_gui_callback;
2398  return 0;
2399 }
2400 
2401 static double object_to_double_(Object* obj) {
2402  PyObject* const pyobj = nrnpy_ho2po(obj);
2403  Py_INCREF(pyobj);
2404  const double result = PyFloat_AsDouble(pyobj);
2405  Py_DECREF(pyobj);
2406  return result;
2407 }
2408 
2409 static void* nrnpy_get_pyobj_(Object* obj) {
2410  // returns something wrapping a PyObject if it is a PyObject else NULL
2411  if (obj->ctemplate->sym == nrnpy_pyobj_sym_) {
2412  return (void*) nrnpy_ho2po(obj);
2413  }
2414  return NULL;
2415 }
2416 
2417 static void nrnpy_decref_(void* pyobj) {
2418  // note: this assumes that pyobj is really a PyObject
2419  if (pyobj) {
2420  Py_DECREF((PyObject*) pyobj);
2421  }
2422 }
2423 
2424 static PyObject* gui_helper_3_helper_(const char* name, Object* obj, int handle_strptr) {
2425  int narg = 1;
2426  while (ifarg(narg)) {
2427  narg++;
2428  }
2429  narg--;
2430  PyObject* args = PyTuple_New(narg + 3);
2431  PyObject* pyname = PyString_FromString(name);
2432  PyTuple_SetItem(args, 0, pyname);
2433  for (int iarg = 0; iarg < narg; iarg++) {
2434  const int iiarg = iarg + 1;
2435  if (hoc_is_object_arg(iiarg)) {
2436  PyObject* active_obj = nrnpy_ho2po(*hoc_objgetarg(iiarg));
2437  PyTuple_SetItem(args, iarg + 3, active_obj);
2438  } else if (hoc_is_pdouble_arg(iiarg)) {
2439  PyHocObject* ptr_nrn = (PyHocObject*) hocobj_new(hocobject_type, 0, 0);
2440  ptr_nrn->type_ = PyHoc::HocScalarPtr;
2441  ptr_nrn->u.px_ = hoc_pgetarg(iiarg);
2442  PyObject* py_ptr = (PyObject*) ptr_nrn;
2443  Py_INCREF(py_ptr);
2444  PyTuple_SetItem(args, iarg + 3, py_ptr);
2445  } else if (hoc_is_str_arg(iiarg)) {
2446  if (handle_strptr > 0) {
2447  char** str_arg = hoc_pgargstr(iiarg);
2448  PyObject* py_ptr = cpp2refstr(str_arg);
2449  Py_INCREF(py_ptr);
2450  PyTuple_SetItem(args, iarg + 3, py_ptr);
2451  } else {
2452  PyObject* py_str = PyString_FromString(gargstr(iiarg));
2453  PyTuple_SetItem(args, iarg + 3, py_str);
2454  }
2455  } else if (hoc_is_double_arg(iiarg)) {
2456  PyObject* py_double = PyFloat_FromDouble(*getarg(iiarg));
2457  PyTuple_SetItem(args, iarg + 3, py_double);
2458  }
2459  }
2460  PyObject* my_obj;
2461  if (obj) {
2462  // there's a problem with this: if obj is intrinisically a PyObject, then this is increasing
2463  // it's refcount and that's
2464  my_obj = nrnpy_ho2po(obj);
2465  } else {
2466  my_obj = Py_None;
2467  Py_INCREF(Py_None);
2468  }
2469  PyTuple_SetItem(args, 1, my_obj); // steals a reference
2470  PyObject* my_obj2;
2471  if (hoc_thisobject && name[0] != '~') {
2472  my_obj2 = nrnpy_ho2po(hoc_thisobject); // in the case of a HOC object, such as happens with
2473  // List.browser, the ref count will be 1
2474  } else {
2475  my_obj2 = Py_None;
2476  Py_INCREF(Py_None);
2477  }
2478 
2479  PyTuple_SetItem(args, 2, my_obj2); // steals a reference to my_obj2
2480  PyObject* po = PyObject_CallObject(gui_callback, args);
2481  if (PyErr_Occurred()) {
2482  // if there was an error, display it and return 0.
2483  // It's not a great solution, but it beats segfaulting
2484  PyErr_Print();
2485  po = PyLong_FromLong(0);
2486  }
2487  Py_DECREF(args); // Note: this decreases the ref count of my_obj and my_obj2
2488  return po;
2489 }
2490 
2491 static Object** gui_helper_3_(const char* name, Object* obj, int handle_strptr) {
2492  if (gui_callback) {
2493  PyObject* po = gui_helper_3_helper_(name, obj, handle_strptr);
2494  // TODO: something that allows None (currently nrnpy_po2ho returns NULL if po == Py_None)
2495  Object* ho = nrnpy_po2ho(po);
2496  Py_DECREF(po);
2497  if (ho) {
2498  --ho->refcount;
2499  }
2500  return hoc_temp_objptr(ho);
2501  }
2502  return NULL;
2503 }
2504 
2505 static char** gui_helper_3_str_(const char* name, Object* obj, int handle_strptr) {
2506  if (gui_callback) {
2507  PyObject* po = gui_helper_3_helper_(name, obj, handle_strptr);
2508  char** ts = hoc_temp_charptr();
2509  Py2NRNString str(po, true);
2510  *ts = str.c_str();
2511  // TODO: is there a memory leak here? do I need to: s2free.push_back(*ts);
2512  Py_DECREF(po);
2513  return ts;
2514  }
2515  return NULL;
2516 }
2517 
2518 
2519 static Object** gui_helper_(const char* name, Object* obj) {
2520  return gui_helper_3_(name, obj, 0);
2521 }
2522 
2523 static Object** vec_as_numpy_helper(int size, double* data) {
2524  if (vec_as_numpy) {
2525  PyObject* po = (*vec_as_numpy)(size, data);
2526  if (po != Py_None) {
2527  Object* ho = nrnpy_po2ho(po);
2528  Py_DECREF(po);
2529  --ho->refcount;
2530  return hoc_temp_objptr(ho);
2531  }
2532  }
2533  hoc_execerror("Vector.as_numpy() error", 0);
2534  return NULL;
2535 }
2536 
2537 static Object** nrnpy_vec_to_python(void* v) {
2538  Vect* hv = (Vect*) v;
2539  int size = hv->size();
2540  double* x = vector_vec(hv);
2541  // printf("%s.to_array\n", hoc_object_name(hv->obj_));
2542  PyObject* po;
2543  Object* ho = 0;
2544 
2545  // as_numpy_array=True is the case where this function is being called by the
2546  // ivocvect __array__ member
2547  // as such perhaps we should check here that no arguments were passed
2548  // although this should be the case unless the function is erroneously called
2549  // by the user.
2550 
2551  if (ifarg(1)) {
2552  ho = *hoc_objgetarg(1);
2553  if (ho->ctemplate->sym != nrnpy_pyobj_sym_) {
2554  hoc_execerror(hoc_object_name(ho), " is not a PythonObject");
2555  }
2556  po = nrnpy_hoc2pyobject(ho);
2557  if (!PySequence_Check(po)) {
2558  hoc_execerror(hoc_object_name(ho), " is not a Python Sequence");
2559  }
2560  if (size != PySequence_Size(po)) {
2561  hoc_execerror(hoc_object_name(ho), "Python Sequence not same size as Vector");
2562  }
2563  } else {
2564  if ((po = PyList_New(size)) == NULL) {
2565  hoc_execerror("Could not create new Python List with correct size.", 0);
2566  }
2567 
2568  ho = nrnpy_po2ho(po);
2569  Py_DECREF(po);
2570  --ho->refcount;
2571  }
2572  // printf("size = %d\n", size);
2573  long stride;
2574  char* y = double_array_interface(po, stride);
2575  if (y) {
2576  for (int i = 0, j = 0; i < size; ++i, j += stride) {
2577  *(double*) (y + j) = x[i];
2578  }
2579  } else if (PyList_Check(po)) { // PySequence_SetItem does DECREF of old items
2580  for (int i = 0; i < size; ++i) {
2581  PyObject* pn = PyFloat_FromDouble(x[i]);
2582  if (!pn || PyList_SetItem(po, i, pn) == -1) {
2583  char buf[50];
2584  sprintf(buf, "%d of %d", i, size);
2585  hoc_execerror("Could not set a Python Sequence item", buf);
2586  }
2587  }
2588  } else { // assume PySequence_SetItem works
2589  for (int i = 0; i < size; ++i) {
2590  PyObject* pn = PyFloat_FromDouble(x[i]);
2591  if (!pn || PySequence_SetItem(po, i, pn) == -1) {
2592  char buf[50];
2593  sprintf(buf, "%d of %d", i, size);
2594  hoc_execerror("Could not set a Python Sequence item", buf);
2595  }
2596  Py_DECREF(pn);
2597  }
2598  }
2599  return hoc_temp_objptr(ho);
2600 }
2601 
2603  if (obj) {
2604  PyObject* py_obj = nrnpy_ho2po(obj);
2605  PyObject* result = PyObject_CallFunctionObjArgs(nrnpy_rvp_pyobj_callback, py_obj, NULL);
2606  Py_DECREF(py_obj);
2607  Object* obj_result = nrnpy_po2ho(result);
2608  Py_DECREF(result); // the previous line incremented the reference count
2609  return obj_result;
2610  } else {
2611  return 0;
2612  }
2613 }
2614 
2615 
2616 extern "C" PyObject* get_plotshape_data(PyObject* sp) {
2617  PyLockGIL lock;
2618  PyHocObject* pho = (PyHocObject*) sp;
2619  ShapePlotInterface* spi;
2620  if (!is_obj_type(pho->ho_, "PlotShape")) {
2621  PyErr_SetString(PyExc_TypeError, "get_plotshape_variable only takes PlotShape objects");
2622  return NULL;
2623  }
2624  void* that = pho->ho_->u.this_pointer;
2625 #if HAVE_IV
2626  if (hoc_usegui) {
2627  spi = ((ShapePlot*) that);
2628  } else {
2629  spi = ((ShapePlotData*) that);
2630  }
2631 #else
2632  spi = ((ShapePlotData*) that);
2633 #endif
2634  Object* sl = spi->neuron_section_list();
2635  PyObject* py_sl = nrnpy_ho2po(sl);
2636  PyObject* py_obj = (PyObject*) spi->varobj();
2637  if (!py_obj) {
2638  py_obj = Py_None;
2639  }
2640  // Note: O increases the reference count; N does not
2641  return Py_BuildValue("sOffN", spi->varname(), py_obj, spi->low(), spi->high(), py_sl);
2642 }
2643 
2644 
2645 // poorly follows __reduce__ and __setstate__
2646 // from numpy/core/src/multiarray/methods.c
2647 static PyObject* hocpickle_reduce(PyObject* self, PyObject* args) {
2648  // printf("hocpickle_reduce\n");
2649  PyHocObject* pho = (PyHocObject*) self;
2650  if (!is_obj_type(pho->ho_, "Vector")) {
2651  PyErr_SetString(PyExc_TypeError, "HocObject: Only Vector instance can be pickled");
2652  return NULL;
2653  }
2654  Vect* vec = (Vect*) pho->ho_->u.this_pointer;
2655 
2656  // neuron module has a _pkl method that returns h.Vector(0)
2657  PyObject* mod = PyImport_ImportModule("neuron");
2658  if (mod == NULL) {
2659  return NULL;
2660  }
2661  PyObject* obj = PyObject_GetAttrString(mod, "_pkl");
2662  Py_DECREF(mod);
2663  if (obj == NULL) {
2664  PyErr_SetString(PyExc_Exception, "neuron module has no _pkl method.");
2665  return NULL;
2666  }
2667 
2668  PyObject* ret = PyTuple_New(3);
2669  if (ret == NULL) {
2670  return NULL;
2671  }
2672  PyTuple_SET_ITEM(ret, 0, obj);
2673  PyTuple_SET_ITEM(ret, 1, Py_BuildValue("(N)", PyInt_FromLong(0)));
2674  // see numpy implementation if more ret[1] stuff needed in case we
2675  // pickle anything but a hoc Vector. I don't think ret[1] can be None.
2676 
2677  // Fill object's state. Tuple with 4 args:
2678  // pickle version, 2.0 bytes to determine if swapbytes needed,
2679  // vector size, string data
2680  PyObject* state = PyTuple_New(4);
2681  if (state == NULL) {
2682  Py_DECREF(ret);
2683  return NULL;
2684  }
2685  PyTuple_SET_ITEM(state, 0, PyInt_FromLong(1));
2686  double x = 2.0;
2687  PyObject* str = PyBytes_FromStringAndSize((const char*) (&x), sizeof(double));
2688  if (str == NULL) {
2689  Py_DECREF(ret);
2690  Py_DECREF(state);
2691  return NULL;
2692  }
2693  PyTuple_SET_ITEM(state, 1, str);
2694  PyTuple_SET_ITEM(state, 2, PyInt_FromLong(vec->size()));
2695  str = PyBytes_FromStringAndSize((const char*) vector_vec(vec), vec->size() * sizeof(double));
2696  if (str == NULL) {
2697  Py_DECREF(ret);
2698  Py_DECREF(state);
2699  return NULL;
2700  }
2701  PyTuple_SET_ITEM(state, 3, str);
2702  PyTuple_SET_ITEM(ret, 2, state);
2703  return ret;
2704 }
2705 
2706 // following copied (except for nrn_need_byteswap line) from NEURON ivocvect.cpp
2707 #define BYTEHEADER \
2708  uint32_t _II__; \
2709  char* _IN__; \
2710  char _OUT__[16]; \
2711  int BYTESWAP_FLAG = 0;
2712 #define BYTESWAP(_X__, _TYPE__) \
2713  if (BYTESWAP_FLAG == 1) { \
2714  _IN__ = (char*) &(_X__); \
2715  for (_II__ = 0; _II__ < sizeof(_TYPE__); _II__++) { \
2716  _OUT__[_II__] = _IN__[sizeof(_TYPE__) - _II__ - 1]; \
2717  } \
2718  (_X__) = *((_TYPE__*) &_OUT__); \
2719  }
2720 
2721 static PyObject* hocpickle_setstate(PyObject* self, PyObject* args) {
2722  BYTEHEADER
2723  int version = -1;
2724  int size = -1;
2725  PyObject* rawdata = NULL;
2726  PyObject* endian_data;
2727  PyHocObject* pho = (PyHocObject*) self;
2728  // printf("hocpickle_setstate %s\n", hoc_object_name(pho->ho_));
2729  Vect* vec = (Vect*) pho->ho_->u.this_pointer;
2730  if (!PyArg_ParseTuple(args, "(iOiO)", &version, &endian_data, &size, &rawdata)) {
2731  return NULL;
2732  }
2733  Py_INCREF(endian_data);
2734  Py_INCREF(rawdata);
2735  // printf("hocpickle version=%d size=%d\n", version, size);
2736  vector_resize(vec, size);
2737  if (!PyBytes_Check(rawdata) || !PyBytes_Check(endian_data)) {
2738  PyErr_SetString(PyExc_TypeError, "pickle not returning string");
2739  Py_DECREF(endian_data);
2740  Py_DECREF(rawdata);
2741  return NULL;
2742  }
2743  char* datastr;
2744  Py_ssize_t len;
2745  if (PyBytes_AsStringAndSize(endian_data, &datastr, &len) < 0) {
2746  Py_DECREF(endian_data);
2747  Py_DECREF(rawdata);
2748  return NULL;
2749  }
2750  if (len != sizeof(double)) {
2751  PyErr_SetString(PyExc_ValueError, "endian_data size is not sizeof(double)");
2752  Py_DECREF(endian_data);
2753  Py_DECREF(rawdata);
2754  return NULL;
2755  }
2756  BYTESWAP_FLAG = 0;
2757  if (*((double*) datastr) != 2.0) {
2758  BYTESWAP_FLAG = 1;
2759  }
2760  Py_DECREF(endian_data);
2761  // printf("byteswap = %d\n", BYTESWAP_FLAG);
2762  if (PyBytes_AsStringAndSize(rawdata, &datastr, &len) < 0) {
2763  Py_DECREF(rawdata);
2764  return NULL;
2765  }
2766  if (len != size * sizeof(double)) {
2767  PyErr_SetString(PyExc_ValueError, "buffer size does not match array size");
2768  Py_DECREF(rawdata);
2769  return NULL;
2770  }
2771  if (BYTESWAP_FLAG) {
2772  double* x = (double*) datastr;
2773  for (int i = 0; i < size; ++i) {
2774  BYTESWAP(x[i], double)
2775  }
2776  }
2777  memcpy((char*) vector_vec(vec), datastr, len);
2778  Py_DECREF(rawdata);
2779  Py_INCREF(Py_None);
2780  return Py_None;
2781 }
2782 
2783 static PyObject* libpython_path(PyObject* self, PyObject* args) {
2784 #if defined(HAVE_DLFCN_H) && !defined(MINGW)
2785  Dl_info info;
2786  int rval = dladdr((const void*) Py_Initialize, &info);
2787  if (!rval) {
2788  PyErr_SetString(PyExc_Exception,
2789  "dladdr: Py_Initialize could not be matched to a shared object");
2790  return NULL;
2791  }
2792  if (!info.dli_fname) {
2793  PyErr_SetString(PyExc_Exception,
2794  "dladdr: No symbol matching Py_Initialize could be found.");
2795  return NULL;
2796  }
2797  return Py_BuildValue("s", info.dli_fname);
2798 #else
2799  Py_INCREF(Py_None);
2800  return Py_None;
2801 #endif
2802 }
2803 
2804 // available for every HocObject
2805 static PyMethodDef hocobj_methods[] = {
2806  {"baseattr", hocobj_baseattr, METH_VARARGS, "To allow use of an overrided base method"},
2807  {"hocobjptr", hocobj_vptr, METH_NOARGS, "Hoc Object pointer as a long int"},
2808  {"same",
2809  (PyCFunction) hocobj_same,
2810  METH_VARARGS,
2811  "o1.same(o2) return True if o1 and o2 wrap the same internal HOC Object"},
2812  {"hname", hocobj_name, METH_NOARGS, "More specific than __str__() or __attr__()."},
2813  {"__reduce__", hocpickle_reduce, METH_VARARGS, "pickle interface"},
2814  {"__setstate__", hocpickle_setstate, METH_VARARGS, "pickle interface"},
2815  {NULL, NULL, 0, NULL}};
2816 
2817 // only for a HocTopLevelInterpreter type HocObject
2818 static PyMethodDef toplevel_methods[] = {
2819  {"ref", mkref, METH_VARARGS, "Wrap to allow call by reference in a hoc function"},
2820  {"cas", nrnpy_cas, METH_VARARGS, "Return the currently accessed section."},
2821  {"allsec", nrnpy_forall, METH_VARARGS, "Return iterator over all sections."},
2822  {"Section",
2823  (PyCFunction) nrnpy_newsecobj,
2824  METH_VARARGS | METH_KEYWORDS,
2825  "Return a new Section"},
2826  {"setpointer", setpointer, METH_VARARGS, "Assign hoc variable address to NMODL POINTER"},
2827  {"libpython_path",
2829  METH_NOARGS,
2830  "Return full path to file that contains Py_Initialize()"},
2831  {NULL, NULL, 0, NULL}};
2832 
2833 static void add2topdict(PyObject* dict) {
2834  for (PyMethodDef* meth = toplevel_methods; meth->ml_name != NULL; meth++) {
2835  int err;
2836  PyObject* nn = Py_BuildValue("s", meth->ml_doc);
2837  if (!nn) {
2838  return;
2839  }
2840  err = PyDict_SetItemString(dict, meth->ml_name, nn);
2841  Py_DECREF(nn);
2842  if (err) {
2843  return;
2844  }
2845  }
2846 }
2847 
2848 static PyObject* nrnpy_vec_math = NULL;
2849 
2850 extern "C" int nrnpy_vec_math_register(PyObject* callback) {
2851  nrnpy_vec_math = callback;
2852  return 0;
2853 }
2854 
2855 extern "C" int nrnpy_rvp_pyobj_callback_register(PyObject* callback) {
2856  nrnpy_rvp_pyobj_callback = callback;
2857  return 0;
2858 }
2859 
2860 static bool pyobj_is_vector(PyObject* obj) {
2861  if (PyObject_TypeCheck(obj, hocobject_type)) {
2862  PyHocObject* obj_h = (PyHocObject*) obj;
2863  if (obj_h->type_ == PyHoc::HocObject) {
2864  // this is an object (e.g. Vector) not a function
2865  if (obj_h->ho_->ctemplate == hoc_vec_template_) {
2866  return true;
2867  }
2868  }
2869  }
2870  return false;
2871 }
2872 
2873 static PyObject* py_hocobj_math(const char* op, PyObject* obj1, PyObject* obj2) {
2874  bool potentially_valid = false;
2875  int reversed = 0;
2876  if (pyobj_is_vector(obj1)) {
2877  potentially_valid = true;
2878  } else if (pyobj_is_vector(obj2)) {
2879  potentially_valid = true;
2880  reversed = 1;
2881  }
2882  if (!potentially_valid) {
2883  Py_INCREF(Py_NotImplemented);
2884  return Py_NotImplemented;
2885  }
2886  char buf[8];
2887  return PyObject_CallFunction(nrnpy_vec_math, strcpy(buf, "siOO"), op, reversed, obj1, obj2);
2888 }
2889 
2890 static PyObject* py_hocobj_math_unary(const char* op, PyObject* obj) {
2891  if (pyobj_is_vector(obj)) {
2892  char buf[8];
2893  return PyObject_CallFunction(nrnpy_vec_math, strcpy(buf, "siO"), op, 2, obj);
2894  }
2895  Py_INCREF(Py_NotImplemented);
2896  return Py_NotImplemented;
2897 }
2898 
2899 static PyObject* py_hocobj_add(PyObject* obj1, PyObject* obj2) {
2900  return py_hocobj_math("add", obj1, obj2);
2901 }
2902 
2903 static PyObject* py_hocobj_uabs(PyObject* obj) {
2904  return py_hocobj_math_unary("uabs", obj);
2905 }
2906 
2907 static PyObject* py_hocobj_uneg(PyObject* obj) {
2908  return py_hocobj_math_unary("uneg", obj);
2909 }
2910 
2911 static PyObject* py_hocobj_upos(PyObject* obj) {
2912  return py_hocobj_math_unary("upos", obj);
2913 }
2914 
2915 static PyObject* py_hocobj_sub(PyObject* obj1, PyObject* obj2) {
2916  return py_hocobj_math("sub", obj1, obj2);
2917 }
2918 
2919 static PyObject* py_hocobj_mul(PyObject* obj1, PyObject* obj2) {
2920  return py_hocobj_math("mul", obj1, obj2);
2921 }
2922 
2923 static PyObject* py_hocobj_div(PyObject* obj1, PyObject* obj2) {
2924  return py_hocobj_math("div", obj1, obj2);
2925 }
2926 static PyMemberDef hocobj_members[] = {{NULL, 0, 0, 0, NULL}};
2927 
2928 #include "nrnpy_hoc.h"
2929 
2930 // Figure out the endian-ness of the system, and return
2931 // 0 (error), '<' (little endian) or '>' (big endian)
2933  char endian_character = 0;
2934 
2935  PyObject* psys = PyImport_ImportModule("sys");
2936  if (psys == NULL) {
2937  PyErr_SetString(PyExc_ImportError, "Failed to import sys to determine system byteorder.");
2938  return 0;
2939  }
2940 
2941  PyObject* pbo = PyObject_GetAttrString(psys, "byteorder");
2942  if (pbo == NULL) {
2943  PyErr_SetString(PyExc_AttributeError, "sys module does not have attribute 'byteorder'!");
2944  return 0;
2945  }
2946 
2947  Py2NRNString byteorder(pbo);
2948  if (byteorder.c_str() == NULL) {
2949  return 0;
2950  }
2951 
2952  if (strcmp(byteorder.c_str(), "little") == 0) {
2953  endian_character = '<';
2954  } else if (strcmp(byteorder.c_str(), "big") == 0) {
2955  endian_character = '>';
2956  } else {
2957  PyErr_SetString(PyExc_RuntimeError, "Unknown system native byteorder.");
2958  return 0;
2959  }
2960  return endian_character;
2961 }
2962 
2963 static void sectionlist_helper_(void* sl, Object* args) {
2964  if (!args || args->ctemplate->sym != nrnpy_pyobj_sym_) {
2965  hoc_execerror("argument must be a Python iterable", "");
2966  }
2967  PyObject* pargs = nrnpy_hoc2pyobject(args);
2968 
2969  PyObject* iterator = PyObject_GetIter(pargs);
2970  PyObject* item;
2971 
2972  if (iterator == NULL) {
2973  PyErr_Clear();
2974  hoc_execerror("argument must be an iterable", "");
2975  }
2976 
2977  while ((item = PyIter_Next(iterator))) {
2978  if (!PyObject_TypeCheck(item, psection_type)) {
2979  hoc_execerror("iterable must contain only Section objects", 0);
2980  }
2981  NPySecObj* pysec = (NPySecObj*) item;
2982  lvappendsec_and_ref(sl, pysec->sec_);
2983  Py_DECREF(item);
2984  }
2985 
2986  Py_DECREF(iterator);
2987  if (PyErr_Occurred()) {
2988  PyErr_Clear();
2989  hoc_execerror("argument must be a Python iterable", "");
2990  }
2991 }
2992 
2993 /// value of neuron.coreneuron.enable as 0, 1 (-1 if error)
2994 extern int (*nrnpy_nrncore_enable_value_p_)();
2995 
2996 /// value of neuron.coreneuron.file_mode as 0, 1 (-1 if error)
2997 extern int (*nrnpy_nrncore_file_mode_value_p_)();
2998 
2999 /*
3000  * Helper function to inspect value of int/boolean option
3001  * under coreneuron module.
3002  *
3003  * \todo : seems like this could be generalized so that
3004  * additional cases would require less code.
3005  */
3006 static int get_nrncore_opt_value(const char* option) {
3007  PyObject* modules = PyImport_GetModuleDict();
3008  if (modules) {
3009  PyObject* module = PyDict_GetItemString(modules, "neuron.coreneuron");
3010  if (module) {
3011  PyObject* val = PyObject_GetAttrString(module, option);
3012  if (val) {
3013  long enable = PyLong_AsLong(val);
3014  Py_DECREF(val);
3015  if (enable != -1) {
3016  return enable;
3017  }
3018  }
3019  }
3020  }
3021  if (PyErr_Occurred()) {
3022  PyErr_Print();
3023  return -1;
3024  }
3025  return 0;
3026 }
3027 
3028 /// return value of neuron.coreneuron.enable
3029 static int nrncore_enable_value() {
3030  return get_nrncore_opt_value("enable");
3031 }
3032 
3033 /// return value of neuron.coreneuron.file_mode
3035  return get_nrncore_opt_value("file_mode");
3036 }
3037 
3038 /** Gets the python string returned by neuron.coreneuron.nrncore_arg(tstop)
3039  return a strdup() copy of the string which should be free when the caller
3040  finishes with it. Return NULL if error or bool(neuron.coreneuron.enable)
3041  is False.
3042 */
3043 extern char* (*nrnpy_nrncore_arg_p_)(double tstop);
3044 static char* nrncore_arg(double tstop) {
3045  PyObject* modules = PyImport_GetModuleDict();
3046  if (modules) {
3047  PyObject* module = PyDict_GetItemString(modules, "neuron.coreneuron");
3048  if (module) {
3049  PyObject* callable = PyObject_GetAttrString(module, "nrncore_arg");
3050  if (callable) {
3051  PyObject* ts = Py_BuildValue("(d)", tstop);
3052  if (ts) {
3053  PyObject* arg = PyObject_CallObject(callable, ts);
3054  Py_DECREF(ts);
3055  if (arg) {
3056  Py2NRNString str(arg);
3057  Py_DECREF(arg);
3058  if (str.err()) {
3059  str.set_pyerr(
3060  PyExc_TypeError,
3061  "neuron.coreneuron.nrncore_arg() must return an ascii string");
3062  return NULL;
3063  }
3064  if (strlen(str.c_str()) > 0) {
3065  return strdup(str.c_str());
3066  }
3067  }
3068  }
3069  }
3070  }
3071  }
3072  if (PyErr_Occurred()) {
3073  PyErr_Print();
3074  }
3075  return NULL;
3076 }
3077 
3078 PyObject* nrnpy_hoc() {
3079  PyObject* m;
3094  PyLockGIL lock;
3095 
3096  char endian_character = 0;
3097 
3098  int err = 0;
3099  PyObject* modules = PyImport_GetModuleDict();
3100  if ((m = PyDict_GetItemString(modules, "hoc")) != NULL && PyModule_Check(m)) {
3101  return m;
3102  }
3103  m = PyModule_Create(&hocmodule);
3104  assert(m);
3105  Symbol* s = NULL;
3106  hocobject_type = (PyTypeObject*) PyType_FromSpec(&nrnpy_HocObjectType_spec);
3107  if (PyType_Ready(hocobject_type) < 0)
3108  goto fail;
3109  Py_INCREF(hocobject_type);
3110  // printf("AddObject HocObject\n");
3111  PyModule_AddObject(m, "HocObject", (PyObject*) hocobject_type);
3112 
3113  topmethdict = PyDict_New();
3114  for (PyMethodDef* meth = toplevel_methods; meth->ml_name != NULL; meth++) {
3115  PyObject* descr;
3116  int err;
3117  descr = PyDescr_NewMethod(hocobject_type, meth);
3118  assert(descr);
3119  err = PyDict_SetItemString(topmethdict, meth->ml_name, descr);
3120  Py_DECREF(descr);
3121  if (err < 0) {
3122  goto fail;
3123  }
3124  }
3125 
3126  s = hoc_lookup("Vector");
3127  assert(s);
3130  assert(sym_vec_x);
3131  s = hoc_lookup("List");
3132  assert(s);
3134  s = hoc_lookup("SectionList");
3135  assert(s);
3137  s = hoc_lookup("Matrix");
3138  assert(s);
3140  assert(sym_mat_x);
3141  s = hoc_lookup("NetCon");
3142  assert(s);
3145 
3146  nrnpy_nrn();
3147  endian_character = get_endian_character();
3148  if (endian_character == 0)
3149  goto fail;
3150  array_interface_typestr[0] = endian_character;
3151 
3152  // Setup bytesize in typestr
3153  snprintf(array_interface_typestr + 2, 3, "%ld", sizeof(double));
3154  err = PyDict_SetItemString(modules, "hoc", m);
3155  assert(err == 0);
3156  // Py_DECREF(m);
3157  return m;
3158 fail:
3159  return NULL;
3160 }
void nrn_pushsec(Section *sec)
Definition: cabcode.cpp:99
void cable_prop_assign(Symbol *sym, double *pd, int op)
Definition: cabcode.cpp:1598
void nrn_popsec(void)
Definition: cabcode.cpp:123
Definition: netcon.h:83
Definition: ocjump.h:25
void * fpycall(void *(*)(void *, void *), void *, void *)
Definition: ocjump.cpp:161
Definition: oclist.h:12
long count()
Definition: oclist.cpp:187
Object * object(long)
Definition: oclist.cpp:231
bool err() const
Definition: nrnpy_utils.h:45
char * c_str() const
Definition: nrnpy_utils.h:42
void set_pyerr(PyObject *type, const char *message)
Definition: nrnpy_utils.h:48
char * get_pyerr()
Definition: nrnpy_utils.h:66
virtual const char * varname() const =0
virtual Object * neuron_section_list()=0
virtual float low()=0
virtual void * varobj() const =0
virtual float high()=0
Symbol * hoc_table_lookup(const char *, Symlist *)
Definition: symbol.cpp:61
double t
Definition: cvodeobj.cpp:59
sprintf(buf, " if (secondorder) {\n" " int _i;\n" " for (_i = 0; _i < %d; ++_i) {\n" " _p[_slist%d[_i]] += dt*_p[_dlist%d[_i]];\n" " }}\n", numeqn, listnum, listnum)
DLFCN_EXPORT int dladdr(const void *addr, Dl_info *info)
Definition: dlfcn.c:731
void hoc_execerror(const char *, const char *)
Definition: hoc.cpp:754
char buf[512]
Definition: init.cpp:13
int hoc_is_object_arg(int narg)
Definition: code.cpp:756
void hoc_pushstr(char **d)
Definition: code.cpp:680
void hoc_execerr_ext(const char *fmt,...)
printf style specification of hoc_execerror message.
Definition: fileio.cpp:931
double hoc_call_func(Symbol *s, int narg)
Definition: code.cpp:1462
void hoc_pushpx(double *d)
Definition: code.cpp:716
void hoc_pushobj(Object **d)
Definition: code.cpp:663
void * hoc_sec_internal_name2ptr(const char *s, int eflag)
Definition: cabcode.cpp:762
int hoc_is_str_arg(int narg)
Definition: code.cpp:752
int hoc_is_temp_charptr(char **cpp)
Definition: code.cpp:647
Objectdata * hoc_objectdata
Definition: hoc_oop.cpp:123
void hoc_assign_str(char **cpp, const char *buf)
Definition: code.cpp:2350
int is_obj_type(Object *obj, const char *type_name)
Definition: hoc_oop.cpp:2059
int hoc_is_double_arg(int narg)
Definition: code.cpp:744
char ** hoc_temp_charptr(void)
Definition: code.cpp:642
double hoc_ac_
Definition: hoc_init.cpp:397
void hoc_obj_ref(Object *obj)
Definition: hoc_oop.cpp:1810
char * hoc_object_name(Object *ob)
Definition: hoc_oop.cpp:72
void * hoc_pysec_name2ptr(const char *s, int eflag)
Definition: cabcode.cpp:803
double * hoc_pxpop(void)
Definition: code.cpp:838
Symbol * hoc_lookup(const char *)
double hoc_xpop(void)
int hoc_is_pdouble_arg(int narg)
Definition: code.cpp:748
double * hoc_pgetarg(int narg)
Definition: code.cpp:1623
void hoc_obj_unref(Object *obj)
Definition: hoc_oop.cpp:1828
void hoc_push_object(Object *d)
Definition: code.cpp:673
char ** hoc_pgargstr(int narg)
Definition: code.cpp:1599
int hoc_usegui
Definition: hoc.cpp:148
Objectdata * hoc_objectdata_restore(Objectdata *obdsav)
Definition: hoc_oop.cpp:143
Objectdata * hoc_objectdata_save(void)
Definition: hoc_oop.cpp:133
#define assert(ex)
Definition: hocassrt.h:32
#define HocContextRestore
Definition: hoccontext.h:17
#define HocTopContextSet
Definition: hoccontext.h:10
#define OBJECTALIAS
Definition: hocdec.h:107
#define USERPROPERTY
Definition: hocdec.h:94
#define JAVAOBJECT
Definition: hocdec.h:105
#define ISARRAY(arg)
Definition: hocdec.h:164
#define USERFLOAT
Definition: hocdec.h:95
#define USERDOUBLE
Definition: hocdec.h:93
#define getarg
Definition: hocdec.h:15
#define OBJECTTMP
Definition: hocdec.h:101
#define gargstr
Definition: hocdec.h:14
#define CPLUSOBJECT
Definition: hocdec.h:104
#define DYNAMICUNITS
Definition: hocdec.h:103
#define USERINT
Definition: hocdec.h:92
#define OPSTR(sym)
Definition: hocdec.h:307
#define STOP
Definition: hocdec.h:66
#define VARALIAS
Definition: hocdec.h:108
#define OBJ(q)
Definition: hoclist.h:67
void hoc_l_delete(hoc_Item *)
Object ** hoc_objgetarg(int)
Definition: code.cpp:1587
void
int ifarg(int)
Definition: code.cpp:1581
void hoc_pushx(double)
int vector_capacity(Vect *v)
Definition: ivocvect.cpp:319
void vector_resize(Vect *v, int n)
Definition: ivocvect.cpp:322
double * vector_vec(Vect *v)
Definition: ivocvect.cpp:328
static int narg()
Definition: ivocvect.cpp:150
Object * hoc_thisobject
Definition: hoc_oop.cpp:122
#define Vect
Definition: ivocvect.h:14
Object ** hoc_temp_objptr(Object *)
Definition: code.cpp:216
#define v
Definition: md1redef.h:4
#define sec
Definition: md1redef.h:13
#define i
Definition: md1redef.h:12
#define prop
Definition: md1redef.h:29
#define CABLESECTION
Definition: membfunc.h:62
#define ITERATE(itm, lst)
Definition: model.h:25
char * name
Definition: init.cpp:16
long subtype
Definition: init.cpp:215
Item * next(Item *item)
Definition: list.cpp:88
#define printf
Definition: mwprefix.h:26
IteratorState
Definition: nrnpython.h:72
@ NextNotLast
Definition: nrnpython.h:72
@ Last
Definition: nrnpython.h:72
@ Begin
Definition: nrnpython.h:72
ObjectType
Definition: nrnpython.h:58
@ HocScalarPtr
Definition: nrnpython.h:68
@ HocRefObj
Definition: nrnpython.h:65
@ HocRefNum
Definition: nrnpython.h:63
@ HocForallSectionIterator
Definition: nrnpython.h:66
@ HocArrayIncomplete
Definition: nrnpython.h:69
@ HocRefStr
Definition: nrnpython.h:64
@ HocObject
Definition: nrnpython.h:60
@ HocArray
Definition: nrnpython.h:62
@ HocRefPStr
Definition: nrnpython.h:70
@ HocTopLevelInterpreter
Definition: nrnpython.h:59
@ HocSectionListIterator
Definition: nrnpython.h:67
@ HocFunction
Definition: nrnpython.h:61
Point_process * ob2pntproc_0(Object *)
Definition: hocmech.cpp:78
static List * info
#define NRNPOINTER
Definition: nocpout.cpp:100
void section_unref(Section *)
Definition: solve.cpp:565
int const size_t stride
Definition: nrngsl.h:11
int const size_t const size_t n
Definition: nrngsl.h:11
#define FUNCTION(a, b)
Definition: nrngsl.h:6
size_t q
if(status)
size_t p
size_t j
hoc_List * section_list
Definition: init.cpp:102
Object **(* nrnpy_gui_helper3_)(const char *, Object *, int)
Definition: xmenu.cpp:15
Object * nrnpy_pyobject_in_obj(PyObject *)
Definition: nrnpy_p2h.cpp:210
static void hocobj_dealloc(PyHocObject *self)
Definition: nrnpy_hoc.cpp:181
int nrnpy_numbercheck(PyObject *po)
Definition: nrnpy_hoc.cpp:474
static PyObject * plotshape_plot
Definition: nrnpy_hoc.cpp:154
static char * double_array_interface(PyObject *po, long &stride)
Definition: nrnpy_hoc.cpp:2226
static Symbol * getsym(char *name, Object *ho, int fail)
Definition: nrnpy_hoc.cpp:416
static PyObject * cpp2refstr(char **cpp)
Definition: nrnpy_hoc.cpp:2022
double ** nrnpy_setpointer_helper(PyObject *, PyObject *)
Definition: nrnpy_nrn.cpp:2141
static PyObject * hocobj_name(PyObject *pself, PyObject *args)
Definition: nrnpy_hoc.cpp:282
static PyObject * hocobj_same(PyHocObject *pself, PyObject *args)
Definition: nrnpy_hoc.cpp:2213
static PyObject * hocobj_getattro(PyObject *subself, PyObject *name)
Definition: nrnpy_hoc.cpp:1292
static Symbol * sym_mat_x
Definition: nrnpy_hoc.cpp:1500
static PyObject * py_hocobj_add(PyObject *obj1, PyObject *obj2)
Definition: nrnpy_hoc.cpp:2899
static cTemplate * hoc_vec_template_
Definition: nrnpy_hoc.cpp:100
static cTemplate * hoc_list_template_
Definition: nrnpy_hoc.cpp:101
static cTemplate * hoc_sectionlist_template_
Definition: nrnpy_hoc.cpp:102
static IvocVect * nrnpy_vec_from_python(void *v)
Definition: nrnpy_hoc.cpp:2268
static int nrncore_file_mode_value()
return value of neuron.coreneuron.file_mode
Definition: nrnpy_hoc.cpp:3034
Object * nrnpy_po2ho(PyObject *)
Definition: nrnpy_hoc.cpp:520
int nrnpy_vec_math_register(PyObject *callback)
Definition: nrnpy_hoc.cpp:2850
char ** hoc_strpop()
Definition: code.cpp:879
PyTypeObject * psection_type
Definition: nrnpy_nrn.cpp:79
static void hocobj_pushargs_free_strings(std::vector< char * > &s2free)
Definition: nrnpy_hoc.cpp:406
static PyObject * curargs_
Definition: nrnpy_hoc.cpp:698
int nrnpy_set_toplevel_callbacks(PyObject *rvp_plot0, PyObject *plotshape_plot0, PyObject *get_mech_object_0, PyObject *store_savestate, PyObject *restore_savestate)
Definition: nrnpy_hoc.cpp:2380
Object * hoc_obj_look_inside_stack(int)
Definition: code.cpp:770
static PyObject * py_hocobj_uabs(PyObject *obj)
Definition: nrnpy_hoc.cpp:2903
static PyObject * nrnexec(PyObject *self, PyObject *args)
Definition: nrnpy_hoc.cpp:162
void(* nrnpy_decref)(void *pyobj)
Definition: shapeplt.cpp:47
static int hocobj_init(PyObject *subself, PyObject *args, PyObject *kwds)
Definition: nrnpy_hoc.cpp:256
#define BYTEHEADER
Definition: nrnpy_hoc.cpp:2707
static int hocobj_pushargs(PyObject *args, std::vector< char * > &s2free)
Definition: nrnpy_hoc.cpp:337
static PyObject * store_savestate_
Definition: nrnpy_hoc.cpp:2331
static PyObject * gui_helper_3_helper_(const char *name, Object *obj, int handle_strptr)
Definition: nrnpy_hoc.cpp:2424
static PyObject * hocobj_call(PyHocObject *self, PyObject *args, PyObject *kwrds)
Definition: nrnpy_hoc.cpp:704
int nrnpy_rvp_pyobj_callback_register(PyObject *callback)
Definition: nrnpy_hoc.cpp:2855
static void * nrnpy_hoc_bool_pop()
Definition: nrnpy_hoc.cpp:639
void hoc_objectvar()
Definition: hoc_oop.cpp:855
static PyObject * gui_callback
Definition: nrnpy_hoc.cpp:2395
static Inst * save_pc(Inst *newpc)
Definition: nrnpy_hoc.cpp:331
Symlist * hoc_top_level_symlist
Definition: symdir.cpp:23
void hoc_call()
Symbol * nrnpy_pyobj_sym_
Section * nrn_noerr_access()
Definition: cabcode.cpp:472
void(* nrnpy_sectionlist_helper_)(void *, Object *)
static void hocobj_objectvar(Symbol *sym)
Definition: nrnpy_hoc.cpp:842
static PyObject * setpointer(PyObject *self, PyObject *args)
Definition: nrnpy_hoc.cpp:2043
int nrn_inpython_
Definition: hoc.cpp:37
static Object ** vec_as_numpy_helper(int size, double *data)
Definition: nrnpy_hoc.cpp:2523
Object ** hoc_objpop()
Definition: code.cpp:860
int ivoc_list_count(Object *)
Definition: oclist.cpp:408
static void * nrnpy_hoc_int_pop()
Definition: nrnpy_hoc.cpp:635
static Object ** gui_helper_3_(const char *name, Object *obj, int handle_strptr)
Definition: nrnpy_hoc.cpp:2491
int hoc_max_builtin_class_id
Definition: hoc_oop.cpp:40
double cable_prop_eval(Symbol *sym)
Definition: cabcode.cpp:1518
Symbol * ivoc_alias_lookup(const char *name, Object *ob)
Definition: strfun.cpp:104
static PyObject * hocpickle_reduce(PyObject *self, PyObject *args)
Definition: nrnpy_hoc.cpp:2647
static PyObject * hocobj_iter(PyObject *self)
Definition: nrnpy_hoc.cpp:1596
PyObject * nrnpy_nrn()
Definition: nrnpy_nrn.cpp:2481
static PyObject * py_hocobj_uneg(PyObject *obj)
Definition: nrnpy_hoc.cpp:2907
double(* nrnpy_object_to_double_)(Object *)
Definition: xmenu.cpp:14
static PyObject * hoc_ac(PyObject *self, PyObject *args)
Definition: nrnpy_hoc.cpp:171
static PyObject *(* vec_as_numpy)(int, double *)
Definition: nrnpy_hoc.cpp:2325
PyObject * nrnpy_hoc_pop()
Definition: nrnpy_hoc.cpp:547
static void add2topdict(PyObject *)
Definition: nrnpy_hoc.cpp:2833
static PyObject * py_hocobj_upos(PyObject *obj)
Definition: nrnpy_hoc.cpp:2911
int hoc_stack_type()
Definition: code.cpp:654
void hoc_pushs(Symbol *)
static void * fcall(void *vself, void *vargs)
Definition: nrnpy_hoc.cpp:643
PyObject * nrnpy_forall(PyObject *, PyObject *)
Definition: nrnpy_hoc.cpp:1587
static void pyobject_in_objptr(Object **, PyObject *)
Definition: nrnpy_hoc.cpp:274
static int araylen(Arrayinfo *a, PyHocObject *po)
Definition: nrnpy_hoc.cpp:1503
static PyObject * libpython_path(PyObject *self, PyObject *args)
Definition: nrnpy_hoc.cpp:2783
void sec_access_push()
Definition: cabcode.cpp:747
PyObject * nrnpy_cas(PyObject *, PyObject *)
Definition: nrnpy_nrn.cpp:2448
static double object_to_double_(Object *obj)
Definition: nrnpy_hoc.cpp:2401
static hoc_Item * next_valid_secitem(hoc_Item *q, hoc_Item *ql)
Definition: nrnpy_hoc.cpp:1629
static void eval_component(PyHocObject *po, int ix)
Definition: nrnpy_hoc.cpp:862
void *(* nrnpy_get_pyobj)(Object *obj)
Definition: shapeplt.cpp:46
static int hocobj_setattro(PyObject *subself, PyObject *pyname, PyObject *value)
Definition: nrnpy_hoc.cpp:1310
static char * nrncore_arg(double tstop)
Definition: nrnpy_hoc.cpp:3044
static PyObject * mkref(PyObject *self, PyObject *args)
Definition: nrnpy_hoc.cpp:1991
static PyObject * pfunc_get_docstring
Definition: nrnpy_hoc.cpp:114
static PyObject * py_hocobj_div(PyObject *obj1, PyObject *obj2)
Definition: nrnpy_hoc.cpp:2923
static PyObject * hocobj_baseattr(PyObject *subself, PyObject *args)
Definition: nrnpy_hoc.cpp:1283
double * hoc_evalpointer()
Definition: code.cpp:1909
Object **(* nrnpy_vec_as_numpy_helper_)(int, double *)
Definition: ivocvect.cpp:140
int nrn_is_hocobj_ptr(PyObject *po, double *&pd)
Definition: nrnpy_hoc.cpp:878
static int hocobj_setitem(PyObject *self, Py_ssize_t i, PyObject *arg)
Definition: nrnpy_hoc.cpp:1890
static int setup_doc_system()
Definition: nrnpy_hoc.cpp:907
int(* nrnpy_nrncore_file_mode_value_p_)()
value of neuron.coreneuron.file_mode as 0, 1 (-1 if error)
PyObject * nrnpy_ho2po(Object *)
Definition: nrnpy_hoc.cpp:499
void hoc_push_string()
Definition: code.cpp:685
void hoc_tobj_unref(Object **)
Definition: code.cpp:226
static PyMethodDef hocobj_methods[]
Definition: nrnpy_hoc.cpp:2805
static void nrnpy_restore_savestate_(int64_t size, char *data)
Definition: nrnpy_hoc.cpp:2358
static void hocobj_pushtop(PyHocObject *po, Symbol *sym, int ix)
Definition: nrnpy_hoc.cpp:827
static PyMethodDef toplevel_methods[]
Definition: nrnpy_hoc.cpp:2818
void hoc_object_component()
Definition: hoc_oop.cpp:999
void lvappendsec_and_ref(void *sl, Section *sec)
Definition: seclist.cpp:25
static PyObject * nrnpy_rvp_pyobj_callback
Definition: nrnpy_hoc.cpp:157
static PyObject * hocobj_richcmp(PyHocObject *self, PyObject *other, int op)
Definition: nrnpy_hoc.cpp:2136
static bool pyobj_is_vector(PyObject *obj)
Definition: nrnpy_hoc.cpp:2860
PyObject * pmech_types
Definition: nrnpy_nrn.cpp:88
static PyObject * py_hocobj_math_unary(const char *op, PyObject *obj)
Definition: nrnpy_hoc.cpp:2890
void hoc_unref_defer()
Definition: code.cpp:247
static PyObject * hocobj_repr(PyObject *p)
Definition: nrnpy_hoc.cpp:327
static Symbol * sym_vec_x
Definition: nrnpy_hoc.cpp:1499
PyObject * nrnpy_pushsec(PyObject *)
Definition: nrnpy_nrn.cpp:1263
static PyObject * hocobj_vptr(PyObject *pself, PyObject *args)
Definition: nrnpy_hoc.cpp:2091
static int get_nrncore_opt_value(const char *option)
Definition: nrnpy_hoc.cpp:3006
int section_object_seen
Object **(* nrnpy_vec_to_python_p_)(void *)
Definition: ivocvect.cpp:139
static PyObject * rvp_plot
Definition: nrnpy_hoc.cpp:153
static PyObject * py_hocobj_sub(PyObject *obj1, PyObject *obj2)
Definition: nrnpy_hoc.cpp:2915
int nrnpy_set_gui_callback(PyObject *)
Definition: nrnpy_hoc.cpp:2396
Object * hoc_newobj1(Symbol *, int)
Definition: hoc_oop.cpp:565
static PyHocObject * intermediate(PyHocObject *po, Symbol *sym, int ix)
Definition: nrnpy_hoc.cpp:801
static PyObject * py_hocobj_math(const char *op, PyObject *obj1, PyObject *obj2)
Definition: nrnpy_hoc.cpp:2873
void(* nrnpy_restore_savestate)(int64_t, char *)
Definition: savstate.cpp:31
static int refuse_to_look
Definition: nrnpy_hoc.cpp:1291
static PyMethodDef HocMethods[]
Definition: nrnpy_hoc.cpp:176
int nrn_netcon_weight(NetCon *, double **)
Definition: netcvode.cpp:160
static PyObject * hocobj_getitem(PyObject *self, Py_ssize_t ix)
Definition: nrnpy_hoc.cpp:1765
static char array_interface_typestr[5]
Definition: nrnpy_hoc.cpp:110
char *(* nrnpy_nrncore_arg_p_)(double tstop)
Gets the python string returned by neuron.coreneuron.nrncore_arg(tstop) return a strdup() copy of the...
int hoc_return_type_code
Definition: code.cpp:42
PyObject * hocobj_call_arg(int i)
Definition: nrnpy_hoc.cpp:700
PyObject * toplevel_get(PyObject *subself, const char *n)
Definition: nrnpy_hoc.cpp:927
static int hocobj_nonzero(PyObject *self)
Definition: nrnpy_hoc.cpp:1568
char **(* nrnpy_gui_helper3_str_)(const char *, Object *, int)
Definition: xmenu.cpp:16
static PyObject * restore_savestate_
Definition: nrnpy_hoc.cpp:2332
static PyObject * nrnpy_vec_math
Definition: nrnpy_hoc.cpp:2848
static Arrayinfo * hocobj_aray(Symbol *sym, Object *ho)
Definition: nrnpy_hoc.cpp:780
static Object ** nrnpy_vec_to_python(void *v)
Definition: nrnpy_hoc.cpp:2537
static void nrnpy_decref_(void *pyobj)
Definition: nrnpy_hoc.cpp:2417
static Py_ssize_t hocobj_len(PyObject *self)
Definition: nrnpy_hoc.cpp:1541
PyObject * nrn_hocobj_ptr(double *pd)
Definition: nrnpy_hoc.cpp:870
static PyObject * hocobj_iternext(PyObject *self)
Definition: nrnpy_hoc.cpp:1740
static int set_final_from_stk(PyObject *po)
Definition: nrnpy_hoc.cpp:582
PyObject * rangevars_
Definition: nrnpy_nrn.cpp:89
static void symlist2dict(Symlist *sl, PyObject *dict)
Definition: nrnpy_hoc.cpp:890
int nrnpy_set_vec_as_numpy(PyObject *(*p)(int, double *))
Definition: nrnpy_hoc.cpp:2326
static int araychk(Arrayinfo *a, PyHocObject *po, int ix)
Definition: nrnpy_hoc.cpp:1524
static long hocobj_hash(PyHocObject *self)
Definition: nrnpy_hoc.cpp:2103
static int nrncore_enable_value()
return value of neuron.coreneuron.enable
Definition: nrnpy_hoc.cpp:3029
Object **(* nrnpy_gui_helper_)(const char *, Object *)
HAVE_IV.
Definition: xmenu.cpp:13
static void nrnpy_store_savestate_(char **save_data, uint64_t *save_data_size)
Definition: nrnpy_hoc.cpp:2335
int(* nrnpy_nrncore_enable_value_p_)()
value of neuron.coreneuron.enable as 0, 1 (-1 if error)
static PyObject * hocobj_new(PyTypeObject *subtype, PyObject *args, PyObject *kwds)
Definition: nrnpy_hoc.cpp:207
Symbol * nrn_child_sym
Definition: secref.cpp:27
static Object ** gui_helper_(const char *name, Object *obj)
Definition: nrnpy_hoc.cpp:2519
Objectdata * hoc_top_level_data
Definition: hoc_oop.cpp:124
char get_endian_character()
Definition: nrnpy_hoc.cpp:2932
static PyObject * iternext_sl(PyHocObject *po, hoc_Item *ql)
Definition: nrnpy_hoc.cpp:1644
int nrn_secref_nchild(Section *)
Definition: secref.cpp:226
static Symbol * sym_netcon_weight
Definition: nrnpy_hoc.cpp:1501
Symlist * hoc_built_in_symlist
Definition: ivocmac.cpp:76
PyObject * get_plotshape_data(PyObject *sp)
Definition: nrnpy_hoc.cpp:2616
PyObject * nrn_ptr_richcmp(void *self_ptr, void *other_ptr, int op)
Definition: nrnpy_hoc.cpp:2107
static int component(PyHocObject *po)
Definition: nrnpy_hoc.cpp:445
static void sectionlist_helper_(void *sl, Object *args)
Definition: nrnpy_hoc.cpp:2963
PyTypeObject * hocobject_type
Definition: nrnpy_hoc.cpp:159
static PyObject * py_hocobj_mul(PyObject *obj1, PyObject *obj2)
Definition: nrnpy_hoc.cpp:2919
void nrn_change_nseg(Section *, int)
Definition: cabcode.cpp:1557
static PyObject * hocobj_getsec(Symbol *sym)
Definition: nrnpy_hoc.cpp:850
static PyObject * hocobj_getattr(PyObject *subself, PyObject *pyname)
Definition: nrnpy_hoc.cpp:944
static char ** gui_helper_3_str_(const char *name, Object *obj, int handle_strptr)
Definition: nrnpy_hoc.cpp:2505
static void * nrnpy_get_pyobj_(Object *obj)
Definition: nrnpy_hoc.cpp:2409
NPySecObj * newpysechelp(Section *sec)
Definition: nrnpy_nrn.cpp:865
static PyObject * hocpickle_setstate(PyObject *self, PyObject *args)
Definition: nrnpy_hoc.cpp:2721
static Object * rvp_rxd_to_callable_(Object *obj)
Definition: nrnpy_hoc.cpp:2602
PyObject * nrnpy_hoc2pyobject(Object *)
Definition: nrnpy_p2h.cpp:196
#define BYTESWAP(_X__, _TYPE__)
Definition: nrnpy_hoc.cpp:2712
static const char * hocobj_docstring
Definition: nrnpy_hoc.cpp:122
static PyObject * topmethdict
Definition: nrnpy_hoc.cpp:119
int nrn_matrix_dim(void *, int)
Definition: ocmatrix.cpp:27
Object *(* nrnpy_rvp_rxd_to_callable)(Object *)
Definition: spaceplt.cpp:27
bool hoc_valid_stmt(const char *, Object *)
Definition: ocjump.cpp:35
IvocVect *(* nrnpy_vec_from_python_p_)(void *)
Definition: ivocvect.cpp:138
Inst * hoc_pc
static PyObject * get_mech_object_
Definition: nrnpy_hoc.cpp:156
PyObject * nrnpy_hoc()
Definition: nrnpy_hoc.cpp:3078
static PyMemberDef hocobj_members[]
Definition: nrnpy_hoc.cpp:2926
PyObject * nrnpy_newsecobj(PyObject *, PyObject *, PyObject *)
Definition: nrnpy_nrn.cpp:373
void(* nrnpy_store_savestate)(char **save_data, uint64_t *save_data_size)
Definition: savstate.cpp:32
static PyType_Spec nrnpy_HocObjectType_spec
Definition: nrnpy_hoc.h:30
static struct PyModuleDef hocmodule
Definition: nrnpy_hoc.h:39
void nrnpy_sec_referr()
Definition: nrnpy_nrn.cpp:135
int nrn_pointer_assign(Prop *prop, Symbol *sym, PyObject *value)
Definition: nrnpy_nrn.cpp:1905
bool is_python_string(PyObject *python_string)
Definition: nrnpy_utils.h:7
#define PyInt_FromLong
Definition: nrnpython.h:29
#define castptr2long
Definition: nrnpython.h:40
#define PyInt_Check
Definition: nrnpython.h:25
#define PyString_FromString
Definition: nrnpython.h:24
#define PyInt_AS_LONG
Definition: nrnpython.h:27
#define lock
static N_Vector x_
static double ref(void *v)
Definition: ocbox.cpp:383
#define STRING
Definition: bbslsrv.cpp:9
static double done(void *v)
Definition: ocbbs.cpp:282
#define e
Definition: passive0.cpp:22
#define data
Definition: rbtqueue.cpp:49
#define arg
Definition: redef.h:28
#define ret
Definition: redef.h:123
int _nrnunit_use_legacy_
Definition: hoc_init.cpp:409
static uint32_t value
Definition: scoprand.cpp:25
sl
Definition: seclist.cpp:181
o
Definition: seclist.cpp:175
#define PROP_PY_INDEX
Definition: section.h:212
#define key
Definition: spt2queue.cpp:20
#define NULL
Definition: sptree.h:16
int nsub
Definition: hocdec.h:70
int sub[1]
Definition: hocdec.h:72
void * element
Definition: model.h:18
struct Item * next
Definition: model.h:19
PyObject * cell_
Definition: nrnpy_hoc.cpp:28
PyObject_HEAD Section * sec_
Definition: nrnpy_hoc.cpp:26
char * name_
Definition: nrnpy_hoc.cpp:27
Definition: hocdec.h:227
void * aliases
Definition: hocdec.h:239
Objectdata * dataspace
Definition: hocdec.h:231
int index
Definition: hocdec.h:229
int refcount
Definition: hocdec.h:228
union Object::@39 u
Prop * prop
Definition: section.h:265
Definition: section.h:214
PyObject_HEAD Object * ho_
Definition: nrnpy_hoc.cpp:137
int nindex_
Definition: grids.h:48
void * iteritem_
Definition: grids.h:47
Symbol * sym_
Definition: nrnpy_hoc.cpp:146
PyObject_HEAD void * ho_
Definition: grids.h:39
PyHoc::IteratorState its_
Definition: nrnpy_hoc.cpp:144
char * s_
Definition: grids.h:42
double x_
Definition: grids.h:41
void * sym_
Definition: grids.h:46
char ** pstr_
Definition: nrnpy_hoc.cpp:141
int type_
Definition: grids.h:50
Object * ho_
Definition: nrnpy_hoc.cpp:142
union PyHocObject::@27 u
int * indices_
Definition: grids.h:49
PyHoc::ObjectType type_
Definition: nrnpy_hoc.cpp:150
double * px_
Definition: grids.h:44
Definition: model.h:57
short type
Definition: model.h:58
struct Symbol::@37::@38 rng
int * pvalint
Definition: hocdec.h:141
long subtype
Definition: model.h:59
union Symbol::@18 u
char * name
Definition: model.h:72
HocStruct cTemplate * ctemplate
Definition: hocdec.h:152
int oboff
Definition: hocdec.h:132
Arrayinfo * arayinfo
Definition: hocdec.h:159
Definition: hocdec.h:84
Symlist * symtable
Definition: hocdec.h:197
Definition: dlfcn.h:72
struct Section * sec
Definition: hoclist.h:46
union hoc_Item::@40 element
Definition: hocdec.h:51
HocUnion Inst * in
Definition: hocdec.h:60
int i
Definition: hocdec.h:63
HocStruct Symbol * sym
Definition: hocdec.h:61
Arrayinfo * arayinfo
Definition: hocdec.h:223