rucio-clients 38.2.0__py3-none-any.whl → 38.4.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.

Files changed (48) hide show
  1. rucio/cli/bin_legacy/rucio.py +26 -23
  2. rucio/cli/command.py +36 -26
  3. rucio/cli/config.py +22 -7
  4. rucio/cli/did.py +2 -2
  5. rucio/cli/download.py +1 -1
  6. rucio/cli/opendata.py +78 -10
  7. rucio/cli/utils.py +13 -1
  8. rucio/client/accountclient.py +20 -19
  9. rucio/client/accountlimitclient.py +5 -4
  10. rucio/client/baseclient.py +25 -25
  11. rucio/client/configclient.py +29 -5
  12. rucio/client/credentialclient.py +2 -1
  13. rucio/client/didclient.py +33 -32
  14. rucio/client/diracclient.py +2 -1
  15. rucio/client/exportclient.py +2 -1
  16. rucio/client/importclient.py +2 -1
  17. rucio/client/lifetimeclient.py +3 -2
  18. rucio/client/lockclient.py +4 -3
  19. rucio/client/metaconventionsclient.py +5 -4
  20. rucio/client/opendataclient.py +8 -7
  21. rucio/client/pingclient.py +2 -1
  22. rucio/client/replicaclient.py +27 -26
  23. rucio/client/requestclient.py +8 -8
  24. rucio/client/richclient.py +6 -0
  25. rucio/client/rseclient.py +31 -28
  26. rucio/client/ruleclient.py +13 -12
  27. rucio/client/scopeclient.py +4 -3
  28. rucio/client/subscriptionclient.py +6 -5
  29. rucio/common/constants.py +23 -0
  30. rucio/common/exception.py +30 -0
  31. rucio/common/plugins.py +33 -15
  32. rucio/common/utils.py +3 -3
  33. rucio/rse/protocols/webdav.py +5 -2
  34. rucio/rse/translation.py +3 -3
  35. rucio/vcsversion.py +3 -3
  36. {rucio_clients-38.2.0.dist-info → rucio_clients-38.4.0.dist-info}/METADATA +1 -1
  37. {rucio_clients-38.2.0.dist-info → rucio_clients-38.4.0.dist-info}/RECORD +48 -48
  38. {rucio_clients-38.2.0.data → rucio_clients-38.4.0.data}/data/etc/rse-accounts.cfg.template +0 -0
  39. {rucio_clients-38.2.0.data → rucio_clients-38.4.0.data}/data/etc/rucio.cfg.atlas.client.template +0 -0
  40. {rucio_clients-38.2.0.data → rucio_clients-38.4.0.data}/data/etc/rucio.cfg.template +0 -0
  41. {rucio_clients-38.2.0.data → rucio_clients-38.4.0.data}/data/requirements.client.txt +0 -0
  42. {rucio_clients-38.2.0.data → rucio_clients-38.4.0.data}/data/rucio_client/merge_rucio_configs.py +0 -0
  43. {rucio_clients-38.2.0.data → rucio_clients-38.4.0.data}/scripts/rucio +0 -0
  44. {rucio_clients-38.2.0.data → rucio_clients-38.4.0.data}/scripts/rucio-admin +0 -0
  45. {rucio_clients-38.2.0.dist-info → rucio_clients-38.4.0.dist-info}/WHEEL +0 -0
  46. {rucio_clients-38.2.0.dist-info → rucio_clients-38.4.0.dist-info}/licenses/AUTHORS.rst +0 -0
  47. {rucio_clients-38.2.0.dist-info → rucio_clients-38.4.0.dist-info}/licenses/LICENSE +0 -0
  48. {rucio_clients-38.2.0.dist-info → rucio_clients-38.4.0.dist-info}/top_level.txt +0 -0
@@ -19,6 +19,7 @@ from urllib.parse import quote_plus
19
19
  from requests.status_codes import codes
20
20
 
21
21
  from rucio.client.baseclient import BaseClient, choice
22
+ from rucio.common.constants import HTTPMethod
22
23
  from rucio.common.utils import build_url
23
24
 
24
25
  if TYPE_CHECKING:
