rucio 32.8.6__py3-none-any.whl → 35.8.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of rucio might be problematic. Click here for more details.

Files changed (502) hide show
  1. rucio/__init__.py +0 -1
  2. rucio/alembicrevision.py +1 -2
  3. rucio/client/__init__.py +0 -1
  4. rucio/client/accountclient.py +45 -25
  5. rucio/client/accountlimitclient.py +37 -9
  6. rucio/client/baseclient.py +199 -154
  7. rucio/client/client.py +2 -3
  8. rucio/client/configclient.py +19 -6
  9. rucio/client/credentialclient.py +9 -4
  10. rucio/client/didclient.py +238 -63
  11. rucio/client/diracclient.py +13 -5
  12. rucio/client/downloadclient.py +162 -51
  13. rucio/client/exportclient.py +4 -4
  14. rucio/client/fileclient.py +3 -4
  15. rucio/client/importclient.py +4 -4
  16. rucio/client/lifetimeclient.py +21 -5
  17. rucio/client/lockclient.py +18 -8
  18. rucio/client/{metaclient.py → metaconventionsclient.py} +18 -15
  19. rucio/client/pingclient.py +0 -1
  20. rucio/client/replicaclient.py +15 -5
  21. rucio/client/requestclient.py +35 -19
  22. rucio/client/rseclient.py +133 -51
  23. rucio/client/ruleclient.py +29 -22
  24. rucio/client/scopeclient.py +8 -6
  25. rucio/client/subscriptionclient.py +47 -35
  26. rucio/client/touchclient.py +8 -4
  27. rucio/client/uploadclient.py +166 -82
  28. rucio/common/__init__.py +0 -1
  29. rucio/common/cache.py +4 -4
  30. rucio/common/config.py +52 -47
  31. rucio/common/constants.py +69 -2
  32. rucio/common/constraints.py +0 -1
  33. rucio/common/didtype.py +24 -22
  34. rucio/common/dumper/__init__.py +70 -41
  35. rucio/common/dumper/consistency.py +26 -22
  36. rucio/common/dumper/data_models.py +16 -23
  37. rucio/common/dumper/path_parsing.py +0 -1
  38. rucio/common/exception.py +281 -222
  39. rucio/common/extra.py +0 -1
  40. rucio/common/logging.py +54 -38
  41. rucio/common/pcache.py +122 -101
  42. rucio/common/plugins.py +153 -0
  43. rucio/common/policy.py +4 -4
  44. rucio/common/schema/__init__.py +17 -10
  45. rucio/common/schema/atlas.py +7 -5
  46. rucio/common/schema/belleii.py +7 -5
  47. rucio/common/schema/domatpc.py +7 -5
  48. rucio/common/schema/escape.py +7 -5
  49. rucio/common/schema/generic.py +8 -6
  50. rucio/common/schema/generic_multi_vo.py +7 -5
  51. rucio/common/schema/icecube.py +7 -5
  52. rucio/common/stomp_utils.py +0 -1
  53. rucio/common/stopwatch.py +0 -1
  54. rucio/common/test_rucio_server.py +2 -2
  55. rucio/common/types.py +262 -17
  56. rucio/common/utils.py +743 -451
  57. rucio/core/__init__.py +0 -1
  58. rucio/core/account.py +99 -29
  59. rucio/core/account_counter.py +89 -24
  60. rucio/core/account_limit.py +90 -24
  61. rucio/core/authentication.py +86 -29
  62. rucio/core/config.py +108 -38
  63. rucio/core/credential.py +14 -7
  64. rucio/core/did.py +680 -782
  65. rucio/core/did_meta_plugins/__init__.py +8 -6
  66. rucio/core/did_meta_plugins/did_column_meta.py +17 -12
  67. rucio/core/did_meta_plugins/did_meta_plugin_interface.py +60 -11
  68. rucio/core/did_meta_plugins/filter_engine.py +90 -50
  69. rucio/core/did_meta_plugins/json_meta.py +41 -16
  70. rucio/core/did_meta_plugins/mongo_meta.py +25 -8
  71. rucio/core/did_meta_plugins/postgres_meta.py +3 -4
  72. rucio/core/dirac.py +46 -17
  73. rucio/core/distance.py +66 -43
  74. rucio/core/exporter.py +5 -5
  75. rucio/core/heartbeat.py +181 -81
  76. rucio/core/identity.py +22 -12
  77. rucio/core/importer.py +23 -12
  78. rucio/core/lifetime_exception.py +32 -32
  79. rucio/core/lock.py +244 -142
  80. rucio/core/message.py +79 -38
  81. rucio/core/{meta.py → meta_conventions.py} +57 -44
  82. rucio/core/monitor.py +19 -13
  83. rucio/core/naming_convention.py +68 -27
  84. rucio/core/nongrid_trace.py +17 -5
  85. rucio/core/oidc.py +151 -29
  86. rucio/core/permission/__init__.py +18 -6
  87. rucio/core/permission/atlas.py +50 -35
  88. rucio/core/permission/belleii.py +6 -5
  89. rucio/core/permission/escape.py +8 -6
  90. rucio/core/permission/generic.py +82 -80
  91. rucio/core/permission/generic_multi_vo.py +9 -7
  92. rucio/core/quarantined_replica.py +91 -58
  93. rucio/core/replica.py +1303 -772
  94. rucio/core/replica_sorter.py +10 -12
  95. rucio/core/request.py +1133 -285
  96. rucio/core/rse.py +142 -102
  97. rucio/core/rse_counter.py +49 -18
  98. rucio/core/rse_expression_parser.py +6 -7
  99. rucio/core/rse_selector.py +41 -16
  100. rucio/core/rule.py +1538 -474
  101. rucio/core/rule_grouping.py +213 -68
  102. rucio/core/scope.py +50 -22
  103. rucio/core/subscription.py +92 -44
  104. rucio/core/topology.py +66 -24
  105. rucio/core/trace.py +42 -28
  106. rucio/core/transfer.py +543 -259
  107. rucio/core/vo.py +36 -18
  108. rucio/core/volatile_replica.py +59 -32
  109. rucio/daemons/__init__.py +0 -1
  110. rucio/daemons/abacus/__init__.py +0 -1
  111. rucio/daemons/abacus/account.py +29 -19
  112. rucio/daemons/abacus/collection_replica.py +21 -10
  113. rucio/daemons/abacus/rse.py +22 -12
  114. rucio/daemons/atropos/__init__.py +0 -1
  115. rucio/daemons/atropos/atropos.py +1 -2
  116. rucio/daemons/auditor/__init__.py +56 -28
  117. rucio/daemons/auditor/hdfs.py +17 -6
  118. rucio/daemons/auditor/srmdumps.py +116 -45
  119. rucio/daemons/automatix/__init__.py +0 -1
  120. rucio/daemons/automatix/automatix.py +30 -18
  121. rucio/daemons/badreplicas/__init__.py +0 -1
  122. rucio/daemons/badreplicas/minos.py +29 -18
  123. rucio/daemons/badreplicas/minos_temporary_expiration.py +5 -7
  124. rucio/daemons/badreplicas/necromancer.py +9 -13
  125. rucio/daemons/bb8/__init__.py +0 -1
  126. rucio/daemons/bb8/bb8.py +10 -13
  127. rucio/daemons/bb8/common.py +151 -154
  128. rucio/daemons/bb8/nuclei_background_rebalance.py +15 -9
  129. rucio/daemons/bb8/t2_background_rebalance.py +15 -8
  130. rucio/daemons/c3po/__init__.py +0 -1
  131. rucio/daemons/c3po/algorithms/__init__.py +0 -1
  132. rucio/daemons/c3po/algorithms/simple.py +8 -5
  133. rucio/daemons/c3po/algorithms/t2_free_space.py +10 -7
  134. rucio/daemons/c3po/algorithms/t2_free_space_only_pop.py +10 -7
  135. rucio/daemons/c3po/algorithms/t2_free_space_only_pop_with_network.py +30 -15
  136. rucio/daemons/c3po/c3po.py +81 -52
  137. rucio/daemons/c3po/collectors/__init__.py +0 -1
  138. rucio/daemons/c3po/collectors/agis.py +17 -17
  139. rucio/daemons/c3po/collectors/free_space.py +32 -13
  140. rucio/daemons/c3po/collectors/jedi_did.py +14 -5
  141. rucio/daemons/c3po/collectors/mock_did.py +11 -6
  142. rucio/daemons/c3po/collectors/network_metrics.py +12 -4
  143. rucio/daemons/c3po/collectors/workload.py +21 -19
  144. rucio/daemons/c3po/utils/__init__.py +0 -1
  145. rucio/daemons/c3po/utils/dataset_cache.py +15 -5
  146. rucio/daemons/c3po/utils/expiring_dataset_cache.py +16 -5
  147. rucio/daemons/c3po/utils/expiring_list.py +6 -7
  148. rucio/daemons/c3po/utils/popularity.py +5 -2
  149. rucio/daemons/c3po/utils/timeseries.py +25 -12
  150. rucio/daemons/cache/__init__.py +0 -1
  151. rucio/daemons/cache/consumer.py +21 -15
  152. rucio/daemons/common.py +42 -18
  153. rucio/daemons/conveyor/__init__.py +0 -1
  154. rucio/daemons/conveyor/common.py +69 -37
  155. rucio/daemons/conveyor/finisher.py +83 -46
  156. rucio/daemons/conveyor/poller.py +101 -69
  157. rucio/daemons/conveyor/preparer.py +35 -28
  158. rucio/daemons/conveyor/receiver.py +64 -21
  159. rucio/daemons/conveyor/stager.py +33 -28
  160. rucio/daemons/conveyor/submitter.py +71 -47
  161. rucio/daemons/conveyor/throttler.py +99 -35
  162. rucio/daemons/follower/__init__.py +0 -1
  163. rucio/daemons/follower/follower.py +12 -8
  164. rucio/daemons/hermes/__init__.py +0 -1
  165. rucio/daemons/hermes/hermes.py +57 -21
  166. rucio/daemons/judge/__init__.py +0 -1
  167. rucio/daemons/judge/cleaner.py +27 -17
  168. rucio/daemons/judge/evaluator.py +31 -18
  169. rucio/daemons/judge/injector.py +31 -23
  170. rucio/daemons/judge/repairer.py +28 -18
  171. rucio/daemons/oauthmanager/__init__.py +0 -1
  172. rucio/daemons/oauthmanager/oauthmanager.py +7 -8
  173. rucio/daemons/reaper/__init__.py +0 -1
  174. rucio/daemons/reaper/dark_reaper.py +15 -9
  175. rucio/daemons/reaper/reaper.py +109 -67
  176. rucio/daemons/replicarecoverer/__init__.py +0 -1
  177. rucio/daemons/replicarecoverer/suspicious_replica_recoverer.py +255 -116
  178. rucio/{api → daemons/rsedecommissioner}/__init__.py +0 -1
  179. rucio/daemons/rsedecommissioner/config.py +81 -0
  180. rucio/daemons/rsedecommissioner/profiles/__init__.py +24 -0
  181. rucio/daemons/rsedecommissioner/profiles/atlas.py +60 -0
  182. rucio/daemons/rsedecommissioner/profiles/generic.py +451 -0
  183. rucio/daemons/rsedecommissioner/profiles/types.py +92 -0
  184. rucio/daemons/rsedecommissioner/rse_decommissioner.py +280 -0
  185. rucio/daemons/storage/__init__.py +0 -1
  186. rucio/daemons/storage/consistency/__init__.py +0 -1
  187. rucio/daemons/storage/consistency/actions.py +152 -59
  188. rucio/daemons/tracer/__init__.py +0 -1
  189. rucio/daemons/tracer/kronos.py +47 -24
  190. rucio/daemons/transmogrifier/__init__.py +0 -1
  191. rucio/daemons/transmogrifier/transmogrifier.py +35 -26
  192. rucio/daemons/undertaker/__init__.py +0 -1
  193. rucio/daemons/undertaker/undertaker.py +10 -10
  194. rucio/db/__init__.py +0 -1
  195. rucio/db/sqla/__init__.py +16 -2
  196. rucio/db/sqla/constants.py +10 -1
  197. rucio/db/sqla/migrate_repo/__init__.py +0 -1
  198. rucio/db/sqla/migrate_repo/env.py +0 -1
  199. rucio/db/sqla/migrate_repo/versions/01eaf73ab656_add_new_rule_notification_state_progress.py +0 -1
  200. rucio/db/sqla/migrate_repo/versions/0437a40dbfd1_add_eol_at_in_rules.py +0 -3
  201. rucio/db/sqla/migrate_repo/versions/0f1adb7a599a_create_transfer_hops_table.py +1 -3
  202. rucio/db/sqla/migrate_repo/versions/102efcf145f4_added_stuck_at_column_to_rules.py +0 -3
  203. rucio/db/sqla/migrate_repo/versions/13d4f70c66a9_introduce_transfer_limits.py +1 -3
  204. rucio/db/sqla/migrate_repo/versions/140fef722e91_cleanup_distances_table.py +1 -3
  205. rucio/db/sqla/migrate_repo/versions/14ec5aeb64cf_add_request_external_host.py +0 -3
  206. rucio/db/sqla/migrate_repo/versions/156fb5b5a14_add_request_type_to_requests_idx.py +1 -4
  207. rucio/db/sqla/migrate_repo/versions/1677d4d803c8_split_rse_availability_into_multiple.py +0 -1
  208. rucio/db/sqla/migrate_repo/versions/16a0aca82e12_create_index_on_table_replicas_path.py +0 -2
  209. rucio/db/sqla/migrate_repo/versions/1803333ac20f_adding_provenance_and_phys_group.py +0 -1
  210. rucio/db/sqla/migrate_repo/versions/1a29d6a9504c_add_didtype_chck_to_requests.py +0 -1
  211. rucio/db/sqla/migrate_repo/versions/1a80adff031a_create_index_on_rules_hist_recent.py +0 -2
  212. rucio/db/sqla/migrate_repo/versions/1c45d9730ca6_increase_identity_length.py +0 -1
  213. rucio/db/sqla/migrate_repo/versions/1d1215494e95_add_quarantined_replicas_table.py +1 -3
  214. rucio/db/sqla/migrate_repo/versions/1d96f484df21_asynchronous_rules_and_rule_approval.py +0 -1
  215. rucio/db/sqla/migrate_repo/versions/1f46c5f240ac_add_bytes_column_to_bad_replicas.py +0 -3
  216. rucio/db/sqla/migrate_repo/versions/1fc15ab60d43_add_message_history_table.py +0 -1
  217. rucio/db/sqla/migrate_repo/versions/2190e703eb6e_move_rse_settings_to_rse_attributes.py +1 -2
  218. rucio/db/sqla/migrate_repo/versions/21d6b9dc9961_add_mismatch_scheme_state_to_requests.py +0 -1
  219. rucio/db/sqla/migrate_repo/versions/22cf51430c78_add_availability_column_to_table_rses.py +0 -3
  220. rucio/db/sqla/migrate_repo/versions/22d887e4ec0a_create_sources_table.py +1 -3
  221. rucio/db/sqla/migrate_repo/versions/25821a8a45a3_remove_unique_constraint_on_requests.py +1 -4
  222. rucio/db/sqla/migrate_repo/versions/25fc855625cf_added_unique_constraint_to_rules.py +0 -2
  223. rucio/db/sqla/migrate_repo/versions/269fee20dee9_add_repair_cnt_to_locks.py +0 -3
  224. rucio/db/sqla/migrate_repo/versions/271a46ea6244_add_ignore_availability_column_to_rules.py +0 -3
  225. rucio/db/sqla/migrate_repo/versions/277b5fbb41d3_switch_heartbeats_executable.py +1 -2
  226. rucio/db/sqla/migrate_repo/versions/27e3a68927fb_remove_replicas_tombstone_and_replicas_.py +0 -1
  227. rucio/db/sqla/migrate_repo/versions/2854cd9e168_added_rule_id_column.py +0 -1
  228. rucio/db/sqla/migrate_repo/versions/295289b5a800_processed_by_and__at_in_requests.py +0 -2
  229. rucio/db/sqla/migrate_repo/versions/2962ece31cf4_add_nbaccesses_column_in_the_did_table.py +0 -3
  230. rucio/db/sqla/migrate_repo/versions/2af3291ec4c_added_replicas_history_table.py +1 -3
  231. rucio/db/sqla/migrate_repo/versions/2b69addda658_add_columns_for_third_party_copy_read_.py +0 -2
  232. rucio/db/sqla/migrate_repo/versions/2b8e7bcb4783_add_config_table.py +1 -4
  233. rucio/db/sqla/migrate_repo/versions/2ba5229cb54c_add_submitted_at_to_requests_table.py +0 -3
  234. rucio/db/sqla/migrate_repo/versions/2cbee484dcf9_added_column_volume_to_rse_transfer_.py +1 -4
  235. rucio/db/sqla/migrate_repo/versions/2edee4a83846_add_source_to_requests_and_requests_.py +0 -1
  236. rucio/db/sqla/migrate_repo/versions/2eef46be23d4_change_tokens_pk.py +1 -3
  237. rucio/db/sqla/migrate_repo/versions/2f648fc909f3_index_in_rule_history_on_scope_name.py +0 -2
  238. rucio/db/sqla/migrate_repo/versions/3082b8cef557_add_naming_convention_table_and_closed_.py +1 -3
  239. rucio/db/sqla/migrate_repo/versions/30fa38b6434e_add_index_on_service_column_in_the_message_table.py +1 -3
  240. rucio/db/sqla/migrate_repo/versions/3152492b110b_added_staging_area_column.py +1 -2
  241. rucio/db/sqla/migrate_repo/versions/32c7d2783f7e_create_bad_replicas_table.py +1 -3
  242. rucio/db/sqla/migrate_repo/versions/3345511706b8_replicas_table_pk_definition_is_in_.py +1 -3
  243. rucio/db/sqla/migrate_repo/versions/35ef10d1e11b_change_index_on_table_requests.py +0 -2
  244. rucio/db/sqla/migrate_repo/versions/379a19b5332d_create_rse_limits_table.py +1 -3
  245. rucio/db/sqla/migrate_repo/versions/384b96aa0f60_created_rule_history_tables.py +2 -3
  246. rucio/db/sqla/migrate_repo/versions/3ac1660a1a72_extend_distance_table.py +0 -3
  247. rucio/db/sqla/migrate_repo/versions/3ad36e2268b0_create_collection_replicas_updates_table.py +1 -4
  248. rucio/db/sqla/migrate_repo/versions/3c9df354071b_extend_waiting_request_state.py +0 -1
  249. rucio/db/sqla/migrate_repo/versions/3d9813fab443_add_a_new_state_lost_in_badfilesstatus.py +0 -1
  250. rucio/db/sqla/migrate_repo/versions/40ad39ce3160_add_transferred_at_to_requests_table.py +0 -3
  251. rucio/db/sqla/migrate_repo/versions/4207be2fd914_add_notification_column_to_rules.py +0 -1
  252. rucio/db/sqla/migrate_repo/versions/42db2617c364_create_index_on_requests_external_id.py +0 -2
  253. rucio/db/sqla/migrate_repo/versions/436827b13f82_added_column_activity_to_table_requests.py +0 -3
  254. rucio/db/sqla/migrate_repo/versions/44278720f774_update_requests_typ_sta_upd_idx_index.py +0 -2
  255. rucio/db/sqla/migrate_repo/versions/45378a1e76a8_create_collection_replica_table.py +2 -4
  256. rucio/db/sqla/migrate_repo/versions/469d262be19_removing_created_at_index.py +0 -2
  257. rucio/db/sqla/migrate_repo/versions/4783c1f49cb4_create_distance_table.py +1 -3
  258. rucio/db/sqla/migrate_repo/versions/49a21b4d4357_create_index_on_table_tokens.py +1 -4
  259. rucio/db/sqla/migrate_repo/versions/4a2cbedda8b9_add_source_replica_expression_column_to_.py +0 -3
  260. rucio/db/sqla/migrate_repo/versions/4a7182d9578b_added_bytes_length_accessed_at_columns.py +0 -3
  261. rucio/db/sqla/migrate_repo/versions/4bab9edd01fc_create_index_on_requests_rule_id.py +0 -2
  262. rucio/db/sqla/migrate_repo/versions/4c3a4acfe006_new_attr_account_table.py +1 -3
  263. rucio/db/sqla/migrate_repo/versions/4cf0a2e127d4_adding_transient_metadata.py +0 -3
  264. rucio/db/sqla/migrate_repo/versions/4df2c5ddabc0_remove_temporary_dids.py +55 -0
  265. rucio/db/sqla/migrate_repo/versions/50280c53117c_add_qos_class_to_rse.py +0 -2
  266. rucio/db/sqla/migrate_repo/versions/52153819589c_add_rse_id_to_replicas_table.py +0 -2
  267. rucio/db/sqla/migrate_repo/versions/52fd9f4916fa_added_activity_to_rules.py +0 -3
  268. rucio/db/sqla/migrate_repo/versions/53b479c3cb0f_fix_did_meta_table_missing_updated_at_.py +0 -3
  269. rucio/db/sqla/migrate_repo/versions/5673b4b6e843_add_wfms_metadata_to_rule_tables.py +0 -3
  270. rucio/db/sqla/migrate_repo/versions/575767d9f89_added_source_history_table.py +1 -2
  271. rucio/db/sqla/migrate_repo/versions/58bff7008037_add_started_at_to_requests.py +0 -3
  272. rucio/db/sqla/migrate_repo/versions/58c8b78301ab_rename_callback_to_message.py +1 -3
  273. rucio/db/sqla/migrate_repo/versions/5f139f77382a_added_child_rule_id_column.py +1 -3
  274. rucio/db/sqla/migrate_repo/versions/688ef1840840_adding_did_meta_table.py +1 -2
  275. rucio/db/sqla/migrate_repo/versions/6e572a9bfbf3_add_new_split_container_column_to_rules.py +0 -3
  276. rucio/db/sqla/migrate_repo/versions/70587619328_add_comment_column_for_subscriptions.py +0 -3
  277. rucio/db/sqla/migrate_repo/versions/739064d31565_remove_history_table_pks.py +1 -2
  278. rucio/db/sqla/migrate_repo/versions/7541902bf173_add_didsfollowed_and_followevents_table.py +2 -4
  279. rucio/db/sqla/migrate_repo/versions/7ec22226cdbf_new_replica_state_for_temporary_.py +0 -1
  280. rucio/db/sqla/migrate_repo/versions/810a41685bc1_added_columns_rse_transfer_limits.py +1 -4
  281. rucio/db/sqla/migrate_repo/versions/83f991c63a93_correct_rse_expression_length.py +0 -2
  282. rucio/db/sqla/migrate_repo/versions/8523998e2e76_increase_size_of_extended_attributes_.py +0 -3
  283. rucio/db/sqla/migrate_repo/versions/8ea9122275b1_adding_missing_function_based_indices.py +1 -2
  284. rucio/db/sqla/migrate_repo/versions/90f47792bb76_add_clob_payload_to_messages.py +0 -3
  285. rucio/db/sqla/migrate_repo/versions/914b8f02df38_new_table_for_lifetime_model_exceptions.py +1 -3
  286. rucio/db/sqla/migrate_repo/versions/94a5961ddbf2_add_estimator_columns.py +0 -3
  287. rucio/db/sqla/migrate_repo/versions/9a1b149a2044_add_saml_identity_type.py +0 -1
  288. rucio/db/sqla/migrate_repo/versions/9a45bc4ea66d_add_vp_table.py +1 -2
  289. rucio/db/sqla/migrate_repo/versions/9eb936a81eb1_true_is_true.py +0 -2
  290. rucio/db/sqla/migrate_repo/versions/a08fa8de1545_transfer_stats_table.py +55 -0
  291. rucio/db/sqla/migrate_repo/versions/a118956323f8_added_vo_table_and_vo_col_to_rse.py +1 -3
  292. rucio/db/sqla/migrate_repo/versions/a193a275255c_add_status_column_in_messages.py +0 -2
  293. rucio/db/sqla/migrate_repo/versions/a5f6f6e928a7_1_7_0.py +1 -4
  294. rucio/db/sqla/migrate_repo/versions/a616581ee47_added_columns_to_table_requests.py +0 -1
  295. rucio/db/sqla/migrate_repo/versions/a6eb23955c28_state_idx_non_functional.py +0 -1
  296. rucio/db/sqla/migrate_repo/versions/a74275a1ad30_added_global_quota_table.py +1 -3
  297. rucio/db/sqla/migrate_repo/versions/a93e4e47bda_heartbeats.py +1 -4
  298. rucio/db/sqla/migrate_repo/versions/ae2a56fcc89_added_comment_column_to_rules.py +0 -1
  299. rucio/db/sqla/migrate_repo/versions/b0070f3695c8_add_deletedidmeta_table.py +57 -0
  300. rucio/db/sqla/migrate_repo/versions/b4293a99f344_added_column_identity_to_table_tokens.py +0 -3
  301. rucio/db/sqla/migrate_repo/versions/b5493606bbf5_fix_primary_key_for_subscription_history.py +41 -0
  302. rucio/db/sqla/migrate_repo/versions/b7d287de34fd_removal_of_replicastate_source.py +1 -2
  303. rucio/db/sqla/migrate_repo/versions/b818052fa670_add_index_to_quarantined_replicas.py +1 -3
  304. rucio/db/sqla/migrate_repo/versions/b8caac94d7f0_add_comments_column_for_subscriptions_.py +0 -3
  305. rucio/db/sqla/migrate_repo/versions/b96a1c7e1cc4_new_bad_pfns_table_and_bad_replicas_.py +1 -5
  306. rucio/db/sqla/migrate_repo/versions/bb695f45c04_extend_request_state.py +1 -3
  307. rucio/db/sqla/migrate_repo/versions/bc68e9946deb_add_staging_timestamps_to_request.py +0 -3
  308. rucio/db/sqla/migrate_repo/versions/bf3baa1c1474_correct_pk_and_idx_for_history_tables.py +1 -3
  309. rucio/db/sqla/migrate_repo/versions/c0937668555f_add_qos_policy_map_table.py +1 -2
  310. rucio/db/sqla/migrate_repo/versions/c129ccdb2d5_add_lumiblocknr_to_dids.py +0 -3
  311. rucio/db/sqla/migrate_repo/versions/ccdbcd48206e_add_did_type_column_index_on_did_meta_.py +1 -4
  312. rucio/db/sqla/migrate_repo/versions/cebad904c4dd_new_payload_column_for_heartbeats.py +1 -2
  313. rucio/db/sqla/migrate_repo/versions/d1189a09c6e0_oauth2_0_and_jwt_feature_support_adding_.py +1 -4
  314. rucio/db/sqla/migrate_repo/versions/d23453595260_extend_request_state_for_preparer.py +1 -3
  315. rucio/db/sqla/migrate_repo/versions/d6dceb1de2d_added_purge_column_to_rules.py +1 -4
  316. rucio/db/sqla/migrate_repo/versions/d6e2c3b2cf26_remove_third_party_copy_column_from_rse.py +0 -2
  317. rucio/db/sqla/migrate_repo/versions/d91002c5841_new_account_limits_table.py +1 -3
  318. rucio/db/sqla/migrate_repo/versions/e138c364ebd0_extending_columns_for_filter_and_.py +0 -3
  319. rucio/db/sqla/migrate_repo/versions/e59300c8b179_support_for_archive.py +1 -3
  320. rucio/db/sqla/migrate_repo/versions/f1b14a8c2ac1_postgres_use_check_constraints.py +0 -1
  321. rucio/db/sqla/migrate_repo/versions/f41ffe206f37_oracle_global_temporary_tables.py +1 -2
  322. rucio/db/sqla/migrate_repo/versions/f85a2962b021_adding_transfertool_column_to_requests_.py +1 -3
  323. rucio/db/sqla/migrate_repo/versions/fa7a7d78b602_increase_refresh_token_size.py +0 -2
  324. rucio/db/sqla/migrate_repo/versions/fb28a95fe288_add_replicas_rse_id_tombstone_idx.py +0 -1
  325. rucio/db/sqla/migrate_repo/versions/fe1a65b176c9_set_third_party_copy_read_and_write_.py +1 -2
  326. rucio/db/sqla/migrate_repo/versions/fe8ea2fa9788_added_third_party_copy_column_to_rse_.py +0 -3
  327. rucio/db/sqla/models.py +122 -216
  328. rucio/db/sqla/sautils.py +12 -5
  329. rucio/db/sqla/session.py +71 -43
  330. rucio/db/sqla/types.py +3 -4
  331. rucio/db/sqla/util.py +91 -69
  332. rucio/gateway/__init__.py +13 -0
  333. rucio/{api → gateway}/account.py +119 -46
  334. rucio/{api → gateway}/account_limit.py +12 -13
  335. rucio/{api → gateway}/authentication.py +106 -33
  336. rucio/{api → gateway}/config.py +12 -13
  337. rucio/{api → gateway}/credential.py +15 -4
  338. rucio/{api → gateway}/did.py +384 -140
  339. rucio/{api → gateway}/dirac.py +16 -6
  340. rucio/{api → gateway}/exporter.py +3 -4
  341. rucio/{api → gateway}/heartbeat.py +17 -5
  342. rucio/{api → gateway}/identity.py +63 -19
  343. rucio/{api → gateway}/importer.py +3 -4
  344. rucio/{api → gateway}/lifetime_exception.py +35 -10
  345. rucio/{api → gateway}/lock.py +34 -12
  346. rucio/{api/meta.py → gateway/meta_conventions.py} +18 -16
  347. rucio/{api → gateway}/permission.py +4 -5
  348. rucio/{api → gateway}/quarantined_replica.py +13 -4
  349. rucio/{api → gateway}/replica.py +12 -11
  350. rucio/{api → gateway}/request.py +129 -28
  351. rucio/{api → gateway}/rse.py +11 -12
  352. rucio/{api → gateway}/rule.py +117 -35
  353. rucio/{api → gateway}/scope.py +24 -14
  354. rucio/{api → gateway}/subscription.py +65 -43
  355. rucio/{api → gateway}/vo.py +17 -7
  356. rucio/rse/__init__.py +3 -4
  357. rucio/rse/protocols/__init__.py +0 -1
  358. rucio/rse/protocols/bittorrent.py +184 -0
  359. rucio/rse/protocols/cache.py +1 -2
  360. rucio/rse/protocols/dummy.py +1 -2
  361. rucio/rse/protocols/gfal.py +12 -10
  362. rucio/rse/protocols/globus.py +7 -7
  363. rucio/rse/protocols/gsiftp.py +2 -3
  364. rucio/rse/protocols/http_cache.py +1 -2
  365. rucio/rse/protocols/mock.py +1 -2
  366. rucio/rse/protocols/ngarc.py +1 -2
  367. rucio/rse/protocols/posix.py +12 -13
  368. rucio/rse/protocols/protocol.py +116 -52
  369. rucio/rse/protocols/rclone.py +6 -7
  370. rucio/rse/protocols/rfio.py +4 -5
  371. rucio/rse/protocols/srm.py +9 -10
  372. rucio/rse/protocols/ssh.py +8 -9
  373. rucio/rse/protocols/storm.py +2 -3
  374. rucio/rse/protocols/webdav.py +17 -14
  375. rucio/rse/protocols/xrootd.py +23 -17
  376. rucio/rse/rsemanager.py +19 -7
  377. rucio/tests/__init__.py +0 -1
  378. rucio/tests/common.py +43 -17
  379. rucio/tests/common_server.py +3 -3
  380. rucio/transfertool/__init__.py +0 -1
  381. rucio/transfertool/bittorrent.py +199 -0
  382. rucio/transfertool/bittorrent_driver.py +52 -0
  383. rucio/transfertool/bittorrent_driver_qbittorrent.py +133 -0
  384. rucio/transfertool/fts3.py +250 -138
  385. rucio/transfertool/fts3_plugins.py +152 -0
  386. rucio/transfertool/globus.py +9 -8
  387. rucio/transfertool/globus_library.py +1 -2
  388. rucio/transfertool/mock.py +21 -12
  389. rucio/transfertool/transfertool.py +33 -24
  390. rucio/vcsversion.py +4 -4
  391. rucio/version.py +5 -13
  392. rucio/web/__init__.py +0 -1
  393. rucio/web/rest/__init__.py +0 -1
  394. rucio/web/rest/flaskapi/__init__.py +0 -1
  395. rucio/web/rest/flaskapi/authenticated_bp.py +0 -1
  396. rucio/web/rest/flaskapi/v1/__init__.py +0 -1
  397. rucio/web/rest/flaskapi/v1/accountlimits.py +15 -13
  398. rucio/web/rest/flaskapi/v1/accounts.py +49 -48
  399. rucio/web/rest/flaskapi/v1/archives.py +12 -10
  400. rucio/web/rest/flaskapi/v1/auth.py +146 -144
  401. rucio/web/rest/flaskapi/v1/common.py +82 -41
  402. rucio/web/rest/flaskapi/v1/config.py +5 -6
  403. rucio/web/rest/flaskapi/v1/credentials.py +7 -8
  404. rucio/web/rest/flaskapi/v1/dids.py +158 -28
  405. rucio/web/rest/flaskapi/v1/dirac.py +8 -8
  406. rucio/web/rest/flaskapi/v1/export.py +3 -5
  407. rucio/web/rest/flaskapi/v1/heartbeats.py +3 -5
  408. rucio/web/rest/flaskapi/v1/identities.py +3 -5
  409. rucio/web/rest/flaskapi/v1/import.py +3 -4
  410. rucio/web/rest/flaskapi/v1/lifetime_exceptions.py +6 -9
  411. rucio/web/rest/flaskapi/v1/locks.py +2 -4
  412. rucio/web/rest/flaskapi/v1/main.py +10 -2
  413. rucio/web/rest/flaskapi/v1/{meta.py → meta_conventions.py} +26 -11
  414. rucio/web/rest/flaskapi/v1/metrics.py +1 -2
  415. rucio/web/rest/flaskapi/v1/nongrid_traces.py +4 -4
  416. rucio/web/rest/flaskapi/v1/ping.py +6 -7
  417. rucio/web/rest/flaskapi/v1/redirect.py +8 -9
  418. rucio/web/rest/flaskapi/v1/replicas.py +43 -19
  419. rucio/web/rest/flaskapi/v1/requests.py +178 -21
  420. rucio/web/rest/flaskapi/v1/rses.py +61 -26
  421. rucio/web/rest/flaskapi/v1/rules.py +48 -18
  422. rucio/web/rest/flaskapi/v1/scopes.py +3 -5
  423. rucio/web/rest/flaskapi/v1/subscriptions.py +22 -18
  424. rucio/web/rest/flaskapi/v1/traces.py +4 -4
  425. rucio/web/rest/flaskapi/v1/types.py +20 -0
  426. rucio/web/rest/flaskapi/v1/vos.py +3 -5
  427. rucio/web/rest/main.py +0 -1
  428. rucio/web/rest/metrics.py +0 -1
  429. rucio/web/rest/ping.py +27 -0
  430. {rucio-32.8.6.data → rucio-35.8.0.data}/data/rucio/etc/ldap.cfg.template +1 -1
  431. rucio-35.8.0.data/data/rucio/requirements.server.txt +268 -0
  432. {rucio-32.8.6.data → rucio-35.8.0.data}/data/rucio/tools/bootstrap.py +3 -3
  433. {rucio-32.8.6.data → rucio-35.8.0.data}/data/rucio/tools/merge_rucio_configs.py +2 -5
  434. {rucio-32.8.6.data → rucio-35.8.0.data}/data/rucio/tools/reset_database.py +3 -3
  435. {rucio-32.8.6.data → rucio-35.8.0.data}/scripts/rucio +87 -85
  436. {rucio-32.8.6.data → rucio-35.8.0.data}/scripts/rucio-abacus-account +0 -1
  437. {rucio-32.8.6.data → rucio-35.8.0.data}/scripts/rucio-abacus-collection-replica +0 -1
  438. {rucio-32.8.6.data → rucio-35.8.0.data}/scripts/rucio-abacus-rse +0 -1
  439. {rucio-32.8.6.data → rucio-35.8.0.data}/scripts/rucio-admin +45 -32
  440. {rucio-32.8.6.data → rucio-35.8.0.data}/scripts/rucio-atropos +0 -1
  441. {rucio-32.8.6.data → rucio-35.8.0.data}/scripts/rucio-auditor +13 -7
  442. {rucio-32.8.6.data → rucio-35.8.0.data}/scripts/rucio-automatix +1 -2
  443. {rucio-32.8.6.data → rucio-35.8.0.data}/scripts/rucio-bb8 +0 -1
  444. {rucio-32.8.6.data → rucio-35.8.0.data}/scripts/rucio-c3po +0 -1
  445. {rucio-32.8.6.data → rucio-35.8.0.data}/scripts/rucio-cache-client +2 -3
  446. {rucio-32.8.6.data → rucio-35.8.0.data}/scripts/rucio-cache-consumer +0 -1
  447. {rucio-32.8.6.data → rucio-35.8.0.data}/scripts/rucio-conveyor-finisher +1 -2
  448. {rucio-32.8.6.data → rucio-35.8.0.data}/scripts/rucio-conveyor-poller +0 -1
  449. {rucio-32.8.6.data → rucio-35.8.0.data}/scripts/rucio-conveyor-preparer +0 -1
  450. {rucio-32.8.6.data → rucio-35.8.0.data}/scripts/rucio-conveyor-receiver +0 -1
  451. {rucio-32.8.6.data → rucio-35.8.0.data}/scripts/rucio-conveyor-stager +0 -1
  452. {rucio-32.8.6.data → rucio-35.8.0.data}/scripts/rucio-conveyor-submitter +2 -3
  453. {rucio-32.8.6.data → rucio-35.8.0.data}/scripts/rucio-conveyor-throttler +0 -1
  454. {rucio-32.8.6.data → rucio-35.8.0.data}/scripts/rucio-dark-reaper +0 -1
  455. {rucio-32.8.6.data → rucio-35.8.0.data}/scripts/rucio-dumper +11 -10
  456. {rucio-32.8.6.data → rucio-35.8.0.data}/scripts/rucio-follower +0 -1
  457. {rucio-32.8.6.data → rucio-35.8.0.data}/scripts/rucio-hermes +0 -1
  458. {rucio-32.8.6.data → rucio-35.8.0.data}/scripts/rucio-judge-cleaner +0 -1
  459. {rucio-32.8.6.data → rucio-35.8.0.data}/scripts/rucio-judge-evaluator +2 -3
  460. {rucio-32.8.6.data → rucio-35.8.0.data}/scripts/rucio-judge-injector +0 -1
  461. {rucio-32.8.6.data → rucio-35.8.0.data}/scripts/rucio-judge-repairer +0 -1
  462. {rucio-32.8.6.data → rucio-35.8.0.data}/scripts/rucio-kronos +1 -3
  463. {rucio-32.8.6.data → rucio-35.8.0.data}/scripts/rucio-minos +0 -1
  464. {rucio-32.8.6.data → rucio-35.8.0.data}/scripts/rucio-minos-temporary-expiration +0 -1
  465. {rucio-32.8.6.data → rucio-35.8.0.data}/scripts/rucio-necromancer +1 -2
  466. {rucio-32.8.6.data → rucio-35.8.0.data}/scripts/rucio-oauth-manager +2 -3
  467. {rucio-32.8.6.data → rucio-35.8.0.data}/scripts/rucio-reaper +0 -1
  468. {rucio-32.8.6.data → rucio-35.8.0.data}/scripts/rucio-replica-recoverer +6 -7
  469. rucio-35.8.0.data/scripts/rucio-rse-decommissioner +66 -0
  470. {rucio-32.8.6.data → rucio-35.8.0.data}/scripts/rucio-storage-consistency-actions +0 -1
  471. {rucio-32.8.6.data → rucio-35.8.0.data}/scripts/rucio-transmogrifier +0 -1
  472. {rucio-32.8.6.data → rucio-35.8.0.data}/scripts/rucio-undertaker +1 -2
  473. rucio-35.8.0.dist-info/METADATA +72 -0
  474. rucio-35.8.0.dist-info/RECORD +493 -0
  475. {rucio-32.8.6.dist-info → rucio-35.8.0.dist-info}/WHEEL +1 -1
  476. {rucio-32.8.6.dist-info → rucio-35.8.0.dist-info}/licenses/AUTHORS.rst +3 -0
  477. rucio/api/temporary_did.py +0 -49
  478. rucio/common/schema/cms.py +0 -478
  479. rucio/common/schema/lsst.py +0 -423
  480. rucio/core/permission/cms.py +0 -1166
  481. rucio/core/temporary_did.py +0 -188
  482. rucio/daemons/reaper/light_reaper.py +0 -255
  483. rucio/web/rest/flaskapi/v1/tmp_dids.py +0 -115
  484. rucio-32.8.6.data/data/rucio/requirements.txt +0 -55
  485. rucio-32.8.6.data/scripts/rucio-light-reaper +0 -53
  486. rucio-32.8.6.dist-info/METADATA +0 -83
  487. rucio-32.8.6.dist-info/RECORD +0 -481
  488. {rucio-32.8.6.data → rucio-35.8.0.data}/data/rucio/etc/alembic.ini.template +0 -0
  489. {rucio-32.8.6.data → rucio-35.8.0.data}/data/rucio/etc/alembic_offline.ini.template +0 -0
  490. {rucio-32.8.6.data → rucio-35.8.0.data}/data/rucio/etc/globus-config.yml.template +0 -0
  491. {rucio-32.8.6.data → rucio-35.8.0.data}/data/rucio/etc/mail_templates/rule_approval_request.tmpl +0 -0
  492. {rucio-32.8.6.data → rucio-35.8.0.data}/data/rucio/etc/mail_templates/rule_approved_admin.tmpl +0 -0
  493. {rucio-32.8.6.data → rucio-35.8.0.data}/data/rucio/etc/mail_templates/rule_approved_user.tmpl +0 -0
  494. {rucio-32.8.6.data → rucio-35.8.0.data}/data/rucio/etc/mail_templates/rule_denied_admin.tmpl +0 -0
  495. {rucio-32.8.6.data → rucio-35.8.0.data}/data/rucio/etc/mail_templates/rule_denied_user.tmpl +0 -0
  496. {rucio-32.8.6.data → rucio-35.8.0.data}/data/rucio/etc/mail_templates/rule_ok_notification.tmpl +0 -0
  497. {rucio-32.8.6.data → rucio-35.8.0.data}/data/rucio/etc/rse-accounts.cfg.template +0 -0
  498. {rucio-32.8.6.data → rucio-35.8.0.data}/data/rucio/etc/rucio.cfg.atlas.client.template +0 -0
  499. {rucio-32.8.6.data → rucio-35.8.0.data}/data/rucio/etc/rucio.cfg.template +0 -0
  500. {rucio-32.8.6.data → rucio-35.8.0.data}/data/rucio/etc/rucio_multi_vo.cfg.template +0 -0
  501. {rucio-32.8.6.dist-info → rucio-35.8.0.dist-info}/licenses/LICENSE +0 -0
  502. {rucio-32.8.6.dist-info → rucio-35.8.0.dist-info}/top_level.txt +0 -0
