NEURON
nrnpython.cpp
Go to the documentation of this file.
1 #include <nrnpython.h>
2 #include <nrnpy_utils.h>
3 #include <stdio.h>
4 #include <InterViews/resource.h>
5 #if HAVE_IV
6 #include <InterViews/session.h>
7 #endif
8 #include <nrnoc2iv.h>
9 #include <nrnpy_reg.h>
10 #include <hoccontext.h>
11 #include <string>
12 #include <ocfile.h> // bool isDirExist(const std::string& path);
13 
14 #include <hocstr.h>
15 extern "C" void nrnpython_real();
16 extern "C" int nrnpython_start(int);
17 extern int hoc_get_line();
18 extern HocStr* hoc_cbufstr;
19 extern int nrnpy_nositeflag;
20 extern char* nrnpy_pyhome;
21 extern char* hoc_ctp;
22 extern FILE* hoc_fin;
23 extern const char* hoc_promptstr;
24 extern char* neuronhome_forward();
25 #if DARWIN || defined(__linux__)
26 extern const char* path_prefix_to_libnrniv();
27 #endif
28 static char* nrnpython_getline(FILE*, FILE*, const char*);
29 extern int nrn_global_argc;
30 extern char** nrn_global_argv;
31 void nrnpy_augment_path();
32 int nrnpy_pyrun(const char*);
33 extern int (*p_nrnpy_pyrun)(const char*);
34 extern int nrn_global_argc;
35 extern char** nrn_global_argv;
36 #if NRNPYTHON_DYNAMICLOAD
37 int nrnpy_site_problem;
38 #endif
39 
40 extern "C" {
41 extern void rl_stuff_char(int);
42 } // extern "C"
43 
45  static int augmented = 0;
46  if (!augmented && strlen(neuronhome_forward()) > 0) {
47  augmented = 1;
48  int err = PyRun_SimpleString("import sys");
49  assert(err == 0);
50 #if defined(__linux__) || defined(DARWIN)
51  // If /where/installed/lib/python/neuron exists, then append to sys.path
52  std::string lib = std::string(path_prefix_to_libnrniv());
53 #else // not defined(__linux__) || defined(DARWIN)
54  std::string lib = std::string(neuronhome_forward()) + std::string("/lib/");
55 #endif //not defined(__linux__) || defined(DARWIN)
56  if (isDirExist(lib + std::string("python/neuron"))) {
57  std::string cmd = std::string("sys.path.append('") + lib + "python')";
58  err = PyRun_SimpleString(cmd.c_str());
59  assert(err == 0);
60  }
61  err = PyRun_SimpleString("sys.path.insert(0, '')");
62  assert(err == 0);
63  }
64 }
65 
66 /** @brief Execute a Python script.
67  * @return 0 on failure, 1 on success.
68  */
69 int nrnpy_pyrun(const char* fname) {
70 #ifdef MINGW
71  // perhaps this should be the generic implementation
72  char* cmd = new char[strlen(fname) + 40];
73  sprintf(cmd, "exec(open(\"%s\").read(), globals())", fname);
74  int err = PyRun_SimpleString(cmd);
75  delete [] cmd;
76  if (err != 0) {
77  PyErr_Print();
78  PyErr_Clear();
79  return 0;
80  }
81  return 1;
82 #else // MINGW not defined
83  FILE* fp = fopen(fname, "r");
84  if (fp) {
85  int const code = PyRun_AnyFile(fp, fname);
86  fclose(fp);
87  return !code;
88  } else {
89  std::cerr << "Could not open " << fname << std::endl;
90  return 0;
91  }
92 #endif // MINGW not defined
93 }
94 
95 static wchar_t** wcargv;
96 
97 static void del_wcargv(int argc) {
98  if (wcargv) {
99  for (int i = 0; i < argc; ++i) {
100  PyMem_Free(wcargv[i]);
101  }
102  PyMem_Free(wcargv);
103  wcargv = NULL;
104  }
105 }
106 
107 static void copy_argv_wcargv(int argc, char** argv) {
108  del_wcargv(argc);
109  // basically a copy of code from Modules/python.c
110  wcargv = (wchar_t**)PyMem_Malloc(sizeof(wchar_t*) * argc);
111  if (!wcargv) {
112  fprintf(stderr, "out of memory\n");
113  exit(1);
114  }
115  for (int i = 0; i < argc; ++i) {
116  wcargv[i] = Py_DecodeLocale(argv[i], NULL);
117  if (!wcargv[i]) {
118  fprintf(stderr, "out of memory\n");
119  exit(1);
120  }
121  }
122 }
123 
124 static wchar_t* mywstrdup(char* s) {
125  size_t sz = mbstowcs(NULL, s, 0);
126  wchar_t* ws = new wchar_t[sz + 1];
127  int count = mbstowcs(ws, s, sz + 1);
128  return ws;
129 }
130 
131 /** @brief Start the Python interpreter.
132  * @arg b Mode of operation, can be 0 (finalize), 1 (initialize),
133  * or 2 (execute commands/scripts)
134  * @return 0 on success, non-zero on error
135  *
136  * There is an internal state variable that stores whether or not Python has
137  * been initialized. Mode 1 only has an effect if Python is not initialized,
138  * while the other modes only take effect if Python is already initialized.
139  */
140 extern "C" int nrnpython_start(int b) {
141 #if USE_PYTHON
142  static int started = 0;
143  //printf("nrnpython_start %d started=%d\n", b, started);
144  if (b == 1 && !started) {
146  if (nrnpy_nositeflag) {
147  Py_NoSiteFlag = 1;
148  }
149  // nrnpy_pyhome hopefully holds the python base root and should
150  // work with virtual environments.
151  // But use only if not overridden by the PYTHONHOME environment variable.
152  char * _p_pyhome = getenv("PYTHONHOME");
153  if (_p_pyhome == NULL) {
154  _p_pyhome = nrnpy_pyhome;
155  }
156  if (_p_pyhome) {
157  Py_SetPythonHome(mywstrdup(_p_pyhome));
158  }
159  Py_Initialize();
160 #if NRNPYTHON_DYNAMICLOAD
161  // return from Py_Initialize means there was no site problem
162  nrnpy_site_problem = 0;
163 #endif
165  PySys_SetArgv(nrn_global_argc, wcargv);
166  started = 1;
167  // see nrnpy_reg.h
168  for (int i = 0; nrnpy_reg_[i]; ++i) {
169  (*nrnpy_reg_[i])();
170  }
172  }
173  if (b == 0 && started) {
174  PyGILState_STATE gilsav = PyGILState_Ensure();
175  Py_Finalize();
177  // because of finalize, no PyGILState_Release(gilsav);
178  started = 0;
179  }
180  if (b == 2 && started) {
181  int i;
183  PySys_SetArgv(nrn_global_argc, wcargv);
185 #if !defined(MINGW)
186  // cannot get this to avoid crashing with MINGW
187  PyOS_ReadlineFunctionPointer = nrnpython_getline;
188 #endif
189  // Is there a -c "command" or file.py arg.
190  bool python_error_encountered{false};
191  for (i = 1; i < nrn_global_argc; ++i) {
192  char* arg = nrn_global_argv[i];
193  if (strcmp(arg, "-c") == 0 && i + 1 < nrn_global_argc) {
194  if(PyRun_SimpleString(nrn_global_argv[i + 1])) {
195  python_error_encountered = true;
196  }
197  break;
198  } else if (strlen(arg) > 3 && strcmp(arg + strlen(arg) - 3, ".py") == 0) {
199  if(!nrnpy_pyrun(arg)) {
200  python_error_encountered = true;
201  }
202  break;
203  }
204  }
205  // python_error_encountered dictates whether NEURON will exit with a nonzero
206  // code. In noninteractive/batch mode that happens immediately, in
207  // interactive mode then we start a Python interpreter first.
208  if(nrn_istty_) {
209  PyRun_InteractiveLoop(hoc_fin, "stdin");
210  }
211  return python_error_encountered;
212  }
213 #endif
214  return 0;
215 }
216 
217 extern "C" void nrnpython_real() {
218  int retval = 0;
219 #if USE_PYTHON
221  {
222  PyLockGIL lock;
223  retval = PyRun_SimpleString(gargstr(1)) == 0;
224  }
226 #endif
227  hoc_retpushx(double(retval));
228 }
229 
230 static char* nrnpython_getline(FILE*, FILE*, const char* prompt) {
231  hoc_cbufstr->buf[0] = '\0';
232  hoc_promptstr = prompt;
233  int r = hoc_get_line();
234  // printf("r=%d c=%d\n", r, hoc_cbufstr->buf[0]);
235  if (r == 1) {
236  size_t n = strlen(hoc_cbufstr->buf) + 1;
237  hoc_ctp = hoc_cbufstr->buf + n - 1;
238  char* p = static_cast<char*>(PyMem_RawMalloc(n));
239  if (p == 0) {
240  return 0;
241  }
242  strcpy(p, hoc_cbufstr->buf);
243  return p;
244  } else if (r == EOF) {
245  char* p = static_cast<char*>(PyMem_RawMalloc(2));
246  if (p == 0) {
247  return 0;
248  }
249  p[0] = '\0';
250  return p;
251  }
252  return 0;
253 }
#define HocContextRestore
Definition: hoccontext.h:17
#define assert(ex)
Definition: hocassrt.h:26
int hoc_get_line()
Definition: hoc.cpp:1869
static realtype retval
void nrnpy_augment_path()
Definition: nrnpython.cpp:44
char * hoc_ctp
size_t p
char * neuronhome_forward()
Definition: code2.cpp:188
int(* p_nrnpy_pyrun)(const char *)
Definition: hoc.cpp:38
int nrnpy_pyrun(const char *)
Execute a Python script.
Definition: nrnpython.cpp:69
#define lock
char * buf
Definition: hocstr.h:9
sprintf(buf," if (secondorder) {\ " int _i;\" " for(_i=0;_i< %d;++_i) {\" " _p[_slist%d[_i]]+=dt *_p[_dlist%d[_i]];\" " }}\", numeqn, listnum, listnum)
#define gargstr
Definition: hocdec.h:14
int nrn_istty_
Definition: hoc.cpp:870
bool isDirExist(const std::string &path)
Definition: ocfile.cpp:557
static PyObject *(* nrnpy_reg_[])()
Definition: nrnpy_reg.h:4
int nrnpython_start(int)
Start the Python interpreter.
Definition: nrnpython.cpp:140
static int started
Definition: init.c:142
static Frame * fp
Definition: code.cpp:154
static void copy_argv_wcargv(int argc, char **argv)
Definition: nrnpython.cpp:107
Definition: hocstr.h:8
int const size_t const size_t n
Definition: nrngsl.h:12
_CONST char * s
Definition: system.cpp:74
char * nrnpy_pyhome
Definition: nrnpy.cpp:80
int
Definition: nrnmusic.cpp:71
void nrnpython_real()
Definition: nrnpython.cpp:217
static const char * fname(const char *name)
Definition: nrnbbs.cpp:108
FILE * hoc_fin
hoc_retpushx(1.0)
char * getenv(const char *s)
Definition: macprt.cpp:67
int nrn_global_argc
Definition: nrnpython.cpp:34
fprintf(stderr, "Don't know the location of params at %p\, pp)
static char * nrnpython_getline(FILE *, FILE *, const char *)
Definition: nrnpython.cpp:230
static void del_wcargv(int argc)
Definition: nrnpython.cpp:97
HocStr * hoc_cbufstr
Definition: hoc.cpp:165
static wchar_t * mywstrdup(char *s)
Definition: nrnpython.cpp:124
int nrnpy_nositeflag
Definition: ivocmain.cpp:193
char ** nrn_global_argv
Definition: nrnpython.cpp:35
void rl_stuff_char(int)
const char * hoc_promptstr
Definition: hoc.cpp:166
#define i
Definition: md1redef.h:12
#define arg
Definition: redef.h:28
static int argc
Definition: inithoc.cpp:53
static wchar_t ** wcargv
Definition: nrnpython.cpp:95
#define HocTopContextSet
Definition: hoccontext.h:10
FILE * fopen()
return NULL
Definition: cabcode.cpp:461
static char ** argv
Definition: inithoc.cpp:54