rucio-clients 32.8.6__py3-none-any.whl → 35.8.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of rucio-clients might be problematic. Click here for more details.
- rucio/__init__.py +0 -1
- rucio/alembicrevision.py +1 -2
- rucio/client/__init__.py +0 -1
- rucio/client/accountclient.py +45 -25
- rucio/client/accountlimitclient.py +37 -9
- rucio/client/baseclient.py +199 -154
- rucio/client/client.py +2 -3
- rucio/client/configclient.py +19 -6
- rucio/client/credentialclient.py +9 -4
- rucio/client/didclient.py +238 -63
- rucio/client/diracclient.py +13 -5
- rucio/client/downloadclient.py +162 -51
- rucio/client/exportclient.py +4 -4
- rucio/client/fileclient.py +3 -4
- rucio/client/importclient.py +4 -4
- rucio/client/lifetimeclient.py +21 -5
- rucio/client/lockclient.py +18 -8
- rucio/client/{metaclient.py → metaconventionsclient.py} +18 -15
- rucio/client/pingclient.py +0 -1
- rucio/client/replicaclient.py +15 -5
- rucio/client/requestclient.py +35 -19
- rucio/client/rseclient.py +133 -51
- rucio/client/ruleclient.py +29 -22
- rucio/client/scopeclient.py +8 -6
- rucio/client/subscriptionclient.py +47 -35
- rucio/client/touchclient.py +8 -4
- rucio/client/uploadclient.py +166 -82
- rucio/common/__init__.py +0 -1
- rucio/common/cache.py +4 -4
- rucio/common/config.py +52 -47
- rucio/common/constants.py +69 -2
- rucio/common/constraints.py +0 -1
- rucio/common/didtype.py +24 -22
- rucio/common/exception.py +281 -222
- rucio/common/extra.py +0 -1
- rucio/common/logging.py +54 -38
- rucio/common/pcache.py +122 -101
- rucio/common/plugins.py +153 -0
- rucio/common/policy.py +4 -4
- rucio/common/schema/__init__.py +17 -10
- rucio/common/schema/atlas.py +7 -5
- rucio/common/schema/belleii.py +7 -5
- rucio/common/schema/domatpc.py +7 -5
- rucio/common/schema/escape.py +7 -5
- rucio/common/schema/generic.py +8 -6
- rucio/common/schema/generic_multi_vo.py +7 -5
- rucio/common/schema/icecube.py +7 -5
- rucio/common/stomp_utils.py +0 -1
- rucio/common/stopwatch.py +0 -1
- rucio/common/test_rucio_server.py +2 -2
- rucio/common/types.py +262 -17
- rucio/common/utils.py +743 -451
- rucio/rse/__init__.py +3 -4
- rucio/rse/protocols/__init__.py +0 -1
- rucio/rse/protocols/bittorrent.py +184 -0
- rucio/rse/protocols/cache.py +1 -2
- rucio/rse/protocols/dummy.py +1 -2
- rucio/rse/protocols/gfal.py +12 -10
- rucio/rse/protocols/globus.py +7 -7
- rucio/rse/protocols/gsiftp.py +2 -3
- rucio/rse/protocols/http_cache.py +1 -2
- rucio/rse/protocols/mock.py +1 -2
- rucio/rse/protocols/ngarc.py +1 -2
- rucio/rse/protocols/posix.py +12 -13
- rucio/rse/protocols/protocol.py +116 -52
- rucio/rse/protocols/rclone.py +6 -7
- rucio/rse/protocols/rfio.py +4 -5
- rucio/rse/protocols/srm.py +9 -10
- rucio/rse/protocols/ssh.py +8 -9
- rucio/rse/protocols/storm.py +2 -3
- rucio/rse/protocols/webdav.py +17 -14
- rucio/rse/protocols/xrootd.py +23 -17
- rucio/rse/rsemanager.py +19 -7
- rucio/vcsversion.py +4 -4
- rucio/version.py +5 -13
- rucio_clients-35.8.0.data/data/requirements.client.txt +15 -0
- {rucio_clients-32.8.6.data → rucio_clients-35.8.0.data}/data/rucio_client/merge_rucio_configs.py +2 -5
- {rucio_clients-32.8.6.data → rucio_clients-35.8.0.data}/scripts/rucio +87 -85
- {rucio_clients-32.8.6.data → rucio_clients-35.8.0.data}/scripts/rucio-admin +45 -32
- {rucio_clients-32.8.6.dist-info → rucio_clients-35.8.0.dist-info}/METADATA +13 -13
- rucio_clients-35.8.0.dist-info/RECORD +88 -0
- {rucio_clients-32.8.6.dist-info → rucio_clients-35.8.0.dist-info}/WHEEL +1 -1
- {rucio_clients-32.8.6.dist-info → rucio_clients-35.8.0.dist-info}/licenses/AUTHORS.rst +3 -0
- rucio/common/schema/cms.py +0 -478
- rucio/common/schema/lsst.py +0 -423
- rucio_clients-32.8.6.data/data/requirements.txt +0 -55
- rucio_clients-32.8.6.dist-info/RECORD +0 -88
- {rucio_clients-32.8.6.data → rucio_clients-35.8.0.data}/data/etc/rse-accounts.cfg.template +0 -0
- {rucio_clients-32.8.6.data → rucio_clients-35.8.0.data}/data/etc/rucio.cfg.atlas.client.template +0 -0
- {rucio_clients-32.8.6.data → rucio_clients-35.8.0.data}/data/etc/rucio.cfg.template +0 -0
- {rucio_clients-32.8.6.dist-info → rucio_clients-35.8.0.dist-info}/licenses/LICENSE +0 -0
- {rucio_clients-32.8.6.dist-info → rucio_clients-35.8.0.dist-info}/top_level.txt +0 -0
rucio/common/config.py
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
# -*- coding: utf-8 -*-
|
|
2
1
|
# Copyright European Organization for Nuclear Research (CERN) since 2012
|
|
3
2
|
#
|
|
4
3
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
@@ -19,7 +18,7 @@ import configparser
|
|
|
19
18
|
import json
|
|
20
19
|
import os
|
|
21
20
|
from collections.abc import Callable
|
|
22
|
-
from typing import TYPE_CHECKING,
|
|
21
|
+
from typing import TYPE_CHECKING, Any, Optional, TypeVar, Union, overload
|
|
23
22
|
|
|
24
23
|
from rucio.common import exception
|
|
25
24
|
from rucio.common.exception import ConfigNotFound, DatabaseException
|
|
@@ -31,7 +30,7 @@ if TYPE_CHECKING:
|
|
|
31
30
|
from sqlalchemy.orm import Session
|
|
32
31
|
|
|
33
32
|
|
|
34
|
-
def convert_to_any_type(value) -> Union[bool, int, float, str]:
|
|
33
|
+
def convert_to_any_type(value: str) -> Union[bool, int, float, str]:
|
|
35
34
|
if value.lower() in ['true', 'yes', 'on']:
|
|
36
35
|
return True
|
|
37
36
|
elif value.lower() in ['false', 'no', 'off']:
|
|
@@ -46,7 +45,7 @@ def convert_to_any_type(value) -> Union[bool, int, float, str]:
|
|
|
46
45
|
return value
|
|
47
46
|
|
|
48
47
|
|
|
49
|
-
def _convert_to_boolean(value):
|
|
48
|
+
def _convert_to_boolean(value: Union[str, bool]) -> bool:
|
|
50
49
|
if isinstance(value, bool):
|
|
51
50
|
return value
|
|
52
51
|
if value.lower() in ['true', 'yes', 'on', '1']:
|
|
@@ -189,12 +188,12 @@ def config_get(
|
|
|
189
188
|
"""
|
|
190
189
|
try:
|
|
191
190
|
return convert_type_fnc(get_config().get(section, option))
|
|
192
|
-
except (configparser.NoOptionError, configparser.NoSectionError,
|
|
191
|
+
except (configparser.NoOptionError, configparser.NoSectionError, ConfigNotFound) as err:
|
|
193
192
|
try:
|
|
194
193
|
legacy_config = get_legacy_config(section, option)
|
|
195
194
|
if legacy_config is not None:
|
|
196
195
|
return convert_type_fnc(legacy_config)
|
|
197
|
-
except
|
|
196
|
+
except ConfigNotFound:
|
|
198
197
|
pass
|
|
199
198
|
|
|
200
199
|
from rucio.common.utils import is_client
|
|
@@ -298,7 +297,7 @@ def config_get_int(
|
|
|
298
297
|
def config_get_int(
|
|
299
298
|
section: str,
|
|
300
299
|
option: str,
|
|
301
|
-
raise_exception,
|
|
300
|
+
raise_exception: bool,
|
|
302
301
|
default: _T = ...,
|
|
303
302
|
*,
|
|
304
303
|
check_config_table: bool = ...,
|
|
@@ -310,14 +309,14 @@ def config_get_int(
|
|
|
310
309
|
|
|
311
310
|
|
|
312
311
|
def config_get_int(
|
|
313
|
-
section,
|
|
314
|
-
option,
|
|
315
|
-
raise_exception=True,
|
|
312
|
+
section: str,
|
|
313
|
+
option: str,
|
|
314
|
+
raise_exception: bool = True,
|
|
316
315
|
default=None,
|
|
317
|
-
check_config_table=True,
|
|
318
|
-
session=None,
|
|
319
|
-
use_cache=True,
|
|
320
|
-
expiration_time=900,
|
|
316
|
+
check_config_table: bool = True,
|
|
317
|
+
session: "Optional[Session]" = None,
|
|
318
|
+
use_cache: bool = True,
|
|
319
|
+
expiration_time: int = 900,
|
|
321
320
|
):
|
|
322
321
|
"""
|
|
323
322
|
Return the integer value for a given option in a section
|
|
@@ -396,14 +395,14 @@ def config_get_float(
|
|
|
396
395
|
|
|
397
396
|
|
|
398
397
|
def config_get_float(
|
|
399
|
-
section,
|
|
400
|
-
option,
|
|
401
|
-
raise_exception=True,
|
|
398
|
+
section: str,
|
|
399
|
+
option: str,
|
|
400
|
+
raise_exception: bool = True,
|
|
402
401
|
default=None,
|
|
403
|
-
check_config_table=True,
|
|
404
|
-
session=None,
|
|
405
|
-
use_cache=True,
|
|
406
|
-
expiration_time=900,
|
|
402
|
+
check_config_table: bool = True,
|
|
403
|
+
session: "Optional[Session]" = None,
|
|
404
|
+
use_cache: bool = True,
|
|
405
|
+
expiration_time: int = 900,
|
|
407
406
|
):
|
|
408
407
|
"""
|
|
409
408
|
Return the floating point value for a given option in a section
|
|
@@ -483,14 +482,14 @@ def config_get_bool(
|
|
|
483
482
|
|
|
484
483
|
|
|
485
484
|
def config_get_bool(
|
|
486
|
-
section,
|
|
487
|
-
option,
|
|
488
|
-
raise_exception=True,
|
|
485
|
+
section: str,
|
|
486
|
+
option: str,
|
|
487
|
+
raise_exception: bool = True,
|
|
489
488
|
default=None,
|
|
490
|
-
check_config_table=True,
|
|
491
|
-
session=None,
|
|
492
|
-
use_cache=True,
|
|
493
|
-
expiration_time=900,
|
|
489
|
+
check_config_table: bool = True,
|
|
490
|
+
session: "Optional[Session]" = None,
|
|
491
|
+
use_cache: bool = True,
|
|
492
|
+
expiration_time: int = 900,
|
|
494
493
|
):
|
|
495
494
|
"""
|
|
496
495
|
Return the boolean value for a given option in a section
|
|
@@ -570,14 +569,14 @@ def config_get_list(
|
|
|
570
569
|
|
|
571
570
|
|
|
572
571
|
def config_get_list(
|
|
573
|
-
section,
|
|
574
|
-
option,
|
|
575
|
-
raise_exception=True,
|
|
572
|
+
section: str,
|
|
573
|
+
option: str,
|
|
574
|
+
raise_exception: bool = True,
|
|
576
575
|
default=None,
|
|
577
|
-
check_config_table=True,
|
|
578
|
-
session=None,
|
|
579
|
-
use_cache=True,
|
|
580
|
-
expiration_time=900,
|
|
576
|
+
check_config_table: bool = True,
|
|
577
|
+
session: "Optional[Session]" = None,
|
|
578
|
+
use_cache: bool = True,
|
|
579
|
+
expiration_time: int = 900,
|
|
581
580
|
):
|
|
582
581
|
"""
|
|
583
582
|
Return a list for a given option in a section
|
|
@@ -692,7 +691,7 @@ def config_remove_option(section: str, option: str) -> bool:
|
|
|
692
691
|
return get_config().remove_option(section, option)
|
|
693
692
|
|
|
694
693
|
|
|
695
|
-
def config_set(section: str, option: str, value: str):
|
|
694
|
+
def config_set(section: str, option: str, value: str) -> None:
|
|
696
695
|
"""
|
|
697
696
|
Set a configuration option in a given section.
|
|
698
697
|
|
|
@@ -705,11 +704,12 @@ def config_set(section: str, option: str, value: str):
|
|
|
705
704
|
return get_config().set(section, option, value)
|
|
706
705
|
|
|
707
706
|
|
|
708
|
-
def get_config_dirs():
|
|
707
|
+
def get_config_dirs() -> list[str]:
|
|
709
708
|
"""
|
|
710
709
|
Returns all available configuration directories in order:
|
|
711
710
|
- $RUCIO_HOME/etc/
|
|
712
711
|
- $VIRTUAL_ENV/etc/
|
|
712
|
+
- $CONDA_PREFIX/etc
|
|
713
713
|
- /opt/rucio/
|
|
714
714
|
"""
|
|
715
715
|
configdirs = []
|
|
@@ -720,22 +720,25 @@ def get_config_dirs():
|
|
|
720
720
|
if 'VIRTUAL_ENV' in os.environ:
|
|
721
721
|
configdirs.append('%s/etc/' % os.environ['VIRTUAL_ENV'])
|
|
722
722
|
|
|
723
|
+
if 'CONDA_PREFIX' in os.environ:
|
|
724
|
+
configdirs.append('%s/etc/' % os.environ['CONDA_PREFIX'])
|
|
725
|
+
|
|
723
726
|
configdirs.append('/opt/rucio/etc/')
|
|
724
727
|
|
|
725
728
|
return configdirs
|
|
726
729
|
|
|
727
730
|
|
|
728
|
-
def get_lfn2pfn_algorithm_default():
|
|
731
|
+
def get_lfn2pfn_algorithm_default() -> str:
|
|
729
732
|
"""Returns the default algorithm name for LFN2PFN translation for this server."""
|
|
730
733
|
default_lfn2pfn = "hash"
|
|
731
734
|
try:
|
|
732
735
|
default_lfn2pfn = config_get('policy', 'lfn2pfn_algorithm_default')
|
|
733
|
-
except (configparser.NoOptionError, configparser.NoSectionError, RuntimeError):
|
|
736
|
+
except (configparser.NoOptionError, configparser.NoSectionError, ConfigNotFound, RuntimeError):
|
|
734
737
|
pass
|
|
735
738
|
return default_lfn2pfn
|
|
736
739
|
|
|
737
740
|
|
|
738
|
-
def get_rse_credentials(path_to_credentials_file: Optional[Union[str, os.PathLike]] = None):
|
|
741
|
+
def get_rse_credentials(path_to_credentials_file: Optional[Union[str, os.PathLike]] = None) -> dict[str, Any]:
|
|
739
742
|
""" Returns credentials for RSEs. """
|
|
740
743
|
|
|
741
744
|
path = ''
|
|
@@ -766,7 +769,7 @@ def get_config() -> configparser.ConfigParser:
|
|
|
766
769
|
return __CONFIG.parser
|
|
767
770
|
|
|
768
771
|
|
|
769
|
-
def clean_cached_config():
|
|
772
|
+
def clean_cached_config() -> None:
|
|
770
773
|
"""Deletes the cached config singleton instance."""
|
|
771
774
|
global __CONFIG
|
|
772
775
|
__CONFIG = None
|
|
@@ -786,11 +789,13 @@ class Config:
|
|
|
786
789
|
configs = [os.path.join(confdir, 'rucio.cfg') for confdir in get_config_dirs()]
|
|
787
790
|
self.configfile = next(iter(filter(os.path.exists, configs)), None)
|
|
788
791
|
if self.configfile is None:
|
|
789
|
-
raise
|
|
790
|
-
|
|
791
|
-
|
|
792
|
+
raise ConfigNotFound(
|
|
793
|
+
'Could not load Rucio configuration file. '
|
|
794
|
+
'Rucio looked in the following paths for a configuration file, in order:'
|
|
795
|
+
'\n\t' + '\n\t'.join(configs))
|
|
792
796
|
|
|
793
797
|
if not self.parser.read(self.configfile) == [self.configfile]:
|
|
794
|
-
raise
|
|
795
|
-
|
|
796
|
-
|
|
798
|
+
raise ConfigNotFound(
|
|
799
|
+
'Could not load Rucio configuration file. '
|
|
800
|
+
'Rucio tried loading the following configuration file:'
|
|
801
|
+
'\n\t' + self.configfile)
|
rucio/common/constants.py
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
# -*- coding: utf-8 -*-
|
|
2
1
|
# Copyright European Organization for Nuclear Research (CERN) since 2012
|
|
3
2
|
#
|
|
4
3
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
@@ -15,6 +14,7 @@
|
|
|
15
14
|
|
|
16
15
|
import enum
|
|
17
16
|
from collections import namedtuple
|
|
17
|
+
from typing import Literal, get_args
|
|
18
18
|
|
|
19
19
|
from rucio.common.config import config_get_bool
|
|
20
20
|
|
|
@@ -48,7 +48,16 @@ if config_get_bool('transfers', 'srm_https_compatibility', raise_exception=False
|
|
|
48
48
|
SCHEME_MAP['srm'].append('davs')
|
|
49
49
|
SCHEME_MAP['davs'].append('srm')
|
|
50
50
|
|
|
51
|
-
|
|
51
|
+
SORTING_ALGORITHMS_LITERAL = Literal['geoip', 'closeness', 'custom_table', 'dynamic', 'ranking', 'random']
|
|
52
|
+
SORTING_ALGORITHMS = list(get_args(SORTING_ALGORITHMS_LITERAL))
|
|
53
|
+
|
|
54
|
+
SUPPORTED_PROTOCOLS_LITERAL = Literal['gsiftp', 'srm', 'root', 'davs', 'http', 'https', 'file', 'storm', 'srm+https', 'scp', 'rsync', 'rclone', 'magnet']
|
|
55
|
+
SUPPORTED_PROTOCOLS: list[str] = list(get_args(SUPPORTED_PROTOCOLS_LITERAL))
|
|
56
|
+
|
|
57
|
+
RSE_SUPPORTED_PROTOCOL_DOMAINS_LITERAL = Literal['ALL', 'LAN', 'WAN']
|
|
58
|
+
|
|
59
|
+
RSE_SUPPORTED_PROTOCOL_OPERATIONS_LITERAL = Literal['read', 'write', 'delete', 'third_party_copy_read', 'third_party_copy_write']
|
|
60
|
+
RSE_SUPPORTED_PROTOCOL_OPERATIONS: list[str] = list(get_args(RSE_SUPPORTED_PROTOCOL_OPERATIONS_LITERAL))
|
|
52
61
|
|
|
53
62
|
FTS_STATE = namedtuple('FTS_STATE', ['SUBMITTED', 'READY', 'ACTIVE', 'FAILED', 'FINISHED', 'FINISHEDDIRTY', 'NOT_USED',
|
|
54
63
|
'CANCELED'])('SUBMITTED', 'READY', 'ACTIVE', 'FAILED', 'FINISHED', 'FINISHEDDIRTY',
|
|
@@ -90,3 +99,61 @@ class HermesService(str, enum.Enum):
|
|
|
90
99
|
ELASTIC = "ELASTIC"
|
|
91
100
|
EMAIL = "EMAIL"
|
|
92
101
|
ACTIVEMQ = "ACTIVEMQ"
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
class RseAttr:
|
|
105
|
+
|
|
106
|
+
"""
|
|
107
|
+
List of functional RSE attributes.
|
|
108
|
+
|
|
109
|
+
This class acts as a namespace containing all RSE attributes referenced in
|
|
110
|
+
the Rucio source code. Setting them affects Rucio's behaviour in some way.
|
|
111
|
+
"""
|
|
112
|
+
|
|
113
|
+
ARCHIVE_TIMEOUT = 'archive_timeout'
|
|
114
|
+
ASSOCIATED_SITES = 'associated_sites'
|
|
115
|
+
AUTO_APPROVE_BYTES = 'auto_approve_bytes'
|
|
116
|
+
AUTO_APPROVE_FILES = 'auto_approve_files'
|
|
117
|
+
BITTORRENT_TRACKER_ADDR = 'bittorrent_tracker_addr'
|
|
118
|
+
BLOCK_MANUAL_APPROVAL = 'block_manual_approval'
|
|
119
|
+
COUNTRY = 'country'
|
|
120
|
+
DECOMMISSION = 'decommission'
|
|
121
|
+
DEFAULT_ACCOUNT_LIMIT_BYTES = 'default_account_limit_bytes'
|
|
122
|
+
FTS = 'fts'
|
|
123
|
+
GLOBUS_ENDPOINT_ID = 'globus_endpoint_id'
|
|
124
|
+
GREEDYDELETION = 'greedyDeletion'
|
|
125
|
+
IS_OBJECT_STORE = 'is_object_store'
|
|
126
|
+
LFN2PFN_ALGORITHM = 'lfn2pfn_algorithm'
|
|
127
|
+
MAXIMUM_PIN_LIFETIME = 'maximum_pin_lifetime'
|
|
128
|
+
MULTIHOP_TOMBSTONE_DELAY = 'multihop_tombstone_delay'
|
|
129
|
+
NAMING_CONVENTION = 'naming_convention'
|
|
130
|
+
OIDC_BASE_PATH = 'oidc_base_path'
|
|
131
|
+
OIDC_SUPPORT = 'oidc_support'
|
|
132
|
+
PHYSGROUP = 'physgroup'
|
|
133
|
+
QBITTORRENT_MANAGEMENT_ADDRESS = 'qbittorrent_management_address'
|
|
134
|
+
RESTRICTED_READ = 'restricted_read'
|
|
135
|
+
RESTRICTED_WRITE = 'restricted_write'
|
|
136
|
+
RULE_APPROVERS = 'rule_approvers'
|
|
137
|
+
S3_URL_STYLE = 's3_url_style'
|
|
138
|
+
SIGN_URL = 'sign_url'
|
|
139
|
+
SIMULATE_MULTIRANGE = 'simulate_multirange'
|
|
140
|
+
SITE = 'site'
|
|
141
|
+
SKIP_UPLOAD_STAT = 'skip_upload_stat'
|
|
142
|
+
SOURCE_FOR_TOTAL_SPACE = 'source_for_total_space'
|
|
143
|
+
SOURCE_FOR_USED_SPACE = 'source_for_used_space'
|
|
144
|
+
STAGING_BUFFER = 'staging_buffer'
|
|
145
|
+
STAGING_REQUIRED = 'staging_required'
|
|
146
|
+
STRICT_COPY = 'strict_copy'
|
|
147
|
+
TOMBSTONE_DELAY = 'tombstone_delay'
|
|
148
|
+
TYPE = 'type'
|
|
149
|
+
USE_IPV4 = 'use_ipv4'
|
|
150
|
+
VERIFY_CHECKSUM = 'verify_checksum'
|
|
151
|
+
|
|
152
|
+
# The following RSE attributes are exclusively used in the permission layer
|
|
153
|
+
# and are likely VO-specific.
|
|
154
|
+
|
|
155
|
+
BLOCK_MANUAL_APPROVE = 'block_manual_approve'
|
|
156
|
+
CMS_TYPE = 'cms_type'
|
|
157
|
+
DEFAULT_LIMIT_FILES = 'default_limit_files'
|
|
158
|
+
QUOTA_APPROVERS = 'quota_approvers'
|
|
159
|
+
RULE_DELETERS = 'rule_deleters'
|
rucio/common/constraints.py
CHANGED
rucio/common/didtype.py
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
# -*- coding: utf-8 -*-
|
|
2
1
|
# Copyright European Organization for Nuclear Research (CERN) since 2012
|
|
3
2
|
#
|
|
4
3
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
@@ -17,10 +16,12 @@
|
|
|
17
16
|
DID type to represent a did and to simplify operations on it
|
|
18
17
|
"""
|
|
19
18
|
|
|
19
|
+
from typing import Union
|
|
20
|
+
|
|
20
21
|
from rucio.common.exception import DIDError
|
|
21
22
|
|
|
22
23
|
|
|
23
|
-
class DID
|
|
24
|
+
class DID:
|
|
24
25
|
|
|
25
26
|
"""
|
|
26
27
|
Class used to store a DID
|
|
@@ -54,29 +55,30 @@ class DID(object):
|
|
|
54
55
|
DID('arg.scope', name='kwarg.name')
|
|
55
56
|
DID('arg.name', scope='kwarg.scope')
|
|
56
57
|
"""
|
|
57
|
-
self.scope
|
|
58
|
+
self.scope: str = ''
|
|
59
|
+
self.name: str = ''
|
|
58
60
|
|
|
59
61
|
num_args = len(args)
|
|
60
62
|
num_kwargs = len(kwargs)
|
|
61
63
|
if (num_args + num_kwargs) > 2:
|
|
62
64
|
raise DIDError('Constructor takes at most 2 arguments. Given number: {}'.format(num_args + num_kwargs))
|
|
63
65
|
|
|
64
|
-
did = ''
|
|
66
|
+
did: Union["DID", str, tuple[str, str], list[str], dict[str, str]] = ''
|
|
65
67
|
if num_args == 1:
|
|
66
68
|
did = args[0]
|
|
67
69
|
|
|
68
70
|
if num_kwargs == 1:
|
|
69
|
-
if
|
|
71
|
+
if isinstance(did, str):
|
|
72
|
+
k, v = next(iter(kwargs.items()))
|
|
73
|
+
if k == 'scope':
|
|
74
|
+
did = (v, did)
|
|
75
|
+
elif k == 'name':
|
|
76
|
+
did = (did, v)
|
|
77
|
+
else:
|
|
78
|
+
raise DIDError('Constructor got unexpected keyword argument: {}'.format(k))
|
|
79
|
+
else:
|
|
70
80
|
raise DIDError('First argument of constructor is expected to be string type'
|
|
71
81
|
'when keyword argument is given. Given type: {}'.format(type(did)))
|
|
72
|
-
|
|
73
|
-
k, v = next(iter(kwargs.items()))
|
|
74
|
-
if k == 'scope':
|
|
75
|
-
did = (v, did)
|
|
76
|
-
elif k == 'name':
|
|
77
|
-
did = (did, v)
|
|
78
|
-
else:
|
|
79
|
-
raise DIDError('Constructor got unexpected keyword argument: {}'.format(k))
|
|
80
82
|
elif num_args == 0:
|
|
81
83
|
did = kwargs.get('did', kwargs)
|
|
82
84
|
else:
|
|
@@ -114,16 +116,16 @@ class DID(object):
|
|
|
114
116
|
if not self.is_valid_format():
|
|
115
117
|
raise DIDError('Object has invalid format after construction: {}'.format(str(self)))
|
|
116
118
|
|
|
117
|
-
def update_implicit_scope(self):
|
|
119
|
+
def update_implicit_scope(self) -> None:
|
|
118
120
|
"""
|
|
119
|
-
This method sets the scope
|
|
121
|
+
This method sets the scope if it is implicitly given in self.name
|
|
120
122
|
"""
|
|
121
123
|
did_parts = self.name.split(DID.IMPLICIT_SCOPE_SEPARATOR)
|
|
122
124
|
num_scope_parts = DID.IMPLICIT_SCOPE_TO_LEN.get(did_parts[0], 0)
|
|
123
125
|
if num_scope_parts > 0:
|
|
124
126
|
self.scope = '.'.join(did_parts[0:num_scope_parts])
|
|
125
127
|
|
|
126
|
-
def is_valid_format(self):
|
|
128
|
+
def is_valid_format(self) -> bool:
|
|
127
129
|
"""
|
|
128
130
|
Method to check if the stored DID has a valid format
|
|
129
131
|
:return: bool
|
|
@@ -132,21 +134,21 @@ class DID(object):
|
|
|
132
134
|
return False
|
|
133
135
|
return True
|
|
134
136
|
|
|
135
|
-
def has_scope(self):
|
|
137
|
+
def has_scope(self) -> bool:
|
|
136
138
|
"""
|
|
137
139
|
Method to check if the scope part was set
|
|
138
140
|
:return: bool
|
|
139
141
|
"""
|
|
140
142
|
return len(self.scope) > 0
|
|
141
143
|
|
|
142
|
-
def has_name(self):
|
|
144
|
+
def has_name(self) -> bool:
|
|
143
145
|
"""
|
|
144
146
|
Method to check if the name part was set
|
|
145
147
|
:return: bool
|
|
146
148
|
"""
|
|
147
149
|
return len(self.name) > 0
|
|
148
150
|
|
|
149
|
-
def __str__(self):
|
|
151
|
+
def __str__(self) -> str:
|
|
150
152
|
"""
|
|
151
153
|
Creates the string representation of self
|
|
152
154
|
:return: string
|
|
@@ -157,7 +159,7 @@ class DID(object):
|
|
|
157
159
|
return self.scope
|
|
158
160
|
return self.name
|
|
159
161
|
|
|
160
|
-
def __eq__(self, other):
|
|
162
|
+
def __eq__(self, other: Union[str, "DID"]) -> bool:
|
|
161
163
|
"""
|
|
162
164
|
Equality comparison with another object
|
|
163
165
|
:return: bool
|
|
@@ -172,14 +174,14 @@ class DID(object):
|
|
|
172
174
|
|
|
173
175
|
return self.scope == other.scope and self.name == other.name
|
|
174
176
|
|
|
175
|
-
def __ne__(self, other):
|
|
177
|
+
def __ne__(self, other: Union[str, "DID"]) -> bool:
|
|
176
178
|
"""
|
|
177
179
|
Inequality comparison with another object
|
|
178
180
|
:return: bool
|
|
179
181
|
"""
|
|
180
182
|
return not self.__eq__(other)
|
|
181
183
|
|
|
182
|
-
def __hash__(self):
|
|
184
|
+
def __hash__(self) -> int:
|
|
183
185
|
"""
|
|
184
186
|
Uses the string representation of self to create a hash
|
|
185
187
|
:return: int
|