@@ -1,4 +1,3 @@
1
- # -*- coding: utf-8 -*-
2
1
  # Copyright European Organization for Nuclear Research (CERN) since 2012
3
2
  #
4
3
  # Licensed under the Apache License, Version 2.0 (the "License");
@@ -62,8 +61,10 @@ for meta_module_path in METADATA_PLUGIN_MODULE_PATHS:
62
61
  base_class = meta_module_path.split(".")[-1]
63
62
  metadata_plugin_module = getattr(importlib.import_module(base_module), base_class)()
64
63
  METADATA_PLUGIN_MODULES.append(metadata_plugin_module)
64
+ except ModuleNotFoundError:
65
+ raise exception.PolicyPackageNotFound(meta_module_path)
65
66
  except ImportError:
66
- raise exception.PolicyPackageNotFound('Module ' + meta_module_path + ' not found')
67
+ raise exception.ErrorLoadingPolicyPackage(meta_module_path)
67
68
 
68
69
  # Set restricted character set for metadata in form character: reason
69
70
  #
@@ -83,8 +84,9 @@ def get_metadata(scope, name, plugin="DID_COLUMN", *, session: "Session"):
83
84
  :param scope: The scope of the did.
84
85
  :param name: The data identifier name.
85
86
  :param plugin: (optional) Filter specific metadata plugins.
