KiCad PCB EDA Suite
python_scripting.cpp
Go to the documentation of this file.
1 /*
2  * This program source code file is part of KiCad, a free EDA CAD application.
3  *
4  * Copyright (C) 2012 NBEE Embedded Systems, Miguel Angel Ajo <miguelangel@nbee.es>
5  * Copyright (C) 1992-2019 KiCad Developers, see AUTHORS.txt for contributors.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, you may find one here:
19  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
20  * or you may search the http://www.gnu.org website for the version 2 license,
21  * or you may write to the Free Software Foundation, Inc.,
22  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
23  */
24 
30 #include <cstdlib>
31 #include <cstring>
32 #include <python_scripting.h>
33 #include <sstream>
34 
35 #include <eda_base_frame.h>
36 #include <gal/color4d.h>
37 #include <trace_helpers.h>
38 #include <kicad_string.h>
39 #include <macros.h>
40 
41 #include <paths.h>
42 #include <pgm_base.h>
44 
45 #include <kiplatform/environment.h>
46 
47 #include <wx/app.h>
48 
49 #include <config.h>
50 
51 /* init functions defined by swig */
52 
53 #if PY_MAJOR_VERSION >= 3
54 extern "C" PyObject* PyInit__pcbnew( void );
55 #else
56 extern "C" void init_kicad( void );
57 
58 extern "C" void init_pcbnew( void );
59 #endif
60 
61 #define EXTRA_PYTHON_MODULES 10 // this is the number of python
62  // modules that we want to add into the list
63 
64 
65 /* python inittab that links module names to module init functions
66  * we will rebuild it to include the original python modules plus
67  * our own ones
68  */
69 
70 struct _inittab* SwigImportInittab;
71 static int SwigNumModules = 0;
72 
74 static bool wxPythonLoaded = false;
75 
76 
78 {
79  return wxPythonLoaded;
80 }
81 
82 
87 #if PY_MAJOR_VERSION >= 3
88 static void swigAddModule( const char* name, PyObject* (* initfunc)() )
89 #else
90 static void swigAddModule( const char* name, void (* initfunc)() )
91 #endif
92 {
93  SwigImportInittab[SwigNumModules].name = (char*) name;
94  SwigImportInittab[SwigNumModules].initfunc = initfunc;
96  SwigImportInittab[SwigNumModules].name = (char*) 0;
97  SwigImportInittab[SwigNumModules].initfunc = 0;
98 }
99 
100 
104 static void swigAddBuiltin()
105 {
106  int i = 0;
107 
108  /* discover the length of the pyimport inittab */
109  while( PyImport_Inittab[i].name )
110  i++;
111 
112  /* allocate memory for the python module table */
113  SwigImportInittab = (struct _inittab*) malloc(
114  sizeof( struct _inittab ) * ( i + EXTRA_PYTHON_MODULES ) );
115 
116  /* copy all pre-existing python modules into our newly created table */
117  i = 0;
118 
119  while( PyImport_Inittab[i].name )
120  {
121  swigAddModule( PyImport_Inittab[i].name, PyImport_Inittab[i].initfunc );
122  i++;
123  }
124 }
125 
126 
130 static void swigAddModules()
131 {
132 #if PY_MAJOR_VERSION >= 3
133  swigAddModule( "_pcbnew", PyInit__pcbnew );
134 #else
135  swigAddModule( "_pcbnew", init_pcbnew );
136 #endif
137 
138  // finally it seems better to include all in just one module
139  // but in case we needed to include any other modules,
140  // it must be done like this:
141  // swigAddModule( "_kicad", init_kicad );
142 }
143 
144 
149 {
150  PyImport_Inittab = SwigImportInittab;
151 }
152 
153 
154 PyThreadState* g_PythonMainTState;
155 
156 
162 bool pcbnewInitPythonScripting( const char* aStockScriptingPath, const char* aUserScriptingPath )
163 {
164  int retv;
165  char cmd[1024];
166 
167  swigAddBuiltin(); // add builtin functions
168  swigAddModules(); // add our own modules
169  swigSwitchPythonBuiltin(); // switch the python builtin modules to our new list
170 
171 #ifdef _MSC_VER
172  // Under vcpkg/msvc, we need to explicitly set the python home
173  // or else it'll start consuming system python registry keys and the like instead
174  // We are going to follow the "unix" layout for the msvc/vcpkg distributions so exes in /root/bin
175  // And the python lib in /root/lib/python3(/Lib,/DLLs)
176  wxFileName pyHome;
177 
178  pyHome.Assign( Pgm().GetExecutablePath() );
179 
180  pyHome.Normalize();
181 
182  // MUST be called before Py_Initialize so it will to create valid default lib paths
183  if( !wxGetEnv( wxT( "KICAD_RUN_FROM_BUILD_DIR" ), nullptr ) )
184  {
185  Py_SetPythonHome( pyHome.GetFullPath().c_str() );
186  }
187 #endif
188 
189  Py_Initialize();
190  PySys_SetArgv( Pgm().App().argc, Pgm().App().argv );
191 
192 #ifdef KICAD_SCRIPTING_WXPYTHON
193 
194 #if PY_VERSION_HEX < 0x03070000 // PyEval_InitThreads() is called by Py_Initialize() starting with version 3.7
195  PyEval_InitThreads();
196 #endif // if PY_VERSION_HEX < 0x03070000
197 
198 #ifndef KICAD_SCRIPTING_WXPYTHON_PHOENIX
199 #ifndef __WINDOWS__ // import wxversion.py currently not working under winbuilder, and not useful.
200  // Make sure that that the correct version of wxPython is loaded. In systems where there
201  // are different versions of wxPython installed this can lead to select wrong wxPython
202  // version being selected.
203  snprintf( cmd, sizeof( cmd ), "import wxversion; wxversion.select( '%s' )", WXPYTHON_VERSION );
204 
205  retv = PyRun_SimpleString( cmd );
206 
207  if( retv != 0 )
208  {
209  wxLogError( "Python error %d occurred running command:\n\n`%s`", retv, cmd );
210  return false;
211  }
212 #endif // ifndef __WINDOWS__
213 
214  // Load the wxPython core API. Imports the wx._core_ module and sets a
215  // local pointer to a function table located there. The pointer is used
216  // internally by the rest of the API functions.
217  if( !wxPyCoreAPI_IMPORT() )
218  {
219  wxLogError( "***** Error importing the wxPython API! *****" );
220  PyErr_Print();
221  Py_Finalize();
222  return false;
223  }
224 #endif // ifndef KICAD_SCRIPTING_WXPYTHON_PHOENIX
225 
226 #if defined( DEBUG )
227  RedirectStdio();
228 #endif
229 
230  wxPythonLoaded = true;
231 
232  // Save the current Python thread state and release the
233  // Global Interpreter Lock.
234  g_PythonMainTState = PyEval_SaveThread();
235 
236 #endif // ifdef KICAD_SCRIPTING_WXPYTHON
237 
238  // Load pcbnew inside Python and load all the user plugins and package-based plugins
239  {
240  PyLOCK lock;
241 
242  // Load os so that we can modify the environment variables through python
243  snprintf( cmd, sizeof( cmd ), "import sys, os, traceback\n"
244  "sys.path.append(\".\")\n"
245  "import pcbnew\n"
246  "pcbnew.LoadPlugins(\"%s\", \"%s\")",
247  aStockScriptingPath, aUserScriptingPath );
248  retv = PyRun_SimpleString( cmd );
249 
250  if( retv != 0 )
251  wxLogError( "Python error %d occurred running command:\n\n`%s`", retv, cmd );
252  }
253 
254  return true;
255 }
256 
257 
264 static void pcbnewRunPythonMethodWithReturnedString( const char* aMethodName, wxString& aNames )
265 {
266  aNames.Clear();
267 
268  PyLOCK lock;
269  PyErr_Clear();
270 
271  PyObject* builtins = PyImport_ImportModule( "pcbnew" );
272  wxASSERT( builtins );
273 
274  if( !builtins ) // Something is wrong in pcbnew.py module (incorrect version?)
275  return;
276 
277  PyObject* globals = PyDict_New();
278  PyDict_SetItemString( globals, "pcbnew", builtins );
279  Py_DECREF( builtins );
280 
281  // Build the python code
282  char cmd[1024];
283  snprintf( cmd, sizeof(cmd), "result = %s()", aMethodName );
284 
285  // Execute the python code and get the returned data
286  PyObject* localDict = PyDict_New();
287  PyObject* pobj = PyRun_String( cmd, Py_file_input, globals, localDict);
288  Py_DECREF( globals );
289 
290  if( pobj )
291  {
292  PyObject* str = PyDict_GetItemString(localDict, "result" );
293 #if PY_MAJOR_VERSION >= 3
294  const char* str_res = NULL;
295 
296  if(str)
297  {
298  PyObject* temp_bytes = PyUnicode_AsEncodedString( str, "UTF-8", "strict" );
299 
300  if( temp_bytes != NULL )
301  {
302  str_res = PyBytes_AS_STRING( temp_bytes );
303  str_res = strdup( str_res );
304  Py_DECREF( temp_bytes );
305  }
306  else
307  {
308  wxLogMessage( "cannot encode unicode python string" );
309  }
310  }
311 #else
312  const char* str_res = str ? PyString_AsString( str ) : 0;
313 #endif
314  aNames = FROM_UTF8( str_res );
315  Py_DECREF( pobj );
316  }
317 
318  Py_DECREF( localDict );
319 
320  if( PyErr_Occurred() )
321  wxLogMessage( PyErrStringWithTraceback() );
322 }
323 
324 
325 void pcbnewGetUnloadableScriptNames( wxString& aNames )
326 {
327  pcbnewRunPythonMethodWithReturnedString( "pcbnew.GetUnLoadableWizards", aNames );
328 }
329 
330 
331 void pcbnewGetScriptsSearchPaths( wxString& aNames )
332 {
333  pcbnewRunPythonMethodWithReturnedString( "pcbnew.GetWizardsSearchPaths", aNames );
334 }
335 
336 
337 void pcbnewGetWizardsBackTrace( wxString& aTrace )
338 {
339  pcbnewRunPythonMethodWithReturnedString( "pcbnew.GetWizardsBackTrace", aTrace );
340 
341  // Filter message before displaying them
342  // a trace starts by "Traceback" and is followed by 2 useless lines
343  // for our purpose
344  wxArrayString traces;
345  wxStringSplit( aTrace, traces, '\n' );
346 
347  // Build the filtered message (remove useless lines)
348  aTrace.Clear();
349 
350  for( unsigned ii = 0; ii < traces.Count(); ++ii )
351  {
352  if( traces[ii].Contains( "Traceback" ) )
353  {
354  ii += 2; // Skip this line and next lines which are related to pcbnew.py module
355 
356  if( !aTrace.IsEmpty() ) // Add separator for the next trace block
357  aTrace << "\n**********************************\n";
358  }
359  else
360  aTrace += traces[ii] + "\n";
361  }
362 }
363 
364 
366 {
367 #ifdef KICAD_SCRIPTING_WXPYTHON
368  PyEval_RestoreThread( g_PythonMainTState );
369 #endif
370  Py_Finalize();
371 }
372 
373 
374 wxString PyEscapeString( const wxString& aSource )
375 {
376  wxString converted;
377 
378  for( wxUniChar c: aSource )
379  {
380  if( c == '\\' )
381  converted += "\\\\";
382  else if( c == '\'' )
383  converted += "\\\'";
384  else if( c == '\"' )
385  converted += "\\\"";
386  else
387  converted += c;
388  }
389 
390  return converted;
391 }
392 
393 
394 void pcbnewUpdatePythonEnvVar( const wxString& aVar, const wxString& aValue )
395 {
396  char cmd[1024];
397 
398  // Ensure the interpreter is initalized before we try to interact with it
399  if( !Py_IsInitialized() )
400  return;
401 
402  wxLogTrace( traceEnvVars, "pcbnewUpdatePythonEnvVar: Updating Python variable %s = %s",
403  aVar, aValue );
404 
405  wxString escapedVar = PyEscapeString( aVar );
406  wxString escapedVal = PyEscapeString( aValue );
407 
408  snprintf( cmd, sizeof( cmd ),
409  "# coding=utf-8\n" // The values could potentially be UTF8
410  "os.environ[\"%s\"]=\"%s\"\n",
411  TO_UTF8( escapedVar ),
412  TO_UTF8( escapedVal ) );
413 
414  PyLOCK lock;
415 
416  int retv = PyRun_SimpleString( cmd );
417 
418  if( retv != 0 )
419  wxLogError( "Python error %d occurred running command:\n\n`%s`", retv, cmd );
420 }
421 
422 
423 #if defined( KICAD_SCRIPTING_WXPYTHON )
424 void RedirectStdio()
425 {
426  // This is a helpful little tidbit to help debugging and such. It
427  // redirects Python's stdout and stderr to a window that will popup
428  // only on demand when something is printed, like a traceback.
429  const char* python_redirect =
430  "import sys\n"
431  "import wx\n"
432  "output = wx.PyOnDemandOutputWindow()\n"
433  "sys.stderr = output\n";
434 
435  PyLOCK lock;
436 
437  int retv = PyRun_SimpleString( python_redirect );
438 
439  if( retv != 0 )
440  wxLogError( "Python error %d occurred running command:\n\n`%s`", retv, python_redirect );
441 }
442 
443 
444 wxWindow* CreatePythonShellWindow( wxWindow* parent, const wxString& aFramenameId )
445 {
446  // parent is actually *PCB_EDIT_FRAME
447  const int parentId = parent->GetId();
448  {
449  wxWindow* parent2 = wxWindow::FindWindowById( parentId );
450  wxASSERT( parent2 == parent );
451  }
452 
453  // passing window ids instead of pointers is because wxPython is not
454  // exposing the needed c++ apis to make that possible.
455  std::stringstream pcbnew_pyshell_one_step;
456  pcbnew_pyshell_one_step << "import kicad_pyshell\n";
457  pcbnew_pyshell_one_step << "import wx\n";
458  pcbnew_pyshell_one_step << "\n";
459  pcbnew_pyshell_one_step << "parent = wx.FindWindowById( " << parentId << " )\n";
460  pcbnew_pyshell_one_step << "newshell = kicad_pyshell.makePcbnewShellWindow( parent )\n";
461  pcbnew_pyshell_one_step << "newshell.SetName( \"" << aFramenameId << "\" )\n";
462  // return value goes into a "global". It's not actually global, but rather
463  // the dict that is passed to PyRun_String
464  pcbnew_pyshell_one_step << "retval = newshell.GetId()\n";
465 
466  // As always, first grab the GIL
467  PyLOCK lock;
468 
469  // Now make a dictionary to serve as the global namespace when the code is
470  // executed. Put a reference to the builtins module in it.
471 
472  PyObject* globals = PyDict_New();
473 #if PY_MAJOR_VERSION >= 3
474  PyObject* builtins = PyImport_ImportModule( "builtins" );
475 #else
476  PyObject* builtins = PyImport_ImportModule( "__builtin__" );
477 #endif
478 
479  wxASSERT( builtins );
480 
481  PyDict_SetItemString( globals, "__builtins__", builtins );
482  Py_DECREF( builtins );
483 
484 #ifdef KICAD_SCRIPTING_WXPYTHON_PHOENIX
485  auto app_ptr = wxTheApp;
486 #endif
487  // Execute the code to make the makeWindow function we defined above
488  PyObject* result = PyRun_String( pcbnew_pyshell_one_step.str().c_str(), Py_file_input,
489  globals, globals );
490 
491 #ifdef KICAD_SCRIPTING_WXPYTHON_PHOENIX
492  // This absolutely ugly hack is to work around the pyshell re-writing the global
493  // wxApp variable. Once we can initialize Phoenix to access the appropriate instance
494  // of wx, we can remove this line
495  wxApp::SetInstance( app_ptr );
496 #endif
497  // Was there an exception?
498  if( !result )
499  {
500  PyErr_Print();
501  return NULL;
502  }
503 
504  Py_DECREF( result );
505 
506  result = PyDict_GetItemString( globals, "retval" );
507 
508 #if PY_MAJOR_VERSION >= 3
509  if( !PyLong_Check( result ) )
510 #else
511  if( !PyInt_Check( result ) )
512 #endif
513  {
514  wxLogError( "creation of scripting window didn't return a number" );
515  return NULL;
516  }
517 
518 #if PY_MAJOR_VERSION >= 3
519  const long windowId = PyLong_AsLong( result );
520 #else
521  const long windowId = PyInt_AsLong( result );
522 #endif
523 
524  // It's important not to decref globals before extracting the window id.
525  // If you do it early, globals, and the retval int it contains, may/will be garbage collected.
526  // We do not need to decref result, because GetItemString returns a borrowed reference.
527  Py_DECREF( globals );
528 
529  wxWindow* window = wxWindow::FindWindowById( windowId );
530 
531  if( !window )
532  {
533  wxLogError( "unable to find pyshell window with id %d", windowId );
534  return NULL;
535  }
536 
537  return window;
538 }
539 #endif
540 
541 
542 wxString PyStringToWx( PyObject* aString )
543 {
544  wxString ret;
545 
546  if( !aString )
547  return ret;
548 
549 #if PY_MAJOR_VERSION >= 3
550  const char* str_res = NULL;
551  PyObject* temp_bytes = PyUnicode_AsEncodedString( aString, "UTF-8", "strict" );
552 
553  if( temp_bytes != NULL )
554  {
555  str_res = PyBytes_AS_STRING( temp_bytes );
556  ret = FROM_UTF8( str_res );
557  Py_DECREF( temp_bytes );
558  }
559  else
560  {
561  wxLogMessage( "cannot encode unicode python string" );
562  }
563 #else
564  const char* str_res = PyString_AsString( aString );
565  ret = FROM_UTF8( str_res );
566 #endif
567 
568  return ret;
569 }
570 
571 
572 wxArrayString PyArrayStringToWx( PyObject* aArrayString )
573 {
574  wxArrayString ret;
575 
576  if( !aArrayString )
577  return ret;
578 
579  int list_size = PyList_Size( aArrayString );
580 
581  for( int n = 0; n < list_size; n++ )
582  {
583  PyObject* element = PyList_GetItem( aArrayString, n );
584 
585  if( element )
586  {
587 #if PY_MAJOR_VERSION >= 3
588  const char* str_res = NULL;
589  PyObject* temp_bytes = PyUnicode_AsEncodedString( element, "UTF-8", "strict" );
590 
591  if( temp_bytes != NULL )
592  {
593  str_res = PyBytes_AS_STRING( temp_bytes );
594  ret.Add( FROM_UTF8( str_res ), 1 );
595  Py_DECREF( temp_bytes );
596  }
597  else
598  {
599  wxLogMessage( "cannot encode unicode python string" );
600  }
601 #else
602  ret.Add( FROM_UTF8( PyString_AsString( element ) ), 1 );
603 #endif
604  }
605  }
606 
607  return ret;
608 }
609 
610 
612 {
613  wxString err;
614 
615  if( !PyErr_Occurred() )
616  return err;
617 
618  PyObject* type;
619  PyObject* value;
620  PyObject* traceback;
621 
622  PyErr_Fetch( &type, &value, &traceback );
623 
624  PyErr_NormalizeException( &type, &value, &traceback );
625 
626  if( traceback == NULL )
627  {
628  traceback = Py_None;
629  Py_INCREF( traceback );
630  }
631 
632 #if PY_MAJOR_VERSION >= 3
633  PyException_SetTraceback( value, traceback );
634 
635  PyObject* tracebackModuleString = PyUnicode_FromString( "traceback" );
636 #else
637  PyObject* tracebackModuleString = PyString_FromString( "traceback" );
638 #endif
639  PyObject* tracebackModule = PyImport_Import( tracebackModuleString );
640  Py_DECREF( tracebackModuleString );
641 
642  PyObject* formatException = PyObject_GetAttrString( tracebackModule,
643  "format_exception" );
644  Py_DECREF( tracebackModule );
645 
646  PyObject* args = Py_BuildValue( "(O,O,O)", type, value, traceback );
647  PyObject* result = PyObject_CallObject( formatException, args );
648  Py_XDECREF( formatException );
649  Py_XDECREF( args );
650  Py_XDECREF( type );
651  Py_XDECREF( value );
652  Py_XDECREF( traceback );
653 
654  wxArrayString res = PyArrayStringToWx( result );
655 
656  for( unsigned i = 0; i<res.Count(); i++ )
657  {
658  err += res[i] + wxT( "\n" );
659  }
660 
661  PyErr_Clear();
662 
663  return err;
664 }
665 
666 
670 wxString PyScriptingPath( bool aUserPath )
671 {
672  wxString path;
673 
674  //@todo This should this be a user configurable variable eg KISCRIPT?
675  if( aUserPath )
676  {
678  }
679  else
680  {
682  }
683 
684  wxFileName scriptPath( path );
685  scriptPath.MakeAbsolute();
686 
687  // Convert '\' to '/' in path, because later python script read \n or \r
688  // as escaped sequence, and create issues, when calling it by PyRun_SimpleString() method.
689  // It can happen on Windows.
690  path = scriptPath.GetFullPath();
691  path.Replace( '\\', '/' );
692 
693  return path;
694 }
695 
696 
697 wxString PyPluginsPath( bool aUserPath )
698 {
699  // Note we are using unix path separator, because window separator sometimes
700  // creates issues when passing a command string to a python method by PyRun_SimpleString
701  return PyScriptingPath( aUserPath ) + '/' + "plugins";
702 }
wxString PyStringToWx(PyObject *aString)
static void pcbnewRunPythonMethodWithReturnedString(const char *aMethodName, wxString &aNames)
Run a python method from the pcbnew module.
bool pcbnewInitPythonScripting(const char *aStockScriptingPath, const char *aUserScriptingPath)
Initialize the python environment and publish the Pcbnew interface inside it.
static wxString FROM_UTF8(const char *cstring)
Convert a UTF8 encoded C string to a wxString for all wxWidgets build modes.
Definition: macros.h:110
static wxString GetUserScriptingPath()
Gets the user path for python scripts.
Definition: paths.cpp:75
void pcbnewUpdatePythonEnvVar(const wxString &aVar, const wxString &aValue)
Set an environment variable in the current Python interpreter.
static wxString GetStockScriptingPath()
Gets the stock (install) scripting path.
Definition: paths.cpp:181
static void swigAddBuiltin()
Add the builtin python modules.
void pcbnewFinishPythonScripting()
KIWAY Kiway & Pgm(), KFCTL_STANDALONE
The global Program "get" accessor.
Definition: single_top.cpp:106
wxString PyScriptingPath(bool aUserPath)
Find the Python scripting path.
#define EXTRA_PYTHON_MODULES
This file contains miscellaneous commonly used macros and functions.
void pcbnewGetWizardsBackTrace(wxString &aTrace)
Return the backtrace of errors (if any) when wizard python scripts are loaded.
#define TO_UTF8(wxstring)
Convert a wxString to a UTF8 encoded C string for all wxWidgets build modes.
Definition: macros.h:96
static void swigAddModules()
Add the internal modules to the python scripting so they will be available to the scripts.
#define NULL
wxString PyPluginsPath(bool aUserPath)
Base window classes and related definitions.
wxLogTrace helper definitions.
static void swigAddModule(const char *name, void(*initfunc)())
Add a name + initfuction to our SwigImportInittab.
wxArrayString PyArrayStringToWx(PyObject *aArrayString)
static void swigSwitchPythonBuiltin()
Switch the python module table to the Pcbnew built one.
const wxChar *const traceEnvVars
Flag to enable debug output of environment variable operations.
static bool wxPythonLoaded
True if the wxPython scripting layer was successfully loaded.
void init_pcbnew(void)
void pcbnewGetUnloadableScriptNames(wxString &aNames)
Collect the list of python scripts which could not be loaded.
void wxStringSplit(const wxString &aText, wxArrayString &aStrings, wxChar aSplitter)
Split aString to a string list separated at aSplitter.
Definition: string.cpp:827
see class PGM_BASE
const char * name
Definition: DXF_plotter.cpp:59
void init_kicad(void)
wxString PyErrStringWithTraceback()
struct _inittab * SwigImportInittab
bool IsWxPythonLoaded()
void pcbnewGetScriptsSearchPaths(wxString &aNames)
Collect the list of paths where python scripts are searched.
static int SwigNumModules
wxString PyEscapeString(const wxString &aSource)
PyThreadState * g_PythonMainTState