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.

Files changed (92) hide show
  1. rucio/__init__.py +0 -1
  2. rucio/alembicrevision.py +1 -2
  3. rucio/client/__init__.py +0 -1
  4. rucio/client/accountclient.py +45 -25
  5. rucio/client/accountlimitclient.py +37 -9
  6. rucio/client/baseclient.py +199 -154
  7. rucio/client/client.py +2 -3
  8. rucio/client/configclient.py +19 -6
  9. rucio/client/credentialclient.py +9 -4
  10. rucio/client/didclient.py +238 -63
  11. rucio/client/diracclient.py +13 -5
  12. rucio/client/downloadclient.py +162 -51
  13. rucio/client/exportclient.py +4 -4
  14. rucio/client/fileclient.py +3 -4
  15. rucio/client/importclient.py +4 -4
  16. rucio/client/lifetimeclient.py +21 -5
  17. rucio/client/lockclient.py +18 -8
  18. rucio/client/{metaclient.py → metaconventionsclient.py} +18 -15
  19. rucio/client/pingclient.py +0 -1
  20. rucio/client/replicaclient.py +15 -5
  21. rucio/client/requestclient.py +35 -19
  22. rucio/client/rseclient.py +133 -51
  23. rucio/client/ruleclient.py +29 -22
  24. rucio/client/scopeclient.py +8 -6
  25. rucio/client/subscriptionclient.py +47 -35
  26. rucio/client/touchclient.py +8 -4
  27. rucio/client/uploadclient.py +166 -82
  28. rucio/common/__init__.py +0 -1
  29. rucio/common/cache.py +4 -4
  30. rucio/common/config.py +52 -47
  31. rucio/common/constants.py +69 -2
  32. rucio/common/constraints.py +0 -1
  33. rucio/common/didtype.py +24 -22
  34. rucio/common/exception.py +281 -222
  35. rucio/common/extra.py +0 -1
  36. rucio/common/logging.py +54 -38
  37. rucio/common/pcache.py +122 -101
  38. rucio/common/plugins.py +153 -0
  39. rucio/common/policy.py +4 -4
  40. rucio/common/schema/__init__.py +17 -10
  41. rucio/common/schema/atlas.py +7 -5
  42. rucio/common/schema/belleii.py +7 -5
  43. rucio/common/schema/domatpc.py +7 -5
  44. rucio/common/schema/escape.py +7 -5
  45. rucio/common/schema/generic.py +8 -6
  46. rucio/common/schema/generic_multi_vo.py +7 -5
  47. rucio/common/schema/icecube.py +7 -5
  48. rucio/common/stomp_utils.py +0 -1
  49. rucio/common/stopwatch.py +0 -1
  50. rucio/common/test_rucio_server.py +2 -2
  51. rucio/common/types.py +262 -17
  52. rucio/common/utils.py +743 -451
  53. rucio/rse/__init__.py +3 -4
  54. rucio/rse/protocols/__init__.py +0 -1
  55. rucio/rse/protocols/bittorrent.py +184 -0
  56. rucio/rse/protocols/cache.py +1 -2
  57. rucio/rse/protocols/dummy.py +1 -2
  58. rucio/rse/protocols/gfal.py +12 -10
  59. rucio/rse/protocols/globus.py +7 -7
  60. rucio/rse/protocols/gsiftp.py +2 -3
  61. rucio/rse/protocols/http_cache.py +1 -2
  62. rucio/rse/protocols/mock.py +1 -2
  63. rucio/rse/protocols/ngarc.py +1 -2
  64. rucio/rse/protocols/posix.py +12 -13
  65. rucio/rse/protocols/protocol.py +116 -52
  66. rucio/rse/protocols/rclone.py +6 -7
  67. rucio/rse/protocols/rfio.py +4 -5
  68. rucio/rse/protocols/srm.py +9 -10
  69. rucio/rse/protocols/ssh.py +8 -9
  70. rucio/rse/protocols/storm.py +2 -3
  71. rucio/rse/protocols/webdav.py +17 -14
  72. rucio/rse/protocols/xrootd.py +23 -17
  73. rucio/rse/rsemanager.py +19 -7
  74. rucio/vcsversion.py +4 -4
  75. rucio/version.py +5 -13
  76. rucio_clients-35.8.0.data/data/requirements.client.txt +15 -0
  77. {rucio_clients-32.8.6.data → rucio_clients-35.8.0.data}/data/rucio_client/merge_rucio_configs.py +2 -5
  78. {rucio_clients-32.8.6.data → rucio_clients-35.8.0.data}/scripts/rucio +87 -85
  79. {rucio_clients-32.8.6.data → rucio_clients-35.8.0.data}/scripts/rucio-admin +45 -32
  80. {rucio_clients-32.8.6.dist-info → rucio_clients-35.8.0.dist-info}/METADATA +13 -13
  81. rucio_clients-35.8.0.dist-info/RECORD +88 -0
  82. {rucio_clients-32.8.6.dist-info → rucio_clients-35.8.0.dist-info}/WHEEL +1 -1
  83. {rucio_clients-32.8.6.dist-info → rucio_clients-35.8.0.dist-info}/licenses/AUTHORS.rst +3 -0
  84. rucio/common/schema/cms.py +0 -478
  85. rucio/common/schema/lsst.py +0 -423
  86. rucio_clients-32.8.6.data/data/requirements.txt +0 -55
  87. rucio_clients-32.8.6.dist-info/RECORD +0 -88
  88. {rucio_clients-32.8.6.data → rucio_clients-35.8.0.data}/data/etc/rse-accounts.cfg.template +0 -0
  89. {rucio_clients-32.8.6.data → rucio_clients-35.8.0.data}/data/etc/rucio.cfg.atlas.client.template +0 -0
  90. {rucio_clients-32.8.6.data → rucio_clients-35.8.0.data}/data/etc/rucio.cfg.template +0 -0
  91. {rucio_clients-32.8.6.dist-info → rucio_clients-35.8.0.dist-info}/licenses/LICENSE +0 -0
  92. {rucio_clients-32.8.6.dist-info → rucio_clients-35.8.0.dist-info}/top_level.txt +0 -0
