Belle II Software  release-08-01-10
testing_payloads.py
1 #!/usr/bin/env python3
2 
3 
10 
11 """
12 Script to upload local database to ConditionsDB.
13 
14 This script takes a local database file and will upload all payloads defined in
15 this file to the ConditionsDB and create iovs for each payload. It assumes that
16 all tags already exist.
17 """
18 
19 import os
20 from basf2 import B2ERROR, LogLevel, logging
21 from conditions_db import file_checksum
22 from B2Tools.b2root import normalize_file
23 
24 
26  """Class to keep information about an entry in the testing payloads storage file"""
27 
28  def __init__(self, line, basedir):
29  """Create new entry from line in testing payloads storage file"""
30  try:
31  name, revision, iov = line.split()
32  except ValueError:
33  raise ValueError("line must be of the form 'dbstore/<payloadname> <revision> "
34  "<firstExp>,<firstRun>,<finalExp>,<finalRun>'")
35 
36 
37  self.revisionrevision = revision
38 
39  try:
40 
41  self.modulemodule = name.split("/")[1]
42  except IndexError:
43  raise ValueError("payload name must be of the form dbstore/<payloadname>")
44 
45  try:
46  iov = [int(e) for e in iov.split(",")]
47  except ValueError:
48  raise ValueError("experiment and run numbers must be integers")
49 
50  if len(iov) != 4:
51  raise ValueError("IoV needs to be four values (firstExp,firstRun,finalExp,finalRun)")
52 
53 
54  self.filenamefilename = os.path.join(basedir, f"dbstore_{self.module}_rev_{self.revision}.root")
55 
56  self.firstRunfirstRun = {"exp": iov[0], "run": iov[1]}
57 
58  self.finalRunfinalRun = {"exp": iov[2], "run": iov[3]}
59 
60  self.__checksum__checksum = None
61 
62  self.__id__id = (self.modulemodule,) + tuple(iov)
63 
64  self.payloadpayload = None
65 
66  self.ioviov = None
67 
68  def normalize(self, name=None, root_version=61408):
69  """Normalize the root file to have the same checksum for the same content"""
70  normalize_file(self.filenamefilename, in_place=True, name=name, root_version=root_version)
71  self.__checksum__checksum = file_checksum(self.filenamefilename)
72 
73  @property
74  def checksum(self):
75  """Return checksum, calculated on first access"""
76  if self.__checksum__checksum is None:
77  self.__checksum__checksum = file_checksum(self.filenamefilename)
78  return self.__checksum__checksum
79 
80  def __repr__(self):
81  """Convert to useful string representation"""
82  return repr(self.__id__id + (self.filenamefilename,))
83 
84  def __eq__(self, other):
85  """Compare to other entries, only consider package, module and iov for equality"""
86  return self.__id__id == other.__id
87 
88  def __le__(self, other):
89  """Compare to other entries, only consider package, module and iov for equality"""
90  return self.__id__id <= other.__id
91 
92  def __lt__(self, other):
93  """Compare to other entries, only consider package, module and iov for equality"""
94  return self.__id__id < other.__id
95 
96  def __hash__(self):
97  """Provide hash function to be able to create a set"""
98  return hash(self.__id__id)
99 
100  @property
101  def iov_tuple(self):
102  """Return a tuple with the valid exp,run range"""
103  return self.firstRunfirstRun['exp'], self.firstRunfirstRun['run'], self.finalRunfinalRun['exp'], self.finalRunfinalRun['run']
104 
105  def iov_str(self):
106  """String representation of IoV"""
107  return f"{self.firstRun['exp']}/{self.firstRun['run']} - {self.finalRun['exp']}/{self.finalRun['run']}"
108 
109 
110 def parse_testing_payloads_file(filename, check_existing=True):
111  """
112  Parse a testing payload storage file
113 
114  This is the python equivalent of TestingPayloadStorage::read implemented in
115  python. Each line in in the file should be of the form
116 
117  "dbstore/{payloadname} {revision} {firstExp},{firstRun},{finalExp},{finalRun}"
118 
119  Comments can be started using "#", everything including this character to
120  the end of the line will be ignored.
121 
122  Parameters:
123  filename (str): filename of the testing payload storage file to parse
124  check_existing (bool): if True check if the payloads actually exist where
125  they should be
126 
127  Returns:
128  a list of TestingPayloadEntry objects or None if there were any errors
129  """
130 
131  # make sure the testing payload storage file exists
132  if not os.path.exists(filename):
133  B2ERROR("Given database file does not exist")
134  return None
135 
136  # set the directory
137  payload_dir = os.path.dirname(filename)
138 
139  # remember the list of errors before start of the function to see if we
140  # create any new ones
141  old_error_count = logging.log_stats[LogLevel.ERROR]
142  entries = []
143  with open(filename) as dbfile:
144  for lineno, line in enumerate(dbfile, 1):
145  # ignore comments
146  line = line.split("#", 1)[0].strip()
147  # and empty lines
148  if not line:
149  continue
150  # parse the line
151  try:
152  entry = TestingPayloadEntry(line, payload_dir)
153  except ValueError as e:
154  B2ERROR("{filename}:{line} error: {error}".format(
155  filename=filename, line=lineno, error=e
156  ))
157  continue
158 
159  if check_existing and not os.path.exists(entry.filename):
160  B2ERROR("{filename}:{line} error: cannot find payload file {missing}".format(
161  filename=filename, line=lineno, missing=entry.filename
162  ))
163  continue
164 
165  entries.append(entry)
166 
167  # ok, if we had any errors so far, exit
168  if logging.log_stats[LogLevel.ERROR] > old_error_count:
169  return None
170 
171  return entries
def normalize(self, name=None, root_version=61408)
__checksum
variable for checksum, calculated on first access
__id
object to uniquely identify this entry (payload + iov)