Skip to content

Commit

Permalink
Transfers: Fixup pylint suggestions. rucio#570
Browse files Browse the repository at this point in the history
  • Loading branch information
bbockelm committed Feb 5, 2018
1 parent ce1b6b2 commit fb507db
Show file tree
Hide file tree
Showing 3 changed files with 75 additions and 32 deletions.
67 changes: 39 additions & 28 deletions lib/rucio/rse/protocols/protocol.py
@@ -1,21 +1,26 @@
# 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:
# - Ralph Vigne, <ralph.vigne@cern.ch>, 2012-2014
# - Cedric Serfon, <cedric.serfon@cern.ch>, 2013-2016
# - Wen Guan, <wen.guan@cern.ch>, 2014
# - Cheng-Hsi Chao, <cheng-hsi.chao@cern.ch>, 2014
# - Mario Lassnig, <mario.lassnig@cern.ch>, 2017
"""
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:
- Ralph Vigne, <ralph.vigne@cern.ch>, 2012-2014
- Cedric Serfon, <cedric.serfon@cern.ch>, 2013-2016
- Wen Guan, <wen.guan@cern.ch>, 2014
- Cheng-Hsi Chao, <cheng-hsi.chao@cern.ch>, 2014
- Mario Lassnig, <mario.lassnig@cern.ch>, 2017
- Brian Bockelman, <bbockelm@cse.unl.edu>, 2018
This module defines the base class for implementing a transfer protocol,
along with some of the default methods for LFN2PFN translations.
"""

import hashlib
import importlib

from exceptions import NotImplementedError
from urlparse import urlparse
from ConfigParser import NoOptionError, NoSectionError

Expand Down Expand Up @@ -65,23 +70,29 @@ def register(lfn2pfn_callable, name=None):
RSEDeterministicTranslation._LFN2PFN_ALGORITHMS[name] = lfn2pfn_callable

@staticmethod
def __hash(scope, name, rse, _, __):
def __hash(scope, name, rse, rse_attrs, protocol_attrs):
"""
Given a LFN, turn it into a sub-directory structure using a hash function.
"""
del rse
del rse_attrs
del protocol_attrs
hstr = hashlib.md5('%s:%s' % (scope, name)).hexdigest()
if scope.startswith('user') or scope.startswith('group'):
scope = scope.replace('.', '/')
return '%s/%s/%s/%s' % (scope, hstr[0:2], hstr[2:4], name)

@staticmethod
def __identity(scope, name, rse, _, __):
def __identity(scope, name, rse, rse_attrs, protocol_attrs):
"""
Given a LFN, convert it directly to a path using the mapping:
scope:path -> scope/path
"""
del rse
del rse_attrs
del protocol_attrs
if scope.startswith('user') or scope.startswith('group'):
scope = scope.replace('.', '/')
return '%s/%s' % (scope, name)
Expand Down Expand Up @@ -122,7 +133,7 @@ def path(self, scope, name):
return algorithm_callable(scope, name, self.rse, self.rse_attributes, self.protocol_attributes)


RSEDeterministicTranslation._module_init_()
RSEDeterministicTranslation._module_init_() #pylint: disable=protected-access


class RSEProtocol(object):
Expand All @@ -139,7 +150,7 @@ def __init__(self, protocol_attr, rse_settings):
self.overwrite = False
self.rse = rse_settings
if self.rse['deterministic']:
self.translator = RSEDeterministicTranslation(self.rse['rse'], self.rse_settings, self.attributes)
self.translator = RSEDeterministicTranslation(self.rse['rse'], rse_settings, self.attributes)
else:
if getattr(rsemanager, 'CLIENT_MODE', None):
setattr(self, 'lfns2pfns', self.__lfns2pfns_client)
Expand All @@ -162,7 +173,7 @@ def lfns2pfns(self, lfns):
if not prefix.endswith('/'):
prefix = ''.join([prefix, '/'])

lfns = [lfns] if type(lfns) == dict else lfns
lfns = [lfns] if isinstance(lfns, dict) else lfns
for lfn in lfns:
scope, name = lfn['scope'], lfn['name']
if 'path' in lfn and lfn['path'] is not None:
Expand All @@ -173,7 +184,7 @@ def lfns2pfns(self, lfns):
str(self.attributes['port']),
prefix,
lfn['path'] if not lfn['path'].startswith('/') else lfn['path'][1:]
])
])
else:
pfns['%s:%s' % (scope, name)] = ''.join([self.attributes['scheme'],
'://',
Expand All @@ -182,7 +193,7 @@ def lfns2pfns(self, lfns):
str(self.attributes['port']),
prefix,
self._get_path(scope=scope, name=name)
])
])
return pfns

def __lfns2pfns_client(self, lfns):
Expand All @@ -195,7 +206,7 @@ def __lfns2pfns_client(self, lfns):
client = ReplicaClient()
pfns = {}

