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
rucio/db/sqla/models.py CHANGED
@@ -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");
@@ -15,30 +14,50 @@
15
14
 
16
15
  import uuid
17
16
  from datetime import datetime, timedelta
18
- from typing import Any, Optional, Union
17
+ from typing import TYPE_CHECKING, Any, Optional, Union
19
18
 
20
- from sqlalchemy import BigInteger, Boolean, DateTime, Enum, Float, Integer, SmallInteger, String, Text, event, UniqueConstraint, inspect
19
+ from sqlalchemy import BigInteger, Boolean, DateTime, Enum, Float, Integer, SmallInteger, String, Text, UniqueConstraint, event
21
20
  from sqlalchemy.engine import Engine
22
21
  from sqlalchemy.ext.compiler import compiles
23
22
  from sqlalchemy.ext.declarative import declared_attr
24
- from sqlalchemy.orm import mapped_column, object_mapper, relationship, Mapped
25
- from sqlalchemy.schema import Index, ForeignKeyConstraint, PrimaryKeyConstraint, CheckConstraint, Table
23
+ from sqlalchemy.orm import Mapped, mapped_column, object_mapper, relationship
24
+ from sqlalchemy.schema import CheckConstraint, ForeignKeyConstraint, Index, PrimaryKeyConstraint, Table
26
25
  from sqlalchemy.sql import Delete
27
26
  from sqlalchemy.types import LargeBinary
28
27
 
29
28
  from rucio.common import utils
30
29
  from rucio.common.schema import get_schema_value
31
30
  from rucio.common.types import InternalAccount, InternalScope
32
- from rucio.db.sqla.constants import (AccountStatus, AccountType, DIDAvailability, DIDType, DIDReEvaluation,
33
- KeyType, IdentityType, LockState, RuleGrouping, BadFilesStatus,
34
- RuleState, ReplicaState, RequestState, RequestType, RSEType,
35
- ScopeStatus, SubscriptionState, RuleNotification, LifetimeExceptionsState,
36
- BadPFNStatus, TransferLimitDirection)
37
- from rucio.db.sqla.session import BASE, get_engine
38
- from rucio.db.sqla.types import GUID, BooleanString, JSON
39
- from rucio.db.sqla.types import InternalAccountString
40
- from rucio.db.sqla.types import InternalScopeString
41
-
31
+ from rucio.db.sqla.constants import (
32
+ AccountStatus,
33
+ AccountType,
34
+ BadFilesStatus,
35
+ BadPFNStatus,
36
+ DIDAvailability,
37
+ DIDReEvaluation,
38
+ DIDType,
39
+ IdentityType,
40
+ KeyType,
41
+ LifetimeExceptionsState,
42
+ LockState,
43
+ ReplicaState,
44
+ RequestState,
45
+ RequestType,
46
+ RSEType,
47
+ RuleGrouping,
48
+ RuleNotification,
49
+ RuleState,
50
+ ScopeStatus,
51
+ SubscriptionState,
52
+ TransferLimitDirection,
53
+ )
54
+ from rucio.db.sqla.session import BASE
55
+ from rucio.db.sqla.types import GUID, JSON, BooleanString, InternalAccountString, InternalScopeString
56
+
57
+ if TYPE_CHECKING:
58
+ from sqlalchemy.engine.base import Connection
59
+ from sqlalchemy.orm import Session
60
+ from sqlalchemy.sql import Insert, Update
42
61
 
43
62
  # SQLAlchemy defines the corresponding code behind TYPE_CHECKING
44
63
  # https://github.com/sqlalchemy/sqlalchemy/blob/d9acd6223299c118464d30abfa483e26a536239d/lib/sqlalchemy/orm/base.py#L814
@@ -50,24 +69,24 @@ from rucio.db.sqla.types import InternalScopeString
50
69
 
51
70
 
52
71
  @compiles(Boolean, "oracle")
53
- def compile_binary_oracle(type_, compiler, **kw):
72
+ def compile_binary_oracle(type_, compiler, **kw) -> str:
54
73
  return "NUMBER(1)"
55
74
 
56
75
 
57
76
  @event.listens_for(Table, "before_create")