@@ -110,7 +111,7 @@ class RuleClient(BaseClient):
110
111
  'activity': activity, 'notify': notify, 'purge_replicas': purge_replicas,
111
112
  'ignore_availability': ignore_availability, 'comment': comment, 'ask_approval': ask_approval,
112
113
  'asynchronous': asynchronous, 'delay_injection': delay_injection, 'priority': priority, 'meta': meta})
113
- r = self._send_request(url, type_='POST', data=data)
114
+ r = self._send_request(url, method=HTTPMethod.POST, data=data)
114
115
  if r.status_code == codes.created:
115
116
  return loads(r.text)
116
117
  exc_cls, exc_msg = self._get_exception(headers=r.headers, status_code=r.status_code, data=r.content)
@@ -140,7 +141,7 @@ class RuleClient(BaseClient):
140
141
 
141
142
  data = dumps({'purge_replicas': purge_replicas})
142
143
 
143
- r = self._send_request(url, type_='DEL', data=data)
144
+ r = self._send_request(url, method=HTTPMethod.DELETE, data=data)
144
145
 
145
146
  if r.status_code == codes.ok:
146
147
  return True
@@ -162,7 +163,7 @@ class RuleClient(BaseClient):
162
163
  """
163
164
  path = self.RULE_BASEURL + '/' + rule_id
164
165
  url = build_url(choice(self.list_hosts), path=path)
165
- r = self._send_request(url, type_='GET')
166
+ r = self._send_request(url, method=HTTPMethod.GET)
166
167
  if r.status_code == codes.ok:
167
168
  return next(self._load_json_data(r))
168
169
  else:
@@ -185,7 +186,7 @@ class RuleClient(BaseClient):
185
186
  path = self.RULE_BASEURL + '/' + rule_id
186
187
  url = build_url(choice(self.list_hosts), path=path)
187
188
  data = dumps({'options': options})
188
- r = self._send_request(url, type_='PUT', data=data)
189
+ r = self._send_request(url, method=HTTPMethod.PUT, data=data)
189
190
  if r.status_code == codes.ok:
190
191
  return True
191
192
  exc_cls, exc_msg = self._get_exception(headers=r.headers, status_code=r.status_code, data=r.content)
@@ -216,7 +217,7 @@ class RuleClient(BaseClient):
216
217
  path = self.RULE_BASEURL + '/' + rule_id + '/reduce'
217
218
  url = build_url(choice(self.list_hosts), path=path)
218
219
  data = dumps({'copies': copies, 'exclude_expression': exclude_expression})
219
- r = self._send_request(url, type_='POST', data=data)
220
+ r = self._send_request(url, method=HTTPMethod.POST, data=data)
220
221
  if r.status_code == codes.ok:
221
222
  return loads(r.text)
222
223
  exc_cls, exc_msg = self._get_exception(headers=r.headers, status_code=r.status_code, data=r.content)
@@ -252,7 +253,7 @@ class RuleClient(BaseClient):
252
253
  'rse_expression': rse_expression,
253
254
  'override': override,
254
255
  })
255
- r = self._send_request(url, type_='POST', data=data)
256
+ r = self._send_request(url, method=HTTPMethod.POST, data=data)
256
257
  if r.status_code == codes.created:
257
258
  return loads(r.text)
258
259
  exc_cls, exc_msg = self._get_exception(headers=r.headers, status_code=r.status_code, data=r.content)
@@ -273,7 +274,7 @@ class RuleClient(BaseClient):
273
274
  path = self.RULE_BASEURL + '/' + rule_id
274
275
  url = build_url(choice(self.list_hosts), path=path)
275
276
  data = dumps({'options': {'approve': True}})
276
- r = self._send_request(url, type_='PUT', data=data)
277
+ r = self._send_request(url, method=HTTPMethod.PUT, data=data)
277
278
  if r.status_code == codes.ok:
278
279
  return True
279
280
  exc_cls, exc_msg = self._get_exception(headers=r.headers, status_code=r.status_code, data=r.content)
@@ -300,7 +301,7 @@ class RuleClient(BaseClient):
300
301
  if reason:
301
302
  options['comment'] = reason
302
303
  data = dumps({'options': options})
303
- r = self._send_request(url, type_='PUT', data=data)
304
+ r = self._send_request(url, method=HTTPMethod.PUT, data=data)
304
305
  if r.status_code == codes.ok:
305
306
  return True
306
307
  exc_cls, exc_msg = self._get_exception(headers=r.headers, status_code=r.status_code, data=r.content)
@@ -321,7 +322,7 @@ class RuleClient(BaseClient):
321
322
  """