86
- :returns: List of metadata for did.
87
- :raises: NotImplementedError
87
+ :param session: (optional) The database session in use.
88
+ :returns: Dictionary containing metadata for did.
89
+ :raises: UnsupportedMetadataPlugin: If the specified plugin is not enabled/available
88
90
  """
89
91
  if plugin.lower() == "all":
90
92
  all_metadata = {}
@@ -96,7 +98,7 @@ def get_metadata(scope, name, plugin="DID_COLUMN", *, session: "Session"):
96
98
  for metadata_plugin in METADATA_PLUGIN_MODULES:
97
99
  if metadata_plugin.get_plugin_name().lower() == plugin.lower():
98
100
  return metadata_plugin.get_metadata(scope, name, session=session)
99
- raise NotImplementedError('Metadata plugin "%s" is not enabled on the server.' % plugin)
101
+ raise exception.UnsupportedMetadataPlugin(f'Metadata plugin "{plugin}" is not enabled on the server.')
100
102
 
101
103
 
102
104
  @transactional_session
@@ -216,7 +218,7 @@ def list_dids(scope=None, filters=None, did_type='collection', ignore_case=False
216
218
  :returns: List of dids satisfying metadata criteria.
217
219
  :raises: InvalidMetadata
218
220
  """
219
- # backwards compatability for filters as single {}.
221
+ # backwards compatibility for filters as single {}.
220
222
  if isinstance(filters, dict):
