Salome HOME
Copyright update 2022
[modules/kernel.git] / src / KERNEL_PY / __init__.py
1 #  -*- coding: iso-8859-1 -*-
2 # Copyright (C) 2007-2022  CEA/DEN, EDF R&D, OPEN CASCADE
3 #
4 # Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
5 # CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
6 #
7 # This library is free software; you can redistribute it and/or
8 # modify it under the terms of the GNU Lesser General Public
9 # License as published by the Free Software Foundation; either
10 # version 2.1 of the License, or (at your option) any later version.
11 #
12 # This library 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 GNU
15 # Lesser General Public License for more details.
16 #
17 # You should have received a copy of the GNU Lesser General Public
18 # License along with this library; if not, write to the Free Software
19 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
20 #
21 # See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
22 #
23
24 #  File   : salome.py renamed as __init__.py for python packaging (gboulant)
25 #  Author : Paul RASCLE, EDF
26 #  Module : SALOME
27 #
28 """ 
29 Module salome gives access to Salome resources.
30
31 variables:
32
33   - salome.orb             : CORBA
34   - salome.naming_service  : instance of naming Service class
35       - methods:
36           - Resolve(name)  : find a CORBA object (ior) by its pathname
37           - Register(name) : register a CORBA object under a pathname
38
39   - salome.lcc             : instance of lifeCycleCORBA class
40       - methods:
41           - FindOrLoadComponent(server,name) :
42                            obtain an Engine (CORBA object)
43                            or launch the Engine if not found,
44                            with a Server name and an Engine name
45
46   - salome.sg              : salome object to communicate with the graphical user interface (if any)
47       - methods:
48          - updateObjBrowser():
49
50          - SelectedCount():      returns number of selected objects
51          - getSelected(i):       returns entry of selected object number i
52          - getAllSelected():     returns list of entry of selected objects
53          - AddIObject(Entry):    select an existing Interactive object
54          - RemoveIObject(Entry): remove object from selection
55          - ClearIObjects():      clear selection
56
57          - Display(*Entry):
58          - DisplayOnly(Entry):
59          - Erase(Entry):
60          - DisplayAll():
61          - EraseAll():
62
63          - IDToObject(Entry):    returns CORBA reference from entry
64
65   - salome.myStudyName     : active Study Name
66   - salome.myStudy         : the active Study itself (CORBA ior)
67       - methods : defined in SALOMEDS.idl
68
69 """
70 ## @package salome
71 # Module salome gives access to Salome resources.
72 #
73 #  \param salome.orb             : CORBA orb object
74 #  \param salome.naming_service  : instance of naming Service class (SALOME_NamingServicePy::SALOME_NamingServicePy_i)
75 #  \param salome.lcc             : instance of lifeCycleCORBA class (SALOME_LifeCycleCORBA)
76 #  \param salome.sg              : Salome object to communicate with the graphical user interface, if running (see interface in salome_iapp::SalomeOutsideGUI)
77 #  \param salome.myStudyName     : active Study Name
78 #  \param salome.myStudy         : the active Study (interface SALOMEDS::Study)
79
80 #
81 # ==========================================================================
82 #
83 # The function extend_path is used here to aggregate in a single
84 # virtual python package all the python sub-packages embedded in each
85 # SALOME modules (python "namespace" pattern).
86 #
87 ROOT_PYTHONPACKAGE_NAME="salome"
88 #
89 # This root package name is expected to be found as a directory in
90 # some paths of the sys.path variable, especially the paths
91 # <MODULE_ROOT_DIR>/lib/pythonX.Y/site-packages/salome where are
92 # installed the python files. These paths are theorically appended by
93 # the SALOME main runner and should be in the sys.path at this point
94 # of the application. The extend_path is looking then for directories
95 # of the type:
96 #
97 # <MODULE_ROOT_DIR>/lib/pythonX.Y/site-packages/salome/<ROOT_PYTHONPACKAGE_NAME>
98 #
99 # And append them to the sys.path. These directories are supposed to
100 # be the pieces to be aggregated as a single virtual python package.
101 #
102 import os, sys
103 from salome_utils import verbose
104
105 MATCH_ENDING_PATTERN="site-packages" + os.path.sep + "salome"
106
107 def extend_path(pname):
108     for dir in sys.path:
109         if not isinstance(dir, str) or not os.path.isdir(dir) or not dir.endswith(MATCH_ENDING_PATTERN):
110             continue
111         subdir = os.path.join(dir, pname)
112         # XXX This may still add duplicate entries to path on
113         # case-insensitive filesystems
114         if os.path.isdir(subdir) and subdir not in __path__:
115             if verbose(): print("INFO - The directory %s is appended to sys.path" % subdir)
116             __path__.append(subdir)
117
118 extend_path(ROOT_PYTHONPACKAGE_NAME)
119 # ==========================================================================
120 #
121
122 from salome_kernel import *
123 from salome_study import *
124 from salome_iapp import *
125 import salome_study
126
127 #
128 # The next block is workaround for the problem of shared symbols loading for the extension modules (e.g. SWIG-generated)
129 # that causes RTTI unavailable in some cases. To solve this problem, sys.setdlopenflags() function is used.
130 # Depending on the Python version and platform, the dlopen flags can be defined in the dl, DLFUN or ctypes module.
131
132 import sys
133 flags = None
134 if not flags:
135     try:
136         # dl module can be unavailable
137         import dl
138         flags = dl.RTLD_NOW | dl.RTLD_GLOBAL
139     except Exception:
140         pass
141     pass
142 if not flags:
143     try:
144         # DLFCN module can be unavailable
145         import DLFCN
146         flags = DLFCN.RTLD_NOW | DLFCN.RTLD_GLOBAL
147     except Exception:
148         pass
149     pass
150 if not flags:
151     try:
152         # ctypes module can be unavailable
153         import ctypes
154         flags = ctypes.RTLD_GLOBAL
155     except Exception:
156         pass
157     pass
158
159 # Disable -> bug with scipy, seems very dangerous to do that
160 #if flags:
161 #    sys.setdlopenflags(flags)
162 #    pass
163
164 orb, lcc, naming_service, cm, sg, esm, dsm, modulcat = None,None,None,None,None,None,None,None
165 myStudy, myStudyName = None,None
166
167 salome_initial=True
168
169 def standalone():
170     pass
171
172 def withServers():
173     import KernelBasis
174     KernelBasis.setSSLMode(False)
175
176 def salome_init(path=None, embedded=False, iorfakensfile=None, forced=False):
177     """
178     Initialize SALOME client process (that can also be server).
179     3 modes of initialization exists:
180     - SSL mode (see salome_init_without_session)
181     - SSL mode attached in the context of python execution inside SALOME_Container_No_NS_Serv server (typically YACS)
182     - Classical mode (see salome_init_with_session)
183     :param iorfakensfile: filename inside which IOR of fake NS will be written
184     :param forced: tell if the multi-initialization protection mecanism of salome_init must be skiped of not
185                    (typically in the context where a path to a study is given whereas a previous initialisation without it was done)
186     """
187     if not forced:
188         if lcc is not None:# multi-initialization protection mecanism is based on lcc global var
189             return
190     PATH_TO_STUDY_FILE_TO_INITIATE = "PATH_TO_STUDY_FILE_TO_INITIATE"
191     import KernelBasis
192     if KernelBasis.getSSLMode():
193         if KernelBasis.getIOROfEmbeddedNS() == "":
194             import os
195             # make runSalome.py -t study.hdf toto.py
196             if path is None and PATH_TO_STUDY_FILE_TO_INITIATE in os.environ:
197                 path = os.environ[PATH_TO_STUDY_FILE_TO_INITIATE]
198             salome_init_without_session(path, embedded, iorfakensfile)
199         else:
200             salome_init_without_session_attached(path, embedded)
201     else:
202         salome_init_with_session(path, embedded)
203
204 def salome_init_without_session_common(path=None, embedded=False):
205     from ORBConfigFile import writeORBConfigFileSSL
206     OMNIORB_USER_PATH = "OMNIORB_USER_PATH"
207     def RemoveOmniorbConfigFile():
208         import os
209         if "OMNIORB_CONFIG" in os.environ:
210             fileToRemove = os.environ["OMNIORB_CONFIG"]
211             if os.path.exists(fileToRemove):
212                 os.unlink(fileToRemove)
213
214     if OMNIORB_USER_PATH in os.environ:
215         import atexit
216         writeORBConfigFileSSL(os.environ[OMNIORB_USER_PATH],kwargs={"with_pid":True})
217         atexit.register(RemoveOmniorbConfigFile)
218
219     global lcc,naming_service,myStudy,orb,modulcat,sg
220     import KernelBasis
221     KernelBasis.setSSLMode(True)
222     import KernelDS
223     myStudy = KernelDS.myStudy()
224     import CORBA
225     orb=CORBA.ORB_init([''])
226     import KernelModuleCatalog
227     import SALOME_ModuleCatalog
228     from salome_kernel import list_of_catalogs_regarding_environement
229     modulcat = KernelModuleCatalog.myModuleCatalog( list_of_catalogs_regarding_environement() )
230     #
231     poa = orb.resolve_initial_references("RootPOA")
232     poaManager = poa._get_the_POAManager()
233     poaManager.activate()
234     #
235     sg = salome_iapp_init(embedded)
236     salome_study_init_without_session(path)
237     #
238     from NamingService import NamingService
239     naming_service = NamingService()
240
241 def salome_init_without_session(path=None, embedded=False, iorfakensfile=None):
242     """
243     Force creation of all servants needed by SALOME session in the current process.
244     A Fake NamingService is created storing reference of all servants in the current process.
245     """
246     salome_init_without_session_common(path,embedded)
247     global lcc,cm,dsm,esm
248     import KernelLauncher
249     cm = KernelLauncher.myContainerManager()
250     from LifeCycleCORBA import LifeCycleCORBASSL
251     lcc = LifeCycleCORBASSL()
252     # create a FactoryServer Container servant
253     import KernelContainer
254     KernelContainer.myContainer()
255     # activate poaManager to accept co-localized CORBA calls.
256     from KernelSDS import GetDSMInstance
257     import sys
258     if hasattr(sys, 'argv'):
259       argv = sys.argv
260     else:
261       argv = ['']
262     dsm = GetDSMInstance(argv)
263     # esm inherits from SALOME_CPythonHelper singleton already initialized by GetDSMInstance
264     # esm inherits also from SALOME_ResourcesManager creation/initialization (concerning SingleThreadPOA POA) when KernelLauncher.GetContainerManager() has been called
265     esm = KernelLauncher.GetExternalServer()
266     #
267     import KernelLogger
268     naming_service.Register(KernelLogger.myLogger(),"/Logger")
269     #
270     from NamingService import NamingService
271     if iorfakensfile is not None:
272         with open(iorfakensfile,"w") as iorfakensf:
273             iorfakensf.write(NamingService.IOROfNS())
274     
275 def salome_init_without_session_attached(path=None, embedded=False):
276     """
277     Configuration SSL inside a python interpretor launched in the SALOME_Container_No_NS_Serv.
278     In this configuration, a local FakeNamingService is created and remote objects are stored in it.
279     lcc is pointing to the FakeNamingService above.
280     """
281     salome_init_without_session_common(path,embedded)
282     global lcc,cm,dsm,esm
283     import CORBA
284     orb=CORBA.ORB_init([''])
285     import Engines
286     import KernelBasis
287     nsAbroad = orb.string_to_object( KernelBasis.getIOROfEmbeddedNS() )
288     import SALOME
289     CM_NAME_IN_NS = "/ContainerManager"
290     cm = orb.string_to_object( nsAbroad.Resolve(CM_NAME_IN_NS).decode() )
291     naming_service.Register(cm,CM_NAME_IN_NS)
292     RM_NAME_IN_NS = "/ResourcesManager"
293     rm = orb.string_to_object( nsAbroad.Resolve(RM_NAME_IN_NS).decode() )
294     naming_service.Register(rm,RM_NAME_IN_NS)
295     #
296     from LifeCycleCORBA import LifeCycleCORBASSL
297     lcc = LifeCycleCORBASSL()
298     DSM_NAME_IN_NS = "/DataServerManager"
299     dsm = orb.string_to_object( nsAbroad.Resolve(DSM_NAME_IN_NS).decode() )
300     naming_service.Register(dsm,DSM_NAME_IN_NS)
301     #
302     ESM_NAME_IN_NS = "/ExternalServers"
303     esm = orb.string_to_object( nsAbroad.Resolve(ESM_NAME_IN_NS).decode() )
304     naming_service.Register(esm,ESM_NAME_IN_NS)
305
306 def salome_init_with_session(path=None, embedded=False):
307     """
308     Performs only once SALOME general purpose initialisation for scripts.
309     Provides:
310     orb             reference to CORBA
311     lcc             a LifeCycleCorba instance
312     naming_service  a naming service instance
313     cm              reference to the container manager
314     esm             reference to external server manager
315     dsm             reference to shared dataserver manager
316     modulcat        reference to modulecatalog instance
317     sg              access to SALOME GUI (when linked with IAPP GUI)
318     myStudy         active study itself (CORBA reference)
319     myStudyName     active study name
320     """
321     global salome_initial
322     global orb, lcc, naming_service, cm, esm, dsm, modulcat
323     global sg
324     global myStudy, myStudyName
325     import KernelBasis
326     KernelBasis.setSSLMode(False)
327     try:
328         if salome_initial:
329             salome_initial=False
330             sg = salome_iapp_init(embedded)
331             orb, lcc, naming_service, cm, esm, dsm, modulcat = salome_kernel_init()
332             myStudy, myStudyName = salome_study_init(path)
333             pass
334         pass
335     except RuntimeError as inst:
336         # wait a little to avoid trace mix
337         import time
338         time.sleep(0.2)
339         x = inst
340         print("salome.salome_init_with_session():", x)
341         print("""
342         ============================================
343         May be there is no running SALOME session
344         salome.salome_init() is intended to be used
345         within an already running session
346         ============================================
347         """)
348         raise
349     
350 def salome_close():
351     global salome_initial, myStudy, myStudyName, lcc
352     try:
353         # study can be clear either from GUI or directly with salome.myStudy.Clear()
354         myStudy.Clear()
355     except Exception:
356         pass
357     salome_initial=True
358     salome_iapp_close()
359     salome_study_close()
360     myStudy, myStudyName = None, None
361     lcc = None # to salome_init to rebuild all in case of salome_init after salome_close
362     import KernelBasis
363     if KernelBasis.getSSLMode() and not KernelBasis.getGUIMode():
364         import KernelDS
365         KernelDS.KillGlobalSessionInstance()
366         import KernelSDS
367         KernelSDS.KillCPythonHelper()
368     pass
369
370 def salome_NS():
371     import CORBA
372     import CosNaming
373     orb = CORBA.ORB_init()
374     ns0 = orb.resolve_initial_references("NameService")
375     return ns0._narrow(CosNaming.NamingContext)
376
377 def salome_walk_on_containers(ns,root):
378     import CosNaming
379     it = ns.list(0)[1]
380     if not it:
381         return
382     cont = True
383     while cont:
384         cont,obj = it.next_one()
385         if cont:
386             if obj.binding_name[0].kind == "object":
387                 import Engines
388                 corbaObj = ns.resolve(obj.binding_name)
389                 if isinstance(corbaObj,Engines._objref_Container):
390                     yield corbaObj,(root,obj.binding_name[0].id)
391             else:
392                 father = ns.resolve([obj.binding_name[0]])
393                 for elt,elt2 in salome_walk_on_containers(father,root+[obj.binding_name[0].id]):
394                     yield elt,elt2
395             pass
396         pass
397     pass
398
399 def salome_shutdown_containers_with_session():
400     salome_init()
401     ns=salome_NS()
402     li = [elt for elt in salome_walk_on_containers(ns,[""])]
403     print("Number of containers in NS : {}".format(len(li)))
404     for cont,(root,cont_name) in li:
405         try:
406             cont.Shutdown()
407         except Exception:
408             pass
409         ref_in_ns = "/".join(root+[cont_name])
410         naming_service.Destroy_Name(ref_in_ns)
411     print("Number of containers in NS after clean : {}".format( len( list(salome_walk_on_containers(ns,[""])) )))
412     
413 def salome_shutdown_containers_without_session():
414     containersEntries = [elt for elt in naming_service.repr() if "/Containers/" == elt[:12]]
415     for containerEntry in containersEntries:
416         cont = naming_service.Resolve(containerEntry)
417         try:
418             cont.Shutdown()
419         except:
420             pass
421
422 def salome_shutdown_containers():
423     import KernelBasis
424     if KernelBasis.getSSLMode():
425         salome_shutdown_containers_without_session()
426     else:
427         salome_shutdown_containers_with_session()
428
429 class SessionContextManager:
430     def __enter__(self):
431         standalone()
432         salome_init()
433     def __exit__(self, type, value, traceback):
434         salome_close()
435
436 #to expose all objects to pydoc
437 __all__=dir()