322
323
  path = '/'.join([self.RULE_BASEURL, quote_plus(scope), quote_plus(name), 'history'])
323
324
  url = build_url(choice(self.list_hosts), path=path)
324
- r = self._send_request(url, type_='GET')
325
+ r = self._send_request(url, method=HTTPMethod.GET)
325
326
  if r.status_code == codes.ok:
326
327
  return self._load_json_data(r)
327
328
  exc_cls, exc_msg = self._get_exception(r.headers, r.status_code)
@@ -341,7 +342,7 @@ class RuleClient(BaseClient):
341
342
  """
342
343
  path = self.RULE_BASEURL + '/' + rule_id + '/analysis'
343
344
  url = build_url(choice(self.list_hosts), path=path)
344
- r = self._send_request(url, type_='GET')
345
+ r = self._send_request(url, method=HTTPMethod.GET)
345
346
  if r.status_code == codes.ok:
346
347
  return next(self._load_json_data(r))
347
348
  exc_cls, exc_msg = self._get_exception(r.headers, r.status_code)
@@ -361,7 +362,7 @@ class RuleClient(BaseClient):
361
362
  """
362
363
  path = self.RULE_BASEURL + '/' + rule_id + '/locks'
363
364
  url = build_url(choice(self.list_hosts), path=path)
364
- r = self._send_request(url, type_='GET')
365
+ r = self._send_request(url, method=HTTPMethod.GET)
365
366
  if r.status_code == codes.ok:
366
367
  return self._load_json_data(r)
367
368
  exc_cls, exc_msg = self._get_exception(r.headers, r.status_code)
@@ -382,7 +383,7 @@ class RuleClient(BaseClient):
382
383
  filters = filters or {}
383
384
  path = self.RULE_BASEURL + '/'
384
385
  url = build_url(choice(self.list_hosts), path=path)
385
- r = self._send_request(url, type_='GET', params=filters)
386
+ r = self._send_request(url, method=HTTPMethod.GET, params=filters)
386
387
  if r.status_code == codes.ok:
387
388
  return self._load_json_data(r)
388
389
  else:
@@ -18,6 +18,7 @@ from urllib.parse import quote_plus
18
18
  from requests.status_codes import codes
19
19
 
20
20
  from rucio.client.baseclient import BaseClient, choice
21
+ from rucio.common.constants import HTTPMethod
21
22
  from rucio.common.utils import build_url
22
23
 
23
24
 
@@ -56,7 +57,7 @@ class ScopeClient(BaseClient):
56
57
 
57
58
  path = '/'.join([self.SCOPE_BASEURL, account, 'scopes', quote_plus(scope)])
58
59
  url = build_url(choice(self.list_hosts), path=path)
59
- r = self._send_request(url, type_='POST')
60
+ r = self._send_request(url, method=HTTPMethod.POST)
60
61
  if r.status_code == codes.created:
61
62
  return True
62
63
  else:
@@ -74,7 +75,7 @@ class ScopeClient(BaseClient):
74
75
 
75
76
  path = '/'.join(['scopes/'])
76
77
  url = build_url(choice(self.list_hosts), path=path)
77
- r = self._send_request(url)
78
+ r = self._send_request(url, method=HTTPMethod.GET)
78
79
  if r.status_code == codes.ok:
79
80
  scopes = loads(r.text)
80
81
  return scopes
@@ -106,7 +107,7 @@ class ScopeClient(BaseClient):
106
107
  path = '/'.join([self.SCOPE_BASEURL, account, 'scopes/'])
107
108
  url = build_url(choice(self.list_hosts), path=path)
108
109
 
109
- r = self._send_request(url)
110
+ r = self._send_request(url, method=HTTPMethod.GET)
110
111
  if r.status_code == codes.ok:
