The Gaudi Framework  v38r3 (c3fc9673)
gaudirun.py
Go to the documentation of this file.
1 #!/usr/bin/env python3
2 
12 
13 import os
14 import sys
15 from tempfile import mkstemp
16 
17 
19  """
20  Remove from the arguments the presence of the profiler and its output in
21  order to relaunch the script w/o infinite loops.
22 
23  >>> getArgsWithoutProfilerInfo(['--profilerName', 'igprof', 'myopts.py'])
24  ['myopts.py']
25 
26  >>> getArgsWithoutProfilerInfo(['--profilerName=igprof', 'myopts.py'])
27  ['myopts.py']
28 
29  >>> getArgsWithoutProfilerInfo(['--profilerName', 'igprof', '--profilerExtraOptions', 'a b c', 'myopts.py'])
30  ['myopts.py']
31 
32  >>> getArgsWithoutProfilerInfo(['--profilerName', 'igprof', '--options', 'a b c', 'myopts.py'])
33  ['--options', 'a b c', 'myopts.py']
34  """
35  newargs = []
36  args = list(args) # make a temp copy
37  while args:
38  o = args.pop(0)
39  if o.startswith("--profile"):
40  if "=" not in o:
41  args.pop(0)
42  else:
43  newargs.append(o)
44  return newargs
45 
46 
47 def setLibraryPreload(newpreload):
48  """Adds a list of libraries to LD_PRELOAD"""
49  preload = os.environ.get("LD_PRELOAD", "")
50  if preload:
51  preload = preload.replace(" ", ":").split(":")
52  else:
53  preload = []
54 
55  for libname in set(preload).intersection(newpreload):
56  logging.warning(
57  "Ignoring preload of library %s because it is " "already in LD_PRELOAD.",
58  libname,
59  )
60 
61  to_load = [libname for libname in newpreload if libname not in set(preload)]
62 
63  if to_load:
64  preload += to_load
65  preload = ":".join(preload)
66  os.environ["LD_PRELOAD"] = preload
67  logging.info("Setting LD_PRELOAD='%s'", preload)
68 
69  return to_load
70 
71 
72 def rationalizepath(path):
73  """
74  Convert the given path to a real path if the pointed file exists, otherwise
75  just normalize it.
76  """
77  path = os.path.normpath(os.path.expandvars(path))
78  if os.path.exists(path):
79  path = os.path.realpath(path)
80  return path
81 
82 
83 # variable used to keep alive the temporary option files extracted
84 # from the .qmt
85 _qmt_tmp_opt_files = []
86 
87 
88 def getArgsFromQmt(qmtfile):
89  """
90  Given a .qmt file, return the command line arguments of the corresponding
91  test.
92  """
93  from xml.etree import ElementTree as ET
94 
95  global _qmt_tmp_opt_files
96  # parse the .qmt file and extract args and options
97  qmt = ET.parse(qmtfile)
98  args = [a.text for a in qmt.findall("argument[@name='args']//text")]
99  options = qmt.find("argument[@name='options']/text")
100 
101  if (
102  options is not None and options.text is not None
103  ): # options need to be dumped in a temporary file
104  import re
105  from tempfile import NamedTemporaryFile
106 
107  if re.search(
108  r"from\s+Gaudi.Configuration\s+import\s+\*"
109  r"|from\s+Configurables\s+import",
110  options.text,
111  ):
112  tmp_opts = NamedTemporaryFile(suffix=".py")
113  else:
114  tmp_opts = NamedTemporaryFile(suffix=".opts")
115  tmp_opts.write(options.text.encode("ascii"))
116  tmp_opts.flush()
117  args.append(tmp_opts.name)
118  _qmt_tmp_opt_files.append(tmp_opts)
119 
120  # relative paths in a .qmt are rooted in the qmtest directory, so
121  # - find where the .qmt lives
122  qmtfile = os.path.abspath(qmtfile)
123  if "qmtest" in qmtfile.split(os.path.sep):
124  # this return the path up to the 'qmtest' entry in qmtfile
125  testdir = qmtfile
126  while os.path.basename(testdir) != "qmtest":
127  testdir = os.path.dirname(testdir)
128  else:
129  testdir = "."
130  # - temporarily switch to that directory and rationalize the paths
131  old_cwd = os.getcwd()
132  os.chdir(testdir)
133  args = [rationalizepath(arg) for arg in args]
134  os.chdir(old_cwd)
135 
136  return args
137 
138 
139 # ---------------------------------------------------------------------
140 if __name__ == "__main__":
141  # ensure that we (and the subprocesses) use the C standard localization
142  if os.environ.get("LC_ALL") != "C":
143  print('# setting LC_ALL to "C"')
144  # !!!!
145  os.environ["LC_ALL"] = "C"
146 
147  from optparse import OptionParser
148 
149  parser = OptionParser(usage="%prog [options] <opts_file|function_id> ...")
150  parser.add_option(
151  "-n",
152  "--dry-run",
153  action="store_true",
154  help="do not run the application, just parse option files",
155  )
156  parser.add_option(
157  "-p",
158  "--pickle-output",
159  action="store",
160  type="string",
161  metavar="FILE",
162  help="DEPRECATED: use '--output file.pkl' instead. Write "
163  "the parsed options as a pickle file (static option "
164  "file)",
165  )
166  parser.add_option(
167  "-v", "--verbose", action="store_true", help="print the parsed options"
168  )
169  parser.add_option(
170  "--old-opts",
171  action="store_true",
172  help="format printed options in old option files style",
173  )
174  parser.add_option(
175  "--all-opts",
176  action="store_true",
177  help="print all the option (even if equal to default)",
178  )
179  # GaudiPython Parallel Mode Option
180  # Argument must be an integer in range [ -1, sys_cpus ]
181  # -1 : All available cpus
182  # 0 : Serial Mode (traditional gaudirun)
183  # n>0 : parallel with n cpus (n <= sys_cpus)
184  parser.add_option(
185  "--ncpus",
186  action="store",
187  type="int",
188  default=0,
189  help="start the application in parallel mode using NCPUS processes. "
190  "0 => serial mode (default), -1 => use all CPUs",
191  )
192 
193  def option_cb(option, opt, value, parser):
194  """Add the option line to a list together with its position in the
195  argument list.
196  """
197  parser.values.options.append((len(parser.largs), value))
198 
199  parser.add_option(
200  "--option",
201  action="callback",
202  callback=option_cb,
203  type="string",
204  nargs=1,
205  help="add a single line (Python) option to the configuration. "
206  "All options lines are executed, one after the other, in "
207  "the same context.",
208  )
209  parser.add_option(
210  "--no-conf-user-apply",
211  action="store_true",
212  help="disable the automatic application of configurable "
213  "users (for backward compatibility)",
214  )
215  parser.add_option(
216  "--old-conf-user-apply",
217  action="store_true",
218  help="use the old logic when applying ConfigurableUsers "
219  "(with bug #103803) [default]",
220  )
221  parser.add_option(
222  "--new-conf-user-apply",
223  action="store_false",
224  dest="old_conf_user_apply",
225  help="use the new (correct) logic when applying "
226  "ConfigurableUsers (fixed bug #103803), can be "
227  "turned on also with the environment variable "
228  "GAUDI_FIXED_APPLY_CONF",
229  )
230  parser.add_option(
231  "-o",
232  "--output",
233  action="store",
234  type="string",
235  help="dump the configuration to a file. The format of "
236  "the options is determined by the extension of the "
237  "file name: .pkl = pickle, .py = python, .opts = "
238  "old style options. The python format cannot be "
239  "used to run the application and it contains the "
240  "same dictionary printed with -v",
241  )
242  parser.add_option(
243  "--post-option",
244  action="append",
245  type="string",
246  dest="post_options",
247  help="Python options to be executed after the ConfigurableUser "
248  "are applied. "
249  "All options lines are executed, one after the other, in "
250  "the same context.",
251  )
252  parser.add_option(
253  "--debug", action="store_true", help="enable some debug print-out"
254  )
255  parser.add_option("--gdb", action="store_true", help="attach gdb")
256  parser.add_option("--printsequence", action="store_true", help="print the sequence")
257  if not sys.platform.startswith("win"):
258  # These options can be used only on unix platforms
259  parser.add_option(
260  "-T",
261  "--tcmalloc",
262  action="store_true",
263  help="Use the Google malloc replacement. The environment "
264  "variable TCMALLOCLIB can be used to specify a different "
265  "name for the library (the default is libtcmalloc.so)",
266  )
267  parser.add_option(
268  "--preload",
269  action="append",
270  help="Allow pre-loading of special libraries (e.g. Google "
271  "profiling libraries).",
272  )
273  # Option to use a profiler
274  parser.add_option(
275  "--profilerName",
276  type="string",
277  help="Select one profiler among: igprofPerf, igprofMem and valgrind<toolname>",
278  )
279 
280  # Option to specify the filename where to collect the profiler's output
281  parser.add_option(
282  "--profilerOutput",
283  type="string",
284  help="Specify the name of the output file for the profiler output",
285  )
286 
287  # Option to specify the filename where to collect the profiler's output
288  parser.add_option(
289  "--profilerExtraOptions",
290  type="string",
291  help="Specify additional options for the profiler. The '--' string should be expressed as '__' (--my-opt becomes __my-opt)",
292  )
293 
294  parser.add_option(
295  "--use-temp-opts",
296  action="store_true",
297  help="when this option is enabled, the options are parsed"
298  " and stored in a temporary file, then the job is "
299  "restarted using that file as input (to save "
300  "memory)",
301  )
302  parser.add_option(
303  "--run-info-file",
304  type="string",
305  help="Save gaudi process information to the file specified (in JSON format)",
306  )
307  parser.add_option(
308  "--application",
309  help="name of the Gaudi::Application to use [default: %default]",
310  )
311 
312  parser.set_defaults(
313  options=[],
314  tcmalloc=False,
315  profilerName="",
316  profilerOutput="",
317  profilerExtraOptions="",
318  preload=[],
319  ncpus=None,
320  # the old logic can be turned off with an env variable
321  old_conf_user_apply="GAUDI_FIXED_APPLY_CONF" not in os.environ,
322  run_info_file=None,
323  application="Gaudi::Application",
324  )
325 
326  # replace .qmt files in the command line with their contained args
327  argv = []
328  for a in sys.argv[1:]:
329  if a.endswith(".qmt") and os.path.exists(a):
330  argv.extend(getArgsFromQmt(a))
331  else:
332  argv.append(a)
333  if argv != sys.argv[1:]:
334  print("# Running", sys.argv[0], "with arguments", argv)
335 
336  opts, args = parser.parse_args(args=argv)
337 
338  # Check consistency of options
339 
340  # Parallel Option ---------------------------------------------------------
341  if opts.ncpus:
342  from multiprocessing import cpu_count
343 
344  sys_cpus = cpu_count()
345  if opts.ncpus > sys_cpus:
346  s = "Invalid value : --ncpus : only %i cpus available" % sys_cpus
347  parser.error(s)
348  elif opts.ncpus < -1:
349  s = "Invalid value : --ncpus must be integer >= -1"
350  parser.error(s)
351  else:
352  # FIXME: is it really needed to set it to None if it is 0 or False?
353  opts.ncpus = None
354 
355  # configure the logging
356  import logging
357 
358  from GaudiKernel.ProcessJobOptions import InstallRootLoggingHandler, PrintOff
359 
360  if opts.old_opts:
361  prefix = "// "
362  else:
363  prefix = "# "
364  level = logging.INFO
365  if opts.debug:
366  level = logging.DEBUG
367  InstallRootLoggingHandler(prefix, level=level, with_time=opts.debug)
368  root_logger = logging.getLogger()
369 
370  # Sanitizer support
371  sanitizers = os.environ.get("PRELOAD_SANITIZER_LIB", "")
372  preload = os.environ.get("LD_PRELOAD", "")
373  if sanitizers:
374  os.environ["PRELOAD_SANITIZER_LIB"] = ""
375  if preload and sanitizers != preload:
376  logging.warning(
377  "Ignoring PRELOAD_SANITIZER_LIB (={}) as LD_PRELOAD (={}) is "
378  "different and takes precedence.".format(sanitizers, preload)
379  )
380  else:
381  for sanitizer in reversed(sanitizers.split(":")):
382  if sanitizer not in preload:
383  opts.preload.insert(0, sanitizer)
384  if opts.profilerName == "jemalloc":
385  logging.warning("jemalloc disabled when using a sanitizer")
386  opts.profilerName = None
387 
388  # tcmalloc support
389  if opts.tcmalloc:
390  # Disable tcmalloc if sanitizer is selected
391  if sanitizers:
392  logging.warning("tcmalloc preload disabled when using a sanitizer")
393  else:
394  opts.preload.insert(0, os.environ.get("TCMALLOCLIB", "libtcmalloc.so"))
395 
396  # allow preloading of libraries
397  if opts.preload:
398  preload = os.environ.get("LD_PRELOAD", "")
399  if preload:
400  preload = preload.replace(" ", ":").split(":")
401  else:
402  preload = []
403  for libname in set(preload).intersection(opts.preload):
404  logging.warning(
405  "Ignoring preload of library %s because it is "
406  "already in LD_PRELOAD.",
407  libname,
408  )
409  to_load = [libname for libname in opts.preload if libname not in set(preload)]
410  if to_load:
411  preload += to_load
412  preload = ":".join(preload)
413  os.environ["LD_PRELOAD"] = preload
414  logging.info("Restarting with LD_PRELOAD='%s'", preload)
415  # remove the --tcmalloc option from the arguments
416  # FIXME: the --preload arguments will issue a warning but it's tricky to remove them
417  args = [a for a in sys.argv if a != "-T" and not "--tcmalloc".startswith(a)]
418  os.execv(sys.executable, [sys.executable] + args)
419 
420  # Profiler Support ------
421  if opts.profilerName:
422  profilerName = opts.profilerName
423  profilerExecName = ""
424  profilerOutput = opts.profilerOutput or (profilerName + ".output")
425 
426  # To restart the application removing the igprof option and prepending the string
427  args = getArgsWithoutProfilerInfo(sys.argv)
428 
429  igprofPerfOptions = "-d -pp -z -o igprof.pp.gz".split()
430 
431  profilerOptions = ""
432  if profilerName == "igprof":
433  if not opts.profilerOutput:
434  profilerOutput += ".profile.gz"
435  profilerOptions = "-d -z -o %s" % profilerOutput
436  profilerExecName = "igprof"
437 
438  elif profilerName == "igprofPerf":
439  if not opts.profilerOutput:
440  profilerOutput += ".pp.gz"
441  profilerOptions = "-d -pp -z -o %s" % profilerOutput
442  profilerExecName = "igprof"
443 
444  elif profilerName == "igprofMem":
445  if not opts.profilerOutput:
446  profilerOutput += ".mp.gz"
447  profilerOptions = "-d -mp -z -o %s" % profilerOutput
448  profilerExecName = "igprof"
449 
450  elif "valgrind" in profilerName:
451  # extract the tool
452  if not opts.profilerOutput:
453  profilerOutput += ".log"
454  toolname = profilerName.replace("valgrind", "")
455  outoption = "--log-file"
456  if toolname in ("massif", "callgrind", "cachegrind"):
457  outoption = "--%s-out-file" % toolname
458  profilerOptions = "--tool=%s %s=%s" % (toolname, outoption, profilerOutput)
459  profilerExecName = "valgrind"
460 
461  elif profilerName == "jemalloc":
462  opts.preload.insert(0, os.environ.get("JEMALLOCLIB", "libjemalloc.so"))
463  os.environ["MALLOC_CONF"] = "prof:true,prof_leak:true"
464  else:
465  root_logger.warning("Profiler %s not recognized!" % profilerName)
466 
467  # Add potential extra options
468  if opts.profilerExtraOptions != "":
469  profilerExtraOptions = opts.profilerExtraOptions
470  profilerExtraOptions = profilerExtraOptions.replace("__", "--")
471  profilerOptions += " %s" % profilerExtraOptions
472 
473  # now we look for the full path of the profiler: is it really there?
474  if profilerExecName:
475  import distutils.spawn
476 
477  profilerPath = distutils.spawn.find_executable(profilerExecName)
478  if not profilerPath:
479  root_logger.error("Cannot locate profiler %s" % profilerExecName)
480  sys.exit(1)
481 
482  root_logger.info(
483  "------ Profiling options are on ------ \n"
484  " o Profiler: %s\n"
485  " o Options: '%s'.\n"
486  " o Output: %s"
487  % (profilerExecName or profilerName, profilerOptions, profilerOutput)
488  )
489 
490  # allow preloading of libraries
491  # That code need to be acsracted from above
492  to_reload = []
493  if opts.preload:
494  to_reload = setLibraryPreload(opts.preload)
495 
496  if profilerExecName:
497  # We profile python
498  profilerOptions += " python"
499 
500  # now we have all the ingredients to prepare our command
501  arglist = [profilerPath] + profilerOptions.split() + args
502  arglist = [a for a in arglist if a != ""]
503  # print profilerPath
504  # for arg in arglist:
505  # print arg
506  os.execv(profilerPath, arglist)
507  else:
508  arglist = [a for a in sys.argv if not a.startswith("--profiler")]
509  os.execv(sys.executable, [sys.executable] + arglist)
510 
511  # End Profiler Support ------
512 
513  if opts.pickle_output:
514  if opts.output:
515  root_logger.error(
516  "Conflicting options: use only --pickle-output or --output"
517  )
518  sys.exit(1)
519  else:
520  root_logger.warning("--pickle-output is deprecated, use --output instead")
521  opts.output = opts.pickle_output
522 
523  from Gaudi.Main import gaudimain
524 
525  c = gaudimain()
526 
528  """
529  Helper class to be able to process option files or options
530  callables as they come along in the arguments.
531  """
532 
533  def __init__(self, initial_config=None):
534  self.config = {} if initial_config is None else initial_config
535 
536  def __call__(self, arg):
537  from GaudiConfig2 import CALLABLE_FORMAT, invokeConfig, mergeConfigs
538 
539  from Gaudi.Configuration import importOptions
540 
541  if CALLABLE_FORMAT.match(arg):
542  self.config = mergeConfigs(self.config, invokeConfig(arg))
543  else:
544  importOptions(arg)
545 
546  process = ArgProcessor()
547 
548  # Prepare the "configuration script" to parse (like this it is easier than
549  # having a list with files and python commands, with an if statements that
550  # decides to do importOptions or exec)
551  options = ["process({!r})".format(arg) for arg in args]
552  # The option lines are inserted into the list of commands using their
553  # position on the command line
554  optlines = list(opts.options)
555  # this allows to avoid to have to care about corrections of the positions
556  optlines.reverse()
557  for pos, l in optlines:
558  options.insert(pos, l)
559 
560  # prevent the usage of GaudiPython
561  class FakeModule(object):
562  def __init__(self, exception):
563  self.exception = exception
564 
565  def __getattr__(self, *args, **kwargs):
566  raise self.exception
567 
568  sys.modules["GaudiPython"] = FakeModule(
569  RuntimeError("GaudiPython cannot be used in option files")
570  )
571 
572  # when the special env GAUDI_TEMP_OPTS_FILE is set, it overrides any
573  # option(file) on the command line
574  if "GAUDI_TEMP_OPTS_FILE" in os.environ:
575  options = ["process({!r})".format(os.environ["GAUDI_TEMP_OPTS_FILE"])]
576  PrintOff(100)
577 
578  # "execute" the configuration script generated (if any)
579  if options:
580  g = {"process": process}
581  l = {}
582  exec("from Gaudi.Configuration import *", g, l)
583  for o in options:
584  logging.debug(o)
585  exec(o, g, l)
586 
587  import GaudiKernel.Proxy.Configurable
588 
589  if opts.no_conf_user_apply:
590  logging.info("Disabling automatic apply of ConfigurableUser")
591  # pretend that they have been already applied
592  GaudiKernel.Proxy.Configurable._appliedConfigurableUsers_ = True
593 
594  # This need to be done before dumping
595  if opts.old_conf_user_apply:
596  from GaudiKernel.Proxy.Configurable import (
597  applyConfigurableUsers_old as applyConfigurableUsers,
598  )
599  else:
600  from GaudiKernel.Proxy.Configurable import applyConfigurableUsers
602 
603  # Options to be processed after applyConfigurableUsers
604  if opts.post_options:
605  g = {"process": process}
606  l = {}
607  exec("from Gaudi.Configuration import *", g, l)
608  for o in opts.post_options:
609  logging.debug(o)
610  exec(o, g, l)
611 
612  if "GAUDI_TEMP_OPTS_FILE" in os.environ:
613  os.remove(os.environ["GAUDI_TEMP_OPTS_FILE"])
614  opts.use_temp_opts = False
615 
616  # make configurations available to getAllOpts
617  # FIXME the whole machinery has to be inverted, to avoid relying on globals
618  from GaudiConfig2 import Configurable, mergeConfigs
619 
620  Configurable.instances = mergeConfigs(Configurable.instances, process.config)
621 
622  if opts.verbose and not opts.use_temp_opts:
623  c.printconfig(opts.old_opts, opts.all_opts)
624  if opts.output:
625  c.writeconfig(opts.output, opts.all_opts)
626 
627  if opts.use_temp_opts:
628  fd, tmpfile = mkstemp(".opts")
629  os.close(fd)
630  c.writeconfig(tmpfile, opts.all_opts)
631  os.environ["GAUDI_TEMP_OPTS_FILE"] = tmpfile
632  logging.info("Restarting from pre-parsed options")
633  os.execv(sys.executable, [sys.executable] + sys.argv)
634 
635  c.printsequence = opts.printsequence
636  if opts.printsequence:
637  if opts.ncpus:
638  logging.warning("--printsequence not supported with --ncpus: ignored")
639  elif opts.dry_run:
640  logging.warning("--printsequence not supported with --dry-run: ignored")
641 
642  c.application = opts.application
643 
644  # re-enable the GaudiPython module
645  del sys.modules["GaudiPython"]
646 
647  if not opts.dry_run:
648  # Do the real processing
649  retcode = c.run(opts.gdb, opts.ncpus)
650 
651  # Now saving the run information pid, retcode and executable path to
652  # a file is requested
653  if opts.run_info_file:
654  import json
655  import os
656 
657  run_info = {}
658  run_info["pid"] = os.getpid()
659  run_info["retcode"] = retcode
660  if os.path.exists("/proc/self/exe"):
661  # These options can be used only on unix platforms
662  run_info["exe"] = os.readlink("/proc/self/exe")
663 
664  logging.info("Saving run info to: %s" % opts.run_info_file)
665  with open(opts.run_info_file, "w") as f:
666  json.dump(run_info, f)
667 
668  sys.exit(retcode)
gaudirun.FakeModule.__init__
def __init__(self, exception)
Definition: gaudirun.py:562
gaudirun.FakeModule
Definition: gaudirun.py:561
gaudirun.ArgProcessor.__call__
def __call__(self, arg)
Definition: gaudirun.py:536
gaudirun.ArgProcessor
Definition: gaudirun.py:527
gaudirun.FakeModule.exception
exception
Definition: gaudirun.py:563
GaudiConfig2.invokeConfig
def invokeConfig(func, *args, **kwargs)
Definition: __init__.py:70
gaudirun.FakeModule.__getattr__
def __getattr__(self, *args, **kwargs)
Definition: gaudirun.py:565
gaudirun.ArgProcessor.__init__
def __init__(self, initial_config=None)
Definition: gaudirun.py:533
gaudirun.getArgsFromQmt
def getArgsFromQmt(qmtfile)
Definition: gaudirun.py:88
GaudiKernel.ProcessJobOptions
Definition: ProcessJobOptions.py:1
gaudirun.getArgsWithoutProfilerInfo
def getArgsWithoutProfilerInfo(args)
Definition: gaudirun.py:18
GaudiConfig2.mergeConfigs
def mergeConfigs(*configs)
Definition: __init__.py:51
Gaudi.Configuration
Definition: Configuration.py:1
Gaudi.Main
Definition: Main.py:1
Gaudi.Main.gaudimain
Definition: Main.py:323
format
GAUDI_API std::string format(const char *,...)
MsgStream format utility "a la sprintf(...)".
Definition: MsgStream.cpp:119
GaudiKernel.ProcessJobOptions.InstallRootLoggingHandler
def InstallRootLoggingHandler(prefix=None, level=None, stream=None, with_time=False)
Definition: ProcessJobOptions.py:128
GaudiKernel.ProcessJobOptions.importOptions
def importOptions(optsfile)
Definition: ProcessJobOptions.py:541
gaudirun.option_cb
def option_cb(option, opt, value, parser)
Definition: gaudirun.py:193
gaudirun.setLibraryPreload
def setLibraryPreload(newpreload)
Definition: gaudirun.py:47
gaudirun.ArgProcessor.config
config
Definition: gaudirun.py:534
gaudirun.rationalizepath
def rationalizepath(path)
Definition: gaudirun.py:72
GaudiKernel.ProcessJobOptions.PrintOff
def PrintOff(step=1)
Definition: ProcessJobOptions.py:141
GaudiKernel.Configurable.applyConfigurableUsers
def applyConfigurableUsers()
Definition: Configurable.py:1605