Repository: rucio/rucio

Issue:
custom rucio exceptions passing args and kwargs wrong to super
Motivation
----------
It looks like all custom rucio exceptions are calling super().__init__(args, kwargs) with the wrong arguments.

Modification
------------
The syntax should be super().__init__(*args, **kwargs)

Expected behavior
-----------------



Discussion:

Resolving patch:
diff --git a/etc/docker/demo/setup_data.py b/etc/docker/demo/setup_data.py
new file mode 100755
--- /dev/null
+++ b/etc/docker/demo/setup_data.py
@@ -0,0 +1,24 @@
+#/usr/local/bin python
+# Copyright 2014-2018 CERN for the benefit of the ATLAS collaboration.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# You may not use this file except in compliance with the License.
+# You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
+#
+# Authors:
+# - Thomas Beermann, <thomas.beermann@cern.ch>, 2018
+
+from rucio.api.account import add_account
+from rucio.api.scope import add_scope
+from rucio.api.did import add_did
+from rucio.db.sqla.util import build_database, create_root_account
+
+if __name__ == '__main__':
+    build_database()
+    create_root_account()
+
+    add_account('jdoe', 'USER', 'test', 'root')
+
+    add_scope('user.jdoe', 'jdoe', 'root')
+
+    add_did('user.jdoe', 'test1', 'DATASET', 'root', account='jdoe')
diff --git a/lib/rucio/client/downloadclient.py b/lib/rucio/client/downloadclient.py
new file mode 100644
--- /dev/null
+++ b/lib/rucio/client/downloadclient.py
@@ -0,0 +1,483 @@
+"""
+ Copyright European Organization for Nuclear Research (CERN)
+ Licensed under the Apache License, Version 2.0 (the "License");
+ You may not use this file except in compliance with the License.
+ You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
+ Authors:
+ - Tomas Javurek, <tomas.javurek@cern.ch>, 2018
+ - Tobias Wegner <tobias.wegner@cern.ch>, 2018
+"""
+
+import os
+import os.path
+# import sys # (for logging)
+
+import logging
+import random
+import time
+import requests
+import json
+import socket
+import signal
+
+from rucio.client.baseclient import BaseClient
+from rucio.common.exception import FileConsistencyMismatch, RSEProtocolNotSupported, RSENotFound, RucioException
+from rucio.common.utils import sizefmt
+from rucio.common.utils import generate_uuid
+
+from rucio.client.client import Client
+from Queue import Queue, Empty
+from threading import Thread
+from rucio.rse import rsemanager as rsemgr
+from copy import deepcopy
+
+client = Client()
+# logging.basicConfig(stream=sys.stdout, level=logging.DEBUG)
+logging.basicConfig()
+logger = logging.getLogger("user")
+SUCCESS = 0
+FAILURE = 1
+
+DEFAULT_SECURE_PORT = 443
+DEFAULT_PORT = 80
+
+
+class DownloadClient(BaseClient):
+    """ This class cover all functionality related to file uploads into Rucio."""
+
+    BASEURL = '??_downloadclient_??'
+
+    def __init__(self, rucio_host=None, auth_host=None, account=None, ca_cert=None, auth_type=None, creds=None, timeout=None):
+        super(DownloadClient, self).__init__(rucio_host, auth_host, account, ca_cert, auth_type, creds, timeout)
+        self.trace_appid = os.environ.get('RUCIO_TRACE_APPID', None),
+        self.trace_dataset = os.environ.get('RUCIO_TRACE_DATASET', None),
+        self.trace_datasetscope = os.environ.get('RUCIO_TRACE_DATASETSCOPE', None),
+        self.trace_pq = os.environ.get('RUCIO_TRACE_PQ', None),
+        self.trace_taskid = os.environ.get('RUCIO_TRACE_TASKID', None),
+        self.trace_usrdn = os.environ.get('RUCIO_TRACE_USRDN', None)
+
+    def download(self, dids, rse, protocol='srm', pfn=None, nrandom=None, nprocs=None, user_agent='rucio_clients', dir='.', no_subd=False):
+
+        trace_endpoint = client.host
+        trace_pattern = {'hostname': socket.getfqdn(),
+                         'account': client.account,
+                         'uuid': generate_uuid(),
+                         'eventType': 'download',
+                         'eventVersion': 'api',
+                         'appid': self.trace_appid,
+                         'dataset': self.trace_dataset,
+                         'datasetScope': self.trace_datasetscope,
+                         'pq': self.trace_pq,
+                         'taskid': self.trace_taskid,
+                         'usrdn': self.trace_usrdn}
+
+        # is used account an admin account?
+        account_attributes = [acc for acc in client.list_account_attributes(client.account)]
+        is_admin = False
+        for attr in account_attributes[0]:
+            if attr['key'] == 'admin' and attr['value'] is True:
+                logger.debug('Admin mode enabled')
+                is_admin = True
+                break
+
+        # extend RSE expression to exclude tape RSEs for non-admin accounts
+        rse_expression = rse
+        if not is_admin:
+            rse_expression = 'istape=False'
+            if rse and len(rse.strip()) > 0:
+                rse_expression = '(%s)&istape=False' % rse
+                logger.debug('RSE-Expression: %s' % rse_expression)
+
+        # Extract the scope, name from the did(s)
+        did_list = []
+        for did in dids:
+            try:
+                scope, name = self.extract_scope(did)
+                if name.find('*') > -1:
+                    for dsn in client.list_dids(scope, filters={'name': name}):
+                        did_list.append({'scope': scope, 'name': dsn})
+                else:
+                    did_list.append({'scope': scope, 'name': name})
+            except ValueError as error:
+                raise error
+                return FAILURE
+
+        if pfn:
+            if not rse:
+                logger.error('--rse option is mandatory in combination with --pfn!')
+                return FAILURE
+
+            if len(dids) > 1:
+                dids = [dids[0]]
+                logger.warning('--pfn option and multiple DIDs given! Only considering first DID...')
+
+        summary = {}
+        num_files_to_dl = {}
+        input_queue = Queue()
+        output_queue = Queue()
+
+        # get replicas for every file of the given dids
+        for arg_did in did_list:
+            arg_didstr = '%s:%s' % (arg_did['scope'], arg_did['name'])
+            summary[arg_didstr] = {}
+
+            # get type of given did; save did if its a dataset
+            files_with_replicas = []
+            if not pfn:
+                try:
+                    did_info = client.get_did(arg_did['scope'], arg_did['name'])
+                    did_type = did_info['type'].upper()
+                    dataset_scope = '' if did_type == 'FILE' else arg_did['scope']
+                    dataset_name = '' if did_type == 'FILE' else arg_did['name']
+                except:
+                    logger.error('Failed to get did info for did %s' % arg_didstr)
+                    return FAILURE
+
+                try:
+                    files_with_replicas = client.list_replicas([arg_did],
+                                                               schemes=None,
+                                                               rse_expression=rse_expression,
+                                                               metalink=None)
+                except:
+                    logger.error('Failed to get list of files with their replicas for DID %s' % arg_didstr)
+                    return FAILURE
+
+                files_with_replicas = [f for f in files_with_replicas]
+                if nrandom:
+                    random.shuffle(files_with_replicas)
+                    files_with_replicas = files_with_replicas[0:nrandom]
+            else:
+                logger.debug('PFN option overrides replica listing')
+                did_type = 'FILE'
+                dataset_scope = ''
+                dataset_name = ''
+                files_with_replicas = [{'bytes': None,
+                                        'adler32': None,
+                                        'scope': arg_did['scope'],
+                                        'name': arg_did['name'],
+                                        'pfns': {pfn: {'rse': rse}},
+                                        'rses': {rse: [pfn]}}]
+
+            num_files_to_dl[arg_didstr] = len(files_with_replicas)
+            for f in files_with_replicas:
+                file_scope = f['scope']
+                file_name = f['name']
+                file_didstr = '%s:%s' % (file_scope, file_name)
+
+                file_exists, dest_dir = self._file_exists(did_type,
+                                                          file_scope,
+                                                          file_name,
+                                                          dir,
+                                                          dsn=dataset_name,
+                                                          no_subdir=no_subd)
+                dest_dir = os.path.abspath(dest_dir)
+
+                if file_exists:
+                    logger.info('File %s already exists locally' % file_didstr)
+
+                    out = {}
+                    out['dataset_scope'] = dataset_scope
+                    out['dataset_name'] = dataset_name
+                    out['scope'] = file_scope
+                    out['name'] = file_name
+                    out['clientState'] = 'ALREADY_DONE'
+                    output_queue.put(out)
+
+                    trace = deepcopy(trace_pattern)
+
+                    if 'datasetScope' not in trace:
+                        trace['datasetScope'] = dataset_scope
+                    if 'dataset' not in trace:
+                        trace['dataset'] = dataset_name
+                    trace.update({'scope': file_scope,
+                                  'filename': file_name,
+                                  'filesize': f['bytes'],
+                                  'transferStart': time.time(),
+                                  'transferEnd': time.time(),
+                                  'clientState': 'ALREADY_DONE'})
+                    self.send_trace(trace, trace_endpoint, user_agent)
+                else:
+                    if not os.path.isdir(dest_dir):
+                        logger.debug('Destination dir not found: %s' % dest_dir)
+                        try:
+                            os.makedirs(dest_dir)
+                        except:
+                            logger.error('Failed to create missing destination directory %s' % dest_dir)
+                            return FAILURE
+                    if no_subd and os.path.isfile('%s/%s' % (dest_dir, file_name)):
+                        # Overwrite the files
+                        logger.debug('Deleteing existing files: %s' % file_name)
+                        os.remove("%s/%s" % (dest_dir, file_name))
+                    f['dataset_scope'] = dataset_scope
+                    f['dataset_name'] = dataset_name
+                    f['dest_dir'] = dest_dir
+                    input_queue.put(f)
+
+        try:
+            self.download_rucio(pfn, protocol, input_queue, output_queue, trace_pattern, trace_endpoint, nprocs, user_agent, dir, no_subd)
+        except Exception as error:
+            logger.error('Exception during download: %s' % str(error))
+
+        while True:
+            try:
+                item = output_queue.get_nowait()
+                output_queue.task_done()
+                ds_didstr = '%s:%s' % (item['dataset_scope'], item['dataset_name'])
+                file_didstr = '%s:%s' % (item['scope'], item['name'])
+
+                if ds_didstr in summary or file_didstr in summary:
+                    if item['dataset_scope'] == '':
+                        summary[file_didstr][file_didstr] = item['clientState']
+                    else:
+                        summary[ds_didstr][file_didstr] = item['clientState']
+                    if item['clientState'] == 'CORRUPTED':
+                        try:
+                            # client.declare_suspicious_file_replicas([item['pfn']], reason='Corrupted')
+                            logger.warning('File %s seems to be corrupted.' % item['pfn'])
+                        except:
+                            logger.warning('File replica %s might be corrupted. Failure to declare it bad to Rucio' % item['pfn'])
+            except Empty:
+                break
+
+    def download_rucio(self, pfn, protocol, input_queue, output_queue, trace_pattern, trace_endpoint, ndownloader, user_agent, dir='.', no_subdir=False):
+
+        total_workers = 1
+        if ndownloader and not pfn:
+            total_workers = ndownloader
+            nlimit = 5
+            if total_workers > nlimit:
+                logger.warning('Cannot use more than %s parallel downloader.' % nlimit)
+                total_workers = nlimit
+
+        total_workers = min(total_workers, input_queue.qsize())
+
+        logger.debug('Starting %d download threads' % total_workers)
+        threads = []
+        for worker in range(total_workers):
+            kwargs = {'pfn': pfn,
+                      'user_agent': user_agent,
+                      'protocol': protocol,
+                      'human': True,
+                      'input_queue': input_queue,
+                      'output_queue': output_queue,
+                      'threadnb': worker + 1,
+                      'total_threads': total_workers,
+                      'trace_endpoint': trace_endpoint,
+                      'trace_pattern': trace_pattern}
+            try:
+                thread = Thread(target=self._downloader, kwargs=kwargs)
+                thread.start()
+                threads.append(thread)
+            except:
+                logger.warning('Failed to start thread %d' % (worker + 1))
+
+        try:
+            logger.debug('Waiting for threads to finish')
+            for thread in threads:
+                thread.join()
+        except KeyboardInterrupt:
+            logger.warning('You pressed Ctrl+C! Exiting gracefully')
+            for thread in threads:
+                thread.kill_received = True
+        logger.debug('All threads finished')
+
+    def _downloader(self, pfn, protocol, human, input_queue, output_queue, user_agent, threadnb, total_threads, trace_endpoint, trace_pattern):
+
+        rse_dict = {}
+        thread_prefix = 'Thread %s/%s' % (threadnb, total_threads)
+        while True:
+            try:
+                file = input_queue.get_nowait()
+            except Empty:
+                return
+
+            dest_dir = file['dest_dir']
+            file_scope = file['scope']
+            file_name = file['name']
+            file_didstr = '%s:%s' % (file_scope, file_name)
+
+            # arguments for rsemgr.download already known
+            dlfile = {}
+            dlfile['name'] = file_name
+            dlfile['scope'] = file_scope
+            dlfile['adler32'] = file['adler32']
+            ignore_checksum = True if pfn else False
+            if pfn:
+                dlfile['pfn'] = pfn
+
+            logger.info('%s : Starting the download of %s' % (thread_prefix, file_didstr))
+            trace = deepcopy(trace_pattern)
+            trace.update({'scope': file_scope,
+                          'filename': file_name,
+                          'datasetScope': file['dataset_scope'],
+                          'dataset': file['dataset_name'],
+                          'filesize': file['bytes']})
+
+            rses = file['rses'].keys()
+            if rses == []:
+                logger.warning('%s : File %s has no available replicas. Cannot be downloaded.' % (thread_prefix, file_didstr))
+                trace['clientState'] = 'FILE_NOT_FOUND'
+                self.send_trace(trace, trace_endpoint, user_agent)
+                input_queue.task_done()
+                continue
+            random.shuffle(rses)
+
+            logger.debug('%s : Potential sources : %s' % (thread_prefix, str(rses)))
+            success = False
+            while not success and len(rses):
+                rse_name = rses.pop()
+                if rse_name not in rse_dict:
+                    try:
+                        rse_dict[rse_name] = rsemgr.get_rse_info(rse_name)
+                    except RSENotFound:
+                        logger.warning('%s : Could not get info of RSE %s' % (thread_prefix, rse_name))
+                        continue
+
+                rse = rse_dict[rse_name]
+
+                if not rse['availability_read']:
+                    logger.info('%s : %s is blacklisted for reading' % (thread_prefix, rse_name))
+                    continue
+
+                try:
+                    if pfn:
+                        protocols = [rsemgr.select_protocol(rse, operation='read', scheme=pfn.split(':')[0])]
+                    else:
+                        protocols = rsemgr.get_protocols_ordered(rse, operation='read', scheme=protocol)
+                        protocols.reverse()
+                except RSEProtocolNotSupported as error:
+                    logger.info('%s : The protocol specfied (%s) is not supported by %s' % (thread_prefix, protocol, rse_name))
+                    logger.debug(error)
+                    continue
+                logger.debug('%s : %d possible protocol(s) for read' % (thread_prefix, len(protocols)))
+                trace['remoteSite'] = rse_name
+                trace['clientState'] = 'DOWNLOAD_ATTEMPT'
+
+                while not success and len(protocols):
+                    protocol_retry = protocols.pop()
+                    logger.debug('%s : Trying protocol %s at %s' % (thread_prefix, protocol_retry['scheme'], rse_name))
+                    trace['protocol'] = protocol_retry['scheme']
+                    out = {}
+                    out['dataset_scope'] = file['dataset_scope']
+                    out['dataset_name'] = file['dataset_name']
+                    out['scope'] = file_scope
+                    out['name'] = file_name
+
+                    attempt = 0
+                    retries = 2
+                    while not success and attempt < retries:
+                        attempt += 1
+                        out['attemptnr'] = attempt
+
+                        logger.info('%s : File %s trying from %s' % (thread_prefix, file_didstr, rse_name))
+                        try:
+                            trace['transferStart'] = time.time()
+
+                            rsemgr.download(rse,
+                                            files=[dlfile],
+                                            dest_dir=dest_dir,
+                                            force_scheme=protocol_retry['scheme'],
+                                            ignore_checksum=ignore_checksum)
+
+                            trace['transferEnd'] = time.time()
+                            trace['clientState'] = 'DONE'
+                            out['clientState'] = 'DONE'
+                            success = True
+                            output_queue.put(out)
+                            logger.info('%s : File %s successfully downloaded from %s' % (thread_prefix, file_didstr, rse_name))
+                        except KeyboardInterrupt:
+                            logger.warning('You pressed Ctrl+C! Exiting gracefully')
+                            os.kill(os.getpgid(), signal.SIGINT)
+                            return
+                        except FileConsistencyMismatch as error:
+                            logger.warning(str(error))
+                            try:
+                                pfns_dict = rsemgr.lfns2pfns(rse,
+                                                             lfns=[{'name': file_name, 'scope': file_scope}],
+                                                             operation='read',
+                                                             scheme=protocol)
+                                pfn = pfns_dict[file_didstr]
+
+                                out['clientState'] = 'CORRUPTED'
+                                out['pfn'] = pfn
+                                output_queue.put(out)
+                            except Exception as error:
+                                logger.debug('%s : %s' % (thread_prefix, str(error)))
+                            trace['clientState'] = 'FAIL_VALIDATE'
+                            logger.debug('%s : Failed attempt %s/%s' % (thread_prefix, attempt, retries))
+                        except Exception as error:
+                            logger.warning(str(error))
+                            trace['clientState'] = str(type(error).__name__)
+                            logger.debug('%s : Failed attempt %s/%s' % (thread_prefix, attempt, retries))
+
+                    self.send_trace(trace, trace_endpoint, user_agent, threadnb=threadnb, total_threads=total_threads)
+
+            if success:
+                duration = round(trace['transferEnd'] - trace['transferStart'], 2)
+                if pfn:
+                    logger.info('%s : File %s successfully downloaded in %s seconds' % (thread_prefix, file_didstr, duration))
+                else:
+                    logger.info('%s : File %s successfully downloaded. %s in %s seconds = %s MBps' % (thread_prefix,
+                                                                                                      file_didstr,
+                                                                                                      sizefmt(file['bytes'], human),
+                                                                                                      duration,
+                                                                                                      round((file['bytes'] / duration) * 1e-6, 2)))
+            else:
+                logger.error('%s : Cannot download file %s' % (thread_prefix, file_didstr))
+
+            input_queue.task_done()
+
+    def extract_scope(self, did):
+        # Try to extract the scope from the DSN
+        if did.find(':') > -1:
+            if len(did.split(':')) > 2:
+                raise RucioException('Too many colons. Cannot extract scope and name')
+            scope, name = did.split(':')[0], did.split(':')[1]
+            if name.endswith('/'):
+                name = name[:-1]
+            return scope, name
+        else:
+            scope = did.split('.')[0]
+            if did.startswith('user') or did.startswith('group'):
+                scope = ".".join(did.split('.')[0:2])
+            if did.endswith('/'):
+                did = did[:-1]
+            return scope, did
+
+    def _file_exists(self, type, scope, name, directory, dsn=None, no_subdir=False):
+        file_exists = False
+        dest_dir = None
+        if no_subdir:
+            dest_dir = '%s' % (directory)
+        else:
+            if type != 'FILE':
+                dest_dir = '%s/%s' % (directory, dsn)
+                if os.path.isfile('%s/%s' % (dest_dir, name)):
+                    file_exists = True
+            else:
+                dest_dir = '%s/%s' % (directory, scope)
+                if os.path.isfile('%s/%s' % (dest_dir, name)):
+                    file_exists = True
+        return file_exists, dest_dir
+
+    def send_trace(self, trace, trace_endpoint, user_agent, retries=5, threadnb=None, total_threads=None):
+
+        if user_agent.startswith('pilot'):
+            logger.debug('pilot detected - not sending trace')
+            return 0
+        else:
+            if threadnb is not None and total_threads is not None:
+                logger.debug('Thread %s/%s : sending trace' % (threadnb, total_threads))
+            else:
+                logger.debug('sending trace')
+
+        for dummy in xrange(retries):
+            try:
+                requests.post(trace_endpoint + '/traces/', verify=False, data=json.dumps(trace))
+                return 0
+            except Exception as error:
+                if threadnb is not None and total_threads is not None:
+                    logger.debug('Thread %s/%s : %s' % (threadnb, total_threads, error))
+                else:
+                    logger.debug(error)
+        return 1
diff --git a/lib/rucio/common/exception.py b/lib/rucio/common/exception.py
--- a/lib/rucio/common/exception.py
+++ b/lib/rucio/common/exception.py
@@ -33,7 +33,7 @@ class RucioException(Exception):
     """
 
     def __init__(self, *args, **kwargs):
-        super(RucioException, self).__init__(args, kwargs)
+        super(RucioException, self).__init__(*args, **kwargs)
         self._message = "An unknown exception occurred."
         self.args = args
         self.kwargs = kwargs
@@ -64,7 +64,7 @@ class AccessDenied(RucioException):
     AccessDenied
     """
     def __init__(self, *args, **kwargs):
