From 264dc6aeaec7a5d72714ddc8703e8885913da5c1 Mon Sep 17 00:00:00 2001 From: Pierre Lasorak Date: Tue, 6 Feb 2024 10:14:01 +0100 Subject: [PATCH 1/5] update our fork --- src/elisa_client_api/core/authentication.py | 22 ++- src/elisa_client_api/core/message.py | 66 ++++---- src/elisa_client_api/core/messageField.py | 112 +++++++------- src/elisa_client_api/core/request.py | 90 +++++------ src/elisa_client_api/core/restServer.py | 141 +++++++++--------- src/elisa_client_api/core/searchField.py | 9 +- src/elisa_client_api/core/serializer.py | 67 +++++---- src/elisa_client_api/elisa.py | 5 +- src/elisa_client_api/exception.py | 19 +-- src/elisa_client_api/messageInsert.py | 7 +- src/elisa_client_api/messageRead.py | 3 +- src/elisa_client_api/messageReply.py | 13 +- src/elisa_client_api/messageUpdate.py | 11 +- src/elisa_client_api/optionsBuilder.py | 34 +++-- src/elisa_client_api/scripts/elisa_config.py | 27 ++-- src/elisa_client_api/scripts/elisa_get.py | 28 ++-- src/elisa_client_api/scripts/elisa_insert.py | 30 ++-- src/elisa_client_api/scripts/elisa_reply.py | 32 ++-- src/elisa_client_api/scripts/elisa_update.py | 26 ++-- .../scripts/elisa_utilhelper.py | 45 +++--- src/elisa_client_api/searchCriteria.py | 49 +++--- 21 files changed, 437 insertions(+), 399 deletions(-) diff --git a/src/elisa_client_api/core/authentication.py b/src/elisa_client_api/core/authentication.py index eff3768..32e0832 100644 --- a/src/elisa_client_api/core/authentication.py +++ b/src/elisa_client_api/core/authentication.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env tdaq_python #-------------------------------------------------------------------------------------- # Title : ELisA authentication. # Project : ATLAS, TDAQ, ELisA @@ -18,6 +18,10 @@ # 18/Dec/2012: created. #-------------------------------------------------------------------------------------- +from future import standard_library +standard_library.install_aliases() +from builtins import str +from builtins import object from elisa_client_api.exception import ArgumentError @@ -49,7 +53,8 @@ def __init__(self, username=None, password=None, ssocookie=None): cj = http.cookiejar.MozillaCookieJar() cj.load(filename=ssocookie, ignore_discard=True, ignore_expires=True) for cookie in cj: - if cookie.name.startswith('_shibsession'): + # if True == cookie.name.startswith('_shibsession'): + if cookie.name.startswith('_shibsession') or cookie.name == 'mod_auth_openidc_session': self.__ssocookie = cookie.name + '=' + cookie.value # ------------------ @@ -63,7 +68,7 @@ def addAuthentication(self, req): else: req.add_header("Authorization", "Basic %s" % self._getEncodedCredentials().decode()) - def addAuthenticationPy3(self, req): + def addAuthenticationPy3(self,req): """ Adds the appropriate authentication header in the http request. """ if self.__ssocookie != None: @@ -71,15 +76,6 @@ def addAuthenticationPy3(self, req): else: req.headers['Authorization'] = "Basic %s" % self._getEncodedCredentials().decode() - def addAuthenticationToDict(self, d): - """ Adds the appropriate authentication header in the http request. - """ - - if self.__ssocookie != None: - d['Cookie'] = self.__ssocookie - else: - d['Authorization'] = "Basic %s" % self._getEncodedCredentials().decode() - # ------------------- # - Private methods - @@ -88,4 +84,4 @@ def _getEncodedCredentials(self): """ Encodes the string username:password with basic 64 """ import base64 - return base64.encodestring(('%s:%s' % (self.__username, self.__password)).encode())[:-1] + return base64.encodebytes(('%s:%s' % (self.__username, self.__password)).encode())[:-1] diff --git a/src/elisa_client_api/core/message.py b/src/elisa_client_api/core/message.py index 40c96d0..3e853ca 100644 --- a/src/elisa_client_api/core/message.py +++ b/src/elisa_client_api/core/message.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env tdaq_python #-------------------------------------------------------------------------------------- # Title : Logbook message # Project : ATLAS, TDAQ, ELisA @@ -17,6 +17,11 @@ # 05/Dec/2012: created. #-------------------------------------------------------------------------------------- +from __future__ import absolute_import +from builtins import str +from builtins import object +import string + from .messageField import SimpleField, AttachmentField, SystemsAffectedField, OptionField class Status(object): @@ -28,7 +33,7 @@ class Status(object): class Message(object): """ Class with all the fields of a logbook message. - + Accessors will be provided as needed in derived classes. """ # ------------------ @@ -39,14 +44,14 @@ def __init__(self, id): # - Private data attributes - # --------------------------- - # The field name parameter is the same as those use in the ELisA server. - # This schema allows for generic code when serializing, deserializing + # The field name parameter is the same as those use in the ELisA server. + # This schema allows for generic code when serializing, deserializing # and printing the fields. self._id = SimpleField('id', id) self._logbook = SimpleField('logbook') self._username = SimpleField('username') self._author = SimpleField('author') - self._date = SimpleField('date') + self._date = SimpleField('date') self._subject = SimpleField('subject') self._message_type = SimpleField('message_type') self._systems_affected = SystemsAffectedField('systems_affected') @@ -61,27 +66,27 @@ def __init__(self, id): self._thread_head = SimpleField('thread_head') self._valid = SimpleField('valid') self._encoding = SimpleField('encoding') - - + + def __str__(self): dump = "" fields = self.getFieldNames() for field in fields: - dump += str(getattr(self, field)) + '\n' + dump += str(getattr(self, field)) + '\n' return dump - - + + def getFieldNames(self): return [attr for attr in dir(self) if getattr(self, attr).__class__.__name__ == "SimpleField" \ or getattr(self, attr).__class__.__name__ == "AttachmentField" \ or getattr(self, attr).__class__.__name__ == "OptionField" \ or getattr(self, attr).__class__.__name__ == "SystemsAffectedField"] - - + + def getTag(self): return "_" - - + + # -------------------- # - Property methods - # -------------------- @@ -94,37 +99,37 @@ def id(self): def logbook(self): """ Message logbook field. """ return self._logbook.value - + @property def userName(self): """ Message user name field. """ return self._username.value - + @property def author(self): """ Message author field. """ return self._author.value - + @property def date(self): """ Message date field. """ return self._date.value - + @property def subject(self): """ Message subject field. """ return self._subject.value - + @property def type(self): """ Message type field. """ return self._message_type.value - + @property def options(self): """ Message options field. """ - return self._options .value - + return self._options .value + @property def systemsAffected(self): """ Message systems affected field. """ @@ -139,45 +144,44 @@ def body(self): def host(self): """ Message host field. """ return self._host.value - + @property def hasReplies(self): """ Message has replies field. """ return self._has_replies.value - + @property def replyTo(self): """ Message reply to field. """ return self._reply_to.value - + @property def hasAttachments(self): """ Message has attachments field. """ return self._has_attachments.value - + @property def attachments(self): """ Message attachments field. """ return self._attachments.value - + @property def status(self): """ Message status field. """ return self._status.value - + @property def threadHead(self): """ Message thread head field. """ return self._thread_head.value - + @property def valid(self): """ Message valid field. """ return self._valid.value - + @property def encoding(self): """ Message encoding field. """ return self._encoding.value - diff --git a/src/elisa_client_api/core/messageField.py b/src/elisa_client_api/core/messageField.py index 5599174..c521d2e 100644 --- a/src/elisa_client_api/core/messageField.py +++ b/src/elisa_client_api/core/messageField.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env tdaq_python #-------------------------------------------------------------------------------------- # Title : Logbook message fields # Project : ATLAS, TDAQ, ELisA @@ -19,15 +19,18 @@ # 23/Jan/2013: use UTF8 for the name and value of the message fields. #-------------------------------------------------------------------------------------- +from builtins import str +from past.builtins import basestring +from builtins import object import xml.etree.ElementTree as ET class SimpleField(object): """ Class providing functionality to define a simple message field. - - Simple message fields are those that only contain the field value + + Simple message fields are those that only contain the field value but no nested fields. - + Assume all fields are string type even those that only have numbers """ # ------------------ @@ -36,44 +39,45 @@ class SimpleField(object): def __init__(self, name, value = None): self.__name = name.encode('utf-8') self.__value = str(value) if value != None else None - + def __str__(self): return '{0:19}: {1}'.format(self.name.decode('utf-8'), self.value) - + def serialize(self, parentNode): if self.value: node = ET.SubElement(parentNode, self.name.decode('utf-8')) node.text = str(self.value) - + def deserialize(self, node): - self.value = node.text.encode('utf-8').decode('utf-8') + if node.text != None: + self.value = node.text.encode('utf-8').decode('utf-8') + - # -------------------- # - Property methods - # -------------------- @property def name(self): return self.__name - + @property def value(self): return self.__value @value.setter def value(self, value): self.__value = value - + # --------------------------- # - Private data attributes - # --------------------------- __name = None __value = None - + class SystemsAffectedField(object): """ Class providing functionality to define the message systems affected field. - + This field contains a list with the systems affected names. """ # Format: @@ -82,7 +86,7 @@ class SystemsAffectedField(object): # DAQ # HLT # - + # ------------------ # - Public methods - # ------------------ @@ -92,14 +96,14 @@ def __init__(self, name): # --------------------------- self.__name = name.encode('utf-8') self.__value = list() - + def __str__(self): return '{0:19}: {1}'.format(self.name.decode('utf-8'), self.value) - + def serialize(self, parentNode): if not self.value: return - + if len(self.value) > 0: rootNode = ET.SubElement(parentNode, self.name.decode('utf-8')) countNode = ET.SubElement(rootNode, 'count') @@ -107,29 +111,29 @@ def serialize(self, parentNode): for system in self.value: sysNode = ET.SubElement(rootNode, 'system_affected') sysNode.text = system - - + + def deserialize(self, node): [self.value.append(child.text.encode('utf-8').decode('utf-8')) for child in node.findall('system_affected')] - + # -------------------- # - Property methods - # -------------------- @property def name(self): return self.__name - + @property def value(self): return self.__value @value.setter def value(self, value): self.__value = value - - + + class AttachmentField(object): """ Class providing functionality to define the message attachment field. - + This field contains a list of tuples with the following simple fields: filename, ID and link """ @@ -156,11 +160,11 @@ def __init__(self, name): def __str__(self): if not self.value: return '{0:19}: 0'.format(self.name.decode('utf-8')) - + dump = '{0:19}: {1}'.format(self.name.decode('utf-8'), len(self.value)) # Message insertion encapsulates attachments as a list of strings. # Message retrieval encapsulates attachments as a list of tuples. - if isinstance(self.value[0], str): + if isinstance(self.value[0], basestring): for attach in self.value: dump += '\n |---- {0}'.format(attach) else: @@ -169,7 +173,7 @@ def __str__(self): dump += '\n |---- {0:4}: {1}'.format("Name", attach[1]) dump += '\n |---- {0:4}: {1}'.format("Link", attach[2]) return dump - + def serialize(self, parentNode): # Attachments are never serialized because its insertion follows # a different path. @@ -177,9 +181,9 @@ def serialize(self, parentNode): def deserialize(self, node): self.value = list() - [self.__value.append((child.find('ID').text.encode('utf-8').decode('utf-8'), - child.find('filename').text.encode('utf-8').decode('utf-8'), - child.find('link').text.encode('utf-8').decode('utf-8'))) + [self.__value.append((child.find('ID').text.encode('utf-8').decode('utf-8'), + child.find('filename').text.encode('utf-8').decode('utf-8'), + child.find('link').text.encode('utf-8').decode('utf-8'))) for child in node.findall('attachment')] @@ -189,18 +193,18 @@ def deserialize(self, node): @property def name(self): return self.__name - + @property def value(self): return self.__value @value.setter def value(self, value): self.__value = value - - + + class OptionField(object): """ Class providing functionality to define the message option field. - + This field contains a list of tuples with the following fields: name, value, list of OptionField """ @@ -218,22 +222,22 @@ class OptionField(object): # - + # ------------------ # - Public methods - # ------------------ - def __init__(self, name): + def __init__(self, name): # --------------------------- # - Private data attributes - # --------------------------- self.__name = name.encode('utf-8') self.__value = list() - - + + def __str__(self): if not self.value: return '{0:19}: 0'.format(self.name.decode('utf-8')) - + dump = '{0:19}: {1}'.format(self.name.decode('utf-8'), len(self.value)) # First level options for option in self.value: @@ -243,14 +247,14 @@ def __str__(self): if innerOptions != None: for innerOpt in innerOptions: dump += '\n |---- {0:14}: {1}'.format(innerOpt['name'], innerOpt['value']) - + return dump - - + + def serialize(self, parentNode): if not self.value: return - + count = len(self.value) if count == 0: return @@ -270,33 +274,33 @@ def serialize(self, parentNode): ET.SubElement(innerOptionNode, 'name').text = str(innerOption['name']) ET.SubElement(innerOptionNode, 'value').text = str(innerOption['value']) ET.SubElement(optionsNode, 'count').text = str(len(innerOptions)) - + ET.SubElement(rootNode, 'count').text = str(count) - + def deserialize(self, node): optionNodes = node.findall('option') # First level options for option in optionNodes: # Second level options listInnerOpts = list() - [[listInnerOpts.append( { 'name' : innerOptionNodes.find('name').text.encode('utf-8').decode('utf-8'), - 'value' : innerOptionNodes.find('value').text.encode('utf-8').decode('utf-8') }) - for innerOptionNodes in innerOptionsNode.findall('option')] - for innerOptionsNode in option.findall('options')] - + [[listInnerOpts.append( { 'name' : innerOptionNodes.find('name').text.encode('utf-8').decode('utf-8'), + 'value' : innerOptionNodes.find('value').text.encode('utf-8').decode('utf-8') }) + for innerOptionNodes in innerOptionsNode.findall('option')] + for innerOptionsNode in option.findall('options')] + self.value.append({ 'name' : option.find('name').text.encode('utf-8').decode('utf-8'), 'value' : option.find('value').text.encode('utf-8').decode('utf-8'), 'options' : listInnerOpts }) - - + + # -------------------- # - Property methods - # -------------------- @property def name(self): return self.__name - + @property def value(self): return self.__value @@ -304,4 +308,4 @@ def value(self): def value(self, value): self.__value = value - + diff --git a/src/elisa_client_api/core/request.py b/src/elisa_client_api/core/request.py index 8e52b79..f972115 100644 --- a/src/elisa_client_api/core/request.py +++ b/src/elisa_client_api/core/request.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env tdaq_python #-------------------------------------------------------------------------------------- # Title : HTTP request # Project : ATLAS, TDAQ, ELisA @@ -18,6 +18,12 @@ # 08/Jan/2012: add authentication #-------------------------------------------------------------------------------------- +from __future__ import absolute_import +from future import standard_library +standard_library.install_aliases() +from builtins import str +from builtins import object +import urllib.request, urllib.parse, urllib.error import requests import os import mimetypes @@ -45,27 +51,23 @@ def get(self): Returns: the data returned by the server. Throws: RestServerError if the request fails. """ - headers = { - 'Accept': 'application/xml' - } - self.__authentication.addAuthenticationToDict(headers) + req = urllib.request.Request(self.__url) + self.__authentication.addAuthentication(req) + req.add_header('Accept', 'application/xml') + req.get_method = lambda: 'GET' try: - response = requests.get( - self.__url, - headers = headers, - verify = False, - ) + response = urllib.request.urlopen(req).read() self._checkSsoAuthen(response) - return response.content - except requests.exceptions.HTTPError as ex: + return response + except urllib.error.HTTPError as ex: # The returned code 302 is expected. The reason why is # explained in http://en.wikipedia.org/wiki/HTTP_302 - # if ex.code == 302: - # return ex.read() + if ex.code == 302: + return ex.read() # Otherwise it is a valid error, raise it. raise RestServerError(str(ex) + ". REST server error: " + ex.read().decode()) - except requests.URLRequired as ex: #? + except urllib.error.URLError as ex: raise RestServerError(str(ex)) @@ -76,26 +78,19 @@ def post(self, message): Returns: the data returned by the server. Throws: RestServerError if the request fails. """ - - headers = { - 'Content-Type': 'application/xml', - 'Accept': 'application/xml', - } - - self.__authentication.addAuthenticationToDict(headers) + req = urllib.request.Request(self.__url,message) + self.__authentication.addAuthentication(req) + req.add_header('Content-Type', 'application/xml') + req.add_header('Accept', 'application/xml') + req.get_method = lambda: 'POST' try: - response = requests.post( - self.__url, - data = message, - headers = headers, - verify = False, - ) + response = urllib.request.urlopen(req).read() self._checkSsoAuthen(response) - return response.content - except requests.exceptions.HTTPError as ex: + return response + except urllib.error.HTTPError as ex: raise RestServerError(str(ex) + ". REST server error: " + ex.read().decode()) - except requests.exceptions.URLRequired as ex: + except urllib.error.URLError as ex: raise RestServerError(str(ex)) @@ -106,26 +101,19 @@ def put(self, message): Returns: the data returned by the server. Throws: RestServerError if the request fails. """ - - headers = { - 'Content-Type': 'application/xml', - 'Accept': 'application/xml', - } - - self.__authentication.addAuthenticationToDict(headers) + req = urllib.request.Request(self.__url,message) + self.__authentication.addAuthentication(req) + req.add_header('Content-Type', 'application/xml') + req.add_header('Accept', 'application/xml') + req.get_method = lambda: 'PUT' try: - response = requests.put( - self.__url, - data = message, - headers = headers, - verify = False, - ) + response = urllib.request.urlopen(req).read() self._checkSsoAuthen(response) - return response.content - except requests.exceptions.HTTPError as ex: + return response + except urllib.error.HTTPError as ex: raise RestServerError(str(ex) + ". REST server error: " + ex.read().decode()) - except requests.exceptions.URLRequired as ex: + except urllib.error.URLError as ex: raise RestServerError(str(ex)) @@ -146,6 +134,7 @@ def multipart(self, message=None, attachments=None): count=0 for attachment in attachments: files['file'+str(count)] = (os.path.basename(attachment), open(attachment, 'rb'), mimetypes.guess_type(attachment)[0] or 'application/octet-stream') + count+=1 request = requests.Request('POST', self.__url, files=files) prepped = session.prepare_request(request) self.__authentication.addAuthenticationPy3(prepped) @@ -158,7 +147,7 @@ def multipart(self, message=None, attachments=None): return response.content except requests.exceptions.HTTPError as ex: raise RestServerError(str(ex) + ". REST server error: " + ex.read().decode()) - #except urllib3.error.URLError as ex: + #except urllib.error.URLError as ex: # raise RestServerError(str(ex)) # ------------------- @@ -166,7 +155,6 @@ def multipart(self, message=None, attachments=None): # ------------------- def _checkSsoAuthen(self, response): # Is there a better way to detect this? - content = response.content.decode() - if ' 0 else "" opts.append(optionVals) - - return opts - - + + return opts + + def deserializeSystemsAffected(self, xmlStr): - """ Creates a list with the systems affected as defined in the + """ Creates a list with the systems affected as defined in the ElisA logbook configuration. - + xmlStr: the XML string representation the logbook configuration. Returns: a list with the systems affected. Throws: FormatterError if deserializing the types fails. @@ -149,7 +154,7 @@ def deserializeSystemsAffected(self, xmlStr): # ------------------- def _deserializeMessage(self, node): """ Creates an object of type MessageRead from an XML format string. - + node: the XML node representing the logbook message. Returns: an object of type MessageRead. Throws: TBD diff --git a/src/elisa_client_api/elisa.py b/src/elisa_client_api/elisa.py index 10002d3..021b834 100644 --- a/src/elisa_client_api/elisa.py +++ b/src/elisa_client_api/elisa.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env tdaq_python #-------------------------------------------------------------------------------------- # Title : Interface to the ELisA logbook database. # Project : ATLAS, TDAQ, ELisA @@ -19,6 +19,8 @@ # 11/Feb/2013: add option to show attributes when searching for messages. #-------------------------------------------------------------------------------------- +from __future__ import absolute_import +from builtins import object from elisa_client_api.core.restServer import RestServer from elisa_client_api.core.authentication import Authentication @@ -189,3 +191,4 @@ def getSystemsAffected(self, msgType=None): # - Private data attributes - # --------------------------- _server = None # ELisA server. + diff --git a/src/elisa_client_api/exception.py b/src/elisa_client_api/exception.py index 4b7eecc..73699de 100644 --- a/src/elisa_client_api/exception.py +++ b/src/elisa_client_api/exception.py @@ -1,6 +1,6 @@ -#!/usr/bin/env python +#!/usr/bin/env tdaq_python #-------------------------------------------------------------------------------------- -# Title : Elisa exceptions +# Title : Elisa exceptions # Project : ATLAS, TDAQ, ELisA #-------------------------------------------------------------------------------------- # File : exception.py @@ -9,7 +9,7 @@ # Revision : 0 $ #-------------------------------------------------------------------------------------- # Class : ElisaError, ArgumentError -# Description : Class encapsulating errors that might be raised. +# Description : Class encapsulating errors that might be raised. #-------------------------------------------------------------------------------------- # Copyright (c) 2012 by University of California, Irvine. All rights reserved. #-------------------------------------------------------------------------------------- @@ -18,6 +18,7 @@ # 18/Mar/2013: parse the Rest Server error. #-------------------------------------------------------------------------------------- +from builtins import str import sys @@ -50,16 +51,16 @@ def __init__(self, reason): self.__reason += '[' + entry.attrib['key'] + ']->' + entry.text if entry != entries[-1]: self.__reason += ', ' - else: + else: self.__reason = reason frame = sys._getframe(3) self.__operation = frame.f_code.co_filename + "[" + frame.f_code.co_name + "():" + str(frame.f_lineno) + ']' - + def __str__(self): return "Exception raised at " + self.__operation + ". Reason: " + self.__reason + "." - + class RestServerError(ElisaError): """ Exception thrown when an error occurs whilst accessing the rest server. @@ -67,16 +68,16 @@ class RestServerError(ElisaError): def __init__(self, reason): super(RestServerError, self).__init__("access to the REST server failed. {0}".format(reason)) - + class ArgumentError(ElisaError): """ Exception thrown when an argument is wrongly passed to the API """ def __init__(self, argument): super(ArgumentError, self).__init__("wrong argument. {0}".format(argument)) - + class FileError(ElisaError): """ Elisa exception thrown when an argument is wrongly passed to the API """ pass - + diff --git a/src/elisa_client_api/messageInsert.py b/src/elisa_client_api/messageInsert.py index 11e6e7d..97930ff 100644 --- a/src/elisa_client_api/messageInsert.py +++ b/src/elisa_client_api/messageInsert.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env tdaq_python #-------------------------------------------------------------------------------------- # Title : Logbook message insert # Project : ATLAS, TDAQ, ELisA @@ -17,6 +17,7 @@ # 27/Nov/2012: created. #-------------------------------------------------------------------------------------- +from __future__ import absolute_import from elisa_client_api.messageReply import MessageReply from elisa_client_api.core.message import Message @@ -26,8 +27,8 @@ class MessageInsert(MessageReply): """ def __init__(self): - super(MessageInsert, self).__init__(None) - + super(MessageInsert, self).__init__(None) + # -------------------- # - Property methods - # -------------------- diff --git a/src/elisa_client_api/messageRead.py b/src/elisa_client_api/messageRead.py index 74076f3..0fef2a9 100644 --- a/src/elisa_client_api/messageRead.py +++ b/src/elisa_client_api/messageRead.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env tdaq_python #-------------------------------------------------------------------------------------- # Title : Logbook message read # Project : ATLAS, TDAQ, ELisA @@ -17,6 +17,7 @@ # 27/Nov/2012: created. #-------------------------------------------------------------------------------------- +from __future__ import absolute_import from elisa_client_api.core.message import Message diff --git a/src/elisa_client_api/messageReply.py b/src/elisa_client_api/messageReply.py index 2a2a36d..3ec36fc 100644 --- a/src/elisa_client_api/messageReply.py +++ b/src/elisa_client_api/messageReply.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env tdaq_python #-------------------------------------------------------------------------------------- # Title : Logbook message reply # Project : ATLAS, TDAQ, ELisA @@ -17,6 +17,7 @@ # 27/Nov/2012: created. #-------------------------------------------------------------------------------------- +from __future__ import absolute_import from elisa_client_api.messageUpdate import MessageUpdate from elisa_client_api.core.message import Message @@ -26,11 +27,11 @@ class MessageReply(MessageUpdate): """ def __init__(self, msgId=None): - super(MessageReply, self).__init__(msgId) - + super(MessageReply, self).__init__(msgId) + # -------------------- # - Property methods - - # -------------------- + # -------------------- @Message.options.setter def options(self, value): self._options.value = value @@ -38,7 +39,7 @@ def options(self, value): @Message.status.setter def status(self, value): self._status.value = value - + @Message.author.setter def author(self, value): self._author.value = value @@ -46,7 +47,7 @@ def author(self, value): @Message.systemsAffected.setter def systemsAffected(self, value): self._systems_affected.value = value - + @Message.subject.setter def subject(self, value): self._subject.value = value diff --git a/src/elisa_client_api/messageUpdate.py b/src/elisa_client_api/messageUpdate.py index e465476..cbb1f18 100644 --- a/src/elisa_client_api/messageUpdate.py +++ b/src/elisa_client_api/messageUpdate.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env tdaq_python #-------------------------------------------------------------------------------------- # Title : Logbook message update # Project : ATLAS, TDAQ, ELisA @@ -17,6 +17,7 @@ # 27/Nov/2012: created. #-------------------------------------------------------------------------------------- +from __future__ import absolute_import from elisa_client_api.messageRead import MessageRead from elisa_client_api.core.message import Message @@ -24,24 +25,24 @@ class MessageUpdate(MessageRead): """ Class providing accessors for the update operation. """ - + # ------------------ # - Public methods - # ------------------ def __init__(self, msgId): super(MessageUpdate, self).__init__(msgId) - + # -------------------- # - Property methods - # -------------------- @Message.body.setter def body(self, value): self._body.value = value - + @Message.attachments.setter def attachments(self, value): self._attachments.value = value - + @Message.date.setter def date(self, value): self._date.value = value diff --git a/src/elisa_client_api/optionsBuilder.py b/src/elisa_client_api/optionsBuilder.py index 405ab7a..d829d47 100644 --- a/src/elisa_client_api/optionsBuilder.py +++ b/src/elisa_client_api/optionsBuilder.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env tdaq_python #-------------------------------------------------------------------------------------- # Title : Logbook message options field builder # Project : ATLAS, TDAQ, ELisA @@ -9,8 +9,8 @@ # Revision : 0 $ #-------------------------------------------------------------------------------------- # Class : OptionsBuilder -# Description : Helper to build the options field which can have multiple levels -# of nested options. Note the user can directly build the list of +# Description : Helper to build the options field which can have multiple levels +# of nested options. Note the user can directly build the list of # options herself without using this helper class. #-------------------------------------------------------------------------------------- # Copyright (c) 2012 by University of California, Irvine. All rights reserved. @@ -19,30 +19,32 @@ # 13/Dec/2012: created. #-------------------------------------------------------------------------------------- +from builtins import str +from builtins import object class OptionsBuilder(object): """ Class providing functionality to build the options fields. """ # Format - # [ { 'name' : 'option1', - # 'value' : value1, + # [ { 'name' : 'option1', + # 'value' : value1, # 'options' : ( { 'name' : 'subOption1', 'value' : "subValue1" }, # { 'name' : 'subOption2', 'value' : "subValue2" } # ) - # { 'name' : 'option2', + # { 'name' : 'option2', # 'value' : 'value2' } - # ] + # ] # ------------------ # - Public methods - - # ------------------ + # ------------------ def __init__(self, name = "Root", value = None): self.__name = name self.__value = value self.__innerOptions = list() - - + + def addOption(self, name, value): """ Creates an option, adds it to this option's level and returns it. - + name: name of this option. value: value of this option. Returns: an object of type Option. @@ -52,7 +54,7 @@ def addOption(self, name, value): self.__innerOptions.append(option) return option - + def toList(self): """ Returns a list of options that can be used to insert a message. @@ -62,8 +64,8 @@ def toList(self): for option in self.__innerOptions: optList.append(option.__toDict()) return optList - - + + # ------------------- # - Private methods - # ------------------- @@ -71,9 +73,9 @@ def __toDict(self): innerOptsList = list() for innerOption in self.__innerOptions: innerOptsList.append(innerOption.__toDict()) - + optDic = {'name' : self.__name, 'value' : str(self.__value) } if len(innerOptsList) > 0: optDic['options'] = innerOptsList - + return optDic diff --git a/src/elisa_client_api/scripts/elisa_config.py b/src/elisa_client_api/scripts/elisa_config.py index e7bf880..ff61731 100755 --- a/src/elisa_client_api/scripts/elisa_config.py +++ b/src/elisa_client_api/scripts/elisa_config.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env tdaq_python #-------------------------------------------------------------------------------------- # Title : Binary to retrieve the Elisa configuration. # Project : ATLAS, TDAQ, ELisA @@ -17,23 +17,28 @@ # 04/Feb/2013: created. #-------------------------------------------------------------------------------------- +from __future__ import print_function +from __future__ import absolute_import +from builtins import str import logging from elisa_client_api.exception import * from elisa_client_api.elisa import Elisa -from elisa_client_api.scripts.elisa_utilhelper import * +import elisa_utilhelper as euh __elisaUtilName__ = 'elisa_config' -from elisa_client_api import __version__ -__author__ = 'Raul Murillo Garcia & Pierre Lasorak ' +__version_info__ = ('0', '0', '1') +__version__ = '.'.join(__version_info__) +__author__ = 'Raul Murillo Garcia ' -def main(): + +if __name__ == '__main__': # Command line arguments availableOpts = ['version', 'verbosity', 'server', 'sso', 'ldap', 'type'] mandatoryArgs = [] - parser, cmdlArgs = buildCommandLineArguments(__elisaUtilName__, availableOpts, mandatoryArgs) + parser, cmdlArgs = euh.buildCommandLineArguments(__elisaUtilName__, availableOpts, mandatoryArgs) if True == cmdlArgs.version: print('\n' + __elisaUtilName__ + ' ' + __version__ + ' (' + __author__ + ')\n') @@ -42,11 +47,11 @@ def main(): # Configure the logging module logger = logging.getLogger('elisa_get_logger') logging.basicConfig(format='%(asctime)s %(funcName)s:%(levelno)s [%(levelname)s]: %(message)s') - logger.setLevel(getLoggingLevel(cmdlArgs.verbosity)) + logger.setLevel(euh.getLoggingLevel(cmdlArgs.verbosity)) elisaArgs = dict() - elisaArgs['connection'] = getElisaServer(cmdlArgs.server) + getElisaURL() - elisaArgs.update(parseCredentials(cmdlArgs)) + elisaArgs['connection'] = euh.getElisaServer(cmdlArgs.server) + euh.getElisaURL() + elisaArgs.update(euh.parseCredentials(cmdlArgs)) elisa = Elisa(**elisaArgs) try: @@ -76,7 +81,3 @@ def main(): print("\n") except ElisaError as ex: logger.error(str(ex)) - - -if __name__ == '__main__': - main() diff --git a/src/elisa_client_api/scripts/elisa_get.py b/src/elisa_client_api/scripts/elisa_get.py index 3a1f570..c956e8f 100755 --- a/src/elisa_client_api/scripts/elisa_get.py +++ b/src/elisa_client_api/scripts/elisa_get.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env tdaq_python #-------------------------------------------------------------------------------------- # Title : Binary to retrieve messages from Elisa. # Project : ATLAS, TDAQ, ELisA @@ -19,16 +19,20 @@ # 04/Feb/2013: attachmentsDst instead of attachPath. #-------------------------------------------------------------------------------------- +from __future__ import print_function +from __future__ import absolute_import +from builtins import str import logging from elisa_client_api.exception import * from elisa_client_api.elisa import Elisa -from elisa_client_api.scripts.elisa_utilhelper import * +import elisa_client_api.scripts.elisa_utilhelper as euh __elisaUtilName__ = 'elisa_get' -from elisa_client_api import __version__ -__author__ = 'Raul Murillo Garcia & Pierre Lasorak ' +__version_info__ = ('0', '0', '2') +__version__ = '.'.join(__version_info__) +__author__ = 'Raul Murillo Garcia ' def writeAttachments(elisa, message, path): @@ -46,7 +50,6 @@ def writeAttachments(elisa, message, path): logger.error(str(ex)) - def main(): # Command line arguments availableArgs = ['version', 'verbosity', 'server', 'sso', @@ -55,7 +58,7 @@ def main(): 'status', 'since', 'to', 'attributes', 'interval', 'limit', 'attachmentsDst'] mandatoryArgs = [] - parser, cmdlArgs = buildCommandLineArguments(__elisaUtilName__, availableArgs, mandatoryArgs) + parser, cmdlArgs = euh.buildCommandLineArguments(__elisaUtilName__, availableArgs, mandatoryArgs) if True == cmdlArgs.version: print('\n' + __elisaUtilName__ + ' ' + __version__ + ' (' + __author__ + ')\n') @@ -64,7 +67,7 @@ def main(): # Configure the logging module logger = logging.getLogger('elisa_get_logger') logging.basicConfig(format='%(asctime)s %(funcName)s:%(levelno)s [%(levelname)s]: %(message)s') - logger.setLevel(getLoggingLevel(cmdlArgs.verbosity)) + logger.setLevel(euh.getLoggingLevel(cmdlArgs.verbosity)) # Make sure the interval argument is correctly entered # At the moment only months are accepted so the format @@ -76,10 +79,12 @@ def main(): sys.exit() logbook = cmdlArgs.logbook + if None == logbook: + logbook = "ATLAS" elisaArgs = dict() - elisaArgs['connection'] = getElisaServer(cmdlArgs.server) + getElisaURL() + logbook + '/' - elisaArgs.update(parseCredentials(cmdlArgs)) + elisaArgs['connection'] = euh.getElisaServer(cmdlArgs.server) + euh.getElisaURL() + logbook + '/' + elisaArgs.update(euh.parseCredentials(cmdlArgs)) elisa = Elisa(**elisaArgs) if None != cmdlArgs.id: @@ -91,7 +96,7 @@ def main(): except ElisaError as ex: logger.error(str(ex)) else: - from elisa_client_api.searchCriteria import SearchCriteria + from searchCriteria import SearchCriteria criteria = SearchCriteria() criteria.userName = cmdlArgs.username criteria.author = cmdlArgs.author @@ -118,6 +123,3 @@ def main(): writeAttachments(elisa, message, cmdlArgs.attachmentsDst) except ElisaError as ex: logger.error(str(ex)) - -if __name__ == '__main__': - main() diff --git a/src/elisa_client_api/scripts/elisa_insert.py b/src/elisa_client_api/scripts/elisa_insert.py index d21efb4..5d1e3fc 100755 --- a/src/elisa_client_api/scripts/elisa_insert.py +++ b/src/elisa_client_api/scripts/elisa_insert.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env tdaq_python #-------------------------------------------------------------------------------------- # Title : Binary to insert an elog messages to Elisa. # Project : ATLAS, TDAQ, ELisA @@ -18,18 +18,22 @@ # 21/Jan/2013: created. #-------------------------------------------------------------------------------------- +from __future__ import print_function +from __future__ import absolute_import +from builtins import str import logging -import sys + from elisa_client_api.exception import * from elisa_client_api.elisa import Elisa from elisa_client_api.messageInsert import MessageInsert -from elisa_client_api.scripts.elisa_utilhelper import * - +import elisa_client_api.scripts.elisa_utilhelper as euh __elisaUtilName__ = 'elisa_insert' -from elisa_client_api import __version__ -__author__ = 'Raul Murillo Garcia & Pierre Lasorak ' +__version_info__ = ('0', '0', '1') +__version__ = '.'.join(__version_info__) +__author__ = 'Raul Murillo Garcia ' + def main(): # Command line arguments @@ -38,7 +42,7 @@ def main(): 'systems', 'options', 'body', 'bodyFile', 'status', 'attachmentsSrc'] mandatoryArgs = ['subject', 'type', 'systems'] - parser, cmdlArgs = buildCommandLineArguments(__elisaUtilName__, availableArgs, mandatoryArgs) + parser, cmdlArgs = euh.buildCommandLineArguments(__elisaUtilName__, availableArgs, mandatoryArgs) if True == cmdlArgs.version: print('\n' + __elisaUtilName__ + ' ' + __version__ + ' (' + __author__ + ')\n') @@ -47,7 +51,7 @@ def main(): # Configure the logging module logger = logging.getLogger('elisa') logging.basicConfig(format='%(asctime)s %(funcName)s:%(levelno)s [%(levelname)s]: %(message)s') - logger.setLevel(getLoggingLevel(cmdlArgs.verbosity)) + logger.setLevel(euh.getLoggingLevel(cmdlArgs.verbosity)) # Body text can only come from one source if cmdlArgs.body and cmdlArgs.bodyFile: @@ -60,10 +64,12 @@ def main(): msgBody = f.read() logbook = cmdlArgs.logbook + if None == logbook: + logbook = "ATLAS" elisaArgs = dict() - elisaArgs['connection'] = getElisaServer(cmdlArgs.server) + getElisaURL() + logbook + '/' - elisaArgs.update(parseCredentials(cmdlArgs)) + elisaArgs['connection'] = euh.getElisaServer(cmdlArgs.server) + euh.getElisaURL() + logbook + '/' + elisaArgs.update(euh.parseCredentials(cmdlArgs)) elisa = Elisa(**elisaArgs) message = MessageInsert() @@ -71,7 +77,7 @@ def main(): message.subject = cmdlArgs.subject message.type = cmdlArgs.type message.systemsAffected = [sys.strip() for sys in cmdlArgs.systems.split(',')] - message.options = parseOptions(cmdlArgs.options, parser) + message.options = euh.parseOptions(cmdlArgs.options, parser) message.body = msgBody message.status = cmdlArgs.status message.attachments = cmdlArgs.attachmentsSrc @@ -83,5 +89,3 @@ def main(): logger.error(str(ex)) -if __name__ == '__main__': - main() diff --git a/src/elisa_client_api/scripts/elisa_reply.py b/src/elisa_client_api/scripts/elisa_reply.py index d534ba6..95df124 100755 --- a/src/elisa_client_api/scripts/elisa_reply.py +++ b/src/elisa_client_api/scripts/elisa_reply.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env tdaq_python #-------------------------------------------------------------------------------------- # Title : Binary to reply an elog messages to Elisa. # Project : ATLAS, TDAQ, ELisA @@ -18,26 +18,31 @@ # 24/Jan/2013: created. #-------------------------------------------------------------------------------------- +from __future__ import print_function +from __future__ import absolute_import +from builtins import str import logging from elisa_client_api.exception import * from elisa_client_api.elisa import Elisa from elisa_client_api.messageReply import MessageReply -from elisa_client_api.scripts.elisa_utilhelper import * +import elisa_utilhelper as euh __elisaUtilName__ = 'elisa_reply' -from elisa_client_api import __version__ -__author__ = 'Raul Murillo Garcia & Pierre Lasorak ' +__version_info__ = ('0', '0', '1') +__version__ = '.'.join(__version_info__) +__author__ = 'Raul Murillo Garcia ' -def main(): + +if __name__ == '__main__': # Command line arguments availableArgs = ['version', 'verbosity', 'server', 'sso', - 'ldap', 'logbook', 'id', 'author', 'systems', + 'ldap', 'logbook', 'id', 'author', 'subject', 'systems', 'options', 'body', 'bodyFile', 'status', 'attachmentsSrc'] mandatoryArgs = ['id'] - parser, cmdlArgs = buildCommandLineArguments(__elisaUtilName__, availableArgs, mandatoryArgs) + parser, cmdlArgs = euh.buildCommandLineArguments(__elisaUtilName__, availableArgs, mandatoryArgs) if True == cmdlArgs.version: print('\n' + __elisaUtilName__ + ' ' + __version__ + ' (' + __author__ + ')\n') @@ -46,7 +51,7 @@ def main(): # Configure the logging module logger = logging.getLogger('elisa') logging.basicConfig(format='%(asctime)s %(funcName)s:%(levelno)s [%(levelname)s]: %(message)s') - logger.setLevel(getLoggingLevel(cmdlArgs.verbosity)) + logger.setLevel(euh.getLoggingLevel(cmdlArgs.verbosity)) # Make sure at least one option is defined if not cmdlArgs.author and not cmdlArgs.systems and not cmdlArgs.options and \ @@ -66,16 +71,19 @@ def main(): msgBody = f.read() logbook = cmdlArgs.logbook + if None == logbook: + logbook = "ATLAS" elisaArgs = dict() - elisaArgs['connection'] = getElisaServer(cmdlArgs.server) + getElisaURL() + logbook + '/' - elisaArgs.update(parseCredentials(cmdlArgs)) + elisaArgs['connection'] = euh.getElisaServer(cmdlArgs.server) + euh.getElisaURL() + logbook + '/' + elisaArgs.update(euh.parseCredentials(cmdlArgs)) elisa = Elisa(**elisaArgs) message = MessageReply(cmdlArgs.id) message.author = cmdlArgs.author + message.subject = cmdlArgs.subject message.systemsAffected = [sys.strip() for sys in cmdlArgs.systems.split(',')] if cmdlArgs.systems else None - message.options = parseOptions(cmdlArgs.options, parser) + message.options = euh.parseOptions(cmdlArgs.options, parser) message.body = msgBody message.status = cmdlArgs.status message.attachments = cmdlArgs.attachmentsSrc @@ -87,5 +95,3 @@ def main(): logger.error(str(ex)) -if __name__ == '__main__': - main() diff --git a/src/elisa_client_api/scripts/elisa_update.py b/src/elisa_client_api/scripts/elisa_update.py index 5aa451e..02d35e4 100755 --- a/src/elisa_client_api/scripts/elisa_update.py +++ b/src/elisa_client_api/scripts/elisa_update.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env tdaq_python #-------------------------------------------------------------------------------------- # Title : Binary to update an elog messages to Elisa. # Project : ATLAS, TDAQ, ELisA @@ -18,26 +18,30 @@ # 24/Jan/2013: created. #-------------------------------------------------------------------------------------- +from __future__ import print_function +from __future__ import absolute_import +from builtins import str import logging from elisa_client_api.exception import * from elisa_client_api.elisa import Elisa from elisa_client_api.messageUpdate import MessageUpdate -from elisa_client_api.scripts.elisa_utilhelper import * +import elisa_utilhelper as euh __elisaUtilName__ = 'elisa_update' -from elisa_client_api import __version__ -__author__ = 'Raul Murillo Garcia & Pierre Lasorak ' +__version_info__ = ('0', '0', '1') +__version__ = '.'.join(__version_info__) +__author__ = 'Raul Murillo Garcia ' -def main(): +if __name__ == '__main__': # Command line arguments availableArgs = ['version', 'verbosity', 'server', 'sso', 'ldap', 'logbook', 'id', 'date', 'body', 'bodyFile', 'attachmentsSrc'] mandatoryArgs = ['id'] - parser, cmdlArgs = buildCommandLineArguments(__elisaUtilName__, availableArgs, mandatoryArgs) + parser, cmdlArgs = euh.buildCommandLineArguments(__elisaUtilName__, availableArgs, mandatoryArgs) if True == cmdlArgs.version: print('\n' + __elisaUtilName__ + ' ' + __version__ + ' (' + __author__ + ')\n') @@ -46,7 +50,7 @@ def main(): # Configure the logging module logger = logging.getLogger('elisa_get_logger') logging.basicConfig(format='%(asctime)s %(funcName)s:%(levelno)s [%(levelname)s]: %(message)s') - logger.setLevel(getLoggingLevel(cmdlArgs.verbosity)) + logger.setLevel(euh.getLoggingLevel(cmdlArgs.verbosity)) # Make sure at least one option is defined if not cmdlArgs.body and not cmdlArgs.attachmentsSrc and not cmdlArgs.bodyFile and not cmdlArgs.date: @@ -64,10 +68,12 @@ def main(): msgBody = f.read() logbook = cmdlArgs.logbook + if None == logbook: + logbook = "ATLAS" elisaArgs = dict() - elisaArgs['connection'] = getElisaServer(cmdlArgs.server) + getElisaURL() + logbook + '/' - elisaArgs.update(parseCredentials(cmdlArgs)) + elisaArgs['connection'] = euh.getElisaServer(cmdlArgs.server) + euh.getElisaURL() + logbook + '/' + elisaArgs.update(euh.parseCredentials(cmdlArgs)) elisa = Elisa(**elisaArgs) message = MessageUpdate(str(cmdlArgs.id)) @@ -82,5 +88,3 @@ def main(): logger.error(str(ex)) -if __name__ == '__main__': - main() diff --git a/src/elisa_client_api/scripts/elisa_utilhelper.py b/src/elisa_client_api/scripts/elisa_utilhelper.py index 5acb6a3..bf98ef1 100755 --- a/src/elisa_client_api/scripts/elisa_utilhelper.py +++ b/src/elisa_client_api/scripts/elisa_utilhelper.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env tdaq_python #-------------------------------------------------------------------------------------- # Title : Utilities helper. # Project : ATLAS, TDAQ, ELisA @@ -34,11 +34,9 @@ def parseCredentials(cmlArgs): # specified, check if the password is also defined. if None == cmlArgs.ldap: import getpass - print("Using SSO authentication!") username = getpass.getuser() password = getpass.getpass("Password for " + username + ": ") else: - print("Using LDAP authentication!") pos = cmlArgs.ldap.find(':') if pos != -1: username = cmlArgs.ldap[:pos] @@ -60,7 +58,8 @@ def buildCommandLineArguments(utilName, cmlArgs, mandatory): usage = 'usage: ' + utilName + ' [options] args' parser = OptionParser(usage=usage, epilog='In case of errors or bugs, please send an email to ' \ - '') + 'atlas-tdaq-cc-wg@cern.ch') + for arg in cmlArgs: addOption = { @@ -80,7 +79,10 @@ def buildCommandLineArguments(utilName, cmlArgs, mandatory): type='string', dest='server', metavar='SERVER', - help='URL of the EliSA REST server (i.e. https://pc-atd-elisa.cern.ch).'), + default=getElisaServer(None), + help='URL of the EliSA REST server (i.e. ' \ + 'https://pc-atd-elisa.cern.ch). If not specified, the main' \ + 'EliSA server in P1 or GPN depending on user location.'), 'sso': lambda: parser.add_option('-o', '--sso-credential', type='string', dest='sso', @@ -95,10 +97,11 @@ def buildCommandLineArguments(utilName, cmlArgs, mandatory): help='user credential in the form USERNAME:PASSWORD or USERNAME. If only ' \ 'the username is provided, the password will be asked interactively.'), 'logbook': lambda: parser.add_option('-k', '--logbook', - type='string', - dest='logbook', - metavar='LOGBOOK', - help='logbook name. If argument is not provided, this script won\'t work!'), + type='string', + dest='logbook', + metavar='LOGBOOK', + help='logbook name. If argument is not provided ' \ + 'the default ATLAS value is used for the logbook.'), 'id': lambda: parser.add_option('-i', '--id', type='int', dest='id', @@ -172,12 +175,12 @@ def buildCommandLineArguments(utilName, cmlArgs, mandatory): type='string', dest='since', metavar='FROM', - help='initial date of the search. Format: DD/MM/YYYY HH:MM:ss.'), + help='initial date of the search. Format: DD-MON-YYYY'), 'to': lambda: parser.add_option('-t', '--date-to', type='string', dest='to', metavar='TO', - help='end date of the search. Format: DD/MM/YYYY HH:MM:ss.'), + help='end date of the search. Format: DD-MON-YYYY'), 'interval': lambda: parser.add_option('-n', '--interval', type='string', dest='interval', @@ -236,18 +239,21 @@ def getLoggingLevel(level): def getElisaServer(cmdlServer): + import os - if not cmdlServer: - raise RuntimeError("You need to specify a server") - else: + if None != cmdlServer: return cmdlServer + elif None != os.environ.get('TDAQ_SETUP_POINT1'): + return 'http://pc-atlas-www.cern.ch' + else: + return 'https://atlasop.cern.ch' def getElisaURL(): import os - if os.environ.get('USE_ELISA_NOT_MERGED'): - return '/elisa.api/api/' - - return '/elisa/api/' + if None != os.environ.get('USE_ELISA_MERGED'): + return '/elisa/api/' + else: + return '/elisa/api/' def parseOptions(options, parser): if not options: @@ -275,7 +281,7 @@ def parseOptions(options, parser): # pp = pprint.PrettyPrinter(indent=2) # pp.pprint(listOpts) - from elisa_client_api.optionsBuilder import OptionsBuilder + from optionsBuilder import OptionsBuilder obroot = OptionsBuilder() # Use a hash table with the option name as the key and the @@ -293,3 +299,4 @@ def parseOptions(options, parser): dirOBs[name] = dirOBs[parts[0]].addOption(parts[1], value) return obroot.toList() + diff --git a/src/elisa_client_api/searchCriteria.py b/src/elisa_client_api/searchCriteria.py index 4fc0cc4..bfc2d4d 100644 --- a/src/elisa_client_api/searchCriteria.py +++ b/src/elisa_client_api/searchCriteria.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env tdaq_python #-------------------------------------------------------------------------------------- # Title : Search criteria # Project : ATLAS, TDAQ, ELisA @@ -19,25 +19,28 @@ # 04/Dec/2012: use properties. #-------------------------------------------------------------------------------------- +from __future__ import absolute_import +from builtins import str +from builtins import object from elisa_client_api.core.searchField import SearchField class SearchCriteria(object): """ Class representing a search criteria. - + This class provides all the fields required to form a search criteria to retrieve logbook messages from the ELisA database. """ # ------------------ # - Public methods - # ------------------ - def __init__(self): + def __init__(self): # ------------------- # - Data attributes - # ------------------- - # The field name parameter is the same as those use in the ELisA server. - # This schema allows for generic code when serializing, deserializing - # and printing the fields. + # The field name parameter is the same as those use in the ELisA server. + # This schema allows for generic code when serializing, deserializing + # and printing the fields. self._limit = SearchField('limit') # Number of entries returned (100 by default). self._page = SearchField('page') # Page number for results pagination. self._userName = SearchField('userName') # Filter results per user name. @@ -51,16 +54,16 @@ def __init__(self): self._since = SearchField('from') # Initial search date. self._until = SearchField('to') # End search date. self._interval = SearchField('month_interval') # Month interval. - - + + def __str__(self): dump = "" fields = self._getFieldNames() for field in fields: - dump += str(getattr(self, field)) + '\n' + dump += str(getattr(self, field)) + '\n' return dump - - + + def getDict(self): """ Returns a dictionary of fieldName:fieldValue """ @@ -70,7 +73,7 @@ def getDict(self): if attr.value != None: params[attr.name] = str(attr.value) return params - + # ------------------------- # - Public helper methods - @@ -82,7 +85,7 @@ def limit(self): @limit.setter def limit(self, value): self._limit.value = value - + @property def page(self): """ Page number for results pagination. """ @@ -90,7 +93,7 @@ def page(self): @page.setter def page(self, value): self._page.value = value - + @property def userName(self): """ Filter results per user name. """ @@ -98,7 +101,7 @@ def userName(self): @userName.setter def userName(self, value): self._userName.value = value - + @property def author(self): """ Filter results per author. """ @@ -114,7 +117,7 @@ def systemsAffected(self): @systemsAffected.setter def systemsAffected(self, value): self._systemsAffected.value = value - + @property def type(self): """ Filter results per type. """ @@ -122,7 +125,7 @@ def type(self): @type.setter def type(self, value): self._type.value = value - + @property def options(self): """ Filter results per options. """ @@ -130,7 +133,7 @@ def options(self): @options.setter def options(self, value): self._options.value = value - + @property def since(self): """ Initial search date. """ @@ -146,7 +149,7 @@ def until(self): @until.setter def until(self, value): self._until.value = value - + @property def interval(self): """ Month interval. """ @@ -162,7 +165,7 @@ def subject(self): @subject.setter def subject(self, value): self._subject.value = value - + @property def status(self): """ Filter results per status. """ @@ -178,11 +181,11 @@ def body(self): @body.setter def body(self, value): self._body.value = value - + # ------------------- # - Private methods - # ------------------- def _getFieldNames(self): return [attr for attr in dir(self) if getattr(self, attr).__class__.__name__ == "SearchField"] - - + + From 95fa5553541228e44e0bb458ef9d5b4e60d44057 Mon Sep 17 00:00:00 2001 From: Pierre Lasorak Date: Tue, 6 Feb 2024 12:04:05 +0100 Subject: [PATCH 2/5] chuck everything --- .gitmodules | 3 + doc/.conf.py.swp | Bin 24576 -> 0 bytes doc/README | 7 - doc/conf.py | 242 -------------- doc/doctrees/elisa_client_api.doctree | Bin 119911 -> 0 bytes doc/doctrees/environment.pickle | Bin 21597 -> 0 bytes doc/doctrees/index.doctree | Bin 5659 -> 0 bytes doc/doctrees/modules.doctree | Bin 2892 -> 0 bytes doc/doctrees/utilities.doctree | Bin 35293 -> 0 bytes doc/elisa_client_api.rst | 59 ---- doc/index.rst | 24 -- doc/modules.rst | 8 - doc/utilities.rst | 275 ---------------- elisa_client_api | 1 + src/elisa_client_api/__init__.py | 1 - src/elisa_client_api/core/__init__.py | 0 src/elisa_client_api/core/authentication.py | 87 ----- src/elisa_client_api/core/message.py | 187 ----------- src/elisa_client_api/core/messageField.py | 311 ------------------ src/elisa_client_api/core/request.py | 160 --------- src/elisa_client_api/core/restServer.py | 286 ---------------- src/elisa_client_api/core/searchField.py | 49 --- src/elisa_client_api/core/serializer.py | 169 ---------- src/elisa_client_api/elisa.py | 194 ----------- src/elisa_client_api/exception.py | 83 ----- src/elisa_client_api/messageInsert.py | 37 --- src/elisa_client_api/messageRead.py | 29 -- src/elisa_client_api/messageReply.py | 53 --- src/elisa_client_api/messageUpdate.py | 49 --- src/elisa_client_api/optionsBuilder.py | 81 ----- src/elisa_client_api/scripts/__init__.py | 0 src/elisa_client_api/scripts/elisa_config.py | 83 ----- src/elisa_client_api/scripts/elisa_get.py | 125 ------- src/elisa_client_api/scripts/elisa_insert.py | 91 ----- src/elisa_client_api/scripts/elisa_reply.py | 97 ------ src/elisa_client_api/scripts/elisa_update.py | 90 ----- .../scripts/elisa_utilhelper.py | 302 ----------------- src/elisa_client_api/searchCriteria.py | 191 ----------- test.sh | 11 - test/certificationTest.py | 58 ---- test/elisaTest.py | 144 -------- test/regression | 60 ---- test/serializeTest.py | 139 -------- 43 files changed, 4 insertions(+), 3782 deletions(-) create mode 100644 .gitmodules delete mode 100644 doc/.conf.py.swp delete mode 100644 doc/README delete mode 100644 doc/conf.py delete mode 100644 doc/doctrees/elisa_client_api.doctree delete mode 100644 doc/doctrees/environment.pickle delete mode 100644 doc/doctrees/index.doctree delete mode 100644 doc/doctrees/modules.doctree delete mode 100644 doc/doctrees/utilities.doctree delete mode 100644 doc/elisa_client_api.rst delete mode 100644 doc/index.rst delete mode 100644 doc/modules.rst delete mode 100644 doc/utilities.rst create mode 160000 elisa_client_api delete mode 100644 src/elisa_client_api/__init__.py delete mode 100644 src/elisa_client_api/core/__init__.py delete mode 100644 src/elisa_client_api/core/authentication.py delete mode 100644 src/elisa_client_api/core/message.py delete mode 100644 src/elisa_client_api/core/messageField.py delete mode 100644 src/elisa_client_api/core/request.py delete mode 100644 src/elisa_client_api/core/restServer.py delete mode 100644 src/elisa_client_api/core/searchField.py delete mode 100644 src/elisa_client_api/core/serializer.py delete mode 100644 src/elisa_client_api/elisa.py delete mode 100644 src/elisa_client_api/exception.py delete mode 100644 src/elisa_client_api/messageInsert.py delete mode 100644 src/elisa_client_api/messageRead.py delete mode 100644 src/elisa_client_api/messageReply.py delete mode 100644 src/elisa_client_api/messageUpdate.py delete mode 100644 src/elisa_client_api/optionsBuilder.py delete mode 100644 src/elisa_client_api/scripts/__init__.py delete mode 100755 src/elisa_client_api/scripts/elisa_config.py delete mode 100755 src/elisa_client_api/scripts/elisa_get.py delete mode 100755 src/elisa_client_api/scripts/elisa_insert.py delete mode 100755 src/elisa_client_api/scripts/elisa_reply.py delete mode 100755 src/elisa_client_api/scripts/elisa_update.py delete mode 100755 src/elisa_client_api/scripts/elisa_utilhelper.py delete mode 100644 src/elisa_client_api/searchCriteria.py delete mode 100755 test.sh delete mode 100644 test/certificationTest.py delete mode 100644 test/elisaTest.py delete mode 100644 test/regression delete mode 100644 test/serializeTest.py diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..f14d685 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "elisa_client_api"] + path = elisa_client_api + url = https://gitlab.cern.ch/atlas-tdaq-software/elisa_client_api.git diff --git a/doc/.conf.py.swp b/doc/.conf.py.swp deleted file mode 100644 index 81e629d39f530b6fb7435df751533adb6027ce3e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 24576 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 diff --git a/doc/README b/doc/README deleted file mode 100644 index d1111cd..0000000 --- a/doc/README +++ /dev/null @@ -1,7 +0,0 @@ -How to build the documentation - -1) cd DAQ/online/elisa_client_api/python -2) Temporarily comment out in elisa.py - #from core.restServer import RestServer - #from core.authentication import Authentication -3) sphinx-build -b html -d doctrees . html diff --git a/doc/conf.py b/doc/conf.py deleted file mode 100644 index 914de90..0000000 --- a/doc/conf.py +++ /dev/null @@ -1,242 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Python Elisa client API documentation build configuration file, created by -# sphinx-quickstart on Tue Feb 19 15:24:35 2013. -# -# This file is execfile()d with the current directory set to its containing dir. -# -# Note that not all possible configuration values are present in this -# autogenerated file. -# -# All configuration values have a default; values that are commented out -# serve to show the default. - -import sys, os - -# If extensions (or modules to document with autodoc) are in another directory, -# add these directories to sys.path here. If the directory is relative to the -# documentation root, use os.path.abspath to make it absolute, like shown here. -sys.path.insert(0, os.path.abspath('../')) - -# -- General configuration ----------------------------------------------------- - -# If your documentation needs a minimal Sphinx version, state it here. -#needs_sphinx = '1.0' - -# Add any Sphinx extension module names here, as strings. They can be extensions -# coming with Sphinx (named 'sphinx.ext.*') or your custom ones. -extensions = ['sphinx.ext.autodoc'] - -# Add any paths that contain templates here, relative to this directory. -templates_path = ['_templates'] - -# The suffix of source filenames. -source_suffix = '.rst' - -# The encoding of source files. -#source_encoding = 'utf-8-sig' - -# The master toctree document. -master_doc = 'index' - -# General information about the project. -project = u'Python Elisa client API' -copyright = u'2013, Raul Murillo Garcia' - -# The version info for the project you're documenting, acts as replacement for -# |version| and |release|, also used in various other places throughout the -# built documents. -# -# The short X.Y version. -version = 'V00-00-09' -# The full version, including alpha/beta/rc tags. -release = 'V00-00-09' - -# The language for content autogenerated by Sphinx. Refer to documentation -# for a list of supported languages. -#language = None - -# There are two options for replacing |today|: either, you set today to some -# non-false value, then it is used: -#today = '' -# Else, today_fmt is used as the format for a strftime call. -#today_fmt = '%B %d, %Y' - -# List of patterns, relative to source directory, that match files and -# directories to ignore when looking for source files. -exclude_patterns = ['_build'] - -# The reST default role (used for this markup: `text`) to use for all documents. -#default_role = None - -# If true, '()' will be appended to :func: etc. cross-reference text. -#add_function_parentheses = True - -# If true, the current module name will be prepended to all description -# unit titles (such as .. function::). -#add_module_names = True - -# If true, sectionauthor and moduleauthor directives will be shown in the -# output. They are ignored by default. -#show_authors = False - -# The name of the Pygments (syntax highlighting) style to use. -pygments_style = 'sphinx' - -# A list of ignored prefixes for module index sorting. -#modindex_common_prefix = [] - - -# -- Options for HTML output --------------------------------------------------- - -# The theme to use for HTML and HTML Help pages. See the documentation for -# a list of builtin themes. -html_theme = 'default' - -# Theme options are theme-specific and customize the look and feel of a theme -# further. For a list of options available for each theme, see the -# documentation. -#html_theme_options = {} - -# Add any paths that contain custom themes here, relative to this directory. -#html_theme_path = [] - -# The name for this set of Sphinx documents. If None, it defaults to -# " v documentation". -#html_title = None - -# A shorter title for the navigation bar. Default is the same as html_title. -#html_short_title = None - -# The name of an image file (relative to this directory) to place at the top -# of the sidebar. -#html_logo = None - -# The name of an image file (within the static path) to use as favicon of the -# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 -# pixels large. -#html_favicon = None - -# Add any paths that contain custom static files (such as style sheets) here, -# relative to this directory. They are copied after the builtin static files, -# so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ['_static'] - -# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, -# using the given strftime format. -#html_last_updated_fmt = '%b %d, %Y' - -# If true, SmartyPants will be used to convert quotes and dashes to -# typographically correct entities. -#html_use_smartypants = True - -# Custom sidebar templates, maps document names to template names. -#html_sidebars = {} - -# Additional templates that should be rendered to pages, maps page names to -# template names. -#html_additional_pages = {} - -# If false, no module index is generated. -#html_domain_indices = True - -# If false, no index is generated. -#html_use_index = True - -# If true, the index is split into individual pages for each letter. -#html_split_index = False - -# If true, links to the reST sources are added to the pages. -#html_show_sourcelink = True - -# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. -#html_show_sphinx = True - -# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. -#html_show_copyright = True - -# If true, an OpenSearch description file will be output, and all pages will -# contain a tag referring to it. The value of this option must be the -# base URL from which the finished HTML is served. -#html_use_opensearch = '' - -# This is the file name suffix for HTML files (e.g. ".xhtml"). -#html_file_suffix = None - -# Output file base name for HTML help builder. -htmlhelp_basename = 'PythonElisaclientAPIdoc' - - -# -- Options for LaTeX output -------------------------------------------------- - -latex_elements = { -# The paper size ('letterpaper' or 'a4paper'). -#'papersize': 'letterpaper', - -# The font size ('10pt', '11pt' or '12pt'). -#'pointsize': '10pt', - -# Additional stuff for the LaTeX preamble. -#'preamble': '', -} - -# Grouping the document tree into LaTeX files. List of tuples -# (source start file, target name, title, author, documentclass [howto/manual]). -latex_documents = [ - ('index', 'PythonElisaclientAPI.tex', u'Python Elisa client API Documentation', - u'Raul Murillo Garcia', 'manual'), -] - -# The name of an image file (relative to this directory) to place at the top of -# the title page. -#latex_logo = None - -# For "manual" documents, if this is true, then toplevel headings are parts, -# not chapters. -#latex_use_parts = False - -# If true, show page references after internal links. -#latex_show_pagerefs = False - -# If true, show URL addresses after external links. -#latex_show_urls = False - -# Documents to append as an appendix to all manuals. -#latex_appendices = [] - -# If false, no module index is generated. -#latex_domain_indices = True - - -# -- Options for manual page output -------------------------------------------- - -# One entry per manual page. List of tuples -# (source start file, name, description, authors, manual section). -man_pages = [ - ('index', 'pythonelisaclientapi', u'Python Elisa client API Documentation', - [u'Raul Murillo Garcia'], 1) -] - -# If true, show URL addresses after external links. -#man_show_urls = False - - -# -- Options for Texinfo output ------------------------------------------------ - -# Grouping the document tree into Texinfo files. List of tuples -# (source start file, target name, title, author, -# dir menu entry, description, category) -texinfo_documents = [ - ('index', 'PythonElisaclientAPI', u'Python Elisa client API Documentation', - u'Raul Murillo Garcia', 'PythonElisaclientAPI', 'One line description of project.', - 'Miscellaneous'), -] - -# Documents to append as an appendix to all manuals. -#texinfo_appendices = [] - -# If false, no module index is generated. -#texinfo_domain_indices = True - -# How to display URL addresses: 'footnote', 'no', or 'inline'. -#texinfo_show_urls = 'footnote' diff --git a/doc/doctrees/elisa_client_api.doctree b/doc/doctrees/elisa_client_api.doctree deleted file mode 100644 index ff6e81bd34a77c28ad8c7b02019e0cb9a9495674..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 119911 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 diff --git a/doc/doctrees/environment.pickle b/doc/doctrees/environment.pickle deleted file mode 100644 index 70c82b83827f3c696217d1d0234d6501a8655506..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 21597 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 VU#4!-7-PwUcuD1H_)Tgf{{pTLxlaH9 diff --git a/doc/doctrees/modules.doctree b/doc/doctrees/modules.doctree deleted file mode 100644 index 03a591359aada9e52e7c5bf6eae3ab90ca9fa986..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2892 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 - # 2 - # DAQ - # HLT - # - - # ------------------ - # - Public methods - - # ------------------ - def __init__(self, name): - # --------------------------- - # - Private data attributes - - # --------------------------- - self.__name = name.encode('utf-8') - self.__value = list() - - def __str__(self): - return '{0:19}: {1}'.format(self.name.decode('utf-8'), self.value) - - def serialize(self, parentNode): - if not self.value: - return - - if len(self.value) > 0: - rootNode = ET.SubElement(parentNode, self.name.decode('utf-8')) - countNode = ET.SubElement(rootNode, 'count') - countNode.text = str(len(self.value)) - for system in self.value: - sysNode = ET.SubElement(rootNode, 'system_affected') - sysNode.text = system - - - def deserialize(self, node): - [self.value.append(child.text.encode('utf-8').decode('utf-8')) for child in node.findall('system_affected')] - - # -------------------- - # - Property methods - - # -------------------- - @property - def name(self): - return self.__name - - @property - def value(self): - return self.__value - @value.setter - def value(self, value): - self.__value = value - - -class AttachmentField(object): - """ Class providing functionality to define the message attachment field. - - This field contains a list of tuples with the following simple fields: - filename, ID and link - """ - # Format: - # - # 1 - # - # foto.jpg - # 0 - # http://example.com/elisa.api/api/messages/200006/attachment/0 - # - # - - # ------------------ - # - Public methods - - # ------------------ - def __init__(self, name): - # --------------------------- - # - Private data attributes - - # --------------------------- - self.__name = name.encode('utf-8') - self.__value = None - - def __str__(self): - if not self.value: - return '{0:19}: 0'.format(self.name.decode('utf-8')) - - dump = '{0:19}: {1}'.format(self.name.decode('utf-8'), len(self.value)) - # Message insertion encapsulates attachments as a list of strings. - # Message retrieval encapsulates attachments as a list of tuples. - if isinstance(self.value[0], basestring): - for attach in self.value: - dump += '\n |---- {0}'.format(attach) - else: - for attach in self.value: - dump += '\n |---- {0:4}: {1}'.format("ID", attach[0]) - dump += '\n |---- {0:4}: {1}'.format("Name", attach[1]) - dump += '\n |---- {0:4}: {1}'.format("Link", attach[2]) - return dump - - def serialize(self, parentNode): - # Attachments are never serialized because its insertion follows - # a different path. - pass - - def deserialize(self, node): - self.value = list() - [self.__value.append((child.find('ID').text.encode('utf-8').decode('utf-8'), - child.find('filename').text.encode('utf-8').decode('utf-8'), - child.find('link').text.encode('utf-8').decode('utf-8'))) - for child in node.findall('attachment')] - - - # -------------------- - # - Property methods - - # -------------------- - @property - def name(self): - return self.__name - - @property - def value(self): - return self.__value - @value.setter - def value(self, value): - self.__value = value - - -class OptionField(object): - """ Class providing functionality to define the message option field. - - This field contains a list of tuples with the following fields: - name, value, list of OptionField - """ - # Format: - # - # 1 - #