111
112
  scopes = loads(r.text)
112
113
  return scopes
@@ -18,6 +18,7 @@ from typing import TYPE_CHECKING, Any, Literal, Optional, Union
18
18
  from requests.status_codes import codes
19
19
 
20
20
  from rucio.client.baseclient import BaseClient, choice
21
+ from rucio.common.constants import HTTPMethod
21
22
  from rucio.common.utils import build_url
22
23
 
23
24
  if TYPE_CHECKING:
@@ -78,7 +79,7 @@ class SubscriptionClient(BaseClient):
78
79
  raise TypeError('replication_rules should be a list')
79
80
  data = dumps({'options': {'filter': filter_, 'replication_rules': replication_rules, 'comments': comments,
80
81
  'lifetime': lifetime, 'retroactive': retroactive, 'dry_run': dry_run, 'priority': priority}})
81
- result = self._send_request(url, type_='POST', data=data)
82
+ result = self._send_request(url, method=HTTPMethod.POST, data=data)
82
83
  if result.status_code == codes.created: # pylint: disable=no-member
83
84
  return result.text
84
85
  else:
@@ -120,7 +121,7 @@ class SubscriptionClient(BaseClient):
120
121
  else:
121
122
  path += '/'
122
123
  url = build_url(choice(self.list_hosts), path=path)
123
- result = self._send_request(url, type_='GET')
124
+ result = self._send_request(url, method=HTTPMethod.GET)
124
125
  if result.status_code == codes.ok: # pylint: disable=no-member
125
126
  return self._load_json_data(result)
126
127
  if result.status_code == codes.not_found:
@@ -173,7 +174,7 @@ class SubscriptionClient(BaseClient):
173
174
  raise TypeError('replication_rules should be a list')
174
175
  data = dumps({'options': {'filter': filter_, 'replication_rules': replication_rules, 'comments': comments,
175
176
  'lifetime': lifetime, 'retroactive': retroactive, 'dry_run': dry_run, 'priority': priority}})
176
- result = self._send_request(url, type_='PUT', data=data)
177
+ result = self._send_request(url, method=HTTPMethod.PUT, data=data)
177
178
  if result.status_code == codes.created: # pylint: disable=no-member
178
179
  return True
179
180
  else:
@@ -203,7 +204,7 @@ class SubscriptionClient(BaseClient):
203
204
  path = self.SUB_BASEURL + '/' + account + '/' + name # type: ignore
204
205
  url = build_url(choice(self.list_hosts), path=path)
205
206
  data = dumps({'options': {'state': 'I'}})
206
- result = self._send_request(url, type_='PUT', data=data)
207
+ result = self._send_request(url, method=HTTPMethod.PUT, data=data)
207
208
  if result.status_code == codes.created: # pylint: disable=no-member
208
209
  return True
209
210
  else:
@@ -228,7 +229,7 @@ class SubscriptionClient(BaseClient):
228
229
 
229
230
  path = '/'.join([self.SUB_BASEURL, account, name, 'rules'])
230
231
  url = build_url(choice(self.list_hosts), path=path)
231
- result = self._send_request(url, type_='GET')
232
+ result = self._send_request(url, method=HTTPMethod.GET)
232
233
  if result.status_code == codes.ok: # pylint: disable=no-member
233
234
  return self._load_json_data(result)
234
235
  else:
rucio/common/constants.py CHANGED
@@ -13,6 +13,7 @@
13
13
  # limitations under the License.
14
14
 
15
15
  import enum
16
+ import sys
16
17
  from collections import namedtuple
17
18
  from typing import Literal, get_args
18
19
 
