rucio-clients 35.7.0__py3-none-any.whl → 37.0.0rc2__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 (86) hide show
  1. rucio/alembicrevision.py +1 -1
  2. rucio/cli/__init__.py +14 -0
  3. rucio/cli/account.py +216 -0
  4. rucio/cli/bin_legacy/__init__.py +13 -0
  5. rucio_clients-35.7.0.data/scripts/rucio → rucio/cli/bin_legacy/rucio.py +769 -486
  6. rucio_clients-35.7.0.data/scripts/rucio-admin → rucio/cli/bin_legacy/rucio_admin.py +476 -423
  7. rucio/cli/command.py +272 -0
  8. rucio/cli/config.py +72 -0
  9. rucio/cli/did.py +191 -0
  10. rucio/cli/download.py +128 -0
  11. rucio/cli/lifetime_exception.py +33 -0
  12. rucio/cli/replica.py +162 -0
  13. rucio/cli/rse.py +293 -0
  14. rucio/cli/rule.py +158 -0
  15. rucio/cli/scope.py +40 -0
  16. rucio/cli/subscription.py +73 -0
  17. rucio/cli/upload.py +60 -0
  18. rucio/cli/utils.py +226 -0
  19. rucio/client/accountclient.py +0 -1
  20. rucio/client/baseclient.py +33 -24
  21. rucio/client/client.py +45 -1
  22. rucio/client/didclient.py +5 -3
  23. rucio/client/downloadclient.py +6 -8
  24. rucio/client/replicaclient.py +0 -2
  25. rucio/client/richclient.py +317 -0
  26. rucio/client/rseclient.py +4 -4
  27. rucio/client/uploadclient.py +26 -12
  28. rucio/common/bittorrent.py +234 -0
  29. rucio/common/cache.py +66 -29
  30. rucio/common/checksum.py +168 -0
  31. rucio/common/client.py +122 -0
  32. rucio/common/config.py +22 -35
  33. rucio/common/constants.py +61 -3
  34. rucio/common/didtype.py +72 -24
  35. rucio/common/exception.py +65 -8
  36. rucio/common/extra.py +5 -10
  37. rucio/common/logging.py +13 -13
  38. rucio/common/pcache.py +8 -7
  39. rucio/common/plugins.py +59 -27
  40. rucio/common/policy.py +12 -3
  41. rucio/common/schema/__init__.py +84 -34
  42. rucio/common/schema/generic.py +0 -17
  43. rucio/common/schema/generic_multi_vo.py +0 -17
  44. rucio/common/stomp_utils.py +383 -119
  45. rucio/common/test_rucio_server.py +12 -6
  46. rucio/common/types.py +132 -52
  47. rucio/common/utils.py +93 -643
  48. rucio/rse/__init__.py +3 -3
  49. rucio/rse/protocols/bittorrent.py +11 -1
  50. rucio/rse/protocols/cache.py +0 -11
  51. rucio/rse/protocols/dummy.py +0 -11
  52. rucio/rse/protocols/gfal.py +14 -9
  53. rucio/rse/protocols/globus.py +1 -1
  54. rucio/rse/protocols/http_cache.py +1 -1
  55. rucio/rse/protocols/posix.py +2 -2
  56. rucio/rse/protocols/protocol.py +84 -317
  57. rucio/rse/protocols/rclone.py +2 -1
  58. rucio/rse/protocols/rfio.py +10 -1
  59. rucio/rse/protocols/ssh.py +2 -1
  60. rucio/rse/protocols/storm.py +2 -13
  61. rucio/rse/protocols/webdav.py +74 -30
  62. rucio/rse/protocols/xrootd.py +2 -1
  63. rucio/rse/rsemanager.py +170 -53
  64. rucio/rse/translation.py +260 -0
  65. rucio/vcsversion.py +4 -4
  66. rucio/version.py +7 -0
  67. {rucio_clients-35.7.0.data → rucio_clients-37.0.0rc2.data}/data/etc/rucio.cfg.atlas.client.template +3 -2
  68. {rucio_clients-35.7.0.data → rucio_clients-37.0.0rc2.data}/data/etc/rucio.cfg.template +3 -19
  69. {rucio_clients-35.7.0.data → rucio_clients-37.0.0rc2.data}/data/requirements.client.txt +11 -7
  70. rucio_clients-37.0.0rc2.data/scripts/rucio +133 -0
  71. rucio_clients-37.0.0rc2.data/scripts/rucio-admin +97 -0
  72. {rucio_clients-35.7.0.dist-info → rucio_clients-37.0.0rc2.dist-info}/METADATA +18 -14
  73. rucio_clients-37.0.0rc2.dist-info/RECORD +104 -0
  74. {rucio_clients-35.7.0.dist-info → rucio_clients-37.0.0rc2.dist-info}/licenses/AUTHORS.rst +3 -0
  75. rucio/common/schema/atlas.py +0 -413
  76. rucio/common/schema/belleii.py +0 -408
  77. rucio/common/schema/domatpc.py +0 -401
  78. rucio/common/schema/escape.py +0 -426
  79. rucio/common/schema/icecube.py +0 -406
  80. rucio/rse/protocols/gsiftp.py +0 -92
  81. rucio_clients-35.7.0.dist-info/RECORD +0 -88
  82. {rucio_clients-35.7.0.data → rucio_clients-37.0.0rc2.data}/data/etc/rse-accounts.cfg.template +0 -0
  83. {rucio_clients-35.7.0.data → rucio_clients-37.0.0rc2.data}/data/rucio_client/merge_rucio_configs.py +0 -0
  84. {rucio_clients-35.7.0.dist-info → rucio_clients-37.0.0rc2.dist-info}/WHEEL +0 -0
  85. {rucio_clients-35.7.0.dist-info → rucio_clients-37.0.0rc2.dist-info}/licenses/LICENSE +0 -0
  86. {rucio_clients-35.7.0.dist-info → rucio_clients-37.0.0rc2.dist-info}/top_level.txt +0 -0