-        super(AccessDenied, self).__init__(args, kwargs)
+        super(AccessDenied, self).__init__(*args, **kwargs)
         self._message = "Access to the requested resource denied."
         self.error_code = 2
 
@@ -74,7 +74,7 @@ class AccountNotFound(RucioException):
     AccountNotFound
     """
     def __init__(self, *args, **kwargs):
-        super(AccountNotFound, self).__init__(args, kwargs)
+        super(AccountNotFound, self).__init__(*args, **kwargs)
         self._message = "Account does not exist."
         self.error_code = 3
 
@@ -84,7 +84,7 @@ class CannotAuthenticate(RucioException):
     CannotAuthenticate
     """
     def __init__(self, *args, **kwargs):
-        super(CannotAuthenticate, self).__init__(args, kwargs)
+        super(CannotAuthenticate, self).__init__(*args, **kwargs)
         self._message = "Cannot authenticate."
         self.error_code = 4
 
@@ -94,7 +94,7 @@ class ClientParameterMismatch(RucioException):
     RucioException
     """
     def __init__(self, *args, **kwargs):
-        super(ClientParameterMismatch, self).__init__(args, kwargs)
+        super(ClientParameterMismatch, self).__init__(*args, **kwargs)
         self._message = "Client parameters don\'t match."
         self.error_code = 5
 
@@ -104,7 +104,7 @@ class ClientProtocolNotSupported(RucioException):
     RucioException
     """
     def __init__(self, *args, **kwargs):
