rucio-clients 37.7.0__tar.gz → 38.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of rucio-clients might be problematic. Click here for more details.
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/AUTHORS.rst +1 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/PKG-INFO +2 -2
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/bin/rucio +2 -1
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/etc/rucio.cfg.template +2 -2
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/lib/rucio/alembicrevision.py +1 -1
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/lib/rucio/cli/bin_legacy/rucio.py +51 -107
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/lib/rucio/cli/bin_legacy/rucio_admin.py +26 -26
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/lib/rucio/cli/command.py +1 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/lib/rucio/cli/did.py +2 -2
- rucio_clients-38.0.0/lib/rucio/cli/opendata.py +132 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/lib/rucio/cli/replica.py +15 -5
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/lib/rucio/cli/rule.py +7 -2
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/lib/rucio/cli/scope.py +3 -2
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/lib/rucio/cli/utils.py +28 -4
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/lib/rucio/client/baseclient.py +9 -1
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/lib/rucio/client/client.py +2 -0
- rucio_clients-38.0.0/lib/rucio/client/diracclient.py +124 -0
- rucio_clients-38.0.0/lib/rucio/client/opendataclient.py +249 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/lib/rucio/client/subscriptionclient.py +30 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/lib/rucio/client/uploadclient.py +10 -13
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/lib/rucio/common/constants.py +4 -1
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/lib/rucio/common/exception.py +55 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/lib/rucio/common/plugins.py +45 -8
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/lib/rucio/common/schema/generic.py +5 -3
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/lib/rucio/common/schema/generic_multi_vo.py +4 -2
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/lib/rucio/common/types.py +8 -7
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/lib/rucio/common/utils.py +176 -11
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/lib/rucio/rse/protocols/protocol.py +9 -5
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/lib/rucio/rse/translation.py +17 -6
- rucio_clients-38.0.0/lib/rucio/vcsversion.py +11 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/lib/rucio_clients.egg-info/SOURCES.txt +3 -1
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/pyproject.toml +5 -6
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/requirements/requirements.client.txt +1 -1
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/setuputil.py +42 -30
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/tests/test_abacus_account.py +1 -2
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/tests/test_abacus_collection_replica.py +5 -6
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/tests/test_abacus_rse.py +1 -2
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/tests/test_bin_rucio.py +31 -4
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/tests/test_cli_client_structure.py +48 -6
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/tests/test_conveyor.py +2 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/tests/test_dataset_replicas.py +20 -5
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/tests/test_hermes.py +33 -16
- rucio_clients-38.0.0/tests/test_opendata.py +573 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/tests/test_policy_package.py +42 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/tests/test_reaper.py +1 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/tests/test_replica.py +3 -4
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/tests/test_rse.py +1 -2
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/tests/test_rule.py +3 -4
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/tests/test_subscription.py +44 -16
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/tests/test_transfer_plugins.py +2 -2
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/tests/test_upload.py +93 -2
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/tests/test_utils.py +82 -6
- rucio_clients-37.7.0/lib/rucio/client/diracclient.py +0 -63
- rucio_clients-37.7.0/lib/rucio/client/fileclient.py +0 -57
- rucio_clients-37.7.0/lib/rucio/vcsversion.py +0 -11
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/ChangeLog +0 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/LICENSE +0 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/MANIFEST.in +0 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/README.md +0 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/bin/rucio-admin +0 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/etc/rse-accounts.cfg.template +0 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/etc/rucio.cfg.atlas.client.template +0 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/lib/rucio/__init__.py +0 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/lib/rucio/cli/__init__.py +0 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/lib/rucio/cli/account.py +0 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/lib/rucio/cli/bin_legacy/__init__.py +0 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/lib/rucio/cli/config.py +0 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/lib/rucio/cli/download.py +0 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/lib/rucio/cli/lifetime_exception.py +0 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/lib/rucio/cli/rse.py +0 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/lib/rucio/cli/subscription.py +0 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/lib/rucio/cli/upload.py +0 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/lib/rucio/client/__init__.py +0 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/lib/rucio/client/accountclient.py +0 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/lib/rucio/client/accountlimitclient.py +0 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/lib/rucio/client/configclient.py +0 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/lib/rucio/client/credentialclient.py +0 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/lib/rucio/client/didclient.py +0 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/lib/rucio/client/downloadclient.py +0 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/lib/rucio/client/exportclient.py +0 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/lib/rucio/client/importclient.py +0 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/lib/rucio/client/lifetimeclient.py +0 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/lib/rucio/client/lockclient.py +0 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/lib/rucio/client/metaconventionsclient.py +0 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/lib/rucio/client/pingclient.py +0 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/lib/rucio/client/replicaclient.py +0 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/lib/rucio/client/requestclient.py +0 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/lib/rucio/client/richclient.py +0 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/lib/rucio/client/rseclient.py +0 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/lib/rucio/client/ruleclient.py +0 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/lib/rucio/client/scopeclient.py +0 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/lib/rucio/client/touchclient.py +0 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/lib/rucio/common/__init__.py +0 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/lib/rucio/common/bittorrent.py +0 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/lib/rucio/common/cache.py +0 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/lib/rucio/common/checksum.py +0 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/lib/rucio/common/client.py +0 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/lib/rucio/common/config.py +0 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/lib/rucio/common/constraints.py +0 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/lib/rucio/common/didtype.py +0 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/lib/rucio/common/extra.py +0 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/lib/rucio/common/logging.py +0 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/lib/rucio/common/pcache.py +0 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/lib/rucio/common/policy.py +0 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/lib/rucio/common/schema/__init__.py +0 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/lib/rucio/common/stomp_utils.py +0 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/lib/rucio/common/stopwatch.py +0 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/lib/rucio/common/test_rucio_server.py +0 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/lib/rucio/rse/__init__.py +0 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/lib/rucio/rse/protocols/__init__.py +0 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/lib/rucio/rse/protocols/bittorrent.py +0 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/lib/rucio/rse/protocols/cache.py +0 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/lib/rucio/rse/protocols/dummy.py +0 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/lib/rucio/rse/protocols/gfal.py +0 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/lib/rucio/rse/protocols/globus.py +0 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/lib/rucio/rse/protocols/http_cache.py +0 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/lib/rucio/rse/protocols/mock.py +0 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/lib/rucio/rse/protocols/ngarc.py +0 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/lib/rucio/rse/protocols/posix.py +0 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/lib/rucio/rse/protocols/rclone.py +0 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/lib/rucio/rse/protocols/rfio.py +0 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/lib/rucio/rse/protocols/srm.py +0 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/lib/rucio/rse/protocols/ssh.py +0 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/lib/rucio/rse/protocols/storm.py +0 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/lib/rucio/rse/protocols/webdav.py +0 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/lib/rucio/rse/protocols/xrootd.py +0 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/lib/rucio/rse/rsemanager.py +0 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/lib/rucio/version.py +0 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/setup.cfg +0 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/setup.py +0 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/tests/test_account.py +0 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/tests/test_account_limits.py +0 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/tests/test_archive.py +0 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/tests/test_auditor.py +0 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/tests/test_auditor_hdfs.py +0 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/tests/test_auditor_srmdumps.py +0 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/tests/test_authentication.py +0 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/tests/test_automatix.py +0 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/tests/test_bad_replica.py +0 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/tests/test_bb8.py +0 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/tests/test_belleii.py +0 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/tests/test_boolean.py +0 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/tests/test_clients.py +0 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/tests/test_config.py +0 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/tests/test_conveyor_submitter.py +0 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/tests/test_counter.py +0 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/tests/test_credential.py +0 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/tests/test_curl.py +0 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/tests/test_daemons.py +0 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/tests/test_db.py +0 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/tests/test_did.py +0 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/tests/test_did_meta_plugins.py +0 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/tests/test_download.py +0 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/tests/test_dumper.py +0 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/tests/test_filter_engine.py +0 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/tests/test_gateway_external_representation.py +0 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/tests/test_heartbeat.py +0 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/tests/test_identity.py +0 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/tests/test_impl_upload_download.py +0 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/tests/test_import_export.py +0 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/tests/test_judge_cleaner.py +0 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/tests/test_judge_evaluator.py +0 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/tests/test_judge_injector.py +0 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/tests/test_judge_repairer.py +0 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/tests/test_lifetime.py +0 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/tests/test_message.py +0 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/tests/test_meta_conventions.py +0 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/tests/test_meta_did.py +0 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/tests/test_module_import.py +0 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/tests/test_monitor.py +0 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/tests/test_multi_vo.py +0 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/tests/test_naming_convention.py +0 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/tests/test_oauthmanager.py +0 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/tests/test_oidc.py +0 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/tests/test_permission.py +0 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/tests/test_pfns.py +0 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/tests/test_ping.py +0 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/tests/test_preparer.py +0 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/tests/test_qos.py +0 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/tests/test_quarantined_replica.py +0 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/tests/test_redirect.py +0 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/tests/test_replica_recoverer.py +0 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/tests/test_replica_sorting.py +0 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/tests/test_request.py +0 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/tests/test_root_proxy.py +0 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/tests/test_rse_expression_parser.py +0 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/tests/test_rse_lfn2path.py +0 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/tests/test_rse_protocol_gfal2.py +0 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/tests/test_rse_protocol_gfal2_impl.py +0 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/tests/test_rse_protocol_posix.py +0 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/tests/test_rse_protocol_rclone.py +0 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/tests/test_rse_protocol_rsync.py +0 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/tests/test_rse_protocol_srm.py +0 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/tests/test_rse_protocol_ssh.py +0 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/tests/test_rse_protocol_webdav.py +0 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/tests/test_rse_protocol_xrootd.py +0 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/tests/test_rse_selector.py +0 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/tests/test_rucio_server.py +0 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/tests/test_scope.py +0 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/tests/test_throttler.py +0 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/tests/test_tpc.py +0 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/tests/test_trace.py +0 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/tests/test_transfer.py +0 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/tests/test_undertaker.py +0 -0
- {rucio_clients-37.7.0 → rucio_clients-38.0.0}/tools/merge_rucio_configs.py +0 -0
|
@@ -69,6 +69,7 @@ Individual contributors to the source code
|
|
|
69
69
|
- Maximilian Linhoff, <maximilian.linhoff@tu-dortmund.de>, 2024
|
|
70
70
|
- Eric Banzuzi, <eric.banzuzi@gmail.com>, 2024
|
|
71
71
|
- Paul Millar, <paul.millar@desy.de>, 2025
|
|
72
|
+
- Vimalan S <vimalan.github@gmail.com>, 2025
|
|
72
73
|
|
|
73
74
|
Organisations employing contributors
|
|
74
75
|
------------------------------------
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: rucio-clients
|
|
3
|
-
Version:
|
|
3
|
+
Version: 38.0.0
|
|
4
4
|
Summary: Rucio Client Lite Package
|
|
5
5
|
Home-page: https://rucio.cern.ch/
|
|
6
6
|
Author: Rucio
|
|
@@ -22,7 +22,7 @@ License-File: AUTHORS.rst
|
|
|
22
22
|
Requires-Dist: click
|
|
23
23
|
Requires-Dist: requests
|
|
24
24
|
Requires-Dist: urllib3
|
|
25
|
-
Requires-Dist: dogpile-cache
|
|
25
|
+
Requires-Dist: dogpile-cache
|
|
26
26
|
Requires-Dist: packaging
|
|
27
27
|
Requires-Dist: tabulate
|
|
28
28
|
Requires-Dist: jsonschema
|
|
@@ -54,6 +54,7 @@ def map_legacy_command() -> Optional[list[str]]:
|
|
|
54
54
|
command_map = {
|
|
55
55
|
"list-file-replicas": ["replica", "list", "file"],
|
|
56
56
|
"list-dataset-replicas": ["replica", "list", "dataset"],
|
|
57
|
+
"list-datasets-rse": ["replica", "list", "dataset", "--rse"],
|
|
57
58
|
"add-dataset": ["did", "add", "--type dataset"],
|
|
58
59
|
"add-container": ["did", "add", "--type container"],
|
|
59
60
|
"attach": ["did", "content", "add"],
|
|
@@ -96,7 +97,7 @@ def map_legacy_command() -> Optional[list[str]]:
|
|
|
96
97
|
|
|
97
98
|
|
|
98
99
|
if __name__ == "__main__":
|
|
99
|
-
commands = ("account", "config", "did", "replica", "rse", "rule", "scope", "subscription", "ping", "whoami", "test-server", "lifetime-exception", "upload", "download")
|
|
100
|
+
commands = ("account", "config", "did", "replica", "rse", "rule", "scope", "subscription", "ping", "whoami", "test-server", "lifetime-exception", "upload", "download", "opendata")
|
|
100
101
|
|
|
101
102
|
parser = argparse.ArgumentParser(add_help=False)
|
|
102
103
|
# Check for legacy flag
|
|
@@ -73,8 +73,8 @@ default_mail_from = spamspamspam@cern.ch
|
|
|
73
73
|
|
|
74
74
|
[database]
|
|
75
75
|
default = sqlite:////tmp/rucio.db
|
|
76
|
-
#default = oracle://_____________:___________@(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=_________)(PORT=______))(ADDRESS=(PROTOCOL=TCP)(HOST=_________)(PORT=_____))(CONNECT_DATA=(SERVER=DEDICATED)(SERVICE_NAME=__________)))
|
|
77
|
-
#default = oracle://_____________:___________@(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=127.0.0.1)(PORT=______))(CONNECT_DATA=(SERVER=DEDICATED)(SERVICE_NAME=_____________)))
|
|
76
|
+
#default = oracle+oracledb://_____________:___________@(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=_________)(PORT=______))(ADDRESS=(PROTOCOL=TCP)(HOST=_________)(PORT=_____))(CONNECT_DATA=(SERVER=DEDICATED)(SERVICE_NAME=__________)))
|
|
77
|
+
#default = oracle+oracledb://_____________:___________@(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=127.0.0.1)(PORT=______))(CONNECT_DATA=(SERVER=DEDICATED)(SERVICE_NAME=_____________)))
|
|
78
78
|
#schema=atlas_rucio # only for cern oracle
|
|
79
79
|
#default = mysql+pymysql://rucio:rucio@localhost/rucio
|
|
80
80
|
#default = postgresql+psycopg://rucio:rucio@localhost/rucio
|
|
@@ -20,12 +20,10 @@ import os
|
|
|
20
20
|
import signal
|
|
21
21
|
import sys
|
|
22
22
|
import time
|
|
23
|
-
import traceback
|
|
24
23
|
import unittest
|
|
25
24
|
import uuid
|
|
26
25
|
from copy import deepcopy
|
|
27
26
|
from datetime import datetime
|
|
28
|
-
from logging import DEBUG
|
|
29
27
|
from typing import TYPE_CHECKING, Optional
|
|
30
28
|
|
|
31
29
|
from rich.console import Console
|
|
@@ -45,13 +43,13 @@ from rucio.common.client import detect_client_location
|
|
|
45
43
|
from rucio.common.config import config_get, config_get_float
|
|
46
44
|
from rucio.common.constants import ReplicaState
|
|
47
45
|
from rucio.common.exception import (
|
|
48
|
-
DIDFilterSyntaxError,
|
|
49
|
-
DuplicateCriteriaInDIDFilter,
|
|
50
46
|
DuplicateRule,
|
|
51
47
|
InputValidationError,
|
|
52
48
|
InvalidObject,
|
|
53
49
|
InvalidType,
|
|
50
|
+
RSENotFound,
|
|
54
51
|
RucioException,
|
|
52
|
+
ScopeNotFound,
|
|
55
53
|
UnsupportedOperation,
|
|
56
54
|
)
|
|
57
55
|
from rucio.common.extra import import_extras
|
|
@@ -109,8 +107,7 @@ def ping(args, client, logger, console, spinner):
|
|
|
109
107
|
if server_info:
|
|
110
108
|
print(server_info['version'])
|
|
111
109
|
return SUCCESS
|
|
112
|
-
|
|
113
|
-
return FAILURE
|
|
110
|
+
raise RucioException('Ping failed')
|
|
114
111
|
|
|
115
112
|
|
|
116
113
|
@exception_handler
|
|
@@ -232,11 +229,9 @@ def list_file_replicas(args, client, logger, console, spinner):
|
|
|
232
229
|
table_data = []
|
|
233
230
|
dids = []
|
|
234
231
|
if args.missing and not args.rses:
|
|
235
|
-
|
|
236
|
-
return FAILURE
|
|
232
|
+
raise InputValidationError('Cannot use --missing without specifying a RSE')
|
|
237
233
|
if args.link and ':' not in args.link:
|
|
238
|
-
|
|
239
|
-
return FAILURE
|
|
234
|
+
raise ValueError('The substitution parameter must equal --link="/pfn/dir:/dst/dir"')
|
|
240
235
|
|
|
241
236
|
if cli_config == 'rich':
|
|
242
237
|
spinner.update(status='Fetching file replicas')
|
|
@@ -398,14 +393,13 @@ def attach(args, client, logger, console, spinner):
|
|
|
398
393
|
|
|
399
394
|
if args.fromfile:
|
|
400
395
|
if len(dids) > 1:
|
|
401
|
-
|
|
402
|
-
return FAILURE
|
|
396
|
+
raise ValueError('If --fromfile option is active, only one file is supported. The file should contain a list of dids, one per line.')
|
|
403
397
|
try:
|
|
404
398
|
f = open(dids[0], 'r')
|
|
405
399
|
dids = [did.rstrip() for did in f.readlines()]
|
|
406
|
-
except OSError:
|
|
400
|
+
except OSError as error:
|
|
407
401
|
logger.error("Can't open file '" + dids[0] + "'.")
|
|
408
|
-
|
|
402
|
+
raise OSError from error
|
|
409
403
|
|
|
410
404
|
dids = [{'scope': get_scope(did, client)[0], 'name': get_scope(did, client)[1]} for did in dids]
|
|
411
405
|
if len(dids) <= limit:
|
|
@@ -468,35 +462,16 @@ def list_dids(args, client, logger, console, spinner):
|
|
|
468
462
|
name = '*'
|
|
469
463
|
|
|
470
464
|
if scope not in client.list_scopes():
|
|
471
|
-
|
|
472
|
-
return FAILURE
|
|
465
|
+
raise ScopeNotFound
|
|
473
466
|
|
|
474
467
|
if args.recursive and '*' in name:
|
|
475
|
-
|
|
476
|
-
return FAILURE
|
|
468
|
+
raise InputValidationError('Option recursive cannot be used with wildcards.')
|
|
477
469
|
else:
|
|
478
470
|
if filters:
|
|
479
471
|
if ('name' in filters) and (name != '*'):
|
|
480
|
-
|
|
481
|
-
return FAILURE
|
|
472
|
+
raise ValueError('Must have a wildcard in did name if filtering by name.')
|
|
482
473
|
|
|
483
|
-
|
|
484
|
-
filters, type_ = parse_did_filter_from_string_fe(args.filter, name)
|
|
485
|
-
except InvalidType as error:
|
|
486
|
-
logger.error(error)
|
|
487
|
-
return FAILURE
|
|
488
|
-
except DuplicateCriteriaInDIDFilter as error:
|
|
489
|
-
logger.error(error)
|
|
490
|
-
return FAILURE
|
|
491
|
-
except DIDFilterSyntaxError as error:
|
|
492
|
-
logger.error(error)
|
|
493
|
-
return FAILURE
|
|
494
|
-
except ValueError as error:
|
|
495
|
-
logger.error(error)
|
|
496
|
-
return FAILURE
|
|
497
|
-
except Exception as e:
|
|
498
|
-
logger.error(e)
|
|
499
|
-
return FAILURE
|
|
474
|
+
filters, type_ = parse_did_filter_from_string_fe(args.filter, name)
|
|
500
475
|
|
|
501
476
|
if cli_config == 'rich':
|
|
502
477
|
spinner.update(status='Fetching DIDs')
|
|
@@ -531,8 +506,7 @@ def list_dids_extended(args, client, logger, console, spinner):
|
|
|
531
506
|
|
|
532
507
|
List the data identifiers for a given scope (DEPRECATED).
|
|
533
508
|
"""
|
|
534
|
-
|
|
535
|
-
return FAILURE
|
|
509
|
+
raise UnsupportedOperation('This command has been deprecated. Please use list_dids instead.')
|
|
536
510
|
|
|
537
511
|
|
|
538
512
|
@exception_handler
|
|
@@ -542,15 +516,17 @@ def list_scopes(args, client, logger, console, spinner):
|
|
|
542
516
|
|
|
543
517
|
List scopes.
|
|
544
518
|
"""
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
if cli_config == 'rich':
|
|
519
|
+
if (cli_config == 'rich') or (not args.csv):
|
|
548
520
|
spinner.update(status='Fetching scopes')
|
|
549
521
|
spinner.start()
|
|
550
522
|
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
523
|
+
if args.account:
|
|
524
|
+
scopes = client.list_scopes_for_account(args.account)
|
|
525
|
+
else:
|
|
526
|
+
scopes = client.list_scopes()
|
|
527
|
+
if (cli_config == 'rich') and (not args.csv):
|
|
528
|
+
scopes = [[scope] for scope in sorted(scopes)]
|
|
529
|
+
table = generate_table(scopes, headers=['SCOPE'], col_alignments=['left'])
|
|
554
530
|
spinner.stop()
|
|
555
531
|
print_output(table, console=console, no_pager=args.no_pager)
|
|
556
532
|
else:
|
|
@@ -813,8 +789,7 @@ def list_parent_dids(args, client, logger, console, spinner):
|
|
|
813
789
|
else:
|
|
814
790
|
print(tabulate(table_data, tablefmt=tablefmt, headers=['SCOPE:NAME', '[DID TYPE]']))
|
|
815
791
|
else:
|
|
816
|
-
|
|
817
|
-
return FAILURE
|
|
792
|
+
raise InputValidationError('At least one option has to be given. Use -h to list the options.')
|
|
818
793
|
return SUCCESS
|
|
819
794
|
|
|
820
795
|
|
|
@@ -931,13 +906,11 @@ def upload(args, client, logger, console, spinner):
|
|
|
931
906
|
Upload files into Rucio
|
|
932
907
|
"""
|
|
933
908
|
if args.lifetime and args.expiration_date:
|
|
934
|
-
|
|
935
|
-
return FAILURE
|
|
909
|
+
raise InputValidationError("--lifetime and --expiration-date cannot be specified at the same time.")
|
|
936
910
|
elif args.expiration_date:
|
|
937
911
|
expiration_date = datetime.strptime(args.expiration_date, "%Y-%m-%d-%H:%M:%S")
|
|
938
912
|
if expiration_date < datetime.utcnow():
|
|
939
|
-
|
|
940
|
-
return FAILURE
|
|
913
|
+
raise ValueError("The specified expiration date should be in the future!")
|
|
941
914
|
args.lifetime = (expiration_date - datetime.utcnow()).total_seconds()
|
|
942
915
|
|
|
943
916
|
dsscope = None
|
|
@@ -1023,23 +996,18 @@ def download(args, client, logger, console, spinner):
|
|
|
1023
996
|
"""
|
|
1024
997
|
# Input validation
|
|
1025
998
|
if not args.dids and not args.filter and not args.metalink_file:
|
|
1026
|
-
|
|
1027
|
-
return FAILURE
|
|
999
|
+
raise InputValidationError('At least one did is mandatory')
|
|
1028
1000
|
elif not args.dids and args.filter and not args.scope:
|
|
1029
|
-
|
|
1030
|
-
return FAILURE
|
|
1001
|
+
raise InputValidationError('The argument scope is mandatory')
|
|
1031
1002
|
|
|
1032
1003
|
if args.filter and args.metalink_file:
|
|
1033
|
-
|
|
1034
|
-
return FAILURE
|
|
1004
|
+
raise InputValidationError('Arguments filter and metalink cannot be used together.')
|
|
1035
1005
|
|
|
1036
1006
|
if args.dids and args.metalink_file:
|
|
1037
|
-
|
|
1038
|
-
return FAILURE
|
|
1007
|
+
raise InputValidationError('Arguments dids and metalink cannot be used together.')
|
|
1039
1008
|
|
|
1040
1009
|
if args.ignore_checksum and args.check_local_with_filesize_only:
|
|
1041
|
-
|
|
1042
|
-
return FAILURE
|
|
1010
|
+
raise InputValidationError('Arguments ignore-checksum and check-local-with-filesize-only cannot be used together.')
|
|
1043
1011
|
|
|
1044
1012
|
trace_pattern = {}
|
|
1045
1013
|
|
|
@@ -1083,16 +1051,12 @@ def download(args, client, logger, console, spinner):
|
|
|
1083
1051
|
filters, type_ = parse_did_filter_from_string(args.filter)
|
|
1084
1052
|
if args.scope:
|
|
1085
1053
|
filters['scope'] = args.scope
|
|
1086
|
-
except InvalidType as error:
|
|
1054
|
+
except (InvalidType, ValueError) as error:
|
|
1087
1055
|
logger.error(error)
|
|
1088
|
-
|
|
1089
|
-
except ValueError as error:
|
|
1090
|
-
logger.error(error)
|
|
1091
|
-
return FAILURE
|
|
1056
|
+
raise error
|
|
1092
1057
|
except Exception as error:
|
|
1093
|
-
logger.error(error)
|
|
1094
1058
|
logger.error("Invalid Filter. Filter must be 'key=value', 'key>=value', 'key>value', 'key<=value', 'key<value'")
|
|
1095
|
-
|
|
1059
|
+
raise error
|
|
1096
1060
|
item_defaults['filters'] = filters
|
|
1097
1061
|
|
|
1098
1062
|
if not args.pfn:
|
|
@@ -1148,8 +1112,7 @@ def download(args, client, logger, console, spinner):
|
|
|
1148
1112
|
|
|
1149
1113
|
download_rse = _get_rse_for_pfn(replicas, args.pfn)
|
|
1150
1114
|
if download_rse is None:
|
|
1151
|
-
|
|
1152
|
-
return FAILURE
|
|
1115
|
+
raise RSENotFound("Could not find RSE for pfn %s" % args.pfn)
|
|
1153
1116
|
else:
|
|
1154
1117
|
item_defaults['rse'] = download_rse
|
|
1155
1118
|
|
|
@@ -1354,8 +1317,7 @@ def delete_rule(args, client, logger, console, spinner):
|
|
|
1354
1317
|
except ValueError:
|
|
1355
1318
|
# Otherwise, trying to extract the scope, name from args.rule_id
|
|
1356
1319
|
if not args.rses:
|
|
1357
|
-
|
|
1358
|
-
return FAILURE
|
|
1320
|
+
raise InputValidationError('A RSE expression must be specified if you do not provide a rule_id but a DID')
|
|
1359
1321
|
scope, name = get_scope(args.rule_id, client)
|
|
1360
1322
|
rules = client.list_did_rules(scope=scope, name=name)
|
|
1361
1323
|
if args.rule_account is None:
|
|
@@ -1372,8 +1334,7 @@ def delete_rule(args, client, logger, console, spinner):
|
|
|
1372
1334
|
client.delete_replication_rule(rule_id=rule['id'], purge_replicas=args.purge_replicas)
|
|
1373
1335
|
deletion_success = True
|
|
1374
1336
|
if not deletion_success:
|
|
1375
|
-
|
|
1376
|
-
return FAILURE
|
|
1337
|
+
raise RucioException('No replication rule was deleted from the DID')
|
|
1377
1338
|
return SUCCESS
|
|
1378
1339
|
|
|
1379
1340
|
|
|
@@ -1394,8 +1355,8 @@ def update_rule(args, client, logger, console, spinner):
|
|
|
1394
1355
|
elif args.locked.title() == "False":
|
|
1395
1356
|
options['locked'] = False
|
|
1396
1357
|
else:
|
|
1397
|
-
|
|
1398
|
-
|
|
1358
|
+
raise InputValidationError('Locked must be True or False')
|
|
1359
|
+
|
|
1399
1360
|
if args.comment:
|
|
1400
1361
|
options['comment'] = args.comment
|
|
1401
1362
|
if args.rule_account:
|
|
@@ -1410,8 +1371,7 @@ def update_rule(args, client, logger, console, spinner):
|
|
|
1410
1371
|
options['source_replica_expression'] = None if args.source_replica_expression.lower() == 'none' else args.source_replica_expression
|
|
1411
1372
|
if args.cancel_requests:
|
|
1412
1373
|
if 'state' not in options:
|
|
1413
|
-
|
|
1414
|
-
return FAILURE
|
|
1374
|
+
raise InputValidationError('--stuck or --suspend must be specified when running --cancel-requests')
|
|
1415
1375
|
options['cancel_requests'] = True
|
|
1416
1376
|
if args.priority:
|
|
1417
1377
|
options['priority'] = int(args.priority)
|
|
@@ -1578,12 +1538,11 @@ def list_rules(args, client, logger, console, spinner):
|
|
|
1578
1538
|
elif args.rule_account:
|
|
1579
1539
|
rules = client.list_account_rules(account=args.rule_account)
|
|
1580
1540
|
elif args.subscription:
|
|
1581
|
-
account = args.
|
|
1582
|
-
name = args.subscription
|
|
1541
|
+
account = args.rule_account if args.rule_account else client.account
|
|
1542
|
+
name = args.subscription
|
|
1583
1543
|
rules = client.list_subscription_rules(account=account, name=name)
|
|
1584
1544
|
else:
|
|
1585
|
-
|
|
1586
|
-
return FAILURE
|
|
1545
|
+
raise InputValidationError('At least one option has to be given. Use -h to list the options.')
|
|
1587
1546
|
if args.csv:
|
|
1588
1547
|
for rule in rules:
|
|
1589
1548
|
print(rule['id'],
|
|
@@ -1990,21 +1949,18 @@ def add_lifetime_exception(args, client, logger, console, spinner):
|
|
|
1990
1949
|
"""
|
|
1991
1950
|
|
|
1992
1951
|
if not args.reason:
|
|
1993
|
-
|
|
1994
|
-
return FAILURE
|
|
1952
|
+
raise InputValidationError('reason for the extension is mandatory')
|
|
1995
1953
|
reason = args.reason
|
|
1996
1954
|
if not args.expiration:
|
|
1997
|
-
|
|
1998
|
-
return FAILURE
|
|
1955
|
+
raise InputValidationError('expiration is mandatory')
|
|
1999
1956
|
try:
|
|
2000
1957
|
expiration = datetime.strptime(args.expiration, "%Y-%m-%d")
|
|
2001
1958
|
except Exception as err:
|
|
2002
|
-
|
|
2003
|
-
|
|
1959
|
+
msg = f'Cannot parse expiration date: {err}'
|
|
1960
|
+
raise ValueError(msg)
|
|
2004
1961
|
|
|
2005
1962
|
if not args.inputfile:
|
|
2006
|
-
|
|
2007
|
-
return FAILURE
|
|
1963
|
+
raise InputValidationError('inputfile is mandatory')
|
|
2008
1964
|
with open(args.inputfile) as infile:
|
|
2009
1965
|
# Deduplicate the content of the input file and ignore empty lines.
|
|
2010
1966
|
dids = set(did for line in infile if (did := line.strip()))
|
|
@@ -2067,22 +2023,8 @@ def add_lifetime_exception(args, client, logger, console, spinner):
|
|
|
2067
2023
|
if not datasets:
|
|
2068
2024
|
logger.error('Nothing to submit')
|
|
2069
2025
|
return SUCCESS
|
|
2070
|
-
|
|
2071
|
-
|
|
2072
|
-
except UnsupportedOperation as err:
|
|
2073
|
-
logger.error(err)
|
|
2074
|
-
return FAILURE
|
|
2075
|
-
except Exception:
|
|
2076
|
-
error_message = 'Failure to submit exception. Please retry.'
|
|
2077
|
-
if cli_config == 'rich':
|
|
2078
|
-
if logger.level == DEBUG:
|
|
2079
|
-
logger.exception(error_message)
|
|
2080
|
-
else:
|
|
2081
|
-
logger.error(error_message)
|
|
2082
|
-
else:
|
|
2083
|
-
logger.error(error_message)
|
|
2084
|
-
logger.debug(traceback.format_exc())
|
|
2085
|
-
return FAILURE
|
|
2026
|
+
|
|
2027
|
+
client.add_exception(dids=datasets, account=client.account, pattern='', comments=reason, expires_at=expiration)
|
|
2086
2028
|
|
|
2087
2029
|
logger.info('Exception successfully submitted. Summary below:')
|
|
2088
2030
|
for key, data in error_summary.items():
|
|
@@ -2499,6 +2441,8 @@ You can filter by key/value, e.g.::
|
|
|
2499
2441
|
''')
|
|
2500
2442
|
|
|
2501
2443
|
scope_list_parser.set_defaults(function=list_scopes)
|
|
2444
|
+
scope_list_parser.add_argument("--csv", action="store_true", default=False, help="Comma Separated Value output.")
|
|
2445
|
+
scope_list_parser.add_argument('--account', help='Filter scopes by account')
|
|
2502
2446
|
|
|
2503
2447
|
# The close command
|
|
2504
2448
|
close_parser = subparsers.add_parser('close', help='Close a dataset or container.')
|
|
@@ -2699,7 +2643,7 @@ You can filter by account::
|
|
|
2699
2643
|
list_rules_parser.add_argument('--csv', dest='csv', action='store_true', default=False, help='Comma Separated Value output')
|
|
2700
2644
|
list_rules_parser.add_argument('--file', dest='file', action='store', help='List associated rules of an affected file')
|
|
2701
2645
|
list_rules_parser.add_argument('--account', dest='rule_account', action='store', help='List by account')
|
|
2702
|
-
list_rules_parser.add_argument('--subscription', dest='subscription', action='store', help='List by
|
|
2646
|
+
list_rules_parser.add_argument('--subscription', dest='subscription', action='store', help='List by subscription name')
|
|
2703
2647
|
|
|
2704
2648
|
# The list_rules_history command
|
|
2705
2649
|
list_rules_history_parser = subparsers.add_parser('list-rules-history', help='List replication rules history for a DID.')
|
|
@@ -37,8 +37,11 @@ from rucio.cli.utils import exception_handler, get_client, setup_gfal2_logger, s
|
|
|
37
37
|
from rucio.client.richclient import MAX_TRACEBACK_WIDTH, MIN_CONSOLE_WIDTH, CLITheme, generate_table, get_cli_config, get_pager, print_output, setup_rich_logger
|
|
38
38
|
from rucio.common.constants import RseAttr
|
|
39
39
|
from rucio.common.exception import (
|
|
40
|
+
InputValidationError,
|
|
41
|
+
InvalidObject,
|
|
40
42
|
ReplicaNotFound,
|
|
41
43
|
RSEOperationNotSupported,
|
|
44
|
+
RucioException,
|
|
42
45
|
)
|
|
43
46
|
from rucio.common.extra import import_extras
|
|
44
47
|
from rucio.common.utils import StoreAndDeprecateWarningAction, chunks, clean_pfns, construct_non_deterministic_pfn, extract_scope, get_bytes_value_from_string, parse_response, render_json, setup_logger, sizefmt
|
|
@@ -222,8 +225,10 @@ def set_limits(args, client, logger, console, spinner):
|
|
|
222
225
|
try:
|
|
223
226
|
byte_limit = int(limit_input)
|
|
224
227
|
except ValueError:
|
|
225
|
-
|
|
226
|
-
|
|
228
|
+
msg = f'\
|
|
229
|
+
The limit could not be set. Either you misspelled infinity or your input ({args.bytes}) could not be converted to integer or you used a wrong pattern. \
|
|
230
|
+
Please use a format like 10GB with B,KB,MB,GB,TB,PB as units (not case sensitive)'
|
|
231
|
+
raise InputValidationError(msg)
|
|
227
232
|
|
|
228
233
|
client.set_account_limit(account=args.account, rse=args.rse, bytes_=byte_limit, locality=locality)
|
|
229
234
|
print('Set account limit for account %s on RSE %s: %s' % (args.account, args.rse, sizefmt(byte_limit, True)))
|
|
@@ -266,12 +271,10 @@ def identity_add(args, client, logger, console, spinner):
|
|
|
266
271
|
|
|
267
272
|
"""
|
|
268
273
|
if args.email == "":
|
|
269
|
-
|
|
270
|
-
return FAILURE
|
|
274
|
+
raise InputValidationError('Error: --email argument can\'t be an empty string. Failed to grant an identity access to an account')
|
|
271
275
|
|
|
272
276
|
if args.authtype == 'USERPASS' and not args.password:
|
|
273
|
-
|
|
274
|
-
return FAILURE
|
|
277
|
+
raise InputValidationError('Missing --password argument')
|
|
275
278
|
|
|
276
279
|
client.add_identity(account=args.account, identity=args.identity, authtype=args.authtype, email=args.email, password=args.password)
|
|
277
280
|
print('Added new identity to account: %s-%s' % (args.identity, args.account))
|
|
@@ -634,8 +637,7 @@ def add_protocol_rse(args, client, logger, console, spinner):
|
|
|
634
637
|
if args.ext_attr_json:
|
|
635
638
|
proto['extended_attributes'] = args.ext_attr_json
|
|
636
639
|
if proto['scheme'] == 'srm' and not args.web_service_path:
|
|
637
|
-
|
|
638
|
-
return FAILURE
|
|
640
|
+
raise InputValidationError('Error: space-token and web-service-path must be provided for SRM endpoints.')
|
|
639
641
|
if args.space_token:
|
|
640
642
|
proto['extended_attributes']['space_token'] = args.space_token
|
|
641
643
|
if args.web_service_path:
|
|
@@ -764,7 +766,7 @@ def list_scopes(args, client, logger, console, spinner):
|
|
|
764
766
|
List scopes.
|
|
765
767
|
|
|
766
768
|
"""
|
|
767
|
-
if cli_config == 'rich':
|
|
769
|
+
if (cli_config == 'rich') and (not args.csv):
|
|
768
770
|
spinner.update(status='Fetching scopes')
|
|
769
771
|
spinner.start()
|
|
770
772
|
|
|
@@ -772,15 +774,14 @@ def list_scopes(args, client, logger, console, spinner):
|
|
|
772
774
|
scopes = client.list_scopes_for_account(args.account)
|
|
773
775
|
else:
|
|
774
776
|
scopes = client.list_scopes()
|
|
775
|
-
if cli_config == 'rich':
|
|
776
|
-
scopes = [[scope] for scope in sorted(scopes)
|
|
777
|
+
if (cli_config == 'rich') and (not args.csv):
|
|
778
|
+
scopes = [[scope] for scope in sorted(scopes)]
|
|
777
779
|
table = generate_table(scopes, headers=['SCOPE'], col_alignments=['left'])
|
|
778
780
|
spinner.stop()
|
|
779
781
|
print_output(table, console=console, no_pager=args.no_pager)
|
|
780
782
|
else:
|
|
781
783
|
for scope in scopes:
|
|
782
|
-
|
|
783
|
-
print(scope)
|
|
784
|
+
print(scope)
|
|
784
785
|
return SUCCESS
|
|
785
786
|
|
|
786
787
|
|
|
@@ -1042,8 +1043,7 @@ def __declare_bad_file_replicas_by_lfns(args: object, client) -> object:
|
|
|
1042
1043
|
Declare a list of bad replicas using RSE name, scope and list of LFNs.
|
|
1043
1044
|
"""
|
|
1044
1045
|
if not args.scope or not args.rse:
|
|
1045
|
-
|
|
1046
|
-
return FAILURE
|
|
1046
|
+
raise InputValidationError("--lfns requires using --rse and --scope")
|
|
1047
1047
|
reason = args.reason
|
|
1048
1048
|
scope = args.scope
|
|
1049
1049
|
rse = args.rse
|
|
@@ -1094,8 +1094,8 @@ def declare_bad_file_replicas(args, client, logger, console, spinner):
|
|
|
1094
1094
|
scope, name = get_scope(bad_file, client)
|
|
1095
1095
|
did_info = client.get_did(scope, name)
|
|
1096
1096
|
if did_info['type'].upper() != 'FILE' and not args.allow_collection:
|
|
1097
|
-
|
|
1098
|
-
|
|
1097
|
+
msg = f'DID {scope}:{name} is a collection and --allow-collection was not specified.'
|
|
1098
|
+
raise InputValidationError(msg)
|
|
1099
1099
|
replicas = [replica for rep in client.list_replicas([{'scope': scope, 'name': name}])
|
|
1100
1100
|
for replica in list(rep['pfns'].keys())]
|
|
1101
1101
|
bad_files_pfns.extend(replicas)
|
|
@@ -1173,15 +1173,15 @@ def declare_temporary_unavailable_replicas(args, client, logger, console, spinne
|
|
|
1173
1173
|
for line in infile:
|
|
1174
1174
|
bad_file = line.rstrip('\n')
|
|
1175
1175
|
if '://' not in bad_file:
|
|
1176
|
-
|
|
1177
|
-
|
|
1176
|
+
msg = f'{bad_file} is not a valid PFN. Aborting'
|
|
1177
|
+
raise InvalidObject(msg)
|
|
1178
1178
|
if bad_file != '':
|
|
1179
1179
|
bad_files.append(bad_file)
|
|
1180
1180
|
else:
|
|
1181
1181
|
bad_files = args.listbadfiles
|
|
1182
1182
|
|
|
1183
1183
|
if args.duration is None:
|
|
1184
|
-
raise
|
|
1184
|
+
raise InputValidationError("Duration should have been set, something went wrong!")
|
|
1185
1185
|
|
|
1186
1186
|
expiration_date = (datetime.datetime.utcnow() + datetime.timedelta(seconds=args.duration)).isoformat()
|
|
1187
1187
|
|
|
@@ -1246,8 +1246,7 @@ def list_pfns(args, client, logger, console, spinner):
|
|
|
1246
1246
|
path if not path.startswith('/') else path[1:]])
|
|
1247
1247
|
print(pfn)
|
|
1248
1248
|
else:
|
|
1249
|
-
|
|
1250
|
-
return FAILURE
|
|
1249
|
+
raise RucioException
|
|
1251
1250
|
else:
|
|
1252
1251
|
print(result)
|
|
1253
1252
|
return SUCCESS
|
|
@@ -1279,7 +1278,7 @@ def import_data(args, client, logger, console, spinner):
|
|
|
1279
1278
|
else:
|
|
1280
1279
|
print('There was problem with decoding your file.')
|
|
1281
1280
|
print(error)
|
|
1282
|
-
|
|
1281
|
+
raise ValueError from error
|
|
1283
1282
|
except OSError as error:
|
|
1284
1283
|
if cli_config == 'rich':
|
|
1285
1284
|
spinner.stop()
|
|
@@ -1288,7 +1287,7 @@ def import_data(args, client, logger, console, spinner):
|
|
|
1288
1287
|
else:
|
|
1289
1288
|
print('There was a problem with reading your file.')
|
|
1290
1289
|
print(error)
|
|
1291
|
-
|
|
1290
|
+
raise OSError from error
|
|
1292
1291
|
|
|
1293
1292
|
if data:
|
|
1294
1293
|
client.import_data(data)
|
|
@@ -1304,7 +1303,7 @@ def import_data(args, client, logger, console, spinner):
|
|
|
1304
1303
|
print_output('Nothing to import.', console=console, no_pager=True)
|
|
1305
1304
|
else:
|
|
1306
1305
|
print('Nothing to import.')
|
|
1307
|
-
|
|
1306
|
+
raise ValueError
|
|
1308
1307
|
|
|
1309
1308
|
|
|
1310
1309
|
@exception_handler
|
|
@@ -1342,7 +1341,7 @@ def export_data(args, client, logger, console, spinner):
|
|
|
1342
1341
|
else:
|
|
1343
1342
|
print('There was a problem with reading your file.')
|
|
1344
1343
|
print(error)
|
|
1345
|
-
|
|
1344
|
+
raise OSError from error
|
|
1346
1345
|
|
|
1347
1346
|
|
|
1348
1347
|
@exception_handler
|
|
@@ -2131,6 +2130,7 @@ def get_parser():
|
|
|
2131
2130
|
'\n')
|
|
2132
2131
|
list_scope_parser.set_defaults(which='list_scopes')
|
|
2133
2132
|
list_scope_parser.add_argument('--account', dest='account', action='store', help='Account name')
|
|
2133
|
+
list_scope_parser.add_argument('--csv', action='store_true', help='Output a list of scopes as a csv')
|
|
2134
2134
|
|
|
2135
2135
|
# The config subparser
|
|
2136
2136
|
config_parser = subparsers.add_parser('config',
|
|
@@ -76,6 +76,7 @@ class LazyGroup(click.Group):
|
|
|
76
76
|
"scope": "rucio.cli.scope.scope",
|
|
77
77
|
"subscription": "rucio.cli.subscription.subscription",
|
|
78
78
|
"upload": "rucio.cli.upload.upload_command",
|
|
79
|
+
"opendata": "rucio.cli.opendata.opendata",
|
|
79
80
|
},
|
|
80
81
|
context_settings={"help_option_names": ["-h", "--help"]}
|
|
81
82
|
) # TODO: Implement https://click.palletsprojects.com/en/stable/options/#dynamic-defaults-for-prompts for args from config or os
|
|
@@ -117,7 +117,7 @@ def content():
|
|
|
117
117
|
|
|
118
118
|
|
|
119
119
|
@content.command("history")
|
|
120
|
-
@click.argument("dids", nargs=-1)
|
|
120
|
+
@click.argument("dids", nargs=-1, required=True)
|
|
121
121
|
@click.pass_context
|
|
122
122
|
def content_history(ctx, dids):
|
|
123
123
|
"""List the content history of a collection-type DID"""
|
|
@@ -146,7 +146,7 @@ def content_remove(ctx, dids, from_did):
|
|
|
146
146
|
|
|
147
147
|
|
|
148
148
|
@content.command("list")
|
|
149
|
-
@click.argument("dids", nargs=-1)
|
|
149
|
+
@click.argument("dids", nargs=-1, required=True)
|
|
150
150
|
@click.option("--short", is_flag=True, default=False, help="Just dump the list of DIDs.")
|
|
151
151
|
@click.pass_context
|
|
152
152
|
def content_list_(ctx, dids, short):
|