rucio/client/rseclient.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");
@@ -14,21 +13,26 @@
14
13
  # limitations under the License.
15
14
 
16
15
  from json import dumps, loads
16
+ from typing import TYPE_CHECKING, Any, Literal, Optional, Union
17
17
  from urllib.parse import quote
18
18
 
19
19
  from requests.status_codes import codes
20
20
 
21
- from rucio.client.baseclient import BaseClient
22
- from rucio.client.baseclient import choice
21
+ from rucio.client.baseclient import BaseClient, choice
23
22
  from rucio.common.utils import build_url
24
23
 
24
+ if TYPE_CHECKING:
25
+ from collections.abc import Iterable, Iterator
26
+
27
+ from rucio.common.constants import RSE_SUPPORTED_PROTOCOL_DOMAINS_LITERAL, RSE_SUPPORTED_PROTOCOL_OPERATIONS_LITERAL, SUPPORTED_PROTOCOLS_LITERAL
28
+
25
29
 
26
30
  class RSEClient(BaseClient):
27
31
  """RSE client class for working with rucio RSEs"""
28
32
 
29
33
  RSE_BASEURL = 'rses'
30
34
 
31
- def get_rse(self, rse):
35
+ def get_rse(self, rse: str) -> dict[str, Any]:
32
36
  """
33
37
  Returns details about the referred RSE.
34
38
 
@@ -43,13 +47,13 @@ class RSEClient(BaseClient):
43
47
 
44
48
  r = self._send_request(url, type_='GET')
45
49
  if r.status_code == codes.ok:
46
- rse = loads(r.text)
47
- return rse
50
+ rse_dict = loads(r.text)
51
+ return rse_dict
48
52
  else:
49
53
  exc_cls, exc_msg = self._get_exception(headers=r.headers, status_code=r.status_code, data=r.content)
50
54
  raise exc_cls(exc_msg)
51
55
 
52
- def add_rse(self, rse, **kwargs):
56
+ def add_rse(self, rse: str, **kwargs) -> Literal[True]:
53
57
  """
54
58
  Sends the request to create a new RSE.
55
59
 
@@ -80,12 +84,12 @@ class RSEClient(BaseClient):
80
84
  exc_cls, exc_msg = self._get_exception(headers=r.headers, status_code=r.status_code, data=r.content)
81
85
  raise exc_cls(exc_msg)
82
86
 
83
- def update_rse(self, rse, parameters):
87
+ def update_rse(self, rse: str, parameters: dict[str, Any]) -> Literal[True]:
84
88
  """
85
89
  Update RSE properties like availability or name.
86
90
 
87
91
  :param rse: the name of the new rse.
88
- :param parameters: A dictionnary with property (name, read, write, delete as keys).
92
+ :param parameters: A dictionary with property (name, read, write, delete as keys).
89
93
  """
90
94
  path = 'rses/' + rse
91
95
  url = build_url(choice(self.list_hosts), path=path)