@@ -29,6 +30,8 @@ RESERVED_KEYS = ['scope', 'name', 'account', 'did_type', 'is_open', 'monotonic',
29
30
 
30
31
  DEFAULT_VO = 'def'
31
32
 
33
+ DEFAULT_ACTIVITY = 'User Subscriptions'
34
+
32
35
  KEY_TYPES = ['ALL', 'COLLECTION', 'FILE', 'DERIVED']
33
36
  # all(container, dataset, file), collection(dataset or container), file, derived(compute from file for collection)
34
37
 
@@ -219,3 +222,23 @@ SUPPORTED_SIGN_URL_SERVICES = list(get_args(SUPPORTED_SIGN_URL_SERVICES_LITERAL)
219
222
 
220
223
  OPENDATA_DID_STATE_LITERAL = Literal['draft', 'public', 'suspended']
221
224
  OPENDATA_DID_STATE_LITERAL_LIST = list(get_args(OPENDATA_DID_STATE_LITERAL))
225
+
226
+ POLICY_ALGORITHM_TYPES_LITERAL = Literal['non_deterministic_pfn', 'scope', 'lfn2pfn', 'pfn2lfn', 'fts3_tape_metadata_plugins', 'fts3_plugins_init', 'auto_approve']
227
+ POLICY_ALGORITHM_TYPES = list(get_args(POLICY_ALGORITHM_TYPES_LITERAL))
228
+
229
+ # https://github.com/rucio/rucio/issues/7958
230
+ # When Python 3.11 is the minimum supported version, we can use the standard library enum and remove this logic
231
+ if sys.version_info >= (3, 11):
232
+ from http import HTTPMethod
233
+ else:
234
+ @enum.unique
235
+ class HTTPMethod(str, enum.Enum):
236
+ """HTTP verbs used in Rucio requests."""
237
+
238
+ HEAD = "HEAD"
239
+ OPTIONS = "OPTIONS"
240
+ PATCH = "PATCH"
241
+ GET = "GET"
242
+ POST = "POST"
243
+ PUT = "PUT"
244
+ DELETE = "DELETE"
rucio/common/exception.py CHANGED
@@ -1261,3 +1261,33 @@ class OpenDataInvalidStateUpdate(OpenDataError):
1261
1261
  super(OpenDataInvalidStateUpdate, self).__init__(*args)
1262
1262
  self._message = "Invalid state update attempted on open data entry."
1263
1263
  self.error_code = 119
1264
+
1265
+
1266
+ class InvalidPolicyPackageAlgorithmType(RucioException):
1267
+ """
1268
+ Thrown when an unknown algorithm type name is encountered.
1269
+ """
1270
+ def __init__(self, param: str, *args):
1271
+ super(InvalidPolicyPackageAlgorithmType, self).__init__(*args)
1272
+ self._message = f"Invalid policy package algorithm type '{param}'."
1273
+ self.error_code = 120
1274
+
1275
+
1276
+ class InvalidAccountType(RucioException):
1277
+ """
1278
+ Thrown when an account is created with an invalid type
1279
+ """
1280
+ def __init__(self, *args):
1281
+ super(InvalidAccountType, self).__init__(*args)
1282
+ self._message = "Cannot create an account with an invalid type."
1283
+ self.error_code = 121
1284
+
1285
+ class OpenDataDuplicateDOI(OpenDataError):
1286
+ """
1287
+ Throws when a data identifier with the same DOI already exists in the open data catalog.
1288
+ """
1289
+
1290
+ def __init__(self, doi: str, *args):
1291
+ super(OpenDataDuplicateDOI, self).__init__(*args)
1292
+ self._message = f"Data identifier with the same DOI ({doi}) already exists in the open data catalog."
1293
+ self.error_code = 122
rucio/common/plugins.py CHANGED
@@ -22,8 +22,8 @@ from packaging.specifiers import SpecifierSet
22
22
 
23
23
  from rucio.common import config
24
24
  from rucio.common.client import get_client_vo
25
- from rucio.common.constants import DEFAULT_VO
26
- from rucio.common.exception import InvalidAlgorithmName, PolicyPackageIsNotVersioned, PolicyPackageVersionError
25
+ from rucio.common.constants import DEFAULT_VO, POLICY_ALGORITHM_TYPES, POLICY_ALGORITHM_TYPES_LITERAL
26
+ from rucio.common.exception import InvalidAlgorithmName, InvalidPolicyPackageAlgorithmType, PolicyPackageIsNotVersioned, PolicyPackageVersionError
27
27
  from rucio.version import current_version
28
28
 
29
29
  if TYPE_CHECKING:
@@ -75,9 +75,9 @@ class PolicyPackageAlgorithms:
75
75
  - the key is the algorithm type
76
76
  - the value is a dictionary of algorithm names and their callables
77
77
  """
78
- _ALGORITHMS: dict[str, dict[str, 'Callable[..., Any]']] = {}
78
+ _ALGORITHMS: dict[POLICY_ALGORITHM_TYPES_LITERAL, dict[str, 'Callable[..., Any]']] = {}
79
79
  _loaded_policy_modules = False
80
- _default_algorithms: dict[str, 'Callable[..., Any]'] = {}
80
+ _default_algorithms: dict[str, Optional['Callable[..., Any]']] = {}
81
81
 
82
82
  def __init__(self) -> None:
83
83
  if not self._loaded_policy_modules:
@@ -85,12 +85,15 @@ class PolicyPackageAlgorithms:
85
85
  self._loaded_policy_modules = True
86
86
 
87
87
  @classmethod
88
- def _get_default_algorithm(cls: type[PolicyPackageAlgorithmsT], algorithm_type: str, vo: str = "") -> Optional['Callable[..., Any]']:
88
+ def _get_default_algorithm(cls: type[PolicyPackageAlgorithmsT], algorithm_type: POLICY_ALGORITHM_TYPES_LITERAL, vo: str = "") -> Optional['Callable[..., Any]']:
89
89
  """
90
90
  Gets the default algorithm of this type, if present in the policy package.
91
91
  The default algorithm is the function named algorithm_type within the module named algorithm_type.
92
92
  Returns None if no default algorithm present.
93
93
  """
94
+ if algorithm_type not in POLICY_ALGORITHM_TYPES:
95
+ raise InvalidPolicyPackageAlgorithmType(algorithm_type)
96
+
94
97
  # check if default algorithm for this VO is already cached
95
98
  type_for_vo = vo + "_" + algorithm_type
96
99
  if type_for_vo in cls._default_algorithms:
@@ -102,52 +105,71 @@ class PolicyPackageAlgorithms:
102
105
  vo = ''
103
106
  package = cls._get_policy_package_name(vo)
104
107
  except (NoOptionError, NoSectionError):
108
+ cls._default_algorithms[type_for_vo] = default_algorithm
105
109
  return default_algorithm
106
110
 
107
111
  module_name = package + "." + algorithm_type
112
+ LOGGER.info('Attempting to find algorithm %s in default location %s...' % (algorithm_type, module_name))
108
113
  try:
109
114
  module = importlib.import_module(module_name)
110
115
 
111
116
  if hasattr(module, algorithm_type):
112
117
  default_algorithm = getattr(module, algorithm_type)
113
- cls._default_algorithms[type_for_vo] = default_algorithm
118
+ except ModuleNotFoundError:
119
+ LOGGER.info('Algorithm %s not found in default location %s' % (algorithm_type, module_name))
114
120
  except ImportError:
115
- LOGGER.info('Policy algorithm module %s could not be loaded' % module_name)
121
+ LOGGER.info('Algorithm %s found in default location %s, but could not be loaded' % (algorithm_type, module_name))
122
+ # if the default algorithm is not present, this will store None and we will
123
+ # not attempt to load the same algorithm again
124
+ cls._default_algorithms[type_for_vo] = default_algorithm
116
125
  return default_algorithm
117
126
 
118
127
  @classmethod
119
- def _get_one_algorithm(cls: type[PolicyPackageAlgorithmsT], algorithm_type: str, name: str) -> 'Callable[..., Any]':
128
+ def _get_one_algorithm(cls: type[PolicyPackageAlgorithmsT], algorithm_type: POLICY_ALGORITHM_TYPES_LITERAL, name: str) -> 'Callable[..., Any]':
120
129
  """
121
130
  Get the algorithm from the dictionary of algorithms
122
131
  """
132
+ if algorithm_type not in POLICY_ALGORITHM_TYPES:
133
+ raise InvalidPolicyPackageAlgorithmType(algorithm_type)
123
134
  return cls._ALGORITHMS[algorithm_type][name]
124
135
 
125
136
  @classmethod
126
- def _get_algorithms(cls: type[PolicyPackageAlgorithmsT], algorithm_type: str) -> dict[str, 'Callable[..., Any]']:
137
+ def _get_algorithms(cls: type[PolicyPackageAlgorithmsT], algorithm_type: POLICY_ALGORITHM_TYPES_LITERAL) -> dict[str, 'Callable[..., Any]']:
127
138
  """
128
139
  Get the dictionary of algorithms for a given type
129
140
  """
141
+ if algorithm_type not in POLICY_ALGORITHM_TYPES:
142
+ raise InvalidPolicyPackageAlgorithmType(algorithm_type)
130
143
  return cls._ALGORITHMS[algorithm_type]
131
144
 
132
145
  @classmethod
133
146
  def _register(
134
147
  cls: type[PolicyPackageAlgorithmsT],
135
- algorithm_type: str, algorithm_dict: dict[str, 'Callable[..., Any]']) -> None:
148
+ algorithm_type: POLICY_ALGORITHM_TYPES_LITERAL,
149
+ algorithm_dict: dict[str, 'Callable[..., Any]']) -> None:
136
150
  """
137
151
  Provided a dictionary of callable function,
138
152
  and the associated algorithm type,
139
153
  register it as one of the valid algorithms.
140
154
  """
155
+ if algorithm_type not in POLICY_ALGORITHM_TYPES:
156
+ raise InvalidPolicyPackageAlgorithmType(algorithm_type)
157
+
141
158
  if algorithm_type in cls._ALGORITHMS:
142
159
  cls._ALGORITHMS[algorithm_type].update(algorithm_dict)
143
160
  else:
144
161
  cls._ALGORITHMS[algorithm_type] = algorithm_dict
145
162
 
146
163
  @classmethod
147
- def _supports(cls: type[PolicyPackageAlgorithmsT], algorithm_type: str, name: str) -> bool:
164
+ def _supports(
165
+ cls: type[PolicyPackageAlgorithmsT],
166
+ algorithm_type: POLICY_ALGORITHM_TYPES_LITERAL,
167
+ name: str) -> bool:
148
168
  """
149
169
  Check if a algorithm is supported by the plugin
150
170
  """
171
+ if algorithm_type not in POLICY_ALGORITHM_TYPES:
172
+ raise InvalidPolicyPackageAlgorithmType(algorithm_type)
151
173
  return name in cls._ALGORITHMS.get(algorithm_type, {})
152
174
 
153
175
  @classmethod
@@ -196,10 +218,6 @@ class PolicyPackageAlgorithms:
196
218
  if hasattr(module, 'get_algorithms'):
197
219
  all_algorithms = module.get_algorithms()
198
220
 
199
- # for backward compatibility, rename 'surl' to 'non_deterministic_pfn' here
200
- if 'surl' in all_algorithms:
201
- all_algorithms['non_deterministic_pfn'] = all_algorithms['surl']
202
-
203
221
  # check that the names are correctly prefixed for multi-VO
204
222
  if vo:
205
223
  for _, algorithms in all_algorithms.items():
rucio/common/utils.py CHANGED
@@ -46,7 +46,7 @@ import requests
46
46
  from typing_extensions import ParamSpec
47
47
 
48
48
  from rucio.common.config import config_get, config_get_bool
49
- from rucio.common.constants import BASE_SCHEME_MAP, DEFAULT_VO
49
+ from rucio.common.constants import BASE_SCHEME_MAP, DEFAULT_VO, POLICY_ALGORITHM_TYPES_LITERAL
50
50
  from rucio.common.exception import DIDFilterSyntaxError, DuplicateCriteriaInDIDFilter, InputValidationError, InvalidType, MetalinkJsonParsingError, MissingModuleException, RucioException
51
51
  from rucio.common.extra import import_extras
52
52
  from rucio.common.plugins import PolicyPackageAlgorithms
@@ -392,7 +392,7 @@ class NonDeterministicPFNAlgorithms(PolicyPackageAlgorithms):
392
392
  from policy packages
393
393
  """
394
394
 
395
- _algorithm_type = 'non_deterministic_pfn'
395
+ _algorithm_type: POLICY_ALGORITHM_TYPES_LITERAL = 'non_deterministic_pfn'
396
396
 
397
397
  def __init__(self, vo: str = DEFAULT_VO) -> None:
398
398
  """
@@ -560,7 +560,7 @@ class ScopeExtractionAlgorithms(PolicyPackageAlgorithms):
560
560
  Handle scope extraction algorithms
561
561
  """
562
562
 
563
- _algorithm_type = 'scope'
563
+ _algorithm_type: POLICY_ALGORITHM_TYPES_LITERAL = 'scope'
564
564
 
565
565
  def __init__(self, vo: str = DEFAULT_VO) -> None:
566
566
  """
@@ -25,6 +25,7 @@ from requests.adapters import HTTPAdapter
25
25
  from urllib3.poolmanager import PoolManager
26
26
 
27
27
  from rucio.common import exception
28
+ from rucio.common.constants import HTTPMethod
28
29
  from rucio.rse.protocols import protocol
29
30
 
30
31
 
@@ -259,9 +260,11 @@ class Default(protocol.RSEProtocol):
259
260
  try:
260
261
  # use GET instead of HEAD for presigned urls
261
262
  if not using_presigned_urls:
262
- result = self.session.request('HEAD', path, verify=False, timeout=self.timeout, cert=self.cert)
263
+ result = self.session.request(HTTPMethod.HEAD.value, path, verify=False, timeout=self.timeout,
264
+ cert=self.cert)
263
265
  else:
264
- result = self.session.request('GET', path, verify=False, timeout=self.timeout, cert=self.cert)
266
+ result = self.session.request(HTTPMethod.GET.value, path, verify=False, timeout=self.timeout,
267
+ cert=self.cert)
265
268
  if result.status_code == 200:
266
269
  return True
267
270
  elif result.status_code in [401, ]:
rucio/rse/translation.py CHANGED
@@ -18,7 +18,7 @@ from configparser import NoOptionError, NoSectionError
18
18
  from typing import TYPE_CHECKING, Any, Optional
19
19
 
20
20
  from rucio.common import config
21
- from rucio.common.constants import DEFAULT_VO, RseAttr
21
+ from rucio.common.constants import DEFAULT_VO, POLICY_ALGORITHM_TYPES_LITERAL, RseAttr
22
22
  from rucio.common.exception import ConfigNotFound
23
23
  from rucio.common.plugins import PolicyPackageAlgorithms
24
24
 
@@ -33,7 +33,7 @@ class RSEDeterministicScopeTranslation(PolicyPackageAlgorithms):
33
33
  Translates a pfn dictionary into a scope and name
34
34
  """
35
35
 
36
- _algorithm_type = "pfn2lfn"
36
+ _algorithm_type: POLICY_ALGORITHM_TYPES_LITERAL = "pfn2lfn"
37
37
 
38
38
  def __init__(self, vo: str = DEFAULT_VO):
39
39
  super().__init__()
@@ -111,7 +111,7 @@ class RSEDeterministicTranslation(PolicyPackageAlgorithms):
111
111
  """
112
112
 
113
113
  _DEFAULT_LFN2PFN = "hash"
114
- _algorithm_type = "lfn2pfn"
114
+ _algorithm_type: POLICY_ALGORITHM_TYPES_LITERAL = "lfn2pfn"
115
115
 
116
116
  def __init__(
117
117
  self,
rucio/vcsversion.py CHANGED
@@ -4,8 +4,8 @@ This file is automatically generated; Do not edit it. :)
4
4
  '''
5
5
  VERSION_INFO = {
6
6
  'final': True,
7
- 'version': '38.2.0',
7
+ 'version': '38.4.0',
8
8
  'branch_nick': 'release-38-LTS',
9
- 'revision_id': 'af0cedfc38c83fa06e4b82991d0c04a1129440a9',
10
- 'revno': 13963
9
+ 'revision_id': '945ab71be90243fe96148bb3bd13c1c3ae410765',
10
+ 'revno': 14030
11
11
  }
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: rucio-clients
3
- Version: 38.2.0
3
+ Version: 38.4.0
4
4
  Summary: Rucio Client Lite Package
5
5
  Home-page: https://rucio.cern.ch/
6
6
  Author: Rucio