221
223
  filters = [filters]
222
224
 
@@ -1,4 +1,3 @@
1
- # -*- coding: utf-8 -*-
2
1
  # Copyright European Organization for Nuclear Research (CERN) since 2012
3
2
  #
4
3
  # Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,9 +16,8 @@ import operator
17
16
  from datetime import datetime, timedelta
18
17
  from typing import TYPE_CHECKING
19
18
 
20
- from sqlalchemy import update, inspect
21
- from sqlalchemy.exc import CompileError, InvalidRequestError
22
- from sqlalchemy.orm.exc import NoResultFound
19
+ from sqlalchemy import inspect, update
20
+ from sqlalchemy.exc import CompileError, InvalidRequestError, NoResultFound
23
21
  from sqlalchemy.sql import func
24
22
  from sqlalchemy.sql.expression import true
25
23
 
@@ -29,10 +27,11 @@ from rucio.core.did_meta_plugins.did_meta_plugin_interface import DidMetaPlugin
29
27
  from rucio.core.did_meta_plugins.filter_engine import FilterEngine
30
28
  from rucio.db.sqla import models
31
29
  from rucio.db.sqla.constants import DIDType
32
- from rucio.db.sqla.session import stream_session, read_session, transactional_session
30
+ from rucio.db.sqla.session import read_session, stream_session, transactional_session
33
31
 