58
- def _mysql_rename_type(target, connection, **kw):
77
+ def _mysql_rename_type(target: Table, connection: "Connection", **kw) -> None:
59
78
  if connection.dialect.name == 'mysql' and target.name == 'quarantined_replicas':
60
79
  target.columns.path.type = String(255)
61
80
 
62
81
 
63
82
  @event.listens_for(Table, "before_create")
64
- def _psql_rename_type(target, connection, **kw):
83
+ def _psql_rename_type(target: Table, connection: "Connection", **kw) -> None:
65
84
  if connection.dialect.name == 'postgresql' and target.name == 'account_map':
66
85
  target.columns.identity_type.type.name = 'IDENTITIES_TYPE_CHK'
67
86
 
68
87
 
69
88
  @event.listens_for(Table, "before_create")
70
- def _oracle_json_constraint(target, connection, **kw):
89
+ def _oracle_json_constraint(target: Table, connection: "Connection", **kw) -> None:
71
90
  if connection.dialect.name == 'oracle':
72
91
  try:
73
92
  oracle_version = int(connection.connection.version.split('.')[0])
@@ -76,12 +95,20 @@ def _oracle_json_constraint(target, connection, **kw):
76
95
  if oracle_version >= 12:
77
96
  if target.name == 'did_meta':
78
97
  target.append_constraint(CheckConstraint('META IS JSON', 'ORACLE_META_JSON_CHK'))
98
+ if target.name == 'deleted_did_meta':
99
+ target.append_constraint(CheckConstraint('META IS JSON', 'ORACLE_DELETE_META_JSON_CHK'))
79
100
  if target.name == 'virtual_placements':
80
101
  target.append_constraint(CheckConstraint('PLACEMENTS IS JSON', 'ORACLE_PLACEMENTS_JSON_CHK'))
81
102
 
82
103
 
83
104
  @event.listens_for(Engine, "before_execute", retval=True)
84
- def _add_hint(conn, element, multiparams, params, execution_options):
105
+ def _add_hint(
106
+ conn: "Connection",
107
+ element: Union[Delete, "Insert", "Update"],
108
+ multiparams,
109
+ params,
110
+ execution_options
111
+ ) -> tuple[Union[Delete, "Insert", "Update"], list, dict]:
85
112
  if conn.dialect.name == 'oracle' and isinstance(element, Delete) and element.table.name == 'locks':
86
113
  element = element.prefix_with("/*+ INDEX(LOCKS LOCKS_PK) */")
87
114
  if conn.dialect.name == 'oracle' and isinstance(element, Delete) and element.table.name == 'replicas':
@@ -96,7 +123,7 @@ def _add_hint(conn, element, multiparams, params, execution_options):
96
123
 
97
124
 
98
125
  @event.listens_for(PrimaryKeyConstraint, "after_parent_attach")
99
- def _pk_constraint_name(const, table):
126
+ def _pk_constraint_name(const: PrimaryKeyConstraint, table: Table) -> None:
100
127
  if table.name.upper() == 'QUARANTINED_REPLICAS_HISTORY':
101
128
  const.name = "QRD_REPLICAS_HISTORY_PK"
102
129
  else:
@@ -104,7 +131,7 @@ def _pk_constraint_name(const, table):
104
131
 
105
132
 
106
133
  @event.listens_for(ForeignKeyConstraint, "after_parent_attach")
107
- def _fk_constraint_name(const, table):
134
+ def _fk_constraint_name(const: ForeignKeyConstraint, table: Table) -> None:
108
135
  if const.name:
109
136
  return
110
137
  fk = const.elements[0]
@@ -115,14 +142,14 @@ def _fk_constraint_name(const, table):
115
142
 
116
143
 
117
144
  @event.listens_for(UniqueConstraint, "after_parent_attach")
118
- def _unique_constraint_name(const, table):
145
+ def _unique_constraint_name(const: UniqueConstraint, table: Table) -> None:
119
146
  if const.name:
120
147
  return
121
148
  const.name = "uq_%s_%s" % (table.name, list(const.columns)[0].name)
122
149
 
123
150
 
