rucio-clients 34.6.0__tar.gz → 35.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-34.6.0 → rucio_clients-35.0.0}/AUTHORS.rst +2 -0
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/MANIFEST.in +1 -1
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/PKG-INFO +12 -13
- rucio_clients-35.0.0/README.md +27 -0
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/bin/rucio +34 -0
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/bin/rucio-admin +8 -8
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/lib/rucio/alembicrevision.py +1 -1
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/lib/rucio/client/baseclient.py +60 -49
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/lib/rucio/client/didclient.py +2 -2
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/lib/rucio/client/downloadclient.py +81 -23
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/lib/rucio/client/subscriptionclient.py +2 -2
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/lib/rucio/client/uploadclient.py +127 -65
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/lib/rucio/common/constants.py +3 -0
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/lib/rucio/common/exception.py +10 -0
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/lib/rucio/common/plugins.py +5 -1
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/lib/rucio/common/schema/atlas.py +6 -3
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/lib/rucio/common/schema/belleii.py +6 -3
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/lib/rucio/common/schema/domatpc.py +6 -3
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/lib/rucio/common/schema/escape.py +6 -3
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/lib/rucio/common/schema/generic.py +6 -3
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/lib/rucio/common/schema/generic_multi_vo.py +6 -3
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/lib/rucio/common/schema/icecube.py +6 -3
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/lib/rucio/common/types.py +90 -1
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/lib/rucio/common/utils.py +66 -66
- rucio_clients-35.0.0/lib/rucio/vcsversion.py +11 -0
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/lib/rucio_clients.egg-info/SOURCES.txt +3 -3
- rucio_clients-35.0.0/requirements/requirements.client.txt +15 -0
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/setup.py +2 -2
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/setuputil.py +19 -12
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/tests/test_account.py +2 -2
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/tests/test_authentication.py +4 -4
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/tests/test_bad_replica.py +3 -3
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/tests/test_bin_rucio.py +18 -3
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/tests/test_clients.py +10 -2
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/tests/test_did.py +4 -4
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/tests/test_did_meta_plugins.py +18 -8
- rucio_clients-34.6.0/tests/test_api_external_representation.py → rucio_clients-35.0.0/tests/test_gateway_external_representation.py +57 -57
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/tests/test_lifetime.py +3 -0
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/tests/test_multi_vo.py +26 -26
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/tests/test_permission.py +3 -3
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/tests/test_reaper.py +18 -18
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/tests/test_replica.py +3 -3
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/tests/test_rule.py +5 -5
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/tests/test_subscription.py +57 -9
- rucio_clients-34.6.0/README.rst +0 -29
- rucio_clients-34.6.0/lib/rucio/vcsversion.py +0 -11
- rucio_clients-34.6.0/requirements.txt +0 -58
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/ChangeLog +0 -0
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/LICENSE +0 -0
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/etc/rse-accounts.cfg.template +0 -0
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/etc/rucio.cfg.atlas.client.template +0 -0
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/etc/rucio.cfg.template +0 -0
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/lib/rucio/__init__.py +0 -0
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/lib/rucio/client/__init__.py +0 -0
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/lib/rucio/client/accountclient.py +0 -0
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/lib/rucio/client/accountlimitclient.py +0 -0
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/lib/rucio/client/client.py +0 -0
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/lib/rucio/client/configclient.py +0 -0
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/lib/rucio/client/credentialclient.py +0 -0
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/lib/rucio/client/diracclient.py +0 -0
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/lib/rucio/client/exportclient.py +0 -0
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/lib/rucio/client/fileclient.py +0 -0
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/lib/rucio/client/importclient.py +0 -0
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/lib/rucio/client/lifetimeclient.py +0 -0
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/lib/rucio/client/lockclient.py +0 -0
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/lib/rucio/client/metaconventionsclient.py +0 -0
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/lib/rucio/client/pingclient.py +0 -0
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/lib/rucio/client/replicaclient.py +0 -0
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/lib/rucio/client/requestclient.py +0 -0
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/lib/rucio/client/rseclient.py +0 -0
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/lib/rucio/client/ruleclient.py +0 -0
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/lib/rucio/client/scopeclient.py +0 -0
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/lib/rucio/client/touchclient.py +0 -0
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/lib/rucio/common/__init__.py +0 -0
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/lib/rucio/common/cache.py +0 -0
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/lib/rucio/common/config.py +0 -0
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/lib/rucio/common/constraints.py +0 -0
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/lib/rucio/common/didtype.py +0 -0
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/lib/rucio/common/extra.py +0 -0
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/lib/rucio/common/logging.py +0 -0
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/lib/rucio/common/pcache.py +0 -0
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/lib/rucio/common/policy.py +0 -0
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/lib/rucio/common/schema/__init__.py +0 -0
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/lib/rucio/common/stomp_utils.py +0 -0
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/lib/rucio/common/stopwatch.py +0 -0
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/lib/rucio/common/test_rucio_server.py +0 -0
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/lib/rucio/rse/__init__.py +0 -0
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/lib/rucio/rse/protocols/__init__.py +0 -0
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/lib/rucio/rse/protocols/bittorrent.py +0 -0
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/lib/rucio/rse/protocols/cache.py +0 -0
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/lib/rucio/rse/protocols/dummy.py +0 -0
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/lib/rucio/rse/protocols/gfal.py +0 -0
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/lib/rucio/rse/protocols/globus.py +0 -0
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/lib/rucio/rse/protocols/gsiftp.py +0 -0
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/lib/rucio/rse/protocols/http_cache.py +0 -0
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/lib/rucio/rse/protocols/mock.py +0 -0
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/lib/rucio/rse/protocols/ngarc.py +0 -0
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/lib/rucio/rse/protocols/posix.py +0 -0
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/lib/rucio/rse/protocols/protocol.py +0 -0
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/lib/rucio/rse/protocols/rclone.py +0 -0
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/lib/rucio/rse/protocols/rfio.py +0 -0
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/lib/rucio/rse/protocols/srm.py +0 -0
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/lib/rucio/rse/protocols/ssh.py +0 -0
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/lib/rucio/rse/protocols/storm.py +0 -0
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/lib/rucio/rse/protocols/webdav.py +0 -0
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/lib/rucio/rse/protocols/xrootd.py +0 -0
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/lib/rucio/rse/rsemanager.py +0 -0
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/lib/rucio/version.py +0 -0
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/pylintrc +0 -0
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/pyproject.toml +0 -0
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/setup.cfg +0 -0
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/tests/test_abacus_account.py +0 -0
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/tests/test_abacus_collection_replica.py +0 -0
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/tests/test_abacus_rse.py +0 -0
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/tests/test_account_limits.py +0 -0
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/tests/test_archive.py +0 -0
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/tests/test_auditor.py +0 -0
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/tests/test_auditor_hdfs.py +0 -0
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/tests/test_auditor_srmdumps.py +0 -0
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/tests/test_automatix.py +0 -0
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/tests/test_bb8.py +0 -0
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/tests/test_belleii.py +0 -0
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/tests/test_boolean.py +0 -0
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/tests/test_common_types.py +0 -0
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/tests/test_config.py +0 -0
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/tests/test_conveyor.py +0 -0
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/tests/test_conveyor_submitter.py +0 -0
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/tests/test_counter.py +0 -0
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/tests/test_credential.py +0 -0
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/tests/test_curl.py +0 -0
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/tests/test_daemons.py +0 -0
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/tests/test_dataset_replicas.py +0 -0
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/tests/test_db.py +0 -0
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/tests/test_didtype.py +0 -0
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/tests/test_download.py +0 -0
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/tests/test_dumper.py +0 -0
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/tests/test_dumper_consistency.py +0 -0
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/tests/test_dumper_data_model.py +0 -0
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/tests/test_dumper_path_parsing.py +0 -0
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/tests/test_filter_engine.py +0 -0
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/tests/test_heartbeat.py +0 -0
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/tests/test_hermes.py +0 -0
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/tests/test_identity.py +0 -0
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/tests/test_impl_upload_download.py +0 -0
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/tests/test_import_export.py +0 -0
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/tests/test_judge_cleaner.py +0 -0
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/tests/test_judge_evaluator.py +0 -0
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/tests/test_judge_injector.py +0 -0
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/tests/test_judge_repairer.py +0 -0
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/tests/test_message.py +0 -0
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/tests/test_meta_conventions.py +0 -0
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/tests/test_meta_did.py +0 -0
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/tests/test_module_import.py +0 -0
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/tests/test_monitor.py +0 -0
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/tests/test_naming_convention.py +0 -0
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/tests/test_oauthmanager.py +0 -0
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/tests/test_oidc.py +0 -0
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/tests/test_pfns.py +0 -0
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/tests/test_ping.py +0 -0
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/tests/test_preparer.py +0 -0
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/tests/test_qos.py +0 -0
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/tests/test_quarantined_replica.py +0 -0
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/tests/test_redirect.py +0 -0
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/tests/test_replica_recoverer.py +0 -0
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/tests/test_replica_sorting.py +0 -0
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/tests/test_request.py +0 -0
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/tests/test_root_proxy.py +0 -0
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/tests/test_rse.py +0 -0
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/tests/test_rse_expression_parser.py +0 -0
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/tests/test_rse_lfn2path.py +0 -0
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/tests/test_rse_protocol_gfal2.py +0 -0
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/tests/test_rse_protocol_gfal2_impl.py +0 -0
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/tests/test_rse_protocol_posix.py +0 -0
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/tests/test_rse_protocol_rclone.py +0 -0
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/tests/test_rse_protocol_rsync.py +0 -0
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/tests/test_rse_protocol_srm.py +0 -0
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/tests/test_rse_protocol_ssh.py +0 -0
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/tests/test_rse_protocol_webdav.py +0 -0
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/tests/test_rse_protocol_xrootd.py +0 -0
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/tests/test_rse_selector.py +0 -0
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/tests/test_rucio_server.py +0 -0
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/tests/test_scope.py +0 -0
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/tests/test_throttler.py +0 -0
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/tests/test_tpc.py +0 -0
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/tests/test_trace.py +0 -0
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/tests/test_transfer.py +0 -0
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/tests/test_transfer_plugins.py +0 -0
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/tests/test_undertaker.py +0 -0
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/tests/test_upload.py +0 -0
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/tests/test_utils.py +0 -0
- {rucio_clients-34.6.0 → rucio_clients-35.0.0}/tools/merge_rucio_configs.py +0 -0
|
@@ -66,6 +66,7 @@ Individual contributors to the source code
|
|
|
66
66
|
- Jensen Zhang <hack@jensen-zhang.site>, 2022
|
|
67
67
|
- Aksel Lunde Aase <aksel.lunde.aase@gmail.com>, 2022
|
|
68
68
|
- Elena Gazzarrini <gazzarrini.elena@gmail.com>, 2022-2023
|
|
69
|
+
- Maximilian Linhoff, <maximilian.linhoff@tu-dortmund.de>, 2024
|
|
69
70
|
|
|
70
71
|
Organisations employing contributors
|
|
71
72
|
------------------------------------
|
|
@@ -93,3 +94,4 @@ Organisations employing contributors
|
|
|
93
94
|
- Imperial College London (UK)
|
|
94
95
|
- University of Chicago (USA)
|
|
95
96
|
- Purdue University (USA)
|
|
97
|
+
- TU Dortmund University (Germany)
|
|
@@ -7,7 +7,7 @@ include setuputil.py
|
|
|
7
7
|
include setup.py
|
|
8
8
|
include setup.cfg
|
|
9
9
|
include pyproject.toml
|
|
10
|
-
include requirements.txt
|
|
10
|
+
include requirements/requirements.client.txt
|
|
11
11
|
include etc/rse-accounts.cfg.template
|
|
12
12
|
include etc/rucio.cfg.atlas.client.template
|
|
13
13
|
include etc/rucio.cfg.template
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: rucio-clients
|
|
3
|
-
Version:
|
|
3
|
+
Version: 35.0.0
|
|
4
4
|
Summary: Rucio Client Lite Package
|
|
5
5
|
Home-page: https://rucio.cern.ch/
|
|
6
6
|
Author: Rucio
|
|
@@ -19,22 +19,21 @@ Classifier: Programming Language :: Python :: 3.10
|
|
|
19
19
|
Requires-Python: >=3.9, <4
|
|
20
20
|
License-File: LICENSE
|
|
21
21
|
License-File: AUTHORS.rst
|
|
22
|
-
Requires-Dist: requests
|
|
23
|
-
Requires-Dist: urllib3
|
|
24
|
-
Requires-Dist:
|
|
25
|
-
Requires-Dist:
|
|
26
|
-
Requires-Dist: jsonschema~=4.20.0
|
|
22
|
+
Requires-Dist: requests>=2.32.2
|
|
23
|
+
Requires-Dist: urllib3>=1.26.18
|
|
24
|
+
Requires-Dist: tabulate>=0.9.0
|
|
25
|
+
Requires-Dist: jsonschema>=4.20.0
|
|
27
26
|
Provides-Extra: ssh
|
|
28
|
-
Requires-Dist: paramiko
|
|
27
|
+
Requires-Dist: paramiko>=3.4.0; extra == "ssh"
|
|
29
28
|
Provides-Extra: kerberos
|
|
30
|
-
Requires-Dist: kerberos
|
|
31
|
-
Requires-Dist: pykerberos
|
|
29
|
+
Requires-Dist: kerberos>=1.3.1; extra == "kerberos"
|
|
30
|
+
Requires-Dist: pykerberos>=1.2.4; extra == "kerberos"
|
|
32
31
|
Requires-Dist: requests-kerberos>=0.14.0; extra == "kerberos"
|
|
33
32
|
Provides-Extra: swift
|
|
34
|
-
Requires-Dist: python-swiftclient
|
|
33
|
+
Requires-Dist: python-swiftclient>=4.4.0; extra == "swift"
|
|
35
34
|
Provides-Extra: argcomplete
|
|
36
|
-
Requires-Dist: argcomplete
|
|
35
|
+
Requires-Dist: argcomplete>=3.1.6; extra == "argcomplete"
|
|
37
36
|
Provides-Extra: sftp
|
|
38
|
-
Requires-Dist: paramiko
|
|
37
|
+
Requires-Dist: paramiko>=3.4.0; extra == "sftp"
|
|
39
38
|
Provides-Extra: dumper
|
|
40
|
-
Requires-Dist: python-magic
|
|
39
|
+
Requires-Dist: python-magic>=0.4.27; extra == "dumper"
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# Rucio - Scientific Data Management
|
|
2
|
+
|
|
3
|
+
Rucio is a software framework that provides functionality to organize, manage, and access large volumes of scientific data using customisable policies.
|
|
4
|
+
The data can be spread across globally distributed locations and across heterogeneous data centers, uniting different storage and network technologies as a single federated entity.
|
|
5
|
+
Rucio offers advanced features such as distributed data recovery or adaptive replication, and is highly scalable, modular, and extensible.
|
|
6
|
+
Rucio has been originally developed to meet the requirements of the high-energy physics experiment ATLAS, and is continuously extended to support LHC experiments and other diverse scientific communities.
|
|
7
|
+
|
|
8
|
+
## Documentation
|
|
9
|
+
|
|
10
|
+
General information, API/REST description and guides can be found in our [documentation](https://rucio.cern.ch/documentation) or on our [webpage](https://rucio.cern.ch).
|
|
11
|
+
|
|
12
|
+
## Try it out
|
|
13
|
+
|
|
14
|
+
We provide a [dockerized environment](https://github.com/rucio/rucio/tree/master/etc/docker/dev) which serves both as a demo environment and a development environment.
|
|
15
|
+
It includes all the necessary preconfigured components for multiple storage and transfers developments.
|
|
16
|
+
|
|
17
|
+
## Developers
|
|
18
|
+
|
|
19
|
+
For information on how to contribute to Rucio, please refer and follow our [CONTRIBUTING](https://rucio.cern.ch/documentation/contributing) guidelines. We strongly recommend to use the [dockerized environment](https://github.com/rucio/rucio/tree/master/etc/docker/dev) for development.
|
|
20
|
+
|
|
21
|
+
## Operators
|
|
22
|
+
|
|
23
|
+
To learn how to deploy and configure Rucio, consult the [documentation](https://rucio.cern.ch/documentation) available online.
|
|
24
|
+
|
|
25
|
+
## Getting Support
|
|
26
|
+
|
|
27
|
+
If you are looking for support, please contact us via one of our [official channels](https://rucio.cern.ch/documentation/contact_us/).
|
|
@@ -30,6 +30,7 @@ from configparser import NoOptionError, NoSectionError
|
|
|
30
30
|
from copy import deepcopy
|
|
31
31
|
from datetime import datetime
|
|
32
32
|
from functools import wraps
|
|
33
|
+
from typing import Optional
|
|
33
34
|
|
|
34
35
|
from tabulate import tabulate
|
|
35
36
|
|
|
@@ -1079,6 +1080,24 @@ def download(args):
|
|
|
1079
1080
|
logger.debug(args.dids)
|
|
1080
1081
|
item_defaults['pfn'] = args.pfn
|
|
1081
1082
|
item_defaults['did'] = did_str
|
|
1083
|
+
if args.rses is None:
|
|
1084
|
+
logger.warning("No RSE was given, selecting one.")
|
|
1085
|
+
client = get_client(args)
|
|
1086
|
+
replicas = client.list_replicas(
|
|
1087
|
+
[{"scope": did_str.split(':')[0], "name": did_str.split(':')[-1]}],
|
|
1088
|
+
schemes=args.protocol,
|
|
1089
|
+
ignore_availability=False,
|
|
1090
|
+
client_location=detect_client_location(),
|
|
1091
|
+
resolve_archives=not args.no_resolve_archives
|
|
1092
|
+
)
|
|
1093
|
+
|
|
1094
|
+
download_rse = _get_rse_for_pfn(replicas, args.pfn)
|
|
1095
|
+
if download_rse is None:
|
|
1096
|
+
logger.error("Could not find RSE for pfn %s", args.pfn)
|
|
1097
|
+
return FAILURE
|
|
1098
|
+
else:
|
|
1099
|
+
item_defaults['rse'] = download_rse
|
|
1100
|
+
|
|
1082
1101
|
result = download_client.download_pfns([item_defaults], 1, trace_pattern, deactivate_file_download_exceptions=deactivate_file_download_exceptions)
|
|
1083
1102
|
|
|
1084
1103
|
if not result:
|
|
@@ -1120,6 +1139,21 @@ def download(args):
|
|
|
1120
1139
|
return SUCCESS
|
|
1121
1140
|
|
|
1122
1141
|
|
|
1142
|
+
def _get_rse_for_pfn(replicas, pfn) -> Optional[str]:
|
|
1143
|
+
# Check each rse in the replica list for the pfn. If no pfn is found, returns None.
|
|
1144
|
+
# If it is found, stop the generator and return the item.
|
|
1145
|
+
for replica in replicas:
|
|
1146
|
+
try:
|
|
1147
|
+
download_rse = next(
|
|
1148
|
+
rse for rse in replica['rses']
|
|
1149
|
+
if pfn in replica['rses'][rse]
|
|
1150
|
+
)
|
|
1151
|
+
except StopIteration:
|
|
1152
|
+
continue
|
|
1153
|
+
else:
|
|
1154
|
+
return download_rse
|
|
1155
|
+
|
|
1156
|
+
|
|
1123
1157
|
@exception_handler
|
|
1124
1158
|
def get_metadata(args):
|
|
1125
1159
|
"""
|
|
@@ -54,7 +54,7 @@ from rucio.common.exception import (
|
|
|
54
54
|
ScopeNotFound,
|
|
55
55
|
)
|
|
56
56
|
from rucio.common.extra import import_extras
|
|
57
|
-
from rucio.common.utils import StoreAndDeprecateWarningAction, chunks,
|
|
57
|
+
from rucio.common.utils import StoreAndDeprecateWarningAction, chunks, clean_pfns, construct_non_deterministic_pfn, extract_scope, get_bytes_value_from_string, parse_response, render_json, sizefmt
|
|
58
58
|
from rucio.rse import rsemanager as rsemgr
|
|
59
59
|
|
|
60
60
|
EXTRA_MODULES = import_extras(['argcomplete'])
|
|
@@ -1148,21 +1148,21 @@ def declare_bad_file_replicas(args):
|
|
|
1148
1148
|
list_bad_pfns = []
|
|
1149
1149
|
cnt += 1
|
|
1150
1150
|
previous_pattern = None
|
|
1151
|
-
for
|
|
1151
|
+
for pfn in clean_pfns(chunk):
|
|
1152
1152
|
unknown = True
|
|
1153
1153
|
if previous_pattern:
|
|
1154
|
-
if previous_pattern in
|
|
1155
|
-
list_bad_pfns.append(
|
|
1154
|
+
if previous_pattern in pfn:
|
|
1155
|
+
list_bad_pfns.append(pfn)
|
|
1156
1156
|
unknown = False
|
|
1157
1157
|
continue
|
|
1158
1158
|
for pattern in prot_dict:
|
|
1159
|
-
if pattern in
|
|
1159
|
+
if pattern in pfn:
|
|
1160
1160
|
previous_pattern = prot_dict[pattern]
|
|
1161
|
-
list_bad_pfns.append(
|
|
1161
|
+
list_bad_pfns.append(pfn)
|
|
1162
1162
|
unknown = False
|
|
1163
1163
|
break
|
|
1164
1164
|
if unknown:
|
|
1165
|
-
print('Cannot find any RSE associated to %s' %
|
|
1165
|
+
print('Cannot find any RSE associated to %s' % pfn)
|
|
1166
1166
|
client.add_bad_pfns(pfns=list_bad_pfns, reason=args.reason, state='BAD', expires_at=None)
|
|
1167
1167
|
ndeclared = len(list_bad_pfns)
|
|
1168
1168
|
tot_file_declared += ndeclared
|
|
@@ -1251,7 +1251,7 @@ def list_pfns(args):
|
|
|
1251
1251
|
logger.warning('The file has multiple parents')
|
|
1252
1252
|
for did in parents:
|
|
1253
1253
|
if did['type'] == 'DATASET':
|
|
1254
|
-
path =
|
|
1254
|
+
path = construct_non_deterministic_pfn(did['name'], scope, name, naming_convention=naming_convention)
|
|
1255
1255
|
pfn = ''.join([proto.attributes['scheme'],
|
|
1256
1256
|
'://',
|
|
1257
1257
|
proto.attributes['hostname'],
|
|
@@ -137,8 +137,6 @@ class BaseClient:
|
|
|
137
137
|
self.logger.debug('No trace_host passed. Using rucio_host instead')
|
|
138
138
|
|
|
139
139
|
self.list_hosts = [self.host]
|
|
140
|
-
self.account = account
|
|
141
|
-
self.vo = vo
|
|
142
140
|
self.ca_cert = ca_cert
|
|
143
141
|
self.auth_token = ""
|
|
144
142
|
self.headers = {}
|
|
@@ -173,7 +171,9 @@ class BaseClient:
|
|
|
173
171
|
self.logger.debug('No ca_cert found in configuration. Falling back to Mozilla default CA bundle (certifi).')
|
|
174
172
|
self.ca_cert = True
|
|
175
173
|
|
|
176
|
-
if account is None:
|
|
174
|
+
if account is not None:
|
|
175
|
+
self.account = account
|
|
176
|
+
else:
|
|
177
177
|
self.logger.debug('No account passed. Trying to get it from the RUCIO_ACCOUNT environment variable or the config file.')
|
|
178
178
|
try:
|
|
179
179
|
self.account = environ['RUCIO_ACCOUNT']
|
|
@@ -183,7 +183,9 @@ class BaseClient:
|
|
|
183
183
|
except (NoOptionError, NoSectionError):
|
|
184
184
|
pass
|
|
185
185
|
|
|
186
|
-
if vo is None:
|
|
186
|
+
if vo is not None:
|
|
187
|
+
self.vo = vo
|
|
188
|
+
else:
|
|
187
189
|
self.logger.debug('No VO passed. Trying to get it from environment variable RUCIO_VO.')
|
|
188
190
|
try:
|
|
189
191
|
self.vo = environ['RUCIO_VO']
|
|
@@ -239,57 +241,62 @@ class BaseClient:
|
|
|
239
241
|
return auth_type
|
|
240
242
|
|
|
241
243
|
def _get_creds(self, creds: Optional[dict[str, Any]]) -> dict[str, Any]:
|
|
242
|
-
if
|
|
243
|
-
if not creds:
|
|
244
|
-
creds = {}
|
|
245
|
-
# if there are default values, check if rucio.cfg does not specify them, otherwise put default
|
|
246
|
-
if 'oidc_refresh_lifetime' not in creds or creds['oidc_refresh_lifetime'] is None:
|
|
247
|
-
creds['oidc_refresh_lifetime'] = config_get('client', 'oidc_refresh_lifetime', False, None)
|
|
248
|
-
if 'oidc_issuer' not in creds or creds['oidc_issuer'] is None:
|
|
249
|
-
creds['oidc_issuer'] = config_get('client', 'oidc_issuer', False, None)
|
|
250
|
-
if 'oidc_audience' not in creds or creds['oidc_audience'] is None:
|
|
251
|
-
creds['oidc_audience'] = config_get('client', 'oidc_audience', False, None)
|
|
252
|
-
if 'oidc_auto' not in creds or creds['oidc_auto'] is False:
|
|
253
|
-
creds['oidc_auto'] = config_get_bool('client', 'oidc_auto', False, False)
|
|
254
|
-
if creds['oidc_auto']:
|
|
255
|
-
if 'oidc_username' not in creds or creds['oidc_username'] is None:
|
|
256
|
-
creds['oidc_username'] = config_get('client', 'oidc_username', False, None)
|
|
257
|
-
if 'oidc_password' not in creds or creds['oidc_password'] is None:
|
|
258
|
-
creds['oidc_password'] = config_get('client', 'oidc_password', False, None)
|
|
259
|
-
if 'oidc_scope' not in creds or creds['oidc_scope'] == 'openid profile':
|
|
260
|
-
creds['oidc_scope'] = config_get('client', 'oidc_scope', False, 'openid profile')
|
|
261
|
-
if 'oidc_polling' not in creds or creds['oidc_polling'] is False:
|
|
262
|
-
creds['oidc_polling'] = config_get_bool('client', 'oidc_polling', False, False)
|
|
263
|
-
|
|
264
|
-
if creds is None:
|
|
244
|
+
if not creds:
|
|
265
245
|
self.logger.debug('No creds passed. Trying to get it from the config file.')
|
|
266
246
|
creds = {}
|
|
267
|
-
|
|
268
|
-
|
|
247
|
+
|
|
248
|
+
try:
|
|
249
|
+
if self.auth_type == 'oidc':
|
|
250
|
+
# if there are default values, check if rucio.cfg does not specify them, otherwise put default
|
|
251
|
+
if 'oidc_refresh_lifetime' not in creds or creds['oidc_refresh_lifetime'] is None:
|
|
252
|
+
creds['oidc_refresh_lifetime'] = config_get('client', 'oidc_refresh_lifetime', False, None)
|
|
253
|
+
if 'oidc_issuer' not in creds or creds['oidc_issuer'] is None:
|
|
254
|
+
creds['oidc_issuer'] = config_get('client', 'oidc_issuer', False, None)
|
|
255
|
+
if 'oidc_audience' not in creds or creds['oidc_audience'] is None:
|
|
256
|
+
creds['oidc_audience'] = config_get('client', 'oidc_audience', False, None)
|
|
257
|
+
if 'oidc_auto' not in creds or creds['oidc_auto'] is False:
|
|
258
|
+
creds['oidc_auto'] = config_get_bool('client', 'oidc_auto', False, False)
|
|
259
|
+
if creds['oidc_auto']:
|
|
260
|
+
if 'oidc_username' not in creds or creds['oidc_username'] is None:
|
|
261
|
+
creds['oidc_username'] = config_get('client', 'oidc_username', False, None)
|
|
262
|
+
if 'oidc_password' not in creds or creds['oidc_password'] is None:
|
|
263
|
+
creds['oidc_password'] = config_get('client', 'oidc_password', False, None)
|
|
264
|
+
if 'oidc_scope' not in creds or creds['oidc_scope'] == 'openid profile':
|
|
265
|
+
creds['oidc_scope'] = config_get('client', 'oidc_scope', False, 'openid profile')
|
|
266
|
+
if 'oidc_polling' not in creds or creds['oidc_polling'] is False:
|
|
267
|
+
creds['oidc_polling'] = config_get_bool('client', 'oidc_polling', False, False)
|
|
268
|
+
|
|
269
|
+
elif self.auth_type in ['userpass', 'saml']:
|
|
270
|
+
if 'username' not in creds or creds['username'] is None:
|
|
269
271
|
creds['username'] = config_get('client', 'username')
|
|
272
|
+
if 'password' not in creds or creds['password'] is None:
|
|
270
273
|
creds['password'] = config_get('client', 'password')
|
|
271
|
-
|
|
274
|
+
|
|
275
|
+
elif self.auth_type == 'x509':
|
|
276
|
+
if 'client_cert' not in creds or creds['client_cert'] is None:
|
|
272
277
|
if "RUCIO_CLIENT_CERT" in environ:
|
|
273
|
-
client_cert = environ["RUCIO_CLIENT_CERT"]
|
|
278
|
+
creds['client_cert'] = environ["RUCIO_CLIENT_CERT"]
|
|
274
279
|
else:
|
|
275
|
-
client_cert = config_get('client', 'client_cert')
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
280
|
+
creds['client_cert'] = config_get('client', 'client_cert')
|
|
281
|
+
creds['client_cert'] = path.abspath(path.expanduser(path.expandvars(creds['client_cert'])))
|
|
282
|
+
if not path.exists(creds['client_cert']):
|
|
283
|
+
raise MissingClientParameter('X.509 client certificate not found: %s' % creds['client_cert'])
|
|
279
284
|
|
|
285
|
+
if 'client_key' not in creds or creds['client_key'] is None:
|
|
280
286
|
if "RUCIO_CLIENT_KEY" in environ:
|
|
281
|
-
client_key = environ["RUCIO_CLIENT_KEY"]
|
|
282
|
-
else:
|
|
283
|
-
client_key = config_get('client', 'client_key')
|
|
284
|
-
creds['client_key'] = path.abspath(path.expanduser(path.expandvars(client_key)))
|
|
285
|
-
if not path.exists(creds['client_key']):
|
|
286
|
-
raise MissingClientParameter('X.509 client key not found: %s' % creds['client_key'])
|
|
287
|
+
creds['client_key'] = environ["RUCIO_CLIENT_KEY"]
|
|
287
288
|
else:
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
289
|
+
creds['client_key'] = config_get('client', 'client_key')
|
|
290
|
+
creds['client_key'] = path.abspath(path.expanduser(path.expandvars(creds['client_key'])))
|
|
291
|
+
if not path.exists(creds['client_key']):
|
|
292
|
+
raise MissingClientParameter('X.509 client key not found: %s' % creds['client_key'])
|
|
293
|
+
else:
|
|
294
|
+
perms = oct(os.stat(creds['client_key']).st_mode)[-3:]
|
|
295
|
+
if perms not in ['400', '600']:
|
|
296
|
+
raise CannotAuthenticate('X.509 authentication selected, but private key (%s) permissions are liberal (required: 400 or 600, found: %s)' % (creds['client_key'], perms))
|
|
291
297
|
|
|
292
|
-
|
|
298
|
+
elif self.auth_type == 'x509_proxy':
|
|
299
|
+
if 'client_proxy' not in creds or creds['client_proxy'] is None:
|
|
293
300
|
try:
|
|
294
301
|
creds['client_proxy'] = path.abspath(path.expanduser(path.expandvars(config_get('client', 'client_x509_proxy'))))
|
|
295
302
|
except NoOptionError:
|
|
@@ -307,11 +314,15 @@ class BaseClient:
|
|
|
307
314
|
raise MissingClientParameter(
|
|
308
315
|
'Cannot find a valid X509 proxy; not in %s, $X509_USER_PROXY not set, and '
|
|
309
316
|
'\'x509_proxy\' not set in the configuration file.' % fname)
|
|
310
|
-
|
|
317
|
+
|
|
318
|
+
elif self.auth_type == 'ssh':
|
|
319
|
+
if 'ssh_private_key' not in creds or creds['ssh_private_key'] is None:
|
|
311
320
|
creds['ssh_private_key'] = path.abspath(path.expanduser(path.expandvars(config_get('client', 'ssh_private_key'))))
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
321
|
+
|
|
322
|
+
except (NoOptionError, NoSectionError) as error:
|
|
323
|
+
if error.args[0] != 'client_key':
|
|
324
|
+
raise MissingClientParameter('Option \'%s\' cannot be found in config file' % error.args[0])
|
|
325
|
+
|
|
315
326
|
return creds
|
|
316
327
|
|
|
317
328
|
def _get_exception(self, headers: dict[str, str], status_code: Optional[int] = None, data=None) -> tuple[type[exception.RucioException], str]:
|
|
@@ -21,7 +21,7 @@ from requests.status_codes import codes
|
|
|
21
21
|
|
|
22
22
|
from rucio.client.baseclient import BaseClient, choice
|
|
23
23
|
from rucio.common.exception import DeprecationError
|
|
24
|
-
from rucio.common.utils import build_url, date_to_str, render_json
|
|
24
|
+
from rucio.common.utils import build_url, date_to_str, render_json
|
|
25
25
|
|
|
26
26
|
if TYPE_CHECKING:
|
|
27
27
|
from collections.abc import Iterable, Iterator, Mapping, Sequence
|
|
@@ -142,7 +142,7 @@ class DIDClient(BaseClient):
|
|
|
142
142
|
"""
|
|
143
143
|
path = '/'.join([self.DIDS_BASEURL])
|
|
144
144
|
url = build_url(choice(self.list_hosts), path=path)
|
|
145
|
-
r = self._send_request(url, type_='POST', data=
|
|
145
|
+
r = self._send_request(url, type_='POST', data=render_json(dids))
|
|
146
146
|
if r.status_code == codes.created:
|
|
147
147
|
return True
|
|
148
148
|
else:
|
|
@@ -25,7 +25,7 @@ import subprocess
|
|
|
25
25
|
import time
|
|
26
26
|
from queue import Empty, Queue, deque
|
|
27
27
|
from threading import Thread
|
|
28
|
-
from typing import Any, Optional
|
|
28
|
+
from typing import TYPE_CHECKING, Any, Optional
|
|
29
29
|
|
|
30
30
|
from rucio import version
|
|
31
31
|
from rucio.client.client import Client
|
|
@@ -36,6 +36,13 @@ from rucio.common.pcache import Pcache
|
|
|
36
36
|
from rucio.common.utils import CHECKSUM_ALGO_DICT, GLOBALLY_SUPPORTED_CHECKSUMS, PREFERRED_CHECKSUM, adler32, detect_client_location, execute, extract_scope, generate_uuid, parse_replicas_from_file, parse_replicas_from_string, send_trace, sizefmt
|
|
37
37
|
from rucio.rse import rsemanager as rsemgr
|
|
38
38
|
|
|
39
|
+
if TYPE_CHECKING:
|
|
40
|
+
from collections.abc import Iterable, Iterator
|
|
41
|
+
from xmlrpc.client import ServerProxy as RPCServerProxy
|
|
42
|
+
|
|
43
|
+
from rucio.common.constants import SORTING_ALGORITHMS_LITERAL
|
|
44
|
+
from rucio.common.types import LoggerFunction
|
|
45
|
+
|
|
39
46
|
|
|
40
47
|
@enum.unique
|
|
41
48
|
class FileDownloadState(str, enum.Enum):
|
|
@@ -54,7 +61,13 @@ class FileDownloadState(str, enum.Enum):
|
|
|
54
61
|
|
|
55
62
|
class BaseExtractionTool:
|
|
56
63
|
|
|
57
|
-
def __init__(
|
|
64
|
+
def __init__(
|
|
65
|
+
self,
|
|
66
|
+
program_name: str,
|
|
67
|
+
useability_check_args: str,
|
|
68
|
+
extract_args: str,
|
|
69
|
+
logger: "LoggerFunction" = logging.log
|
|
70
|
+
):
|
|
58
71
|
"""
|
|
59
72
|
Initialises a extraction tool object
|
|
60
73
|
|
|
@@ -69,7 +82,7 @@ class BaseExtractionTool:
|
|
|
69
82
|
self.logger = logger
|
|
70
83
|
self.is_useable_result = None
|
|
71
84
|
|
|
72
|
-
def is_useable(self):
|
|
85
|
+
def is_useable(self) -> bool:
|
|
73
86
|
"""
|
|
74
87
|
Checks if the extraction tool is installed and usable
|
|
75
88
|
|
|
@@ -89,7 +102,12 @@ class BaseExtractionTool:
|
|
|
89
102
|
self.logger(logging.DEBUG, error)
|
|
90
103
|
return self.is_usable_result
|
|
91
104
|
|
|
92
|
-
def try_extraction(
|
|
105
|
+
def try_extraction(
|
|
106
|
+
self,
|
|
107
|
+
archive_file_path: str,
|
|
108
|
+
file_to_extract: str,
|
|
109
|
+
dest_dir_path: str
|
|
110
|
+
) -> bool:
|
|
93
111
|
"""
|
|
94
112
|
Calls the extraction program to extract a file from an archive
|
|
95
113
|
|
|
@@ -119,7 +137,14 @@ class BaseExtractionTool:
|
|
|
119
137
|
|
|
120
138
|
class DownloadClient:
|
|
121
139
|
|
|
122
|
-
def __init__(
|
|
140
|
+
def __init__(
|
|
141
|
+
self,
|
|
142
|
+
client: Optional[Client] = None,
|
|
143
|
+
logger: Optional["LoggerFunction"] = None,
|
|
144
|
+
tracing: bool = True,
|
|
145
|
+
check_admin: bool = False,
|
|
146
|
+
check_pcache: bool = False
|
|
147
|
+
):
|
|
123
148
|
"""
|
|
124
149
|
Initialises the basic settings for an DownloadClient object
|
|
125
150
|
|
|
@@ -272,7 +297,7 @@ class DownloadClient:
|
|
|
272
297
|
trace_custom_fields: Optional[dict[str, Any]] = None,
|
|
273
298
|
traces_copy_out: Optional[list[dict[str, Any]]] = None,
|
|
274
299
|
deactivate_file_download_exceptions: bool = False,
|
|
275
|
-
sort: Optional[
|
|
300
|
+
sort: Optional["SORTING_ALGORITHMS_LITERAL"] = None
|
|
276
301
|
) -> list[dict[str, Any]]:
|
|
277
302
|
"""
|
|
278
303
|
Download items with given DIDs. This function can also download datasets and wildcarded DIDs.
|
|
@@ -445,7 +470,14 @@ class DownloadClient:
|
|
|
445
470
|
thread.kill_received = True
|
|
446
471
|
return list(output_queue.queue)
|
|
447
472
|
|
|
448
|
-
def _download_worker(
|
|
473
|
+
def _download_worker(
|
|
474
|
+
self,
|
|
475
|
+
input_queue: Queue,
|
|
476
|
+
output_queue: Queue,
|
|
477
|
+
trace_custom_fields: dict[str, Any],
|
|
478
|
+
traces_copy_out: Optional[list[dict[str, Any]]],
|
|
479
|
+
log_prefix: str
|
|
480
|
+
) -> None:
|
|
449
481
|
"""
|
|
450
482
|
This function runs as long as there are items in the input queue,
|
|
451
483
|
downloads them and stores the output in the output queue.
|
|
@@ -481,7 +513,7 @@ class DownloadClient:
|
|
|
481
513
|
output_queue.put(item)
|
|
482
514
|
|
|
483
515
|
@staticmethod
|
|
484
|
-
def _compute_actual_transfer_timeout(item):
|
|
516
|
+
def _compute_actual_transfer_timeout(item: dict[str, Any]) -> int:
|
|
485
517
|
"""
|
|
486
518
|
Merge the two options related to timeout into the value which will be used for protocol download.
|
|
487
519
|
:param item: dictionary that describes the item to download
|
|
@@ -493,11 +525,11 @@ class DownloadClient:
|
|
|
493
525
|
# establishing connections and download of small files
|
|
494
526
|
transfer_speed_timeout_static_increment = 60
|
|
495
527
|
|
|
496
|
-
transfer_timeout = item.get('merged_options', {}).get('transfer_timeout')
|
|
528
|
+
transfer_timeout: Optional[int] = item.get('merged_options', {}).get('transfer_timeout')
|
|
497
529
|
if transfer_timeout is not None:
|
|
498
530
|
return transfer_timeout
|
|
499
531
|
|
|
500
|
-
transfer_speed_timeout = item.get('merged_options', {}).get('transfer_speed_timeout')
|
|
532
|
+
transfer_speed_timeout: Optional[int] = item.get('merged_options', {}).get('transfer_speed_timeout')
|
|
501
533
|
bytes_ = item.get('bytes')
|
|
502
534
|
if not bytes_ or transfer_speed_timeout is None:
|
|
503
535
|
return default_transfer_timeout
|
|
@@ -510,7 +542,13 @@ class DownloadClient:
|
|
|
510
542
|
timeout = bytes_ // transfer_speed_timeout + transfer_speed_timeout_static_increment
|
|
511
543
|
return timeout
|
|
512
544
|
|
|
513
|
-
def _download_item(
|
|
545
|
+
def _download_item(
|
|
546
|
+
self,
|
|
547
|
+
item: dict[str, Any],
|
|
548
|
+
trace: dict[str, Any],
|
|
549
|
+
traces_copy_out: Optional[list[dict[str, Any]]],
|
|
550
|
+
log_prefix: str = ''
|
|
551
|
+
) -> dict[str, Any]:
|
|
514
552
|
"""
|
|
515
553
|
Downloads the given item and sends traces for success/failure.
|
|
516
554
|
(This function is meant to be used as class internal only)
|
|
@@ -775,7 +813,7 @@ class DownloadClient:
|
|
|
775
813
|
trace_custom_fields: Optional[dict[str, Any]] = None,
|
|
776
814
|
filters: Optional[dict[str, Any]] = None,
|
|
777
815
|
deactivate_file_download_exceptions: bool = False,
|
|
778
|
-
sort: Optional[
|
|
816
|
+
sort: Optional["SORTING_ALGORITHMS_LITERAL"] = None
|
|
779
817
|
) -> list[dict[str, Any]]:
|
|
780
818
|
"""
|
|
781
819
|
Uses aria2c to download the items with given DIDs. This function can also download datasets and wildcarded DIDs.
|
|
@@ -838,7 +876,7 @@ class DownloadClient:
|
|
|
838
876
|
|
|
839
877
|
return self._check_output(output_items, deactivate_file_download_exceptions=deactivate_file_download_exceptions)
|
|
840
878
|
|
|
841
|
-
def _start_aria2c_rpc(self, rpc_secret):
|
|
879
|
+
def _start_aria2c_rpc(self, rpc_secret: str) -> tuple[subprocess.Popen, "RPCServerProxy"]:
|
|
842
880
|
"""
|
|
843
881
|
Starts aria2c in RPC mode as a subprocess. Also creates
|
|
844
882
|
the RPC proxy instance.
|
|
@@ -1072,7 +1110,7 @@ class DownloadClient:
|
|
|
1072
1110
|
|
|
1073
1111
|
return items
|
|
1074
1112
|
|
|
1075
|
-
def _resolve_one_item_dids(self, item):
|
|
1113
|
+
def _resolve_one_item_dids(self, item: dict[str, Any]) -> "Iterator[dict[str, Any]]":
|
|
1076
1114
|
"""
|
|
1077
1115
|
Resolve scopes or wildcard DIDs to lists of full did names:
|
|
1078
1116
|
:param item: One input item
|
|
@@ -1105,7 +1143,11 @@ class DownloadClient:
|
|
|
1105
1143
|
if not any_did_resolved and '*' not in did_name:
|
|
1106
1144
|
yield {'scope': scope, 'name': did_name}
|
|
1107
1145
|
|
|
1108
|
-
def _resolve_and_merge_input_items(
|
|
1146
|
+
def _resolve_and_merge_input_items(
|
|
1147
|
+
self,
|
|
1148
|
+
input_items: list[dict[str, Any]],
|
|
1149
|
+
sort: Optional["SORTING_ALGORITHMS_LITERAL"] = None
|
|
1150
|
+
) -> tuple[dict[str, Any], list[dict[str, Any]]]:
|
|
1109
1151
|
"""
|
|
1110
1152
|
This function takes the input items given to download_dids etc.
|
|
1111
1153
|
and resolves the sources.
|
|
@@ -1282,7 +1324,7 @@ class DownloadClient:
|
|
|
1282
1324
|
|
|
1283
1325
|
return did_to_input_items, merged_items_with_sources
|
|
1284
1326
|
|
|
1285
|
-
def _options_from_input_items(self, input_items):
|
|
1327
|
+
def _options_from_input_items(self, input_items: "Iterable[dict[str, Any]]") -> dict[str, Any]:
|
|
1286
1328
|
"""
|
|
1287
1329
|
Best-effort generation of download options from multiple input items which resolve to the same file DID.
|
|
1288
1330
|
This is done to download each file DID only once, even if it is requested multiple times via overlapping
|
|
@@ -1323,7 +1365,11 @@ class DownloadClient:
|
|
|
1323
1365
|
options['transfer_speed_timeout'] = float(new_transfer_speed_timeout)
|
|
1324
1366
|
return options
|
|
1325
1367
|
|
|
1326
|
-
def _prepare_items_for_download(
|
|
1368
|
+
def _prepare_items_for_download(
|
|
1369
|
+
self,
|
|
1370
|
+
did_to_input_items: dict[str, Any],
|
|
1371
|
+
file_items: list[dict[str, Any]]
|
|
1372
|
+
) -> list[dict[str, Any]]:
|
|
1327
1373
|
"""
|
|
1328
1374
|
Optimises the amount of files to download
|
|
1329
1375
|
(This function is meant to be used as class internal only)
|
|
@@ -1550,7 +1596,7 @@ class DownloadClient:
|
|
|
1550
1596
|
download_packs.append(file_item)
|
|
1551
1597
|
return download_packs
|
|
1552
1598
|
|
|
1553
|
-
def _split_did_str(self, did_str):
|
|
1599
|
+
def _split_did_str(self, did_str: str) -> tuple[str, str]:
|
|
1554
1600
|
"""
|
|
1555
1601
|
Splits a given DID string (e.g. 'scope1:name.file') into its scope and name part
|
|
1556
1602
|
(This function is meant to be used as class internal only)
|
|
@@ -1583,7 +1629,12 @@ class DownloadClient:
|
|
|
1583
1629
|
|
|
1584
1630
|
return did_scope, did_name
|
|
1585
1631
|
|
|
1586
|
-
def _prepare_dest_dir(
|
|
1632
|
+
def _prepare_dest_dir(
|
|
1633
|
+
self,
|
|
1634
|
+
base_dir: str,
|
|
1635
|
+
dest_dir_name: str,
|
|
1636
|
+
no_subdir: Optional[bool]
|
|
1637
|
+
) -> str:
|
|
1587
1638
|
"""
|
|
1588
1639
|
Builds the final destination path for a file and creates the
|
|
1589
1640
|
destination directory if it's not existent.
|
|
@@ -1605,7 +1656,11 @@ class DownloadClient:
|
|
|
1605
1656
|
|
|
1606
1657
|
return dest_dir_path
|
|
1607
1658
|
|
|
1608
|
-
def _check_output(
|
|
1659
|
+
def _check_output(
|
|
1660
|
+
self,
|
|
1661
|
+
output_items: list[dict[str, Any]],
|
|
1662
|
+
deactivate_file_download_exceptions: bool = False
|
|
1663
|
+
) -> list[dict[str, Any]]:
|
|
1609
1664
|
"""
|
|
1610
1665
|
Checks if all files were successfully downloaded
|
|
1611
1666
|
(This function is meant to be used as class internal only)
|
|
@@ -1635,7 +1690,7 @@ class DownloadClient:
|
|
|
1635
1690
|
|
|
1636
1691
|
return output_items
|
|
1637
1692
|
|
|
1638
|
-
def _send_trace(self, trace):
|
|
1693
|
+
def _send_trace(self, trace: dict[str, Any]) -> None:
|
|
1639
1694
|
"""
|
|
1640
1695
|
Checks if sending trace is allowed and send the trace.
|
|
1641
1696
|
|
|
@@ -1644,7 +1699,7 @@ class DownloadClient:
|
|
|
1644
1699
|
if self.tracing:
|
|
1645
1700
|
send_trace(trace, self.client.trace_host, self.client.user_agent)
|
|
1646
1701
|
|
|
1647
|
-
def preferred_impl(self, sources):
|
|
1702
|
+
def preferred_impl(self, sources: list[dict[str, Any]]) -> Optional[str]:
|
|
1648
1703
|
"""
|
|
1649
1704
|
Finds the optimum protocol impl preferred by the client and
|
|
1650
1705
|
supported by the remote RSE.
|
|
@@ -1708,7 +1763,10 @@ class DownloadClient:
|
|
|
1708
1763
|
return supported_impl
|
|
1709
1764
|
|
|
1710
1765
|
|
|
1711
|
-
def _verify_checksum(
|
|
1766
|
+
def _verify_checksum(
|
|
1767
|
+
item: dict[str, Any],
|
|
1768
|
+
path: str
|
|
1769
|
+
) -> tuple[bool, Optional[str], Optional[str]]:
|
|
1712
1770
|
rucio_checksum = item.get(PREFERRED_CHECKSUM)
|
|
1713
1771
|
local_checksum = None
|
|
1714
1772
|
checksum_algo = CHECKSUM_ALGO_DICT.get(PREFERRED_CHECKSUM)
|
|
@@ -93,7 +93,7 @@ class SubscriptionClient(BaseClient):
|
|
|
93
93
|
if name:
|
|
94
94
|
path += '/%s' % (name)
|
|
95
95
|
elif name:
|
|
96
|
-
path += '/
|
|
96
|
+
path += '/name/%s' % (name)
|
|
97
97
|
else:
|
|
98
98
|
path += '/'
|
|
99
99
|
url = build_url(choice(self.list_hosts), path=path)
|
|
@@ -163,7 +163,7 @@ class SubscriptionClient(BaseClient):
|
|
|
163
163
|
:param name: Name of the subscription.
|
|
164
164
|
"""
|
|
165
165
|
|
|
166
|
-
path = '/'.join([self.SUB_BASEURL, account, name, '
|
|
166
|
+
path = '/'.join([self.SUB_BASEURL, account, name, 'rules'])
|
|
167
167
|
url = build_url(choice(self.list_hosts), path=path)
|
|
168
168
|
result = self._send_request(url, type_='GET')
|
|
169
169
|
if result.status_code == codes.ok: # pylint: disable=no-member
|