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.
- rucio/__init__.py +0 -1
- rucio/alembicrevision.py +1 -2
- rucio/client/__init__.py +0 -1
- rucio/client/accountclient.py +45 -25
- rucio/client/accountlimitclient.py +37 -9
- rucio/client/baseclient.py +199 -154
- rucio/client/client.py +2 -3
- rucio/client/configclient.py +19 -6
- rucio/client/credentialclient.py +9 -4
- rucio/client/didclient.py +238 -63
- rucio/client/diracclient.py +13 -5
- rucio/client/downloadclient.py +162 -51
- rucio/client/exportclient.py +4 -4
- rucio/client/fileclient.py +3 -4
- rucio/client/importclient.py +4 -4
- rucio/client/lifetimeclient.py +21 -5
- rucio/client/lockclient.py +18 -8
- rucio/client/{metaclient.py → metaconventionsclient.py} +18 -15
- rucio/client/pingclient.py +0 -1
- rucio/client/replicaclient.py +15 -5
- rucio/client/requestclient.py +35 -19
- rucio/client/rseclient.py +133 -51
- rucio/client/ruleclient.py +29 -22
- rucio/client/scopeclient.py +8 -6
- rucio/client/subscriptionclient.py +47 -35
- rucio/client/touchclient.py +8 -4
- rucio/client/uploadclient.py +166 -82
- rucio/common/__init__.py +0 -1
- rucio/common/cache.py +4 -4
- rucio/common/config.py +52 -47
- rucio/common/constants.py +69 -2
- rucio/common/constraints.py +0 -1
- rucio/common/didtype.py +24 -22
- rucio/common/dumper/__init__.py +70 -41
- rucio/common/dumper/consistency.py +26 -22
- rucio/common/dumper/data_models.py +16 -23
- rucio/common/dumper/path_parsing.py +0 -1
- rucio/common/exception.py +281 -222
- rucio/common/extra.py +0 -1
- rucio/common/logging.py +54 -38
- rucio/common/pcache.py +122 -101
- rucio/common/plugins.py +153 -0
- rucio/common/policy.py +4 -4
- rucio/common/schema/__init__.py +17 -10
- rucio/common/schema/atlas.py +7 -5
- rucio/common/schema/belleii.py +7 -5
- rucio/common/schema/domatpc.py +7 -5
- rucio/common/schema/escape.py +7 -5
- rucio/common/schema/generic.py +8 -6
- rucio/common/schema/generic_multi_vo.py +7 -5
- rucio/common/schema/icecube.py +7 -5
- rucio/common/stomp_utils.py +0 -1
- rucio/common/stopwatch.py +0 -1
- rucio/common/test_rucio_server.py +2 -2
- rucio/common/types.py +262 -17
- rucio/common/utils.py +743 -451
- rucio/core/__init__.py +0 -1
- rucio/core/account.py +99 -29
- rucio/core/account_counter.py +89 -24
- rucio/core/account_limit.py +90 -24
- rucio/core/authentication.py +86 -29
- rucio/core/config.py +108 -38
- rucio/core/credential.py +14 -7
- rucio/core/did.py +680 -782
- rucio/core/did_meta_plugins/__init__.py +8 -6
- rucio/core/did_meta_plugins/did_column_meta.py +17 -12
- rucio/core/did_meta_plugins/did_meta_plugin_interface.py +60 -11
- rucio/core/did_meta_plugins/filter_engine.py +90 -50
- rucio/core/did_meta_plugins/json_meta.py +41 -16
- rucio/core/did_meta_plugins/mongo_meta.py +25 -8
- rucio/core/did_meta_plugins/postgres_meta.py +3 -4
- rucio/core/dirac.py +46 -17
- rucio/core/distance.py +66 -43
- rucio/core/exporter.py +5 -5
- rucio/core/heartbeat.py +181 -81
- rucio/core/identity.py +22 -12
- rucio/core/importer.py +23 -12
- rucio/core/lifetime_exception.py +32 -32
- rucio/core/lock.py +244 -142
- rucio/core/message.py +79 -38
- rucio/core/{meta.py → meta_conventions.py} +57 -44
- rucio/core/monitor.py +19 -13
- rucio/core/naming_convention.py +68 -27
- rucio/core/nongrid_trace.py +17 -5
- rucio/core/oidc.py +151 -29
- rucio/core/permission/__init__.py +18 -6
- rucio/core/permission/atlas.py +50 -35
- rucio/core/permission/belleii.py +6 -5
- rucio/core/permission/escape.py +8 -6
- rucio/core/permission/generic.py +82 -80
- rucio/core/permission/generic_multi_vo.py +9 -7
- rucio/core/quarantined_replica.py +91 -58
- rucio/core/replica.py +1303 -772
- rucio/core/replica_sorter.py +10 -12
- rucio/core/request.py +1133 -285
- rucio/core/rse.py +142 -102
- rucio/core/rse_counter.py +49 -18
- rucio/core/rse_expression_parser.py +6 -7
- rucio/core/rse_selector.py +41 -16
- rucio/core/rule.py +1538 -474
- rucio/core/rule_grouping.py +213 -68
- rucio/core/scope.py +50 -22
- rucio/core/subscription.py +92 -44
- rucio/core/topology.py +66 -24
- rucio/core/trace.py +42 -28
- rucio/core/transfer.py +543 -259
- rucio/core/vo.py +36 -18
- rucio/core/volatile_replica.py +59 -32
- rucio/daemons/__init__.py +0 -1
- rucio/daemons/abacus/__init__.py +0 -1
- rucio/daemons/abacus/account.py +29 -19
- rucio/daemons/abacus/collection_replica.py +21 -10
- rucio/daemons/abacus/rse.py +22 -12
- rucio/daemons/atropos/__init__.py +0 -1
- rucio/daemons/atropos/atropos.py +1 -2
- rucio/daemons/auditor/__init__.py +56 -28
- rucio/daemons/auditor/hdfs.py +17 -6
- rucio/daemons/auditor/srmdumps.py +116 -45
- rucio/daemons/automatix/__init__.py +0 -1
- rucio/daemons/automatix/automatix.py +30 -18
- rucio/daemons/badreplicas/__init__.py +0 -1
- rucio/daemons/badreplicas/minos.py +29 -18
- rucio/daemons/badreplicas/minos_temporary_expiration.py +5 -7
- rucio/daemons/badreplicas/necromancer.py +9 -13
- rucio/daemons/bb8/__init__.py +0 -1
- rucio/daemons/bb8/bb8.py +10 -13
- rucio/daemons/bb8/common.py +151 -154
- rucio/daemons/bb8/nuclei_background_rebalance.py +15 -9
- rucio/daemons/bb8/t2_background_rebalance.py +15 -8
- rucio/daemons/c3po/__init__.py +0 -1
- rucio/daemons/c3po/algorithms/__init__.py +0 -1
- rucio/daemons/c3po/algorithms/simple.py +8 -5
- rucio/daemons/c3po/algorithms/t2_free_space.py +10 -7
- rucio/daemons/c3po/algorithms/t2_free_space_only_pop.py +10 -7
- rucio/daemons/c3po/algorithms/t2_free_space_only_pop_with_network.py +30 -15
- rucio/daemons/c3po/c3po.py +81 -52
- rucio/daemons/c3po/collectors/__init__.py +0 -1
- rucio/daemons/c3po/collectors/agis.py +17 -17
- rucio/daemons/c3po/collectors/free_space.py +32 -13
- rucio/daemons/c3po/collectors/jedi_did.py +14 -5
- rucio/daemons/c3po/collectors/mock_did.py +11 -6
- rucio/daemons/c3po/collectors/network_metrics.py +12 -4
- rucio/daemons/c3po/collectors/workload.py +21 -19
- rucio/daemons/c3po/utils/__init__.py +0 -1
- rucio/daemons/c3po/utils/dataset_cache.py +15 -5
- rucio/daemons/c3po/utils/expiring_dataset_cache.py +16 -5
- rucio/daemons/c3po/utils/expiring_list.py +6 -7
- rucio/daemons/c3po/utils/popularity.py +5 -2
- rucio/daemons/c3po/utils/timeseries.py +25 -12
- rucio/daemons/cache/__init__.py +0 -1
- rucio/daemons/cache/consumer.py +21 -15
- rucio/daemons/common.py +42 -18
- rucio/daemons/conveyor/__init__.py +0 -1
- rucio/daemons/conveyor/common.py +69 -37
- rucio/daemons/conveyor/finisher.py +83 -46
- rucio/daemons/conveyor/poller.py +101 -69
- rucio/daemons/conveyor/preparer.py +35 -28
- rucio/daemons/conveyor/receiver.py +64 -21
- rucio/daemons/conveyor/stager.py +33 -28
- rucio/daemons/conveyor/submitter.py +71 -47
- rucio/daemons/conveyor/throttler.py +99 -35
- rucio/daemons/follower/__init__.py +0 -1
- rucio/daemons/follower/follower.py +12 -8
- rucio/daemons/hermes/__init__.py +0 -1
- rucio/daemons/hermes/hermes.py +57 -21
- rucio/daemons/judge/__init__.py +0 -1
- rucio/daemons/judge/cleaner.py +27 -17
- rucio/daemons/judge/evaluator.py +31 -18
- rucio/daemons/judge/injector.py +31 -23
- rucio/daemons/judge/repairer.py +28 -18
- rucio/daemons/oauthmanager/__init__.py +0 -1
- rucio/daemons/oauthmanager/oauthmanager.py +7 -8
- rucio/daemons/reaper/__init__.py +0 -1
- rucio/daemons/reaper/dark_reaper.py +15 -9
- rucio/daemons/reaper/reaper.py +109 -67
- rucio/daemons/replicarecoverer/__init__.py +0 -1
- rucio/daemons/replicarecoverer/suspicious_replica_recoverer.py +255 -116
- rucio/{api → daemons/rsedecommissioner}/__init__.py +0 -1
- rucio/daemons/rsedecommissioner/config.py +81 -0
- rucio/daemons/rsedecommissioner/profiles/__init__.py +24 -0
- rucio/daemons/rsedecommissioner/profiles/atlas.py +60 -0
- rucio/daemons/rsedecommissioner/profiles/generic.py +451 -0
- rucio/daemons/rsedecommissioner/profiles/types.py +92 -0
- rucio/daemons/rsedecommissioner/rse_decommissioner.py +280 -0
- rucio/daemons/storage/__init__.py +0 -1
- rucio/daemons/storage/consistency/__init__.py +0 -1
- rucio/daemons/storage/consistency/actions.py +152 -59
- rucio/daemons/tracer/__init__.py +0 -1
- rucio/daemons/tracer/kronos.py +47 -24
- rucio/daemons/transmogrifier/__init__.py +0 -1
- rucio/daemons/transmogrifier/transmogrifier.py +35 -26
- rucio/daemons/undertaker/__init__.py +0 -1
- rucio/daemons/undertaker/undertaker.py +10 -10
- rucio/db/__init__.py +0 -1
- rucio/db/sqla/__init__.py +16 -2
- rucio/db/sqla/constants.py +10 -1
- rucio/db/sqla/migrate_repo/__init__.py +0 -1
- rucio/db/sqla/migrate_repo/env.py +0 -1
- rucio/db/sqla/migrate_repo/versions/01eaf73ab656_add_new_rule_notification_state_progress.py +0 -1
- rucio/db/sqla/migrate_repo/versions/0437a40dbfd1_add_eol_at_in_rules.py +0 -3
- rucio/db/sqla/migrate_repo/versions/0f1adb7a599a_create_transfer_hops_table.py +1 -3
- rucio/db/sqla/migrate_repo/versions/102efcf145f4_added_stuck_at_column_to_rules.py +0 -3
- rucio/db/sqla/migrate_repo/versions/13d4f70c66a9_introduce_transfer_limits.py +1 -3
- rucio/db/sqla/migrate_repo/versions/140fef722e91_cleanup_distances_table.py +1 -3
- rucio/db/sqla/migrate_repo/versions/14ec5aeb64cf_add_request_external_host.py +0 -3
- rucio/db/sqla/migrate_repo/versions/156fb5b5a14_add_request_type_to_requests_idx.py +1 -4
- rucio/db/sqla/migrate_repo/versions/1677d4d803c8_split_rse_availability_into_multiple.py +0 -1
- rucio/db/sqla/migrate_repo/versions/16a0aca82e12_create_index_on_table_replicas_path.py +0 -2
- rucio/db/sqla/migrate_repo/versions/1803333ac20f_adding_provenance_and_phys_group.py +0 -1
- rucio/db/sqla/migrate_repo/versions/1a29d6a9504c_add_didtype_chck_to_requests.py +0 -1
- rucio/db/sqla/migrate_repo/versions/1a80adff031a_create_index_on_rules_hist_recent.py +0 -2
- rucio/db/sqla/migrate_repo/versions/1c45d9730ca6_increase_identity_length.py +0 -1
- rucio/db/sqla/migrate_repo/versions/1d1215494e95_add_quarantined_replicas_table.py +1 -3
- rucio/db/sqla/migrate_repo/versions/1d96f484df21_asynchronous_rules_and_rule_approval.py +0 -1
- rucio/db/sqla/migrate_repo/versions/1f46c5f240ac_add_bytes_column_to_bad_replicas.py +0 -3
- rucio/db/sqla/migrate_repo/versions/1fc15ab60d43_add_message_history_table.py +0 -1
- rucio/db/sqla/migrate_repo/versions/2190e703eb6e_move_rse_settings_to_rse_attributes.py +1 -2
- rucio/db/sqla/migrate_repo/versions/21d6b9dc9961_add_mismatch_scheme_state_to_requests.py +0 -1
- rucio/db/sqla/migrate_repo/versions/22cf51430c78_add_availability_column_to_table_rses.py +0 -3
- rucio/db/sqla/migrate_repo/versions/22d887e4ec0a_create_sources_table.py +1 -3
- rucio/db/sqla/migrate_repo/versions/25821a8a45a3_remove_unique_constraint_on_requests.py +1 -4
- rucio/db/sqla/migrate_repo/versions/25fc855625cf_added_unique_constraint_to_rules.py +0 -2
- rucio/db/sqla/migrate_repo/versions/269fee20dee9_add_repair_cnt_to_locks.py +0 -3
- rucio/db/sqla/migrate_repo/versions/271a46ea6244_add_ignore_availability_column_to_rules.py +0 -3
- rucio/db/sqla/migrate_repo/versions/277b5fbb41d3_switch_heartbeats_executable.py +1 -2
- rucio/db/sqla/migrate_repo/versions/27e3a68927fb_remove_replicas_tombstone_and_replicas_.py +0 -1
- rucio/db/sqla/migrate_repo/versions/2854cd9e168_added_rule_id_column.py +0 -1
- rucio/db/sqla/migrate_repo/versions/295289b5a800_processed_by_and__at_in_requests.py +0 -2
- rucio/db/sqla/migrate_repo/versions/2962ece31cf4_add_nbaccesses_column_in_the_did_table.py +0 -3
- rucio/db/sqla/migrate_repo/versions/2af3291ec4c_added_replicas_history_table.py +1 -3
- rucio/db/sqla/migrate_repo/versions/2b69addda658_add_columns_for_third_party_copy_read_.py +0 -2
- rucio/db/sqla/migrate_repo/versions/2b8e7bcb4783_add_config_table.py +1 -4
- rucio/db/sqla/migrate_repo/versions/2ba5229cb54c_add_submitted_at_to_requests_table.py +0 -3
- rucio/db/sqla/migrate_repo/versions/2cbee484dcf9_added_column_volume_to_rse_transfer_.py +1 -4
- rucio/db/sqla/migrate_repo/versions/2edee4a83846_add_source_to_requests_and_requests_.py +0 -1
- rucio/db/sqla/migrate_repo/versions/2eef46be23d4_change_tokens_pk.py +1 -3
- rucio/db/sqla/migrate_repo/versions/2f648fc909f3_index_in_rule_history_on_scope_name.py +0 -2
- rucio/db/sqla/migrate_repo/versions/3082b8cef557_add_naming_convention_table_and_closed_.py +1 -3
- rucio/db/sqla/migrate_repo/versions/30fa38b6434e_add_index_on_service_column_in_the_message_table.py +1 -3
- rucio/db/sqla/migrate_repo/versions/3152492b110b_added_staging_area_column.py +1 -2
- rucio/db/sqla/migrate_repo/versions/32c7d2783f7e_create_bad_replicas_table.py +1 -3
- rucio/db/sqla/migrate_repo/versions/3345511706b8_replicas_table_pk_definition_is_in_.py +1 -3
- rucio/db/sqla/migrate_repo/versions/35ef10d1e11b_change_index_on_table_requests.py +0 -2
- rucio/db/sqla/migrate_repo/versions/379a19b5332d_create_rse_limits_table.py +1 -3
- rucio/db/sqla/migrate_repo/versions/384b96aa0f60_created_rule_history_tables.py +2 -3
- rucio/db/sqla/migrate_repo/versions/3ac1660a1a72_extend_distance_table.py +0 -3
- rucio/db/sqla/migrate_repo/versions/3ad36e2268b0_create_collection_replicas_updates_table.py +1 -4
- rucio/db/sqla/migrate_repo/versions/3c9df354071b_extend_waiting_request_state.py +0 -1
- rucio/db/sqla/migrate_repo/versions/3d9813fab443_add_a_new_state_lost_in_badfilesstatus.py +0 -1
- rucio/db/sqla/migrate_repo/versions/40ad39ce3160_add_transferred_at_to_requests_table.py +0 -3
- rucio/db/sqla/migrate_repo/versions/4207be2fd914_add_notification_column_to_rules.py +0 -1
- rucio/db/sqla/migrate_repo/versions/42db2617c364_create_index_on_requests_external_id.py +0 -2
- rucio/db/sqla/migrate_repo/versions/436827b13f82_added_column_activity_to_table_requests.py +0 -3
- rucio/db/sqla/migrate_repo/versions/44278720f774_update_requests_typ_sta_upd_idx_index.py +0 -2
- rucio/db/sqla/migrate_repo/versions/45378a1e76a8_create_collection_replica_table.py +2 -4
- rucio/db/sqla/migrate_repo/versions/469d262be19_removing_created_at_index.py +0 -2
- rucio/db/sqla/migrate_repo/versions/4783c1f49cb4_create_distance_table.py +1 -3
- rucio/db/sqla/migrate_repo/versions/49a21b4d4357_create_index_on_table_tokens.py +1 -4
- rucio/db/sqla/migrate_repo/versions/4a2cbedda8b9_add_source_replica_expression_column_to_.py +0 -3
- rucio/db/sqla/migrate_repo/versions/4a7182d9578b_added_bytes_length_accessed_at_columns.py +0 -3
- rucio/db/sqla/migrate_repo/versions/4bab9edd01fc_create_index_on_requests_rule_id.py +0 -2
- rucio/db/sqla/migrate_repo/versions/4c3a4acfe006_new_attr_account_table.py +1 -3
- rucio/db/sqla/migrate_repo/versions/4cf0a2e127d4_adding_transient_metadata.py +0 -3
- rucio/db/sqla/migrate_repo/versions/4df2c5ddabc0_remove_temporary_dids.py +55 -0
- rucio/db/sqla/migrate_repo/versions/50280c53117c_add_qos_class_to_rse.py +0 -2
- rucio/db/sqla/migrate_repo/versions/52153819589c_add_rse_id_to_replicas_table.py +0 -2
- rucio/db/sqla/migrate_repo/versions/52fd9f4916fa_added_activity_to_rules.py +0 -3
- rucio/db/sqla/migrate_repo/versions/53b479c3cb0f_fix_did_meta_table_missing_updated_at_.py +0 -3
- rucio/db/sqla/migrate_repo/versions/5673b4b6e843_add_wfms_metadata_to_rule_tables.py +0 -3
- rucio/db/sqla/migrate_repo/versions/575767d9f89_added_source_history_table.py +1 -2
- rucio/db/sqla/migrate_repo/versions/58bff7008037_add_started_at_to_requests.py +0 -3
- rucio/db/sqla/migrate_repo/versions/58c8b78301ab_rename_callback_to_message.py +1 -3
- rucio/db/sqla/migrate_repo/versions/5f139f77382a_added_child_rule_id_column.py +1 -3
- rucio/db/sqla/migrate_repo/versions/688ef1840840_adding_did_meta_table.py +1 -2
- rucio/db/sqla/migrate_repo/versions/6e572a9bfbf3_add_new_split_container_column_to_rules.py +0 -3
- rucio/db/sqla/migrate_repo/versions/70587619328_add_comment_column_for_subscriptions.py +0 -3
- rucio/db/sqla/migrate_repo/versions/739064d31565_remove_history_table_pks.py +1 -2
- rucio/db/sqla/migrate_repo/versions/7541902bf173_add_didsfollowed_and_followevents_table.py +2 -4
- rucio/db/sqla/migrate_repo/versions/7ec22226cdbf_new_replica_state_for_temporary_.py +0 -1
- rucio/db/sqla/migrate_repo/versions/810a41685bc1_added_columns_rse_transfer_limits.py +1 -4
- rucio/db/sqla/migrate_repo/versions/83f991c63a93_correct_rse_expression_length.py +0 -2
- rucio/db/sqla/migrate_repo/versions/8523998e2e76_increase_size_of_extended_attributes_.py +0 -3
- rucio/db/sqla/migrate_repo/versions/8ea9122275b1_adding_missing_function_based_indices.py +1 -2
- rucio/db/sqla/migrate_repo/versions/90f47792bb76_add_clob_payload_to_messages.py +0 -3
- rucio/db/sqla/migrate_repo/versions/914b8f02df38_new_table_for_lifetime_model_exceptions.py +1 -3
- rucio/db/sqla/migrate_repo/versions/94a5961ddbf2_add_estimator_columns.py +0 -3
- rucio/db/sqla/migrate_repo/versions/9a1b149a2044_add_saml_identity_type.py +0 -1
- rucio/db/sqla/migrate_repo/versions/9a45bc4ea66d_add_vp_table.py +1 -2
- rucio/db/sqla/migrate_repo/versions/9eb936a81eb1_true_is_true.py +0 -2
- rucio/db/sqla/migrate_repo/versions/a08fa8de1545_transfer_stats_table.py +55 -0
- rucio/db/sqla/migrate_repo/versions/a118956323f8_added_vo_table_and_vo_col_to_rse.py +1 -3
- rucio/db/sqla/migrate_repo/versions/a193a275255c_add_status_column_in_messages.py +0 -2
- rucio/db/sqla/migrate_repo/versions/a5f6f6e928a7_1_7_0.py +1 -4
- rucio/db/sqla/migrate_repo/versions/a616581ee47_added_columns_to_table_requests.py +0 -1
- rucio/db/sqla/migrate_repo/versions/a6eb23955c28_state_idx_non_functional.py +0 -1
- rucio/db/sqla/migrate_repo/versions/a74275a1ad30_added_global_quota_table.py +1 -3
- rucio/db/sqla/migrate_repo/versions/a93e4e47bda_heartbeats.py +1 -4
- rucio/db/sqla/migrate_repo/versions/ae2a56fcc89_added_comment_column_to_rules.py +0 -1
- rucio/db/sqla/migrate_repo/versions/b0070f3695c8_add_deletedidmeta_table.py +57 -0
- rucio/db/sqla/migrate_repo/versions/b4293a99f344_added_column_identity_to_table_tokens.py +0 -3
- rucio/db/sqla/migrate_repo/versions/b5493606bbf5_fix_primary_key_for_subscription_history.py +41 -0
- rucio/db/sqla/migrate_repo/versions/b7d287de34fd_removal_of_replicastate_source.py +1 -2
- rucio/db/sqla/migrate_repo/versions/b818052fa670_add_index_to_quarantined_replicas.py +1 -3
- rucio/db/sqla/migrate_repo/versions/b8caac94d7f0_add_comments_column_for_subscriptions_.py +0 -3
- rucio/db/sqla/migrate_repo/versions/b96a1c7e1cc4_new_bad_pfns_table_and_bad_replicas_.py +1 -5
- rucio/db/sqla/migrate_repo/versions/bb695f45c04_extend_request_state.py +1 -3
- rucio/db/sqla/migrate_repo/versions/bc68e9946deb_add_staging_timestamps_to_request.py +0 -3
- rucio/db/sqla/migrate_repo/versions/bf3baa1c1474_correct_pk_and_idx_for_history_tables.py +1 -3
- rucio/db/sqla/migrate_repo/versions/c0937668555f_add_qos_policy_map_table.py +1 -2
- rucio/db/sqla/migrate_repo/versions/c129ccdb2d5_add_lumiblocknr_to_dids.py +0 -3
- rucio/db/sqla/migrate_repo/versions/ccdbcd48206e_add_did_type_column_index_on_did_meta_.py +1 -4
- rucio/db/sqla/migrate_repo/versions/cebad904c4dd_new_payload_column_for_heartbeats.py +1 -2
- rucio/db/sqla/migrate_repo/versions/d1189a09c6e0_oauth2_0_and_jwt_feature_support_adding_.py +1 -4
- rucio/db/sqla/migrate_repo/versions/d23453595260_extend_request_state_for_preparer.py +1 -3
- rucio/db/sqla/migrate_repo/versions/d6dceb1de2d_added_purge_column_to_rules.py +1 -4
- rucio/db/sqla/migrate_repo/versions/d6e2c3b2cf26_remove_third_party_copy_column_from_rse.py +0 -2
- rucio/db/sqla/migrate_repo/versions/d91002c5841_new_account_limits_table.py +1 -3
- rucio/db/sqla/migrate_repo/versions/e138c364ebd0_extending_columns_for_filter_and_.py +0 -3
- rucio/db/sqla/migrate_repo/versions/e59300c8b179_support_for_archive.py +1 -3
- rucio/db/sqla/migrate_repo/versions/f1b14a8c2ac1_postgres_use_check_constraints.py +0 -1
- rucio/db/sqla/migrate_repo/versions/f41ffe206f37_oracle_global_temporary_tables.py +1 -2
- rucio/db/sqla/migrate_repo/versions/f85a2962b021_adding_transfertool_column_to_requests_.py +1 -3
- rucio/db/sqla/migrate_repo/versions/fa7a7d78b602_increase_refresh_token_size.py +0 -2
- rucio/db/sqla/migrate_repo/versions/fb28a95fe288_add_replicas_rse_id_tombstone_idx.py +0 -1
- rucio/db/sqla/migrate_repo/versions/fe1a65b176c9_set_third_party_copy_read_and_write_.py +1 -2
- rucio/db/sqla/migrate_repo/versions/fe8ea2fa9788_added_third_party_copy_column_to_rse_.py +0 -3
- rucio/db/sqla/models.py +122 -216
- rucio/db/sqla/sautils.py +12 -5
- rucio/db/sqla/session.py +71 -43
- rucio/db/sqla/types.py +3 -4
- rucio/db/sqla/util.py +91 -69
- rucio/gateway/__init__.py +13 -0
- rucio/{api → gateway}/account.py +119 -46
- rucio/{api → gateway}/account_limit.py +12 -13
- rucio/{api → gateway}/authentication.py +106 -33
- rucio/{api → gateway}/config.py +12 -13
- rucio/{api → gateway}/credential.py +15 -4
- rucio/{api → gateway}/did.py +384 -140
- rucio/{api → gateway}/dirac.py +16 -6
- rucio/{api → gateway}/exporter.py +3 -4
- rucio/{api → gateway}/heartbeat.py +17 -5
- rucio/{api → gateway}/identity.py +63 -19
- rucio/{api → gateway}/importer.py +3 -4
- rucio/{api → gateway}/lifetime_exception.py +35 -10
- rucio/{api → gateway}/lock.py +34 -12
- rucio/{api/meta.py → gateway/meta_conventions.py} +18 -16
- rucio/{api → gateway}/permission.py +4 -5
- rucio/{api → gateway}/quarantined_replica.py +13 -4
- rucio/{api → gateway}/replica.py +12 -11
- rucio/{api → gateway}/request.py +129 -28
- rucio/{api → gateway}/rse.py +11 -12
- rucio/{api → gateway}/rule.py +117 -35
- rucio/{api → gateway}/scope.py +24 -14
- rucio/{api → gateway}/subscription.py +65 -43
- rucio/{api → gateway}/vo.py +17 -7
- rucio/rse/__init__.py +3 -4
- rucio/rse/protocols/__init__.py +0 -1
- rucio/rse/protocols/bittorrent.py +184 -0
- rucio/rse/protocols/cache.py +1 -2
- rucio/rse/protocols/dummy.py +1 -2
- rucio/rse/protocols/gfal.py +12 -10
- rucio/rse/protocols/globus.py +7 -7
- rucio/rse/protocols/gsiftp.py +2 -3
- rucio/rse/protocols/http_cache.py +1 -2
- rucio/rse/protocols/mock.py +1 -2
- rucio/rse/protocols/ngarc.py +1 -2
- rucio/rse/protocols/posix.py +12 -13
- rucio/rse/protocols/protocol.py +116 -52
- rucio/rse/protocols/rclone.py +6 -7
- rucio/rse/protocols/rfio.py +4 -5
- rucio/rse/protocols/srm.py +9 -10
- rucio/rse/protocols/ssh.py +8 -9
- rucio/rse/protocols/storm.py +2 -3
- rucio/rse/protocols/webdav.py +17 -14
- rucio/rse/protocols/xrootd.py +23 -17
- rucio/rse/rsemanager.py +19 -7
- rucio/tests/__init__.py +0 -1
- rucio/tests/common.py +43 -17
- rucio/tests/common_server.py +3 -3
- rucio/transfertool/__init__.py +0 -1
- rucio/transfertool/bittorrent.py +199 -0
- rucio/transfertool/bittorrent_driver.py +52 -0
- rucio/transfertool/bittorrent_driver_qbittorrent.py +133 -0
- rucio/transfertool/fts3.py +250 -138
- rucio/transfertool/fts3_plugins.py +152 -0
- rucio/transfertool/globus.py +9 -8
- rucio/transfertool/globus_library.py +1 -2
- rucio/transfertool/mock.py +21 -12
- rucio/transfertool/transfertool.py +33 -24
- rucio/vcsversion.py +4 -4
- rucio/version.py +5 -13
- rucio/web/__init__.py +0 -1
- rucio/web/rest/__init__.py +0 -1
- rucio/web/rest/flaskapi/__init__.py +0 -1
- rucio/web/rest/flaskapi/authenticated_bp.py +0 -1
- rucio/web/rest/flaskapi/v1/__init__.py +0 -1
- rucio/web/rest/flaskapi/v1/accountlimits.py +15 -13
- rucio/web/rest/flaskapi/v1/accounts.py +49 -48
- rucio/web/rest/flaskapi/v1/archives.py +12 -10
- rucio/web/rest/flaskapi/v1/auth.py +146 -144
- rucio/web/rest/flaskapi/v1/common.py +82 -41
- rucio/web/rest/flaskapi/v1/config.py +5 -6
- rucio/web/rest/flaskapi/v1/credentials.py +7 -8
- rucio/web/rest/flaskapi/v1/dids.py +158 -28
- rucio/web/rest/flaskapi/v1/dirac.py +8 -8
- rucio/web/rest/flaskapi/v1/export.py +3 -5
- rucio/web/rest/flaskapi/v1/heartbeats.py +3 -5
- rucio/web/rest/flaskapi/v1/identities.py +3 -5
- rucio/web/rest/flaskapi/v1/import.py +3 -4
- rucio/web/rest/flaskapi/v1/lifetime_exceptions.py +6 -9
- rucio/web/rest/flaskapi/v1/locks.py +2 -4
- rucio/web/rest/flaskapi/v1/main.py +10 -2
- rucio/web/rest/flaskapi/v1/{meta.py → meta_conventions.py} +26 -11
- rucio/web/rest/flaskapi/v1/metrics.py +1 -2
- rucio/web/rest/flaskapi/v1/nongrid_traces.py +4 -4
- rucio/web/rest/flaskapi/v1/ping.py +6 -7
- rucio/web/rest/flaskapi/v1/redirect.py +8 -9
- rucio/web/rest/flaskapi/v1/replicas.py +43 -19
- rucio/web/rest/flaskapi/v1/requests.py +178 -21
- rucio/web/rest/flaskapi/v1/rses.py +61 -26
- rucio/web/rest/flaskapi/v1/rules.py +48 -18
- rucio/web/rest/flaskapi/v1/scopes.py +3 -5
- rucio/web/rest/flaskapi/v1/subscriptions.py +22 -18
- rucio/web/rest/flaskapi/v1/traces.py +4 -4
- rucio/web/rest/flaskapi/v1/types.py +20 -0
- rucio/web/rest/flaskapi/v1/vos.py +3 -5
- rucio/web/rest/main.py +0 -1
- rucio/web/rest/metrics.py +0 -1
- rucio/web/rest/ping.py +27 -0
- {rucio-32.8.6.data → rucio-35.8.0.data}/data/rucio/etc/ldap.cfg.template +1 -1
- rucio-35.8.0.data/data/rucio/requirements.server.txt +268 -0
- {rucio-32.8.6.data → rucio-35.8.0.data}/data/rucio/tools/bootstrap.py +3 -3
- {rucio-32.8.6.data → rucio-35.8.0.data}/data/rucio/tools/merge_rucio_configs.py +2 -5
- {rucio-32.8.6.data → rucio-35.8.0.data}/data/rucio/tools/reset_database.py +3 -3
- {rucio-32.8.6.data → rucio-35.8.0.data}/scripts/rucio +87 -85
- {rucio-32.8.6.data → rucio-35.8.0.data}/scripts/rucio-abacus-account +0 -1
- {rucio-32.8.6.data → rucio-35.8.0.data}/scripts/rucio-abacus-collection-replica +0 -1
- {rucio-32.8.6.data → rucio-35.8.0.data}/scripts/rucio-abacus-rse +0 -1
- {rucio-32.8.6.data → rucio-35.8.0.data}/scripts/rucio-admin +45 -32
- {rucio-32.8.6.data → rucio-35.8.0.data}/scripts/rucio-atropos +0 -1
- {rucio-32.8.6.data → rucio-35.8.0.data}/scripts/rucio-auditor +13 -7
- {rucio-32.8.6.data → rucio-35.8.0.data}/scripts/rucio-automatix +1 -2
- {rucio-32.8.6.data → rucio-35.8.0.data}/scripts/rucio-bb8 +0 -1
- {rucio-32.8.6.data → rucio-35.8.0.data}/scripts/rucio-c3po +0 -1
- {rucio-32.8.6.data → rucio-35.8.0.data}/scripts/rucio-cache-client +2 -3
- {rucio-32.8.6.data → rucio-35.8.0.data}/scripts/rucio-cache-consumer +0 -1
- {rucio-32.8.6.data → rucio-35.8.0.data}/scripts/rucio-conveyor-finisher +1 -2
- {rucio-32.8.6.data → rucio-35.8.0.data}/scripts/rucio-conveyor-poller +0 -1
- {rucio-32.8.6.data → rucio-35.8.0.data}/scripts/rucio-conveyor-preparer +0 -1
- {rucio-32.8.6.data → rucio-35.8.0.data}/scripts/rucio-conveyor-receiver +0 -1
- {rucio-32.8.6.data → rucio-35.8.0.data}/scripts/rucio-conveyor-stager +0 -1
- {rucio-32.8.6.data → rucio-35.8.0.data}/scripts/rucio-conveyor-submitter +2 -3
- {rucio-32.8.6.data → rucio-35.8.0.data}/scripts/rucio-conveyor-throttler +0 -1
- {rucio-32.8.6.data → rucio-35.8.0.data}/scripts/rucio-dark-reaper +0 -1
- {rucio-32.8.6.data → rucio-35.8.0.data}/scripts/rucio-dumper +11 -10
- {rucio-32.8.6.data → rucio-35.8.0.data}/scripts/rucio-follower +0 -1
- {rucio-32.8.6.data → rucio-35.8.0.data}/scripts/rucio-hermes +0 -1
- {rucio-32.8.6.data → rucio-35.8.0.data}/scripts/rucio-judge-cleaner +0 -1
- {rucio-32.8.6.data → rucio-35.8.0.data}/scripts/rucio-judge-evaluator +2 -3
- {rucio-32.8.6.data → rucio-35.8.0.data}/scripts/rucio-judge-injector +0 -1
- {rucio-32.8.6.data → rucio-35.8.0.data}/scripts/rucio-judge-repairer +0 -1
- {rucio-32.8.6.data → rucio-35.8.0.data}/scripts/rucio-kronos +1 -3
- {rucio-32.8.6.data → rucio-35.8.0.data}/scripts/rucio-minos +0 -1
- {rucio-32.8.6.data → rucio-35.8.0.data}/scripts/rucio-minos-temporary-expiration +0 -1
- {rucio-32.8.6.data → rucio-35.8.0.data}/scripts/rucio-necromancer +1 -2
- {rucio-32.8.6.data → rucio-35.8.0.data}/scripts/rucio-oauth-manager +2 -3
- {rucio-32.8.6.data → rucio-35.8.0.data}/scripts/rucio-reaper +0 -1
- {rucio-32.8.6.data → rucio-35.8.0.data}/scripts/rucio-replica-recoverer +6 -7
- rucio-35.8.0.data/scripts/rucio-rse-decommissioner +66 -0
- {rucio-32.8.6.data → rucio-35.8.0.data}/scripts/rucio-storage-consistency-actions +0 -1
- {rucio-32.8.6.data → rucio-35.8.0.data}/scripts/rucio-transmogrifier +0 -1
- {rucio-32.8.6.data → rucio-35.8.0.data}/scripts/rucio-undertaker +1 -2
- rucio-35.8.0.dist-info/METADATA +72 -0
- rucio-35.8.0.dist-info/RECORD +493 -0
- {rucio-32.8.6.dist-info → rucio-35.8.0.dist-info}/WHEEL +1 -1
- {rucio-32.8.6.dist-info → rucio-35.8.0.dist-info}/licenses/AUTHORS.rst +3 -0
- rucio/api/temporary_did.py +0 -49
- rucio/common/schema/cms.py +0 -478
- rucio/common/schema/lsst.py +0 -423
- rucio/core/permission/cms.py +0 -1166
- rucio/core/temporary_did.py +0 -188
- rucio/daemons/reaper/light_reaper.py +0 -255
- rucio/web/rest/flaskapi/v1/tmp_dids.py +0 -115
- rucio-32.8.6.data/data/rucio/requirements.txt +0 -55
- rucio-32.8.6.data/scripts/rucio-light-reaper +0 -53
- rucio-32.8.6.dist-info/METADATA +0 -83
- rucio-32.8.6.dist-info/RECORD +0 -481
- {rucio-32.8.6.data → rucio-35.8.0.data}/data/rucio/etc/alembic.ini.template +0 -0
- {rucio-32.8.6.data → rucio-35.8.0.data}/data/rucio/etc/alembic_offline.ini.template +0 -0
- {rucio-32.8.6.data → rucio-35.8.0.data}/data/rucio/etc/globus-config.yml.template +0 -0
- {rucio-32.8.6.data → rucio-35.8.0.data}/data/rucio/etc/mail_templates/rule_approval_request.tmpl +0 -0
- {rucio-32.8.6.data → rucio-35.8.0.data}/data/rucio/etc/mail_templates/rule_approved_admin.tmpl +0 -0
- {rucio-32.8.6.data → rucio-35.8.0.data}/data/rucio/etc/mail_templates/rule_approved_user.tmpl +0 -0
- {rucio-32.8.6.data → rucio-35.8.0.data}/data/rucio/etc/mail_templates/rule_denied_admin.tmpl +0 -0
- {rucio-32.8.6.data → rucio-35.8.0.data}/data/rucio/etc/mail_templates/rule_denied_user.tmpl +0 -0
- {rucio-32.8.6.data → rucio-35.8.0.data}/data/rucio/etc/mail_templates/rule_ok_notification.tmpl +0 -0
- {rucio-32.8.6.data → rucio-35.8.0.data}/data/rucio/etc/rse-accounts.cfg.template +0 -0
- {rucio-32.8.6.data → rucio-35.8.0.data}/data/rucio/etc/rucio.cfg.atlas.client.template +0 -0
- {rucio-32.8.6.data → rucio-35.8.0.data}/data/rucio/etc/rucio.cfg.template +0 -0
- {rucio-32.8.6.data → rucio-35.8.0.data}/data/rucio/etc/rucio_multi_vo.cfg.template +0 -0
- {rucio-32.8.6.dist-info → rucio-35.8.0.dist-info}/licenses/LICENSE +0 -0
- {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.
|
|
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
|
-
:
|
|
87
|
-
:
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
235
|
+
stmt = stmt.with_hint(
|
|
236
|
+
models.DataIdentifier,
|
|
237
|
+
'NO_EXPAND',
|
|
238
|
+
'oracle'
|
|
239
|
+
)
|
|
237
240
|
|
|
238
241
|
if limit:
|
|
239
|
-
|
|
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
|
|
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
|
|
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':
|
|
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
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
92
|
-
|
|
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(
|
|
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
|
|
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_,
|
|
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__(
|
|
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
|
-
|
|
93
|
+
filters, _ = parse_did_filter_from_string_fe(filters, omit_name=True)
|
|
83
94
|
elif isinstance(filters, dict):
|
|
84
|
-
|
|
95
|
+
filters = [filters]
|
|
85
96
|
elif isinstance(filters, list):
|
|
86
|
-
|
|
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
|
|
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
|
|
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(
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
279
|
+
typecasted_value = datetime.strptime(value, format)
|
|
263
280
|
except ValueError:
|
|
264
281
|
continue
|
|
265
282
|
else:
|
|
266
|
-
return
|
|
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(
|
|
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(
|
|
331
|
-
|
|
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
|
|
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(
|
|
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
|
|
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,
|
|
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
|
|
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
|
-
|
|
494
|
-
|
|
495
|
-
|
|
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,
|
|
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,
|
|
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 '
|