124
151
  @event.listens_for(CheckConstraint, "after_parent_attach")
125
- def _ck_constraint_name(const, table):
152
+ def _ck_constraint_name(const: CheckConstraint, table: Table) -> None:
126
153
 
127
154
  if const.name is None:
128
155
  if 'DELETED' in str(const.sqltext).upper():
@@ -168,7 +195,7 @@ def _ck_constraint_name(const, table):
168
195
  const.name = "REQUESTS_HISTORY_STATE_CHK"
169
196
 
170
197
 
171
- class ModelBase(object):
198
+ class ModelBase:
172
199
  """Base class for Rucio Models"""
173
200
  __table_initialized__ = False
174
201
 
@@ -205,23 +232,23 @@ class ModelBase(object):
205
232
  def updated_at(cls): # pylint: disable=no-self-argument
206
233
  return mapped_column("updated_at", DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
207
234
 
208
- def save(self, flush=True, session=None):
235
+ def save(self, flush: bool = True, session: Optional["Session"] = None) -> None:
209
236
  """Save this object"""
210
- # Sessions created with autoflush=True be default since sqlAlchemy 1.4.
211
- # So explicatly calling session.flush is not necessary.
237
+ # Sessions created with autoflush: bool = True be default since sqlAlchemy 1.4.
238
+ # So explicitly calling session.flush is not necessary.
212
239
  # However, when autogenerated primary keys involved, calling
213
240
  # session.flush to get the id from DB.
214
241
  session.add(self)
215
242
  if flush:
216
243
  session.flush()
217
244
 
218
- def delete(self, flush=True, session=None):
245
+ def delete(self, flush: bool = True, session: Optional["Session"] = None) -> None:
219
246
  """Delete this object"""
220
247
  session.delete(self)
221
248
  if flush:
222
249
  session.flush()
223
250
 
224
- def update(self, values, flush=True, session=None):
251
+ def update(self, values: dict[str, Any], flush: bool = True, session: Optional["Session"] = None) -> None:
225
252
  """dict.update() behaviour."""
226
253
  for k, v in values.items():
227
254
  self[k] = v
@@ -279,7 +306,7 @@ class SoftModelBase(ModelBase):
279
306
  def deleted_at(cls): # pylint: disable=no-self-argument
280
307
  return mapped_column("deleted_at", DateTime)
281
308
 
282
- def delete(self, flush=True, session=None):
309
+ def delete(self, flush: bool = True, session: Optional["Session"] = None) -> None:
283
310
  """Delete this object"""
284
311
  self.deleted = True
285
312
  self.deleted_at = datetime.utcnow()
@@ -462,6 +489,19 @@ class DidMeta(BASE, ModelBase):
462
489
  Index('DID_META_DID_TYPE_IDX', 'did_type'))
463
490
 
464
491
 
492
+ class DeletedDidMeta(BASE, ModelBase):
493
+ __tablename__ = 'deleted_did_meta'
494
+ scope: Mapped[InternalScope] = mapped_column(InternalScopeString(get_schema_value('SCOPE_LENGTH')))
495
+ name: Mapped[str] = mapped_column(String(get_schema_value('NAME_LENGTH')))
496
+ did_type: Mapped[Optional[DIDType]] = mapped_column(Enum(DIDType, name='DEL_DID_META_DID_TYPE_CHK',
497
+ create_constraint=True,
498
+ values_callable=lambda obj: [e.value for e in obj]))
499
+ meta: Mapped[Optional[Union[str, dict[str, Any]]]] = mapped_column(JSON())
500
+ deleted_at: Mapped[Optional[datetime]] = mapped_column(DateTime)
501
+ _table_args = (PrimaryKeyConstraint('scope', 'name', name='DEL_DID_META_PK'),
502
+ Index('DEL_DID_META_DID_TYPE_IDX', 'did_type'))
503
+
504
+
465
505
  class DeletedDataIdentifier(BASE, ModelBase):
466
506
  """Represents a dataset"""
467
507
  __tablename__ = 'deleted_dids'
