Logo ROOT  
Reference Guide
Loading...
Searching...
No Matches
cmdLineUtils.py
Go to the documentation of this file.
1#!/usr/bin/env @python@
2
3# ROOT command line tools module: cmdLineUtils
4# Author: Julien Ripoche
5# Mail: julien.ripoche@u-psud.fr
6# Date: 20/08/15
7
8"""Contain utils for ROOT command line tools"""
9
10##########
11# Stream redirect functions
12# The original code of the these functions can be found here :
13# http://stackoverflow.com/questions/4675728/redirect-stdout-to-a-file-in-python/22434262#22434262
14# Thanks J.F. Sebastian !!
15
16from contextlib import contextmanager
17import os
18import sys
19from time import sleep
20from itertools import zip_longest
21
22def fileno(file_or_fd):
23 """
24 Look for 'fileno' attribute.
25 """
26 fd = getattr(file_or_fd, "fileno", lambda: file_or_fd)()
27 if not isinstance(fd, int):
28 raise ValueError("Expected a file (`.fileno()`) or a file descriptor")
29 return fd
30
31
32@contextmanager
33def streamRedirected(source=sys.stdout, destination=os.devnull):
34 """
35 Redirect the output from source to destination.
36 """
37 stdout_fd = fileno(source)
38 # copy stdout_fd before it is overwritten
39 # NOTE: `copied` is inheritable on Windows when duplicating a standard stream
40 with os.fdopen(os.dup(stdout_fd), "wb") as copied:
41 source.flush() # flush library buffers that dup2 knows nothing about
42 try:
43 os.dup2(fileno(destination), stdout_fd) # $ exec >&destination
44 except ValueError: # filename
45 with open(destination, "wb") as destination_file:
46 os.dup2(destination_file.fileno(), stdout_fd) # $ exec > destination
47 try:
48 yield source # allow code to be run with the redirected stream
49 finally:
50 # restore source to its previous value
51 # NOTE: dup2 makes stdout_fd inheritable unconditionally
52 source.flush()
53 os.dup2(copied.fileno(), stdout_fd) # $ exec >&copied
54
55
57 """
58 Redirect the output from sys.stdout to os.devnull.
59 """
60 return streamRedirected(sys.stdout, os.devnull)
61
62
64 """
65 Redirect the output from sys.stderr to os.devnull.
66 """
67 return streamRedirected(sys.stderr, os.devnull)
68
69
70# The end of streamRedirected functions
71##########
72
73##########
74# Imports
75
76##
77# redirect output (escape characters during ROOT importation...)
78with stdoutRedirected():
79 import ROOT
80# Silence Davix warning (see ROOT-7577)
81ROOT.PyConfig.IgnoreCommandLineOptions = True
82ROOT.gROOT.GetVersion()
83
84import argparse
85import glob
86import fnmatch
87import logging
88
89LOG_FORMAT = "%(levelname)s: %(message)s"
90logging.basicConfig(format=LOG_FORMAT)
91
92# The end of imports
93##########
94
95##########
96# Different functions to get a parser of arguments and options
97
98
99def _getParser(theHelp, theEpilog):
100 """
101 Get a commandline parser with the defaults of the commandline utils.
102 """
103 return argparse.ArgumentParser(
104 description=theHelp, formatter_class=argparse.RawDescriptionHelpFormatter, epilog=theEpilog
105 )
106
107
108def getParserSingleFile(theHelp, theEpilog=""):
109 """
110 Get a commandline parser with the defaults of the commandline utils and a
111 source file or not.
112 """
113 parser = _getParser(theHelp, theEpilog)
114 parser.add_argument("FILE", nargs="?", help="Input file")
115 return parser
116
117
118def getParserFile(theHelp, theEpilog=""):
119 """
120 Get a commandline parser with the defaults of the commandline utils and a
121 list of source files.
122 """
123 parser = _getParser(theHelp, theEpilog)
124 parser.add_argument("FILE", nargs="+", help="Input file")
125 return parser
126
127
128def getParserSourceDest(theHelp, theEpilog=""):
129 """
130 Get a commandline parser with the defaults of the commandline utils,
131 a list of source files and a destination file.
132 """
133 parser = _getParser(theHelp, theEpilog)
134 parser.add_argument("SOURCE", nargs="+", help="Source file")
135 parser.add_argument("DEST", help="Destination file")
136 return parser
137
138
139# The end of get parser functions
140##########
141
142##########
143# Several utils
144
145
146@contextmanager
148 originalLevel = ROOT.gErrorIgnoreLevel
149 ROOT.gErrorIgnoreLevel = level
150 yield
151 ROOT.gErrorIgnoreLevel = originalLevel
152
153
154def changeDirectory(rootFile, pathSplit):
155 """
156 Change the current directory (ROOT.gDirectory) by the corresponding (rootFile,pathSplit)
157 """
158 rootFile.cd()
159 for directoryName in pathSplit:
160 theDir = ROOT.gDirectory.Get(directoryName)
161 if not theDir:
162 logging.warning("Directory %s does not exist." % directoryName)
163 return 1
164 else:
165 theDir.cd()
166 return 0
167
168
169def createDirectory(rootFile, pathSplit):
170 """
171 Add a directory named 'pathSplit[-1]' in (rootFile,pathSplit[:-1])
172 """
173 retcode = changeDirectory(rootFile, pathSplit[:-1])
174 if retcode == 0:
175 ROOT.gDirectory.mkdir(pathSplit[-1])
176 return retcode
177
178
179def getFromDirectory(objName):
180 """
181 Get the object objName from the current directory
182 """
183 return ROOT.gDirectory.Get(objName)
184
185
186def isExisting(rootFile, pathSplit):
187 """
188 Return True if the object, corresponding to (rootFile,pathSplit), exits
189 """
190 changeDirectory(rootFile, pathSplit[:-1])
191 return ROOT.gDirectory.GetListOfKeys().Contains(pathSplit[-1])
192
193
195 """
196 Return True if the object, corresponding to the key, inherits from TDirectory
197 """
198 classname = key.GetClassName()
199 cl = ROOT.gROOT.GetClass(classname)
200 if not cl:
201 logging.warning("Unknown class to ROOT: " + classname)
202 return False
203 return cl.InheritsFrom(ROOT.TDirectory.Class())
204
205
206def isTreeKey(key):
207 """
208 Return True if the object, corresponding to the key, inherits from TTree
209 """
210 classname = key.GetClassName()
211 cl = ROOT.gROOT.GetClass(classname)
212 if not cl:
213 logging.warning("Unknown class to ROOT: " + classname)
214 return False
215 return cl.InheritsFrom(ROOT.TTree.Class())
216
217
219 """
220 Return True if the object, corresponding to the key, inherits from THnSparse
221 """
222 classname = key.GetClassName()
223 cl = ROOT.gROOT.GetClass(classname)
224 if not cl:
225 logging.warning("Unknown class to ROOT: " + classname)
226 return False
227 return cl.InheritsFrom(ROOT.THnSparse.Class())
228
229
230def getKey(rootFile, pathSplit):
231 """
232 Get the key of the corresponding object (rootFile,pathSplit)
233 """
234 changeDirectory(rootFile, pathSplit[:-1])
235 return ROOT.gDirectory.GetKey(pathSplit[-1])
236
237
238def isDirectory(rootFile, pathSplit):
239 """
240 Return True if the object, corresponding to (rootFile,pathSplit), inherits from TDirectory
241 """
242 if pathSplit == []:
243 return True # the object is the rootFile itself
244 else:
245 return isDirectoryKey(getKey(rootFile, pathSplit))
246
247
248def isTree(rootFile, pathSplit):
249 """
250 Return True if the object, corresponding to (rootFile,pathSplit), inherits from TTree
251 """
252 if pathSplit == []:
253 return False # the object is the rootFile itself
254 else:
255 return isTreeKey(getKey(rootFile, pathSplit))
256
257
258def getKeyList(rootFile, pathSplit):
259 """
260 Get the list of keys of the directory (rootFile,pathSplit),
261 if (rootFile,pathSplit) is not a directory then get the key in a list
262 """
263 if isDirectory(rootFile, pathSplit):
264 changeDirectory(rootFile, pathSplit)
265 return ROOT.gDirectory.GetListOfKeys()
266 else:
267 return [getKey(rootFile, pathSplit)]
268
269
270def keyListSort(keyList):
271 """
272 Sort list of keys by their names ignoring the case
273 """
274 keyList.sort(key=lambda x: x.GetName().lower())
275
276
277def tupleListSort(tupleList):
278 """
279 Sort list of tuples by their first elements ignoring the case
280 """
281 tupleList.sort(key=lambda x: x[0].lower())
282
283
284def dirListSort(dirList):
285 """
286 Sort list of directories by their names ignoring the case
287 """
288 dirList.sort(key=lambda x: [n.lower() for n in x])
289
290
291def keyClassSplitter(rootFile, pathSplitList):
292 """
293 Return a list of directories and a list of keys corresponding
294 to the other objects, for rootls and rootprint use
295 """
296 keyList = []
297 dirList = []
298 for pathSplit in pathSplitList:
299 if pathSplit == []:
300 dirList.append(pathSplit)
301 elif isDirectory(rootFile, pathSplit):
302 dirList.append(pathSplit)
303 else:
304 keyList.append(getKey(rootFile, pathSplit))
305 keyListSort(keyList)
306 dirListSort(dirList)
307 return keyList, dirList
308
309
310def openROOTFile(fileName, mode="read"):
311 """
312 Open the ROOT file corresponding to fileName in the corresponding mode,
313 redirecting the output not to see missing dictionnaries
314
315 Returns:
316 theFile (TFile)
317 """
318 # with stderrRedirected():
319 with _setIgnoreLevel(ROOT.kError):
320 theFile = ROOT.TFile.Open(fileName, mode)
321 if not theFile:
322 logging.warning("File %s does not exist", fileName)
323 return theFile
324
325
326def openROOTFileCompress(fileName, compress, recreate):
327 """
328 Open a ROOT file (like openROOTFile) with the possibility
329 to change compression settings
330 """
331 if compress != None and os.path.isfile(fileName):
332 logging.warning("can't change compression settings on existing file")
333 return None
334 mode = "recreate" if recreate else "update"
335 theFile = openROOTFile(fileName, mode)
336 if compress != None:
337 theFile.SetCompressionSettings(compress)
338 return theFile
339
340
341def joinPathSplit(pathSplit):
342 """
343 Join the pathSplit with '/'
344 """
345 return "/".join(pathSplit)
346
347
348MANY_OCCURENCE_WARNING = "Several versions of '{0}' are present in '{1}'. Only the most recent will be considered."
349
350
351def manyOccurenceRemove(pathSplitList, fileName):
352 """
353 Search for double occurence of the same pathSplit and remove them
354 """
355 if len(pathSplitList) > 1:
356 for n in pathSplitList:
357 if pathSplitList.count(n) != 1:
358 logging.warning(MANY_OCCURENCE_WARNING.format(joinPathSplit(n), fileName))
359 while n in pathSplitList and pathSplitList.count(n) != 1:
360 pathSplitList.remove(n)
361
362
363def patternToPathSplitList(fileName, pattern):
364 """
365 Get the list of pathSplit of objects in the ROOT file
366 corresponding to fileName that match with the pattern
367 """
368 # Open ROOT file
369 rootFile = openROOTFile(fileName)
370 if not rootFile:
371 return []
372
373 # Split pattern avoiding multiple slash problem
374 patternSplit = [n for n in pattern.split("/") if n != ""]
375
376 # Main loop
377 pathSplitList = [[]]
378 for patternPiece in patternSplit:
379 newPathSplitList = []
380 for pathSplit in pathSplitList:
381 if isDirectory(rootFile, pathSplit):
382 changeDirectory(rootFile, pathSplit)
383 newPathSplitList.extend(
384 [
385 pathSplit + [key.GetName()]
386 for key in ROOT.gDirectory.GetListOfKeys()
387 if fnmatch.fnmatch(key.GetName(), patternPiece)
388 ]
389 )
390 pathSplitList = newPathSplitList
391
392 # No match
393 if pathSplitList == []:
394 logging.warning("can't find {0} in {1}".format(pattern, fileName))
395
396 # Same match (remove double occurrences from the list)
397 manyOccurenceRemove(pathSplitList, fileName)
398
399 return pathSplitList
400
401
402def fileNameListMatch(filePattern, wildcards):
403 """
404 Get the list of fileName that match with objPattern
405 """
406 if wildcards:
407 return [os.path.expandvars(os.path.expanduser(i)) for i in glob.iglob(filePattern)]
408 else:
409 return [os.path.expandvars(os.path.expanduser(filePattern))]
410
411
412def pathSplitListMatch(fileName, objPattern, wildcards):
413 """
414 Get the list of pathSplit that match with objPattern
415 """
416 if wildcards:
417 return patternToPathSplitList(fileName, objPattern)
418 else:
419 return [[n for n in objPattern.split("/") if n != ""]]
420
421
422def patternToFileNameAndPathSplitList(pattern, wildcards=True):
423 """
424 Get the list of tuple containing both :
425 - ROOT file name
426 - list of splited path (in the corresponding file) of objects that matche
427 Use unix wildcards by default
428 """
429 rootFilePattern = "*.root"
430 rootObjPattern = rootFilePattern + ":*"
431 httpRootFilePattern = "htt*://*.root"
432 httpRootObjPattern = httpRootFilePattern + ":*"
433 xrootdRootFilePattern = "root://*.root"
434 xrootdRootObjPattern = xrootdRootFilePattern + ":*"
435 s3RootFilePattern = "s3://*.root"
436 s3RootObjPattern = s3RootFilePattern + ":*"
437 gsRootFilePattern = "gs://*.root"
438 gsRootObjPattern = gsRootFilePattern + ":*"
439 pcmFilePattern = "*.pcm"
440 pcmObjPattern = pcmFilePattern + ":*"
441
442 if (
443 fnmatch.fnmatch(pattern, httpRootObjPattern)
444 or fnmatch.fnmatch(pattern, xrootdRootObjPattern)
445 or fnmatch.fnmatch(pattern, s3RootObjPattern)
446 or fnmatch.fnmatch(pattern, gsRootObjPattern)
447 ):
448 patternSplit = pattern.rsplit(":", 1)
449 fileName = patternSplit[0]
450 objPattern = patternSplit[1]
451 pathSplitList = pathSplitListMatch(fileName, objPattern, wildcards)
452 return [(fileName, pathSplitList)]
453
454 if (
455 fnmatch.fnmatch(pattern, httpRootFilePattern)
456 or fnmatch.fnmatch(pattern, xrootdRootFilePattern)
457 or fnmatch.fnmatch(pattern, s3RootFilePattern)
458 or fnmatch.fnmatch(pattern, gsRootFilePattern)
459 ):
460 fileName = pattern
461 pathSplitList = [[]]
462 return [(fileName, pathSplitList)]
463
464 if fnmatch.fnmatch(pattern, rootObjPattern) or fnmatch.fnmatch(pattern, pcmObjPattern):
465 patternSplit = pattern.split(":")
466 filePattern = patternSplit[0]
467 objPattern = patternSplit[1]
468 fileNameList = fileNameListMatch(filePattern, wildcards)
469 return [(fileName, pathSplitListMatch(fileName, objPattern, wildcards)) for fileName in fileNameList]
470
471 if fnmatch.fnmatch(pattern, rootFilePattern) or fnmatch.fnmatch(pattern, pcmFilePattern):
472 filePattern = pattern
473 fileNameList = fileNameListMatch(filePattern, wildcards)
474 pathSplitList = [[]]
475 return [(fileName, pathSplitList) for fileName in fileNameList]
476
477 logging.warning("{0}: No such file (or extension not supported)".format(pattern))
478 return []
479
480
481# End of utils
482##########
483
484##########
485# Set of functions to put the arguments in shape
486
487
488def getArgs(parser):
489 """
490 Get arguments corresponding to parser.
491 """
492 return parser.parse_args()
493
494
495def getSourceListArgs(parser, wildcards=True):
496 """
497 Create a list of tuples that contain source ROOT file names
498 and lists of path in these files as well as the original arguments
499 """
500 args = getArgs(parser)
501 inputFiles = []
502 try:
503 inputFiles = args.FILE
504 except:
505 inputFiles = args.SOURCE
506 sourceList = [tup for pattern in inputFiles for tup in patternToFileNameAndPathSplitList(pattern, wildcards)]
507 return sourceList, args
508
509
510def getSourceListOptDict(parser, wildcards=True):
511 """
512 Get the list of tuples and the dictionary with options
513
514 returns:
515 sourceList: a list of tuples with one list element per file
516 the first tuple entry being the root file,
517 the second a list of subdirectories,
518 each being represented as a list itself with a string per level
519 e.g.
520 rootls tutorial/tmva/TMVA.root:Method_BDT/BDT turns into
521 [('tutorials/tmva/TMVA.root', [['Method_BDT','BDT']])]
522 vars(args): a dictionary of matched options, e.g.
523 {'longListing': False,
524 'oneColumn': False,
525 'treeListing': False,
526 'recursiveListing'; False,
527 'FILE': ['tutorials/tmva/TMVA.root:Method_BDT/BDT']
528 }
529 """
530 sourceList, args = getSourceListArgs(parser, wildcards)
531 if sourceList == []:
532 logging.error("Input file(s) not found!")
533 return sourceList, vars(args)
534
535
536def getSourceDestListOptDict(parser, wildcards=True):
537 """
538 Get the list of tuples of sources, create destination name, destination pathSplit
539 and the dictionary with options
540 """
541 sourceList, args = getSourceListArgs(parser, wildcards)
542 destList = patternToFileNameAndPathSplitList(args.DEST, wildcards=False)
543 if destList != []:
544 destFileName, destPathSplitList = destList[0]
545 destPathSplit = destPathSplitList[0]
546 else:
547 destFileName = ""
548 destPathSplit = []
549 return sourceList, destFileName, destPathSplit, vars(args)
550
551
552# The end of the set of functions to put the arguments in shape
553##########
554
555##########
556# Several functions shared by rootcp, rootmv and rootrm
557
558TARGET_ERROR = "target '{0}' is not a directory"
559OMITTING_ERROR = "{0} '{1}' will be copied but not its subdirectories (if any). Use the -r option if you need a recursive copy."
560OVERWRITE_ERROR = "cannot overwrite non-directory '{0}' with directory '{1}'"
561
562
563def copyRootObject(sourceFile, sourcePathSplit, destFile, destPathSplit, oneSource, recursive, replace):
564 """
565 Initialize the recursive function 'copyRootObjectRecursive', written to be as unix-like as possible
566 """
567 retcode = 0
568 isMultipleInput = not (oneSource and sourcePathSplit != [])
569 recursiveOption = recursive
570 # Multiple input and un-existing or non-directory destination
571 # TARGET_ERROR
572 if (
573 isMultipleInput
574 and destPathSplit != []
575 and not (isExisting(destFile, destPathSplit) and isDirectory(destFile, destPathSplit))
576 ):
577 logging.warning(TARGET_ERROR.format(destPathSplit[-1]))
578 retcode += 1
579 # Entire ROOT file or directory in input omitting "-r" option
580 if not recursiveOption:
581 if sourcePathSplit == []:
582 logging.warning(OMITTING_ERROR.format("file", sourceFile.GetName()))
583 retcode += 1
584 elif isDirectory(sourceFile, sourcePathSplit):
585 logging.warning(OMITTING_ERROR.format("directory", sourcePathSplit[-1]))
586 retcode += 1
587 # Run copyRootObjectRecursive function with the wish
588 # to follow the unix copy behaviour
589 if sourcePathSplit == []:
590 retcode += copyRootObjectRecursive(sourceFile, sourcePathSplit, destFile, destPathSplit, replace)
591 else:
592 setName = ""
593 if not isMultipleInput and (destPathSplit != [] and not isExisting(destFile, destPathSplit)):
594 setName = destPathSplit[-1]
595 objectName = sourcePathSplit[-1]
596 if isDirectory(sourceFile, sourcePathSplit):
597 if setName != "":
598 createDirectory(destFile, destPathSplit[:-1] + [setName])
599 retcode += copyRootObjectRecursive(
600 sourceFile, sourcePathSplit, destFile, destPathSplit[:-1] + [setName], replace
601 )
602 elif isDirectory(destFile, destPathSplit):
603 if not isExisting(destFile, destPathSplit + [objectName]):
604 createDirectory(destFile, destPathSplit + [objectName])
605 if isDirectory(destFile, destPathSplit + [objectName]):
606 retcode += copyRootObjectRecursive(
607 sourceFile, sourcePathSplit, destFile, destPathSplit + [objectName], replace
608 )
609 else:
610 logging.warning(OVERWRITE_ERROR.format(objectName, objectName))
611 retcode += 1
612 else:
613 logging.warning(OVERWRITE_ERROR.format(destPathSplit[-1], objectName))
614 retcode += 1
615 else:
616 if setName != "":
617 retcode += copyRootObjectRecursive(
618 sourceFile, sourcePathSplit, destFile, destPathSplit[:-1], replace, setName
619 )
620 elif isDirectory(destFile, destPathSplit):
621 retcode += copyRootObjectRecursive(sourceFile, sourcePathSplit, destFile, destPathSplit, replace)
622 else:
623 setName = destPathSplit[-1]
624 retcode += copyRootObjectRecursive(
625 sourceFile, sourcePathSplit, destFile, destPathSplit[:-1], replace, setName
626 )
627 return retcode
628
629
630DELETE_ERROR = "object {0} was not existing, so it is not deleted"
631
632
633def deleteObject(rootFile, pathSplit):
634 """
635 Delete the object 'pathSplit[-1]' from (rootFile,pathSplit[:-1])
636 """
637 retcode = changeDirectory(rootFile, pathSplit[:-1])
638 if retcode == 0:
639 fileName = pathSplit[-1]
640 if isExisting(rootFile, pathSplit):
641 ROOT.gDirectory.Delete(fileName + ";*")
642 else:
643 logging.warning(DELETE_ERROR.format(fileName))
644 retcode += 1
645 return retcode
646
647
648def copyRootObjectRecursive(sourceFile, sourcePathSplit, destFile, destPathSplit, replace, setName=""):
649 """
650 Copy objects from a file or directory (sourceFile,sourcePathSplit)
651 to an other file or directory (destFile,destPathSplit)
652 - Has the will to be unix-like
653 - that's a recursive function
654 - Python adaptation of a root input/output tutorial : copyFiles.C
655 """
656 retcode = 0
657 replaceOption = replace
658 seen = {}
659 for key in getKeyList(sourceFile, sourcePathSplit):
660 objectName = key.GetName()
661
662 # write keys only if the cycle is higher than before
663 if objectName not in seen.keys():
664 seen[objectName] = key
665 else:
666 if seen[objectName].GetCycle() < key.GetCycle():
667 seen[objectName] = key
668 else:
669 continue
670
671 if isDirectoryKey(key):
672 if not isExisting(destFile, destPathSplit + [objectName]):
673 createDirectory(destFile, destPathSplit + [objectName])
674 if isDirectory(destFile, destPathSplit + [objectName]):
675 retcode += copyRootObjectRecursive(
676 sourceFile, sourcePathSplit + [objectName], destFile, destPathSplit + [objectName], replace
677 )
678 else:
679 logging.warning(OVERWRITE_ERROR.format(objectName, objectName))
680 retcode += 1
681 elif isTreeKey(key):
682 T = key.GetMotherDir().Get(objectName + ";" + str(key.GetCycle()))
683 if replaceOption and isExisting(destFile, destPathSplit + [T.GetName()]):
684 retcodeTemp = deleteObject(destFile, destPathSplit + [T.GetName()])
685 if retcodeTemp:
686 retcode += retcodeTemp
687 continue
688 changeDirectory(destFile, destPathSplit)
689 newT = T.CloneTree(-1, "fast")
690 if setName != "":
691 newT.SetName(setName)
692 newT.Write()
693 else:
694 obj = key.ReadObj()
695 if replaceOption and isExisting(destFile, destPathSplit + [setName]):
696 changeDirectory(destFile, destPathSplit)
697 otherObj = getFromDirectory(setName)
698 retcodeTemp = deleteObject(destFile, destPathSplit + [setName])
699 if retcodeTemp:
700 retcode += retcodeTemp
701 continue
702 else:
703 if isinstance(obj, ROOT.TNamed):
704 obj.SetName(setName)
705 changeDirectory(destFile, destPathSplit)
706 obj.Write()
707 elif issubclass(obj.__class__, ROOT.TCollection):
708 # probably the object was written with kSingleKey
709 changeDirectory(destFile, destPathSplit)
710 obj.Write(setName, ROOT.TObject.kSingleKey)
711 else:
712 if setName != "":
713 if isinstance(obj, ROOT.TNamed):
714 obj.SetName(setName)
715 else:
716 if isinstance(obj, ROOT.TNamed):
717 obj.SetName(objectName)
718 changeDirectory(destFile, destPathSplit)
719 obj.Write()
720 obj.Delete()
721 changeDirectory(destFile, destPathSplit)
722 ROOT.gDirectory.SaveSelf(ROOT.kTRUE)
723 return retcode
724
725
726FILE_REMOVE_ERROR = "cannot remove '{0}': Is a ROOT file"
727DIRECTORY_REMOVE_ERROR = "cannot remove '{0}': Is a directory"
728ASK_FILE_REMOVE = "remove '{0}' ? (y/n) : "
729ASK_OBJECT_REMOVE = "remove '{0}' from '{1}' ? (y/n) : "
730
731
732def deleteRootObject(rootFile, pathSplit, interactive, recursive):
733 """
734 Remove the object (rootFile,pathSplit)
735 -interactive : prompt before every removal
736 -recursive : allow directory, and ROOT file, removal
737 """
738 retcode = 0
739 if not recursive and isDirectory(rootFile, pathSplit):
740 if pathSplit == []:
741 logging.warning(FILE_REMOVE_ERROR.format(rootFile.GetName()))
742 retcode += 1
743 else:
744 logging.warning(DIRECTORY_REMOVE_ERROR.format(pathSplit[-1]))
745 retcode += 1
746 else:
747 if interactive:
748 if pathSplit != []:
749 answer = input(ASK_OBJECT_REMOVE.format("/".join(pathSplit), rootFile.GetName()))
750 else:
751 answer = input(ASK_FILE_REMOVE.format(rootFile.GetName()))
752 remove = answer.lower() == "y"
753 else:
754 remove = True
755 if remove:
756 if pathSplit != []:
757 retcode += deleteObject(rootFile, pathSplit)
758 else:
759 rootFile.Close()
760 os.remove(rootFile.GetName())
761 return retcode
762
763
764# End of functions shared by rootcp, rootmv and rootrm
765##########
766
767##########
768# Help strings for ROOT command line tools
769
770# Arguments
771SOURCE_HELP = "path of the source."
772SOURCES_HELP = "path of the source(s)."
773DEST_HELP = "path of the destination."
774
775# Options
776COMPRESS_HELP = """change the compression settings of the
777destination file (if not already existing)."""
778INTERACTIVE_HELP = "prompt before every removal."
779RECREATE_HELP = "recreate the destination file."
780RECURSIVE_HELP = "recurse inside directories"
781REPLACE_HELP = "replace object if already existing"
782
783# End of help strings
784##########
785
786##########
787# ROOTEVENTSELECTOR
788
789
790def _setBranchStatus(tree, branchSelectionString, status=0):
791 """This is used by _copyTreeSubset() to turn on/off branches"""
792 for branchToModify in branchSelectionString.split(","):
793 logging.info("Setting branch status to %d for %s" % (status, branchToModify))
794 tree.SetBranchStatus(branchToModify, status)
795 return tree
796
797
799 sourceFile,
800 sourcePathSplit,
801 destFile,
802 destPathSplit,
803 firstEvent,
804 lastEvent,
805 selectionString,
806 branchinclude,
807 branchexclude,
808):
809 """Copy a subset of the tree from (sourceFile,sourcePathSplit)
810 to (destFile,destPathSplit) according to options in optDict"""
811 retcode = changeDirectory(sourceFile, sourcePathSplit[:-1])
812 if retcode != 0:
813 return retcode
814 bigTree = getFromDirectory(sourcePathSplit[-1])
815 nbrEntries = bigTree.GetEntries()
816 # changeDirectory for the small tree not to be memory-resident
817 retcode = changeDirectory(destFile, destPathSplit)
818 if retcode != 0:
819 return retcode
820
821 if lastEvent == -1:
822 lastEvent = nbrEntries - 1
823 numberOfEntries = (lastEvent - firstEvent) + 1
824
825 # "Slim" tree by removing branches -
826 # This is done after the skimming to allow for the user to skim on a
827 # branch they no longer need to keep
828 outputTree = bigTree
829 if branchexclude:
830 _setBranchStatus(outputTree, branchexclude, 0)
831 if branchinclude:
832 _setBranchStatus(outputTree, branchinclude, 1)
833 if branchexclude or branchinclude:
834 outputTree = outputTree.CloneTree()
835
836 # "Skim" events based on branch values using selectionString
837 # as well as selecting a range of events by index
838 outputTree = outputTree.CopyTree(selectionString, "", numberOfEntries, firstEvent)
839
840 outputTree.Write()
841 return retcode
842
843
845 fileName, pathSplitList, destFile, destPathSplit, first, last, selectionString, branchinclude, branchexclude
846):
847 retcode = 0
848 destFileName = destFile.GetName()
849 rootFile = openROOTFile(fileName) if fileName != destFileName else destFile
850 if not rootFile:
851 return 1
852 for pathSplit in pathSplitList:
853 if isTree(rootFile, pathSplit):
854 retcode += _copyTreeSubset(
855 rootFile, pathSplit, destFile, destPathSplit, first, last, selectionString, branchinclude, branchexclude
856 )
857 if fileName != destFileName:
858 rootFile.Close()
859 return retcode
860
861
863 sourceList,
864 destFileName,
865 destPathSplit,
866 compress=None,
867 recreate=False,
868 first=0,
869 last=-1,
870 selectionString="",
871 branchinclude="",
872 branchexclude="",
873):
874 # Check arguments
875 if sourceList == [] or destFileName == "":
876 return 1
877 if recreate and destFileName in sourceList:
878 logging.error("cannot recreate destination file if this is also a source file")
879 return 1
880
881 # Open destination file
882 destFile = openROOTFileCompress(destFileName, compress, recreate)
883 if not destFile:
884 return 1
885
886 # Loop on the root file
887 retcode = 0
888 for fileName, pathSplitList in sourceList:
889 retcode += _copyTreeSubsets(
890 fileName, pathSplitList, destFile, destPathSplit, first, last, selectionString, branchinclude, branchexclude
891 )
892 destFile.Close()
893 return retcode
894
895
896# End of ROOTEVENTSELECTOR
897##########
898
899##########
900# ROOTMV
901
902MOVE_ERROR = "error during copy of {0}, it is not removed from {1}"
903
904
905def _moveObjects(fileName, pathSplitList, destFile, destPathSplit, oneFile, interactive):
906 retcode = 0
907 recursive = True
908 replace = True
909 destFileName = destFile.GetName()
910 rootFile = openROOTFile(fileName, "update") if fileName != destFileName else destFile
911 if not rootFile:
912 return 1
913 ROOT.gROOT.GetListOfFiles().Remove(rootFile) # Fast copy necessity
914 for pathSplit in pathSplitList:
915 oneSource = oneFile and len(pathSplitList) == 1
916 retcodeTemp = copyRootObject(rootFile, pathSplit, destFile, destPathSplit, oneSource, recursive, replace)
917 if not retcodeTemp:
918 retcode += deleteRootObject(rootFile, pathSplit, interactive, recursive)
919 else:
920 logging.warning(MOVE_ERROR.format("/".join(pathSplit), rootFile.GetName()))
921 retcode += retcodeTemp
922 if fileName != destFileName:
923 rootFile.Close()
924 return retcode
925
926
927def rootMv(sourceList, destFileName, destPathSplit, compress=None, interactive=False, recreate=False):
928 # Check arguments
929 if sourceList == [] or destFileName == "":
930 return 1
931 if recreate and destFileName in sourceList:
932 logging.error("cannot recreate destination file if this is also a source file")
933 return 1
934
935 # Open destination file
936 destFile = openROOTFileCompress(destFileName, compress, recreate)
937 if not destFile:
938 return 1
939 ROOT.gROOT.GetListOfFiles().Remove(destFile) # Fast copy necessity
940
941 # Loop on the root files
942 retcode = 0
943 for fileName, pathSplitList in sourceList:
944 retcode += _moveObjects(fileName, pathSplitList, destFile, destPathSplit, len(sourceList) == 1, interactive)
945 destFile.Close()
946 return retcode
947
948
949# End of ROOTMV
950##########
951
952##########
953# ROOTPRINT
954
955
956def _keyListExtended(rootFile, pathSplitList, recursive = False):
957 prefixList = []
958 keyList, dirList = keyClassSplitter(rootFile, pathSplitList)
959 for pathSplit in dirList:
960 keyList.extend(getKeyList(rootFile, pathSplit))
961 subList = [key for key in keyList if isDirectoryKey(key)]
962 keyList = [key for key in keyList if not isDirectoryKey(key)]
963 prefixList = ["" for key in keyList]
964 if recursive:
965 for subdir in subList:
966 subkeyList, subprefixList = _keyListExtended(ROOT.gDirectory.Get(subdir.GetName()), pathSplitList, recursive)
967 keyList.extend(subkeyList)
968 prefixList.extend([subdir.GetName() + "_" + prefix for prefix in subprefixList])
969 if recursive:
970 keyList, prefixList = (list(t) for t in zip(*sorted(zip(keyList, prefixList), key=lambda x: x[0].GetName().lower())))
971 else:
972 keyListSort(keyList)
973 return keyList, prefixList
974
975
977 sourceList,
978 directoryOption=None,
979 divideOption=None,
980 drawOption="",
981 formatOption=None,
982 outputOption=None,
983 sizeOption=None,
984 styleOption=None,
985 verboseOption=False,
986 recursiveOption=False,
987):
988 # Check arguments
989 if sourceList == []:
990 return 1
991 tupleListSort(sourceList)
992
993 # Don't open windows
994 ROOT.gROOT.SetBatch()
995
996 # (Style option)
997 if styleOption:
998 ROOT.gInterpreter.ProcessLine(".x {0}".format(styleOption))
999
1000 # (Verbose option)
1001 if not verboseOption:
1002 ROOT.gErrorIgnoreLevel = 9999
1003
1004 # Initialize the canvas (Size option)
1005 if sizeOption:
1006 try:
1007 width, height = sizeOption.split("x")
1008 width = int(width)
1009 height = int(height)
1010 except ValueError:
1011 logging.warning("canvas size is on a wrong format")
1012 return 1
1013 canvas = ROOT.TCanvas("canvas", "canvas", width, height)
1014 else:
1015 canvas = ROOT.TCanvas("canvas")
1016
1017 # Divide the canvas (Divide option)
1018 if divideOption:
1019 try:
1020 x, y = divideOption.split(",")
1021 x = int(x)
1022 y = int(y)
1023 except ValueError:
1024 logging.warning("divide is on a wrong format")
1025 return 1
1026 canvas.Divide(x, y)
1027 caseNumber = x * y
1028
1029 # Take the format of the output file (formatOutput option)
1030 if not formatOption and outputOption:
1031 fileName = outputOption
1032 fileFormat = fileName.split(".")[-1]
1033 formatOption = fileFormat
1034
1035 # Use pdf as default format
1036 if not formatOption:
1037 formatOption = "pdf"
1038
1039 # Create the output directory (directory option)
1040 if directoryOption:
1041 if not os.path.isdir(os.path.join(os.getcwd(), directoryOption)):
1042 os.mkdir(directoryOption)
1043
1044 # Make the output name, begin to print (output option)
1045 if outputOption:
1046 if formatOption in ["ps", "pdf"]:
1047 outputFileName = outputOption
1048 if directoryOption:
1049 outputFileName = directoryOption + "/" + outputFileName
1050 canvas.Print(outputFileName + "[", formatOption)
1051 else:
1052 logging.warning("can't merge pictures, only postscript or pdf files")
1053 return 1
1054
1055 # Loop on the root files
1056 retcode = 0
1057 objDrawnNumber = 0
1058 openRootFiles = []
1059 for fileName, pathSplitList in sourceList:
1060 rootFile = openROOTFile(fileName)
1061 if not rootFile:
1062 retcode += 1
1063 continue
1064 openRootFiles.append(rootFile)
1065 # Fill the key list (almost the same as in root)
1066 keyList, prefixList = _keyListExtended(rootFile, pathSplitList, recursiveOption)
1067 for k, key in enumerate(keyList):
1068 if isTreeKey(key):
1069 pass
1070 else:
1071 if divideOption:
1072 canvas.cd(objDrawnNumber % caseNumber + 1)
1073 objDrawnNumber += 1
1074 obj = key.ReadObj()
1075 obj.Draw(drawOption)
1076 if divideOption:
1077 if objDrawnNumber % caseNumber == 0:
1078 if not outputOption:
1079 outputFileName = str(objDrawnNumber // caseNumber) + "." + formatOption
1080 if directoryOption:
1081 outputFileName = os.path.join(directoryOption, outputFileName)
1082 canvas.Print(outputFileName, formatOption)
1083 canvas.Clear()
1084 canvas.Divide(x, y)
1085 else:
1086 prefix = prefixList[k]
1087 if not outputOption:
1088 outputFileName = prefix + key.GetName() + "." + formatOption
1089 if directoryOption:
1090 outputFileName = os.path.join(directoryOption, outputFileName)
1091 if outputOption or formatOption == "pdf":
1092 objTitle = "Title:" + key.GetClassName() + " : " + key.GetTitle()
1093 canvas.Print(outputFileName, objTitle)
1094 else:
1095 canvas.Print(outputFileName, formatOption)
1096
1097 # Last page (divideOption)
1098 if divideOption:
1099 if objDrawnNumber % caseNumber != 0:
1100 if not outputOption:
1101 outputFileName = str(objDrawnNumber // caseNumber + 1) + "." + formatOption
1102 if directoryOption:
1103 outputFileName = os.path.join(directoryOption, outputFileName)
1104 canvas.Print(outputFileName, formatOption)
1105
1106 # End to print (output option)
1107 if outputOption:
1108 if not divideOption:
1109 canvas.Print(outputFileName + "]", objTitle)
1110 else:
1111 canvas.Print(outputFileName + "]")
1112
1113 # Close ROOT files
1114 map(lambda rootFile: rootFile.Close(), openRootFiles)
1115
1116 return retcode
1117
1118
1119# End of ROOTPRINT
1120##########
STL class.
getFromDirectory(objName)
Get the object objName from the current directory.
manyOccurenceRemove(pathSplitList, fileName)
Search for double occurence of the same pathSplit and remove them.
rootMv(sourceList, destFileName, destPathSplit, compress=None, interactive=False, recreate=False)
getSourceListArgs(parser, wildcards=True)
Create a list of tuples that contain source ROOT file names and lists of path in these files as well ...
_keyListExtended(rootFile, pathSplitList, recursive=False)
ROOTPRINT.
rootEventselector(sourceList, destFileName, destPathSplit, compress=None, recreate=False, first=0, last=-1, selectionString="", branchinclude="", branchexclude="")
openROOTFile(fileName, mode="read")
Open the ROOT file corresponding to fileName in the corresponding mode, redirecting the output not to...
_copyTreeSubset(sourceFile, sourcePathSplit, destFile, destPathSplit, firstEvent, lastEvent, selectionString, branchinclude, branchexclude)
Copy a subset of the tree from (sourceFile,sourcePathSplit) to (destFile,destPathSplit) according to ...
getParserSingleFile(theHelp, theEpilog="")
Get a commandline parser with the defaults of the commandline utils and a source file or not.
keyClassSplitter(rootFile, pathSplitList)
Return a list of directories and a list of keys corresponding to the other objects,...
deleteRootObject(rootFile, pathSplit, interactive, recursive)
Remove the object (rootFile,pathSplit) -interactive : prompt before every removal -recursive : allow ...
tupleListSort(tupleList)
Sort list of tuples by their first elements ignoring the case.
patternToPathSplitList(fileName, pattern)
Get the list of pathSplit of objects in the ROOT file corresponding to fileName that match with the p...
fileno(file_or_fd)
Look for 'fileno' attribute.
_setBranchStatus(tree, branchSelectionString, status=0)
ROOTEVENTSELECTOR.
copyRootObjectRecursive(sourceFile, sourcePathSplit, destFile, destPathSplit, replace, setName="")
Copy objects from a file or directory (sourceFile,sourcePathSplit) to an other file or directory (des...
_moveObjects(fileName, pathSplitList, destFile, destPathSplit, oneFile, interactive)
createDirectory(rootFile, pathSplit)
Add a directory named 'pathSplit[-1]' in (rootFile,pathSplit[:-1]).
getKeyList(rootFile, pathSplit)
Get the list of keys of the directory (rootFile,pathSplit), if (rootFile,pathSplit) is not a director...
isDirectoryKey(key)
Return True if the object, corresponding to the key, inherits from TDirectory.
isTHnSparseKey(key)
Return True if the object, corresponding to the key, inherits from THnSparse.
isTree(rootFile, pathSplit)
Return True if the object, corresponding to (rootFile,pathSplit), inherits from TTree.
dirListSort(dirList)
Sort list of directories by their names ignoring the case.
rootPrint(sourceList, directoryOption=None, divideOption=None, drawOption="", formatOption=None, outputOption=None, sizeOption=None, styleOption=None, verboseOption=False, recursiveOption=False)
isTreeKey(key)
Return True if the object, corresponding to the key, inherits from TTree.
pathSplitListMatch(fileName, objPattern, wildcards)
Get the list of pathSplit that match with objPattern.
getParserSourceDest(theHelp, theEpilog="")
Get a commandline parser with the defaults of the commandline utils, a list of source files and a des...
keyListSort(keyList)
Sort list of keys by their names ignoring the case.
getSourceDestListOptDict(parser, wildcards=True)
Get the list of tuples of sources, create destination name, destination pathSplit and the dictionary ...
_copyTreeSubsets(fileName, pathSplitList, destFile, destPathSplit, first, last, selectionString, branchinclude, branchexclude)
getSourceListOptDict(parser, wildcards=True)
Get the list of tuples and the dictionary with options.
openROOTFileCompress(fileName, compress, recreate)
Open a ROOT file (like openROOTFile) with the possibility to change compression settings.
_getParser(theHelp, theEpilog)
Different functions to get a parser of arguments and options.
getParserFile(theHelp, theEpilog="")
Get a commandline parser with the defaults of the commandline utils and a list of source files.
deleteObject(rootFile, pathSplit)
Delete the object 'pathSplit[-1]' from (rootFile,pathSplit[:-1]).
getKey(rootFile, pathSplit)
Get the key of the corresponding object (rootFile,pathSplit).
getArgs(parser)
Set of functions to put the arguments in shape.
_setIgnoreLevel(level)
Several utils.
changeDirectory(rootFile, pathSplit)
Change the current directory (ROOT.gDirectory) by the corresponding (rootFile,pathSplit).
isDirectory(rootFile, pathSplit)
Return True if the object, corresponding to (rootFile,pathSplit), inherits from TDirectory.
copyRootObject(sourceFile, sourcePathSplit, destFile, destPathSplit, oneSource, recursive, replace)
Initialize the recursive function 'copyRootObjectRecursive', written to be as unix-like as possible.
joinPathSplit(pathSplit)
Join the pathSplit with '/'.
stdoutRedirected()
Redirect the output from sys.stdout to os.devnull.
fileNameListMatch(filePattern, wildcards)
Get the list of fileName that match with objPattern.
stderrRedirected()
Redirect the output from sys.stderr to os.devnull.
isExisting(rootFile, pathSplit)
Return True if the object, corresponding to (rootFile,pathSplit), exits.
streamRedirected(source=sys.stdout, destination=os.devnull)
Redirect the output from source to destination.
patternToFileNameAndPathSplitList(pattern, wildcards=True)
Get the list of tuple containing both :