CMS 3D CMS Logo

runTheMatrix.py
Go to the documentation of this file.
1 #!/usr/bin/env python3
2 from __future__ import print_function
3 import sys, os
4 
5 from Configuration.PyReleaseValidation.MatrixReader import MatrixReader
6 from Configuration.PyReleaseValidation.MatrixRunner import MatrixRunner
7 from Configuration.PyReleaseValidation.MatrixInjector import MatrixInjector,performInjectionOptionTest
8 
9 # ================================================================================
10 
11 def showRaw(opt):
12 
13  mrd = MatrixReader(opt)
14  mrd.showRaw(opt.useInput, opt.refRel, opt.fromScratch, opt.raw, opt.step1Only, selected=opt.testList)
15 
16  return 0
17 
18 # ================================================================================
19 
20 def runSelected(opt):
21 
22  mrd = MatrixReader(opt)
23  mrd.prepare(opt.useInput, opt.refRel, opt.fromScratch)
24 
25  # test for wrong input workflows
26  if opt.testList:
27  definedWf = [dwf.numId for dwf in mrd.workFlows]
28  definedSet = set(definedWf)
29  testSet = set(opt.testList)
30  undefSet = testSet - definedSet
31  if len(undefSet)>0: raise ValueError('Undefined workflows: '+', '.join(map(str,list(undefSet))))
32  duplicates = [wf for wf in testSet if definedWf.count(wf)>1 ]
33  if len(duplicates)>0: raise ValueError('Duplicated workflows: '+', '.join(map(str,list(duplicates))))
34 
35  ret = 0
36  if opt.show:
37  mrd.show(opt.testList, opt.extended, opt.cafVeto)
38  if opt.testList : print('testListected items:', opt.testList)
39  else:
40  mRunnerHi = MatrixRunner(mrd.workFlows, opt.nProcs, opt.nThreads)
41  ret = mRunnerHi.runTests(opt)
42 
43  if opt.wmcontrol:
44  if ret!=0:
45  print('Cannot go on with wmagent injection with failing workflows')
46  else:
47  wfInjector = MatrixInjector(opt,mode=opt.wmcontrol,options=opt.wmoptions)
48  ret= wfInjector.prepare(mrd,
49  mRunnerHi.runDirs)
50  if ret==0:
51  wfInjector.upload()
52  wfInjector.submit()
53  return ret
54 
55 # ================================================================================
56 
57 if __name__ == '__main__':
58 
59  #this can get out of here
60  predefinedSet={
61  'limited' : [5.1, #FastSim ttbar
62  7.3, #CosmicsSPLoose_UP17
63  8, #BH/Cosmic MC
64  25, #MC ttbar
65  4.22, #cosmic data
66  4.53, #run1 data + miniAOD
67  9.0, #Higgs200 charged taus
68  1000, #data+prompt
69  1001, #data+express
70  101.0, #SingleElectron120E120EHCAL
71  136.731, #2016B Photon data
72  136.7611, #2016E JetHT reMINIAOD from 80X legacy
73  136.8311, #2017F JetHT reMINIAOD from 94X reprocessing
74  136.88811,#2018D JetHT reMINIAOD from UL processing
75  136.793, #2017C DoubleEG
76  136.874, #2018C EGamma
77  138.4, #2021 MinimumBias prompt reco
78  138.5, #2021 MinimumBias express
79  139.001, #2021 MinimumBias offline with HLT step
80  140.53, #2011 HI data
81  140.56, #2018 HI data
82  158.01, #reMiniAOD of 2018 HI MC with pp-like reco
83  312.0, #2021/Run3 HI MC Pyquen_ZeemumuJets_pt10 with pp-like reco
84  1306.0, #SingleMu Pt1 UP15
85  2500.4, #test NanoAOD from existing MINI
86  1330, #Run2 2015/2016 MC Zmm
87  135.4, #Run 2 2015/2016 Zee ttbar fastsim
88  10042.0, #2017 ZMM
89  10024.0, #2017 ttbar
90  10824.0, #2018 ttbar
91  2018.1, #2018 ttbar fastsim
92  11634.911, #2021 DD4hep ttbar reading geometry from XML
93  11634.914, #2021 DDD ttbar reading geometry from the DB
94  11634.0, #2021 ttbar (switching to DD4hep by default)
95  11834.0, #2021 ttbar PU
96  13234.0, #2021 ttbar fastsim
97  13434.0, #2021 ttbar PU fastsim
98  12434.0, #2023 ttbar
99  12434.7, #2023 ttbar mkFit
100  24834.0, #2026D98 ttbar (Phase-2 baseline)
101  24834.911, #2026D98 ttbar DD4hep XML
102  25034.999, #2026D98 ttbar premixing stage1+stage2, PU50
103  24896.0, #CE_E_Front_120um D98
104  24900.0, #CE_H_Coarse_Scint D98
105  23234.0, #2026D94 ttbar (exercise with HFNose)
106  25202.0, #2016 ttbar UP15 PU
107  250202.181, #2018 ttbar stage1 + stage2 premix
108  ],
109  'jetmc': [5.1, 13, 15, 25, 38, 39], #MC
110  'metmc' : [5.1, 15, 25, 37, 38, 39], #MC
111  'muonmc' : [5.1, 124.4, 124.5, 20, 21, 22, 23, 25, 30], #MC
112  }
113 
114 
115  import argparse
116  usage = 'usage: runTheMatrix.py --show -s '
117 
118  parser = argparse.ArgumentParser(usage,formatter_class=argparse.ArgumentDefaultsHelpFormatter)
119 
120  parser.add_argument('-b','--batchName',
121  help='relval batch: suffix to be appended to Campaign name',
122  dest='batchName',
123  default='')
124 
125  parser.add_argument('-m','--memoryOffset',
126  help='memory of the wf for single core',
127  dest='memoryOffset',
128  type=int,
129  default=3000)
130 
131  parser.add_argument('--addMemPerCore',
132  help='increase of memory per each n > 1 core: memory(n_core) = memoryOffset + (n_core-1) * memPerCore',
133  dest='memPerCore',
134  type=int,
135  default=1500)
136 
137  parser.add_argument('-j','--nproc',
138  help='number of processes. 0 Will use 4 processes, not execute anything but create the wfs',
139  dest='nProcs',
140  type=int,
141  default=4)
142 
143  parser.add_argument('-t','--nThreads',
144  help='number of threads per process to use in cmsRun.',
145  dest='nThreads',
146  type=int,
147  default=1)
148 
149  parser.add_argument('--nStreams',
150  help='number of streams to use in cmsRun.',
151  dest='nStreams',
152  type=int,
153  default=0)
154 
155  parser.add_argument('--nEvents',
156  help='number of events to process in cmsRun. If 0 will use the standard 10 events.',
157  dest='nEvents',
158  type=int,
159  default=0)
160 
161  parser.add_argument('--numberEventsInLuminosityBlock',
162  help='number of events in a luminosity block',
163  dest='numberEventsInLuminosityBlock',
164  type=int,
165  default=-1)
166 
167  parser.add_argument('-n','--showMatrix',
168  help='Only show the worflows. Use --ext to show more',
169  dest='show',
170  default=False,
171  action='store_true')
172 
173  parser.add_argument('-e','--extended',
174  help='Show details of workflows, used with --show',
175  dest='extended',
176  default=False,
177  action='store_true')
178 
179  parser.add_argument('-s','--selected',
180  help='Run a pre-defined selected matrix of wf. Deprecated, please use -l limited',
181  dest='restricted',
182  default=False,
183  action='store_true')
184 
185  parser.add_argument('-l','--list',
186  help='Comma separated list of workflow to be shown or ran. Possible keys are also '+str(predefinedSet.keys())+'. and wild card like muon, or mc',
187  dest='testList',
188  default=None)
189 
190  parser.add_argument('-f','--failed-from',
191  help='Provide a matrix report to specify the workflows to be run again. Augments the -l option if specified already',
192  dest='failed_from',
193  default=None)
194 
195  parser.add_argument('-r','--raw',
196  help='Temporary dump the .txt needed for prodAgent interface. To be discontinued soon. Argument must be the name of the set (standard, pileup,...)',
197  dest='raw')
198 
199  parser.add_argument('-i','--useInput',
200  help='Use recyling where available. Either all, or a comma separated list of wf number.',
201  dest='useInput',
202  type=lambda x: x.split(','),
203  default=None)
204 
205  parser.add_argument('-w','--what',
206  help='Specify the set to be used. Argument must be the name of a set (standard, pileup,...) or multiple sets separated by commas (--what standard,pileup )',
207  dest='what',
208  default='all')
209 
210  parser.add_argument('--step1',
211  help='Used with --raw. Limit the production to step1',
212  dest='step1Only',
213  default=False)
214 
215  parser.add_argument('--maxSteps',
216  help='Only run maximum on maxSteps. Used when we are only interested in first n steps.',
217  dest='maxSteps',
218  default=9999,
219  type=int)
220 
221  parser.add_argument('--fromScratch',
222  help='Comma separated list of wf to be run without recycling. all is not supported as default.',
223  dest='fromScratch',
224  type=lambda x: x.split(','),
225  default=None)
226 
227  parser.add_argument('--refRelease',
228  help='Allow to modify the recycling dataset version',
229  dest='refRel',
230  default=None)
231 
232  parser.add_argument('--wmcontrol',
233  help='Create the workflows for injection to WMAgent. In the WORKING. -wmcontrol init will create the the workflows, -wmcontrol test will dryRun a test, -wmcontrol submit will submit to wmagent',
234  choices=['init','test','submit','force'],
235  dest='wmcontrol',
236  default=None)
237 
238  parser.add_argument('--revertDqmio',
239  help='When submitting workflows to wmcontrol, force DQM outout to use pool and not DQMIO',
240  choices=['yes','no'],
241  dest='revertDqmio',
242  default='no')
243 
244  parser.add_argument('--optionswm',
245  help='Specify a few things for wm injection',
246  default='',
247  dest='wmoptions')
248 
249  parser.add_argument('--keep',
250  help='allow to specify for which comma separated steps the output is needed',
251  default=None)
252 
253  parser.add_argument('--label',
254  help='allow to give a special label to the output dataset name',
255  default='')
256 
257  parser.add_argument('--command',
258  help='provide a way to add additional command to all of the cmsDriver commands in the matrix',
259  dest='command',
260  action='append',
261  default=None)
262 
263  parser.add_argument('--apply',
264  help='allow to use the --command only for 1 comma separeated',
265  dest='apply',
266  default=None)
267 
268  parser.add_argument('--workflow',
269  help='define a workflow to be created or altered from the matrix',
270  action='append',
271  dest='workflow',
272  default=None)
273 
274  parser.add_argument('--dryRun',
275  help='do not run the wf at all',
276  action='store_true',
277  dest='dryRun',
278  default=False)
279 
280  parser.add_argument('--testbed',
281  help='workflow injection to cmswebtest (you need dedicated rqmgr account)',
282  dest='testbed',
283  default=False,
284  action='store_true')
285 
286  parser.add_argument('--noCafVeto',
287  help='Run from any source, ignoring the CAF label',
288  dest='cafVeto',
289  default=True,
290  action='store_false')
291 
292  parser.add_argument('--overWrite',
293  help='Change the content of a step for another. List of pairs.',
294  dest='overWrite',
295  default=None)
296 
297  parser.add_argument('--noRun',
298  help='Remove all run list selection from wfs',
299  dest='noRun',
300  default=False,
301  action='store_true')
302 
303  parser.add_argument('--das-options',
304  help='Options to be passed to dasgoclient.',
305  dest='dasOptions',
306  default="--limit 0",
307  action='store')
308 
309  parser.add_argument('--job-reports',
310  help='Dump framework job reports',
311  dest='jobReports',
312  default=False,
313  action='store_true')
314 
315  parser.add_argument('--ibeos',
316  help='Use IB EOS site configuration',
317  dest='IBEos',
318  default=False,
319  action='store_true')
320 
321  parser.add_argument('--sites',
322  help='Run DAS query to get data from a specific site. Set it to empty string to search all sites.',
323  dest='dasSites',
324  default='T2_CH_CERN',
325  action='store')
326 
327  parser.add_argument('--interactive',
328  help="Open the Matrix interactive shell",
329  action='store_true',
330  default=False)
331 
332  parser.add_argument('--dbs-url',
333  help='Overwrite DbsUrl value in JSON submitted to ReqMgr2',
334  dest='dbsUrl',
335  default=None,
336  action='store')
337 
338  gpugroup = parser.add_argument_group('GPU-related options','These options are only meaningful when --gpu is used, and is not set to forbidden.')
339 
340  gpugroup.add_argument('--gpu','--requires-gpu',
341  help='Enable GPU workflows. Possible options are "forbidden" (default), "required" (implied if no argument is given), or "optional".',
342  dest='gpu',
343  choices=['forbidden', 'optional', 'required'],
344  nargs='?',
345  const='required',
346  default='forbidden',
347  action='store')
348 
349  gpugroup.add_argument('--gpu-memory',
350  help='Specify the minimum amount of GPU memory required by the job, in MB.',
351  dest='GPUMemoryMB',
352  type=int,
353  default=8000)
354 
355  gpugroup.add_argument('--cuda-capabilities',
356  help='Specify a comma-separated list of CUDA "compute capabilities", or GPU hardware architectures, that the job can use.',
357  dest='CUDACapabilities',
358  type=lambda x: x.split(','),
359  default='6.0,6.1,6.2,7.0,7.2,7.5,8.0,8.6')
360 
361  # read the CUDA runtime version included in CMSSW
362  cudart_version = None
363  libcudart = os.path.realpath(os.path.expandvars('$CMSSW_RELEASE_BASE/external/$SCRAM_ARCH/lib/libcudart.so'))
364  if os.path.isfile(libcudart):
365  cudart_basename = os.path.basename(libcudart)
366  cudart_version = '.'.join(cudart_basename.split('.')[2:4])
367  gpugroup.add_argument('--cuda-runtime',
368  help='Specify major and minor version of the CUDA runtime used to build the application.',
369  dest='CUDARuntime',
370  default=cudart_version)
371 
372  gpugroup.add_argument('--force-gpu-name',
373  help='Request a specific GPU model, e.g. "Tesla T4" or "NVIDIA GeForce RTX 2080". The default behaviour is to accept any supported GPU.',
374  dest='GPUName',
375  default='')
376 
377  gpugroup.add_argument('--force-cuda-driver-version',
378  help='Request a specific CUDA driver version, e.g. 470.57.02. The default behaviour is to accept any supported CUDA driver version.',
379  dest='CUDADriverVersion',
380  default='')
381 
382  gpugroup.add_argument('--force-cuda-runtime-version',
383  help='Request a specific CUDA runtime version, e.g. 11.4. The default behaviour is to accept any supported CUDA runtime version.',
384  dest='CUDARuntimeVersion',
385  default='')
386 
387  opt = parser.parse_args()
388  if opt.command: opt.command = ' '.join(opt.command)
389  os.environ["CMSSW_DAS_QUERY_SITES"]=opt.dasSites
390  if opt.failed_from:
391  rerunthese=[]
392  with open(opt.failed_from,'r') as report:
393  for report_line in report:
394  if 'FAILED' in report_line:
395  to_run,_=report_line.split('_',1)
396  rerunthese.append(to_run)
397  if opt.testList:
398  opt.testList+=','.join(['']+rerunthese)
399  else:
400  opt.testList = ','.join(rerunthese)
401 
402  if opt.IBEos:
403  from subprocess import getstatusoutput as run_cmd
404 
405  ibeos_cache = os.path.join(os.getenv("LOCALRT"), "ibeos_cache.txt")
406  if not os.path.exists(ibeos_cache):
407  err, out = run_cmd("curl -L -s -o %s https://raw.githubusercontent.com/cms-sw/cms-sw.github.io/master/das_queries/ibeos.txt" % ibeos_cache)
408  if err:
409  run_cmd("rm -f %s" % ibeos_cache)
410  print("Error: Unable to download ibeos cache information")
411  print(out)
412  sys.exit(err)
413 
414  for cmssw_env in [ "CMSSW_BASE", "CMSSW_RELEASE_BASE" ]:
415  cmssw_base = os.getenv(cmssw_env,None)
416  if not cmssw_base: continue
417  cmssw_base = os.path.join(cmssw_base,"src/Utilities/General/ibeos")
418  if os.path.exists(cmssw_base):
419  os.environ["PATH"]=cmssw_base+":"+os.getenv("PATH")
420  os.environ["CMS_PATH"]="/cvmfs/cms-ib.cern.ch"
421  os.environ["SITECONFIG_PATH"]="/cvmfs/cms-ib.cern.ch/SITECONF/local"
422  os.environ["CMSSW_USE_IBEOS"]="true"
423  print(">> WARNING: You are using SITECONF from /cvmfs/cms-ib.cern.ch")
424  break
425  if opt.restricted:
426  print('Deprecated, please use -l limited')
427  if opt.testList: opt.testList+=',limited'
428  else: opt.testList='limited'
429 
430  def stepOrIndex(s):
431  if s.isdigit():
432  return int(s)
433  else:
434  return s
435  if opt.apply:
436  opt.apply=map(stepOrIndex,opt.apply.split(','))
437  if opt.keep:
438  opt.keep=map(stepOrIndex,opt.keep.split(','))
439 
440  if opt.testList:
441  testList=[]
442  for entry in opt.testList.split(','):
443  if not entry: continue
444  mapped=False
445  for k in predefinedSet:
446  if k.lower().startswith(entry.lower()) or k.lower().endswith(entry.lower()):
447  testList.extend(predefinedSet[k])
448  mapped=True
449  break
450  if not mapped:
451  try:
452  testList.append(float(entry))
453  except:
454  print(entry,'is not a possible selected entry')
455 
456  opt.testList = list(set(testList))
457 
458  if opt.wmcontrol:
460  if opt.overWrite:
461  opt.overWrite=eval(opt.overWrite)
462  if opt.interactive:
463  import cmd
464  from colorama import Fore, Style
465  from os import isatty
466 
467  class TheMatrix(cmd.Cmd):
468  intro = "Welcome to the Matrix (? for help)"
469  prompt = "matrix> "
470 
471  def __init__(self, opt):
472  cmd.Cmd.__init__(self)
473  self.opt_ = opt
474  self.matrices_ = {}
475  tmp = MatrixReader(self.opt_)
476  for what in tmp.files:
477  what = what.replace('relval_','')
478  self.opt_.what = what
479  self.matrices_[what] = MatrixReader(self.opt_)
480  self.matrices_[what].prepare(self.opt_.useInput, self.opt_.refRel,
481  self.opt_.fromScratch)
482  os.system("clear")
483 
484  def do_clear(self, arg):
485  """Clear the screen, put prompt at the top"""
486  os.system("clear")
487 
488  def do_exit(self, arg):
489  print("Leaving the Matrix")
490  return True
491 
492  def default(self, inp):
493  if inp == 'x' or inp == 'q':
494  return self.do_exit(inp)
495  else:
496  is_pipe = not isatty(sys.stdin.fileno())
497  print(Fore.RED + "Error: " + Fore.RESET + "unrecognized command.")
498  # Quit only if given a piped command.
499  if is_pipe:
500  sys.exit(1)
501 
502  def help_predefined(self):
503  print("\n".join(["predefined [predef1 [...]]\n",
504  "Run w/o argument, it will print the list of known predefined workflows.",
505  "Run with space-separated predefined workflows, it will print the workflow-ids registered to them"]))
506 
507  def complete_predefined(self, text, line, start_idx, end_idx):
508  if text and len(text) > 0:
509  return [t for t in predefinedSet.keys() if t.startswith(text)]
510  else:
511  return predefinedSet.keys()
512 
513  def do_predefined(self, arg):
514  """Print the list of predefined workflows"""
515  print("List of predefined workflows")
516  if arg:
517  for w in arg.split():
518  if w in predefinedSet.keys():
519  print("Predefined Set: %s" % w)
520  print(predefinedSet[w])
521  else:
522  print("Unknown Set: %s" % w)
523  else:
524  print("[ " + Fore.RED + ", ".join([str(k) for k in predefinedSet.keys()]) + Fore.RESET + " ]")
525 
526  def help_showWorkflow(self):
527  print("\n".join(["showWorkflow [workflow1 [...]]\n",
528  "Run w/o arguments, it will print the list of registered macro-workflows.",
529  "Run with space-separated workflows, it will print the full list of workflow-ids registered to them"]))
530 
531  def complete_showWorkflow(self, text, line, start_idx, end_idx):
532  if text and len(text) > 0:
533  return [t for t in self.matrices_.keys() if t.startswith(text)]
534  else:
535  return self.matrices_.keys()
536 
537  def do_showWorkflow(self, arg):
538  if arg == '':
539  print("Available workflows:")
540  for k in self.matrices_.keys():
541  print(Fore.RED + Style.BRIGHT + k)
542  print(Style.RESET_ALL)
543  else:
544  selected = arg.split()
545  for k in selected:
546  if k not in self.matrices_.keys():
547  print("Unknown workflow %s: skipping" % k)
548  else:
549  for wfl in self.matrices_[k].workFlows:
550  print("%s %s" % (Fore.BLUE + str(wfl.numId) + Fore.RESET,
551  Fore.GREEN + wfl.nameId + Fore.RESET))
552  print("%s contains %d workflows" % (Fore.RED + k + Fore.RESET, len(self.matrices_[k].workFlows)))
553 
555  print("\n".join(["searchInWorkflow wfl_name search_regexp\n",
556  "This command will search for a match within all workflows registered to wfl_name.",
557  "The search is done on both the workflow name and the names of steps registered to it."]))
558 
559  def complete_searchInWorkflow(self, text, line, start_idx, end_idx):
560  if text and len(text) > 0:
561  return [t for t in self.matrices_.keys() if t.startswith(text)]
562  else:
563  return self.matrices_.keys()
564 
565  def do_searchInWorkflow(self, arg):
566  args = arg.split()
567  if len(args) < 2:
568  print("searchInWorkflow name regexp")
569  return
570  if args[0] not in self.matrices_.keys():
571  print("Unknown workflow")
572  return
573  import re
574  pattern = None
575  try:
576  pattern = re.compile(args[1])
577  except:
578  print("Failed to compile regexp %s" % args[1])
579  return
580  counter = 0
581  for wfl in self.matrices_[args[0]].workFlows:
582  if re.match(pattern, wfl.nameId):
583  print("%s %s" % (Fore.BLUE + str(wfl.numId) + Fore.RESET,
584  Fore.GREEN + wfl.nameId + Fore.RESET))
585  counter +=1
586  print("Found %s compatible workflows inside %s" % (Fore.RED + str(counter) + Fore.RESET,
587  Fore.YELLOW + str(args[0])) + Fore.RESET)
588 
589  def help_search(self):
590  print("\n".join(["search search_regexp\n",
591  "This command will search for a match within all workflows registered.",
592  "The search is done on both the workflow name and the names of steps registered to it."]))
593 
594  def do_search(self, arg):
595  args = arg.split()
596  if len(args) < 1:
597  print("search regexp")
598  return
599  for wfl in self.matrices_.keys():
600  self.do_searchInWorkflow(' '.join([wfl, args[0]]))
601 
603  print("\n".join(["dumpWorkflowId [wfl-id1 [...]]\n",
604  "Dumps the details (cmsDriver commands for all steps) of the space-separated workflow-ids in input."]))
605 
606  def do_dumpWorkflowId(self, arg):
607  wflids = arg.split()
608  if len(wflids) == 0:
609  print("dumpWorkflowId [wfl-id1 [...]]")
610  return
611 
612  fmt = "[%s]: %s\n"
613  maxLen = 100
614  for wflid in wflids:
615  dump = True
616  for key, mrd in self.matrices_.items():
617  for wfl in mrd.workFlows:
618  if wfl.numId == float(wflid):
619  if dump:
620  dump = False
621  print(Fore.GREEN + str(wfl.numId) + Fore.RESET + " " + Fore.YELLOW + wfl.nameId + Fore.RESET)
622  for i,s in enumerate(wfl.cmds):
623  print(fmt % (Fore.RED + str(i+1) + Fore.RESET,
624  (str(s)+' ')))
625  print("\nWorkflow found in %s." % key)
626  else:
627  print("Workflow also found in %s." % key)
628 
629  do_EOF = do_exit
630 
631  TheMatrix(opt).cmdloop()
632  sys.exit(0)
633 
634  if opt.raw and opt.show:
635  ret = showRaw(opt)
636  else:
637  ret = runSelected(opt)
638 
639 
640  sys.exit(ret)
def performInjectionOptionTest(opt)
def runSelected(opt)
Definition: runTheMatrix.py:20
def do_predefined(self, arg)
def do_showWorkflow(self, arg)
def complete_showWorkflow(self, text, line, start_idx, end_idx)
def do_search(self, arg)
def showRaw(opt)
Definition: runTheMatrix.py:11
def do_clear(self, arg)
def help_dumpWorkflowId(self)
def complete_predefined(self, text, line, start_idx, end_idx)
def help_searchInWorkflow(self)
def do_dumpWorkflowId(self, arg)
void print(TMatrixD &m, const char *label=nullptr, bool mathematicaFormat=false)
Definition: Utilities.cc:47
def __init__(self, opt)
static std::string join(char **cmd)
Definition: RemoteFile.cc:19
def do_exit(self, arg)
def default(self, inp)
def complete_searchInWorkflow(self, text, line, start_idx, end_idx)
def stepOrIndex(s)
#define str(s)
def do_searchInWorkflow(self, arg)