Salome HOME
Fix pb with persistence of "light" modules: SaveAs operation leads to loss of non...
[modules/gui.git] / src / PyConsole / PyConsole_Interp.cxx
1 // Copyright (C) 2007-2014  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
3 // Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
5 //
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 2.1 of the License, or (at your option) any later version.
10 //
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 // Lesser General Public License for more details.
15 //
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
19 //
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21 //
22
23 //  SALOME SALOMEGUI : implementation of desktop and GUI kernel
24 //  File   : PyConsole_Interp.cxx
25 //  Author : Nicolas REJNERI
26 //  Module : SALOME
27 //
28 #include "PyConsole_Interp.h"
29
30 /*!
31   \class PyConsole_Interp
32   \brief Python interpreter to be embedded to the SALOME study's GUI.
33
34   Python interpreter is created one per SALOME study.
35
36   Call initialize method defined in the base class PyInterp_Interp,
37   to intialize interpreter after instance creation.
38
39   The method initialize() calls virtuals methods
40   - initPython()  to initialize global Python interpreter
41   - initState()   to initialize embedded interpreter state
42   - initContext() to initialize interpreter internal context
43   - initRun()     to prepare interpreter for running commands
44
45   /EDF-CCAR/
46   When SALOME uses multi Python interpreter feature, 
47   every study has its own interpreter and thread state (_tstate = Py_NewInterpreter()).
48   This is fine because every study has its own modules (sys.modules) stdout and stderr.
49
50   <b>But</b> some Python modules must be imported only once. In multi interpreter 
51   context Python modules (*.py) are imported several times.
52   For example, the PyQt module must be imported only once because 
53   it registers classes in a C module.
54
55   It's quite the same with omniorb modules (internals and generated with omniidl).
56
57   This problem is handled with "shared modules" defined in salome_shared_modules.py.
58   These "shared modules" are imported only once and only copied in all 
59   the other interpreters.
60
61   <b>But</b> it's not the only problem. Every interpreter has its own 
62   __builtin__ module. That's fine but if we have copied some modules 
63   and imported others problems may arise with operations that are not allowed
64   in restricted execution environment. So we must impose that all interpreters
65   have identical __builtin__ module.
66 */
67
68 /*!
69   \brief Constructor.
70
71   Creates new python interpreter.
72 */
73 PyConsole_Interp::PyConsole_Interp(): PyInterp_Interp()
74 {
75 }
76
77 /*!
78   \brief Destructor.
79
80   Does nothing for the moment.
81 */
82 PyConsole_Interp::~PyConsole_Interp()
83 {
84 }
85  
86 /*!
87   \brief Initialize internal Python interpreter state.
88
89   When calling initState the GIL is not held
90   It must not be held on exit
91
92   \return \c true on success
93 */
94 bool PyConsole_Interp::initState()
95 {
96   PyEval_AcquireLock();
97   _tstate = Py_NewInterpreter(); // create an interpreter and save current state
98   PySys_SetArgv(PyInterp_Interp::_argc,PyInterp_Interp::_argv); // initialize sys.argv
99   
100   if(!builtinmodule) // PAL18041: deepcopy function don't work in Salome
101   {
102     //builtinmodule is static member of PyInterp class
103     //If it is not NULL (initialized to the builtin module of the main interpreter
104     //all the sub interpreters will have the same builtin
105     //_interp is a static member and is the main interpreter
106     //The first time we initialized it to the builtin of main interpreter
107     builtinmodule=PyDict_GetItemString(_interp->modules, "__builtin__");
108   }
109
110   //If builtinmodule has been initialized all the sub interpreters
111   // will have the same __builtin__ module
112   if(builtinmodule){ 
113     PyObject *m = PyImport_GetModuleDict();
114     PyDict_SetItemString(m, "__builtin__", builtinmodule);
115     _tstate->interp->builtins = PyModule_GetDict(builtinmodule);
116     Py_INCREF(_tstate->interp->builtins);
117   }
118   PyEval_ReleaseThread(_tstate);
119   return true;
120 }
121
122 /*!
123   \brief Initialize python interpeter context.
124
125   The GIL is assumed to be held.
126   It is the caller responsability to acquire the GIL.
127   It must still be held on initContext() exit.
128
129   \return \c true on success
130 */
131 bool PyConsole_Interp::initContext()
132 {
133   PyObject *m = PyImport_AddModule("__main__");  // interpreter main module (module context)
134   if(!m){
135     PyErr_Print();
136     return false;
137   }  
138   _g = PyModule_GetDict(m);          // get interpreter dictionnary context
139
140   if(builtinmodule){
141     PyDict_SetItemString(_g, "__builtins__", builtinmodule); // assign singleton __builtin__ module
142   }
143   return true;
144 }