Repository: rucio/rucio

Issue:
two different `DIDType` object types are confusing
Motivation
----------
There is a DIDType object 
- one represents the "type" of a DID (file, container, etc)
- the other is used to represent a scope+name

Modification
------------
I suggest to rename the second one to `DID`




Discussion:

Resolving patch:
diff --git a/lib/rucio/client/downloadclient.py b/lib/rucio/client/downloadclient.py
--- a/lib/rucio/client/downloadclient.py
+++ b/lib/rucio/client/downloadclient.py
@@ -33,7 +33,7 @@
 from rucio.client.client import Client
 from rucio.common.config import config_get
 from rucio.common.exception import (InputValidationError, NoFilesDownloaded, NotAllFilesDownloaded, RucioException)
-from rucio.common.didtype import DIDType
+from rucio.common.didtype import DID
 from rucio.common.pcache import Pcache
 from rucio.common.utils import adler32, detect_client_location, generate_uuid, parse_replicas_from_string, \
     send_trace, sizefmt, execute, parse_replicas_from_file, extract_scope
@@ -202,7 +202,7 @@ def download_pfns(self, items, num_threads=2, trace_custom_fields={}, traces_cop
             did_str = item.get('did')
             pfn = item.get('pfn')
             rse = item.get('rse')
-            item['input_dids'] = {DIDType(did_str): {}}
+            item['input_dids'] = {DID(did_str): {}}
 
             if not did_str or not pfn or not rse:
                 logger(logging.DEBUG, item)
@@ -322,7 +322,7 @@ def download_from_metalink_file(self, item, metalink_file_path, num_threads=2, t
 
         did_to_options = {}
         for metalink in metalinks:
-            did = DIDType(metalink['did'])
+            did = DID(metalink['did'])
             did_to_options[did] = [item]
             metalink['input_dids'] = {did: {}}
 
@@ -1090,7 +1090,7 @@ def _resolve_and_merge_input_items(self, input_items):
                 logger(logging.WARNING, 'An item didnt have any DIDs after resolving the input: %s.' % item.get('did', item))
             item['dids'] = resolved_dids
             for did in resolved_dids:
-                did_to_input_items.setdefault(DIDType(did), []).append(item)
+                did_to_input_items.setdefault(DID(did), []).append(item)
 
                 if 'length' in did and not did['length']:
                     did_with_size = self.client.get_did(scope=did['scope'], name=did['name'], dynamic=True)
@@ -1118,7 +1118,7 @@ def _resolve_and_merge_input_items(self, input_items):
         for item_group in item_groups:
             # Take configuration from the first item in the group; but dids from all items
             item = item_group[0]
-            input_dids = {DIDType(did): did
+            input_dids = {DID(did): did
                           for item in item_group
                           for did in item.get('dids')}
 
@@ -1193,9 +1193,9 @@ def _resolve_and_merge_input_items(self, input_items):
             # Match the file did back to the dids which were provided to list_replicas.
             # Later, this will allow to match the file back to input_items via did_to_input_items
             for file_item in file_items:
-                file_did = DIDType(file_item['did'])
+                file_did = DID(file_item['did'])
 
-                file_input_dids = {DIDType(did) for did in file_item.get('parent_dids', [])}.intersection(input_dids)
+                file_input_dids = {DID(did) for did in file_item.get('parent_dids', [])}.intersection(input_dids)
                 if file_did in input_dids:
                     file_input_dids.add(file_did)
                 file_item['input_dids'] = {did: input_dids[did] for did in file_input_dids}
@@ -1272,7 +1272,7 @@ def _prepare_items_for_download(self, did_to_input_items, file_items):
 
         # get replicas for every file of the given dids
         for file_item in file_items:
-            file_did = DIDType(file_item['did'])
+            file_did = DID(file_item['did'])
             input_items = list(itertools.chain.from_iterable(did_to_input_items.get(did, []) for did in file_item['input_dids']))
             options = self._options_from_input_items(input_items)
 
diff --git a/lib/rucio/common/didtype.py b/lib/rucio/common/didtype.py
--- a/lib/rucio/common/didtype.py
+++ b/lib/rucio/common/didtype.py
@@ -19,14 +19,14 @@
 
 from six import string_types
 
-from rucio.common.exception import DIDTypeError
+from rucio.common.exception import DIDError
 
 
-class DIDType(object):
+class DID(object):
 
     """
     Class used to store a DID
-    Given an object did of type DIDType
+    Given an object did of type DID
     scope is stored in did.scope
     name is stored in did.name
     """
@@ -38,30 +38,30 @@ class DIDType(object):
 
     def __init__(self, *args, **kwargs):
         """
-        Constructs the DIDType object. Possible parameter combinations are:
-            DIDType()
-            DIDType('scope:name.did.str')
-            DIDType('user.implicit.scope.in.name')
-            DIDType('custom.scope', 'custom.name')
-            DIDType(['list.scope', 'list.name'])
-            DIDType(('tuple.scope', 'tuple.name'))
-            DIDType({'scope': 'dict.scope', 'name': 'dict.name'})
-            DIDType(scope='kw.scope')
-            DIDType(name='kw.name')
-            DIDType(name='user.kw.implicit.scope')
-            DIDType(scope='kw.scope', name='kw.name')
-            DIDType(did={'scope': 'kw.did.scope', 'name': 'kw.did.name'})
-            DIDType(did=['kw.list.scope', 'kw.list.name'])
-            DIDType(did=('kw.tuple.scope', 'kw.tuple.name'))
-            DIDType('arg.scope', name='kwarg.name')
-            DIDType('arg.name', scope='kwarg.scope')
+        Constructs the DID object. Possible parameter combinations are:
+            DID()
+            DID('scope:name.did.str')
+            DID('user.implicit.scope.in.name')
+            DID('custom.scope', 'custom.name')
+            DID(['list.scope', 'list.name'])
+            DID(('tuple.scope', 'tuple.name'))
+            DID({'scope': 'dict.scope', 'name': 'dict.name'})
+            DID(scope='kw.scope')
+            DID(name='kw.name')
+            DID(name='user.kw.implicit.scope')
+            DID(scope='kw.scope', name='kw.name')
+            DID(did={'scope': 'kw.did.scope', 'name': 'kw.did.name'})
+            DID(did=['kw.list.scope', 'kw.list.name'])
+            DID(did=('kw.tuple.scope', 'kw.tuple.name'))
+            DID('arg.scope', name='kwarg.name')
+            DID('arg.name', scope='kwarg.scope')
         """
         self.scope = self.name = ''
 
         num_args = len(args)
         num_kwargs = len(kwargs)
         if (num_args + num_kwargs) > 2:
-            raise DIDTypeError('Constructor takes at most 2 arguments. Given number: {}'.format(num_args + num_kwargs))
+            raise DIDError('Constructor takes at most 2 arguments. Given number: {}'.format(num_args + num_kwargs))
 
         did = ''
         if num_args == 1:
@@ -69,8 +69,8 @@ def __init__(self, *args, **kwargs):
 
             if num_kwargs == 1:
                 if not isinstance(did, string_types):
-                    raise DIDTypeError('First argument of constructor is expected to be string type'
-                                       'when keyword argument is given. Given type: {}'.format(type(did)))
+                    raise DIDError('First argument of constructor is expected to be string type'
+                                   'when keyword argument is given. Given type: {}'.format(type(did)))
 
                 k, v = next(iter(kwargs.items()))
                 if k == 'scope':
@@ -78,7 +78,7 @@ def __init__(self, *args, **kwargs):
                 elif k == 'name':
                     did = (did, v)
                 else:
-                    raise DIDTypeError('Constructor got unexpected keyword argument: {}'.format(k))
+                    raise DIDError('Constructor got unexpected keyword argument: {}'.format(k))
         elif num_args == 0:
             did = kwargs.get('did', kwargs)
         else:
@@ -91,37 +91,37 @@ def __init__(self, *args, **kwargs):
                 self.update_implicit_scope()
         elif isinstance(did, tuple) or isinstance(did, list):
             if len(did) != 2:
-                raise DIDTypeError('Construction from tuple or list requires exactly 2 elements')
+                raise DIDError('Construction from tuple or list requires exactly 2 elements')
             self.scope = did[0]
             self.name = did[1]
         elif isinstance(did, string_types):
-            did_parts = did.split(DIDType.SCOPE_SEPARATOR, 1)
+            did_parts = did.split(DID.SCOPE_SEPARATOR, 1)
             if len(did_parts) == 1:
                 self.name = did
                 self.update_implicit_scope()
                 if not self.has_scope():
-                    raise DIDTypeError('Object construction from non-splitable string is ambigious')
+                    raise DIDError('Object construction from non-splitable string is ambigious')
             else:
                 self.scope = did_parts[0]
                 self.name = did_parts[1]
-        elif isinstance(did, DIDType):
+        elif isinstance(did, DID):
             self.scope = did.scope
             self.name = did.name
         else:
-            raise DIDTypeError('Cannot build object from: {}'.format(type(did)))
+            raise DIDError('Cannot build object from: {}'.format(type(did)))
 
         if self.name.endswith('/'):
             self.name = self.name[:-1]
 
         if not self.is_valid_format():
-            raise DIDTypeError('Object has invalid format after construction: {}'.format(str(self)))
+            raise DIDError('Object has invalid format after construction: {}'.format(str(self)))
 
     def update_implicit_scope(self):
         """
         This method sets the scope  if it is implicitly given in self.name
         """
-        did_parts = self.name.split(DIDType.IMPLICIT_SCOPE_SEPARATOR)
-        num_scope_parts = DIDType.IMPLICIT_SCOPE_TO_LEN.get(did_parts[0], 0)
+        did_parts = self.name.split(DID.IMPLICIT_SCOPE_SEPARATOR)
+        num_scope_parts = DID.IMPLICIT_SCOPE_TO_LEN.get(did_parts[0], 0)
         if num_scope_parts > 0:
             self.scope = '.'.join(did_parts[0:num_scope_parts])
 
@@ -130,7 +130,7 @@ def is_valid_format(self):
         Method to check if the stored DID has a valid format
         :return: bool
         """
-        if self.scope.count(DIDType.SCOPE_SEPARATOR) or self.name.count(DIDType.SCOPE_SEPARATOR):
+        if self.scope.count(DID.SCOPE_SEPARATOR) or self.name.count(DID.SCOPE_SEPARATOR):
             return False
         return True
 
@@ -154,7 +154,7 @@ def __str__(self):
         :return: string
         """
         if self.has_scope() and self.has_name():
-            return '{}{}{}'.format(self.scope, DIDType.SCOPE_SEPARATOR, self.name)
+            return '{}{}{}'.format(self.scope, DID.SCOPE_SEPARATOR, self.name)
         elif self.has_scope():
             return self.scope
         return self.name
@@ -166,10 +166,10 @@ def __eq__(self, other):
         """
         if isinstance(other, string_types):
             return str(self) == other
-        elif not isinstance(other, DIDType):
+        elif not isinstance(other, DID):
             try:
-                other = DIDType(other)
-            except DIDTypeError:
+                other = DID(other)
+            except DIDError:
                 return False
 
         return self.scope == other.scope and self.name == other.name
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
@@ -941,13 +941,13 @@ def __init__(self, *args, **kwargs):
         self.error_code = 90
 
 
-class DIDTypeError(RucioException):
+class DIDError(RucioException):
     """
-    An operation related to DIDType went wrong
+    An operation related to DID type went wrong
     """
     def __init__(self, *args, **kwargs):
-        super(DIDTypeError, self).__init__(*args, **kwargs)
-        self._message = 'Error using DIDType'
+        super(DIDError, self).__init__(*args, **kwargs)
+        self._message = 'Error using DID type'
         self.error_code = 91
 
 


Test patch:
diff --git a/lib/rucio/tests/test_didtype.py b/lib/rucio/tests/test_didtype.py
--- a/lib/rucio/tests/test_didtype.py
+++ b/lib/rucio/tests/test_didtype.py
@@ -13,14 +13,14 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-from rucio.common.didtype import DIDType
-from rucio.common.exception import DIDTypeError
+from rucio.common.didtype import DID
+from rucio.common.exception import DIDError
 
 
 class TestDIDType:
     ''' Test the DIDType class '''
 
-    def _test_did(self, did, cmp_str, diff_half_did=DIDType(scope='diff'), diff_full_did=DIDType('sdiff:ndiff'), is_valid=True):
+    def _test_did(self, did, cmp_str, diff_half_did=DID(scope='diff'), diff_full_did=DID('sdiff:ndiff'), is_valid=True):
         stat = 0
         did_as_str = str(did)
         if did == diff_half_did:
@@ -48,50 +48,50 @@ def test_did_type(self):
         ''' Test DIDType '''
         self.success = True
         try:
-            self._print_test(self._test_did(DIDType(), ''))
-            self._print_test(self._test_did(DIDType('scope:name.did.str'), 'scope:name.did.str'))
-            self._print_test(self._test_did(DIDType('user.implicit.scope.in.name'), 'user.implicit:user.implicit.scope.in.name'))
-            self._print_test(self._test_did(DIDType('custom.scope', 'custom.name'), 'custom.scope:custom.name'))
-            self._print_test(self._test_did(DIDType(['list.scope', 'list.name']), 'list.scope:list.name'))
-            self._print_test(self._test_did(DIDType(('tuple.scope', 'tuple.name')), 'tuple.scope:tuple.name'))
-            self._print_test(self._test_did(DIDType({'scope': 'dict.scope', 'name': 'dict.name'}), 'dict.scope:dict.name'))
-            self._print_test(self._test_did(DIDType(scope='kw.scope'), 'kw.scope'))
-            self._print_test(self._test_did(DIDType(name='kw.name'), 'kw.name'))
-            self._print_test(self._test_did(DIDType(name='user.kw.implicit.scope'), 'user.kw:user.kw.implicit.scope'))
-            self._print_test(self._test_did(DIDType(scope='kw.scope', name='kw.name'), 'kw.scope:kw.name'))
-            self._print_test(self._test_did(DIDType(did={'scope': 'kw.did.scope', 'name': 'kw.did.name'}), 'kw.did.scope:kw.did.name'))
-            self._print_test(self._test_did(DIDType(did=['kw.list.scope', 'kw.list.name']), 'kw.list.scope:kw.list.name'))
-            self._print_test(self._test_did(DIDType(did=('kw.tuple.scope', 'kw.tuple.name')), 'kw.tuple.scope:kw.tuple.name'))
-            self._print_test(self._test_did(DIDType('arg.scope', name='kwarg.name'), 'arg.scope:kwarg.name'))
-            self._print_test(self._test_did(DIDType('arg.name', scope='kwarg.scope'), 'kwarg.scope:arg.name'))
-            x = DIDType('scope.copy:name.test')
-            y = DIDType(x)
+            self._print_test(self._test_did(DID(), ''))
+            self._print_test(self._test_did(DID('scope:name.did.str'), 'scope:name.did.str'))
+            self._print_test(self._test_did(DID('user.implicit.scope.in.name'), 'user.implicit:user.implicit.scope.in.name'))
+            self._print_test(self._test_did(DID('custom.scope', 'custom.name'), 'custom.scope:custom.name'))
+            self._print_test(self._test_did(DID(['list.scope', 'list.name']), 'list.scope:list.name'))
+            self._print_test(self._test_did(DID(('tuple.scope', 'tuple.name')), 'tuple.scope:tuple.name'))
+            self._print_test(self._test_did(DID({'scope': 'dict.scope', 'name': 'dict.name'}), 'dict.scope:dict.name'))
+            self._print_test(self._test_did(DID(scope='kw.scope'), 'kw.scope'))
+            self._print_test(self._test_did(DID(name='kw.name'), 'kw.name'))
+            self._print_test(self._test_did(DID(name='user.kw.implicit.scope'), 'user.kw:user.kw.implicit.scope'))
+            self._print_test(self._test_did(DID(scope='kw.scope', name='kw.name'), 'kw.scope:kw.name'))
+            self._print_test(self._test_did(DID(did={'scope': 'kw.did.scope', 'name': 'kw.did.name'}), 'kw.did.scope:kw.did.name'))
+            self._print_test(self._test_did(DID(did=['kw.list.scope', 'kw.list.name']), 'kw.list.scope:kw.list.name'))
+            self._print_test(self._test_did(DID(did=('kw.tuple.scope', 'kw.tuple.name')), 'kw.tuple.scope:kw.tuple.name'))
+            self._print_test(self._test_did(DID('arg.scope', name='kwarg.name'), 'arg.scope:kwarg.name'))
+            self._print_test(self._test_did(DID('arg.name', scope='kwarg.scope'), 'kwarg.scope:arg.name'))
+            x = DID('scope.copy:name.test')
+            y = DID(x)
             if x != y:
                 print('Copy failed: {} != {}'.format(x, y))
                 self.success = False
-        except DIDTypeError as err:
+        except DIDError as err:
             print('Exception: {}'.format(err))
             self.success = False
 
         try:
-            DIDType('non.implicit.single.string')
+            DID('non.implicit.single.string')
             print('Exception for invalid DID did not work!')
             self.success = False
-        except DIDTypeError:
+        except DIDError:
             pass
 
         try:
-            DIDType('invalid', 'user.implicit:user:invalid')
+            DID('invalid', 'user.implicit:user:invalid')
             print('Exception for invalid DID did not work!')
             self.success = False
-        except DIDTypeError:
+        except DIDError:
             pass
 
         try:
-            DIDType('user.implicit:user:invalid')
+            DID('user.implicit:user:invalid')
             print('Exception for invalid DID did not work!')
             self.success = False
-        except DIDTypeError:
+        except DIDError:
             pass
 
         assert self.success