@@ -534,7 +574,7 @@ class UpdatedDID(BASE, ModelBase):
534
574
  Index('UPDATED_DIDS_SCOPERULENAME_IDX', 'scope', 'rule_evaluation_action', 'name'))
535
575
 
536
576
 
537
- class BadReplicas(BASE, ModelBase):
577
+ class BadReplica(BASE, ModelBase):
538
578
  """Represents the suspicious or bad replicas"""
539
579
  __tablename__ = 'bad_replicas'
540
580
  scope: Mapped[InternalScope] = mapped_column(InternalScopeString(get_schema_value('SCOPE_LENGTH')))
@@ -558,8 +598,8 @@ class BadReplicas(BASE, ModelBase):
558
598
  Index('BAD_REPLICAS_ACCOUNT_IDX', 'account'))
559
599
 
560
600
 
561
- class BadPFNs(BASE, ModelBase):
562
- """Represents bad, suspicious or temporary unavailable PFNs which have to be processed and added to BadReplicas Table"""
601
+ class BadPFN(BASE, ModelBase):
602
+ """Represents bad, suspicious or temporary unavailable PFNs which have to be processed and added to BadReplica Table"""
563
603
  __tablename__ = 'bad_pfns'
564
604
  path: Mapped[str] = mapped_column(String(2048)) # PREFIX + PFN
565
605
  state: Mapped[BadPFNStatus] = mapped_column(Enum(BadPFNStatus, name='BAD_PFNS_STATE_CHK',
@@ -605,8 +645,8 @@ class QuarantinedReplicaHistory(BASE, ModelBase):
605
645
  _table_args = ()
606
646
 
607
647
 
608
- class DIDKey(BASE, ModelBase):
609
- """Represents Data IDentifier property keys"""
648
+ class DIDMetaConventionsKey(BASE, ModelBase):
649
+ """Represents allowed keys of DID Metadata"""
610
650
  __tablename__ = 'did_keys'
611
651
  key: Mapped[str] = mapped_column(String(255))
612
652
  is_enum: Mapped[bool] = mapped_column(Boolean(name='DID_KEYS_IS_ENUM_CHK', create_constraint=True),
@@ -621,8 +661,8 @@ class DIDKey(BASE, ModelBase):
621
661
  CheckConstraint('is_enum IS NOT NULL', name='DID_KEYS_IS_ENUM_NN'))
622
662
 
623
663
 
624
- class DIDKeyValueAssociation(BASE, ModelBase):
625
- """Represents Data IDentifier property key/values"""
664
+ class DIDMetaConventionsConstraint(BASE, ModelBase):
665
+ """Represents a map for constraint values a DID metadata key must follow """
626
666
  __tablename__ = 'did_key_map'
627
667
  key: Mapped[str] = mapped_column(String(255))
628
668
  value: Mapped[str] = mapped_column(String(255))
@@ -854,12 +894,12 @@ class RSEAttrAssociation(BASE, ModelBase):
854
894
  Index('RSE_ATTR_MAP_KEY_VALUE_IDX', 'key', 'value'))
855
895
 
856
896
 
857
- class RSEProtocols(BASE, ModelBase):
897
+ class RSEProtocol(BASE, ModelBase):
858
898
  """Represents supported protocols of RSEs (Rucio Storage Elements)"""
859
899
  __tablename__ = 'rse_protocols'
860
900
  rse_id: Mapped[uuid.UUID] = mapped_column(GUID())
861
901
  scheme: Mapped[str] = mapped_column(String(255))
862
- hostname: Mapped[str] = mapped_column(String(255), server_default='') # For protocol without host e.g. POSIX on local file systems localhost is assumed as beeing default
902
+ hostname: Mapped[str] = mapped_column(String(255), server_default='') # For protocol without host e.g. POSIX on local file systems localhost is assumed as being default
863
903
  port: Mapped[int] = mapped_column(Integer, server_default='0') # like host, for local protocol the port 0 is assumed to be default
864
904
  prefix: Mapped[Optional[str]] = mapped_column(String(1024), nullable=True)
865
905
  impl: Mapped[str] = mapped_column(String(255), nullable=False)
@@ -1408,30 +1448,36 @@ class SourceHistory(BASE, ModelBase):
1408
1448
  )