-        super(ClientProtocolNotSupported, self).__init__(args, kwargs)
+        super(ClientProtocolNotSupported, self).__init__(*args, **kwargs)
         self._message = "Client protocol not supported."
         self.error_code = 6
 
@@ -114,7 +114,7 @@ class ConfigNotFound(RucioException):
     RucioException
     """
     def __init__(self, *args, **kwargs):
-        super(ConfigNotFound, self).__init__(args, kwargs)
+        super(ConfigNotFound, self).__init__(*args, **kwargs)
         self._message = "Configuration not found."
         self.error_code = 7
 
@@ -124,7 +124,7 @@ class ConfigurationError(RucioException):
     RucioException
     """
     def __init__(self, *args, **kwargs):
-        super(ConfigurationError, self).__init__(args, kwargs)
+        super(ConfigurationError, self).__init__(*args, **kwargs)
         self._message = "Error during configuration."
         self.error_code = 8
 
@@ -134,7 +134,7 @@ class CounterNotFound(RucioException):
     RucioException
     """
     def __init__(self, *args, **kwargs):
-        super(CounterNotFound, self).__init__(args, kwargs)
+        super(CounterNotFound, self).__init__(*args, **kwargs)
         self._message = "The requested counter does not exist."
         self.error_code = 9
 
@@ -144,7 +144,7 @@ class DatabaseException(RucioException):
     RucioException
     """
     def __init__(self, *args, **kwargs):