lfns = [lfns] if type(lfns) == dict else lfns
lfns = [lfns] if isinstance(lfns, dict) else lfns
for lfn in lfns:
scope = lfn['scope']
name = lfn['name']
Expand All @@ -219,12 +230,12 @@ def _get_path(self, scope, name):
"""
return self.translator.path(scope, name)

def _get_path_nondeterministic_server(self, scope, name):
def _get_path_nondeterministic_server(self, scope, name): #pylint: disable=invalid-name
""" Provides the path of a replica for non-deterministic sites. Will be assigned to get path by the __init__ method if neccessary. """
r = replica.get_replica(rse=self.rse['rse'], scope=scope, name=name, rse_id=self.rse['id'])
if 'path' in r and r['path'] is not None:
path = r['path']
elif 'state' in r and (r['state'] is None or r['state'] == 'UNAVAILABLE'):
rep = replica.get_replica(rse=self.rse['rse'], scope=scope, name=name, rse_id=self.rse['id'])
if 'path' in rep and rep['path'] is not None:
path = rep['path']
elif 'state' in rep and (rep['state'] is None or rep['state'] == 'UNAVAILABLE'):
raise exception.ReplicaUnAvailable('Missing path information and state is UNAVAILABLE for replica %s:%s on non-deterministic storage named %s' % (scope, name, self.rse['rse']))
else:
raise exception.ReplicaNotFound('Missing path information for replica %s:%s on non-deterministic storage named %s' % (scope, name, self.rse['rse']))
Expand All @@ -245,7 +256,7 @@ def parse_pfns(self, pfns):
:raises RSEFileNameNotSupported: if the provided PFN doesn't match with the protocol settings
"""
ret = dict()
pfns = [pfns] if ((type(pfns) == str) or (type(pfns) == unicode)) else pfns
pfns = [pfns] if (isinstance(pfns, str) or isinstance(pfns, unicode)) else pfns

for pfn in pfns:
parsed = urlparse(pfn)
Expand Down
8 changes: 7 additions & 1 deletion lib/rucio/tests/lfn2pfn_module_test.py
Expand Up @@ -11,7 +11,13 @@
from rucio.rse.protocols.protocol import RSEDeterministicTranslation


def lfn2pfn_module_algorithm(scope, name, rse, rse_attributes, protcol_attributes):
def lfn2pfn_module_algorithm(scope, name, rse, rse_attributes, protocol_attributes):
"""Dummy LFN2PFN algorithm for unit tests."""
del scope
del name
del rse
del rse_attributes
del protocol_attributes
return "lfn2pfn_module_algorithm_value"


Expand Down
32 changes: 29 additions & 3 deletions lib/rucio/tests/test_rse_lfn2path.py
Expand Up @@ -21,6 +21,13 @@ class TestDeterministicTranslation(object):
Verify the deterministic translator.
"""

def __init__(self):
"""Setup dummy instance"""
self.rse = None
self.rse_attributes = None
self.protocol_attributes = None
self.translator = None

def setup(self):
"""LFN2PFN: Creating RSEDeterministicTranslation instance"""
self.rse = 'Mock'
Expand Down Expand Up @@ -55,9 +62,21 @@ def test_user_scope(self):
def test_register_func(self):
"""LFN2PFN: Verify we can register a custom function (Success)"""
def static_register_test1(scope, name, rse, rse_attrs, proto_attrs):
"""Test function for registering LFN2PATH functions."""
del scope
del name
del rse
del rse_attrs
del proto_attrs
return "static_register_value1"

def static_register_test2(scope, name, rse, rse_attrs, proto_attrs):
"""Second test function for registering LFN2PATH functions."""
del scope
del name
del rse
del rse_attrs
del proto_attrs
return "static_register_value2"

RSEDeterministicTranslation.register(static_register_test1)
Expand All @@ -72,6 +91,7 @@ def static_register_test2(scope, name, rse, rse_attrs, proto_attrs):
def test_attr_mapping(self):
"""LFN2PFN: Verify we can map using rse and attrs (Successs)"""
def rse_algorithm(scope, name, rse, rse_attrs, proto_attrs):
"""Test LFN2PATH function for exercising the different RSE/proto attrs."""
tier = rse_attrs.get("tier", "T1")
scheme = proto_attrs.get("scheme", "http")
return "%s://%s_%s/%s/%s" % (scheme, tier, rse, scope, name)
Expand All @@ -92,7 +112,7 @@ def rse_algorithm(scope, name, rse, rse_attrs, proto_attrs):
def test_module_load(self):
"""LFN2PFN: Test ability to provide LFN2PFN functions via module (Success)"""
config.config_set('policy', 'lfn2pfn_module', 'rucio.tests.lfn2pfn_module_test')
RSEDeterministicTranslation._module_init_()
RSEDeterministicTranslation._module_init_() #pylint: disable=protected-access
self.rse_attributes['lfn2pfn_algorithm'] = 'lfn2pfn_module_algorithm'
self.create_translator()
assert_equal(self.translator.path("foo", "bar"), "lfn2pfn_module_algorithm_value")
Expand All @@ -105,16 +125,22 @@ def test_config_default_override(self):
orig_value = None

def static_test(scope, name, rse, rse_attrs, proto_attrs):
"""Static test function for config override."""
del scope
del name
del rse
del rse_attrs
del proto_attrs
return "static_test_value"

RSEDeterministicTranslation.register(static_test)
try:
config.config_set('policy', 'lfn2pfn_algorithm_default', 'static_test')
RSEDeterministicTranslation._module_init_()
RSEDeterministicTranslation._module_init_() #pylint: disable=protected-access
assert_equal(self.translator.path("foo", "bar"), "static_test_value")
finally:
if orig_value is None:
config.config_remove_option('policy', 'lfn2pfn_algorithm_default')
else:
config.config_set('policy', 'lfn2pfn_algorithm_default', orig_value)
RSEDeterministicTranslation._module_init_()
RSEDeterministicTranslation._module_init_() #pylint: disable=protected-access

0 comments on commit fb507db

Please sign in to comment.