1409
1449
 
1410
1450
 
1411
- # Compatibility code to permit 1.30 to run with a distances table from the 1.29 database schema
1412
- # TODO: remove this code in rucio 1.31
1413
- _distance_column_name = 'distance'
1414
- _engine = get_engine()
1415
- if _engine.dialect.name in ['oracle', 'mysql', 'postgresql']:
1416
- _insp = inspect(_engine)
1417
- if _engine.dialect.name in ['oracle', 'postgresql'] or BASE.metadata.schema in _insp.get_schema_names():
1418
- if 'distances' in _insp.get_table_names(schema=BASE.metadata.schema):
1419
- if any(c['name'] == 'ranking' for c in _insp.get_columns(table_name='distances', schema=BASE.metadata.schema)):
1420
- _distance_column_name = 'ranking'
1421
-
1422
-
1423
1451
  class Distance(BASE, ModelBase):
1424
1452
  """Represents distance between rses"""
1425
1453
  __tablename__ = 'distances'
1426
1454
  src_rse_id: Mapped[uuid.UUID] = mapped_column(GUID())
1427
1455
  dest_rse_id: Mapped[uuid.UUID] = mapped_column(GUID())
1428
- distance: Mapped[Optional[int]] = mapped_column(Integer(), name=_distance_column_name)
1456
+ distance: Mapped[Optional[int]] = mapped_column(Integer())
1429
1457
  _table_args = (PrimaryKeyConstraint('src_rse_id', 'dest_rse_id', name='DISTANCES_PK'),
1430
1458
  ForeignKeyConstraint(['src_rse_id'], ['rses.id'], name='DISTANCES_SRC_RSES_FK'),
1431
1459
  ForeignKeyConstraint(['dest_rse_id'], ['rses.id'], name='DISTANCES_DEST_RSES_FK'),
1432
1460
  Index('DISTANCES_DEST_RSEID_IDX', 'dest_rse_id'))
1433
1461
 
1434
1462
 
1463
+ class TransferStats(BASE, ModelBase):
1464
+ """Represents counters for transfer link usage"""
1465
+ __tablename__ = 'transfer_stats'
1466
+ id: Mapped[uuid.UUID] = mapped_column(GUID(), default=utils.generate_uuid)
1467
+ resolution: Mapped[int] = mapped_column(Integer)
1468
+ timestamp: Mapped[datetime] = mapped_column(DateTime)
1469
+ dest_rse_id: Mapped[uuid.UUID] = mapped_column(GUID())
1470
+ src_rse_id: Mapped[uuid.UUID] = mapped_column(GUID())
1471
+ activity: Mapped[Optional[str]] = mapped_column(String(50))
1472
+ files_done: Mapped[int] = mapped_column(BigInteger)
1473
+ bytes_done: Mapped[int] = mapped_column(BigInteger)
1474
+ files_failed: Mapped[int] = mapped_column(BigInteger)
1475
+ _table_args = (PrimaryKeyConstraint('id', name='TRANSFER_STATS_PK'),
1476
+ ForeignKeyConstraint(['dest_rse_id'], ['rses.id'], name='TRANSFER_STATS_DEST_RSE_FK'),
1477
+ ForeignKeyConstraint(['src_rse_id'], ['rses.id'], name='TRANSFER_STATS_SRC_RSE_FK'),
1478
+ Index('TRANSFER_STATS_KEY_IDX', 'resolution', 'timestamp', 'dest_rse_id', 'src_rse_id', 'activity'))
1479
+
1480
+
1435
1481
  class Subscription(BASE, ModelBase):
1436
1482
  """Represents a subscription"""
1437
1483
  __tablename__ = 'subscriptions'
@@ -1478,7 +1524,7 @@ class SubscriptionHistory(BASE, ModelBase):
1478
1524
  retroactive: Mapped[bool] = mapped_column(Boolean(name='SUBS_HISTORY_RETROACTIVE_CHK', create_constraint=True),
1479
1525
  default=False)
1480
1526
  expired_at: Mapped[Optional[datetime]] = mapped_column(DateTime)