34
32
  if TYPE_CHECKING:
35
33
  from typing import Optional
34
+
36
35
  from sqlalchemy.orm import Session
37
36
 
38
37
 
@@ -198,7 +197,7 @@ class DidColumnMeta(DidMetaPlugin):
198
197
  'file': [DIDType.FILE]
199
198
  }
200
199
 
201
- # backwards compatability for filters as single {}.
200
+ # backwards compatibility for filters as single {}.
202
201
  if isinstance(filters, dict):
203
202
  filters = [filters]
204
203
 
@@ -220,7 +219,7 @@ class DidColumnMeta(DidMetaPlugin):
220
219
 
221
220
  # instantiate fe and create sqla query
222
221
  fe = FilterEngine(filters, model_class=models.DataIdentifier)
223
- query = fe.create_sqla_query(
222
+ stmt = fe.create_sqla_query(
224
223
  additional_model_attributes=[
225
224
  models.DataIdentifier.scope,
226
225
  models.DataIdentifier.name,
@@ -233,16 +232,22 @@ class DidColumnMeta(DidMetaPlugin):
233
232
  ],
234
233
  session=session
235
234
  )
236
- query.with_hint(models.DataIdentifier, 'NO_EXPAND', 'oracle')
235
+ stmt = stmt.with_hint(
236
+ models.DataIdentifier,
237
+ 'NO_EXPAND',
238
+ 'oracle'
239
+ )
237
240
 
238
241
  if limit:
239
- query = query.limit(limit)
242
+ stmt = stmt.limit(
243
+ limit
244
+ )
240
245
  if recursive:
241
246
  from rucio.core.did import list_content
242
247
 
243
248
  # Get attached DIDs and save in list because query has to be finished before starting a new one in the recursion
244
249
  collections_content = []
245
- for did in query.yield_per(100):
250
+ for did in session.execute(stmt).yield_per(100):
246
251
  if (did.did_type == DIDType.CONTAINER or did.did_type == DIDType.DATASET):
247
252
  collections_content += [d for d in list_content(scope=did.scope, name=did.name)]
248
253
 
@@ -254,7 +259,7 @@ class DidColumnMeta(DidMetaPlugin):
254
259
  long=long, ignore_dids=ignore_dids, session=session):