@@ -95,7 +99,7 @@ class RSEClient(BaseClient):
95
99
  exc_cls, exc_msg = self._get_exception(headers=r.headers, status_code=r.status_code, data=r.content)
96
100
  raise exc_cls(exc_msg)
97
101
 
98
- def delete_rse(self, rse):
102
+ def delete_rse(self, rse: str) -> Literal[True]:
99
103
  """
100
104
  Sends the request to delete a rse.
101
105
 
@@ -111,7 +115,7 @@ class RSEClient(BaseClient):
111
115
  exc_cls, exc_msg = self._get_exception(headers=r.headers, status_code=r.status_code, data=r.content)
112
116
  raise exc_cls(exc_msg)
113
117
 
114
- def list_rses(self, rse_expression=None):
118
+ def list_rses(self, rse_expression: Optional[str] = None) -> "Iterator[dict[str, Any]]":
115
119
  """
116
120
  Sends the request to list all rucio locations(RSEs).
117
121
 
@@ -131,7 +135,12 @@ class RSEClient(BaseClient):
131
135
  exc_cls, exc_msg = self._get_exception(headers=r.headers, status_code=r.status_code, data=r.content)
132
136
  raise exc_cls(exc_msg)
133
137
 
134
- def add_rse_attribute(self, rse, key, value):
138
+ def add_rse_attribute(
139
+ self,
140
+ rse: str,
141
+ key: str,
142
+ value: Any
143
+ ) -> Literal[True]:
135
144
  """
136
145
  Sends the request to add a RSE attribute.
137
146
 
@@ -153,7 +162,7 @@ class RSEClient(BaseClient):
153
162
  exc_cls, exc_msg = self._get_exception(headers=r.headers, status_code=r.status_code, data=r.content)
154
163
  raise exc_cls(exc_msg)
155
164
 
156
- def delete_rse_attribute(self, rse, key):
165
+ def delete_rse_attribute(self, rse: str, key: str) -> Literal[True]:
157
166
  """
158
167
  Sends the request to delete a RSE attribute.
159
168
 
@@ -172,7 +181,7 @@ class RSEClient(BaseClient):
172
181
  exc_cls, exc_msg = self._get_exception(headers=r.headers, status_code=r.status_code, data=r.content)
173
182
  raise exc_cls(exc_msg)
174
183
 
175
- def list_rse_attributes(self, rse):
184
+ def list_rse_attributes(self, rse: str) -> dict[str, Any]:
176
185
  """
177
186
  Sends the request to get RSE attributes.
178
187
 
@@ -190,7 +199,7 @@ class RSEClient(BaseClient):
190
199
  exc_cls, exc_msg = self._get_exception(headers=r.headers, status_code=r.status_code, data=r.content)
191
200
  raise exc_cls(exc_msg)
192
201
 
193
- def add_protocol(self, rse, params):
202
+ def add_protocol(self, rse: str, params: dict[str, Any]) -> Literal[True]:
194
203
  """
195
204
  Sends the request to create a new protocol for the given RSE.
196
205
 
@@ -225,9 +234,16 @@ class RSEClient(BaseClient):
225
234
  exc_cls, exc_msg = self._get_exception(headers=r.headers, status_code=r.status_code, data=r.content)
226
235
  raise exc_cls(exc_msg)
227
236
 
228
- def get_protocols(self, rse, protocol_domain='ALL', operation=None, default=False, scheme=None):
237
+ def get_protocols(
238
+ self,
239
+ rse: str,
240
+ protocol_domain: "RSE_SUPPORTED_PROTOCOL_DOMAINS_LITERAL" = 'ALL',
241
+ operation: Optional["RSE_SUPPORTED_PROTOCOL_OPERATIONS_LITERAL"] = None,
242
+ default: bool = False,
243
+ scheme: Optional['SUPPORTED_PROTOCOLS_LITERAL'] = None
244
+ ) -> Any:
229
245
  """
230
- Returns protocol information. Parameter comibantions are:
246
+ Returns protocol information. Parameter combinations are:
231
247
  (operation OR default) XOR protocol.
232
248
 
233
249
  :param rse: the RSE name.
@@ -237,7 +253,7 @@ class RSEClient(BaseClient):
237
253
  :param default: Indicates if only the default operations should be returned.
238
254
  :param scheme: The identifier of the requested protocol.
239
255
 
240
- :returns: A list with details about each matching protocol.
256
+ :returns: A dict with details about each matching protocol.
241
257
 
242
258
  :raises RSENotFound: if the RSE doesn't exist.
243
259
  :raises RSEProtocolNotSupported: if no matching protocol entry could be found.
@@ -266,7 +282,14 @@ class RSEClient(BaseClient):
266
282
  exc_cls, exc_msg = self._get_exception(headers=r.headers, status_code=r.status_code, data=r.content)
267
283
  raise exc_cls(exc_msg)
268
284
 
269
- def lfns2pfns(self, rse, lfns, protocol_domain='ALL', operation=None, scheme=None):
285
+ def lfns2pfns(
286
+ self,
287
+ rse: str,
288
+ lfns: 'Iterable[str]',
289
+ protocol_domain: 'RSE_SUPPORTED_PROTOCOL_DOMAINS_LITERAL' = 'ALL',
290
+ operation: Optional['RSE_SUPPORTED_PROTOCOL_OPERATIONS_LITERAL'] = None,
291
+ scheme: Optional['SUPPORTED_PROTOCOLS_LITERAL'] = None
292
+ ) -> dict[str, str]:
270
293
  """