1481
- _table_args = (PrimaryKeyConstraint('id', 'updated_at', name='SUBSCRIPTIONS_PK'),)
1527
+ _table_args = (PrimaryKeyConstraint('id', 'updated_at', name='SUBSCRIPTIONS_HISTORY_PK'),)
1482
1528
 
1483
1529
 
1484
1530
  class Token(BASE, ModelBase):
@@ -1575,7 +1621,7 @@ class ConfigHistory(BASE, ModelBase):
1575
1621
  _table_args = ()
1576
1622
 
1577
1623
 
1578
- class Heartbeats(BASE, ModelBase):
1624
+ class Heartbeat(BASE, ModelBase):
1579
1625
  """Represents the status and heartbeat of the running daemons and services"""
1580
1626
  __tablename__ = 'heartbeats'
1581
1627
  executable: Mapped[str] = mapped_column(String(64)) # SHA-2
@@ -1600,29 +1646,7 @@ class NamingConvention(BASE, ModelBase):
1600
1646
  ForeignKeyConstraint(['scope'], ['scopes.scope'], name='NAMING_CONVENTIONS_SCOPE_FK'))
1601
1647
 
1602
1648
 
1603
- class TemporaryDataIdentifier(BASE, ModelBase):
1604
- """Represents a temporary DID (pre-merged files, etc.)"""
1605
- __tablename__ = 'tmp_dids'
1606
- scope: Mapped[InternalScope] = mapped_column(InternalScopeString(get_schema_value('SCOPE_LENGTH')))
1607
- name: Mapped[str] = mapped_column(String(get_schema_value('NAME_LENGTH')))
1608
- rse_id: Mapped[Optional[uuid.UUID]] = mapped_column(GUID())
1609
- path: Mapped[Optional[str]] = mapped_column(String(1024))
1610
- bytes: Mapped[Optional[int]] = mapped_column(BigInteger)
1611
- md5: Mapped[Optional[str]] = mapped_column(String(32))
1612
- adler32: Mapped[Optional[str]] = mapped_column(String(8))
1613
- expired_at: Mapped[Optional[datetime]] = mapped_column(DateTime)
1614
- guid: Mapped[Optional[uuid.UUID]] = mapped_column(GUID())
1615
- events: Mapped[Optional[int]] = mapped_column(BigInteger)
1616
- task_id: Mapped[Optional[int]] = mapped_column(Integer())
1617
- panda_id: Mapped[Optional[int]] = mapped_column(Integer())
1618
- parent_scope: Mapped[Optional[InternalScope]] = mapped_column(InternalScopeString(get_schema_value('SCOPE_LENGTH')))
1619
- parent_name: Mapped[Optional[str]] = mapped_column(String(get_schema_value('NAME_LENGTH')))
1620
- offset: Mapped[Optional[int]] = mapped_column(BigInteger)
1621
- _table_args = (PrimaryKeyConstraint('scope', 'name', name='TMP_DIDS_PK'),
1622
- Index('TMP_DIDS_EXPIRED_AT_IDX', 'expired_at'))
1623
-
1624
-
1625
- class LifetimeExceptions(BASE, ModelBase):
1649
+ class LifetimeException(BASE, ModelBase):
1626
1650
  """Represents the exceptions to the lifetime model"""
1627
1651
  __tablename__ = 'lifetime_except'
1628
1652
  id: Mapped[uuid.UUID] = mapped_column(GUID(), default=utils.generate_uuid)
@@ -1654,8 +1678,8 @@ class VO(BASE, ModelBase):
1654
1678
  _table_args = (PrimaryKeyConstraint('vo', name='VOS_PK'), )
1655
1679
 
1656
1680
 
1657
- class DidsFollowed(BASE, ModelBase):
1658
- """Represents the datasets followed by an user"""
1681
+ class DidFollowed(BASE, ModelBase):
1682
+ """Represents the datasets followed by a user"""
1659
1683
  __tablename__ = 'dids_followed'
1660
1684
  scope: Mapped[InternalScope] = mapped_column(InternalScopeString(get_schema_value('SCOPE_LENGTH')))
1661
1685
  name: Mapped[str] = mapped_column(String(get_schema_value('NAME_LENGTH')))