255
260
  yield result
256
261
 
257
- for did in query.yield_per(5): # don't unpack this as it makes it dependent on query return order!
262
+ for did in session.execute(stmt).yield_per(5): # don't unpack this as it makes it dependent on query return order!
258
263
  if long:
259
264
  did_full = "{}:{}".format(did.scope, did.name)
260
265
  if did_full not in ignore_dids: # concatenating results of OR clauses may contain duplicate DIDs if query result sets not mutually exclusive.
@@ -262,7 +267,7 @@ class DidColumnMeta(DidMetaPlugin):
262
267
  yield {
263
268
  'scope': did.scope,
264
269
  'name': did.name,
265
- 'did_type': str(did.did_type),
270
+ 'did_type': did.did_type.name,
266
271
  'bytes': did.bytes,
267
272
  'length': did.length
268
273
  }
@@ -1,4 +1,3 @@
1
- # -*- coding: utf-8 -*-
2
1
  # Copyright European Organization for Nuclear Research (CERN) since 2012
3
2
  #
4
3
  # Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,16 +13,20 @@
14
13
  # limitations under the License.
15
14
 
16
15
  from abc import ABCMeta, abstractmethod
17
- from typing import TYPE_CHECKING
16
+ from typing import TYPE_CHECKING, Literal
18
17
 
19
18
  from rucio.db.sqla.session import transactional_session
20
19
 
21
20
  if TYPE_CHECKING:
22
- from typing import Optional
21
+ from collections.abc import Iterator
22
+ from typing import Any, Optional, Union
23
+
23
24
  from sqlalchemy.orm import Session
24
25
 
26
+ from rucio.common.types import InternalScope
27
+
25
28
 
26
- class DidMetaPlugin(object, metaclass=ABCMeta):
29
+ class DidMetaPlugin(metaclass=ABCMeta):
27
30
  """
28
31
  Interface for plugins managing metadata of DIDs
29
32
  """
@@ -35,7 +38,13 @@ class DidMetaPlugin(object, metaclass=ABCMeta):
35
38
  pass
36
39
 
37
40
  @abstractmethod
38
- def get_metadata(self, scope, name, *, session: "Optional[Session]" = None):
41
+ def get_metadata(
42
+ self,
43
+ scope: "InternalScope",
44
+ name: str,
45
+ *,
46
+ session: "Optional[Session]" = None
47
+ ) -> "Any":
39
48
  """
40
49
  Get data identifier metadata
41
50
 
@@ -46,7 +55,16 @@ class DidMetaPlugin(object, metaclass=ABCMeta):
46
55
  pass
47
56
 
48
57
  @abstractmethod
49
- def set_metadata(self, scope, name, key, value, recursive=False, *, session: "Optional[Session]" = None):
58
+ def set_metadata(
59
+ self,
60
+ scope: "InternalScope",
61
+ name: str,
62
+ key: str,
63
+ value: str,
64
+ recursive: bool = False,
65
+ *,
66
+ session: "Optional[Session]" = None
67
+ ) -> None:
50
68
  """
51
69
  Add metadata to data identifier.
52
70
 
@@ -61,7 +79,15 @@ class DidMetaPlugin(object, metaclass=ABCMeta):
61
79
  pass
62
80
 
63
81
  @transactional_session
64
- def set_metadata_bulk(self, scope, name, meta, recursive=False, *, session: "Optional[Session]" = None):
82
+ def set_metadata_bulk(
83
+ self,
84
+ scope: "InternalScope",
85
+ name: str,
86
+ meta: dict[str, "Any"],
87
+ recursive: bool = False,
88
+ *,
89
+ session: "Optional[Session]" = None
90
+ ) -> None:
65
91
  """
66
92
  Add metadata to data identifier in bulk.
67
93
 
@@ -76,7 +102,14 @@ class DidMetaPlugin(object, metaclass=ABCMeta):
76
102
  self.set_metadata(scope, name, key, value, recursive=recursive, session=session)
77
103
 
78
104
  @abstractmethod
79
- def delete_metadata(self, scope, name, key, *, session: "Session" = None):
105
+ def delete_metadata(
106
+ self,
107
+ scope: "InternalScope",
108
+ name: str,
109
+ key: str,
110
+ *,
111
+ session: "Optional[Session]" = None
112
+ ) -> None:
80
113
  """
81
114
  Deletes the metadata stored for the given key.
82
115
 
