Salome HOME
Merge branch 'mbs/auto_backup' of https://codev-tuleap.cea.fr/plugins/git/salome...
[modules/kernel.git] / bin / salomeContext.py
1 #! /usr/bin/env python3
2 # Copyright (C) 2013-2024  CEA, EDF, OPEN CASCADE
3 #
4 # This library is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU Lesser General Public
6 # License as published by the Free Software Foundation; either
7 # version 2.1 of the License, or (at your option) any later version.
8 #
9 # This library is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12 # Lesser General Public License for more details.
13 #
14 # You should have received a copy of the GNU Lesser General Public
15 # License along with this library; if not, write to the Free Software
16 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
17 #
18 # See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
19 #
20
21 import os
22 import sys
23 import logging
24 import configparser
25
26 from parseConfigFile import parseConfigFile
27
28 import tempfile
29 import pickle
30 import subprocess
31 import sys
32 import platform
33
34 from salomeContextUtils import SalomeContextException
35
36 def usage():
37   msg = '''\
38 Usage: salome [command] [options] [--config=<file,folder,...>] [--with-env-modules=<env_module1,env_module2,...>]
39
40 Commands:
41 =========
42     start           Start a new SALOME instance. Start a single SALOME_Session_Server_No_Server
43                     process with environment relevant to the application and hosting all servants in it.
44     context         Initialize SALOME context. Current environment is extended.
45     shell           Initialize SALOME context, attached to the last created SALOME
46                     instance if any, and executes scripts passed as command arguments.
47                     User works in a Shell terminal. SALOME environment is set but
48                     application is not started.
49     test            Run SALOME tests.
50     info            Display some information about SALOME.
51     doc <module(s)> Show online module documentation (if available).
52                     Module names must be separated by blank characters.
53     help            Show this message.
54     remote          run command in SALOME environment from remote call, ssh or rsh.
55     withsession     Start a new SWS SALOME instance with multiple servers hosting all servants.
56     connect         In SWS context, Connect a Python console to the active SALOME instance.
57     kill <port(s)>  In SWS context, Terminate SALOME instances running on given ports for current user.
58                     Port numbers must be separated by blank characters.
59     killall         Terminate *all* SALOME running SWS instances for current user.
60                     Do not start a new one.
61
62 If no command is given, default is start.
63
64 Command options:
65 ================
66     Use salome <command> --help to show help on command. Available for the
67     following commands: start, shell, connect, test, info.
68
69 --config=<file,folder,...>
70 ==========================
71     Initialize SALOME context from a list of context files and/or a list
72     of folders containing context files. The list is comma-separated, without
73     any blank characters.
74
75 --with-env-modules=<env_module1,env_module2,...>
76 ================================================
77     Initialize SALOME context with the provided additional environment modules.
78     The list is comma-separated, without any blank characters.
79 '''
80
81   print(msg)
82 #
83
84 """
85 The SalomeContext class in an API to configure SALOME context then
86 start SALOME using a single python command.
87
88 """
89 class SalomeContext:
90   """
91   Initialize context from a list of configuration files
92   identified by their names.
93   These files should be in appropriate .cfg format.
94   """
95   def __init__(self, configFileNames=0):
96     self.getLogger().setLevel(logging.INFO)
97     #it could be None explicitly (if user use multiples setVariable...for standalone)
98     if configFileNames is None:
99        return
100     configFileNames = configFileNames or []
101     if len(configFileNames) == 0:
102       raise SalomeContextException("No configuration files given")
103
104     reserved=['PATH', 'DYLD_FALLBACK_LIBRARY_PATH', 'DYLD_LIBRARY_PATH', 'LD_LIBRARY_PATH', 'PYTHONPATH', 'MANPATH', 'PV_PLUGIN_PATH', 'INCLUDE', 'LIBPATH', 'SALOME_PLUGINS_PATH', 'LIBRARY_PATH', 'QT_PLUGIN_PATH']
105     for filename in configFileNames:
106       basename, extension = os.path.splitext(filename)
107       if extension == ".cfg":
108         self.__setContextFromConfigFile(filename, reserved)
109       else:
110         self.getLogger().error("Unrecognized extension for configuration file: %s", filename)
111   #
112
113   def __loadEnvModules(self, env_modules):
114     modulecmd = os.getenv('LMOD_CMD')
115     if not modulecmd:
116       raise SalomeContextException("Module environment not present")
117       return
118     try:
119       out, err = subprocess.Popen([modulecmd, "python", "try-load"] + env_modules, stdout=subprocess.PIPE).communicate()
120       exec(out)  # define specific environment variables
121     except Exception:
122       raise SalomeContextException("Failed to load env modules: %s ..." % ' '.join(env_modules))
123       pass
124   #
125
126   def runSalome(self, args):
127     import os
128     # Run this module as a script, in order to use appropriate Python interpreter
129     # according to current path (initialized from context files).
130     env_modules_option = "--with-env-modules="
131     env_modules_l = [x for x in args if x.startswith(env_modules_option)]
132     if env_modules_l:
133       env_modules = env_modules_l[-1][len(env_modules_option):].split(',')
134       self.__loadEnvModules(env_modules)
135       args = [x for x in args if not x.startswith(env_modules_option)]
136     else:
137       env_modules = os.getenv("SALOME_ENV_MODULES", None)
138       if env_modules:
139         self.__loadEnvModules(env_modules.split(','))
140
141     absoluteAppliPath = os.getenv('ABSOLUTE_APPLI_PATH','')
142     env_copy = os.environ.copy()
143     selfBytes= pickle.dumps(self, protocol=0)
144     argsBytes= pickle.dumps(args, protocol=0)
145     proc = subprocess.Popen(['python3', os.path.join(absoluteAppliPath,"bin","salome","salomeContext.py"), selfBytes.decode('latin1'), argsBytes.decode('latin1')], shell=False, close_fds=True, env=env_copy)
146     out, err = proc.communicate()
147     return out, err, proc.returncode
148   #
149
150   """Append value to PATH environment variable"""
151   def addToPath(self, value):
152     self.addToVariable('PATH', value)
153   #
154
155   """Append value to LD_LIBRARY_PATH environment variable"""
156   def addToLdLibraryPath(self, value):
157     if sys.platform == 'win32':
158       self.addToVariable('PATH', value)
159     elif  sys.platform == 'darwin':
160       if "LAPACK" in value:
161         self.addToVariable('DYLD_FALLBACK_LIBRARY_PATH', value)
162       else:
163         self.addToVariable('DYLD_LIBRARY_PATH', value)
164     else:
165       self.addToVariable('LD_LIBRARY_PATH', value)
166   #
167
168   """Append value to DYLD_LIBRARY_PATH environment variable"""
169   def addToDyldLibraryPath(self, value):
170     self.addToVariable('DYLD_LIBRARY_PATH', value)
171   #
172
173   """Append value to PYTHONPATH environment variable"""
174   def addToPythonPath(self, value):
175     self.addToVariable('PYTHONPATH', value)
176   #
177
178   """Set environment variable to value"""
179   def setVariable(self, name, value, overwrite=False):
180     env = os.getenv(name, '')
181     if env and not overwrite:
182       self.getLogger().error("Environment variable already existing (and not overwritten): %s=%s", name, value)
183       return
184
185     if env:
186       self.getLogger().debug("Overwriting environment variable: %s=%s", name, value)
187
188     value = os.path.expandvars(value) # expand environment variables
189     self.getLogger().debug("Set environment variable: %s=%s", name, value)
190     os.environ[name] = value
191   #
192
193   def setDefaultValue(self, name, value):
194     """ Set environment variable only if it is undefined."""
195     env = os.getenv(name, '')
196     if not env:
197       value = os.path.expandvars(value) # expand environment variables
198       self.getLogger().debug("Set environment variable: %s=%s", name, value)
199       os.environ[name] = value
200
201   """Unset environment variable"""
202   def unsetVariable(self, name):
203     if name in os.environ:
204       del os.environ[name]
205   #
206
207   """Prepend value to environment variable"""
208   def addToVariable(self, name, value, separator=os.pathsep):
209     if value == '':
210       return
211
212     value = os.path.expandvars(value) # expand environment variables
213     self.getLogger().debug("Add to %s: %s", name, value)
214     env = os.getenv(name, None)
215     if env is None:
216       os.environ[name] = value
217     else:
218       os.environ[name] = value + separator + env
219   #
220
221   """Append a variable"""
222   def appendVariable(self, name, value, separator=os.pathsep):
223     if value == '':
224       return
225
226     value = os.path.expandvars(value) # expand environment variables
227     env = os.getenv(name, None)
228     if env is None:
229       os.environ[name] = value
230     else:
231       os.environ[name] = env + separator + value
232     return
233
234   ###################################
235   # This begins the private section #
236   ###################################
237
238   def __parseArguments(self, args):
239     if len(args) == 0 or args[0].startswith("-"):
240       return None, args
241
242     command = args[0]
243     options = args[1:]
244
245     availableCommands = {
246       'start'   : '_sessionless',
247       'withsession' : '_runAppli',
248       'context' : '_setContext',
249       'shell'   : '_runSession',
250       'remote'  : '_runRemote',
251       'connect' : '_runConsole',
252       'kill'    : '_kill',
253       'killall' : '_killAll',
254       'test'    : '_runTests',
255       'info'    : '_showInfo',
256       'doc'     : '_showDoc',
257       'help'    : '_usage',
258       'coffee'  : '_makeCoffee',
259       'car'     : '_getCar',
260       }
261
262     if command not in availableCommands:
263       command = "start"
264       options = args
265
266     return availableCommands[command], options
267   #
268
269   """
270   Run SALOME!
271   Args consist in a mandatory command followed by optional parameters.
272   See usage for details on commands.
273   """
274   def _startSalome(self, args):
275     import os
276     import sys
277     try:
278       from setenv import add_path
279       absoluteAppliPath = os.getenv('ABSOLUTE_APPLI_PATH')
280       path = os.path.realpath(os.path.join(absoluteAppliPath, "bin", "salome"))
281       add_path(path, "PYTHONPATH")
282       path = os.path.realpath(os.path.join(absoluteAppliPath, "bin", "salome", "appliskel"))
283       add_path(path, "PYTHONPATH")
284
285     except Exception:
286       pass
287
288     command, options = self.__parseArguments(args)
289     sys.argv = options
290
291     if command is None:
292       if args and args[0] in ["-h","--help","help"]:
293         usage()
294         return 0
295       # try to default to "start" command
296       command = "_sessionless"
297
298     try:
299       res = getattr(self, command)(options) # run appropriate method
300       return res or 0
301     except SystemExit as ex:
302       if ex.code != 0:
303         self.getLogger().error("SystemExit %s in method %s.", ex.code, command)
304       return ex.code
305     except SalomeContextException as e:
306       self.getLogger().error(e)
307       return 1
308     except Exception:
309       self.getLogger().error("Unexpected error:")
310       import traceback
311       traceback.print_exc()
312       return 1
313   #
314
315   def __setContextFromConfigFile(self, filename, reserved=None):
316     mesa_root_dir = "MESA_ROOT_DIR"
317     if reserved is None:
318       reserved = []
319     try:
320       configInfo = parseConfigFile(filename, reserved)
321       unsetVars = configInfo.unsetVariables
322       configVars = configInfo.outputVariables
323       reservedDict = configInfo.reservedValues
324       defaultValues = configInfo.defaultValues
325     except SalomeContextException as e:
326       msg = "%s"%e
327       self.getLogger().error(msg)
328       return 1
329
330     # unset variables
331     for var in unsetVars:
332       self.unsetVariable(var)
333
334     # mesa stuff
335     if "MESA_GL_VERSION_OVERRIDE" in os.environ:
336       configVarsDict = {k:v for (k,v) in configVars}
337       if mesa_root_dir in configVarsDict:
338         path_to_mesa_lib = os.path.join(configVarsDict[mesa_root_dir],"lib")
339         if os.name == "posix":
340           self.addToVariable("LD_LIBRARY_PATH",path_to_mesa_lib)
341         else:
342           self.addToVariable("PATH",path_to_mesa_lib)
343
344     # set context
345     for reserved in reservedDict:
346       a = [_f for _f in reservedDict[reserved] if _f] # remove empty elements
347       a = [ os.path.realpath(x) for x in a ]
348       reformattedVals = os.pathsep.join(a)
349       if reserved in ["INCLUDE", "LIBPATH"]:
350         self.addToVariable(reserved, reformattedVals, separator=' ')
351       else:
352         self.addToVariable(reserved, reformattedVals)
353       pass
354
355
356     for key,val in configVars:
357       self.setVariable(key, val, overwrite=True)
358       pass
359
360     for key,val in defaultValues:
361       self.setDefaultValue(key, val)
362       pass
363
364     pythonpath = os.getenv('PYTHONPATH','').split(os.pathsep)
365     pythonpath = [ os.path.realpath(x) for x in pythonpath ]
366     sys.path[:0] = pythonpath
367   #
368
369   def _runAppli(self, args=None):
370     if args is None:
371       args = []
372     # Initialize SALOME environment
373     sys.argv = ['runSalomeOld'] + args
374     import setenv
375     setenv.main(True, exeName="salome withsession")
376
377     import runSalomeOld
378     runSalomeOld.runSalome()
379     return 0
380   #
381
382   def _sessionless(self, args=None):
383     if args is None:
384       args = []
385     sys.argv = ['runSalome'] + args
386     import setenv
387     setenv.main(True, exeName="salome withsession")
388
389     import runSalome
390     runSalome.runSalome()
391     return 0
392   #
393
394   def _setContext(self, args=None):
395     salome_context_set = os.getenv("SALOME_CONTEXT_SET")
396     if salome_context_set:
397       print("***")
398       print("*** SALOME context has already been set.")
399       print("*** Enter 'exit' (only once!) to leave SALOME context.")
400       print("***")
401       return 0
402
403     os.environ["SALOME_CONTEXT_SET"] = "yes"
404     print("***")
405     print("*** SALOME context is now set.")
406     print("*** Enter 'exit' (only once!) to leave SALOME context.")
407     print("***")
408
409     if sys.platform == 'win32':
410       cmd = ['cmd.exe']
411     else:
412       cmd = ["/bin/bash"]
413     proc = subprocess.Popen(cmd, shell=False, close_fds=True)
414     proc.communicate()
415     return proc.returncode
416   #
417
418   def _runSession(self, args=None):
419     if args is None:
420       args = []
421     sys.argv = ['runSession'] + args
422     import runSession
423     params, args = runSession.configureSession(args, exe="salome shell")
424
425     sys.argv = ['runSession'] + args
426     import setenv
427     setenv.main(True)
428
429     return runSession.runSession(params, args)
430   #
431
432   def _runRemote(self, args=None):
433     if args is None:
434       args = []
435 #   complete salome environment 
436     sys.argv = ['runRemote']
437     import setenv
438     setenv.main(True)
439
440     import runRemote
441     return runRemote.runRemote(args)
442   #
443
444   def _runConsole(self, args=None):
445     if args is None:
446       args = []
447     # Initialize SALOME environment
448     sys.argv = ['runConsole']
449     import setenv
450     setenv.main(True)
451
452     import runConsole
453     return runConsole.connect(args)
454   #
455
456   def _kill(self, args=None):
457     if args is None:
458       args = []
459     ports = args
460     if not ports:
461       print("Port number(s) not provided to command: salome kill <port(s)>")
462       return 1
463
464     import subprocess
465     sys.argv = ['kill']
466     import setenv
467     setenv.main(True)
468     if os.getenv("NSHOST") == "no_host":
469       os.unsetenv("NSHOST")
470     for port in ports:
471       if sys.platform == "win32":
472         proc = subprocess.Popen([os.getenv("PYTHONBIN"), "-m", "killSalomeWithPort", str(port)])
473       else:
474         proc = subprocess.Popen(["killSalomeWithPort.py", str(port)])
475       proc.communicate()
476     return 0
477   #
478
479   def _killAll(self, unused=None):
480     sys.argv = ['killAll']
481     import setenv
482     setenv.main(True)
483     if os.getenv("NSHOST") == "no_host":
484       os.unsetenv("NSHOST")
485     try:
486       import PortManager # mandatory
487       import subprocess
488       ports = PortManager.getBusyPorts()['this']
489
490       if ports:
491         for port in ports:
492           if sys.platform == "win32":
493             proc = subprocess.Popen([os.getenv("PYTHONBIN"), "-m", "killSalomeWithPort", str(port)])
494           else:
495             proc = subprocess.Popen(["killSalomeWithPort.py", str(port)])
496           proc.communicate()
497     except ImportError:
498       # :TODO: should be declared obsolete
499       from killSalome import killAllPorts
500       killAllPorts()
501       pass
502     from addToKillList import killList
503     killList()
504     return 0
505   #
506
507   def _runTests(self, args=None):
508     if args is None:
509       args = []
510     sys.argv = ['runTests']
511     import setenv
512     setenv.main(True)
513
514     import runTests
515     return runTests.runTests(args, exe="salome test")
516   #
517
518   def _showSoftwareVersions(self, softwares=None):
519     config = configparser.SafeConfigParser()
520     absoluteAppliPath = os.getenv('ABSOLUTE_APPLI_PATH')
521     filename = os.path.join(absoluteAppliPath, "sha1_collections.txt")
522     versions = {}
523     max_len = 0
524     with open(filename) as f:
525       for line in f:
526         try:
527           software, version, sha1 = line.split()
528           versions[software.upper()] = version
529           if len(software) > max_len:
530             max_len = len(software)
531         except Exception:
532           pass
533         pass
534       pass
535     if softwares:
536       for soft in softwares:
537         if soft.upper() in versions:
538           print(soft.upper().rjust(max_len), versions[soft.upper()])
539     else:
540       import collections
541       od = collections.OrderedDict(sorted(versions.items()))
542       for name, version in od.items():
543         print(name.rjust(max_len), versions[name])
544     pass
545
546   def _showInfo(self, args=None):
547     if args is None:
548       args = []
549
550     usage = "Usage: salome info [options]"
551     epilog  = """\n
552 Display some information about SALOME.\n
553 Available options are:
554     -p,--ports                     Show the list of busy ports (running SALOME instances).
555     -s,--softwares [software(s)]   Show the list and versions of SALOME softwares.
556                                    Software names must be separated by blank characters.
557                                    If no software is given, show version of all softwares.
558     -v,--version                   Show running SALOME version.
559     -h,--help                      Show this message.
560 """
561     if not args:
562       args = ["--version"]
563
564     if "-h" in args or "--help" in args:
565       print(usage + epilog)
566       return 0
567
568     if "-p" in args or "--ports" in args:
569       import PortManager
570       ports = PortManager.getBusyPorts()
571       this_ports = ports['this']
572       other_ports = ports['other']
573       if this_ports or other_ports:
574           print("SALOME instances are running on the following ports:")
575           if this_ports:
576               print("   This application:", this_ports)
577           else:
578               print("   No SALOME instances of this application")
579           if other_ports:
580               print("   Other applications:", other_ports)
581           else:
582               print("   No SALOME instances of other applications")
583       else:
584           print("No SALOME instances are running")
585
586     if "-s" in args or "--softwares" in args:
587       if "-s" in args:
588         index = args.index("-s")
589       else:
590         index = args.index("--softwares")
591       indexEnd=index+1
592       while indexEnd < len(args) and args[indexEnd][0] != "-":
593         indexEnd = indexEnd + 1
594       self._showSoftwareVersions(softwares=args[index+1:indexEnd])
595
596     if "-v" in args or "--version" in args:
597       print("Running with python", platform.python_version())
598       return self._sessionless(["--version"])
599
600     return 0
601   #
602
603   def _showDoc(self, args=None):
604     if args is None:
605       args = []
606
607     modules = args
608     if not modules:
609       print("Module(s) not provided to command: salome doc <module(s)>")
610       return 1
611
612     appliPath = os.getenv("ABSOLUTE_APPLI_PATH")
613     if not appliPath:
614       raise SalomeContextException("Unable to find application path. Please check that the variable ABSOLUTE_APPLI_PATH is set.")
615     baseDir = os.path.join(appliPath, "share", "doc", "salome")
616     for module in modules:
617       docfile = os.path.join(baseDir, "gui", module.upper(), "index.html")
618       if not os.path.isfile(docfile):
619         docfile = os.path.join(baseDir, "tui", module.upper(), "index.html")
620       if not os.path.isfile(docfile):
621         docfile = os.path.join(baseDir, "dev", module.upper(), "index.html")
622       if os.path.isfile(docfile):
623         out, err = subprocess.Popen(["xdg-open", docfile]).communicate()
624       else:
625         print("Online documentation is not accessible for module:", module)
626
627   def _usage(self, unused=None):
628     usage()
629   #
630
631   def _makeCoffee(self, unused=None):
632     print("                        (")
633     print("                          )     (")
634     print("                   ___...(-------)-....___")
635     print("               .-\"\"       )    (          \"\"-.")
636     print("         .-\'``\'|-._             )         _.-|")
637     print("        /  .--.|   `\"\"---...........---\"\"`   |")
638     print("       /  /    |                             |")
639     print("       |  |    |                             |")
640     print("        \\  \\   |                             |")
641     print("         `\\ `\\ |                             |")
642     print("           `\\ `|            SALOME           |")
643     print("           _/ /\\            4 EVER           /")
644     print("          (__/  \\             <3            /")
645     print("       _..---\"\"` \\                         /`\"\"---.._")
646     print("    .-\'           \\                       /          \'-.")
647     print("   :               `-.__             __.-\'              :")
648     print("   :                  ) \"\"---...---\"\" (                 :")
649     print("    \'._               `\"--...___...--\"`              _.\'")
650     print("      \\\"\"--..__                              __..--\"\"/")
651     print("       \'._     \"\"\"----.....______.....----\"\"\"     _.\'")
652     print("          `\"\"--..,,_____            _____,,..--\"\"`")
653     print("                        `\"\"\"----\"\"\"`")
654     print("")
655     print("                    SALOME is working for you; what else?")
656     print("")
657   #
658
659   def _getCar(self, unused=None):
660     print("                                              _____________")
661     print("                                  ..---:::::::-----------. ::::;;.")
662     print("                               .\'\"\"\"\"\"\"                  ;;   \\  \":.")
663     print("                            .\'\'                          ;     \\   \"\\__.")
664     print("                          .\'                            ;;      ;   \\\\\";")
665     print("                        .\'                              ;   _____;   \\\\/")
666     print("                      .\'                               :; ;\"     \\ ___:\'.")
667     print("                    .\'--...........................    : =   ____:\"    \\ \\")
668     print("               ..-\"\"                               \"\"\"\'  o\"\"\"     ;     ; :")
669     print("          .--\"\"  .----- ..----...    _.-    --.  ..-\"     ;       ;     ; ;")
670     print("       .\"\"_-     \"--\"\"-----\'\"\"    _-\"        .-\"\"         ;        ;    .-.")
671     print("    .\'  .\'   SALOME             .\"         .\"              ;       ;   /. |")
672     print("   /-./\'         4 EVER <3    .\"          /           _..  ;       ;   ;;;|")
673     print("  :  ;-.______               /       _________==.    /_  \\ ;       ;   ;;;;")
674     print("  ;  / |      \"\"\"\"\"\"\"\"\"\"\".---.\"\"\"\"\"\"\"          :    /\" \". |;       ; _; ;;;")
675     print(" /\"-/  |                /   /                  /   /     ;|;      ;-\" | ;\';")
676     print(":-  :   \"\"\"----______  /   /              ____.   .  .\"\'. ;;   .-\"..T\"   .")
677     print("\'. \"  ___            \"\":   \'\"\"\"\"\"\"\"\"\"\"\"\"\"\"    .   ; ;    ;; ;.\" .\"   \'--\"")
678     print(" \",   __ \"\"\"  \"\"---... :- - - - - - - - - \' \'  ; ;  ;    ;;\"  .\"")
679     print("  /. ;  \"\"\"---___                             ;  ; ;     ;|.\"\"")
680     print(" :  \":           \"\"\"----.    .-------.       ;   ; ;     ;:")
681     print("  \\  \'--__               \\   \\        \\     /    | ;     ;;")
682     print("   \'-..   \"\"\"\"---___      :   .______..\\ __/..-\"\"|  ;   ; ;")
683     print("       \"\"--..       \"\"\"--\"        m l s         .   \". . ;")
684     print("             \"\"------...                  ..--\"\"      \" :")
685     print("                        \"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"    \\        /")
686     print("                                               \"------\"")
687     print("")
688     print("                                Drive your simulation properly with SALOME!")
689     print("")
690   #
691
692   # Add the following two methods since logger is not pickable
693   # Ref: http://stackoverflow.com/questions/2999638/how-to-stop-attributes-from-being-pickled-in-python
694   def __getstate__(self):
695     d = dict(self.__dict__)
696     if hasattr(self, '_logger'):
697       del d['_logger']
698     return d
699   #
700   def __setstate__(self, d):
701     self.__dict__.update(d) # I *think* this is a safe way to do it
702   #
703   # Excluding self._logger from pickle operation imply using the following method to access logger
704   def getLogger(self):
705     if not hasattr(self, '_logger'):
706       self._logger = logging.getLogger(__name__)
707       #self._logger.setLevel(logging.DEBUG)
708       #self._logger.setLevel(logging.WARNING)
709       self._logger.setLevel(logging.ERROR)
710     return self._logger
711   #
712
713 if __name__ == "__main__":
714   if len(sys.argv) == 3:
715     context = pickle.loads(sys.argv[1].encode('latin1'))
716     args = pickle.loads(sys.argv[2].encode('latin1'))
717
718     status = context._startSalome(args)
719     sys.exit(status)
720   else:
721     usage()
722 #