-        super(DatabaseException, self).__init__(args, kwargs)
+        super(DatabaseException, self).__init__(*args, **kwargs)
         self._message = "Database exception."
         self.error_code = 10
 
@@ -154,7 +154,7 @@ class DataIdentifierAlreadyExists(RucioException):
     RucioException
     """
     def __init__(self, *args, **kwargs):
-        super(DataIdentifierAlreadyExists, self).__init__(args, kwargs)
+        super(DataIdentifierAlreadyExists, self).__init__(*args, **kwargs)
         self._message = "Data Identifier Already Exists."
         self.error_code = 11
 
@@ -164,7 +164,7 @@ class DataIdentifierNotFound(RucioException):
     RucioException
     """
     def __init__(self, *args, **kwargs):
-        super(DataIdentifierNotFound, self).__init__(args, kwargs)
+        super(DataIdentifierNotFound, self).__init__(*args, **kwargs)
         self._message = "Data identifier not found."
         self.error_code = 12
 
@@ -174,7 +174,7 @@ class DestinationNotAccessible(RucioException):
     RucioException
     """
     def __init__(self, *args, **kwargs):
-        super(DestinationNotAccessible, self).__init__(args, kwargs)
+        super(DestinationNotAccessible, self).__init__(*args, **kwargs)
         self._message = "Access to local destination denied."
         self.error_code = 13
 
@@ -184,7 +184,7 @@ class Duplicate(RucioException):
     RucioException
     """
     def __init__(self, *args, **kwargs):