@@ -1672,7 +1696,7 @@ class DidsFollowed(BASE, ModelBase):
1672
1696
  ForeignKeyConstraint(['scope', 'name'], ['dids.scope', 'dids.name'], name='DIDS_FOLLOWED_SCOPE_NAME_FK'))
1673
1697
 
1674
1698
 
1675
- class FollowEvents(BASE, ModelBase):
1699
+ class FollowEvent(BASE, ModelBase):
1676
1700
  """Represents the events affecting the datasets which are followed"""
1677
1701
  __tablename__ = 'dids_followed_events'
1678
1702
  scope: Mapped[InternalScope] = mapped_column(InternalScopeString(get_schema_value('SCOPE_LENGTH')))
@@ -1692,143 +1716,25 @@ class FollowEvents(BASE, ModelBase):
1692
1716
  Index('DIDS_FOLLOWED_EVENTS_ACC_IDX', 'account'))
1693
1717
 
1694
1718
 
1695
- def register_models(engine):
1719
+ def register_models(engine: Engine) -> None:
1696
1720
  """
1697
- Creates database tables for all models with the given engine
1721
+ Creates database tables for all models in the `BASE.metadata` schema with the given engine.
1722
+ Functionally this creates all models, as they all inherit from BASE and exist in the same `BASE.metadata` schema.
1723
+
1724
+ :param engine: engine to register the models with
1725
+ :type engine: sqlalchemy.engine.Engine
1726
+ :returns: None
1698
1727
  """
1728
+ BASE.metadata.create_all(engine)
1699
1729
 
1700
- models = (Account,
1701
- AccountAttrAssociation,
1702
- AccountLimit,
1703
- AccountGlobalLimit,
1704
- AccountUsage,
1705
- AccountUsageHistory,
1706
- AlembicVersion,
1707
- BadReplicas,
1708
- CollectionReplica,
1709
- Config,
1710
- ConfigHistory,
1711
- ConstituentAssociation,
1712
- ConstituentAssociationHistory,
1713
- DataIdentifierAssociation,
1714
- DataIdentifierAssociationHistory,
1715
- DIDKey,
1716
- DIDKeyValueAssociation,
1717
- DataIdentifier,
1718
- DidMeta,
1719
- VirtualPlacements,
1720
- DeletedDataIdentifier,
1721
- DidsFollowed,
1722
- FollowEvents,
1723
- Heartbeats,
1724
- Identity,
1725
- IdentityAccountAssociation,
1726
- LifetimeExceptions,
1727
- Message,
1728
- MessageHistory,
1729
- NamingConvention,
1730
- OAuthRequest,
1731
- QuarantinedReplica,
1732
- QuarantinedReplicaHistory,
1733
- RSE,
1734
- RSEAttrAssociation,
1735
- RSEFileAssociation,
1736
- RSEFileAssociationHistory,
1737
- RSELimit,
1738
- RSEProtocols,
1739
- RSEQoSAssociation,
1740
- RSEUsage,
1741
- RSEUsageHistory,
1742
- ReplicaLock,
1743
- ReplicationRule,
1744
- ReplicationRule,
1745
- ReplicationRuleHistory,
1746
- ReplicationRuleHistoryRecent,
1747
- Request,
1748
- RequestHistory,
1749
- TransferHop,
1750
- Scope,
1751
- Source,
1752
- SourceHistory,
1753
- Subscription,
1754
- SubscriptionHistory,
1755
- TemporaryDataIdentifier,
1756
- Token,
1757
- UpdatedAccountCounter,
1758
- UpdatedDID,
1759
- UpdatedRSECounter,
1760
- UpdatedCollectionReplica,
1761
- VO)
1762
-
1763
- for model in models:
1764
- model.metadata.create_all(engine) # pylint: disable=maybe-no-member
1765
-
1766
-
1767
- def unregister_models(engine):
1730
+
1731
+ def unregister_models(engine: Engine) -> None:
1768
1732
  """
1769
- Drops database tables for all models with the given engine
1733
+ Drops database tables for all models in the `BASE.metadata` schema with the given engine.
1734
+ Functionally this drops all models, as they all inherit from BASE and exist in the same `BASE.metadata` schema.
1735
+
1736
+ :param engine: The engine to unregister the models with
1737
+ :type engine: sqlalchemy.engine.Engine
1738
+ :returns: None
1770
1739
  """
