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