271
294
  Returns PFNs that should be used at a RSE, corresponding to requested LFNs.
272
295
  The PFNs are generated for the RSE *regardless* of whether a replica exists for the LFN.
@@ -305,7 +328,13 @@ class RSEClient(BaseClient):
305
328
  exc_cls, exc_msg = self._get_exception(headers=r.headers, status_code=r.status_code, data=r.content)
306
329
  raise exc_cls(exc_msg)
307
330
 
308
- def delete_protocols(self, rse, scheme, hostname=None, port=None):
331
+ def delete_protocols(
332
+ self,
333
+ rse: str,
334
+ scheme: 'SUPPORTED_PROTOCOLS_LITERAL',
335
+ hostname: Optional[str] = None,
336
+ port: Optional[int] = None
337
+ ) -> Literal[True]:
309
338
  """
310
339
  Deletes matching protocols from RSE. Protocols using the same identifier can be
311
340
  distinguished by hostname and port.
@@ -336,14 +365,20 @@ class RSEClient(BaseClient):
336
365
  exc_cls, exc_msg = self._get_exception(headers=r.headers, status_code=r.status_code, data=r.content)
337
366
  raise exc_cls(exc_msg)
338
367
 
339
- def update_protocols(self, rse, scheme, data, hostname=None, port=None):
368
+ def update_protocols(
369
+ self,
370
+ rse: str,
371
+ scheme: 'SUPPORTED_PROTOCOLS_LITERAL',
372
+ data: dict[str, Any],
373
+ hostname: Optional[str] = None,
374
+ port: Optional[int] = None):
340
375
  """
341
376
  Updates matching protocols from RSE. Protocol using the same identifier can be
342
377
  distinguished by hostname and port.
343
378
 
344
379
  :param rse: the RSE name.
345
380
  :param scheme: identifier of the protocol.
346
- :param data: A dict providing the new values of the protocol attibutes.
381
+ :param data: A dict providing the new values of the protocol attributes.
347
382
  Keys must match column names in database.
348
383
  :param hostname: hostname of the protocol.
349
384
  :param port: port of the protocol.
@@ -370,7 +405,14 @@ class RSEClient(BaseClient):
370
405
  exc_cls, exc_msg = self._get_exception(headers=r.headers, status_code=r.status_code, data=r.content)
371
406
  raise exc_cls(exc_msg)
372
407
 
373
- def swap_protocols(self, rse, domain, operation, scheme_a, scheme_b):
408
+ def swap_protocols(
409
+ self,
410
+ rse: str,
411
+ domain: 'RSE_SUPPORTED_PROTOCOL_DOMAINS_LITERAL',
412
+ operation: 'RSE_SUPPORTED_PROTOCOL_OPERATIONS_LITERAL',
413
+ scheme_a: 'SUPPORTED_PROTOCOLS_LITERAL',
414
+ scheme_b: 'SUPPORTED_PROTOCOLS_LITERAL'
415
+ ) -> bool:
374
416
  """
375
417
  Swaps the priorities of the provided operation.
376
418
 
@@ -387,22 +429,21 @@ class RSEClient(BaseClient):
387
429
  :raises KeyNotFound: if invalid data was provided for update.
388
430
  :raises AccessDenied: if not authorized.
389
431
  """
390
- protocol_a = protocol_b = None
432
+
391
433
  protocols = self.get_protocols(rse, domain, operation, False, scheme_a)['protocols']
392
- for p in protocols:
393
- if p['scheme'] == scheme_a:
394
- protocol_a = p
395
- if p['scheme'] == scheme_b:
396
- protocol_b = p
397
- if (protocol_a or protocol_b) is None:
434
+ protocol_a = next((p for p in protocols if p['scheme'] == scheme_a), None)
435
+ protocol_b = next((p for p in protocols if p['scheme'] == scheme_b), None)
436
+
437
+ if protocol_a is None or protocol_b is None:
398
438
  return False
439
+
399
440
  priority_a = protocol_a['domains'][domain][operation]
400
441
  priority_b = protocol_b['domains'][domain][operation]
401
442
  self.update_protocols(rse, protocol_a['scheme'], {'domains': {domain: {operation: priority_b}}}, protocol_a['hostname'], protocol_a['port'])
402
443
  self.update_protocols(rse, protocol_b['scheme'], {'domains': {domain: {operation: priority_a}}}, protocol_b['hostname'], protocol_b['port'])
403
444
  return True
404
445
 
405
- def add_qos_policy(self, rse, qos_policy):
446
+ def add_qos_policy(self, rse: str, qos_policy: str) -> Literal[True]:
406
447
  """
407
448
  Add a QoS policy from an RSE.
408
449
 
@@ -424,7 +465,7 @@ class RSEClient(BaseClient):
424
465
  exc_cls, exc_msg = self._get_exception(headers=r.headers, status_code=r.status_code, data=r.content)
425
466
  raise exc_cls(exc_msg)
426
467
 
427
- def delete_qos_policy(self, rse, qos_policy):
468
+ def delete_qos_policy(self, rse: str, qos_policy: str) -> Literal[True]:
428
469
  """
429
470
  Delete a QoS policy from an RSE.
430
471
 
@@ -445,7 +486,7 @@ class RSEClient(BaseClient):
445
486
  exc_cls, exc_msg = self._get_exception(headers=r.headers, status_code=r.status_code, data=r.content)
446
487
  raise exc_cls(exc_msg)
447
488
 
448
- def list_qos_policies(self, rse):
489
+ def list_qos_policies(self, rse: str) -> list[str]:
449
490
  """
450
491
  List all QoS policies of an RSE.
451
492
 
@@ -465,7 +506,14 @@ class RSEClient(BaseClient):
465
506
  exc_cls, exc_msg = self._get_exception(headers=r.headers, status_code=r.status_code, data=r.content)
466
507
  raise exc_cls(exc_msg)
467
508
 
468
- def set_rse_usage(self, rse, source, used, free, files=None):
509
+ def set_rse_usage(
510
+ self,
511
+ rse: str,
512
+ source: str,
513
+ used: int,
514
+ free: int,
515
+ files: Optional[int] = None
516
+ ) -> Literal[True]:
469
517
  """
470
518
  Set RSE usage information.
471
519
 
@@ -475,7 +523,7 @@ class RSEClient(BaseClient):
475
523
  :param free: the free in bytes.
476
524
  :param files: the number of files
477
525
 
478
- :returns: True if successful, otherwise false.
526
+ :returns: True if successful
479
527
  """
480
528
  path = [self.RSE_BASEURL, rse, 'usage']
481
529
  path = '/'.join(path)
@@ -488,7 +536,11 @@ class RSEClient(BaseClient):
488
536
  exc_cls, exc_msg = self._get_exception(headers=r.headers, status_code=r.status_code, data=r.content)
489
537
  raise exc_cls(exc_msg)
490
538
 
491
- def get_rse_usage(self, rse, filters=None):
539
+ def get_rse_usage(
540
+ self,
541
+ rse: str,
542
+ filters: Optional[dict[str, Any]] = None
543
+ ) -> "Iterator[dict[str, Any]]":
492
544
  """
493
545
  Get RSE usage information.
494
546
 
@@ -507,14 +559,18 @@ class RSEClient(BaseClient):
507
559
  exc_cls, exc_msg = self._get_exception(headers=r.headers, status_code=r.status_code, data=r.content)
508
560
  raise exc_cls(exc_msg)
509
561
 
510
- def list_rse_usage_history(self, rse, filters=None):
562
+ def list_rse_usage_history(
563
+ self,
564
+ rse: str,
565
+ filters: Optional[dict[str, Any]] = None
566
+ ) -> "Iterator[dict[str, Any]]":
511
567
  """
512
568
  List RSE usage history information.
513
569
 
514
570
  :param rse: The RSE name.
515
571
  :param filters: dictionary of attributes by which the results should be filtered.
516
572
 
517
- :returns: list of dictionnaries.
573
+ :returns: list of dictionaries.
518
574
  """
519
575
  path = [self.RSE_BASEURL, rse, 'usage', 'history']
520
576
  path = '/'.join(path)
@@ -528,7 +584,12 @@ class RSEClient(BaseClient):
528
584
  data=r.content)
529
585
  raise exc_cls(exc_msg)
530
586
 
531
- def set_rse_limits(self, rse, name, value):
587
+ def set_rse_limits(
588
+ self,
589
+ rse: str,
590
+ name: str,
591
+ value: int
592
+ ) -> Literal[True]:
532
593
  """
533
594
  Set RSE limit information.
534
595
 
@@ -536,7 +597,7 @@ class RSEClient(BaseClient):
536
597
  :param name: The name of the limit.
537
598
  :param value: The feature value.
538
599
 
539
- :returns: True if successful, otherwise false.
600
+ :returns: True if successful
540
601
  """
541
602
  path = [self.RSE_BASEURL, rse, 'limits']
542
603
  path = '/'.join(path)
@@ -549,13 +610,16 @@ class RSEClient(BaseClient):
549
610
  data=r.content)
550
611
  raise exc_cls(exc_msg)
551
612
 
552
- def get_rse_limits(self, rse):
613
+ def get_rse_limits(
614
+ self,
615
+ rse: str
616
+ ) -> "Iterator[dict[str, Union[str, int]]]":
553
617
  """
554
618
  Get RSE limits.
555
619
 
556
620
  :param rse: The RSE name.
557
621
 
558
- :returns: True if successful, otherwise false.
622
+ :returns: An iterator of RSE limits as dicts with 'name' and 'value' as keys.
559
623
  """
560
624
  path = [self.RSE_BASEURL, rse, 'limits']
561
625
  path = '/'.join(path)
@@ -568,14 +632,14 @@ class RSEClient(BaseClient):
568
632
  data=r.content)
569
633
  raise exc_cls(exc_msg)
570
634
 
571
- def delete_rse_limits(self, rse, name):
635
+ def delete_rse_limits(self, rse: str, name: str) -> Literal[True]:
572
636
  """
573
637
  Delete RSE limit information.
574
638
 
575
639
  :param rse: The RSE name.
576
640
  :param name: The name of the limit.
577
641
 
578
- :returns: True if successful, otherwise false.
642
+ :returns: True if successful
579
643
  """
580
644
  path = [self.RSE_BASEURL, rse, 'limits']
581
645
  path = '/'.join(path)
@@ -587,15 +651,20 @@ class RSEClient(BaseClient):
587
651
  status_code=r.status_code,
588
652
  data=r.content)
589
653
 
590
- return exc_cls(exc_msg)
654
+ raise exc_cls(exc_msg)
591
655
 
592
- def add_distance(self, source, destination, parameters):
656
+ def add_distance(
657
+ self,
658
+ source: str,
659
+ destination: str,
660
+ parameters: dict[str, int]
661
+ ) -> Literal[True]:
593
662
  """
594
663
  Add a src-dest distance.
595
664
 
596
665
  :param source: The source.
597
666
  :param destination: The destination.
598
- :param parameters: A dictionnary with property.
667
+ :param parameters: A dictionary with property.
599
668
  """
600
669
  path = [self.RSE_BASEURL, source, 'distances', destination]
601
670
  path = '/'.join(path)
@@ -608,13 +677,18 @@ class RSEClient(BaseClient):
608
677
  data=r.content)
609
678
  raise exc_cls(exc_msg)
610
679
 
611
- def update_distance(self, source, destination, parameters):
680
+ def update_distance(
681
+ self,
682
+ source: str,
683
+ destination: str,
684
+ parameters: dict[str, int]
685
+ ) -> Literal[True]:
612
686
  """
613
687
  Update distances with the given RSE ids.
614
688
 
615
689
  :param source: The source.
616
690
  :param destination: The destination.
617
- :param parameters: A dictionnary with property.
691
+ :param parameters: A dictionary with property.
618
692
  """
619
693
  path = [self.RSE_BASEURL, source, 'distances', destination]
620
694
  path = '/'.join(path)
@@ -627,7 +701,11 @@ class RSEClient(BaseClient):
627
701
  data=r.content)
628
702
  raise exc_cls(exc_msg)
629
703
 
630
- def get_distance(self, source, destination):
704
+ def get_distance(
705
+ self,
706
+ source: str,
707
+ destination: str
708
+ ) -> list[dict[str, Union[str, int]]]:
631
709
  """
632
710
  Get distances between rses.
633
711
 
@@ -645,7 +723,11 @@ class RSEClient(BaseClient):
645
723
  exc_cls, exc_msg = self._get_exception(headers=r.headers, status_code=r.status_code, data=r.content)
646
724
  raise exc_cls(exc_msg)
647
725
 
648
- def delete_distance(self, source, destination):
726
+ def delete_distance(
727
+ self,
728
+ source: str,
729
+ destination: str
730
+ ) -> Literal[True]:
649
731
  """
650
732
  Delete distances with the given RSE ids.
651
733
 
@@ -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");
@@ -14,15 +13,17 @@
14
13
  # limitations under the License.
15
14
 
16
15
  from json import dumps, loads
17
- from typing import Any, Optional, Union
16
+ from typing import TYPE_CHECKING, Any, Literal, Optional, Union
18
17
  from urllib.parse import quote_plus
19
18
 
20
19
  from requests.status_codes import codes
21
20
 
22
- from rucio.client.baseclient import BaseClient
23
- from rucio.client.baseclient import choice
21
+ from rucio.client.baseclient import BaseClient, choice
24
22
  from rucio.common.utils import build_url
25
23
 
24
+ if TYPE_CHECKING:
25
+ from collections.abc import Iterator, Mapping, Sequence
26
+
26
27
 
27
28
  class RuleClient(BaseClient):
28
29
 
@@ -32,7 +33,7 @@ class RuleClient(BaseClient):
32
33
 
33
34
  def add_replication_rule(
34
35
  self,
35
- dids: list[str],
36
+ dids: "Sequence[dict[str, str]]",
36
37
  copies: int,
37
38
  rse_expression: str,
38
39
  priority: int = 3,
@@ -48,10 +49,10 @@ class RuleClient(BaseClient):
48
49
  ask_approval: bool = False,
49
50
  asynchronous: bool = False,
50
51
  locked: bool = False,
51
- delay_injection=None,
52
- comment=None,
53
- weight=None,
54
- ):
52
+ delay_injection: Optional[int] = None,
53
+ comment: Optional[str] = None,
54
+ weight: Optional[int] = None,
55
+ ) -> Any:
55
56
  """
56
57
  :param dids: The data identifier set.
57
58
  :param copies: The number of replicas.
@@ -92,7 +93,7 @@ class RuleClient(BaseClient):
92
93
 
93
94
  def delete_replication_rule(
94
95
  self, rule_id: str, purge_replicas: Optional[bool] = None
95
- ):
96
+ ) -> Literal[True]:
96
97
  """
97
98
  Deletes a replication rule and all associated locks.
98
99
 
@@ -113,7 +114,7 @@ class RuleClient(BaseClient):
113
114
  exc_cls, exc_msg = self._get_exception(headers=r.headers, status_code=r.status_code, data=r.content)
114
115
  raise exc_cls(exc_msg)
115
116
 
116
- def get_replication_rule(self, rule_id: str):
117
+ def get_replication_rule(self, rule_id: str) -> Any:
117
118
  """
118
119
  Get a replication rule.
119
120
 
@@ -129,7 +130,7 @@ class RuleClient(BaseClient):
129
130
  exc_cls, exc_msg = self._get_exception(headers=r.headers, status_code=r.status_code, data=r.content)
130
131
  raise exc_cls(exc_msg)
131
132
 
132
- def update_replication_rule(self, rule_id: str, options: dict[str, Any]):
133
+ def update_replication_rule(self, rule_id: str, options: dict[str, Any]) -> Literal[True]:
133
134
  """
134
135
  :param rule_id: The id of the rule to be retrieved.
135
136
  :param options: Options dictionary.
@@ -145,8 +146,11 @@ class RuleClient(BaseClient):
145
146
  raise exc_cls(exc_msg)
146
147
 
147
148
  def reduce_replication_rule(
148
- self, rule_id: str, copies: int, exclude_expression=None
149
- ):
149
+ self,
150
+ rule_id: str,
151
+ copies: int,
152
+ exclude_expression: Optional[str] = None
153
+ ) -> Any:
150
154
  """
151
155
  :param rule_id: Rule to be reduced.
152
156
  :param copies: Number of copies of the new rule.
@@ -164,8 +168,11 @@ class RuleClient(BaseClient):
164
168
  raise exc_cls(exc_msg)
165
169
 
166
170
  def move_replication_rule(
167
- self, rule_id: str, rse_expression: str, override
168
- ):
171
+ self,
172
+ rule_id: str,
173
+ rse_expression: str,
174
+ override: "Mapping[str, Any]"
175
+ ) -> Any:
169
176
  """
170
177
  Move a replication rule to another RSE and, once done, delete the original one.
171
178
 
@@ -188,7 +195,7 @@ class RuleClient(BaseClient):
188
195
  exc_cls, exc_msg = self._get_exception(headers=r.headers, status_code=r.status_code, data=r.content)
189
196
  raise exc_cls(exc_msg)
190
197
 
191
- def approve_replication_rule(self, rule_id: str):
198
+ def approve_replication_rule(self, rule_id: str) -> Literal[True]:
192
199
  """
193
200
  :param rule_id: Rule to be approved.
194
201
  :raises: RuleNotFound
@@ -203,7 +210,7 @@ class RuleClient(BaseClient):
203
210
  exc_cls, exc_msg = self._get_exception(headers=r.headers, status_code=r.status_code, data=r.content)
204
211
  raise exc_cls(exc_msg)
205
212
 
206
- def deny_replication_rule(self, rule_id: str, reason: Optional[str] = None):
213
+ def deny_replication_rule(self, rule_id: str, reason: Optional[str] = None) -> Literal[True]:
207
214
  """
208
215
  :param rule_id: Rule to be denied.
209
216
  :param reason: Reason for denying the rule.
@@ -224,7 +231,7 @@ class RuleClient(BaseClient):
224
231
 
225
232
  def list_replication_rule_full_history(
226
233
  self, scope: Union[str, bytes], name: Union[str, bytes]
227
- ):
234
+ ) -> "Iterator[dict[str, Any]]":
228
235
  """
229
236
  List the rule history of a DID.
230
237
 
@@ -239,7 +246,7 @@ class RuleClient(BaseClient):
239
246
  exc_cls, exc_msg = self._get_exception(r.headers, r.status_code)
240
247
  raise exc_cls(exc_msg)
241
248
 
242
- def examine_replication_rule(self, rule_id: str):
249
+ def examine_replication_rule(self, rule_id: str) -> Any:
243
250
  """
244
251
  Examine a replication rule for errors during transfer.
245
252
 
@@ -254,7 +261,7 @@ class RuleClient(BaseClient):
254
261
  exc_cls, exc_msg = self._get_exception(r.headers, r.status_code)
255
262
  raise exc_cls(exc_msg)
256
263
 
257
- def list_replica_locks(self, rule_id: str):
264
+ def list_replica_locks(self, rule_id: str) -> Any:
258
265
  """
259
266
  List details of all replica locks for a rule.
260
267
 
@@ -269,7 +276,7 @@ class RuleClient(BaseClient):
269
276
  exc_cls, exc_msg = self._get_exception(r.headers, r.status_code)
270
277
  raise exc_cls(exc_msg)
271
278
 
272
- def list_replication_rules(self, filters=None):
279
+ def list_replication_rules(self, filters: Optional[dict[str, Any]] = None) -> "Iterator[dict[str, Any]]":
273
280
  """
274
281
  List all replication rules which match a filter
275
282
  :param filters: dictionary of attributes by which the rules should be filtered
@@ -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");
@@ -18,8 +17,7 @@ from urllib.parse import quote_plus
18
17
 
19
18
  from requests.status_codes import codes
20
19
 
21
- from rucio.client.baseclient import BaseClient
22
- from rucio.client.baseclient import choice
20
+ from rucio.client.baseclient import BaseClient, choice
23
21
  from rucio.common.utils import build_url
24
22
 
25
23
 
@@ -29,7 +27,11 @@ class ScopeClient(BaseClient):
29
27
 
30
28
  SCOPE_BASEURL = 'accounts'
31
29
 
32
- def add_scope(self, account, scope):
30
+ def add_scope(
31
+ self,
32
+ account: str,
33
+ scope: str
34
+ ) -> bool:
33
35
  """
34
36
  Sends the request to add a new scope.
35
37
 
@@ -49,7 +51,7 @@ class ScopeClient(BaseClient):
49
51
  exc_cls, exc_msg = self._get_exception(headers=r.headers, status_code=r.status_code, data=r.content)
50
52
  raise exc_cls(exc_msg)
51
53
 
52
- def list_scopes(self):
54
+ def list_scopes(self) -> list[str]:
53
55
  """
54
56
  Sends the request to list all scopes.
55
57
 
@@ -66,7 +68,7 @@ class ScopeClient(BaseClient):
66
68
  exc_cls, exc_msg = self._get_exception(headers=r.headers, status_code=r.status_code, data=r.content)
67
69
  raise exc_cls(exc_msg)
68
70
 
69
- def list_scopes_for_account(self, account):
71
+ def list_scopes_for_account(self, account: str) -> list[str]:
70
72
  """
71
73
  Sends the request to list all scopes for a rucio account.
72
74