File indexing completed on 2024-04-06 12:01:53
0001 """
0002
0003 Using Audrius' models from flask browser.
0004
0005 This file contains models that are used with SQLAlchemy.
0006
0007 Note: some things done in methods written in classes rely on the querying module adding extra information to classes,
0008 so these will not work in a normal context outside the framework.
0009
0010 """
0011 import json
0012 import datetime
0013
0014 try:
0015 import sqlalchemy
0016 from sqlalchemy.orm import relationship, backref
0017 from sqlalchemy.ext.declarative import declarative_base
0018
0019 from sqlalchemy import Column, String, Integer, DateTime, Binary, ForeignKey, BigInteger, and_
0020 except ImportError:
0021 print("You must be working inside a CMSSW environment. Try running 'cmsenv'.")
0022 exit()
0023
0024 from . import data_sources, data_formats
0025 import urllib.request, urllib.parse, urllib.error, urllib.request, urllib.error, urllib.parse, base64
0026 from copy import deepcopy
0027
0028
0029 from .utils import to_timestamp, to_datetime, friendly_since
0030
0031 def session_independent_object(object, schema=None):
0032
0033
0034
0035
0036 if object.__class__.__name__.lower() == "payload":
0037 map_blobs = object.blobs_mapped
0038 else:
0039 map_blobs = False
0040
0041
0042 cls = object.__class__
0043 class_name = class_name_to_column(cls).lower()
0044 new_class = generate(map_blobs=map_blobs, class_name=class_name)
0045 new_class.__table__.schema = schema
0046 new_object = new_class(object.as_dicts(), convert_timestamps=False)
0047
0048 return new_object
0049
0050 def session_independent(objects):
0051 if type(objects) == list:
0052 return list(map(session_independent_object, objects))
0053 else:
0054
0055 return session_independent_object(objects)
0056
0057 def class_name_to_column(cls):
0058 class_name = cls.__name__
0059 all_upper_case = True
0060 for character in class_name:
0061 all_upper_case = character.isupper()
0062 if all_upper_case:
0063 return class_name
0064 for n in range(0, len(class_name)):
0065 if class_name[n].isupper() and n != 0:
0066 class_name = str(class_name[0:n]) + "".join(["_", class_name[n].lower()]) + str(class_name[n+1:])
0067 elif class_name[n].isupper() and n == 0:
0068 class_name = str(class_name[0:n]) + "".join([class_name[n].lower()]) + str(class_name[n+1:])
0069 return class_name
0070
0071 def status_full_name(status):
0072 full_status = {
0073 'P': 'Pending',
0074 'R': 'Rejected',
0075 'A': 'Accepted'
0076 }
0077 return full_status[status]
0078
0079 def date_args_to_days(**radius):
0080 days = radius.get("days")
0081 days += radius.get("weeks")*7 if radius.get("weeks") != None else 0
0082 days += radius.get("months")*28 if radius.get("months") != None else 0
0083 days += radius.get("years")+365 if radius.get("years") != None else 0
0084 return days
0085
0086 class ContinuousRange(object):
0087 """
0088 Base class for Radius and Range - used for checking by apply_filter function
0089 """
0090
0091 def __init__(self):
0092 pass
0093
0094 def get_start(self):
0095 return self._start
0096
0097 def get_end(self):
0098 return self._end
0099
0100 class Radius(ContinuousRange):
0101 """
0102 Used to tell proxy methods that a range of values defined by a centre and a radius should be queried for - special case of filter clauses.
0103 """
0104 def __init__(self, centre, radius):
0105 """
0106 centre and radius should be objects that can be added and subtracted.
0107 eg, centre could be a datetime.datetime object, and radius could be datetime.timedelta
0108
0109 Radius and Range objects are assigned to properties of querying.connection objects, hence are given the database type.
0110 """
0111 self._centre = centre
0112 self._radius = radius
0113 self._start = self._centre - self._radius
0114 self._end = self._centre + self._radius
0115
0116 class Range(ContinuousRange):
0117 """
0118 Used to tell proxy methods that a range of values defined by a start and end point should be queried for - special case of filter clauses.
0119 """
0120 def __init__(self, start, end):
0121 """
0122 centre and radius should be objects that can be added and subtracted.
0123 eg, centre could be a datetime.datetime object, and radius could be datetime.timedelta
0124
0125 Radius and Range objects are assigned to properties of querying.connection objects, hence are given the database type.
0126 """
0127 self._start = start
0128 self._end = end
0129
0130 class RegExp(object):
0131 """
0132 Used to tell proxy methods that a regular expression should be used to query the column.
0133 """
0134 def __init__(self, regexp):
0135 self._regexp = regexp
0136
0137 def get_regexp(self):
0138 return self._regexp
0139
0140 def apply(self):
0141
0142 if self.database_type in ["oracle", "frontier"]:
0143 return sqlalchemy.func.regexp_like(field, regexp)
0144 elif self.database_type == "sqlite":
0145
0146 self.connection_object.engine.pool.connect().create_function('regexp', 2, lambda data, regexp: re.search(regexp, data) is not None)
0147
0148 return sqlalchemy.func.regexp(field, regexp)
0149 else:
0150 raise NotImplemented("Can only apply regular expression search to Oracle, Frontier and SQLite.")
0151
0152 def apply_filter(orm_query, orm_class, attribute, value):
0153 filter_attribute = getattr(orm_class, attribute)
0154 if type(value) == list:
0155 orm_query = orm_query.filter(filter_attribute.in_(value))
0156 elif type(value) == data_sources.json_list:
0157 orm_query = orm_query.filter(filter_attribute.in_(value.data()))
0158 elif type(value) in [Range, Radius]:
0159
0160 minus = value.get_start()
0161 plus = value.get_end()
0162 orm_query = orm_query.filter(and_(filter_attribute >= minus, filter_attribute <= plus))
0163
0164 elif type(value) == RegExp:
0165
0166
0167
0168 if value.database_type in ["oracle", "frontier"]:
0169 regexp = sqlalchemy.func.regexp_like(filter_attribute, value.get_regexp())
0170 elif value.database_type == "sqlite":
0171 value.connection_object.engine.pool.connect().create_function('regexp', 2, lambda data, regexp: re.search(regexp, data) is not None)
0172 regexp = sqlalchemy.func.regexp(filter_attribute, value.get_regexp())
0173 else:
0174 raise NotImplemented("Can only apply regular expression search to Oracle, Frontier and SQLite.")
0175 orm_query = orm_query.filter(regexp)
0176
0177 else:
0178 orm_query = orm_query.filter(filter_attribute == value)
0179 return orm_query
0180
0181 def apply_filters(orm_query, orm_class, **filters):
0182 for (key, value) in list(filters.items()):
0183 if not(key in ["amount"]):
0184 orm_query = apply_filter(orm_query, orm_class, key, value)
0185 return orm_query
0186
0187 def generate(map_blobs=False, class_name=None):
0188
0189 Base = declarative_base()
0190 schema = {"schema" : "CMS_CONDITIONS"}
0191 fk_schema_prefix = ("%s." % schema["schema"]) if schema else ""
0192
0193 class GlobalTag(Base):
0194 __table_args__ = schema
0195 __tablename__ = 'GLOBAL_TAG'
0196
0197 headers = ["name", "validity", "description", "release", "insertion_time", "snapshot_time", "scenario", "workflow", "type"]
0198
0199 name = Column(String(100), unique=True, nullable=False, primary_key=True)
0200 validity = Column(Integer, nullable=False)
0201 description = Column(String(4000), nullable=False)
0202 release = Column(String(100), nullable=False)
0203 insertion_time = Column(DateTime, nullable=False)
0204 snapshot_time = Column(DateTime, nullable=False)
0205 scenario = Column(String(100))
0206 workflow = Column(String(100))
0207 type = Column(String(1))
0208 tag_map = relationship('GlobalTagMap', backref='global_tag')
0209
0210 def __init__(self, dictionary={}, convert_timestamps=True):
0211
0212 for key in dictionary:
0213 try:
0214 if convert_timestamps:
0215 self.__dict__[key] = to_timestamp(dictionary[key])
0216 else:
0217 self.__dict__[key] = dictionary[key]
0218 except KeyError as k:
0219 continue
0220
0221 def __repr__(self):
0222 return '<GlobalTag %r>' % self.name
0223
0224 def as_dicts(self, convert_timestamps=False):
0225 """
0226 Returns dictionary form of Global Tag object.
0227 """
0228 json_gt = {
0229 'name': self.name,
0230 'validity': self.validity,
0231 'description': self.description,
0232 'release': self.release,
0233 'insertion_time': to_timestamp(self.insertion_time) if convert_timestamps else self.insertion_time,
0234 'snapshot_time': to_timestamp(self.snapshot_time) if convert_timestamps else self.snapshot_time,
0235 'scenario': self.scenario,
0236 'workflow': self.workflow,
0237 'type': self.type
0238 }
0239 return json_gt
0240
0241 def to_array(self):
0242 return [self.name, self.release, to_timestamp(self.insertion_time), to_timestamp(self.snapshot_time), self.description]
0243
0244 def all(self, **kwargs):
0245 """
0246 Returns `amount` Global Tags ordered by Global Tag name.
0247 """
0248 query = self.session.query(GlobalTag)
0249 query = apply_filters(query, self.__class__, **kwargs)
0250 amount = kwargs["amount"] if "amount" in list(kwargs.keys()) else None
0251 query_result = query.order_by(GlobalTag.name).limit(amount).all()
0252 gts = data_sources.json_data_node.make(query_result)
0253 return gts
0254
0255 def tags(self, **kwargs):
0256 """
0257 Returns `amount` *Global Tag Maps* belonging to this Global Tag.
0258 """
0259 kwargs["global_tag_name"] = self.name
0260 all_tags = self.session.query(GlobalTagMap.global_tag_name, GlobalTagMap.record, GlobalTagMap.label, GlobalTagMap.tag_name)
0261 all_tags = apply_filters(all_tags, GlobalTagMap, **kwargs)
0262 amount = kwargs["amount"] if "amount" in list(kwargs.keys()) else None
0263 all_tags = all_tags.order_by(GlobalTagMap.tag_name).limit(amount).all()
0264 column_names = ["global_tag_name", "record", "label", "tag_name"]
0265 all_tags = [dict(list(zip(column_names, list(map(to_timestamp, row))))) for row in all_tags]
0266 all_tags = data_formats._dicts_to_orm_objects(GlobalTagMap, all_tags)
0267 return data_sources.json_data_node.make(all_tags)
0268
0269 def iovs(self, **kwargs):
0270 """
0271 Returns `amount` IOVs belonging to all Tags held in this Global Tag.
0272 For large Global Tags (which is most of them), VERY slow.
0273 Highly recommended to instead used `tags().get_members("tag_name").data()` to get a `list` of tag names,
0274 and then get IOVs from each Tag name.
0275
0276 At some point, this method may replace the method currently used.
0277 """
0278
0279
0280
0281
0282 tag_names = self.tags().get_members("tag_name").data()
0283 iovs_all_tags = self.session.query(IOV).filter(IOV.tag_name.in_(tag_names))
0284 iovs_all_tags = apply_filters(iovs_all_tags, IOV, **kwargs)
0285 amount = kwargs["amount"] if "amount" in list(kwargs.keys()) else None
0286 iovs_all_tags = iovs_all_tags.limit(amount).subquery()
0287
0288
0289 iovs_gt_tags = self.session.query(GlobalTagMap.tag_name, iovs_all_tags.c.since,\
0290 iovs_all_tags.c.payload_hash, iovs_all_tags.c.insertion_time)\
0291 .filter(GlobalTagMap.global_tag_name == self.name)\
0292 .join(iovs_all_tags, GlobalTagMap.tag_name == iovs_all_tags.c.tag_name)
0293
0294 iovs_gt_tags = iovs_gt_tags.order_by(iovs_all_tags.c.since).all()
0295
0296 column_names = ["tag_name", "since", "payload_hash", "insertion_time"]
0297 all_iovs = [dict(list(zip(column_names, row))) for row in iovs_gt_tags]
0298 all_iovs = data_formats._dicts_to_orm_objects(IOV, all_iovs)
0299
0300 return data_sources.json_data_node.make(all_iovs)
0301
0302 def __sub__(self, other):
0303 """
0304 Allows Global Tag objects to be used with the "-" arithmetic operator to find their difference.
0305 Note: gt1 - gt2 = gt1.diff(gt2) ( = gt2 - gt1 = gt2.diff(gt1))
0306 """
0307 return self.diff(other)
0308
0309 def diff(self, gt):
0310 """
0311 Returns the json_list of differences in the form of tuples:
0312
0313 (record, label, tag name of gt1 (self), tag name of gt2 (gt))
0314 """
0315
0316 record_label_to_tag_name1 = dict([((gt_map.record, gt_map.label), gt_map.tag_name) for gt_map in self.tags().data()])
0317 record_label_to_tag_name2 = dict([((gt_map.record, gt_map.label), gt_map.tag_name) for gt_map in gt.tags().data()])
0318
0319 record_label_pairs = sorted(set(record_label_to_tag_name1) | set(record_label_to_tag_name2))
0320
0321 table = []
0322 tags_pairs_with_differences = []
0323
0324 for record_label in record_label_pairs:
0325 tag_name1 = record_label_to_tag_name1.get(record_label)
0326 tag_name2 = record_label_to_tag_name2.get(record_label)
0327
0328 if tag_name1 == None or tag_name2 == None or tag_name1 != tag_name2:
0329 table.append({
0330 "Record" : record_label[0],
0331 "Label" : record_label[1],
0332 ("%s Tag" % self.name) : tag_name1,
0333 ("%s Tag" % gt.name) : tag_name2
0334 })
0335
0336 return data_sources.json_data_node.make(table)
0337
0338 class GlobalTagMap(Base):
0339 __table_args__ = schema
0340 __tablename__ = 'GLOBAL_TAG_MAP'
0341
0342 headers = ["global_tag_name", "record", "label", "tag_name"]
0343
0344 global_tag_name = Column(String(100), ForeignKey(fk_schema_prefix + 'GLOBAL_TAG.name'), primary_key=True, nullable=False)
0345 record = Column(String(100), ForeignKey(fk_schema_prefix + 'RECORDS.record'), primary_key=True, nullable=False)
0346 label = Column(String(100), primary_key=True, nullable=False)
0347 tag_name = Column(String(100), ForeignKey(fk_schema_prefix + 'TAG.name'), nullable=False)
0348
0349 def __init__(self, dictionary={}, convert_timestamps=True):
0350
0351 for key in dictionary:
0352 try:
0353 if convert_timestamps:
0354 self.__dict__[key] = to_timestamp(dictionary[key])
0355 else:
0356 self.__dict__[key] = dictionary[key]
0357 except KeyError as k:
0358 continue
0359
0360 def __repr__(self):
0361 return '<GlobalTagMap %r>' % self.global_tag_name
0362
0363 def as_dicts(self, convert_timestamps=False):
0364 """
0365 Returns dictionary form of this Global Tag Map.
0366 """
0367 json_gtm = {
0368 "global_tag_name" : str(self.global_tag_name),
0369 "record" : str(self.record),
0370 "label" : str(self.label),
0371 "tag_name" : str(self.tag_name)
0372 }
0373 return json_gtm
0374
0375
0376 class GlobalTagMapRequest(Base):
0377 __table_args__ = schema
0378 __tablename__ = 'GLOBAL_TAG_MAP_REQUEST'
0379
0380 queue = Column(String(100), primary_key=True, nullable=False)
0381 tag = Column(String(100), ForeignKey(fk_schema_prefix + 'TAG.name'), primary_key=True, nullable=False)
0382 record = Column(String(100), ForeignKey(fk_schema_prefix + 'RECORDS.record'), primary_key=True, nullable=False)
0383 label = Column(String(100), primary_key=True, nullable=False)
0384 status = Column(String(1), nullable=False)
0385 description = Column(String(4000), nullable=False)
0386 submitter_id = Column(Integer, nullable=False)
0387 time_submitted = Column(DateTime, nullable=False)
0388 last_edited = Column(DateTime, nullable=False)
0389
0390 def __init__(self, dictionary={}, convert_timestamps=True):
0391
0392 for key in dictionary:
0393 try:
0394 if convert_timestamps:
0395 self.__dict__[key] = to_timestamp(dictionary[key])
0396 else:
0397 self.__dict__[key] = dictionary[key]
0398 except KeyError as k:
0399 continue
0400
0401 headers = ["queue", "tag", "record", "label", "status", "description", "submitter_id", "time_submitted", "last_edited"]
0402
0403 def as_dicts(self):
0404 """
0405 Returns dictionary form of this Global Tag Map Request.
0406 """
0407 return {
0408 "queue" : self.queue,
0409 "tag" : self.tag,
0410 "record" : self.record,
0411 "label" : self.label,
0412 "status" : self.status,
0413 "description" : self.description,
0414 "submitter_id" : self.submitter_id,
0415 "time_submitted" : self.time_submitted,
0416 "last_edited" : self.last_edited
0417 }
0418
0419 def __repr__(self):
0420 return '<GlobalTagMapRequest %r>' % self.queue
0421
0422 def to_array(self):
0423 return [self.queue, self.tag, self.record, self.label, status_full_name(self.status), to_timestamp(self.time_submitted), to_timestamp(self.last_edited)]
0424
0425 class IOV(Base):
0426 __table_args__ = schema
0427 __tablename__ = 'IOV'
0428
0429 headers = ["tag_name", "since", "payload_hash", "insertion_time"]
0430
0431 tag_name = Column(String(4000), ForeignKey(fk_schema_prefix + 'TAG.name'), primary_key=True, nullable=False)
0432 since = Column(Integer, primary_key=True, nullable=False)
0433 payload_hash = Column(String(40), ForeignKey(fk_schema_prefix + 'PAYLOAD.hash'), nullable=False)
0434 insertion_time = Column(DateTime, primary_key=True, nullable=False)
0435
0436 def __init__(self, dictionary={}, convert_timestamps=True):
0437
0438 for key in dictionary:
0439 try:
0440 if convert_timestamps:
0441 self.__dict__[key] = to_timestamp(dictionary[key])
0442 else:
0443 self.__dict__[key] = dictionary[key]
0444 except KeyError as k:
0445 continue
0446
0447 def as_dicts(self, convert_timestamps=False):
0448 """
0449 Returns dictionary form of this IOV.
0450 """
0451 return {
0452 "tag_name" : self.tag_name,
0453 "since" : self.since,
0454 "payload_hash" : self.payload_hash,
0455 "insertion_time" : to_timestamp(self.insertion_time) if convert_timestamps else self.insertion_time
0456 }
0457
0458 def __repr__(self):
0459 return '<IOV %r>' % self.tag_name
0460
0461 def to_array(self):
0462 return [self.since, to_timestamp(self.insertion_time), self.payload_hash]
0463
0464 def all(self, **kwargs):
0465 """
0466 Returns `amount` IOVs ordered by since.
0467 """
0468 query = self.session.query(IOV)
0469 query = apply_filters(query, IOV, **kwargs)
0470 amount = kwargs["amount"] if "amount" in list(kwargs.keys()) else None
0471 query_result = query.order_by(IOV.tag_name).order_by(IOV.since).limit(amount).all()
0472 return data_sources.json_data_node.make(query_result)
0473
0474
0475 class Payload(Base):
0476 __table_args__ = schema
0477 __tablename__ = 'PAYLOAD'
0478
0479 headers = ["hash", "object_type", "version", "insertion_time"]
0480
0481 hash = Column(String(40), primary_key=True, nullable=False)
0482 object_type = Column(String(4000), nullable=False)
0483 version = Column(String(4000), nullable=False)
0484 insertion_time = Column(DateTime, nullable=False)
0485 if map_blobs:
0486 data = Column(Binary, nullable=False)
0487 streamer_info = Column(Binary, nullable=False)
0488 blobs_mapped = map_blobs
0489
0490 def __init__(self, dictionary={}, convert_timestamps=True):
0491
0492 for key in dictionary:
0493 try:
0494 if convert_timestamps:
0495 self.__dict__[key] = to_timestamp(dictionary[key])
0496 else:
0497 self.__dict__[key] = dictionary[key]
0498 except KeyError as k:
0499 continue
0500
0501 if map_blobs:
0502 def as_dicts(self, convert_timestamps=False):
0503 """
0504 Returns dictionary form of this Payload's metadata (not the actual Payload).
0505 """
0506 return {
0507 "hash" : self.hash,
0508 "object_type" : self.object_type,
0509 "version" : self.version,
0510 "insertion_time" : to_timestamp(self.insertion_time) if convert_timestamps else self.insertion_time,
0511 "data" : self.data,
0512 "streamer_info" : self.streamer_info
0513 }
0514 else:
0515 def as_dicts(self, convert_timestamps=False):
0516 """
0517 Returns dictionary form of this Payload's metadata (not the actual Payload).
0518 """
0519 return {
0520 "hash" : self.hash,
0521 "object_type" : self.object_type,
0522 "version" : self.version,
0523 "insertion_time" : to_timestamp(self.insertion_time) if convert_timestamps else self.insertion_time
0524 }
0525
0526 def __repr__(self):
0527 return '<Payload %r>' % self.hash
0528
0529 def to_array(self):
0530 return [self.hash, self.object_type, self.version, to_timestamp(self.insertion_time)]
0531
0532 def parent_tags(self, **kwargs):
0533 """
0534 Returns `amount` parent Tags ordered by Tag name.
0535 """
0536
0537 if self.empty:
0538 return None
0539 else:
0540 kwargs["payload_hash"] = self.hash
0541 query = self.session.query(IOV.tag_name)
0542 query = apply_filters(query, IOV, **kwargs)
0543 query_result = query.all()
0544 tag_names = [entry[0] for entry in query_result]
0545 amount = kwargs["amount"] if "amount" in list(kwargs.keys()) else None
0546 tags = self.session.query(Tag).filter(Tag.name.in_(tag_names)).order_by(Tag.name).limit(amount).all()
0547 return data_sources.json_data_node.make(tags)
0548
0549 def all(self, **kwargs):
0550 """
0551 Returns `amount` Payloads ordered by Payload hash.
0552 """
0553 query = self.session.query(Payload)
0554 query = apply_filters(query, Payload, **kwargs)
0555 amount = kwargs["amount"] if "amount" in list(kwargs.keys()) else None
0556 query_result = query.order_by(Payload.hash).limit(amount).all()
0557 return data_sources.json_data_node.make(query_result)
0558
0559
0560 class Record(Base):
0561 __table_args__ = schema
0562 __tablename__ = 'RECORDS'
0563
0564 headers = ["record", "object", "type"]
0565
0566 record = Column(String(100), primary_key=True, nullable=False)
0567 object = Column(String(200), nullable=False)
0568 type = Column(String(20), nullable=False)
0569
0570 def as_dicts(self):
0571 """
0572 Returns dictionary form of this Record.
0573 """
0574 return {
0575 "record" : self.record,
0576 "object" : self.object,
0577 "type" : self.type
0578 }
0579
0580 def __repr__(self):
0581 return '<Record %r>' % self.record
0582
0583 def to_array(self):
0584 return [self.record, self.object]
0585
0586 def all(self, **kwargs):
0587 """
0588 Returns `amount` Records ordered by Record record.
0589 """
0590 query = self.session.query(Record)
0591 query = apply_filters(query, Record, kwargs)
0592 amount = kwargs["amount"] if "amount" in list(kwargs.keys()) else None
0593 query_result = query.order_by(Record.record).limit(amount).all()
0594 return data_sources.json_data_node.make(query_result)
0595
0596
0597 class Tag(Base):
0598 __table_args__ = schema
0599 __tablename__ = 'TAG'
0600
0601 headers = ["name", "time_type", "object_type", "synchronization", "end_of_validity",\
0602 "description", "last_validated_time", "insertion_time", "modification_time", "protection_code"]
0603
0604 name = Column(String(4000), primary_key=True, nullable=False)
0605 time_type = Column(String(4000), nullable=False)
0606 object_type = Column(String(4000), nullable=False)
0607 synchronization = Column(String(4000), nullable=False)
0608 end_of_validity = Column(Integer, nullable=False)
0609 description = Column(String(4000), nullable=False)
0610 last_validated_time = Column(BigInteger, nullable=False)
0611 insertion_time = Column(DateTime, nullable=False)
0612 modification_time = Column(DateTime, nullable=False)
0613 protection_code = Column(Integer, nullable=False)
0614
0615 record = None
0616 label = None
0617
0618 iovs_list = relationship('IOV', backref='tag')
0619
0620 def __init__(self, dictionary={}, convert_timestamps=True):
0621
0622 for key in dictionary:
0623 try:
0624 if convert_timestamps:
0625 self.__dict__[key] = to_timestamp(dictionary[key])
0626 else:
0627 self.__dict__[key] = dictionary[key]
0628 except KeyError as k:
0629 continue
0630
0631 def as_dicts(self, convert_timestamps=False):
0632 """
0633 Returns dictionary form of this Tag.
0634 """
0635 return {
0636 "name" : self.name,
0637 "time_type" : self.time_type,
0638 "object_type" : self.object_type,
0639 "synchronization" : self.synchronization,
0640 "end_of_validity" : self.end_of_validity,
0641 "description" : self.description,
0642 "last_validated_time" : self.last_validated_time,
0643 "insertion_time" : to_timestamp(self.insertion_time) if convert_timestamps else self.insertion_time,
0644 "modification_time" : to_timestamp(self.modification_time) if convert_timestamps else self.modification_time,
0645 "record" : self.record,
0646 "label" : self.label
0647 }
0648
0649 def __repr__(self):
0650 return '<Tag %r>' % self.name
0651
0652 def to_array(self):
0653 return [self.name, self.time_type, self.object_type, self.synchronization, to_timestamp(self.insertion_time), self.description]
0654
0655 def parent_global_tags(self, **kwargs):
0656 """
0657 Returns `amount` Global Tags that contain this Tag.
0658 """
0659 if self.empty:
0660 return None
0661 else:
0662 kwargs["tag_name"] = self.name
0663 query = self.session.query(GlobalTagMap.global_tag_name)
0664 query = apply_filters(query, GlobalTagMap, **kwargs)
0665 query_result = query.all()
0666 if len(query_result) != 0:
0667 global_tag_names = [entry[0] for entry in query_result]
0668 amount = kwargs["amount"] if "amount" in list(kwargs.keys()) else None
0669 global_tags = self.session.query(GlobalTag).filter(GlobalTag.name.in_(global_tag_names)).order_by(GlobalTag.name).limit(amount).all()
0670 else:
0671 global_tags = None
0672 return data_sources.json_data_node.make(global_tags)
0673
0674 def all(self, **kwargs):
0675 """
0676 Returns `amount` Tags ordered by Tag name.
0677 """
0678 query = self.session.query(Tag)
0679 query = apply_filters(query, Tag, **kwargs)
0680 amount = kwargs["amount"] if "amount" in list(kwargs.keys()) else None
0681 query_result = query.order_by(Tag.name).limit(amount).all()
0682 return data_sources.json_data_node.make(query_result)
0683
0684 def iovs(self, **kwargs):
0685 """
0686 Returns `amount` IOVs that belong to this Tag ordered by IOV since.
0687 """
0688
0689 iovs_query = self.session.query(IOV).filter(IOV.tag_name == self.name)
0690 iovs_query = apply_filters(iovs_query, IOV, **kwargs)
0691 amount = kwargs["amount"] if "amount" in list(kwargs.keys()) else None
0692 iovs = iovs_query.order_by(IOV.since).limit(amount).all()
0693 return data_sources.json_data_node.make(iovs)
0694
0695 def latest_iov(self):
0696 """
0697 Returns the single highest since held by this Tag.
0698 Insertion times do not matter - if there are two IOVs at since > all others, both have the highest since.
0699 """
0700 iov = self.session.query(IOV).filter(IOV.tag_name == self.name).order_by(IOV.since.desc()).first()
0701 return iov
0702
0703 def __sub__(self, other):
0704 """
0705 Allows the arithmetic operator "-" to be applied to find the difference between two tags.
0706 Note: diff() is symmetric, hence tag1 - tag2 = tag2 - tag1.
0707 """
0708 return self.diff(other)
0709
0710 def diff(self, tag, short=False):
0711 """
0712 Returns the `diff` of the first Tag, and the Tag given.
0713 Summary of algorithm:
0714
0715 Compute the ordered set of iov sinces from both tags, and construct a list of triples, (since, tag1 hash, tag2 hash).
0716 Set previous_payload1 and previous_payload2 to be the first hash values from each tag for the first since in the merged list.
0717 Note: depending on where each Tag's IOVs start, 1 or both of these values can be None.
0718 Set the first_since_in_equality_range = -1, which holds the since at which the last hashes were equal in the Tags.
0719 For each triple (since, hash1, hash2),
0720
0721 If the first_since_in_equality_range = None,
0722 We are at the first since in the merged list, so set first_since... = since
0723 Note: this is so set the previous... values for the second row, since the first row will never result in a print because
0724 a row is only printed when past iovs have been processed.
0725
0726 If either hash1 or hash2 is None, set it to the previous hash found
0727 Note: if a Tag defines a hash for one since and then not another for n rows, the last defined hash will be carried through because of this.
0728
0729 If the previous found hashes were equal, that means we have equality on the range [first_since_in_equality_range, since)
0730 Note: we CANNOT conclude anything about the hashes corresponding to sinces >= since
0731 because we have no looked forward, but we do know about the previous hashes.
0732
0733 If hash1 != hash2,
0734 The region of equality has ended, and so we have that [first_since_in_equality_range, since) is equal for both Tags
0735 Hence, print that for this range we have equal hashes denoted by "=" in each hash column.
0736
0737 Else:
0738
0739 The previous hashes were not equal, BUT we must check that ths hashes on this row are not identical...
0740 If the hashes on this row are the same as the hashes above (hash1 == previous_payload1 and hash2 == previous_payload2),
0741 then we have not found the end of a region of equality!
0742 If the hashes have changed, print a row.
0743
0744 """
0745 if tag.__class__.__name__ != "Tag":
0746 raise TypeError("Tag given must be a CondDBFW Tag object.")
0747
0748
0749 iovs1 = dict([(iov.since, iov.payload_hash) for iov in self.iovs().data()])
0750 iovs2 = dict([(iov.since, iov.payload_hash) for iov in tag.iovs().data()])
0751
0752 iovs = [(x, iovs1.get(x), iovs2.get(x)) for x in sorted(set(iovs1) | set(iovs2))]
0753 iovs.append(("Infinity", 1, 2))
0754 table = []
0755
0756 previous_hash1 = None
0757 previous_hash2 = None
0758 first_since_in_equality_range = None
0759 previous_equal = False
0760
0761 for since, hash1, hash2 in iovs:
0762
0763 if first_since_in_equality_range == None:
0764
0765
0766
0767
0768 first_since_in_equality_range = since
0769 previous_hash1 = hash1
0770 previous_hash2 = hash2
0771 previous_equal = hash1 == hash2
0772 continue
0773
0774
0775
0776 if hash1 == None:
0777 hash1 = previous_hash1
0778 if hash2 == None:
0779 hash2 = previous_hash2
0780
0781 if previous_equal:
0782
0783 if hash1 != hash2:
0784 table.append({"since" : "[%s, %s)" % (first_since_in_equality_range, since), self.name : "=", tag.name : "="})
0785
0786 first_since_in_equality_range = since
0787 else:
0788
0789
0790
0791
0792 if not(hash1 == previous_hash1 and hash2 == previous_hash2):
0793 table.append({"since" : "[%s, %s)" % (first_since_in_equality_range, since), self.name : previous_hash1, tag.name : previous_hash2})
0794 first_since_in_equality_range = since
0795
0796 previous_hash1 = hash1
0797 previous_hash2 = hash2
0798 previous_equal = hash1 == hash2
0799
0800 final_list = data_sources.json_data_node.make(table)
0801 return final_list
0802
0803 def merge_into(self, tag, range_object):
0804 """
0805 Given another connection, apply the 'merge' algorithm to merge the IOVs from this Tag
0806 into the IOVs of the other Tag.
0807
0808 tag : CondDBFW Tag object that the IOVs from this Tag should be merged into.
0809
0810 range_object : CondDBFW.data_sources.Range object to describe the subset of IOVs that should be copied
0811 from the database this Tag belongs to.
0812
0813 Script originally written by Joshua Dawes,
0814 and adapted by Giacomo Govi, Gianluca Cerminara and Giovanni Franzoni.
0815 """
0816
0817 oracle_tag = self
0818 merged_tag_name = oracle_tag.name + "_merged"
0819
0820
0821 since_range = range_object
0822
0823
0824
0825
0826 sqlite_tag = tag
0827 if sqlite_tag == None:
0828 raise TypeError("Tag to be merged cannot be None.")
0829
0830 sqlite_iovs = sqlite_tag.iovs().data()
0831 sqlite_tag.iovs().as_table()
0832
0833 new_tag = self.connection.models["tag"](sqlite_tag.as_dicts(convert_timestamps=False), convert_timestamps=False)
0834 new_tag.name = merged_tag_name
0835
0836 imported_iovs = oracle_tag.iovs(since=since_range).data()
0837
0838 for i in range(0, len(imported_iovs)):
0839 imported_iovs[i].source = "oracle"
0840
0841 sqlite_iovs_sinces=[]
0842 for i in range(0, len(sqlite_iovs)):
0843 sqlite_iovs[i].source = "sqlite"
0844 sqlite_iovs_sinces.append(sqlite_iovs[i].since)
0845
0846
0847 print(sqlite_iovs_sinces)
0848
0849 new_iovs_list = imported_iovs + sqlite_iovs
0850 new_iovs_list = sorted(new_iovs_list, key=lambda iov : iov.since)
0851
0852 for (n, iov) in enumerate(new_iovs_list):
0853
0854 if iov.source == "oracle":
0855 if new_iovs_list[n].since in sqlite_iovs_sinces:
0856
0857
0858 iov.source = "tobedeleted"
0859 else:
0860
0861
0862 for i in reversed(list(range(0,n))):
0863 if new_iovs_list[i].source == "sqlite":
0864 print("change %s to %s at since %d" % (iov.payload_hash, new_iovs_list[i].payload_hash, iov.since))
0865 iov.payload_hash = new_iovs_list[i].payload_hash
0866 break
0867
0868
0869 new_iov_list_copied = []
0870
0871 for iov in new_iovs_list:
0872
0873 if iov.source != "tobedeleted":
0874 new_iov_list_copied.append(iov)
0875
0876 new_iov_list_copied = sorted(new_iov_list_copied, key=lambda iov : iov.since)
0877
0878 now = datetime.datetime.utcnow()
0879
0880 new_iovs = []
0881 for iov in new_iov_list_copied:
0882 new_iovs.append( self.connection.models["iov"](iov.as_dicts(convert_timestamps=False), convert_timestamps=False) )
0883 for iov in new_iovs:
0884 iov.insertion_time = now
0885 iov.tag_name = merged_tag_name
0886
0887 new_tag.iovs_list = new_iovs
0888
0889 return new_tag
0890
0891
0892
0893 class TagAuthorization(Base):
0894 __table_args__ = schema
0895 __tablename__ = 'TAG_AUTHORIZATION'
0896
0897 headers = ["tag_name", "access_type", "credential", "credential_type"]
0898
0899 tag_name = Column(String(100), ForeignKey(fk_schema_prefix + 'TAG.name'), primary_key=True, nullable=False)
0900 access_type = Column(Integer, nullable=False)
0901 credential = Column(String(100), primary_key=True, nullable=False)
0902 credential_type = Column(Integer, nullable=False)
0903
0904 def as_dicts(self):
0905 """
0906 Returns dictionary form of this Tag Authorization.
0907 """
0908 return {
0909 "tag_name" : self.tag_name,
0910 "access_type" : self.access_type,
0911 "credential" : self.credential,
0912 "credential_type" : self.credential_type
0913 }
0914
0915 def __repr__(self):
0916 return '<TagAuthorization %s %s %s %s>' % (self.tag_name, self.access_type, self.credential, self.credential_type)
0917
0918 def to_array(self):
0919 return [self.tag_name, self.access_type, self.credential, self.credential_type]
0920
0921 def all(self, **kwargs):
0922 """
0923 Returns `amount` Records ordered by Record record.
0924 """
0925 query = self.session.query(TagAuthorization)
0926 query = apply_filters(query, TagAuthorization, kwargs)
0927 amount = kwargs["amount"] if "amount" in list(kwargs.keys()) else None
0928 query_result = query.order_by(TagAuthorization.tag).limit(amount).all()
0929 return data_sources.json_data_node.make(query_result)
0930
0931 classes = {"globaltag" : GlobalTag, "iov" : IOV, "globaltagmap" : GlobalTagMap,\
0932 "payload" : Payload, "tag" : Tag, "TagAuthorization": TagAuthorization, "Base" : Base}
0933
0934 if class_name == None:
0935 return classes
0936 else:
0937 return classes[class_name]