@@ -88,8 +121,19 @@ class DidMetaPlugin(object, metaclass=ABCMeta):
88
121
  pass
89
122
 
90
123
  @abstractmethod
91
- def list_dids(self, scope, filters, did_type='collection', ignore_case=False, limit=None,
92
- offset=None, long=False, recursive=False, *, session: "Optional[Session]" = None):
124
+ def list_dids(
125
+ self,
126
+ scope: "InternalScope",
127
+ filters: dict[str, "Any"],
128
+ did_type: Literal['all', 'collection', 'dataset', 'container', 'file'] = 'collection',
129
+ ignore_case: bool = False,
130
+ limit: "Optional[int]" = None,
131
+ offset: "Optional[int]" = None,
132
+ long: bool = False,
133
+ recursive: bool = False,
134
+ *,
135
+ session: "Optional[Session]" = None
136
+ ) -> "Iterator[Union[str, dict[str, Any]]]":
93
137
  """
94
138
  Search data identifiers
95
139
 
@@ -106,7 +150,12 @@ class DidMetaPlugin(object, metaclass=ABCMeta):
106
150
  pass
107
151
 
108
152
  @abstractmethod
109
- def manages_key(self, key, *, session: "Optional[Session]" = None):
153
+ def manages_key(
154
+ self,
155
+ key: str,
156
+ *,
157
+ session: "Optional[Session]" = None
158
+ ) -> bool:
110
159
  """
111
160
  Returns whether key is managed by this plugin or not.
112
161
  :param key: Key of the metadata.
@@ -1,4 +1,3 @@
1
- # -*- coding: utf-8 -*-
2
1
  # Copyright European Organization for Nuclear Research (CERN) since 2012
3
2
  #
4
3
  # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,12 +15,13 @@
16
15
  import ast
17
16
  import fnmatch
18
17
  import operator
19
- from datetime import datetime, timedelta, date
18
+ from datetime import date, datetime, timedelta
20
19
  from importlib import import_module
21
- from typing import TYPE_CHECKING
20
+ from typing import TYPE_CHECKING, Any, Optional, TypeVar, Union
22
21
 
23
22
  import sqlalchemy
24
- from sqlalchemy import cast, or_, and_
23
+ from sqlalchemy import Select, and_, cast, or_, select
24
+ from sqlalchemy.orm import InstrumentedAttribute
25
25
  from sqlalchemy.sql.expression import text
26
26
 
27
27
  from rucio.common import exception
@@ -30,8 +30,14 @@ from rucio.db.sqla.constants import DIDType
30
30
  from rucio.db.sqla.session import read_session
31
31
 
32
32
  if TYPE_CHECKING:
33
+ from collections.abc import Callable, Iterable
34
+
33
35
  from sqlalchemy.orm import Session
34
36
 
37
+ from rucio.db.sqla.models import ModelBase
38
+
39
+ KeyType = TypeVar("KeyType", str, InstrumentedAttribute)
40
+ FilterTuple = tuple[KeyType, Callable[[object, object], Any], Union[bool, datetime, float, str]]
35
41
 
36
42
  # lookup table converting keyword suffixes to pythonic operators.