1771
- models = (Account,
1772
- AccountAttrAssociation,
1773
- AccountLimit,
1774
- AccountGlobalLimit,
1775
- AccountUsage,
1776
- AccountUsageHistory,
1777
- AlembicVersion,
1778
- BadReplicas,
1779
- CollectionReplica,
1780
- Config,
1781
- ConfigHistory,
1782
- ConstituentAssociation,
1783
- ConstituentAssociationHistory,
1784
- DataIdentifierAssociation,
1785
- DataIdentifierAssociationHistory,
1786
- DIDKey,
1787
- DIDKeyValueAssociation,
1788
- DidMeta,
1789
- DataIdentifier,
1790
- DeletedDataIdentifier,
1791
- DidsFollowed,
1792
- FollowEvents,
1793
- Heartbeats,
1794
- Identity,
1795
- IdentityAccountAssociation,
1796
- LifetimeExceptions,
1797
- Message,
1798
- MessageHistory,
1799
- NamingConvention,
1800
- OAuthRequest,
1801
- QuarantinedReplica,
1802
- QuarantinedReplicaHistory,
1803
- RSE,
1804
- RSEAttrAssociation,
1805
- RSEFileAssociation,
1806
- RSEFileAssociationHistory,
1807
- RSELimit,
1808
- RSEProtocols,
1809
- RSEQoSAssociation,
1810
- RSEUsage,
1811
- RSEUsageHistory,
1812
- ReplicaLock,
1813
- ReplicationRule,
1814
- ReplicationRule,
1815
- ReplicationRuleHistory,
1816
- ReplicationRuleHistoryRecent,
1817
- Request,
1818
- RequestHistory,
1819
- TransferHop,
1820
- Scope,
1821
- Source,
1822
- SourceHistory,
1823
- Subscription,
1824
- SubscriptionHistory,
1825
- Token,
1826
- TemporaryDataIdentifier,
1827
- UpdatedAccountCounter,
1828
- UpdatedDID,
1829
- UpdatedRSECounter,
1830
- UpdatedCollectionReplica,
1831
- VO)
1832
-
1833
- for model in models:
1834
- model.metadata.drop_all(engine) # pylint: disable=maybe-no-member
1740
+ BASE.metadata.drop_all(engine)
rucio/db/sqla/sautils.py CHANGED
@@ -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");
@@ -18,19 +17,27 @@ SQLAlchemy utilities
18
17
 
19
18
  '''
20
19
 
20
+ from typing import TYPE_CHECKING, Any, Union
21
+
21
22
  from sqlalchemy.ext.compiler import compiles
22
- from sqlalchemy.sql.expression import Executable, ClauseElement
23
+ from sqlalchemy.sql.expression import ClauseElement, Executable
24
+
25
+ if TYPE_CHECKING:
26
+ from sqlalchemy import Table
27
+ from sqlalchemy.engine.interfaces import SQLCompiler
28
+ from sqlalchemy.sql.schema import Column
29
+ from sqlalchemy.sql.selectable import Select
23
30
 
24
31
 
25
32
  class InsertFromSelect(Executable, ClauseElement):
26
- def __init__(self, insert_spec, select):
33
+ def __init__(self, insert_spec: "Union[Table, list[Column]]", select: "Select") -> None:
27
34
  self.insert_spec = insert_spec
28
35
  self.select = select
29
36
 
30
37
 
31
38
  @compiles(InsertFromSelect)
32
- def visit_insert_from_select(element, compiler, **kw):
33
- if type(element.insert_spec) == list:
39
+ def visit_insert_from_select(element: InsertFromSelect, compiler: "SQLCompiler", **kw: Any) -> str:
40
+ if isinstance(element.insert_spec, list):
34
41
  columns = []
35
42
  for column in element.insert_spec:
36
43
  if element.insert_spec[0].table != column.table: