acceldata-sdk-python 26.7.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.
Files changed (303) hide show
  1. acceldata/__init__.py +7 -0
  2. acceldata/client/__init__.py +0 -0
  3. acceldata/client/adoc_client.py +666 -0
  4. acceldata/client/http_client.py +346 -0
  5. acceldata/client/transient_retry.py +142 -0
  6. acceldata/constants/__init__.py +1 -0
  7. acceldata/constants/constants.py +13 -0
  8. acceldata/exceptions/__init__.py +52 -0
  9. acceldata/exceptions/api_errors.py +85 -0
  10. acceldata/exceptions/exceptions.py +174 -0
  11. acceldata/exceptions/sdk_exceptions.py +98 -0
  12. acceldata/mappers/__init__.py +21 -0
  13. acceldata/mappers/catalog_executions.py +107 -0
  14. acceldata/models/__init__.py +0 -0
  15. acceldata/models/api/catalog/above_configs.py +99 -0
  16. acceldata/models/api/catalog/above_configs_success.py +138 -0
  17. acceldata/models/api/catalog/absolute_configs.py +197 -0
  18. acceldata/models/api/catalog/absolute_configs_fallback.py +101 -0
  19. acceldata/models/api/catalog/absolute_threshold_config.py +105 -0
  20. acceldata/models/api/catalog/analysis_job_context.py +102 -0
  21. acceldata/models/api/catalog/analytics_pipeline.py +385 -0
  22. acceldata/models/api/catalog/analytics_pipeline_endpoint.py +136 -0
  23. acceldata/models/api/catalog/anomaly_config.py +95 -0
  24. acceldata/models/api/catalog/anomaly_details.py +119 -0
  25. acceldata/models/api/catalog/anomaly_threshold_config.py +105 -0
  26. acceldata/models/api/catalog/artifact.py +92 -0
  27. acceldata/models/api/catalog/assembly.py +171 -0
  28. acceldata/models/api/catalog/asset.py +162 -0
  29. acceldata/models/api/catalog/asset_catalog_listing.py +159 -0
  30. acceldata/models/api/catalog/asset_catalog_listing_response.py +102 -0
  31. acceldata/models/api/catalog/asset_label_request.py +96 -0
  32. acceldata/models/api/catalog/asset_progress.py +96 -0
  33. acceldata/models/api/catalog/asset_progress_details.py +117 -0
  34. acceldata/models/api/catalog/asset_tag.py +124 -0
  35. acceldata/models/api/catalog/asset_tag_info.py +140 -0
  36. acceldata/models/api/catalog/asset_tag_request.py +95 -0
  37. acceldata/models/api/catalog/asset_tag_response.py +96 -0
  38. acceldata/models/api/catalog/asset_tags_response.py +102 -0
  39. acceldata/models/api/catalog/asset_type.py +96 -0
  40. acceldata/models/api/catalog/auto_anomaly_feature_analysis.py +160 -0
  41. acceldata/models/api/catalog/auto_anomaly_item_execution.py +133 -0
  42. acceldata/models/api/catalog/auto_anomaly_meta_data.py +162 -0
  43. acceldata/models/api/catalog/auto_anomaly_rule_execution.py +102 -0
  44. acceldata/models/api/catalog/auto_anomaly_summary.py +124 -0
  45. acceldata/models/api/catalog/backing_asset.py +126 -0
  46. acceldata/models/api/catalog/below_configs.py +99 -0
  47. acceldata/models/api/catalog/big_decimal.py +100 -0
  48. acceldata/models/api/catalog/big_integer.py +98 -0
  49. acceldata/models/api/catalog/bounds_date_time_marker_config.py +110 -0
  50. acceldata/models/api/catalog/bounds_file_event_marker_config.py +108 -0
  51. acceldata/models/api/catalog/bounds_id_marker_config.py +96 -0
  52. acceldata/models/api/catalog/catalog_asset_meta_data.py +128 -0
  53. acceldata/models/api/catalog/changes_by_config.py +105 -0
  54. acceldata/models/api/catalog/column_mapping.py +139 -0
  55. acceldata/models/api/catalog/column_metadata.py +90 -0
  56. acceldata/models/api/catalog/column_metric_with_anomaly_details.py +119 -0
  57. acceldata/models/api/catalog/column_variable.py +111 -0
  58. acceldata/models/api/catalog/composite_policy_execution.py +102 -0
  59. acceldata/models/api/catalog/composite_policy_item_execution.py +104 -0
  60. acceldata/models/api/catalog/connection.py +118 -0
  61. acceldata/models/api/catalog/connection_test_result.py +106 -0
  62. acceldata/models/api/catalog/connection_type.py +90 -0
  63. acceldata/models/api/catalog/connection_types_response.py +96 -0
  64. acceldata/models/api/catalog/crawler.py +88 -0
  65. acceldata/models/api/catalog/crawler_action_response.py +90 -0
  66. acceldata/models/api/catalog/crawler_execution.py +147 -0
  67. acceldata/models/api/catalog/crawler_execution_response.py +102 -0
  68. acceldata/models/api/catalog/crawler_status_response.py +90 -0
  69. acceldata/models/api/catalog/create_profile.py +194 -0
  70. acceldata/models/api/catalog/custom_sql_config.py +121 -0
  71. acceldata/models/api/catalog/data_bricks_spark_resource_config.py +104 -0
  72. acceldata/models/api/catalog/data_cadence_rule.py +236 -0
  73. acceldata/models/api/catalog/data_cadence_rule_details.py +125 -0
  74. acceldata/models/api/catalog/data_cadence_rule_execution.py +102 -0
  75. acceldata/models/api/catalog/data_cadence_rule_item.py +104 -0
  76. acceldata/models/api/catalog/data_cadence_rule_item_execution.py +158 -0
  77. acceldata/models/api/catalog/data_cadence_rule_response.py +98 -0
  78. acceldata/models/api/catalog/data_drift_execution.py +102 -0
  79. acceldata/models/api/catalog/data_drift_item_execution.py +121 -0
  80. acceldata/models/api/catalog/data_quality_engine.py +90 -0
  81. acceldata/models/api/catalog/data_quality_execution.py +106 -0
  82. acceldata/models/api/catalog/data_quality_rule.py +323 -0
  83. acceldata/models/api/catalog/data_quality_rule_details.py +186 -0
  84. acceldata/models/api/catalog/data_quality_rule_response.py +120 -0
  85. acceldata/models/api/catalog/data_quality_rules_response.py +102 -0
  86. acceldata/models/api/catalog/databricks_compute_config.py +113 -0
  87. acceldata/models/api/catalog/dataplane_engine.py +105 -0
  88. acceldata/models/api/catalog/dataplane_health_metrics.py +101 -0
  89. acceldata/models/api/catalog/dataplane_job.py +216 -0
  90. acceldata/models/api/catalog/dataplane_job_status.py +113 -0
  91. acceldata/models/api/catalog/dataplane_request.py +96 -0
  92. acceldata/models/api/catalog/dataproc_compute_config.py +106 -0
  93. acceldata/models/api/catalog/dataproc_spark_resource_config.py +104 -0
  94. acceldata/models/api/catalog/date_based_partition_marker_config.py +116 -0
  95. acceldata/models/api/catalog/date_partitioning_marker_config.py +113 -0
  96. acceldata/models/api/catalog/date_time_marker_config.py +109 -0
  97. acceldata/models/api/catalog/day_month_year_based_partition_marker_config.py +124 -0
  98. acceldata/models/api/catalog/decreased_by_config.py +105 -0
  99. acceldata/models/api/catalog/delete_artifact_response.py +88 -0
  100. acceldata/models/api/catalog/dq_rule_execution.py +248 -0
  101. acceldata/models/api/catalog/drift.py +121 -0
  102. acceldata/models/api/catalog/enable_rule_request.py +88 -0
  103. acceldata/models/api/catalog/engine.py +90 -0
  104. acceldata/models/api/catalog/execution_cancellation_response.py +92 -0
  105. acceldata/models/api/catalog/execution_response.py +144 -0
  106. acceldata/models/api/catalog/execution_result.py +126 -0
  107. acceldata/models/api/catalog/executions_response.py +102 -0
  108. acceldata/models/api/catalog/failed_asset_detail.py +90 -0
  109. acceldata/models/api/catalog/failed_summary.py +98 -0
  110. acceldata/models/api/catalog/file.py +94 -0
  111. acceldata/models/api/catalog/file_marker_config.py +99 -0
  112. acceldata/models/api/catalog/generic_config_fallback.py +101 -0
  113. acceldata/models/api/catalog/generic_execution.py +221 -0
  114. acceldata/models/api/catalog/generic_rule_execution.py +137 -0
  115. acceldata/models/api/catalog/global_storage_config_dto.py +172 -0
  116. acceldata/models/api/catalog/hosted_dp_deployment_response.py +98 -0
  117. acceldata/models/api/catalog/id_marker_config.py +94 -0
  118. acceldata/models/api/catalog/increased_by_config.py +105 -0
  119. acceldata/models/api/catalog/item.py +160 -0
  120. acceldata/models/api/catalog/item_execution.py +192 -0
  121. acceldata/models/api/catalog/item_segment.py +131 -0
  122. acceldata/models/api/catalog/job_schedule.py +118 -0
  123. acceldata/models/api/catalog/job_spec.py +96 -0
  124. acceldata/models/api/catalog/kubernetes_metrics.py +91 -0
  125. acceldata/models/api/catalog/label.py +97 -0
  126. acceldata/models/api/catalog/livy_compute_config.py +103 -0
  127. acceldata/models/api/catalog/livy_spark_resource_config.py +106 -0
  128. acceldata/models/api/catalog/look_back_config.py +90 -0
  129. acceldata/models/api/catalog/manual_tag_request.py +92 -0
  130. acceldata/models/api/catalog/mapping.py +97 -0
  131. acceldata/models/api/catalog/marker.py +88 -0
  132. acceldata/models/api/catalog/marker_config.py +349 -0
  133. acceldata/models/api/catalog/marker_config_fallback.py +101 -0
  134. acceldata/models/api/catalog/meta.py +92 -0
  135. acceldata/models/api/catalog/meta_data.py +92 -0
  136. acceldata/models/api/catalog/meta_data_item.py +94 -0
  137. acceldata/models/api/catalog/mini_profile_request.py +112 -0
  138. acceldata/models/api/catalog/notification_payload.py +114 -0
  139. acceldata/models/api/catalog/offset_based_marker_config.py +97 -0
  140. acceldata/models/api/catalog/operational_config.py +92 -0
  141. acceldata/models/api/catalog/pattern_configuration.py +90 -0
  142. acceldata/models/api/catalog/pipe_line_request.py +92 -0
  143. acceldata/models/api/catalog/pipeline_compute_config.py +110 -0
  144. acceldata/models/api/catalog/policy_execution_marker_config.py +94 -0
  145. acceldata/models/api/catalog/policy_execution_request.py +229 -0
  146. acceldata/models/api/catalog/policy_group.py +114 -0
  147. acceldata/models/api/catalog/policy_transform_udf.py +113 -0
  148. acceldata/models/api/catalog/process_metrics.py +91 -0
  149. acceldata/models/api/catalog/profile_anomaly_details_response.py +109 -0
  150. acceldata/models/api/catalog/profile_anomaly_item_execution.py +127 -0
  151. acceldata/models/api/catalog/profile_anomaly_rule_execution.py +102 -0
  152. acceldata/models/api/catalog/profile_anomaly_rule_item.py +109 -0
  153. acceldata/models/api/catalog/profile_cancellation_response.py +92 -0
  154. acceldata/models/api/catalog/profile_request.py +211 -0
  155. acceldata/models/api/catalog/profile_request_response.py +92 -0
  156. acceldata/models/api/catalog/property_template.py +178 -0
  157. acceldata/models/api/catalog/property_templates.py +123 -0
  158. acceldata/models/api/catalog/pub_sub_lookback_marker_config.py +96 -0
  159. acceldata/models/api/catalog/pub_sub_timestamp_marker_config.py +108 -0
  160. acceldata/models/api/catalog/quality_rule.py +381 -0
  161. acceldata/models/api/catalog/quality_rule_execution_metrics.py +114 -0
  162. acceldata/models/api/catalog/quality_rule_with_latest_execution.py +115 -0
  163. acceldata/models/api/catalog/range_configs.py +109 -0
  164. acceldata/models/api/catalog/reconciliation_item.py +102 -0
  165. acceldata/models/api/catalog/reconciliation_item_execution.py +157 -0
  166. acceldata/models/api/catalog/reconciliation_rule.py +339 -0
  167. acceldata/models/api/catalog/reconciliation_rule_details.py +225 -0
  168. acceldata/models/api/catalog/reconciliation_rule_execution.py +102 -0
  169. acceldata/models/api/catalog/reconciliation_rule_response.py +98 -0
  170. acceldata/models/api/catalog/reconciliation_rules_response.py +102 -0
  171. acceldata/models/api/catalog/relative_config.py +197 -0
  172. acceldata/models/api/catalog/relative_config_fallback.py +101 -0
  173. acceldata/models/api/catalog/relative_threshold_config.py +111 -0
  174. acceldata/models/api/catalog/root_cause_analysis.py +108 -0
  175. acceldata/models/api/catalog/rule_execution.py +327 -0
  176. acceldata/models/api/catalog/rule_execution_result.py +90 -0
  177. acceldata/models/api/catalog/rule_item_result.py +125 -0
  178. acceldata/models/api/catalog/rule_meta_data.py +94 -0
  179. acceldata/models/api/catalog/rule_spark_sql_dynamic_filter_variable_mapping.py +100 -0
  180. acceldata/models/api/catalog/rule_tag.py +101 -0
  181. acceldata/models/api/catalog/rule_threshold_configuration.py +236 -0
  182. acceldata/models/api/catalog/rule_threshold_configuration_fallback.py +101 -0
  183. acceldata/models/api/catalog/rules_with_latest_execution_response.py +102 -0
  184. acceldata/models/api/catalog/sample_data_api_response.py +122 -0
  185. acceldata/models/api/catalog/schema_drift_item_execution.py +131 -0
  186. acceldata/models/api/catalog/schema_drift_rule_execution.py +102 -0
  187. acceldata/models/api/catalog/secret_manager_configuration.py +90 -0
  188. acceldata/models/api/catalog/secret_manager_configuration_with_option.py +98 -0
  189. acceldata/models/api/catalog/security_config.py +90 -0
  190. acceldata/models/api/catalog/segment_metric_json.py +142 -0
  191. acceldata/models/api/catalog/segments_analysis.py +145 -0
  192. acceldata/models/api/catalog/short_segment.py +97 -0
  193. acceldata/models/api/catalog/simple_quality_rule_response.py +92 -0
  194. acceldata/models/api/catalog/snapshot_data.py +117 -0
  195. acceldata/models/api/catalog/source_model.py +90 -0
  196. acceldata/models/api/catalog/source_type.py +100 -0
  197. acceldata/models/api/catalog/source_types_response.py +102 -0
  198. acceldata/models/api/catalog/spark_job_status.py +113 -0
  199. acceldata/models/api/catalog/spark_resource_config.py +114 -0
  200. acceldata/models/api/catalog/standard_response_assembly.py +92 -0
  201. acceldata/models/api/catalog/standard_response_crawler_action_response.py +92 -0
  202. acceldata/models/api/catalog/standard_response_crawler_status_response.py +92 -0
  203. acceldata/models/api/catalog/standard_response_delete_artifact_response.py +92 -0
  204. acceldata/models/api/catalog/standard_response_list.py +96 -0
  205. acceldata/models/api/catalog/standard_response_map.py +88 -0
  206. acceldata/models/api/catalog/standard_response_meta_data.py +92 -0
  207. acceldata/models/api/catalog/standard_response_mini_profile_request.py +92 -0
  208. acceldata/models/api/catalog/standard_response_profile_request.py +92 -0
  209. acceldata/models/api/catalog/start_profiling_request.py +92 -0
  210. acceldata/models/api/catalog/tag_domain.py +116 -0
  211. acceldata/models/api/catalog/threshold_breach_details.py +101 -0
  212. acceldata/models/api/catalog/time_based_config.py +92 -0
  213. acceldata/models/api/catalog/time_based_threshold_config.py +105 -0
  214. acceldata/models/api/catalog/timestamp_based_marker_config.py +115 -0
  215. acceldata/models/api/catalog/udf_variable.py +97 -0
  216. acceldata/models/api/catalog/yunikorn_compute_config.py +133 -0
  217. acceldata/models/api/catalog/yunikorn_spark_resource_config.py +154 -0
  218. acceldata/models/api/pipeline/big_decimal.py +100 -0
  219. acceldata/models/api/pipeline/big_integer.py +98 -0
  220. acceldata/models/api/pipeline/child_span_response.py +96 -0
  221. acceldata/models/api/pipeline/create_span_event.py +109 -0
  222. acceldata/models/api/pipeline/edge.py +108 -0
  223. acceldata/models/api/pipeline/event_alert_object.py +95 -0
  224. acceldata/models/api/pipeline/generic_config_fallback.py +101 -0
  225. acceldata/models/api/pipeline/identifier.py +146 -0
  226. acceldata/models/api/pipeline/job_request.py +130 -0
  227. acceldata/models/api/pipeline/meta.py +107 -0
  228. acceldata/models/api/pipeline/meta_data.py +92 -0
  229. acceldata/models/api/pipeline/metric.py +103 -0
  230. acceldata/models/api/pipeline/node.py +201 -0
  231. acceldata/models/api/pipeline/node_response.py +92 -0
  232. acceldata/models/api/pipeline/notification_payload.py +114 -0
  233. acceldata/models/api/pipeline/pipeline.py +152 -0
  234. acceldata/models/api/pipeline/pipeline_baseline_metric.py +92 -0
  235. acceldata/models/api/pipeline/pipeline_details.py +118 -0
  236. acceldata/models/api/pipeline/pipeline_details_response.py +102 -0
  237. acceldata/models/api/pipeline/pipeline_input_request.py +92 -0
  238. acceldata/models/api/pipeline/pipeline_listing_info.py +118 -0
  239. acceldata/models/api/pipeline/pipeline_response.py +92 -0
  240. acceldata/models/api/pipeline/pipeline_run.py +136 -0
  241. acceldata/models/api/pipeline/pipeline_run_request.py +92 -0
  242. acceldata/models/api/pipeline/pipeline_runs_response.py +102 -0
  243. acceldata/models/api/pipeline/pipeline_summary.py +98 -0
  244. acceldata/models/api/pipeline/pipelines_listing_response.py +102 -0
  245. acceldata/models/api/pipeline/policy_summary.py +102 -0
  246. acceldata/models/api/pipeline/span.py +115 -0
  247. acceldata/models/api/pipeline/span_event.py +114 -0
  248. acceldata/models/api/pipeline/span_event_request.py +92 -0
  249. acceldata/models/api/pipeline/span_event_response.py +92 -0
  250. acceldata/models/api/pipeline/span_request.py +94 -0
  251. acceldata/models/api/pipeline/spans_response.py +96 -0
  252. acceldata/models/api/pipeline/tag.py +97 -0
  253. acceldata/models/sdk/__init__.py +0 -0
  254. acceldata/models/sdk/catalog/__init__.py +105 -0
  255. acceldata/models/sdk/catalog/asset_resource.py +112 -0
  256. acceldata/models/sdk/catalog/asset_source_type.py +59 -0
  257. acceldata/models/sdk/catalog/custom_asset_metadata.py +11 -0
  258. acceldata/models/sdk/catalog/datasource_resource.py +88 -0
  259. acceldata/models/sdk/catalog/executor.py +524 -0
  260. acceldata/models/sdk/catalog/policy_execution_request.py +114 -0
  261. acceldata/models/sdk/catalog/policy_execution_type.py +16 -0
  262. acceldata/models/sdk/catalog/policy_filter.py +94 -0
  263. acceldata/models/sdk/catalog/policy_rule_resources.py +388 -0
  264. acceldata/models/sdk/catalog/profile_request_resource.py +77 -0
  265. acceldata/models/sdk/catalog/profiling.py +82 -0
  266. acceldata/models/sdk/catalog/profiling_configuration_error.py +5 -0
  267. acceldata/models/sdk/pipeline/__init__.py +62 -0
  268. acceldata/models/sdk/pipeline/create_job_input.py +108 -0
  269. acceldata/models/sdk/pipeline/create_pipeline_input_request.py +72 -0
  270. acceldata/models/sdk/pipeline/events/__init__.py +5 -0
  271. acceldata/models/sdk/pipeline/events/generic_event.py +31 -0
  272. acceldata/models/sdk/pipeline/events/log_event.py +34 -0
  273. acceldata/models/sdk/pipeline/events/span_event.py +8 -0
  274. acceldata/models/sdk/pipeline/pipeline_resource.py +171 -0
  275. acceldata/models/sdk/pipeline/pipeline_run_input.py +84 -0
  276. acceldata/models/sdk/pipeline/pipeline_run_resource.py +208 -0
  277. acceldata/models/sdk/pipeline/pipeline_source_type.py +20 -0
  278. acceldata/models/sdk/pipeline/span_resource.py +327 -0
  279. acceldata/openapi_deserialization_patches.py +161 -0
  280. acceldata/openapi_repr_patches.py +62 -0
  281. acceldata/services/__init__.py +0 -0
  282. acceldata/services/api_timestamp.py +31 -0
  283. acceldata/services/asset_service.py +651 -0
  284. acceldata/services/datasource_service.py +120 -0
  285. acceldata/services/generic_service.py +132 -0
  286. acceldata/services/marker_config.py +232 -0
  287. acceldata/services/pipeline_big_decimal_api.py +102 -0
  288. acceldata/services/pipeline_response_parse.py +209 -0
  289. acceldata/services/pipeline_service.py +494 -0
  290. acceldata/services/rule_service.py +620 -0
  291. acceldata/urls/__init__.py +1 -0
  292. acceldata/urls/catalog_urls.py +137 -0
  293. acceldata/urls/pipeline_urls.py +55 -0
  294. acceldata/utils/__init__.py +6 -0
  295. acceldata/utils/datetime_utils.py +16 -0
  296. acceldata/utils/operation_ack.py +22 -0
  297. acceldata/utils/span_helpers.py +95 -0
  298. acceldata/utils/time_range_utils.py +90 -0
  299. acceldata_sdk_python-26.7.0.dist-info/METADATA +26 -0
  300. acceldata_sdk_python-26.7.0.dist-info/RECORD +303 -0
  301. acceldata_sdk_python-26.7.0.dist-info/WHEEL +5 -0
  302. acceldata_sdk_python-26.7.0.dist-info/licenses/LICENSE +22 -0
  303. acceldata_sdk_python-26.7.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,620 @@
1
+ from __future__ import annotations
2
+
3
+ import logging
4
+ from typing import Any
5
+
6
+ from pydantic import ValidationError
7
+
8
+ from acceldata.client.http_client import BaseHttpClient
9
+ from acceldata.mappers.catalog_executions import (
10
+ catalog_generic_execution_branch_typename,
11
+ catalog_generic_execution_payload,
12
+ )
13
+ from acceldata.models.api.catalog.data_cadence_rule_response import DataCadenceRuleResponse
14
+ from acceldata.models.api.catalog.data_quality_execution import DataQualityExecution
15
+ from acceldata.models.api.catalog.data_quality_rule_response import DataQualityRuleResponse
16
+ from acceldata.models.api.catalog.enable_rule_request import EnableRuleRequest
17
+ from acceldata.models.api.catalog.execution_cancellation_response import ExecutionCancellationResponse
18
+ from acceldata.models.api.catalog.execution_result import ExecutionResult
19
+ from acceldata.models.api.catalog.generic_execution import GenericExecution
20
+ from acceldata.models.api.catalog.policy_execution_request import (
21
+ PolicyExecutionRequest as CatalogPolicyExecutionRequest,
22
+ )
23
+ from acceldata.models.api.catalog.data_cadence_rule_execution import DataCadenceRuleExecution
24
+ from acceldata.models.api.catalog.data_drift_execution import DataDriftExecution
25
+ from acceldata.models.api.catalog.reconciliation_rule_execution import ReconciliationRuleExecution
26
+ from acceldata.models.api.catalog.schema_drift_rule_execution import SchemaDriftRuleExecution
27
+ from acceldata.models.sdk.catalog.policy_execution_request import (
28
+ PolicyExecutionRequestInput,
29
+ ensure_catalog_policy_execution_request,
30
+ )
31
+ from acceldata.models.sdk.catalog.policy_execution_type import PolicyExecutionType
32
+ from acceldata.models.api.catalog.quality_rule import QualityRule
33
+ from acceldata.models.api.catalog.reconciliation_rule_response import ReconciliationRuleResponse
34
+ from acceldata.models.api.catalog.rules_with_latest_execution_response import \
35
+ RulesWithLatestExecutionResponse
36
+ from acceldata.models.sdk.catalog.policy_filter import PolicyFilter, RuleType
37
+ from acceldata.utils.time_range_utils import TimeRangeCalculator
38
+
39
+ logger = logging.getLogger("sdk")
40
+
41
+ # POST …/rules/{kind}/{id}/executions — each endpoint’s body matches one ``GenericExecution`` branch.
42
+ # Use concrete execution DTO types from ``acceldata.models.api.catalog`` that match the wire shape,
43
+ # or ``GenericExecution(typed)`` validation fails.
44
+ _EXECUTE_RESPONSE_MODEL = {
45
+ "execute_dq_rule": DataQualityExecution,
46
+ "execute_reconciliation_rule": ReconciliationRuleExecution,
47
+ "execute_freshness_rule": DataCadenceRuleExecution,
48
+ }
49
+
50
+ # GET ``.../rules/.../executions`` list rows match exactly one ``GenericExecution`` branch; avoid
51
+ # ``GenericExecution.from_dict`` here — the oneOf deserializer can match several branches for the same JSON.
52
+ _POLICY_EXECUTIONS_LIST_ROW_MODEL: dict[RuleType, type] = {
53
+ RuleType.DATA_QUALITY: DataQualityExecution,
54
+ RuleType.RECONCILIATION: ReconciliationRuleExecution,
55
+ RuleType.EQUALITY: ReconciliationRuleExecution,
56
+ RuleType.DATA_DRIFT: DataDriftExecution,
57
+ RuleType.SCHEMA_DRIFT: SchemaDriftRuleExecution,
58
+ RuleType.DATA_CADENCE: DataCadenceRuleExecution,
59
+ }
60
+
61
+
62
+ def _normalize_catalog_policy_execution_row(row: dict[str, Any]) -> dict[str, Any]:
63
+ """Catalog execution list rows may omit ``items`` or send ``null``; typed API DTOs expect a list."""
64
+ normalized = dict(row)
65
+ if normalized.get("items") is None:
66
+ normalized["items"] = []
67
+ return normalized
68
+
69
+
70
+ def _generic_execution_from_policy_executions_row(row: dict[str, Any], rule_type: RuleType) -> GenericExecution:
71
+ model_cls = _POLICY_EXECUTIONS_LIST_ROW_MODEL.get(rule_type)
72
+ if model_cls is None:
73
+ raise ValueError(f"policy_executions: unsupported rule_type {rule_type!r}")
74
+ row = _normalize_catalog_policy_execution_row(row)
75
+ try:
76
+ typed = model_cls.from_dict(row)
77
+ except (ValidationError, ValueError, TypeError) as strict_exc:
78
+ # Newer / looser list rows: same outer shape may no longer match the exact typed
79
+ # wrapper, but the payload may still be a valid :class:`GenericExecution` oneOf. Mirrors
80
+ # the POST ``_parse_generic_execution_response`` fallback to ``GenericExecution.from_dict``.
81
+ try:
82
+ ge = GenericExecution.from_dict(row)
83
+ except (ValidationError, ValueError) as loose_exc:
84
+ raise TypeError(
85
+ f"policy_executions could not deserialize row as {model_cls.__name__} "
86
+ f"and GenericExecution oneOf also failed. Strict: {strict_exc}. OneOf: {loose_exc}"
87
+ ) from strict_exc
88
+ branch = catalog_generic_execution_payload(ge)
89
+ if branch is None:
90
+ raise TypeError(
91
+ f"policy_executions: GenericExecution fallback deserialised empty (expected for row keys "
92
+ f"{sorted(row.keys())!r})"
93
+ ) from strict_exc
94
+ logger.debug(
95
+ "policy_executions: row was not a strict %s; deserialized as GenericExecution (oneOf: %s)",
96
+ model_cls.__name__,
97
+ catalog_generic_execution_branch_typename(ge),
98
+ )
99
+ return ge
100
+ if typed is None:
101
+ raise TypeError(f"policy_executions: empty deserialization for {model_cls.__name__}")
102
+ if not isinstance(typed, model_cls):
103
+ # ``from_dict`` should return ``model_cls``; keep behavior resilient for mocked/stubbed returns.
104
+ try:
105
+ return GenericExecution(typed)
106
+ except (ValidationError, ValueError, TypeError):
107
+ logger.debug(
108
+ "policy_executions: using unvalidated GenericExecution wrapper for %s.from_dict return type %s",
109
+ model_cls.__name__,
110
+ type(typed).__name__,
111
+ )
112
+ return GenericExecution.model_construct(actual_instance=typed)
113
+ return GenericExecution(typed)
114
+
115
+
116
+ def _describe_generic_execution_parse_failure(exc: BaseException) -> str:
117
+ """One-line classification for GenericExecution ``oneOf`` failures (avoid huge pydantic dumps in logs)."""
118
+ msg = str(exc)
119
+ if "Multiple matches found" in msg:
120
+ return (
121
+ "GenericExecution oneOf is ambiguous (several branches matched). "
122
+ "Common when the API omits nulls for nested item fields while the client model schema marks those "
123
+ "properties as required without defaults — fix the spec / annotations and regenerate the client."
124
+ )
125
+ if "No match found" in msg:
126
+ return "GenericExecution oneOf: no branch matched this JSON shape."
127
+ return f"{type(exc).__name__}: {msg[:200]}{'…' if len(msg) > 200 else ''}"
128
+
129
+
130
+ # Path segment under ``GET /rules/{segment}/{ruleId}/executions`` (kebab-case).
131
+ # Data-quality and reconciliation use these typed paths; all other kinds use
132
+ # ``GET /rules/executions`` with ``ruleId``; see ``_uses_rules_executions_endpoint``.
133
+ _RULE_TYPE_TO_EXECUTIONS_PATH_SEGMENT: dict[RuleType, str] = {
134
+ RuleType.DATA_QUALITY: "data-quality",
135
+ RuleType.RECONCILIATION: "reconciliation",
136
+ }
137
+
138
+
139
+ def _uses_rules_executions_endpoint(rule_type: RuleType) -> bool:
140
+ """Whether to call ``GET /rules/executions`` with ``ruleId`` (any kind except data-quality / reconciliation)."""
141
+ return rule_type not in (RuleType.DATA_QUALITY, RuleType.RECONCILIATION)
142
+
143
+
144
+ class RuleService:
145
+ def __init__(self, http_client: BaseHttpClient) -> None:
146
+ self._client = http_client
147
+
148
+ def get_all_rules(
149
+ self,
150
+ filter: PolicyFilter,
151
+ page: int = 0,
152
+ size: int = 25,
153
+ with_latest_execution: bool = True,
154
+ sort_by: str = "updatedAt:DESC",
155
+ ) -> RulesWithLatestExecutionResponse:
156
+ params: dict[str, Any] = {
157
+ "page": page,
158
+ "size": size,
159
+ "withLatestExecution": with_latest_execution,
160
+ "sortBy": sort_by,
161
+ }
162
+ if filter.policy_type is not None:
163
+ params["ruleType"] = filter.policy_type.name
164
+ if filter.policy_type.name == RuleType.RECONCILIATION.name:
165
+ params["ruleType"] = params["ruleType"] + ",EQUALITY"
166
+ if filter.last_execution_result is not None:
167
+ params["resultStatus"] = filter.last_execution_result.name
168
+ if filter.enable is not None:
169
+ params["enabled"] = filter.enable
170
+ if filter.active is not None and filter.active is True:
171
+ params["ruleStatus"] = "ACTIVE"
172
+ else:
173
+ params["ruleStatus"] = "ALL"
174
+ if filter.assets is not None:
175
+ params["assetIds"] = ",".join([str(i.id) for i in filter.assets])
176
+ if filter.data_sources is not None:
177
+ params["assemblyIds"] = ",".join([str(i.id) for i in filter.data_sources])
178
+ if filter.period is not None:
179
+ finished_before_time, started_after_time = TimeRangeCalculator.calculate_time_range(filter)
180
+ if started_after_time is not None:
181
+ params["startedAfter"] = int(round(started_after_time.timestamp() * 1000))
182
+ params["finishedBefore"] = int(round(finished_before_time.timestamp() * 1000))
183
+
184
+ logger.debug(params)
185
+ url = self._client.catalog_urls.rules()
186
+ response = self._client._get(
187
+ url=url,
188
+ params=params,
189
+ )
190
+ logger.debug(f"Response: {response}")
191
+ return RulesWithLatestExecutionResponse.from_dict(response)
192
+
193
+ @staticmethod
194
+ def _require_object_response(response: object, operation: str) -> dict[str, Any]:
195
+ if not isinstance(response, dict):
196
+ raise TypeError(f"{operation} expected a JSON object response, got {type(response).__name__}")
197
+ return response
198
+
199
+ def get_policy(self, identifier: str | int) -> QualityRule:
200
+ """GET ``/rules/{identifier}`` — returns :class:`~acceldata.models.api.catalog.quality_rule.QualityRule`."""
201
+ url = self._client.catalog_urls.rule_by_identifier(identifier)
202
+ response = self._client._get(url=url)
203
+ raw = self._require_object_response(response, "get_policy")
204
+ parsed = QualityRule.from_dict(raw)
205
+ if parsed is None:
206
+ raise TypeError("get_policy received an empty QualityRule payload")
207
+ return parsed
208
+
209
+ def get_dq_rule(self, rule_id: str | int) -> DataQualityRuleResponse:
210
+ """GET ``/rules/data-quality/{rule_id}`` — Data quality :class:`~acceldata.models.api.catalog.rule_response.RuleResponse`."""
211
+ url = self._client.catalog_urls.data_quality_rule(rule_id)
212
+ response = self._client._get(url=url)
213
+ raw = self._require_object_response(response, "get_dq_rule")
214
+ logger.info(f"Raw dq rule: {raw} ")
215
+ parsed = DataQualityRuleResponse.from_dict(raw)
216
+ logger.debug(f"DataQualityRuleResponse: {parsed}")
217
+ if parsed is None:
218
+ raise TypeError("get_dq_rule received an empty RuleResponse payload")
219
+ return parsed
220
+
221
+ def get_reconciliation_rule(self, rule_id: str | int) -> ReconciliationRuleResponse:
222
+ """GET ``/rules/reconciliation/{rule_id}``."""
223
+ url = self._client.catalog_urls.reconciliation_rule(rule_id)
224
+ response = self._client._get(url=url)
225
+ raw = self._require_object_response(response, "get_reconciliation_rule")
226
+ parsed = ReconciliationRuleResponse.from_dict(raw)
227
+ if parsed is None:
228
+ raise TypeError("get_reconciliation_rule received an empty response payload")
229
+ return parsed
230
+
231
+ def get_freshness_rule(self, rule_id: str | int) -> DataCadenceRuleResponse:
232
+ """GET ``/rules/data-cadence/{rule_id}`` (freshness / cadence rule)."""
233
+ url = self._client.catalog_urls.data_cadence_rule(rule_id)
234
+ response = self._client._get(url=url)
235
+ raw = self._require_object_response(response, "get_freshness_rule")
236
+ parsed = DataCadenceRuleResponse.from_dict(raw)
237
+ if parsed is None:
238
+ raise TypeError("get_freshness_rule received an empty response payload")
239
+ return parsed
240
+
241
+ def get_reconciliation_rule_execution_details(
242
+ self, execution_id: str | int
243
+ ) -> ReconciliationRuleExecution:
244
+ """GET ``/rules/reconciliation/executions/{execution_id}`` — Reconciliation.Execution payload."""
245
+ url = self._client.catalog_urls.reconciliation_rule_execution(execution_id)
246
+ response = self._client._get(url=url)
247
+ raw = self._require_object_response(response, "get_reconciliation_rule_execution_details")
248
+ parsed = ReconciliationRuleExecution.from_dict(raw)
249
+ if parsed is None:
250
+ raise TypeError("get_reconciliation_rule_execution_details received an empty response payload")
251
+ return parsed
252
+
253
+ def get_reconciliation_rule_result(self, execution_id: str | int) -> ExecutionResult:
254
+ """GET ``/rules/reconciliation/executions/{execution_id}/result`` — :class:`ExecutionResult`."""
255
+ url = self._client.catalog_urls.reconciliation_rule_execution_result(execution_id)
256
+ response = self._client._get(url=url)
257
+ raw = self._require_object_response(response, "get_reconciliation_rule_result")
258
+ parsed = ExecutionResult.from_dict(raw)
259
+ if parsed is None:
260
+ raise TypeError("get_reconciliation_rule_result received an empty response payload")
261
+ return parsed
262
+
263
+ @staticmethod
264
+ def _identifier_is_numeric_rule_id(identifier: str | int) -> bool:
265
+ if isinstance(identifier, int):
266
+ return True
267
+ return TimeRangeCalculator.check_int(str(identifier))
268
+
269
+ def _resolve_rule_id_for_executions(self, identifier: str | int, rule_type: RuleType) -> str | int:
270
+ if self._identifier_is_numeric_rule_id(identifier):
271
+ return identifier
272
+ if rule_type == RuleType.DATA_QUALITY:
273
+ rule_res = self.get_dq_rule(identifier)
274
+ rid = rule_res.rule.id
275
+ elif rule_type in (RuleType.RECONCILIATION, RuleType.EQUALITY):
276
+ rule_res = self.get_reconciliation_rule(identifier)
277
+ rid = rule_res.rule.id
278
+ elif rule_type == RuleType.DATA_CADENCE:
279
+ rule_res = self.get_freshness_rule(identifier)
280
+ rid = rule_res.rule.id
281
+ elif _uses_rules_executions_endpoint(rule_type):
282
+ qr = self.get_policy(identifier)
283
+ rid = qr.id
284
+ else:
285
+ raise ValueError(
286
+ f"A numeric rule id is required for {rule_type.name}; "
287
+ "name-based lookup is not implemented for this rule kind."
288
+ )
289
+ if rid is None:
290
+ raise TypeError("Resolved rule has no id; cannot list executions.")
291
+ return rid
292
+
293
+ def _policy_executions_url(self, rule_type: RuleType, rule_id: str | int) -> str:
294
+ segment = _RULE_TYPE_TO_EXECUTIONS_PATH_SEGMENT.get(rule_type)
295
+ if segment is None:
296
+ raise ValueError(f"Unknown rule type for listing executions: {rule_type!r}")
297
+ base = self._client.catalog_urls.rules()
298
+ return f"{base}/{segment}/{rule_id}/executions"
299
+
300
+ @staticmethod
301
+ def _executions_rows_from_policy_list_response(raw: dict[str, Any]) -> list[Any]:
302
+ """Normalize list payloads from GET ``.../rules/{{kind}}/{{id}}/executions``.
303
+
304
+ The API may return either a flat ``ExecutionsResponse`` shape
305
+ (``executions`` + ``meta`` at the top level) or a Kotlin-style wrapper whose
306
+ sole meaningful key ends with ``ExecutionsResponse``, e.g.
307
+ ``DataQuality.ExecutionsResponse`` or ``Reconciliation.ExecutionsResponse``.
308
+
309
+ When the payload has no recognizable executions list (e.g. empty object or
310
+ only ``meta``), returns an empty list — the rule may never have been executed.
311
+ """
312
+ if not raw:
313
+ return []
314
+ if "executions" in raw:
315
+ top = raw["executions"]
316
+ if top is None:
317
+ return []
318
+ if isinstance(top, list):
319
+ return top
320
+ raise TypeError(
321
+ "policy_executions expected top-level 'executions' to be a list or null, "
322
+ f"got {type(top).__name__}"
323
+ )
324
+
325
+ for key, value in raw.items():
326
+ if not isinstance(value, dict):
327
+ continue
328
+ if not key.endswith("ExecutionsResponse"):
329
+ continue
330
+ nested = value.get("executions")
331
+ if nested is None:
332
+ return []
333
+ if isinstance(nested, list):
334
+ return nested
335
+ raise TypeError(
336
+ "policy_executions expected wrapped *ExecutionsResponse.executions to be a list, "
337
+ f"got {type(nested).__name__} (key {key!r})"
338
+ )
339
+
340
+ logger.debug(
341
+ "policy_executions: no executions list in response (keys=%s); treating as no runs",
342
+ sorted(raw.keys()),
343
+ )
344
+ return []
345
+
346
+ def policy_executions(
347
+ self,
348
+ identifier: str | int,
349
+ rule_type: RuleType,
350
+ page: int = 0,
351
+ size: int = 25,
352
+ sort_by: str = "finishedAt:DESC",
353
+ ) -> list[GenericExecution]:
354
+ """List rule executions.
355
+
356
+ Uses ``GET /rules/{{kind}}/{{rule_id}}/executions`` for data-quality and reconciliation
357
+ rules only. All other kinds use ``GET /rules/executions`` with query param ``ruleId``
358
+ (same contract as the catalog UI).
359
+
360
+ Accepts both flat ``ExecutionsResponse`` JSON and wrapped shapes such as
361
+ ``DataQuality.ExecutionsResponse`` / ``Reconciliation.ExecutionsResponse``.
362
+
363
+ Returns an empty list when the catalog has no executions yet (including a JSON
364
+ ``null`` body parsed as ``None``, an empty object ``{}``, or a payload with no
365
+ ``executions`` / ``*ExecutionsResponse`` list).
366
+
367
+ Each row is first parsed with the rule-kind–specific typed model (e.g. ``DataQualityExecution``).
368
+ If that fails, the same row is retried with :class:`GenericExecution` (``oneOf``), same strategy as
369
+ :meth:`execute_dq_rule` and :meth:`_parse_generic_execution_response` for execute responses.
370
+ """
371
+ rule_id = self._resolve_rule_id_for_executions(identifier, rule_type)
372
+ if _uses_rules_executions_endpoint(rule_type):
373
+ url = self._client.catalog_urls.rules_executions()
374
+ params: dict[str, Any] = {
375
+ "page": page,
376
+ "size": size,
377
+ "sortBy": sort_by,
378
+ "ruleId": rule_id,
379
+ }
380
+ else:
381
+ url = self._policy_executions_url(rule_type, rule_id)
382
+ params = {
383
+ "page": page,
384
+ "size": size,
385
+ "sortBy": sort_by,
386
+ }
387
+ response = self._client._get(url=url, params=params)
388
+ logger.debug(f"Rule executions response: {response}")
389
+ if response is None:
390
+ return []
391
+ raw = self._require_object_response(response, "policy_executions")
392
+ rows = self._executions_rows_from_policy_list_response(raw)
393
+ row_model = _POLICY_EXECUTIONS_LIST_ROW_MODEL.get(rule_type)
394
+ if row_model is None:
395
+ raise ValueError(f"policy_executions: unsupported rule_type {rule_type!r}")
396
+ logger.debug(
397
+ "policy_executions: parsing %d row(s) as %s (rule_type=%s)",
398
+ len(rows),
399
+ row_model.__name__,
400
+ rule_type.name,
401
+ )
402
+ parsed: list[GenericExecution] = []
403
+ for row in rows:
404
+ if not isinstance(row, dict):
405
+ raise TypeError(
406
+ "policy_executions expected each row to be an object with an 'execution' field, "
407
+ f"got {type(row).__name__}"
408
+ )
409
+ if "execution" not in row:
410
+ raise TypeError("policy_executions row is missing required 'execution' field")
411
+ execution_raw = row["execution"]
412
+ if execution_raw is None:
413
+ raise TypeError("policy_executions row['execution'] is null")
414
+ if not isinstance(execution_raw, dict):
415
+ raise TypeError(
416
+ "policy_executions expected row['execution'] to be an object, "
417
+ f"got {type(execution_raw).__name__}"
418
+ )
419
+ # List rows match ``DataQualityExecution`` / ``ReconciliationRuleExecution`` etc. (execution +
420
+ # items + policy fields), not bare ``RuleExecution`` / ``GenericRuleExecution`` payloads.
421
+ ge = _generic_execution_from_policy_executions_row(row, rule_type)
422
+ if ge is None:
423
+ raise TypeError("policy_executions received empty execution payload")
424
+ parsed.append(ge)
425
+ return parsed
426
+
427
+ def execute_dq_rule(
428
+ self,
429
+ rule_id: str | int,
430
+ policy_execution_request: PolicyExecutionRequestInput,
431
+ ) -> GenericExecution:
432
+ """POST ``/rules/data-quality/{rule_id}/executions`` — returns :class:`GenericExecution`."""
433
+ payload = self._payload_from_policy_execution_request(policy_execution_request)
434
+ response = self._client._post(
435
+ url=self._client.catalog_urls.data_quality_rule_executions(rule_id),
436
+ payload=payload,
437
+ )
438
+ logger.debug(f"execute_dq_rule response: {response}")
439
+ return self._parse_generic_execution_response(response, "execute_dq_rule")
440
+
441
+ def execute_reconciliation_rule(
442
+ self,
443
+ rule_id: str | int,
444
+ policy_execution_request: PolicyExecutionRequestInput,
445
+ ) -> GenericExecution:
446
+ """POST ``/rules/reconciliation/{rule_id}/executions`` — returns :class:`GenericExecution`."""
447
+ payload = self._payload_from_policy_execution_request(policy_execution_request)
448
+ response = self._client._post(
449
+ url=self._client.catalog_urls.reconciliation_rule_executions(rule_id),
450
+ payload=payload,
451
+ )
452
+ return self._parse_generic_execution_response(response, "execute_reconciliation_rule")
453
+
454
+ def execute_freshness_rule(
455
+ self,
456
+ rule_id: str | int,
457
+ policy_execution_request: PolicyExecutionRequestInput,
458
+ ) -> GenericExecution:
459
+ """POST ``/rules/data-cadence/{rule_id}/executions`` — returns :class:`GenericExecution`."""
460
+ payload = self._payload_from_policy_execution_request(policy_execution_request)
461
+ response = self._client._post(
462
+ url=self._client.catalog_urls.data_cadence_rule_executions(rule_id),
463
+ payload=payload,
464
+ )
465
+ return self._parse_generic_execution_response(response, "execute_freshness_rule")
466
+
467
+ @staticmethod
468
+ def _payload_from_policy_execution_request(req: PolicyExecutionRequestInput) -> dict[str, Any]:
469
+ api_req = ensure_catalog_policy_execution_request(req)
470
+ if (
471
+ api_req.execution_type == PolicyExecutionType.SELECTIVE.value
472
+ and not api_req.marker_configs
473
+ ):
474
+ raise ValueError("markerConfigs is mandatory when execution_type is SELECTIVE")
475
+ # Always use generated model ``to_dict()`` so oneOf wrappers (e.g. MarkerConfig) serialize
476
+ # as plain wire JSON accepted by catalog execution endpoints.
477
+ return api_req.to_dict()
478
+
479
+ @staticmethod
480
+ def _parse_generic_execution_response(response: object, operation_name: str) -> GenericExecution:
481
+ raw = RuleService._require_object_response(response, operation_name)
482
+ first_error: BaseException | None = None
483
+
484
+ model_cls = _EXECUTE_RESPONSE_MODEL.get(operation_name)
485
+ if model_cls is not None and isinstance(raw, dict):
486
+ try:
487
+ typed = model_cls.from_dict(raw)
488
+ if typed is not None:
489
+ logger.debug("%s: parsed as %s", operation_name, model_cls.__name__)
490
+ return GenericExecution(typed)
491
+ except (ValidationError, ValueError, TypeError) as e:
492
+ first_error = e
493
+ logger.debug(
494
+ "%s: %s.from_dict failed; falling back to GenericExecution",
495
+ operation_name,
496
+ model_cls.__name__,
497
+ exc_info=e,
498
+ )
499
+
500
+ try:
501
+ ge = GenericExecution.from_dict(raw)
502
+ logger.debug("%s: response deserialized as GenericExecution (oneOf)", operation_name)
503
+ return ge
504
+ except (ValueError, ValidationError) as e:
505
+ first_error = e
506
+ logger.debug("%s: %s", operation_name, _describe_generic_execution_parse_failure(e))
507
+ logger.debug("%s: GenericExecution.from_dict failure detail", operation_name, exc_info=e)
508
+
509
+ # Kotlin/Jackson may wrap under a key ending in ``.Execution``.
510
+ for key, value in raw.items():
511
+ if isinstance(value, dict) and key.endswith(".Execution"):
512
+ try:
513
+ ge = GenericExecution.from_dict(value)
514
+ logger.debug("%s: response deserialized from nested key %r", operation_name, key)
515
+ return ge
516
+ except (ValueError, ValidationError):
517
+ continue
518
+
519
+ hint = (
520
+ _describe_generic_execution_parse_failure(first_error)
521
+ if first_error is not None
522
+ else "could not classify parse failure"
523
+ )
524
+ raise TypeError(
525
+ f"{operation_name}: could not deserialize execution response. {hint} "
526
+ f"Top-level keys: {sorted(raw.keys())}."
527
+ ) from first_error
528
+
529
+ def get_dq_rule_result(self, execution_id: str | int) -> ExecutionResult:
530
+ """GET ``/rules/data-quality/executions/{execution_id}/result`` — :class:`ExecutionResult`."""
531
+ url = self._client.catalog_urls.data_quality_rule_execution_result(execution_id)
532
+ response = self._client._get(url=url)
533
+ raw = self._require_object_response(response, "get_dq_rule_result")
534
+ parsed = ExecutionResult.from_dict(raw)
535
+ if parsed is None:
536
+ raise TypeError("get_dq_rule_result received an empty response payload")
537
+ return parsed
538
+
539
+ def get_dq_rule_execution_details(self, execution_id: str | int) -> DataQualityExecution:
540
+ """GET ``/rules/data-quality/executions/{execution_id}`` — :class:`DataQualityExecution`."""
541
+ url = self._client.catalog_urls.data_quality_rule_execution(execution_id)
542
+ response = self._client._get(url=url)
543
+ raw = self._require_object_response(response, "get_dq_rule_execution_details")
544
+ parsed = DataQualityExecution.from_dict(raw)
545
+ if parsed is None:
546
+ raise TypeError("get_dq_rule_execution_details received an empty response payload")
547
+ return parsed
548
+
549
+ def get_freshness_rule_result(self, execution_id: str | int) -> ExecutionResult:
550
+ """GET ``/rules/data-cadence/executions/{execution_id}/result`` — :class:`ExecutionResult`."""
551
+ url = self._client.catalog_urls.data_cadence_rule_execution_result(execution_id)
552
+ response = self._client._get(url=url)
553
+ raw = self._require_object_response(response, "get_freshness_rule_result")
554
+ parsed = ExecutionResult.from_dict(raw)
555
+ if parsed is None:
556
+ raise TypeError("get_freshness_rule_result received an empty response payload")
557
+ return parsed
558
+
559
+ def get_data_cadence_rule_execution_details(
560
+ self, execution_id: str | int
561
+ ) -> DataCadenceRuleExecution:
562
+ """GET ``/rules/data-cadence/executions/{execution_id}`` — :class:`DataCadenceRuleExecution`."""
563
+ url = self._client.catalog_urls.data_cadence_rule_execution(execution_id)
564
+ response = self._client._get(url=url)
565
+ raw = self._require_object_response(response, "get_data_cadence_rule_execution_details")
566
+ parsed = DataCadenceRuleExecution.from_dict(raw)
567
+ if parsed is None:
568
+ raise TypeError("get_data_cadence_rule_execution_details received an empty response payload")
569
+ return parsed
570
+
571
+ def cancel_rule_execution(self, execution_id: str | int) -> ExecutionCancellationResponse:
572
+ """PUT ``/rules/execution/{execution_id}/cancel`` — returns :class:`ExecutionCancellationResponse`."""
573
+ response = self._client._put(
574
+ url=self._client.catalog_urls.cancel_rule_execution(execution_id),
575
+ payload={},
576
+ )
577
+ raw = self._require_object_response(response, "cancel_rule_execution")
578
+ parsed = ExecutionCancellationResponse.from_dict(raw)
579
+ if parsed is None:
580
+ raise TypeError("cancel_rule_execution received an empty response payload")
581
+ if parsed.result.message is None:
582
+ parsed.result.message = (
583
+ f"Cancellation requested for execution {execution_id} "
584
+ f"(status={parsed.result.status})."
585
+ )
586
+ if parsed.result.request_id is None:
587
+ parsed.result.request_id = str(execution_id)
588
+ return parsed
589
+
590
+ def enable_rule(self, rule_id: str | int) -> QualityRule:
591
+ """PUT ``/rules/{rule_id}/enable`` with :class:`~acceldata.models.api.catalog.enable_rule_request.EnableRuleRequest` (``enable: true``); returns :class:`QualityRule`."""
592
+ payload = EnableRuleRequest(enable=True).to_dict()
593
+ response = self._client._put(
594
+ url=self._client.catalog_urls.rule_enable(rule_id),
595
+ payload=payload,
596
+ )
597
+ raw = self._require_object_response(response, "enable_rule")
598
+ inner = raw.get("rule", raw)
599
+ if not isinstance(inner, dict):
600
+ raise TypeError(f"enable_rule expected rule object, got {type(inner).__name__}")
601
+ parsed = QualityRule.from_dict(inner)
602
+ if parsed is None:
603
+ raise TypeError("enable_rule received an empty QualityRule payload")
604
+ return parsed
605
+
606
+ def disable_rule(self, rule_id: str | int) -> QualityRule:
607
+ """PUT ``/rules/{rule_id}/enable`` with :class:`~acceldata.models.api.catalog.enable_rule_request.EnableRuleRequest` (``enable: false``); returns :class:`QualityRule`."""
608
+ payload = EnableRuleRequest(enable=False).to_dict()
609
+ response = self._client._put(
610
+ url=self._client.catalog_urls.rule_enable(rule_id),
611
+ payload=payload,
612
+ )
613
+ raw = self._require_object_response(response, "disable_rule")
614
+ inner = raw.get("rule", raw)
615
+ if not isinstance(inner, dict):
616
+ raise TypeError(f"disable_rule expected rule object, got {type(inner).__name__}")
617
+ parsed = QualityRule.from_dict(inner)
618
+ if parsed is None:
619
+ raise TypeError("disable_rule received an empty QualityRule payload")
620
+ return parsed
@@ -0,0 +1 @@
1
+ from .catalog_urls import CatalogUrls