37
43
  OPERATORS_CONVERSION_LUT = {
@@ -77,31 +83,36 @@ class FilterEngine:
77
83
  """
78
84
  An engine to provide advanced filtering functionality to DID listing requests.
79
85
  """
80
- def __init__(self, filters, model_class=None, strict_coerce=True):
86
+ def __init__(
87
+ self,
88
+ filters: Union[str, dict[str, Any], list[dict[str, Any]]],
89
+ model_class: Optional[type["ModelBase"]] = None,
90
+ strict_coerce: bool = True
91
+ ):
81
92
  if isinstance(filters, str):
82
- self._filters, _ = parse_did_filter_from_string_fe(filters, omit_name=True)
93
+ filters, _ = parse_did_filter_from_string_fe(filters, omit_name=True)
83
94
  elif isinstance(filters, dict):
84
- self._filters = [filters]
95
+ filters = [filters]
85
96
  elif isinstance(filters, list):
86
- self._filters = filters
97
+ filters = filters
87
98
  else:
88
99
  raise exception.DIDFilterSyntaxError("Input filters are of an unrecognised type.")
89
100
 
90
- self._make_input_backwards_compatible()
91
- self.mandatory_model_attributes = self._translate_filters(model_class=model_class, strict_coerce=strict_coerce)
101
+ filters = self._make_input_backwards_compatible(filters=filters)
102
+ self._filters, self.mandatory_model_attributes = self._translate_filters(filters=filters, model_class=model_class, strict_coerce=strict_coerce)
92
103
  self._sanity_check_translated_filters()
93
104
 
94
105
  @property
95
- def filters(self):
106
+ def filters(self) -> list[list["FilterTuple"]]:
96
107
  return self._filters
97
108
 
98
- def _coerce_filter_word_to_model_attribute(self, word, model_class, strict=True):
109
+ def _coerce_filter_word_to_model_attribute(self, word: Any, model_class: Optional[type["ModelBase"]], strict: bool = True) -> Any:
99
110
  """
100
111
  Attempts to coerce a filter word to an attribute of a <model_class>.
101
112
 
102
113
  :param model_class: The word.
103
114
  :param model_class: The SQL model class.
104
- :params: strict: Enforce that keywords must be coercable to a model attribute.
115
+ :params: strict: Enforce that keywords must be coercible to a model attribute.
105
116
  :returns: The coerced attribute if successful or (if strict is False) the word if not.
106
117
  :raises: KeyNotFound
107
118
  """
@@ -113,7 +124,7 @@ class FilterEngine:
113
124
  raise exception.KeyNotFound("'{}' keyword could not be coerced to model class attribute. Attribute not found.".format(word))
114
125
  return word
115
126
 
116
- def _make_input_backwards_compatible(self):
127
+ def _make_input_backwards_compatible(self, filters: list[dict[str, Any]]) -> list[dict[str, Any]]:
117
128
  """
118
129
  Backwards compatibility for previous versions of filtering.
119
130
 
@@ -121,13 +132,14 @@ class FilterEngine:
121
132
  - converts "created_after" key to "created_at.gte"
122
133
  - converts "created_before" key to "created_at.lte"
123
134
  """
124
- for or_group in self._filters:
135
+ for or_group in filters:
125
136
  if 'created_after' in or_group:
126
137
  or_group['created_at.gte'] = or_group.pop('created_after')
127
138
  elif 'created_before' in or_group:
128
139
  or_group['created_at.lte'] = or_group.pop('created_before')
140
+ return filters
129
141
 
130
- def _sanity_check_translated_filters(self):
142
+ def _sanity_check_translated_filters(self) -> None:
131
143
  """
132
144
  Perform a few sanity checks on translated filters.
133
145
 
@@ -153,7 +165,7 @@ class FilterEngine:
153
165
  raise ValueError("Name operator must be an equality operator.")
154
166
  if key == 'length': # (3)
155
167
  try:
156
- int(value)
168
+ int(value) # type: ignore
157
169
  except ValueError:
158
170
  raise ValueError('Length has to be an integer value.')
159
171
 
@@ -170,7 +182,12 @@ class FilterEngine:
170
182
  if len(set(or_group_test_duplicates)) != len(or_group_test_duplicates): # (6)
171
183
  raise exception.DuplicateCriteriaInDIDFilter()
172
184
 
173
- def _translate_filters(self, model_class, strict_coerce=True):
185
+ def _translate_filters(
186
+ self,
187
+ filters: "Iterable[dict[str, Any]]",
188
+ model_class: Optional[type["ModelBase"]],
189
+ strict_coerce: bool = True
190
+ ) -> tuple[list[list["FilterTuple"]], list[InstrumentedAttribute[Any]]]:
174
191
  """
175
192
  Reformats filters from:
176
193
 
@@ -199,9 +216,10 @@ class FilterEngine:
199
216
 
200
217
  Typecasting of values is also attempted.
201
218
 
219
+ :param filters: The filters to translate.
202
220
  :param model_class: The SQL model class.
203
- :param strict_coerce: Enforce that keywords must be coercable to a model attribute.
204
- :returns: The set of mandatory model attributes to be used in the filter query.
221
+ :param strict_coerce: Enforce that keywords must be coercible to a model attribute.
222
+ :returns: The list of translated filters, and the set of mandatory model attributes to be used in the filter query.
205
223
  :raises: MissingModuleException, DIDFilterSyntaxError
206
224
  """
207
225
  if model_class:
@@ -212,7 +230,7 @@ class FilterEngine:
212
230
 
213
231
  mandatory_model_attributes = set()
214
232
  filters_translated = []
215
- for or_group in self._filters:
233
+ for or_group in filters:
216
234
  and_group_parsed = []
217
235
  for key, value in or_group.items():
218
236
  # KEY
@@ -245,10 +263,9 @@ class FilterEngine:
245
263
  and_group_parsed.append(
246
264
  (key_no_suffix, OPERATORS_CONVERSION_LUT.get(oper), value))
247
265
  filters_translated.append(and_group_parsed)
248
- self._filters = filters_translated
249
- return list(mandatory_model_attributes)
266
+ return filters_translated, list(mandatory_model_attributes)
250
267
 
251
- def _try_typecast_string(self, value):
268
+ def _try_typecast_string(self, value: str) -> Union[bool, datetime, float, str]:
252
269
  """
253
270
  Check if string can be typecasted to bool, datetime or float.
254
271
 
@@ -259,11 +276,11 @@ class FilterEngine:
259
276
  value = value.replace('false', 'False').replace('FALSE', 'False')
260
277
  for format in VALID_DATE_FORMATS: # try parsing multiple date formats.
261
278
  try:
262
- value = datetime.strptime(value, format)
279
+ typecasted_value = datetime.strptime(value, format)
263
280
  except ValueError:
264
281
  continue
265
282
  else:
266
- return value
283
+ return typecasted_value
267
284
  try:
268
285
  operators = ('+', '-', '*', '/')
269
286
  if not any(operator in value for operator in operators): # fix for lax ast literal_eval in earlier python versions
@@ -272,21 +289,25 @@ class FilterEngine:
272
289
  pass
273
290
  return value
274
291
 
275
- def create_mongo_query(self, additional_filters={}):
292
+ def create_mongo_query(
293
+ self,
294
+ additional_filters: Optional["Iterable[FilterTuple]"] = None
295
+ ) -> dict[str, Any]:
276
296
  """
277
297
  Returns a single mongo query describing the filters expression.
278
298
 
279
299
  :param additional_filters: additional filters to be applied to all clauses.
280
300
  :returns: a mongo query string describing the filters expression.
281
301
  """
302
+ additional_filters = additional_filters or []
282
303
  # Add additional filters, applied as AND clauses to each OR group.
283
304
  for or_group in self._filters:
284
305
  for filter in additional_filters:
285
- or_group.append(list(filter))
306
+ or_group.append(list(filter)) # type: ignore
286
307
 
287
- or_expressions = []
308
+ or_expressions: list[dict[str, Any]] = []
288
309
  for or_group in self._filters:
289
- and_expressions = []
310
+ and_expressions: list[dict[str, dict[str, Any]]] = []
290
311
  for and_group in or_group:
291
312
  key, oper, value = and_group
292
313
  if isinstance(value, str) and any([char in value for char in ['*', '%']]): # wildcards
@@ -327,8 +348,12 @@ class FilterEngine:
327
348
 
328
349
  return query_str
329
350
 
330
- def create_postgres_query(self, additional_filters={}, fixed_table_columns=('scope', 'name', 'vo'),
331
- jsonb_column='data'):
351
+ def create_postgres_query(
352
+ self,
353
+ additional_filters: Optional["Iterable[FilterTuple]"] = None,
354
+ fixed_table_columns: Union[tuple[str, ...], dict[str, str]] = ('scope', 'name', 'vo'),
355
+ jsonb_column: str = 'data'
356
+ ) -> str:
332
357
  """
333
358
  Returns a single postgres query describing the filters expression.
334
359
 
@@ -336,14 +361,15 @@ class FilterEngine:
336
361
  :param fixed_table_columns: the table columns
337
362
  :returns: a postgres query string describing the filters expression.
338
363
  """
364
+ additional_filters = additional_filters or []
339
365
  # Add additional filters, applied as AND clauses to each OR group.
340
366
  for or_group in self._filters:
341
367
  for _filter in additional_filters:
342
- or_group.append(list(_filter))
368
+ or_group.append(list(_filter)) # type: ignore
343
369
 
344
- or_expressions = []
370
+ or_expressions: list[str] = []
345
371
  for or_group in self._filters:
346
- and_expressions = []
372
+ and_expressions: list[str] = []
347
373
  for and_group in or_group:
348
374
  key, oper, value = and_group
349
375
  if key in fixed_table_columns: # is this key filtering on a column or in the jsonb?
@@ -368,7 +394,7 @@ class FilterEngine:
368
394
  # Infer what type key should be cast to from typecasting the value in the expression.
369
395
  try:
370
396
  if isinstance(value, int): # this could be bool or int (as bool subclass of int)
371
- if type(value) == bool:
397
+ if isinstance(value, bool):
372
398
  if is_in_json_column:
373
399
  expression = "({}->>'{}')::boolean {} {}".format(jsonb_column, key, POSTGRES_OP_MAP[oper], str(value).lower())
374
400
  else:
@@ -401,7 +427,14 @@ class FilterEngine:
401
427
  return ' OR '.join(or_expressions)
402
428
 
403
429
  @read_session
404
- def create_sqla_query(self, *, session: "Session", additional_model_attributes=[], additional_filters={}, json_column=None):
430
+ def create_sqla_query(
431
+ self,
432
+ *,
433
+ session: "Session",
434
+ additional_model_attributes: Optional[list[InstrumentedAttribute[Any]]] = None,
435
+ additional_filters: Optional["Iterable[FilterTuple]"] = None,
436
+ json_column: Optional[InstrumentedAttribute] = None
437
+ ) -> Select:
405
438
  """
406
439
  Returns a database query that fully describes the filters.
407
440
 
@@ -412,22 +445,24 @@ class FilterEngine:
412
445
  :param additional_model_attributes: Additional model attributes to retrieve.
413
446
  :param additional_filters: Additional filters to be applied to all clauses.
414
447
  :param json_column: Column to be checked if filter key has not been coerced to a model attribute. Only valid if engine instantiated with strict_coerce=False.
415
- :returns: A database query.
448
+ :returns: A SQLAlchemy Select object.
416
449
  :raises: FilterEngineGenericError
417
450
  """
451
+ additional_model_attributes = additional_model_attributes or []
452
+ additional_filters = additional_filters or []
418
453
  all_model_attributes = set(self.mandatory_model_attributes + additional_model_attributes)
419
454
 
420
455
  # Add additional filters, applied as AND clauses to each OR group.
421
456
  for or_group in self._filters:
422
457
  for _filter in additional_filters:
423
- or_group.append(list(_filter))
458
+ or_group.append(list(_filter)) # type: ignore
424
459
 
425
- or_expressions = []
460
+ or_expressions: list = []
426
461
  for or_group in self._filters:
427
462
  and_expressions = []
428
463
  for and_group in or_group:
429
464
  key, oper, value = and_group
430
- if isinstance(key, sqlalchemy.orm.attributes.InstrumentedAttribute): # -> this key filters on a table column.
465
+ if isinstance(key, InstrumentedAttribute): # -> this key filters on a table column.
431
466
  if isinstance(value, str) and any([char in value for char in ['*', '%']]): # wildcards
432
467
  if value in ('*', '%', '*', '%'): # match wildcard exactly == no filtering on key
433
468
  continue
@@ -473,7 +508,7 @@ class FilterEngine:
473
508
  # Infer what type key should be cast to from typecasting the value in the expression.
474
509
  try:
475
510
  if isinstance(value, int): # this could be bool or int (as bool subclass of int)
476
- if type(value) == bool:
511
+ if isinstance(value, bool):
477
512
  expression = oper(json_column[key].as_boolean(), value)
478
513
  else:
479
514
  expression = oper(json_column[key].as_float(), value) # cast as float, not integer, to avoid potentially losing precision in key
@@ -490,9 +525,14 @@ class FilterEngine:
490
525
 
491
526
  and_expressions.append(expression)
492
527
  or_expressions.append(and_(*and_expressions))
493
- return session.query(*all_model_attributes).filter(or_(*or_expressions))
494
-
495
- def evaluate(self):
528
+ stmt = select(
529
+ *all_model_attributes
530
+ ).where(
531
+ or_(*or_expressions)
532
+ )
533
+ return stmt
534
+
535
+ def evaluate(self) -> bool:
496
536
  """
497
537
  Evaluates an expression and returns a boolean result.
498
538
 
@@ -507,7 +547,7 @@ class FilterEngine:
507
547
  or_group_evaluations.append(all(and_group_evaluations))
508
548
  return any(or_group_evaluations)
509
549
 
510
- def print_filters(self):
550
+ def print_filters(self) -> str:
511
551
  """
512
552
  A (more) human readable format of <filters>.
513
553
  """
@@ -517,16 +557,16 @@ class FilterEngine:
517
557
  for or_group in self._filters:
518
558
  for and_group in or_group:
519
559
  key, oper, value = and_group
520
- if isinstance(key, sqlalchemy.orm.attributes.InstrumentedAttribute):
560
+ if isinstance(key, InstrumentedAttribute):
521
561
  key = and_group[0].key
522
562
  if operators_conversion_LUT_inv[oper] == "":
523
563
  oper = "eq"
524
564
  else:
525
565
  oper = operators_conversion_LUT_inv[oper]
526
- if isinstance(value, sqlalchemy.orm.attributes.InstrumentedAttribute):
527
- value = and_group[2].key
566
+ if isinstance(value, InstrumentedAttribute):
567
+ value = and_group[2].key # type: ignore
528
568
  elif isinstance(value, DIDType):
529
- value = and_group[2].name
569
+ value = and_group[2].name # type: ignore
530
570
  filters = "{}{} {} {}".format(filters, key, oper, value)
531
571
  if and_group != or_group[-1]:
532
572
  filters += ' AND '