ATLAS Offline Software
tags.py
Go to the documentation of this file.
1 # Copyright (C) 2002-2022 CERN for the benefit of the ATLAS collaboration
2 
3 from logging import getLogger; log = getLogger("DQDefects.tags")
4 
5 from PyCool import cool
6 
7 from DQUtils import IOVSet
8 
9 from DQDefects import DEFECT_LOGIC_TAG_FORMAT
10 
11 from .exceptions import InvalidTagError, InvalidDefectTagError, InvalidLogicTagError
12 
13 from .virtual_mixin import NONHEAD_MODIFICATION_MSG
14 
15 from typing import List, Optional, Iterable
16 
17 import collections
18 tagtype = collections.namedtuple('tagtype', ['defects', 'logic'])
19 
21  def __init__(self) -> None:
22  super(DefectsDBTagsMixin, self).__init__()
23 
24  self.check_tag_validity()
25 
26  @property
27  def logics_tags(self) -> List[str]:
28  """
29  Returns a list of existing logic tags
30  """
31  return [str(t) for t in self.defect_logic_folder.listTags()]
32 
33  @property
34  def defects_tags(self) -> List[str]:
35  """
36  Returns a list of existing defect tags
37  """
38  return [str(t) for t in self.defects_folder.listTags()]
39 
40  @property
41  def next_logics_tag(self) -> str:
42  """
43  Gives the next available DEFECTLOGICS tag
44  """
45  existing_tags = self.logics_tags
46  if existing_tags:
47  new_id = max(int(str(t).split("-")[-1]) for t in existing_tags) + 1
48  else:
49  new_id = 0
50  return DEFECT_LOGIC_TAG_FORMAT % new_id
51 
52  def _tag_head_and_lock(self, folder: cool.IFolder, name: str, description: str) -> None:
53  """
54  Give the current HEAD of `folder` a new tag and lock it.
55  """
56  LOCKED = cool.HvsTagLock.LOCKED
57  aname = name.encode('ascii')
58  folder.cloneTagAsUserTag('HEAD', aname, description.encode('utf-8'))
59  folder.setTagLockStatus(aname, LOCKED)
60 
61  def new_hierarchical_tag(self, defects_tag: str, logics_tag: str) -> str:
62  """
63  Create a new heirarchical tag relating the defects and logics
64 
65  New tag is of the form
66  "DetStatus-[Logic revision number]-[Defect tagname]"
67  and has description
68  "(v%i) blah"
69  """
70  logic_revision = int(logics_tag.split("-")[-1])
71  defect_part = "-".join(defects_tag.split("-")[1:])
72  hierarchical_tag = "DetStatus-v%02i-%s" % (logic_revision, defect_part)
73  logicspart = "(%i) " % logic_revision
74 
75  adefects_tag = defects_tag.encode('ascii')
76  alogics_tag = logics_tag.encode('ascii')
77  ahierarchical_tag = hierarchical_tag.encode('ascii')
78  logicspart = logicspart.encode('ascii')
79  defect_descr = self.defects_folder.tagDescription(adefects_tag).encode('utf-8')
80 
81  # Protection here against making descriptions too long
82  description = logicspart + defect_descr[:255 - len(logicspart)]
83 
84  parent_folder = self.parent_folderset
85  self.defects_folder.createTagRelation(ahierarchical_tag, adefects_tag)
86  self.defect_logic_folder.createTagRelation(ahierarchical_tag, alogics_tag)
87  parent_folder.setTagDescription(ahierarchical_tag, description)
88 
89  log.info("New hierarchical tag %s", hierarchical_tag)
90  return hierarchical_tag
91 
92  @property
93  def defects_tag_valid(self) -> bool:
94  try:
95  self.defects_tag
96  except InvalidTagError:
97  return False
98  else:
99  return True
100 
101  @property
102  def logics_tag_valid(self) -> bool:
103  try:
104  self.logics_tag
105  except InvalidTagError:
106  return False
107  else:
108  return True
109 
110  def check_tag_validity(self) -> None:
111  """
112  Ensure that the tags that this DefectsDB instance was constructed with
113  are functional
114  """
115  if not (self.defects_tag_valid or self.logics_tag_valid):
116  raise InvalidTagError("Tag doesn't resolve: {0}".format(self._tag))
117 
118  @property
119  def defects_tag(self) -> str:
120  """
121  Return the tag used for retrieving defects on this DefectsDB instance
122  """
123  if self._tag.defects == "HEAD": return "HEAD"
124  try:
125  return self.defects_folder.resolveTag(self._tag.defects)
126  except Exception:
127  if self._read_only:
128  raise InvalidDefectTagError(self._tag.defects)
129  # assume user knows what they're doing (e.g. writing to fresh tag)
130  return self._tag.defects
131 
132  @property
133  def logics_tag(self) -> str:
134  """
135  Return the tag used for retrieving virtual defect clauses
136  """
137  if self._tag.logic == "HEAD": return "HEAD"
138  try:
139  return self.defect_logic_folder.resolveTag(self._tag.logic)
140  except Exception:
141  if self._read_only:
142  raise InvalidLogicTagError(self._tag.logic)
143  # assume user knows what they're doing (e.g. writing to fresh tag)
144  return self._tag.logic
145 
146  @property
147  def tag(self) -> tagtype:
148  """
149  Readonly property stating the tag that the database was instantiated on
150  """
151  return self._tag
152 
153  @property
154  def tags(self) -> List[str]:
155  """
156  The list of tags which are on the database
157  """
158  return [str(t) for t in self.parent_folderset.listTags()]
159 
160  def new_logics_tag(self, description: str = "") -> str:
161  """
162  Create a new tag for the logic folder and lock it.
163 
164  Parameters:
165  `description` : What changed in this tag? (optional, default "")
166  """
167  assert self.logics_tag == "HEAD", NONHEAD_MODIFICATION_MSG
168 
169  new_tag_name = self.next_logics_tag
170  folder = self.defect_logic_folder
171  self._tag_head_and_lock(folder, new_tag_name, description)
172  log.info("Tagged DEFECTLOGICS HEAD with %s", new_tag_name)
173  return new_tag_name
174 
175  def new_defects_tag(self, name: str, description: str, iovranges: Optional[Iterable] = None) -> str:
176  """
177  Clones the current DEFECTS tag (specified in the constructor) to a new one
178  If iovranges != None, does the slower thing of copying IOVs one by one
179 
180  Parameters:
181  `name` : Name of the new tag
182  `description` : Description of the contents of this tag
183  """
184  if name.startswith("DetStatus"):
185  raise RuntimeError("Only specify the last part of the defect tag")
186  adescription = description.encode('utf-8')
187 
188  log.info("Creating new tag %s", name)
189 
190  name = f"DetStatusDEFECTS-{name}"
191  aname = name.encode('ascii')
192 
193  if iovranges is None:
194  self.defects_folder.cloneTagAsUserTag(self.defects_tag.encode('ascii'), aname, adescription)
195  return name
196 
197  # Fetch all primary defects relevant to `iovranges`
198  kwargs = dict(primary_only=True, nonpresent=True, intersect=True)
199  iovsets = (self.retrieve(*iovrange, **kwargs) for iovrange in iovranges)
200  to_copy = IOVSet.from_iovsets(iovsets)
201 
202  log.info("Copying IoVs: %r", to_copy)
203 
204  with self.storage_buffer:
205  for iov in to_copy:
206  self._insert_iov(iov, name)
207 
208  # If there are no IOVs to copy, there is no new tag to describe
209  if to_copy:
210  self.defects_folder.setTagDescription(aname, adescription)
211 
212  return name
python.tags.DefectsDBTagsMixin.logics_tag
logics_tag
Definition: tags.py:167
python.tags.DefectsDBTagsMixin.__init__
None __init__(self)
Definition: tags.py:21
max
#define max(a, b)
Definition: cfImp.cxx:41
vtune_athena.format
format
Definition: vtune_athena.py:14
CaloCellPos2Ntuple.int
int
Definition: CaloCellPos2Ntuple.py:24
python.tags.DefectsDBTagsMixin.tags
List[str] tags(self)
Definition: tags.py:154
python.tags.DefectsDBTagsMixin.defects_tag_valid
bool defects_tag_valid(self)
Definition: tags.py:93
python.tags.DefectsDBTagsMixin
Definition: tags.py:20
python.tags.DefectsDBTagsMixin._tag_head_and_lock
None _tag_head_and_lock(self, cool.IFolder folder, str name, str description)
Definition: tags.py:52
python.exceptions.InvalidDefectTagError
Definition: exceptions.py:12
python.tags.DefectsDBTagsMixin.tag
tagtype tag(self)
Definition: tags.py:147
python.tags.DefectsDBTagsMixin.defects_tag
str defects_tag(self)
Definition: tags.py:119
python.tags.DefectsDBTagsMixin.next_logics_tag
str next_logics_tag(self)
Definition: tags.py:41
python.tags.DefectsDBTagsMixin.new_hierarchical_tag
str new_hierarchical_tag(self, str defects_tag, str logics_tag)
Definition: tags.py:61
python.exceptions.InvalidTagError
Definition: exceptions.py:9
python.tags.DefectsDBTagsMixin.logics_tags
List[str] logics_tags(self)
Definition: tags.py:27
TCS::join
std::string join(const std::vector< std::string > &v, const char c=',')
Definition: Trigger/TrigT1/L1Topo/L1TopoCommon/Root/StringUtils.cxx:10
python.tags.DefectsDBTagsMixin.new_logics_tag
str new_logics_tag(self, str description="")
Definition: tags.py:160
python.tags.DefectsDBTagsMixin.logics_tag_valid
bool logics_tag_valid(self)
Definition: tags.py:102
python.tags.DefectsDBTagsMixin.defects_tags
List[str] defects_tags(self)
Definition: tags.py:34
pickleTool.object
object
Definition: pickleTool.py:30
str
Definition: BTagTrackIpAccessor.cxx:11
python.tags.DefectsDBTagsMixin.new_defects_tag
str new_defects_tag(self, str name, str description, Optional[Iterable] iovranges=None)
Definition: tags.py:175
python.PerfMonSerializer.encode
def encode(data, use_base64=True)
Definition: PerfMonSerializer.py:375
python.tags.DefectsDBTagsMixin.check_tag_validity
None check_tag_validity(self)
Definition: tags.py:110
Trk::split
@ split
Definition: LayerMaterialProperties.h:38
python.exceptions.InvalidLogicTagError
Definition: exceptions.py:18
python.CaloCondLogger.getLogger
def getLogger(name="CaloCond")
Definition: CaloCondLogger.py:16