rucio-clients 38.1.0__py3-none-any.whl → 38.3.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 (28) 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 +1 -1
  5. rucio/cli/download.py +1 -1
  6. rucio/cli/opendata.py +60 -9
  7. rucio/cli/utils.py +13 -1
  8. rucio/client/configclient.py +23 -0
  9. rucio/client/richclient.py +6 -0
  10. rucio/common/constants.py +5 -0
  11. rucio/common/exception.py +10 -0
  12. rucio/common/plugins.py +24 -8
  13. rucio/common/utils.py +3 -3
  14. rucio/rse/translation.py +3 -3
  15. rucio/vcsversion.py +3 -3
  16. {rucio_clients-38.1.0.dist-info → rucio_clients-38.3.0.dist-info}/METADATA +1 -1
  17. {rucio_clients-38.1.0.dist-info → rucio_clients-38.3.0.dist-info}/RECORD +28 -28
  18. {rucio_clients-38.1.0.data → rucio_clients-38.3.0.data}/data/etc/rse-accounts.cfg.template +0 -0
  19. {rucio_clients-38.1.0.data → rucio_clients-38.3.0.data}/data/etc/rucio.cfg.atlas.client.template +0 -0
  20. {rucio_clients-38.1.0.data → rucio_clients-38.3.0.data}/data/etc/rucio.cfg.template +0 -0
  21. {rucio_clients-38.1.0.data → rucio_clients-38.3.0.data}/data/requirements.client.txt +0 -0
  22. {rucio_clients-38.1.0.data → rucio_clients-38.3.0.data}/data/rucio_client/merge_rucio_configs.py +0 -0
  23. {rucio_clients-38.1.0.data → rucio_clients-38.3.0.data}/scripts/rucio +0 -0
  24. {rucio_clients-38.1.0.data → rucio_clients-38.3.0.data}/scripts/rucio-admin +0 -0
  25. {rucio_clients-38.1.0.dist-info → rucio_clients-38.3.0.dist-info}/WHEEL +0 -0
  26. {rucio_clients-38.1.0.dist-info → rucio_clients-38.3.0.dist-info}/licenses/AUTHORS.rst +0 -0
  27. {rucio_clients-38.1.0.dist-info → rucio_clients-38.3.0.dist-info}/licenses/LICENSE +0 -0
  28. {rucio_clients-38.1.0.dist-info → rucio_clients-38.3.0.dist-info}/top_level.txt +0 -0
@@ -449,7 +449,6 @@ def list_dids(args, client, logger, console, spinner):
449
449
  """
450
450
 
451
451
  filters = {}
452
- type_ = 'collection'
453
452
  table_data = []
454
453
 
455
454
  try:
@@ -482,19 +481,17 @@ def list_dids(args, client, logger, console, spinner):
482
481
  else:
483
482
  table_data.append([f"{did['scope']}:{did['name']}", did['did_type']])
484
483
 
485
- if cli_config == 'rich':
486
- if args.short:
487
- table = generate_table([[did] for did, _ in table_data], headers=['SCOPE:NAME'], col_alignments=['left'])
488
- else:
489
- table = generate_table(table_data, headers=['SCOPE:NAME', '[DID TYPE]'], col_alignments=['left', 'left'])
490
- spinner.stop()
491
- print_output(table, console=console, no_pager=args.no_pager)
484
+ if args.short:
485
+ for did, _ in table_data:
486
+ print(did)
492
487
  else:
493
- if args.short:
494
- for did, _ in table_data:
495
- print(did)
488
+ if cli_config == 'rich':
489
+ table = generate_table(table_data, headers=['SCOPE:NAME', '[DID TYPE]'], col_alignments=['left', 'left'])
490
+ spinner.stop()
491
+ print_output(table, console=console, no_pager=args.no_pager)
496
492
  else:
497
493
  print(tabulate(table_data, tablefmt=tablefmt, headers=['SCOPE:NAME', '[DID TYPE]']))
494
+
498
495
  return SUCCESS
499
496
 
500
497
 
@@ -657,19 +654,17 @@ def list_content(args, client, logger, console, spinner):
657
654
  else:
658
655
  table_data.append([f"{content['scope']}:{content['name']}", content['type'].upper()])
659
656
 
660
- if cli_config == 'rich':
661
- if args.short:
662
- table = generate_table([[did] for did, _ in table_data], headers=['SCOPE:NAME'], col_alignments=['left'])
663
- else:
664
- table = generate_table(table_data, headers=['SCOPE:NAME', '[DID TYPE]'], col_alignments=['left', 'left'])
665
- spinner.stop()
666
- print_output(table, console=console, no_pager=args.no_pager)
657
+ if args.short:
658
+ for did, dummy in table_data:
659
+ print(did)
667
660
  else:
668
- if args.short:
669
- for did, dummy in table_data:
670
- print(did)
661
+ if cli_config == 'rich':
662
+ table = generate_table(table_data, headers=['SCOPE:NAME', '[DID TYPE]'], col_alignments=['left', 'left'])
663
+ spinner.stop()
664
+ print_output(table, console=console, no_pager=args.no_pager)
671
665
  else:
672
666
  print(tabulate(table_data, tablefmt=tablefmt, headers=['SCOPE:NAME', '[DID TYPE]']))
667
+
673
668
  return SUCCESS
674
669
 
675
670
 
@@ -1011,6 +1006,8 @@ def download(args, client, logger, console, spinner):
1011
1006
  items = []
1012
1007
  if args.dids:
1013
1008
  for did in args.dids:
1009
+ if args.scope:
1010
+ did = f"{args.scope}:{did}"
1014
1011
  item = {'did': did}
1015
1012
  item.update(item_defaults)
1016
1013
  items.append(item)
@@ -1043,9 +1040,15 @@ def download(args, client, logger, console, spinner):
1043
1040
  item_defaults['did'] = did_str
1044
1041
  if args.rses is None:
1045
1042
  logger.warning("No RSE was given, selecting one.")
1043
+ if not args.scope:
1044
+ scope = did_str.split(':')[0]
1045
+ did = did_str.split(':')[-1]
1046
+ else:
1047
+ scope = args.scope
1048
+ did = did_str.split(':')[-1]
1046
1049
 
1047
1050
  replicas = client.list_replicas(
1048
- [{"scope": did_str.split(':')[0], "name": did_str.split(':')[-1]}],
1051
+ [{"scope": scope, "name": did}],
1049
1052
  schemes=args.protocol,
1050
1053
  ignore_availability=False,
1051
1054
  client_location=detect_client_location(),
@@ -2473,7 +2476,7 @@ You can filter by key/value, e.g.::
2473
2476
  selected_parser.add_argument('--trace_taskid', '--trace-taskid', new_option_string='--trace-taskid', dest='trace_taskid', action=StoreAndDeprecateWarningAction, default=os.environ.get('RUCIO_TRACE_TASKID', None), help=argparse.SUPPRESS)
2474
2477
  selected_parser.add_argument('--trace_usrdn', '--trace-usrdn', new_option_string='--trace-usrdn', dest='trace_usrdn', action=StoreAndDeprecateWarningAction, default=os.environ.get('RUCIO_TRACE_USRDN', None), help=argparse.SUPPRESS)
2475
2478
  selected_parser.add_argument('--filter', dest='filter', action='store', help='Filter files by key-value pairs like guid=2e2232aafac8324db452070304f8d745.')
2476
- selected_parser.add_argument('--scope', dest='scope', action='store', help='Scope if you are using the filter option and no full DID.')
2479
+ selected_parser.add_argument('--scope', dest='scope', action='store', help='Scope to use as a filter or to use with DID names.')
2477
2480
  selected_parser.add_argument('--metalink', dest='metalink_file', action='store', help='Path to a metalink file.')
2478
2481
  selected_parser.add_argument('--deactivate-file-download-exceptions', dest='deactivate_file_download_exceptions', action='store_true', help='Does not raise NoFilesDownloaded, NotAllFilesDownloaded or incorrect number of output queue files Exception.') # NOQA: E501
2479
2482
  selected_parser.add_argument('--replica-selection', dest='sort', action='store', help='Select the best replica using a replica sorting algorithm provided by replica sorter (e.g., random, geoip).')
rucio/cli/command.py CHANGED
@@ -13,6 +13,7 @@
13
13
  # limitations under the License.
14
14
  import importlib
15
15
  import signal
16
+ import sys
16
17
  import time
17
18
 
18
19
  import click
@@ -61,6 +62,16 @@ class LazyGroup(click.Group):
61
62
  raise ValueError(f"Lazy loading of {import_path} failed by returning " "a non-command object")
62
63
  return cmd_object
63
64
 
65
+ @exception_handler
66
+ def _invoke_with_handler(self, ctx: click.Context):
67
+ return super().invoke(ctx)
68
+
69
+ def invoke(self, ctx: click.Context):
70
+ result = self._invoke_with_handler(ctx)
71
+ if result not in (None, 0):
72
+ sys.exit(1 if result != 2 else 2)
73
+ return result
74
+
64
75
 
65
76
  @click.group(
66
77
  cls=LazyGroup,
@@ -87,7 +98,7 @@ class LazyGroup(click.Group):
87
98
  @click.option("--ca-certificate", help="CA certificate to verify peer against (SSL)")
88
99
  @click.option("--certificate", help="Client certificate file")
89
100
  @click.option("--client-key", help="Client key for x509 Authentication")
90
- @click.option("--config", help="The Rucio configuration file to use")
101
+ @click.option("--config", help="The Rucio configuration file to use", envvar="RUCIO_CONFIG")
91
102
  @click.option("-H", "--host", help="The Rucio API host")
92
103
  # oidc auth
93
104
  @click.option("--oidc-user", help="OIDC username")
@@ -146,33 +157,32 @@ class LazyGroup(click.Group):
146
157
  @click.version_option(version.version_string(), message="%(prog)s %(version)s")
147
158
  # Hidden options at the end
148
159
  @click.option("--no-pager", is_flag=True, default=False, hidden=True)
149
- @exception_handler
150
160
  @click.pass_context
151
161
  def main(
152
- ctx,
153
- config,
154
- verbose,
155
- host,
156
- auth_host,
157
- issuer,
158
- auth_strategy,
159
- timeout,
160
- user_agent,
161
- vo,
162
- no_pager,
163
- user,
164
- password,
165
- oidc_user,
166
- oidc_password,
167
- oidc_scope,
168
- oidc_audience,
169
- oidc_auto,
170
- oidc_polling,
171
- oidc_refresh_lifetime,
172
- oidc_issuer,
173
- certificate,
174
- client_key,
175
- ca_certificate,
162
+ ctx: click.Context,
163
+ config: str,
164
+ verbose: bool,
165
+ host: str,
166
+ auth_host: str,
167
+ issuer: str,
168
+ auth_strategy: str,
169
+ timeout: float,
170
+ user_agent: str,
171
+ vo: str,
172
+ no_pager: bool,
173
+ user: str,
174
+ password: str,
175
+ oidc_user: str,
176
+ oidc_password: str,
177
+ oidc_scope: str,
178
+ oidc_audience: str,
179
+ oidc_auto: str,
180
+ oidc_polling: str,
181
+ oidc_refresh_lifetime: str,
182
+ oidc_issuer: str,
183
+ certificate: str,
184
+ client_key: str,
185
+ ca_certificate: str,
176
186
  ):
177
187
  ctx.ensure_object(Arguments)
178
188
  ctx.obj.start_time = time.time()
rucio/cli/config.py CHANGED
@@ -27,18 +27,17 @@ def config():
27
27
  @click.option("-s", "--section", help="Filter by sections")
28
28
  @click.option("-k", "--key", help="Show key's value, section required.")
29
29
  @click.pass_context
30
- def list_(ctx, section, key):
30
+ def list_(ctx: click.Context, section: str, key: str):
31
31
  """List the sections or content of sections in the rucio.cfg"""
32
32
  get_config(Arguments({"no_pager": ctx.obj.no_pager, "section": section, "key": key}), ctx.obj.client, ctx.obj.logger, ctx.obj.console, ctx.obj.spinner)
33
33
 
34
34
 
35
- # TODO Change to only add new fields and cannot modify an existing field
36
35
  @config.command("add")
37
36
  @click.option("-s", "--section", help="Section name", required=True)
38
37
  @click.option('--key', help='Attribute key', required=True)
39
38
  @click.option('--value', help='Attribute value', required=True)
40
39
  @click.pass_context
41
- def add_(ctx, section, key, value):
40
+ def add_(ctx: click.Context, section: str, key: str, value: str):
42
41
  """
43
42
  Add a new key/value to a section.
44
43
 
@@ -46,6 +45,12 @@ def add_(ctx, section, key, value):
46
45
  Example, Add a key to an existing section:
47
46
  $ rucio config add --section my-section --key key --value value
48
47
  """
48
+ has_option = ctx.obj.client.get_config().get(section, {}).get(key) is not None
49
+ if has_option:
50
+ msg = f"Config already has field {section}: {key}, please use \n\
51
+ rucio config update --section {section} --key {key} --value {value}"
52
+ raise ValueError(msg)
53
+
49
54
  args = Arguments({"no_pager": ctx.obj.no_pager, "section": section, "option": key, "value": value})
50
55
  set_config_option(args, ctx.obj.client, ctx.obj.logger, ctx.obj.console, ctx.obj.spinner)
51
56
 
@@ -54,7 +59,7 @@ def add_(ctx, section, key, value):
54
59
  @click.option("-s", "--section", help="Section", required=True)
55
60
  @click.option("-k", "--key", help="Key in section", required=True)
56
61
  @click.pass_context
57
- def remove(ctx, section, key):
62
+ def remove(ctx: click.Context, section: str, key: str):
58
63
  """Remove the section.key from the config."""
59
64
  args = Arguments({"no_pager": ctx.obj.no_pager, "section": section, "option": key})
60
65
  delete_config_option(args, ctx.obj.client, ctx.obj.logger, ctx.obj.console, ctx.obj.spinner)
@@ -66,7 +71,17 @@ def show(ctx):
66
71
  """Show a single sections options"""
67
72
 
68
73
 
69
- # TODO Change this so that it only modifies existing fields
70
- def update():
74
+ @config.command("update")
75
+ @click.option("-s", "--section", required=True)
76
+ @click.option("-k", "--key", help='Attribute key', required=True)
77
+ @click.option("-v", "--value", help='Attribute value', required=True)
78
+ @click.pass_context
79
+ def update(ctx: click.Context, section: str, key: str, value: str):
71
80
  """Modify an existing command"""
72
- pass
81
+ has_option = ctx.obj.client.get_config().get(section, {}).get(key) is not None
82
+ if has_option:
83
+ ctx.obj.client.set_config_option(section, key, value)
84
+ else:
85
+ msg = f"{section} {key} not present. Please use \n\
86
+ rucio config add --section {section} --key {key} --value {value}"
87
+ raise ValueError(msg)
rucio/cli/did.py CHANGED
@@ -34,7 +34,7 @@ def did():
34
34
  are used: ";" represents the logical OR operator; "," represents the logical AND operator',
35
35
  """,
36
36
  ) # TODO Shorten this help and make supplying this easier
37
- @click.option("--short", is_flag=True, default=False, help="Dump the list of DIDs")
37
+ @click.option("--short", is_flag=True, default=False, help="Just dump the list of DIDs.")
38
38
  @click.argument("did-pattern", nargs=-1)
39
39
  @click.option("--parent", default=False, is_flag=True, help="List the parents of the DID - must use a full DID scope and name")
40
40
  @click.pass_context
rucio/cli/download.py CHANGED
@@ -52,7 +52,7 @@ from rucio.common.config import config_get_float
52
52
  @click.option("--trace-taskid", default=os.environ.get("RUCIO_TRACE_TASKID", None), hidden=True)
53
53
  @click.option("--trace-usrdn", default=os.environ.get("RUCIO_TRACE_USRDN", None), hidden=True)
54
54
  @click.option("--filter", help="Filter files by key-value pairs like guid=2e2232aafac8324db452070304f8d745.")
55
- @click.option("--scope", help="Scope if you are using the filter option and no full DID.")
55
+ @click.option("--scope", help="Scope to use as a filter or to use with DID names.")
56
56
  @click.option("--metalink", help="Path to a metalink file.")
57
57
  @click.option("--no-show-download-exceptions", default=False, is_flag=True, help="Does not raise NoFilesDownloaded, NotAllFilesDownloaded or incorrect number of output queue files Exception.") # NOQA: E501
58
58
  @click.option("--replica-selection", help="Select the best replica using a replica sorting algorithm provided by replica sorter (e.g., random, geoip).")
rucio/cli/opendata.py CHANGED
@@ -16,8 +16,11 @@ import json
16
16
  from typing import TYPE_CHECKING, Optional
17
17
 
18
18
  import click
19
+ from rich.text import Text
20
+ from tabulate import tabulate
19
21
 
20
22
  from rucio.cli.utils import JSONType
23
+ from rucio.client.richclient import CLITheme, generate_table, get_cli_config, print_output
21
24
  from rucio.common.constants import OPENDATA_DID_STATE_LITERAL_LIST
22
25
  from rucio.common.utils import extract_scope
23
26
 
@@ -26,6 +29,8 @@ if TYPE_CHECKING:
26
29
 
27
30
  from rucio.common.constants import OPENDATA_DID_STATE_LITERAL
28
31
 
32
+ cli_config = get_cli_config()
33
+
29
34
 
30
35
  def is_valid_json(s: str) -> bool:
31
36
  try:
@@ -50,15 +55,42 @@ def opendata_did() -> None:
50
55
  help="Filter on Opendata state")
51
56
  @click.option("--public", required=False, is_flag=True, default=False,
52
57
  help="Perform request against the public endpoint")
58
+ @click.option("--short", is_flag=True, default=False, help="Dump the list of Opendata DIDs")
53
59
  @click.pass_context
54
- def list_opendata_dids(ctx: "Context", state: Optional["OPENDATA_DID_STATE_LITERAL"], public: bool) -> None:
60
+ def list_opendata_dids(ctx: "Context", state: Optional["OPENDATA_DID_STATE_LITERAL"], public: bool,
61
+ short: bool) -> None:
55
62
  """
56
63
  List Opendata DIDs, optionally filtered by state and public/private access
57
64
  """
58
65
 
59
66
  client = ctx.obj.client
60
- result = client.list_opendata_dids(state=state, public=public)
61
- print(json.dumps(result, indent=4, sort_keys=True, ensure_ascii=False))
67
+ spinner = ctx.obj.spinner
68
+
69
+ dids_list = client.list_opendata_dids(state=state, public=public)
70
+
71
+ table_data = []
72
+
73
+ if cli_config == 'rich':
74
+ spinner.update(status='Fetching Opendata DIDs')
75
+ spinner.start()
76
+
77
+ for did in dids_list["dids"]:
78
+ if cli_config == 'rich':
79
+ table_data.append([f"{did['scope']}:{did['name']}",
80
+ Text(did['state'], style=CLITheme.OPENDATA_DID_STATE.get(did['state'], 'default'))])
81
+ else:
82
+ table_data.append([f"{did['scope']}:{did['name']}", did['state']])
83
+
84
+ if short:
85
+ for did, _ in table_data:
86
+ print(did)
87
+ else:
88
+ if cli_config == 'rich':
89
+ table = generate_table(table_data, headers=['SCOPE:NAME', '[STATE]'], col_alignments=['left', 'left'])
90
+ spinner.stop()
91
+ print_output(table, console=ctx.obj.console, no_pager=ctx.obj.no_pager)
92
+ else:
93
+ print(tabulate(table_data, tablefmt="psql", headers=['SCOPE:NAME', '[STATE]']))
62
94
 
63
95
 
64
96
  @opendata_did.command("add")
@@ -95,18 +127,37 @@ def remove_opendata_did(ctx: "Context", did: str) -> None:
95
127
  @click.option("--public", required=False, is_flag=True, default=False,
96
128
  help="Perform request against the public endpoint")
97
129
  @click.pass_context
98
- def get_opendata_did(ctx: "Context", did: str, include_files: bool, include_metadata: bool, public: bool) -> None:
130
+ def get_opendata_did(ctx: "Context", did: str, files: bool, meta: bool, public: bool) -> None:
99
131
  """
100
132
  Get information about an Opendata DID, optionally including files and metadata.
101
133
  """
102
134
 
103
135
  client = ctx.obj.client
136
+ spinner = ctx.obj.spinner
137
+ console = ctx.obj.console
138
+
104
139
  scope, name = extract_scope(did)
105
- result = client.get_opendata_did(scope=scope, name=name, public=public,
106
- include_files=include_files, include_metadata=include_metadata,
107
- include_doi=True)
108
- # TODO: pretty print using tables, etc
109
- print(json.dumps(result, indent=4, sort_keys=True, ensure_ascii=False))
140
+ info = client.get_opendata_did(scope=scope, name=name, public=public,
141
+ include_files=files, include_metadata=meta,
142
+ include_doi=True)
143
+
144
+ output = []
145
+ if cli_config == 'rich':
146
+ spinner.update(status='Fetching Opendata DID stats')
147
+ spinner.start()
148
+ keyword_styles = {**CLITheme.BOOLEAN, **CLITheme.OPENDATA_DID_STATE}
149
+
150
+ table_data = [(k, Text(str(v), style=keyword_styles.get(str(v), 'default'))) for (k, v) in
151
+ sorted(info.items())]
152
+ table = generate_table(table_data, row_styles=['none'], col_alignments=['left', 'left'])
153
+ output.append(table)
154
+ else:
155
+ table = [(k + ':', str(v)) for (k, v) in sorted(info.items())]
156
+ print(tabulate(table, tablefmt='plain', disable_numparse=True))
157
+
158
+ if cli_config == 'rich':
159
+ spinner.stop()
160
+ print_output(*output, console=console, no_pager=ctx.obj.no_pager)
110
161
 
111
162
 
112
163
  @opendata_did.command("update")
rucio/cli/utils.py CHANGED
@@ -57,7 +57,19 @@ def exception_handler(function):
57
57
  def new_funct(*args, **kwargs):
58
58
  try:
59
59
  return function(*args, **kwargs)
60
- except InputValidationError as error:
60
+ except click.exceptions.Exit as error:
61
+ # Exit is evoked every time click ends a program without running anything
62
+ # This error is raised when the help menu is called
63
+ logger.debug("Exited click context")
64
+ if ("-h" not in sys.argv) or ("--help" not in sys.argv):
65
+ return error.exit_code
66
+ return SUCCESS
67
+ except click.MissingParameter as error:
68
+ error.show()
69
+ msg = f"{error}. Please check the command help (-h/--help)."
70
+ logger.error(msg)
71
+ return 2 # Always return an error 2 for an incorrect specification
72
+ except (InputValidationError, click.exceptions.UsageError) as error:
61
73
  logger.error(error)
62
74
  logger.debug("This means that one you provided an invalid combination of parameters, or incorrect types. Please check the command help (-h/--help).")
63
75
  return FAILURE
@@ -147,3 +147,26 @@ class ConfigClient(BaseClient):
147
147
  else:
148
148
  exc_cls, exc_msg = self._get_exception(headers=r.headers, status_code=r.status_code, data=r.content)
149
149
  raise exc_cls(exc_msg)
150
+
151
+ def delete_config_section(self, section: str):
152
+ """
153
+ Delete a whole section from the config
154
+
155
+ Parameters
156
+ ----------
157
+ section :
158
+ The name of the section.
159
+
160
+ Returns
161
+ -------
162
+ True if option was removed successfully.
163
+ """
164
+ path = '/'.join([self.CONFIG_BASEURL, section])
165
+ url = build_url(choice(self.list_hosts), path=path)
166
+ r = self._send_request(url, type_='DEL')
167
+
168
+ if r.status_code == codes.ok:
169
+ return True
170
+ else:
171
+ exc_cls, exc_msg = self._get_exception(headers=r.headers, status_code=r.status_code, data=r.content)
172
+ raise exc_cls(exc_msg)
@@ -131,6 +131,12 @@ class CLITheme:
131
131
  'SERVICE': 'yellow'
132
132
  }
133
133
 
134
+ OPENDATA_DID_STATE = {
135
+ 'PUBLIC': 'bold green',
136
+ 'DRAFT': 'bold default',
137
+ 'SUSPENDED': 'bold red',
138
+ }
139
+
134
140
 
135
141
  def setup_rich_logger(
136
142
  module_name: Optional[str] = None,
rucio/common/constants.py CHANGED
@@ -29,6 +29,8 @@ RESERVED_KEYS = ['scope', 'name', 'account', 'did_type', 'is_open', 'monotonic',
29
29
 
30
30
  DEFAULT_VO = 'def'
31
31
 
32
+ DEFAULT_ACTIVITY = 'User Subscriptions'
33
+
32
34
  KEY_TYPES = ['ALL', 'COLLECTION', 'FILE', 'DERIVED']
33
35
  # all(container, dataset, file), collection(dataset or container), file, derived(compute from file for collection)
34
36
 
@@ -219,3 +221,6 @@ SUPPORTED_SIGN_URL_SERVICES = list(get_args(SUPPORTED_SIGN_URL_SERVICES_LITERAL)
219
221
 
220
222
  OPENDATA_DID_STATE_LITERAL = Literal['draft', 'public', 'suspended']
221
223
  OPENDATA_DID_STATE_LITERAL_LIST = list(get_args(OPENDATA_DID_STATE_LITERAL))
224
+
225
+ POLICY_ALGORITHM_TYPES_LITERAL = Literal['non_deterministic_pfn', 'scope', 'lfn2pfn', 'pfn2lfn', 'fts3_tape_metadata_plugins', 'fts3_plugins_init', 'auto_approve']
226
+ POLICY_ALGORITHM_TYPES = list(get_args(POLICY_ALGORITHM_TYPES_LITERAL))
rucio/common/exception.py CHANGED
@@ -1261,3 +1261,13 @@ 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
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,7 +75,7 @@ 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
80
  _default_algorithms: dict[str, 'Callable[..., Any]'] = {}
81
81
 
@@ -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:
@@ -116,38 +119,51 @@ class PolicyPackageAlgorithms:
116
119
  return default_algorithm
117
120
 
118
121
  @classmethod
119
- def _get_one_algorithm(cls: type[PolicyPackageAlgorithmsT], algorithm_type: str, name: str) -> 'Callable[..., Any]':
122
+ def _get_one_algorithm(cls: type[PolicyPackageAlgorithmsT], algorithm_type: POLICY_ALGORITHM_TYPES_LITERAL, name: str) -> 'Callable[..., Any]':
120
123
  """
121
124
  Get the algorithm from the dictionary of algorithms
122
125
  """
126
+ if algorithm_type not in POLICY_ALGORITHM_TYPES:
127
+ raise InvalidPolicyPackageAlgorithmType(algorithm_type)
123
128
  return cls._ALGORITHMS[algorithm_type][name]
124
129
 
125
130
  @classmethod
126
- def _get_algorithms(cls: type[PolicyPackageAlgorithmsT], algorithm_type: str) -> dict[str, 'Callable[..., Any]']:
131
+ def _get_algorithms(cls: type[PolicyPackageAlgorithmsT], algorithm_type: POLICY_ALGORITHM_TYPES_LITERAL) -> dict[str, 'Callable[..., Any]']:
127
132
  """
128
133
  Get the dictionary of algorithms for a given type
129
134
  """
135
+ if algorithm_type not in POLICY_ALGORITHM_TYPES:
136
+ raise InvalidPolicyPackageAlgorithmType(algorithm_type)
130
137
  return cls._ALGORITHMS[algorithm_type]
131
138
 
132
139
  @classmethod
133
140
  def _register(
134
141
  cls: type[PolicyPackageAlgorithmsT],
135
- algorithm_type: str, algorithm_dict: dict[str, 'Callable[..., Any]']) -> None:
142
+ algorithm_type: POLICY_ALGORITHM_TYPES_LITERAL,
143
+ algorithm_dict: dict[str, 'Callable[..., Any]']) -> None:
136
144
  """
137
145
  Provided a dictionary of callable function,
138
146
  and the associated algorithm type,
139
147
  register it as one of the valid algorithms.
140
148
  """
149
+ if algorithm_type not in POLICY_ALGORITHM_TYPES:
150
+ raise InvalidPolicyPackageAlgorithmType(algorithm_type)
151
+
141
152
  if algorithm_type in cls._ALGORITHMS:
142
153
  cls._ALGORITHMS[algorithm_type].update(algorithm_dict)
143
154
  else:
144
155
  cls._ALGORITHMS[algorithm_type] = algorithm_dict
145
156
 
146
157
  @classmethod
147
- def _supports(cls: type[PolicyPackageAlgorithmsT], algorithm_type: str, name: str) -> bool:
158
+ def _supports(
159
+ cls: type[PolicyPackageAlgorithmsT],
160
+ algorithm_type: POLICY_ALGORITHM_TYPES_LITERAL,
161
+ name: str) -> bool:
148
162
  """
149
163
  Check if a algorithm is supported by the plugin
150
164
  """
165
+ if algorithm_type not in POLICY_ALGORITHM_TYPES:
166
+ raise InvalidPolicyPackageAlgorithmType(algorithm_type)
151
167
  return name in cls._ALGORITHMS.get(algorithm_type, {})
152
168
 
153
169
  @classmethod
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
  """
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.1.0',
7
+ 'version': '38.3.0',
8
8
  'branch_nick': 'release-38-LTS',
9
- 'revision_id': 'f63f25c84c254eac1701a9640e3cb658a7bbdd8e',
10
- 'revno': 13947
9
+ 'revision_id': '5eebc4e67a544dcb2d689bd45260cb73fb10066a',
10
+ 'revno': 14003
11
11
  }
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: rucio-clients
3
- Version: 38.1.0
3
+ Version: 38.3.0
4
4
  Summary: Rucio Client Lite Package
5
5
  Home-page: https://rucio.cern.ch/
6
6
  Author: Rucio
@@ -1,31 +1,31 @@
1
1
  rucio/__init__.py,sha256=Y7cPPlHVQPFyN8bSPFC0W3WViEdONr5g_qwBub5rufE,660
2
2
  rucio/alembicrevision.py,sha256=9tnjQLFkTpUEcZqcw-ojWpt4Wbg-5OtMJ0CfjPc0wX8,690
3
- rucio/vcsversion.py,sha256=yMKoNaABtSAIdUEDF8GKVaGThokyhemXGEjqfWPCHaI,248
3
+ rucio/vcsversion.py,sha256=mQsxiR0m-shMbCPg19FH-Ol-CaR3LE4pKaB4sgr3qZI,248
4
4
  rucio/version.py,sha256=IwsNb1QQk0D092QQbR2K9wBPF2Akny1RGs-ZZziUohE,1519
5
5
  rucio/cli/__init__.py,sha256=GIkHmxgE3xdvWSf-7ZnvVaJmbs7NokaSjbFzsrXOG9o,662
6
6
  rucio/cli/account.py,sha256=2Fe-iEaTfLxqlW5mDJsJPwD-Etm4VqaMowTSA67hZIo,9458
7
- rucio/cli/command.py,sha256=dr9bhugorgc2kX-JsdrRsq9Yfh92sYwaALB7CrX6PNI,10835
8
- rucio/cli/config.py,sha256=L7vhzAyUVKZBWKKDvrLl7zCei8O6kDyzX_x_-p-vk9M,2706
9
- rucio/cli/did.py,sha256=IDrFFAfMhnVhGJMBm9QySO1avnbRcx_VTSaDMi41am8,9020
10
- rucio/cli/download.py,sha256=nltAf8nm8P6nrfIu0CUveY4YM6oL5nSR3w6yS4qBbw0,6248
7
+ rucio/cli/command.py,sha256=7jqBakwQOW7gORCLf63wrGOfzsQKdZbsc1TWUMmDH5s,11294
8
+ rucio/cli/config.py,sha256=chcCxby1ET8YvoMx9IUIty0wVaZghISwEO_Ahe22ReA,3558
9
+ rucio/cli/did.py,sha256=OfVO2Egjh-7woiw7xxDKCc_SwzVi1dZN66mS-LZ1Mxc,9026
10
+ rucio/cli/download.py,sha256=kIB_n45egqBp4inVFmUXdofFAmlPkdAgxLTpPlG4WLM,6241
11
11
  rucio/cli/lifetime_exception.py,sha256=joi9HdaiYP_g3115IR_ImX7oFlEg1xbSaK-IzmoIVcY,1498
12
- rucio/cli/opendata.py,sha256=wnfzcVBpCmkA9WQFqNsqtMuT-2QRl1LHBjLBgm_c4AU,4741
12
+ rucio/cli/opendata.py,sha256=gAt6kyTXQUaQ6cv0XcB_9jmkYKavr3s3HCce84ywK7g,6580
13
13
  rucio/cli/replica.py,sha256=ZeknO6aKOambwe7lJGWcI_YAflz1-oMYBSZTYvMVIe0,8657
14
14
  rucio/cli/rse.py,sha256=J2IjCGUzvv9U0swFcU0ykZ1pYweHqTlXwmpGfSI-VgE,11490
15
15
  rucio/cli/rule.py,sha256=H_Yw8hx_DiqX_twEtgEY0x2AkftsRyLboMaXv_Zc6Ac,9090
16
16
  rucio/cli/scope.py,sha256=jzP9SK4IDKUrjWzE2Gs34I_gQpXnqmsBd6LbLuJI3QM,1698
17
17
  rucio/cli/subscription.py,sha256=kx1ox3OkWqdwfdflhdsv00XSYI6nnUZCp97YBZa4Aw4,4269
18
18
  rucio/cli/upload.py,sha256=29gJGfb7jsiA6-UwPCSg1kGZu-OJ-bdxUZr27S2mJEM,3237
19
- rucio/cli/utils.py,sha256=AEmdlvvebyFqBiM5z2HWrR1_kWmcDR1yLq3694rFqMs,10410
19
+ rucio/cli/utils.py,sha256=3WWzfXzircnK1FLEu5KzZAQZ_E9K9WGd0_AlNuQUmY0,11078
20
20
  rucio/cli/bin_legacy/__init__.py,sha256=Q91iipvMQ0VzNMuYcYQfDujZ0vL-hrB4Kmd0YrgtHGQ,618
21
- rucio/cli/bin_legacy/rucio.py,sha256=Z53nUKd5orN9sFPHXcC6XC2diwMo1Dx5AzJhT3ha7Dw,140892
21
+ rucio/cli/bin_legacy/rucio.py,sha256=EprZpF5A7teDGH6aXIevMMM3vbs4mKE1LaqgcpqsCmg,140816
22
22
  rucio/cli/bin_legacy/rucio_admin.py,sha256=pRpJhEGMr3-xzw3EsGeVayEiu8NI_UxEI2wSIbeulzI,141046
23
23
  rucio/client/__init__.py,sha256=0-jkSlrJf-eqbN4swA5a07eaWd6_6JXPQPLXMs4A3iI,660
24
24
  rucio/client/accountclient.py,sha256=kScbVL9rR8pyZRmETOyz_gwffc7biaPriMgDnCLxA_0,18864
25
25
  rucio/client/accountlimitclient.py,sha256=SWYdRMAMibWLZOhFb3HBI9vLvmp2uYjEhtM2ej1iGzQ,6905
26
26
  rucio/client/baseclient.py,sha256=gXh1RfzpQfvsFFm74F82jareOD8k9IlUOVHwwqsFyxI,50798
27
27
  rucio/client/client.py,sha256=npg0pFWzqnmnObjFO7QDdSkH1O0jrY-HglXEVfDrWNY,4493
28
- rucio/client/configclient.py,sha256=pbp_yEem7g8JTVVOMY-ehMyLh6T3Rxf1AxCluLE-JE8,4800
28
+ rucio/client/configclient.py,sha256=l-0kjkrAQXhzV78CPtqduzp7lgonnAl65wmtUflf9Dc,5493
29
29
  rucio/client/credentialclient.py,sha256=q4i_t-dIiojRmiY70iuJsAgnPqaZVwkJLbThxoc8_9k,2214
30
30
  rucio/client/didclient.py,sha256=66ODAQnrtvwwSo0Cu9FpCRo_36N28tHtUjbrz92hu_c,34619
31
31
  rucio/client/diracclient.py,sha256=MQCY0UxgXXlosL9-dKB469wkZ9XLgPs4dPsuEFfk4Rc,4465
@@ -39,7 +39,7 @@ rucio/client/opendataclient.py,sha256=x0ESKis92lwX_lrB0nKukJy0qcvT7cZ5jWccoYxPVG
39
39
  rucio/client/pingclient.py,sha256=WU7jwbHoISky-ULw9h1_VqS0opRAM3j3RFnpWC7l48Y,2392
40
40
  rucio/client/replicaclient.py,sha256=Gi7vg87g4hhrW_UA9MB1FewGh67FW2wAnSWj4H9oMQk,20591
41
41
  rucio/client/requestclient.py,sha256=Vr1lAmAbfX2iGzj_aKRmRFPBpMXbVxIw_0LVAZ5Xtq0,8574
42
- rucio/client/richclient.py,sha256=kP6cHQsvCtKEl1c2fycqpDjfLrMAzaMxuZA_kWddm08,10111
42
+ rucio/client/richclient.py,sha256=ArTHvnx0eJxRysfpBxnx0zaDI8ixgnfA_8vAegZQC2Y,10243
43
43
  rucio/client/rseclient.py,sha256=4R-WcCROjPRfWjcWuFM7itf4vmRRk0qvOa-itnTlZ8w,31858
44
44
  rucio/client/ruleclient.py,sha256=tlYRFMKVwjCuzketqg2F4XoGydbhNAjkOnm1BGUZEVg,13639
45
45
  rucio/client/scopeclient.py,sha256=-rXLdXScKeXavOaw9EwBHYo4SXwfcuqsOG6yGMIBWyM,3485
@@ -52,26 +52,26 @@ rucio/common/cache.py,sha256=oa1WCodXpsmHzM-LJoYL7wQHw7VMU5I0g3TBg-VzEfo,3389
52
52
  rucio/common/checksum.py,sha256=nSqjY8TdDGohpAzcEM2fjv4FPdOKmKr_3U27HalKkoY,5254
53
53
  rucio/common/client.py,sha256=vHJ1gnHRBiXC2ZPfSgYPlsdJi0DbvwWDdHHMEOVgBvU,3129
54
54
  rucio/common/config.py,sha256=69AhxgP9SXXrlaTqlOCQiaiqGqHLhSfhRFasroGfDdc,24402
55
- rucio/common/constants.py,sha256=5MhQHY24NODmvp71MqHS8BzSird2K1ICmC94clD-JlY,7751
55
+ rucio/common/constants.py,sha256=WhpUEh_L2AF35jL1yDO1yOPgiAWVgJxmYvD_F5Fwh6A,8029
56
56
  rucio/common/constraints.py,sha256=MrdiAwKyoaZGfspUWX_53XS2790nXMSMg1JYmTO_ciQ,726
57
57
  rucio/common/didtype.py,sha256=nXoyK740yrwsiGX9e9vOc8UX0PXRvKry67C0Sd8SpmM,8010
58
- rucio/common/exception.py,sha256=q_vSqaJ_SdPorkyo247-l9HqBDpZSGZ1pf2-ZR4uaUY,36188
58
+ rucio/common/exception.py,sha256=I90THVS-iNKCPl5zuBFGzsGuaQ4D6fx-n3ZevSl8z4U,36546
59
59
  rucio/common/extra.py,sha256=IE01275vTJobyNiYbptU9NmsUl2Ga_92FSoOODV8Qfk,1054
60
60
  rucio/common/logging.py,sha256=_G1QDFpPLghz2VXOjdhC7j-TtZBxmPJsyJtztW7mf68,15874
61
61
  rucio/common/pcache.py,sha256=V2OnO4h4v5yaxWT9T9DMJpm-2rLalBzzaqlUWUq5x4c,47097
62
- rucio/common/plugins.py,sha256=vojZpsEu8jzOdHyrYykJRQnShD_Nq9ODj6EFX3i1OAU,8735
62
+ rucio/common/plugins.py,sha256=A2koy6tXBPxE3lF89lBpbtg-d5Vn4bgg7osHt3Qd-Io,9664
63
63
  rucio/common/policy.py,sha256=4i7SHyUpWxagS9nI72nBpWyfvYfz_aH6GH4lFMtDARo,3546
64
64
  rucio/common/stomp_utils.py,sha256=3GTiRTJ0roe5OX_wgkVwOJYAIhGgYbhiROHc2M8LQT8,5414
65
65
  rucio/common/stopwatch.py,sha256=_9zxoLjr8A0wUDJsljK4vZNDCI-dIOgpcxXiCNVJcHU,1641
66
66
  rucio/common/test_rucio_server.py,sha256=2teFpN5Pthp-zQt1_aErOURDTgOhFP9GKdEr1NMmc4o,5085
67
67
  rucio/common/types.py,sha256=joi_upIQsi3U3HMmyfVOVQem3404kGI6OixyFzrqavk,11941
68
- rucio/common/utils.py,sha256=FauL76qhhSm2IZxKrZT7cSnURPCytWAZP5awHdTAXNY,67298
68
+ rucio/common/utils.py,sha256=GUm8XmWhooRqZ_OpV_Ex1rqI70G8gxwAzJhQLKW27eo,67394
69
69
  rucio/common/schema/__init__.py,sha256=gC39BlHz45lX6-OTtIL5U8RqVJpZGk0RfqCwSKRseYU,7284
70
70
  rucio/common/schema/generic.py,sha256=NmmQJ0Z8dHbL7xnbFL7rvXFK29wA8ZGtkwwwMAxzVC0,15887
71
71
  rucio/common/schema/generic_multi_vo.py,sha256=UK5DOO-dO7pY6O44t9SJqzeS3xUye_stu_f-EVD-r0s,15107
72
72
  rucio/rse/__init__.py,sha256=0Y-ZU-K8E-a_sc6q-rTjstREC25EmxPmtIWig5gFNU4,3361
73
73
  rucio/rse/rsemanager.py,sha256=Qi8dUD3z0wUCr7O-GeKHKcjt9ur7Jo9d1H3lpm08KcI,41127
74
- rucio/rse/translation.py,sha256=3UwhOYoYs6NTm4JvK47VpfkGDdxajbhlSfnJSFQ-llU,9609
74
+ rucio/rse/translation.py,sha256=Hzv73mDFkne1Iu19ID6K1QMo3i_sBt_7gvJ6CeR5_yE,9705
75
75
  rucio/rse/protocols/__init__.py,sha256=Q91iipvMQ0VzNMuYcYQfDujZ0vL-hrB4Kmd0YrgtHGQ,618
76
76
  rucio/rse/protocols/bittorrent.py,sha256=ZBm_n7vU_NGXQaaZJWKQ-KUp6nYOMdbLqTvGuKN_LKk,7475
77
77
  rucio/rse/protocols/cache.py,sha256=vJxwPa32TWMQSmETKJ_9ZcXmB4GS47yQGkB-d7IJAdc,4306
@@ -90,16 +90,16 @@ rucio/rse/protocols/ssh.py,sha256=pHPAQx2bPNkMrtqbCqDfq7OXoy7XphQ-i2Stzdvnf1k,17
90
90
  rucio/rse/protocols/storm.py,sha256=Z4fzklxG-x70A0Lugg1jE1RicwCSeF27iz0MXO-4to0,7864
91
91
  rucio/rse/protocols/webdav.py,sha256=8UzmBA8vF_-exoUvpIHRQLfhvAvExQsfu-P4WbXGOXI,24810
92
92
  rucio/rse/protocols/xrootd.py,sha256=oJHueVR44dcW5nkg8jCbr9PetV9UIti3C0tka_m7yIk,12604
93
- rucio_clients-38.1.0.data/data/requirements.client.txt,sha256=ob8DW6vHurtEcXZ2j_u67WO_M2Mf7dzJFROKqIQINTo,1790
94
- rucio_clients-38.1.0.data/data/etc/rse-accounts.cfg.template,sha256=IfDnXVxBPUrMnTMbJnd3P7eYHgY1C4Kfz7xKskJs-FI,543
95
- rucio_clients-38.1.0.data/data/etc/rucio.cfg.atlas.client.template,sha256=aHP1oX9m5yA8xVTTT2Hz6AyOYu92-Bcd5LF0i3AZRQw,1350
96
- rucio_clients-38.1.0.data/data/etc/rucio.cfg.template,sha256=hKnGDIm7oIFWBhj6vr5L6bE4TDRHT-7eZh9IsqOHbpo,8023
97
- rucio_clients-38.1.0.data/data/rucio_client/merge_rucio_configs.py,sha256=u62K1EcCGydM5nZA30zhlqWo4EX5N87b_MDkx5YfzVI,6163
98
- rucio_clients-38.1.0.data/scripts/rucio,sha256=f8f5X6O9W2JfUqWiSdsuDROekGt28p9CBvFZropZ-C0,5260
99
- rucio_clients-38.1.0.data/scripts/rucio-admin,sha256=AhPO6-fAPviHObhB_Yi7GJXKfjpaH6m0RqxwctBeFlE,4229
100
- rucio_clients-38.1.0.dist-info/licenses/AUTHORS.rst,sha256=FQ5q2_bY3dYKDmEw-8YD-SgPJ4fgnM1XI5wRF5ksQPg,4771
101
- rucio_clients-38.1.0.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
102
- rucio_clients-38.1.0.dist-info/METADATA,sha256=33Fl0bZ2J05hdH-p_7R8kVu1LJgRQdrfi4IE1q1dmtM,1740
103
- rucio_clients-38.1.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
104
- rucio_clients-38.1.0.dist-info/top_level.txt,sha256=lJM8plwW0ePPICkwFnpYzfdqHnSv6JZr1OD4JEysPgM,6
105
- rucio_clients-38.1.0.dist-info/RECORD,,
93
+ rucio_clients-38.3.0.data/data/requirements.client.txt,sha256=ob8DW6vHurtEcXZ2j_u67WO_M2Mf7dzJFROKqIQINTo,1790
94
+ rucio_clients-38.3.0.data/data/etc/rse-accounts.cfg.template,sha256=IfDnXVxBPUrMnTMbJnd3P7eYHgY1C4Kfz7xKskJs-FI,543
95
+ rucio_clients-38.3.0.data/data/etc/rucio.cfg.atlas.client.template,sha256=aHP1oX9m5yA8xVTTT2Hz6AyOYu92-Bcd5LF0i3AZRQw,1350
96
+ rucio_clients-38.3.0.data/data/etc/rucio.cfg.template,sha256=hKnGDIm7oIFWBhj6vr5L6bE4TDRHT-7eZh9IsqOHbpo,8023
97
+ rucio_clients-38.3.0.data/data/rucio_client/merge_rucio_configs.py,sha256=u62K1EcCGydM5nZA30zhlqWo4EX5N87b_MDkx5YfzVI,6163
98
+ rucio_clients-38.3.0.data/scripts/rucio,sha256=f8f5X6O9W2JfUqWiSdsuDROekGt28p9CBvFZropZ-C0,5260
99
+ rucio_clients-38.3.0.data/scripts/rucio-admin,sha256=AhPO6-fAPviHObhB_Yi7GJXKfjpaH6m0RqxwctBeFlE,4229
100
+ rucio_clients-38.3.0.dist-info/licenses/AUTHORS.rst,sha256=FQ5q2_bY3dYKDmEw-8YD-SgPJ4fgnM1XI5wRF5ksQPg,4771
101
+ rucio_clients-38.3.0.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
102
+ rucio_clients-38.3.0.dist-info/METADATA,sha256=uXRJ4c_TAzifO6vFNdXWtehgoSHuRXpT9kl_W1ZJUoI,1740
103
+ rucio_clients-38.3.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
104
+ rucio_clients-38.3.0.dist-info/top_level.txt,sha256=lJM8plwW0ePPICkwFnpYzfdqHnSv6JZr1OD4JEysPgM,6
105
+ rucio_clients-38.3.0.dist-info/RECORD,,