-        super(Duplicate, self).__init__(args, kwargs)
+        super(Duplicate, self).__init__(*args, **kwargs)
         self._message = "An object with the same identifier already exists."
         self.error_code = 14
 
@@ -194,7 +194,7 @@ class DuplicateContent(RucioException):
     RucioException
     """
     def __init__(self, *args, **kwargs):
-        super(DuplicateContent, self).__init__(args, kwargs)
+        super(DuplicateContent, self).__init__(*args, **kwargs)
         self._message = "Data identifier already added to the destination content."
         self.error_code = 15
 
@@ -204,7 +204,7 @@ class DuplicateRule(RucioException):
     RucioException
     """
     def __init__(self, *args, **kwargs):
-        super(DuplicateRule, self).__init__(args, kwargs)
+        super(DuplicateRule, self).__init__(*args, **kwargs)
         self._message = "A duplicate rule for this account, did, rse_expression, copies already exists."
         self.error_code = 16
 
@@ -214,7 +214,7 @@ class ErrorLoadingCredentials(RucioException):
     RucioException
     """
     def __init__(self, *args, **kwargs):
-        super(ErrorLoadingCredentials, self).__init__(args, kwargs)
+        super(ErrorLoadingCredentials, self).__init__(*args, **kwargs)
         self._message = "Unable to to load user credentials."
         self.error_code = 17
 
@@ -224,7 +224,7 @@ class FileAlreadyExists(RucioException):
     RucioException
     """
     def __init__(self, *args, **kwargs):
-        super(FileAlreadyExists, self).__init__(args, kwargs)
+        super(FileAlreadyExists, self).__init__(*args, **kwargs)
         self._message = "The file already exists."
         self.error_code = 18
 
@@ -234,7 +234,7 @@ class FileConsistencyMismatch(RucioException):
     RucioException
     """
     def __init__(self, *args, **kwargs):
-        super(FileConsistencyMismatch, self).__init__(args, kwargs)
+        super(FileConsistencyMismatch, self).__init__(*args, **kwargs)
         self._message = "Error related to file consistency."
         self.error_code = 19
 
@@ -244,7 +244,7 @@ class FileReplicaAlreadyExists(RucioException):
     RucioException
     """
     def __init__(self, *args, **kwargs):
-        super(FileReplicaAlreadyExists, self).__init__(args, kwargs)
+        super(FileReplicaAlreadyExists, self).__init__(*args, **kwargs)
         self._message = "File name in specified scope already exists"
         self.error_code = 20
 
@@ -254,7 +254,7 @@ class ReplicaNotFound(RucioException):
     RucioException
     """
     def __init__(self, *args, **kwargs):
-        super(ReplicaNotFound, self).__init__(args, kwargs)
+        super(ReplicaNotFound, self).__init__(*args, **kwargs)
         self._message = "Replica not found"
         self.error_code = 21
 
@@ -264,7 +264,7 @@ class ReplicaUnAvailable(RucioException):
     RucioException
     """
     def __init__(self, *args, **kwargs):
-        super(ReplicaUnAvailable, self).__init__(args, kwargs)
+        super(ReplicaUnAvailable, self).__init__(*args, **kwargs)
         self._message = "Replica unavailable"
         self.error_code = 22
 
@@ -274,7 +274,7 @@ class FullStorage(RucioException):
     RucioException
     """
     def __init__(self, *args, **kwargs):
-        super(FullStorage, self).__init__(args, kwargs)
+        super(FullStorage, self).__init__(*args, **kwargs)
         self._message = "The Referenced storage is out of disk space."
         self.error_code = 23
 
@@ -284,14 +284,14 @@ class IdentityError(RucioException):
     RucioException
     """
     def __init__(self, *args, **kwargs):
-        super(IdentityError, self).__init__(args, kwargs)
+        super(IdentityError, self).__init__(*args, **kwargs)
         self._message = "Identity error."
         self.error_code = 24
 
 
 class IdentityNotFound(RucioException):
     def __init__(self, *args, **kwargs):
-        super(IdentityNotFound, self).__init__(args, kwargs)
+        super(IdentityNotFound, self).__init__(*args, **kwargs)
         self._message = "This identity does not exist."
         self.error_code = 25
 
@@ -301,7 +301,7 @@ class InputValidationError(RucioException):
     RucioException
     """
     def __init__(self, *args, **kwargs):
-        super(InputValidationError, self).__init__(args, kwargs)
+        super(InputValidationError, self).__init__(*args, **kwargs)
         self._message = "There is an error with one of the input parameters."
         self.error_code = 26
 
@@ -311,7 +311,7 @@ class InsufficientAccountLimit(RucioException):
     RucioException
     """
     def __init__(self, *args, **kwargs):
-        super(InsufficientAccountLimit, self).__init__(args, kwargs)
+        super(InsufficientAccountLimit, self).__init__(*args, **kwargs)
         self._message = "There is not enough quota left to fulfil the operation."
         self.error_code = 27
 