rucio/common/types.py CHANGED
@@ -14,40 +14,39 @@
14
14
 
15
15
  import sys
16
16
  from collections.abc import Callable
17
- from datetime import datetime
18
17
  from os import PathLike
19
18
 
20
- if sys.version_info < (3, 11):
21
- from typing_extensions import TYPE_CHECKING, Any, Literal, NotRequired, Optional, TypedDict, Union # noqa: UP035
19
+ if sys.version_info < (3, 11): # pragma: no cover
20
+ from typing_extensions import TYPE_CHECKING, Any, Literal, NotRequired, Optional, TypedDict, TypeGuard, Union # noqa: UP035
22
21
  PathTypeAlias = Union[PathLike, str]
23
22
  else:
24
- from typing import TYPE_CHECKING, Any, Literal, NotRequired, Optional, TypedDict, Union
23
+ from typing import TYPE_CHECKING, Any, Literal, NotRequired, Optional, TypedDict, TypeGuard, Union
25
24
  PathTypeAlias = PathLike
26
25
 
27
26
 
28
27
  if TYPE_CHECKING:
28
+ from datetime import datetime
29
+
29
30
  from rucio.common.constants import SUPPORTED_PROTOCOLS_LITERAL
30
- from rucio.db.sqla.constants import AccountType, IdentityType, RequestState, RequestType
31
+ from rucio.db.sqla.constants import AccountType, IdentityType, ReplicaState, RequestState, RequestType, RSEType
31
32
 
32
33
 
33
34
  class InternalType:
34
35
  '''
35
36
  Base for Internal representations of string types
36
37
  '''
37
- def __init__(self, value: Optional[str], vo: str = 'def', fromExternal: bool = True):
38
+ def __init__(self, value: Optional[str], vo: str = 'def', from_external: bool = True):
38
39
  if value is None:
39
40
  self.external = None
40
41
  self.internal = None
41
42
  self.vo = vo
42
- elif not isinstance(value, str):
43
- raise TypeError('Expected value to be string type, got %s' % type(value))
44
- elif fromExternal:
43
+ elif from_external:
45
44
  self.external = value
46
45
  self.vo = vo
47
- self.internal = self._calc_internal()
46
+ self.internal = _RepresentationCalculator.calc_internal(self.external, self.vo)
48
47
  else:
49
48
  self.internal = value
50
- vo, external = self._calc_external()
49
+ vo, external = _RepresentationCalculator.calc_external(self.internal)
51
50
  self.external = external
52
51
  self.vo = vo
53
52
 
@@ -58,49 +57,56 @@ class InternalType:
58
57
  return self.external
59
58
 
60
59
  def __eq__(self, other):