@@ -321,7 +321,7 @@ class InsufficientTargetRSEs(RucioException):
     RucioException
     """
     def __init__(self, *args, **kwargs):
-        super(InsufficientTargetRSEs, self).__init__(args, kwargs)
+        super(InsufficientTargetRSEs, self).__init__(*args, **kwargs)
         self._message = "There are not enough target RSEs to fulfil the request at this time."
         self.error_code = 28
 
@@ -331,7 +331,7 @@ class InvalidMetadata(RucioException):
     RucioException
     """
     def __init__(self, *args, **kwargs):
-        super(InvalidMetadata, self).__init__(args, kwargs)
+        super(InvalidMetadata, self).__init__(*args, **kwargs)
         self._message = "Provided metadata is considered invalid."
         self.error_code = 29
 
@@ -341,7 +341,7 @@ class InvalidObject(RucioException):
     RucioException
     """
     def __init__(self, *args, **kwargs):
-        super(InvalidObject, self).__init__(args, kwargs)
+        super(InvalidObject, self).__init__(*args, **kwargs)
         self._message = "Provided object does not match schema."
         self.error_code = 30
 
@@ -351,7 +351,7 @@ class InvalidReplicationRule(RucioException):
     RucioException
     """
     def __init__(self, *args, **kwargs):
-        super(InvalidReplicationRule, self).__init__(args, kwargs)
+        super(InvalidReplicationRule, self).__init__(*args, **kwargs)
         self._message = "Provided replication rule is considered invalid."
         self.error_code = 31
 
@@ -361,7 +361,7 @@ class InvalidRSEExpression(RucioException):
     RucioException
     """
     def __init__(self, *args, **kwargs):
-        super(InvalidRSEExpression, self).__init__(args, kwargs)
+        super(InvalidRSEExpression, self).__init__(*args, **kwargs)
         self._message = "Provided RSE expression is considered invalid."
         self.error_code = 32
 
@@ -371,7 +371,7 @@ class InvalidRuleWeight(RucioException):
     RucioException
     """
     def __init__(self, *args, **kwargs):
-        super(InvalidRuleWeight, self).__init__(args, kwargs)
+        super(InvalidRuleWeight, self).__init__(*args, **kwargs)
         self._message = "An invalid weight value/type is used for an RSE."
         self.error_code = 33
 
@@ -381,7 +381,7 @@ class InvalidType(RucioException):
     RucioException
     """
     def __init__(self, *args, **kwargs):
-        super(InvalidType, self).__init__(args, kwargs)
+        super(InvalidType, self).__init__(*args, **kwargs)
         self._message = "Provided type is considered invalid."
         self.error_code = 34
 
@@ -391,7 +391,7 @@ class InvalidValueForKey(RucioException):
     RucioException
     """
     def __init__(self, *args, **kwargs):
-        super(InvalidValueForKey, self).__init__(args, kwargs)
+        super(InvalidValueForKey, self).__init__(*args, **kwargs)
         self._message = "Invalid value for the key."
         self.error_code = 35
 
@@ -401,7 +401,7 @@ class InvalidRequest(RucioException):
     RucioException
     """
     def __init__(self, *args, **kwargs):
-        super(InvalidRequest, self).__init__(args, kwargs)
+        super(InvalidRequest, self).__init__(*args, **kwargs)
         self._message = "Request is considered invalid."
         self.error_code = 36
 
@@ -411,7 +411,7 @@ class InvalidPath(RucioException):
     RucioException
     """
     def __init__(self, *args, **kwargs):
-        super(InvalidPath, self).__init__(args, kwargs)
+        super(InvalidPath, self).__init__(*args, **kwargs)
         self._message = "The path provided is invalid."
         self.error_code = 37
 
@@ -421,7 +421,7 @@ class KeyNotFound(RucioException):
     RucioException
     """
     def __init__(self, *args, **kwargs):
-        super(KeyNotFound, self).__init__(args, kwargs)
+        super(KeyNotFound, self).__init__(*args, **kwargs)
         self._message = "Key does not exist."
         self.error_code = 38
 
@@ -431,7 +431,7 @@ class LifetimeExceptionDuplicate(RucioException):
     RucioException
     """
     def __init__(self, *args, **kwargs):
-        super(LifetimeExceptionDuplicate, self).__init__(args, kwargs)
+        super(LifetimeExceptionDuplicate, self).__init__(*args, **kwargs)
         self._message = "An exception already exists."
         self.error_code = 39
 
@@ -441,7 +441,7 @@ class LifetimeExceptionNotFound(RucioException):
     RucioException
     """
     def __init__(self, *args, **kwargs):
-        super(LifetimeExceptionNotFound, self).__init__(args, kwargs)
+        super(LifetimeExceptionNotFound, self).__init__(*args, **kwargs)
         self._message = "Exception does not exist."
         self.error_code = 40
 
@@ -451,7 +451,7 @@ class ManualRuleApprovalBlocked(RucioException):
     RucioException
     """
     def __init__(self, *args, **kwargs):
-        super(ManualRuleApprovalBlocked, self).__init__(args, kwargs)
+        super(ManualRuleApprovalBlocked, self).__init__(*args, **kwargs)
         self._message = "Manual rule approval is blocked on this RSE."
         self.error_code = 41
 
@@ -461,7 +461,7 @@ class MissingClientParameter(RucioException):
     RucioException
     """
     def __init__(self, *args, **kwargs):
-        super(MissingClientParameter, self).__init__(args, kwargs)
+        super(MissingClientParameter, self).__init__(*args, **kwargs)
         self._message = "Client parameters are missing."
         self.error_code = 42
 
@@ -471,7 +471,7 @@ class MissingDependency(RucioException):
     RucioException
     """
     def __init__(self, *args, **kwargs):
-        super(MissingDependency, self).__init__(args, kwargs)
+        super(MissingDependency, self).__init__(*args, **kwargs)
         self._message = "One dependency is missing."
         self.error_code = 43
 
@@ -481,7 +481,7 @@ class MissingSourceReplica(RucioException):
     RucioException
     """
     def __init__(self, *args, **kwargs):
-        super(MissingSourceReplica, self).__init__(args, kwargs)
+        super(MissingSourceReplica, self).__init__(*args, **kwargs)
         self._message = "Source replicas are missing to fulfil the request at this moment."
         self.error_code = 44
 
@@ -491,7 +491,7 @@ class NameTypeError(RucioException):
     RucioException
     """
     def __init__(self, *args, **kwargs):
-        super(NameTypeError, self).__init__(args, kwargs)
+        super(NameTypeError, self).__init__(*args, **kwargs)
         self._message = "Name is of the wrong type"
         self.error_code = 45
 
@@ -501,7 +501,7 @@ class NoAuthInformation(RucioException):
     RucioException
     """
     def __init__(self, *args, **kwargs):
-        super(NoAuthInformation, self).__init__(args, kwargs)
+        super(NoAuthInformation, self).__init__(*args, **kwargs)
         self._message = "No authentication information passed."
         self.error_code = 46
 
@@ -511,7 +511,7 @@ class NoFilesDownloaded(RucioException):
     RucioException
     """
     def __init__(self, *args, **kwargs):
-        super(NoFilesDownloaded, self).__init__(args, kwargs)
+        super(NoFilesDownloaded, self).__init__(*args, **kwargs)
         self._message = "None of the requested files have been downloaded."
         self.error_code = 75
 
@@ -521,7 +521,7 @@ class NotAllFilesDownloaded(RucioException):
     RucioException
     """
     def __init__(self, *args, **kwargs):
-        super(NotAllFilesDownloaded, self).__init__(args, kwargs)
+        super(NotAllFilesDownloaded, self).__init__(*args, **kwargs)
         self._message = "Not all of the requested files have been downloaded."
         self.error_code = 76
 
@@ -531,14 +531,14 @@ class ReplicationRuleCreationTemporaryFailed(RucioException):
     RucioException
     """
     def __init__(self, *args, **kwargs):
-        super(ReplicationRuleCreationTemporaryFailed, self).__init__(args, kwargs)
+        super(ReplicationRuleCreationTemporaryFailed, self).__init__(*args, **kwargs)
         self._message = "The creation of the replication rule failed at this time. Please try again later."
         self.error_code = 47
 
 
 class RequestNotFound(RucioException):
     def __init__(self, *args, **kwargs):
-        super(RequestNotFound, self).__init__(args, kwargs)
+        super(RequestNotFound, self).__init__(*args, **kwargs)
         self._message = "A request for this DID and RSE does not exist."
         self.error_code = 48
 
@@ -548,7 +548,7 @@ class RSEAccessDenied(RucioException):
     RucioException
     """
     def __init__(self, *args, **kwargs):
-        super(RSEAccessDenied, self).__init__(args, kwargs)
+        super(RSEAccessDenied, self).__init__(*args, **kwargs)
         self._message = "Referenced RSE not reachable."
         self.error_code = 49
 
@@ -558,7 +558,7 @@ class RSEBlacklisted(RucioException):
     RucioException
     """
     def __init__(self, *args, **kwargs):
-        super(RSEBlacklisted, self).__init__(args, kwargs)
+        super(RSEBlacklisted, self).__init__(*args, **kwargs)
         self._message = "RSE excluded due to write blacklisting."
         self.error_code = 50
 
@@ -568,7 +568,7 @@ class RSENotConnected(RucioException):
     RucioException
     """
     def __init__(self, *args, **kwargs):
-        super(RSENotConnected, self).__init__(args, kwargs)
+        super(RSENotConnected, self).__init__(*args, **kwargs)
         self._message = "Connection to RSE not established."
         self.error_code = 51
 
@@ -578,7 +578,7 @@ class RSENotFound(RucioException):
     RucioException
     """
     def __init__(self, *args, **kwargs):
-        super(RSENotFound, self).__init__(args, kwargs)
+        super(RSENotFound, self).__init__(*args, **kwargs)
         self._message = "RSE does not exist."
         self.error_code = 52
 
@@ -588,7 +588,7 @@ class RSEProtocolNotSupported(RucioException):
     RucioException
     """
     def __init__(self, *args, **kwargs):
-        super(RSEProtocolNotSupported, self).__init__(args, kwargs)
+        super(RSEProtocolNotSupported, self).__init__(*args, **kwargs)
         self._message = "RSE does not support requested protocol."
         self.error_code = 53
 
@@ -598,7 +598,7 @@ class RSEProtocolPriorityError(RucioException):
     RucioException
     """
     def __init__(self, *args, **kwargs):
-        super(RSEProtocolPriorityError, self).__init__(args, kwargs)
+        super(RSEProtocolPriorityError, self).__init__(*args, **kwargs)
         self._message = "RSE does not support provided protocol priority for protocol."
         self.error_code = 54
 
@@ -608,7 +608,7 @@ class RSEProtocolDomainNotSupported(RucioException):
     RucioException
     """
     def __init__(self, *args, **kwargs):
-        super(RSEProtocolDomainNotSupported, self).__init__(args, kwargs)
+        super(RSEProtocolDomainNotSupported, self).__init__(*args, **kwargs)
         self._message = "RSE does not support requested protocol scope."
         self.error_code = 55
 
@@ -618,7 +618,7 @@ class RSEOperationNotSupported(RucioException):
     RucioException
     """
     def __init__(self, *args, **kwargs):
-        super(RSEOperationNotSupported, self).__init__(args, kwargs)
+        super(RSEOperationNotSupported, self).__init__(*args, **kwargs)
         self._message = "RSE does not support requested operation."
         self.error_code = 56
 
@@ -628,7 +628,7 @@ class RSEFileNameNotSupported(RucioException):
     RucioException
     """
     def __init__(self, *args, **kwargs):
-        super(RSEFileNameNotSupported, self).__init__(args, kwargs)
+        super(RSEFileNameNotSupported, self).__init__(*args, **kwargs)
         self._message = "RSE does not support provided filename."
         self.error_code = 57
 
@@ -638,7 +638,7 @@ class RSEOverQuota(RucioException):
     RucioException
     """
     def __init__(self, *args, **kwargs):
-        super(RSEOverQuota, self).__init__(args, kwargs)
+        super(RSEOverQuota, self).__init__(*args, **kwargs)
         self._message = "Quota of Referenced RSE is exceeded."
         self.error_code = 58
 