61
- if isinstance(other, self.__class__):
60
+ if type(self) is type(other):
62
61
  return self.internal == other.internal
63
62
  return NotImplemented
64
63
 
65
- def __ne__(self, other):
66
- val = self == other
67
- if val is NotImplemented:
68
- return NotImplemented
69
- return not val
70
-
71
64
  def __le__(self, other):
72
- val = self.external <= other.external
73
- if val is NotImplemented:
74
- return NotImplemented
75
- return val
65
+ if type(self) is type(other) and self.external is not None and other.external is not None:
66
+ return self.external <= other.external
67
+ return NotImplemented
76
68
 
77
69
  def __lt__(self, other):
78
- val = self.external < other.external
79
- if val is NotImplemented:
80
- return NotImplemented
81
- return val
70
+ if type(self) is type(other) and self.external is not None and other.external is not None:
71
+ return self.external < other.external
72
+ return NotImplemented
82
73
 
83
74
  def __hash__(self):
84
75
  return hash(self.internal)
85
76
 
86
- def _calc_external(self) -> tuple[str, str]:
87
- ''' Utility to convert between internal and external representations'''
88
- if isinstance(self.internal, str):
89
- split = self.internal.split('@', 1)
90
- if len(split) == 1: # if cannot convert, vo is '' and this is single vo
91
- vo = 'def'
92
- external = split[0]
93
- else:
94
- vo = split[1]
95
- external = split[0]
96
- return vo, external
97
- return '', ''
98
-
99
- def _calc_internal(self) -> str:
100
- ''' Utility to convert between internal and external representations'''
101
- if self.vo == 'def' and self.external is not None:
102
- return self.external
103
- internal = '{}@{}'.format(self.external, self.vo)
77
+
78
+ class _RepresentationCalculator:
79
+ @staticmethod
80
+ def calc_external(internal: str) -> tuple[str, str]:
81
+ """
82
+ Calculate external representation from internal representation
83
+
84
+ :param internal: internal representation
85
+
86
+ :returns: tuple of VO and external representation
87
+ """
88
+ split = internal.split('@', 1)
89
+ if len(split) == 1: # if cannot convert, vo is '' and this is single vo
90
+ vo = 'def'
91
+ external = split[0]
92
+ else:
93
+ vo = split[1]
94
+ external = split[0]
95
+ return vo, external
96
+
97
+ @staticmethod
98
+ def calc_internal(external: str, vo: str) -> str:
99
+ """
100
+ Calculate internal representation from external representation and VO
101
+
102
+ :param external: external representation
103
+ :param vo: VO name
104
+
105
+ :returns: internal representation
106
+ """
107
+ if vo == 'def':
108
+ return external
109
+ internal = '{}@{}'.format(external, vo)
104
110
  return internal
105
111
 
106
112
 
@@ -108,16 +114,16 @@ class InternalAccount(InternalType):
108
114
  '''
109
115
  Internal representation of an account
110
116
  '''
111
- def __init__(self, account: Optional[str], vo: str = 'def', fromExternal: bool = True):
112
- super(InternalAccount, self).__init__(value=account, vo=vo, fromExternal=fromExternal)
117
+ def __init__(self, account: Optional[str], vo: str = 'def', from_external: bool = True):
118
+ super(InternalAccount, self).__init__(value=account, vo=vo, from_external=from_external)
113
119
 
114
120
 
115
121
  class InternalScope(InternalType):
116
122
  '''
117
123
  Internal representation of a scope
118
124
  '''
119
- def __init__(self, scope: Optional[str], vo: str = 'def', fromExternal: bool = True):
120
- super(InternalScope, self).__init__(value=scope, vo=vo, fromExternal=fromExternal)
125
+ def __init__(self, scope: Optional[str], vo: str = 'def', from_external: bool = True):
126
+ super(InternalScope, self).__init__(value=scope, vo=vo, from_external=from_external)
121
127
 
122
128
 
123
129
  LoggerFunction = Callable[..., Any]
@@ -176,12 +182,50 @@ class RSESettingsDict(TypedDict):
176
182
  domain: list[str]
177
183
  protocols: list[RSEProtocolDict]
178
184
 
185
+ # Compatibility with protocols that access protocol-specific data from rse_settings (e.g. RFIO)
186
+ protocol: RSEProtocolDict
187
+ prefix: str
188
+ scheme: str
189
+ hostname: str
190
+
179
191
 
180
192
  class RSEAccountCounterDict(TypedDict):
181
193
  account: InternalAccount
182
194
  rse_id: str
183
195
 
184
196
 
197
+ class RSEAccountUsageDict(TypedDict):
198
+ rse_id: str
199
+ rse: str
200
+ account: InternalAccount
201
+ used_files: int
202
+ used_bytes: int
203
+ quota_bytes: int
204
+
205
+
206
+ class RSEGlobalAccountUsageDict(TypedDict):
207
+ rse_expression: str
208
+ bytes: int
209
+ files: int
210
+ bytes_limit: int
211
+ bytes_remaining: int
212
+
213
+
214
+ class RSELocalAccountUsageDict(TypedDict):
215
+ rse_id: str
216
+ rse: str
217
+ bytes: int
218
+ files: int
219
+ bytes_limit: int
220
+ bytes_remaining: int
221
+
222
+
223
+ class RSEResolvedGlobalAccountLimitDict(TypedDict):
224
+ resolved_rses: str
225
+ resolved_rse_ids: list[str]
226
+ limit: float
227
+
228
+
185
229
  class RuleDict(TypedDict):
186
230
  account: InternalAccount
187
231
  copies: int
@@ -197,6 +241,20 @@ class RuleDict(TypedDict):
197
241
  purge_replicas: bool
198
242
 
199
243
 
244
+ class ReplicaDict(TypedDict):
245
+ scope: InternalScope
246
+ name: str
247
+ path: Optional[str]
248
+ state: "ReplicaState"
249
+ bytes: int
250
+ md5: Optional[str]
251
+ adler32: Optional[str]
252
+ rse_id: str
253
+ rse_name: str
254
+ rse_type: "RSEType"
255
+ volatile: bool
256
+
257
+
200
258
  class DIDDict(TypedDict):
201
259
  name: str
202
260
  scope: InternalScope
@@ -207,6 +265,16 @@ class DIDStringDict(TypedDict):
207
265
  scope: str
208
266
 
209
267
 
268
+ class LFNDict(TypedDict):
269
+ name: str
270
+ scope: str
271
+ path: NotRequired[str]
272
+ filesize: NotRequired[int]
273
+ adler32: NotRequired[str]
274
+ md5: NotRequired[str]
275
+ filename: NotRequired[str]
276
+
277
+
210
278
  class DatasetDict(DIDStringDict):
211
279
  rse: str
212
280
 
@@ -226,18 +294,24 @@ class HopDict(TypedDict):
226
294
 
227
295
  class TokenDict(TypedDict):
228
296
  token: str
229
- expires_at: datetime
297
+ expires_at: 'datetime'
230
298
 
231
299
 
232
300
  class TokenValidationDict(TypedDict):
233
301
  account: Optional[InternalAccount]
234
302
  identity: Optional[str]
235
- lifetime: datetime
303
+ lifetime: 'datetime'
236
304
  audience: Optional[str]
237
305
  authz_scope: Optional[str]
238
306
 
239
307
 
240
308
  class IPDict(TypedDict):
309
+ ip: Optional[str]
310
+ fqdn: Optional[str]
311
+ site: Optional[str]
312
+
313
+
314
+ class IPWithLocationDict(TypedDict):
241
315
  ip: str
242
316
  fqdn: str
243
317
  site: str
@@ -265,7 +339,7 @@ class IdentityDict(TypedDict):
265
339
  class UsageDict(TypedDict):
266
340
  bytes: int
267
341
  files: int
268
- updated_at: Optional[datetime]
342
+ updated_at: Optional['datetime']
269
343
 
270
344
 
271
345
  class AccountUsageModelDict(TypedDict):
@@ -399,5 +473,11 @@ class RequestAttributesDict(TypedDict):
399
473
  class FilterDict(TypedDict):
400
474
  rule_id: str
401
475
  request_id: str
402
- older_than: datetime
476
+ older_than: 'datetime'
403
477
  activities: Union[list[str], str]
478
+
479
+
480
+ def is_str_list(in_list: list[Any]) -> TypeGuard[list[str]]:
481
+ """Typeguard to narrow type of list to list[str].
482
+ For speed, assumes that all elements are str if the first element is str."""
483
+ return isinstance(next(iter(in_list), None), str)