@@ -648,7 +648,7 @@ class ResourceTemporaryUnavailable(RucioException):
     RucioException
     """
     def __init__(self, *args, **kwargs):
-        super(ResourceTemporaryUnavailable, self).__init__(args, kwargs)
+        super(ResourceTemporaryUnavailable, self).__init__(*args, **kwargs)
         self._message = "The resource is temporary not available."
         self.error_code = 59
 
@@ -658,7 +658,7 @@ class RuleNotFound(RucioException):
     RucioException
     """
     def __init__(self, *args, **kwargs):
-        super(RuleNotFound, self).__init__(args, kwargs)
+        super(RuleNotFound, self).__init__(*args, **kwargs)
         self._message = "No replication rule found."
         self.error_code = 60
 
@@ -668,7 +668,7 @@ class RuleReplaceFailed(RucioException):
     RucioException
     """
     def __init__(self, *args, **kwargs):
-        super(RuleReplaceFailed, self).__init__(args, kwargs)
+        super(RuleReplaceFailed, self).__init__(*args, **kwargs)
         self._message = "The replace operation for the rule failed."
         self.error_code = 61
 
@@ -678,7 +678,7 @@ class ScratchDiskLifetimeConflict(RucioException):
     RucioException
     """
     def __init__(self, *args, **kwargs):
-        super(ScratchDiskLifetimeConflict, self).__init__(args, kwargs)
+        super(ScratchDiskLifetimeConflict, self).__init__(*args, **kwargs)
         self._message = "The requested replication rule exceeds the maximum SCRATCHDISK lifetime of 15 days."
         self.error_code = 62
 
@@ -688,7 +688,7 @@ class ServiceUnavailable(RucioException):
     RucioException
     """
     def __init__(self, *args, **kwargs):
-        super(ServiceUnavailable, self).__init__(args, kwargs)
+        super(ServiceUnavailable, self).__init__(*args, **kwargs)
         self._message = "The requested service is not available at the moment."
         self.error_code = 63
 
@@ -698,7 +698,7 @@ class ScopeAccessDenied(RucioException):
     RucioException
     """
     def __init__(self, *args, **kwargs):
-        super(ScopeAccessDenied, self).__init__(args, kwargs)
+        super(ScopeAccessDenied, self).__init__(*args, **kwargs)
         self._message = "Access to Referenced scope denied."
         self.error_code = 64
 
@@ -708,7 +708,7 @@ class ScopeNotFound(RucioException):
     RucioException
     """
     def __init__(self, *args, **kwargs):
-        super(ScopeNotFound, self).__init__(args, kwargs)
+        super(ScopeNotFound, self).__init__(*args, **kwargs)
         self._message = "Scope does not exist."
         self.error_code = 65
 
@@ -718,7 +718,7 @@ class SourceAccessDenied(RucioException):
     RucioException
     """
     def __init__(self, *args, **kwargs):
-        super(SourceAccessDenied, self).__init__(args, kwargs)
+        super(SourceAccessDenied, self).__init__(*args, **kwargs)
         self._message = "Access to local source file denied."
         self.error_code = 66
 
@@ -728,7 +728,7 @@ class SourceNotFound(RucioException):
     RucioException
     """
     def __init__(self, *args, **kwargs):
-        super(SourceNotFound, self).__init__(args, kwargs)
+        super(SourceNotFound, self).__init__(*args, **kwargs)
         self._message = "Source file not found."
         self.error_code = 67
 
@@ -738,7 +738,7 @@ class StagingAreaRuleRequiresLifetime(RucioException):
     RucioException
     """
     def __init__(self, *args, **kwargs):
-        super(StagingAreaRuleRequiresLifetime, self).__init__(args, kwargs)
+        super(StagingAreaRuleRequiresLifetime, self).__init__(*args, **kwargs)
         self._message = "A rule involving a staging area requires a lifetime!"
         self.error_code = 68
 
@@ -748,7 +748,7 @@ class SubscriptionDuplicate(RucioException):
     RucioException
     """
     def __init__(self, *args, **kwargs):
-        super(SubscriptionDuplicate, self).__init__(args, kwargs)
+        super(SubscriptionDuplicate, self).__init__(*args, **kwargs)
         self._message = "A subscription with the same identifier already exists."
         self.error_code = 69
 
@@ -758,7 +758,7 @@ class SubscriptionNotFound(RucioException):
     RucioException
     """
     def __init__(self, *args, **kwargs):
-        super(SubscriptionNotFound, self).__init__(args, kwargs)
+        super(SubscriptionNotFound, self).__init__(*args, **kwargs)
         self._message = "Subscription not found."
         self.error_code = 70
 
@@ -768,7 +768,7 @@ class UnsupportedDIDType(RucioException):
     RucioException
     """
     def __init__(self, *args, **kwargs):
-        super(UnsupportedDIDType, self).__init__(args, kwargs)
+        super(UnsupportedDIDType, self).__init__(*args, **kwargs)
         self._message = "Unsupported DID type for this operation. Only DATASET or FILE is allowed."
         self.error_code = 71
 
@@ -778,7 +778,7 @@ class UnsupportedOperation(RucioException):
     RucioException
     """
     def __init__(self, *args, **kwargs):
-        super(UnsupportedOperation, self).__init__(args, kwargs)
+        super(UnsupportedOperation, self).__init__(*args, **kwargs)
         self._message = "The resource doesn't support the requested operation."
         self.error_code = 72
 
@@ -788,7 +788,7 @@ class UnsupportedStatus(RucioException):
     RucioException
     """
     def __init__(self, *args, **kwargs):
-        super(UnsupportedStatus, self).__init__(args, kwargs)
+        super(UnsupportedStatus, self).__init__(*args, **kwargs)
         self._message = "Unsupported data identifier status."
         self.error_code = 73
 
@@ -798,6 +798,6 @@ class UnsupportedValueType(RucioException):
     RucioException
     """
     def __init__(self, *args, **kwargs):
-        super(UnsupportedValueType, self).__init__(args, kwargs)
+        super(UnsupportedValueType, self).__init__(*args, **kwargs)
         self._message = "Unsupported type for the value. List of supported types: %s." % str(AUTHORIZED_VALUE_TYPES)
         self.error_code = 74


Test patch: