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.
- acceldata/__init__.py +7 -0
- acceldata/client/__init__.py +0 -0
- acceldata/client/adoc_client.py +666 -0
- acceldata/client/http_client.py +346 -0
- acceldata/client/transient_retry.py +142 -0
- acceldata/constants/__init__.py +1 -0
- acceldata/constants/constants.py +13 -0
- acceldata/exceptions/__init__.py +52 -0
- acceldata/exceptions/api_errors.py +85 -0
- acceldata/exceptions/exceptions.py +174 -0
- acceldata/exceptions/sdk_exceptions.py +98 -0
- acceldata/mappers/__init__.py +21 -0
- acceldata/mappers/catalog_executions.py +107 -0
- acceldata/models/__init__.py +0 -0
- acceldata/models/api/catalog/above_configs.py +99 -0
- acceldata/models/api/catalog/above_configs_success.py +138 -0
- acceldata/models/api/catalog/absolute_configs.py +197 -0
- acceldata/models/api/catalog/absolute_configs_fallback.py +101 -0
- acceldata/models/api/catalog/absolute_threshold_config.py +105 -0
- acceldata/models/api/catalog/analysis_job_context.py +102 -0
- acceldata/models/api/catalog/analytics_pipeline.py +385 -0
- acceldata/models/api/catalog/analytics_pipeline_endpoint.py +136 -0
- acceldata/models/api/catalog/anomaly_config.py +95 -0
- acceldata/models/api/catalog/anomaly_details.py +119 -0
- acceldata/models/api/catalog/anomaly_threshold_config.py +105 -0
- acceldata/models/api/catalog/artifact.py +92 -0
- acceldata/models/api/catalog/assembly.py +171 -0
- acceldata/models/api/catalog/asset.py +162 -0
- acceldata/models/api/catalog/asset_catalog_listing.py +159 -0
- acceldata/models/api/catalog/asset_catalog_listing_response.py +102 -0
- acceldata/models/api/catalog/asset_label_request.py +96 -0
- acceldata/models/api/catalog/asset_progress.py +96 -0
- acceldata/models/api/catalog/asset_progress_details.py +117 -0
- acceldata/models/api/catalog/asset_tag.py +124 -0
- acceldata/models/api/catalog/asset_tag_info.py +140 -0
- acceldata/models/api/catalog/asset_tag_request.py +95 -0
- acceldata/models/api/catalog/asset_tag_response.py +96 -0
- acceldata/models/api/catalog/asset_tags_response.py +102 -0
- acceldata/models/api/catalog/asset_type.py +96 -0
- acceldata/models/api/catalog/auto_anomaly_feature_analysis.py +160 -0
- acceldata/models/api/catalog/auto_anomaly_item_execution.py +133 -0
- acceldata/models/api/catalog/auto_anomaly_meta_data.py +162 -0
- acceldata/models/api/catalog/auto_anomaly_rule_execution.py +102 -0
- acceldata/models/api/catalog/auto_anomaly_summary.py +124 -0
- acceldata/models/api/catalog/backing_asset.py +126 -0
- acceldata/models/api/catalog/below_configs.py +99 -0
- acceldata/models/api/catalog/big_decimal.py +100 -0
- acceldata/models/api/catalog/big_integer.py +98 -0
- acceldata/models/api/catalog/bounds_date_time_marker_config.py +110 -0
- acceldata/models/api/catalog/bounds_file_event_marker_config.py +108 -0
- acceldata/models/api/catalog/bounds_id_marker_config.py +96 -0
- acceldata/models/api/catalog/catalog_asset_meta_data.py +128 -0
- acceldata/models/api/catalog/changes_by_config.py +105 -0
- acceldata/models/api/catalog/column_mapping.py +139 -0
- acceldata/models/api/catalog/column_metadata.py +90 -0
- acceldata/models/api/catalog/column_metric_with_anomaly_details.py +119 -0
- acceldata/models/api/catalog/column_variable.py +111 -0
- acceldata/models/api/catalog/composite_policy_execution.py +102 -0
- acceldata/models/api/catalog/composite_policy_item_execution.py +104 -0
- acceldata/models/api/catalog/connection.py +118 -0
- acceldata/models/api/catalog/connection_test_result.py +106 -0
- acceldata/models/api/catalog/connection_type.py +90 -0
- acceldata/models/api/catalog/connection_types_response.py +96 -0
- acceldata/models/api/catalog/crawler.py +88 -0
- acceldata/models/api/catalog/crawler_action_response.py +90 -0
- acceldata/models/api/catalog/crawler_execution.py +147 -0
- acceldata/models/api/catalog/crawler_execution_response.py +102 -0
- acceldata/models/api/catalog/crawler_status_response.py +90 -0
- acceldata/models/api/catalog/create_profile.py +194 -0
- acceldata/models/api/catalog/custom_sql_config.py +121 -0
- acceldata/models/api/catalog/data_bricks_spark_resource_config.py +104 -0
- acceldata/models/api/catalog/data_cadence_rule.py +236 -0
- acceldata/models/api/catalog/data_cadence_rule_details.py +125 -0
- acceldata/models/api/catalog/data_cadence_rule_execution.py +102 -0
- acceldata/models/api/catalog/data_cadence_rule_item.py +104 -0
- acceldata/models/api/catalog/data_cadence_rule_item_execution.py +158 -0
- acceldata/models/api/catalog/data_cadence_rule_response.py +98 -0
- acceldata/models/api/catalog/data_drift_execution.py +102 -0
- acceldata/models/api/catalog/data_drift_item_execution.py +121 -0
- acceldata/models/api/catalog/data_quality_engine.py +90 -0
- acceldata/models/api/catalog/data_quality_execution.py +106 -0
- acceldata/models/api/catalog/data_quality_rule.py +323 -0
- acceldata/models/api/catalog/data_quality_rule_details.py +186 -0
- acceldata/models/api/catalog/data_quality_rule_response.py +120 -0
- acceldata/models/api/catalog/data_quality_rules_response.py +102 -0
- acceldata/models/api/catalog/databricks_compute_config.py +113 -0
- acceldata/models/api/catalog/dataplane_engine.py +105 -0
- acceldata/models/api/catalog/dataplane_health_metrics.py +101 -0
- acceldata/models/api/catalog/dataplane_job.py +216 -0
- acceldata/models/api/catalog/dataplane_job_status.py +113 -0
- acceldata/models/api/catalog/dataplane_request.py +96 -0
- acceldata/models/api/catalog/dataproc_compute_config.py +106 -0
- acceldata/models/api/catalog/dataproc_spark_resource_config.py +104 -0
- acceldata/models/api/catalog/date_based_partition_marker_config.py +116 -0
- acceldata/models/api/catalog/date_partitioning_marker_config.py +113 -0
- acceldata/models/api/catalog/date_time_marker_config.py +109 -0
- acceldata/models/api/catalog/day_month_year_based_partition_marker_config.py +124 -0
- acceldata/models/api/catalog/decreased_by_config.py +105 -0
- acceldata/models/api/catalog/delete_artifact_response.py +88 -0
- acceldata/models/api/catalog/dq_rule_execution.py +248 -0
- acceldata/models/api/catalog/drift.py +121 -0
- acceldata/models/api/catalog/enable_rule_request.py +88 -0
- acceldata/models/api/catalog/engine.py +90 -0
- acceldata/models/api/catalog/execution_cancellation_response.py +92 -0
- acceldata/models/api/catalog/execution_response.py +144 -0
- acceldata/models/api/catalog/execution_result.py +126 -0
- acceldata/models/api/catalog/executions_response.py +102 -0
- acceldata/models/api/catalog/failed_asset_detail.py +90 -0
- acceldata/models/api/catalog/failed_summary.py +98 -0
- acceldata/models/api/catalog/file.py +94 -0
- acceldata/models/api/catalog/file_marker_config.py +99 -0
- acceldata/models/api/catalog/generic_config_fallback.py +101 -0
- acceldata/models/api/catalog/generic_execution.py +221 -0
- acceldata/models/api/catalog/generic_rule_execution.py +137 -0
- acceldata/models/api/catalog/global_storage_config_dto.py +172 -0
- acceldata/models/api/catalog/hosted_dp_deployment_response.py +98 -0
- acceldata/models/api/catalog/id_marker_config.py +94 -0
- acceldata/models/api/catalog/increased_by_config.py +105 -0
- acceldata/models/api/catalog/item.py +160 -0
- acceldata/models/api/catalog/item_execution.py +192 -0
- acceldata/models/api/catalog/item_segment.py +131 -0
- acceldata/models/api/catalog/job_schedule.py +118 -0
- acceldata/models/api/catalog/job_spec.py +96 -0
- acceldata/models/api/catalog/kubernetes_metrics.py +91 -0
- acceldata/models/api/catalog/label.py +97 -0
- acceldata/models/api/catalog/livy_compute_config.py +103 -0
- acceldata/models/api/catalog/livy_spark_resource_config.py +106 -0
- acceldata/models/api/catalog/look_back_config.py +90 -0
- acceldata/models/api/catalog/manual_tag_request.py +92 -0
- acceldata/models/api/catalog/mapping.py +97 -0
- acceldata/models/api/catalog/marker.py +88 -0
- acceldata/models/api/catalog/marker_config.py +349 -0
- acceldata/models/api/catalog/marker_config_fallback.py +101 -0
- acceldata/models/api/catalog/meta.py +92 -0
- acceldata/models/api/catalog/meta_data.py +92 -0
- acceldata/models/api/catalog/meta_data_item.py +94 -0
- acceldata/models/api/catalog/mini_profile_request.py +112 -0
- acceldata/models/api/catalog/notification_payload.py +114 -0
- acceldata/models/api/catalog/offset_based_marker_config.py +97 -0
- acceldata/models/api/catalog/operational_config.py +92 -0
- acceldata/models/api/catalog/pattern_configuration.py +90 -0
- acceldata/models/api/catalog/pipe_line_request.py +92 -0
- acceldata/models/api/catalog/pipeline_compute_config.py +110 -0
- acceldata/models/api/catalog/policy_execution_marker_config.py +94 -0
- acceldata/models/api/catalog/policy_execution_request.py +229 -0
- acceldata/models/api/catalog/policy_group.py +114 -0
- acceldata/models/api/catalog/policy_transform_udf.py +113 -0
- acceldata/models/api/catalog/process_metrics.py +91 -0
- acceldata/models/api/catalog/profile_anomaly_details_response.py +109 -0
- acceldata/models/api/catalog/profile_anomaly_item_execution.py +127 -0
- acceldata/models/api/catalog/profile_anomaly_rule_execution.py +102 -0
- acceldata/models/api/catalog/profile_anomaly_rule_item.py +109 -0
- acceldata/models/api/catalog/profile_cancellation_response.py +92 -0
- acceldata/models/api/catalog/profile_request.py +211 -0
- acceldata/models/api/catalog/profile_request_response.py +92 -0
- acceldata/models/api/catalog/property_template.py +178 -0
- acceldata/models/api/catalog/property_templates.py +123 -0
- acceldata/models/api/catalog/pub_sub_lookback_marker_config.py +96 -0
- acceldata/models/api/catalog/pub_sub_timestamp_marker_config.py +108 -0
- acceldata/models/api/catalog/quality_rule.py +381 -0
- acceldata/models/api/catalog/quality_rule_execution_metrics.py +114 -0
- acceldata/models/api/catalog/quality_rule_with_latest_execution.py +115 -0
- acceldata/models/api/catalog/range_configs.py +109 -0
- acceldata/models/api/catalog/reconciliation_item.py +102 -0
- acceldata/models/api/catalog/reconciliation_item_execution.py +157 -0
- acceldata/models/api/catalog/reconciliation_rule.py +339 -0
- acceldata/models/api/catalog/reconciliation_rule_details.py +225 -0
- acceldata/models/api/catalog/reconciliation_rule_execution.py +102 -0
- acceldata/models/api/catalog/reconciliation_rule_response.py +98 -0
- acceldata/models/api/catalog/reconciliation_rules_response.py +102 -0
- acceldata/models/api/catalog/relative_config.py +197 -0
- acceldata/models/api/catalog/relative_config_fallback.py +101 -0
- acceldata/models/api/catalog/relative_threshold_config.py +111 -0
- acceldata/models/api/catalog/root_cause_analysis.py +108 -0
- acceldata/models/api/catalog/rule_execution.py +327 -0
- acceldata/models/api/catalog/rule_execution_result.py +90 -0
- acceldata/models/api/catalog/rule_item_result.py +125 -0
- acceldata/models/api/catalog/rule_meta_data.py +94 -0
- acceldata/models/api/catalog/rule_spark_sql_dynamic_filter_variable_mapping.py +100 -0
- acceldata/models/api/catalog/rule_tag.py +101 -0
- acceldata/models/api/catalog/rule_threshold_configuration.py +236 -0
- acceldata/models/api/catalog/rule_threshold_configuration_fallback.py +101 -0
- acceldata/models/api/catalog/rules_with_latest_execution_response.py +102 -0
- acceldata/models/api/catalog/sample_data_api_response.py +122 -0
- acceldata/models/api/catalog/schema_drift_item_execution.py +131 -0
- acceldata/models/api/catalog/schema_drift_rule_execution.py +102 -0
- acceldata/models/api/catalog/secret_manager_configuration.py +90 -0
- acceldata/models/api/catalog/secret_manager_configuration_with_option.py +98 -0
- acceldata/models/api/catalog/security_config.py +90 -0
- acceldata/models/api/catalog/segment_metric_json.py +142 -0
- acceldata/models/api/catalog/segments_analysis.py +145 -0
- acceldata/models/api/catalog/short_segment.py +97 -0
- acceldata/models/api/catalog/simple_quality_rule_response.py +92 -0
- acceldata/models/api/catalog/snapshot_data.py +117 -0
- acceldata/models/api/catalog/source_model.py +90 -0
- acceldata/models/api/catalog/source_type.py +100 -0
- acceldata/models/api/catalog/source_types_response.py +102 -0
- acceldata/models/api/catalog/spark_job_status.py +113 -0
- acceldata/models/api/catalog/spark_resource_config.py +114 -0
- acceldata/models/api/catalog/standard_response_assembly.py +92 -0
- acceldata/models/api/catalog/standard_response_crawler_action_response.py +92 -0
- acceldata/models/api/catalog/standard_response_crawler_status_response.py +92 -0
- acceldata/models/api/catalog/standard_response_delete_artifact_response.py +92 -0
- acceldata/models/api/catalog/standard_response_list.py +96 -0
- acceldata/models/api/catalog/standard_response_map.py +88 -0
- acceldata/models/api/catalog/standard_response_meta_data.py +92 -0
- acceldata/models/api/catalog/standard_response_mini_profile_request.py +92 -0
- acceldata/models/api/catalog/standard_response_profile_request.py +92 -0
- acceldata/models/api/catalog/start_profiling_request.py +92 -0
- acceldata/models/api/catalog/tag_domain.py +116 -0
- acceldata/models/api/catalog/threshold_breach_details.py +101 -0
- acceldata/models/api/catalog/time_based_config.py +92 -0
- acceldata/models/api/catalog/time_based_threshold_config.py +105 -0
- acceldata/models/api/catalog/timestamp_based_marker_config.py +115 -0
- acceldata/models/api/catalog/udf_variable.py +97 -0
- acceldata/models/api/catalog/yunikorn_compute_config.py +133 -0
- acceldata/models/api/catalog/yunikorn_spark_resource_config.py +154 -0
- acceldata/models/api/pipeline/big_decimal.py +100 -0
- acceldata/models/api/pipeline/big_integer.py +98 -0
- acceldata/models/api/pipeline/child_span_response.py +96 -0
- acceldata/models/api/pipeline/create_span_event.py +109 -0
- acceldata/models/api/pipeline/edge.py +108 -0
- acceldata/models/api/pipeline/event_alert_object.py +95 -0
- acceldata/models/api/pipeline/generic_config_fallback.py +101 -0
- acceldata/models/api/pipeline/identifier.py +146 -0
- acceldata/models/api/pipeline/job_request.py +130 -0
- acceldata/models/api/pipeline/meta.py +107 -0
- acceldata/models/api/pipeline/meta_data.py +92 -0
- acceldata/models/api/pipeline/metric.py +103 -0
- acceldata/models/api/pipeline/node.py +201 -0
- acceldata/models/api/pipeline/node_response.py +92 -0
- acceldata/models/api/pipeline/notification_payload.py +114 -0
- acceldata/models/api/pipeline/pipeline.py +152 -0
- acceldata/models/api/pipeline/pipeline_baseline_metric.py +92 -0
- acceldata/models/api/pipeline/pipeline_details.py +118 -0
- acceldata/models/api/pipeline/pipeline_details_response.py +102 -0
- acceldata/models/api/pipeline/pipeline_input_request.py +92 -0
- acceldata/models/api/pipeline/pipeline_listing_info.py +118 -0
- acceldata/models/api/pipeline/pipeline_response.py +92 -0
- acceldata/models/api/pipeline/pipeline_run.py +136 -0
- acceldata/models/api/pipeline/pipeline_run_request.py +92 -0
- acceldata/models/api/pipeline/pipeline_runs_response.py +102 -0
- acceldata/models/api/pipeline/pipeline_summary.py +98 -0
- acceldata/models/api/pipeline/pipelines_listing_response.py +102 -0
- acceldata/models/api/pipeline/policy_summary.py +102 -0
- acceldata/models/api/pipeline/span.py +115 -0
- acceldata/models/api/pipeline/span_event.py +114 -0
- acceldata/models/api/pipeline/span_event_request.py +92 -0
- acceldata/models/api/pipeline/span_event_response.py +92 -0
- acceldata/models/api/pipeline/span_request.py +94 -0
- acceldata/models/api/pipeline/spans_response.py +96 -0
- acceldata/models/api/pipeline/tag.py +97 -0
- acceldata/models/sdk/__init__.py +0 -0
- acceldata/models/sdk/catalog/__init__.py +105 -0
- acceldata/models/sdk/catalog/asset_resource.py +112 -0
- acceldata/models/sdk/catalog/asset_source_type.py +59 -0
- acceldata/models/sdk/catalog/custom_asset_metadata.py +11 -0
- acceldata/models/sdk/catalog/datasource_resource.py +88 -0
- acceldata/models/sdk/catalog/executor.py +524 -0
- acceldata/models/sdk/catalog/policy_execution_request.py +114 -0
- acceldata/models/sdk/catalog/policy_execution_type.py +16 -0
- acceldata/models/sdk/catalog/policy_filter.py +94 -0
- acceldata/models/sdk/catalog/policy_rule_resources.py +388 -0
- acceldata/models/sdk/catalog/profile_request_resource.py +77 -0
- acceldata/models/sdk/catalog/profiling.py +82 -0
- acceldata/models/sdk/catalog/profiling_configuration_error.py +5 -0
- acceldata/models/sdk/pipeline/__init__.py +62 -0
- acceldata/models/sdk/pipeline/create_job_input.py +108 -0
- acceldata/models/sdk/pipeline/create_pipeline_input_request.py +72 -0
- acceldata/models/sdk/pipeline/events/__init__.py +5 -0
- acceldata/models/sdk/pipeline/events/generic_event.py +31 -0
- acceldata/models/sdk/pipeline/events/log_event.py +34 -0
- acceldata/models/sdk/pipeline/events/span_event.py +8 -0
- acceldata/models/sdk/pipeline/pipeline_resource.py +171 -0
- acceldata/models/sdk/pipeline/pipeline_run_input.py +84 -0
- acceldata/models/sdk/pipeline/pipeline_run_resource.py +208 -0
- acceldata/models/sdk/pipeline/pipeline_source_type.py +20 -0
- acceldata/models/sdk/pipeline/span_resource.py +327 -0
- acceldata/openapi_deserialization_patches.py +161 -0
- acceldata/openapi_repr_patches.py +62 -0
- acceldata/services/__init__.py +0 -0
- acceldata/services/api_timestamp.py +31 -0
- acceldata/services/asset_service.py +651 -0
- acceldata/services/datasource_service.py +120 -0
- acceldata/services/generic_service.py +132 -0
- acceldata/services/marker_config.py +232 -0
- acceldata/services/pipeline_big_decimal_api.py +102 -0
- acceldata/services/pipeline_response_parse.py +209 -0
- acceldata/services/pipeline_service.py +494 -0
- acceldata/services/rule_service.py +620 -0
- acceldata/urls/__init__.py +1 -0
- acceldata/urls/catalog_urls.py +137 -0
- acceldata/urls/pipeline_urls.py +55 -0
- acceldata/utils/__init__.py +6 -0
- acceldata/utils/datetime_utils.py +16 -0
- acceldata/utils/operation_ack.py +22 -0
- acceldata/utils/span_helpers.py +95 -0
- acceldata/utils/time_range_utils.py +90 -0
- acceldata_sdk_python-26.7.0.dist-info/METADATA +26 -0
- acceldata_sdk_python-26.7.0.dist-info/RECORD +303 -0
- acceldata_sdk_python-26.7.0.dist-info/WHEEL +5 -0
- acceldata_sdk_python-26.7.0.dist-info/licenses/LICENSE +22 -0
- acceldata_sdk_python-26.7.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,494 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import logging
|
|
4
|
+
from dataclasses import asdict, is_dataclass
|
|
5
|
+
from datetime import datetime
|
|
6
|
+
from enum import Enum
|
|
7
|
+
from typing import TYPE_CHECKING, Any, Optional
|
|
8
|
+
|
|
9
|
+
from acceldata.models.api.pipeline.pipeline_runs_response import PipelineRunsResponse
|
|
10
|
+
from pydantic import BaseModel, JsonValue
|
|
11
|
+
|
|
12
|
+
from acceldata.client.http_client import BaseHttpClient
|
|
13
|
+
from acceldata.exceptions import InvalidPipelineRunLookupError, PipelineRunNotFoundError
|
|
14
|
+
from acceldata.models.api.pipeline.node_response import NodeResponse
|
|
15
|
+
from acceldata.models.api.pipeline.pipeline_details_response import PipelineDetailsResponse
|
|
16
|
+
from acceldata.models.api.pipeline.pipeline_response import PipelineResponse
|
|
17
|
+
from acceldata.models.api.pipeline.pipeline import Pipeline
|
|
18
|
+
from acceldata.models.api.pipeline.pipeline_run import PipelineRun
|
|
19
|
+
from acceldata.models.api.pipeline.tag import Tag
|
|
20
|
+
from acceldata.models.api.pipeline.pipelines_listing_response import PipelinesListingResponse
|
|
21
|
+
from acceldata.models.api.pipeline.span import Span
|
|
22
|
+
from acceldata.models.api.pipeline.span_event import SpanEvent
|
|
23
|
+
from acceldata.models.api.pipeline.span_event_request import SpanEventRequest
|
|
24
|
+
from acceldata.models.api.pipeline.span_request import SpanRequest
|
|
25
|
+
from acceldata.models.api.pipeline.spans_response import SpansResponse
|
|
26
|
+
from acceldata.models.sdk.pipeline.create_pipeline_input_request import CreatePipelineInputRequest
|
|
27
|
+
from acceldata.models.sdk.pipeline.pipeline_run_input import PipelineRunResult, PipelineRunStatus
|
|
28
|
+
from acceldata.services.pipeline_response_parse import (
|
|
29
|
+
pipeline_response_from_api_dict,
|
|
30
|
+
span_from_api_dict,
|
|
31
|
+
span_request_from_api_dict,
|
|
32
|
+
spans_response_from_api_dict,
|
|
33
|
+
)
|
|
34
|
+
from acceldata.utils.operation_ack import ack_failure, ack_success
|
|
35
|
+
|
|
36
|
+
if TYPE_CHECKING:
|
|
37
|
+
from acceldata.models.sdk.pipeline.span_resource import SpanResource
|
|
38
|
+
|
|
39
|
+
logger = logging.getLogger("pipelineservice")
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def _sanitize_for_json(obj: Any) -> Any:
|
|
43
|
+
if obj is None:
|
|
44
|
+
return None
|
|
45
|
+
if isinstance(obj, Enum):
|
|
46
|
+
return obj.value
|
|
47
|
+
if isinstance(obj, datetime):
|
|
48
|
+
return obj.isoformat()
|
|
49
|
+
if isinstance(obj, dict):
|
|
50
|
+
return {str(k): _sanitize_for_json(v) for k, v in obj.items()}
|
|
51
|
+
if isinstance(obj, (list, tuple)):
|
|
52
|
+
return [_sanitize_for_json(x) for x in obj]
|
|
53
|
+
if isinstance(obj, (str, int, float, bool)):
|
|
54
|
+
return obj
|
|
55
|
+
if isinstance(obj, BaseModel):
|
|
56
|
+
if hasattr(obj, "model_dump"):
|
|
57
|
+
dumped = obj.model_dump(by_alias=True, exclude_none=True)
|
|
58
|
+
else:
|
|
59
|
+
dumped = obj.dict(by_alias=True, exclude_none=True)
|
|
60
|
+
return _sanitize_for_json(dumped)
|
|
61
|
+
if is_dataclass(obj):
|
|
62
|
+
return _sanitize_for_json(asdict(obj))
|
|
63
|
+
return obj
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
class PipelineService:
|
|
67
|
+
def __init__(self, http_client: BaseHttpClient) -> None:
|
|
68
|
+
self._client = http_client
|
|
69
|
+
self.logger = logger
|
|
70
|
+
|
|
71
|
+
def _convert_pipeline_to_dict(self, pipeline: Optional[CreatePipelineInputRequest]) -> dict[str, JsonValue]:
|
|
72
|
+
if isinstance(pipeline, dict):
|
|
73
|
+
return dict(pipeline)
|
|
74
|
+
if pipeline is None:
|
|
75
|
+
raise TypeError("create_pipeline_input_request is required")
|
|
76
|
+
# CreatePipelineInputRequest is a Pydantic BaseModel, not a dataclass — use to_dict().
|
|
77
|
+
if isinstance(pipeline, BaseModel):
|
|
78
|
+
outer = pipeline.to_dict()
|
|
79
|
+
inner = outer.get("pipeline")
|
|
80
|
+
if not isinstance(inner, dict):
|
|
81
|
+
raise TypeError(
|
|
82
|
+
"CreatePipelineInputRequest must serialize to a dict with a 'pipeline' object"
|
|
83
|
+
)
|
|
84
|
+
raw = _sanitize_for_json(inner)
|
|
85
|
+
elif is_dataclass(pipeline):
|
|
86
|
+
raw = _sanitize_for_json(asdict(pipeline))
|
|
87
|
+
else:
|
|
88
|
+
raise TypeError(
|
|
89
|
+
f"Unsupported pipeline request type: {type(pipeline).__name__}"
|
|
90
|
+
)
|
|
91
|
+
if not isinstance(raw, dict):
|
|
92
|
+
raise TypeError("Pipeline serialization must produce a JSON object")
|
|
93
|
+
return raw
|
|
94
|
+
|
|
95
|
+
def create_pipeline(self, create_pipeline_input_request: Optional[CreatePipelineInputRequest] = None,
|
|
96
|
+
**kwargs) -> PipelineResponse:
|
|
97
|
+
payload = self._convert_pipeline_to_dict(create_pipeline_input_request)
|
|
98
|
+
url = self._client.pipeline_urls.pipelines_root()
|
|
99
|
+
response = self._client._put(url, payload={"pipeline": payload})
|
|
100
|
+
if not isinstance(response, dict):
|
|
101
|
+
raise TypeError(f"Expected dict from create pipeline, got {type(response).__name__}")
|
|
102
|
+
p = response.get("pipeline")
|
|
103
|
+
if not isinstance(p, dict):
|
|
104
|
+
raise TypeError("Create pipeline response must include a 'pipeline' object")
|
|
105
|
+
out = pipeline_response_from_api_dict(response)
|
|
106
|
+
pid = out.pipeline.id if out.pipeline is not None else None
|
|
107
|
+
ack_success(self.logger, "create_pipeline", pipeline_id=pid)
|
|
108
|
+
return out
|
|
109
|
+
|
|
110
|
+
def update_pipeline(self, pipeline: Pipeline) -> PipelineResponse:
|
|
111
|
+
"""PUT ``/pipelines`` with a full :class:`~acceldata.models.api.pipeline.pipeline.Pipeline` body (must include ``id`` when updating)."""
|
|
112
|
+
if pipeline.id is None:
|
|
113
|
+
raise ValueError("Pipeline id is required to update a pipeline")
|
|
114
|
+
raw = _sanitize_for_json(pipeline.to_dict())
|
|
115
|
+
if not isinstance(raw, dict):
|
|
116
|
+
raise TypeError("Pipeline serialization must produce a JSON object")
|
|
117
|
+
url = self._client.pipeline_urls.pipelines_root()
|
|
118
|
+
response = self._client._put(url, payload={"pipeline": raw})
|
|
119
|
+
if not isinstance(response, dict):
|
|
120
|
+
raise TypeError(f"Expected dict from update pipeline, got {type(response).__name__}")
|
|
121
|
+
p = response.get("pipeline")
|
|
122
|
+
if not isinstance(p, dict):
|
|
123
|
+
raise TypeError("Update pipeline response must include a 'pipeline' object")
|
|
124
|
+
out = pipeline_response_from_api_dict(response)
|
|
125
|
+
pid = out.pipeline.id if out.pipeline is not None else None
|
|
126
|
+
ack_success(self.logger, "update_pipeline", pipeline_id=pid)
|
|
127
|
+
return out
|
|
128
|
+
|
|
129
|
+
def replace_pipeline_tags(
|
|
130
|
+
self, pipeline_identity: str | int, tags: list[Tag]
|
|
131
|
+
) -> PipelineResponse:
|
|
132
|
+
"""GET the pipeline by identity, replace its ``tags`` list, and PUT the full pipeline back."""
|
|
133
|
+
current = self.get_pipeline(str(pipeline_identity))
|
|
134
|
+
pl = current.pipeline
|
|
135
|
+
if pl is None:
|
|
136
|
+
raise TypeError("get_pipeline returned no pipeline object")
|
|
137
|
+
updated = pl.model_copy(update={"tags": list(tags)})
|
|
138
|
+
return self.update_pipeline(updated)
|
|
139
|
+
|
|
140
|
+
def delete_pipeline(self, pipeline_id: str | int) -> dict[str, JsonValue]:
|
|
141
|
+
url = self._client.pipeline_urls.pipeline_by_identity(pipeline_id)
|
|
142
|
+
response = self._client._delete(url)
|
|
143
|
+
ack_success(self.logger, "delete_pipeline", pipeline_id=pipeline_id)
|
|
144
|
+
if isinstance(response, dict):
|
|
145
|
+
return response
|
|
146
|
+
return {}
|
|
147
|
+
|
|
148
|
+
def create_job(self, job: dict[str, Any], pipeline_id: int) -> NodeResponse:
|
|
149
|
+
url = self._client.pipeline_urls.pipeline_jobs(pipeline_id)
|
|
150
|
+
response = self._client._put(url, payload=job)
|
|
151
|
+
if not isinstance(response, dict):
|
|
152
|
+
raise TypeError(f"Expected dict from create job, got {type(response).__name__}")
|
|
153
|
+
node = NodeResponse.from_dict(response)
|
|
154
|
+
job_uid = node.node.uid if node.node is not None else None
|
|
155
|
+
ack_success(self.logger, "create_job", pipeline_id=pipeline_id, job_uid=job_uid)
|
|
156
|
+
return node
|
|
157
|
+
|
|
158
|
+
def get_pipeline_run(
|
|
159
|
+
self,
|
|
160
|
+
pipeline_run_id: Optional[int] = None,
|
|
161
|
+
continuation_id: Optional[str] = None,
|
|
162
|
+
pipeline_id: Optional[int] = None,
|
|
163
|
+
) -> PipelineRun:
|
|
164
|
+
if pipeline_run_id is not None:
|
|
165
|
+
url = self._client.pipeline_urls.pipeline_run_by_id(pipeline_run_id)
|
|
166
|
+
response = self._client._get(url)
|
|
167
|
+
if not isinstance(response, dict):
|
|
168
|
+
raise TypeError(f"Expected dict from get pipeline run, got {type(response).__name__}")
|
|
169
|
+
r = response.get("run")
|
|
170
|
+
elif continuation_id is not None and pipeline_id is not None:
|
|
171
|
+
url = self._client.pipeline_urls.pipeline_runs(pipeline_id)
|
|
172
|
+
response = self._client._get(url, params={"continuationId": continuation_id})
|
|
173
|
+
if not isinstance(response, dict):
|
|
174
|
+
raise TypeError(f"Expected dict from pipeline runs listing, got {type(response).__name__}")
|
|
175
|
+
runs = response.get("runs") or []
|
|
176
|
+
if not isinstance(runs, list) or not runs:
|
|
177
|
+
ack_failure(
|
|
178
|
+
self.logger,
|
|
179
|
+
"get_pipeline_run",
|
|
180
|
+
"run_not_found",
|
|
181
|
+
continuation_id=continuation_id,
|
|
182
|
+
pipeline_id=pipeline_id,
|
|
183
|
+
)
|
|
184
|
+
raise PipelineRunNotFoundError(
|
|
185
|
+
(
|
|
186
|
+
f"No pipeline run found for continuation_id={continuation_id!r} on pipeline_id={pipeline_id}. "
|
|
187
|
+
"Confirm the continuation id matches the active run, or use get_latest_pipeline_run() "
|
|
188
|
+
"when a single latest run is sufficient."
|
|
189
|
+
),
|
|
190
|
+
continuation_id=continuation_id,
|
|
191
|
+
pipeline_id=pipeline_id,
|
|
192
|
+
)
|
|
193
|
+
r = runs[0]
|
|
194
|
+
else:
|
|
195
|
+
ack_failure(
|
|
196
|
+
self.logger,
|
|
197
|
+
"get_pipeline_run",
|
|
198
|
+
"invalid_lookup",
|
|
199
|
+
pipeline_run_id=pipeline_run_id,
|
|
200
|
+
continuation_id=continuation_id,
|
|
201
|
+
pipeline_id=pipeline_id,
|
|
202
|
+
)
|
|
203
|
+
raise InvalidPipelineRunLookupError(
|
|
204
|
+
"Provide pipeline_run_id, or both continuation_id and pipeline_id together."
|
|
205
|
+
)
|
|
206
|
+
if not isinstance(r, dict):
|
|
207
|
+
raise TypeError("Pipeline run response must include a 'run' object")
|
|
208
|
+
run = PipelineRun.from_dict(r)
|
|
209
|
+
ack_success(
|
|
210
|
+
self.logger,
|
|
211
|
+
"get_pipeline_run",
|
|
212
|
+
pipeline_run_id=run.id,
|
|
213
|
+
continuation_id=continuation_id,
|
|
214
|
+
)
|
|
215
|
+
return run
|
|
216
|
+
|
|
217
|
+
def get_latest_pipeline_run(self, pipeline_id: int) -> PipelineRun:
|
|
218
|
+
url = self._client.pipeline_urls.pipeline_latest_run(pipeline_id)
|
|
219
|
+
response = self._client._get(url)
|
|
220
|
+
if not isinstance(response, dict):
|
|
221
|
+
raise TypeError(f"Expected dict from latest pipeline run, got {type(response).__name__}")
|
|
222
|
+
r = response.get("run")
|
|
223
|
+
if not isinstance(r, dict):
|
|
224
|
+
raise TypeError("Latest pipeline run response must include a 'run' object")
|
|
225
|
+
run = PipelineRun.from_dict(r)
|
|
226
|
+
ack_success(self.logger, "get_latest_pipeline_run", pipeline_id=pipeline_id, pipeline_run_id=run.id)
|
|
227
|
+
return run
|
|
228
|
+
|
|
229
|
+
def get_pipeline_runs(self, pipeline_id: int) -> PipelineRunsResponse:
|
|
230
|
+
url = self._client.pipeline_urls.pipeline_runs(pipeline_id)
|
|
231
|
+
response = self._client._get(url)
|
|
232
|
+
if not isinstance(response, dict):
|
|
233
|
+
raise TypeError(f"Expected dict from pipeline runs, got {type(response).__name__}")
|
|
234
|
+
listing = PipelineRunsResponse.from_dict(response)
|
|
235
|
+
ack_success(self.logger, "get_pipeline_runs", pipeline_id=pipeline_id)
|
|
236
|
+
return listing
|
|
237
|
+
|
|
238
|
+
def create_pipeline_run(
|
|
239
|
+
self,
|
|
240
|
+
pipeline_id: int,
|
|
241
|
+
*,
|
|
242
|
+
context_data: Optional[dict[str, Any]] = None,
|
|
243
|
+
continuation_id: Optional[str] = None,
|
|
244
|
+
started_at: Optional[datetime] = None,
|
|
245
|
+
) -> PipelineRun:
|
|
246
|
+
run_inner: dict[str, Any] = {
|
|
247
|
+
"pipelineId": pipeline_id,
|
|
248
|
+
"status": PipelineRunStatus.STARTED.value,
|
|
249
|
+
}
|
|
250
|
+
if continuation_id is not None:
|
|
251
|
+
run_inner["continuationId"] = continuation_id
|
|
252
|
+
if context_data is not None:
|
|
253
|
+
run_inner["args"] = context_data
|
|
254
|
+
if started_at is not None:
|
|
255
|
+
run_inner["startedAt"] = started_at.isoformat()
|
|
256
|
+
payload = {"run": _sanitize_for_json(run_inner)}
|
|
257
|
+
url = self._client.pipeline_urls.pipeline_runs(pipeline_id)
|
|
258
|
+
response = self._client._post(url, payload=payload)
|
|
259
|
+
if not isinstance(response, dict):
|
|
260
|
+
raise TypeError(f"Expected dict from create pipeline run, got {type(response).__name__}")
|
|
261
|
+
r = response.get("run")
|
|
262
|
+
if not isinstance(r, dict):
|
|
263
|
+
raise TypeError("Create pipeline run response must include a 'run' object")
|
|
264
|
+
run = PipelineRun.from_dict(r)
|
|
265
|
+
ack_success(
|
|
266
|
+
self.logger,
|
|
267
|
+
"create_pipeline_run",
|
|
268
|
+
pipeline_id=pipeline_id,
|
|
269
|
+
pipeline_run_id=run.id,
|
|
270
|
+
continuation_id=continuation_id,
|
|
271
|
+
)
|
|
272
|
+
return run
|
|
273
|
+
|
|
274
|
+
def update_pipeline_run(
|
|
275
|
+
self,
|
|
276
|
+
pipeline_run_id: int,
|
|
277
|
+
*,
|
|
278
|
+
pipeline_id: int,
|
|
279
|
+
result: PipelineRunResult,
|
|
280
|
+
status: PipelineRunStatus,
|
|
281
|
+
version_id: Optional[int] = None,
|
|
282
|
+
context_data: Optional[dict[str, Any]] = None,
|
|
283
|
+
continuation_id: Optional[str] = None,
|
|
284
|
+
started_at: Optional[datetime] = None,
|
|
285
|
+
finished_at: Optional[datetime] = None,
|
|
286
|
+
) -> PipelineRun:
|
|
287
|
+
|
|
288
|
+
run_inner: dict[str, Any] = {
|
|
289
|
+
"pipelineId": pipeline_id,
|
|
290
|
+
"result": result.value,
|
|
291
|
+
"status": status.value,
|
|
292
|
+
}
|
|
293
|
+
if version_id is not None:
|
|
294
|
+
run_inner["versionId"] = version_id
|
|
295
|
+
if continuation_id is not None:
|
|
296
|
+
run_inner["continuationId"] = continuation_id
|
|
297
|
+
if context_data is not None:
|
|
298
|
+
run_inner["args"] = context_data
|
|
299
|
+
if started_at is not None:
|
|
300
|
+
run_inner["startedAt"] = started_at.isoformat()
|
|
301
|
+
if finished_at is not None:
|
|
302
|
+
run_inner["finishedAt"] = finished_at.isoformat()
|
|
303
|
+
payload = {"run": _sanitize_for_json(run_inner)}
|
|
304
|
+
url = self._client.pipeline_urls.pipeline_run_by_id(pipeline_run_id)
|
|
305
|
+
response = self._client._put(url, payload=payload)
|
|
306
|
+
if not isinstance(response, dict):
|
|
307
|
+
raise TypeError(f"Expected dict from update pipeline run, got {type(response).__name__}")
|
|
308
|
+
r = response.get("run")
|
|
309
|
+
if not isinstance(r, dict):
|
|
310
|
+
raise TypeError("Update pipeline run response must include a 'run' object")
|
|
311
|
+
run = PipelineRun.from_dict(r)
|
|
312
|
+
ack_success(
|
|
313
|
+
self.logger,
|
|
314
|
+
"update_pipeline_run",
|
|
315
|
+
pipeline_run_id=pipeline_run_id,
|
|
316
|
+
pipeline_id=pipeline_id,
|
|
317
|
+
result=result.value,
|
|
318
|
+
status=status.value,
|
|
319
|
+
)
|
|
320
|
+
return run
|
|
321
|
+
|
|
322
|
+
def create_span(
|
|
323
|
+
self,
|
|
324
|
+
pipeline_run_id: int,
|
|
325
|
+
payload: dict[str, JsonValue],
|
|
326
|
+
) -> Span:
|
|
327
|
+
url = self._client.pipeline_urls.pipeline_run_spans(pipeline_run_id)
|
|
328
|
+
response = self._client._post(url, payload=payload)
|
|
329
|
+
if not isinstance(response, dict):
|
|
330
|
+
raise TypeError(f"Expected dict from create span, got {type(response).__name__}")
|
|
331
|
+
s = response.get("span")
|
|
332
|
+
if not isinstance(s, dict):
|
|
333
|
+
raise TypeError("Create span response must include a 'span' object")
|
|
334
|
+
res = span_from_api_dict(s)
|
|
335
|
+
if res is None:
|
|
336
|
+
raise TypeError("Could not parse span from create span response")
|
|
337
|
+
ack_success(
|
|
338
|
+
self.logger,
|
|
339
|
+
"create_span",
|
|
340
|
+
pipeline_run_id=pipeline_run_id,
|
|
341
|
+
span_uid=res.uid,
|
|
342
|
+
span_id=res.id,
|
|
343
|
+
)
|
|
344
|
+
return res
|
|
345
|
+
|
|
346
|
+
def get_child_spans(self, span_id: int) -> list[Span]:
|
|
347
|
+
url = self._client.pipeline_urls.span_child_spans(span_id)
|
|
348
|
+
response = self._client._get(url)
|
|
349
|
+
if not isinstance(response, dict):
|
|
350
|
+
raise TypeError(f"Expected dict from child spans, got {type(response).__name__}")
|
|
351
|
+
raw = response.get("childSpans") or []
|
|
352
|
+
if not isinstance(raw, list):
|
|
353
|
+
raise TypeError("childSpans must be a list when present")
|
|
354
|
+
out: list[Span] = []
|
|
355
|
+
for item in raw:
|
|
356
|
+
if not isinstance(item, dict):
|
|
357
|
+
raise TypeError("Each child span must be an object")
|
|
358
|
+
s = span_from_api_dict(item)
|
|
359
|
+
if s is not None:
|
|
360
|
+
out.append(s)
|
|
361
|
+
ack_success(self.logger, "get_child_spans", span_id=span_id, count=len(out))
|
|
362
|
+
return out
|
|
363
|
+
|
|
364
|
+
def create_span_event(self, request: SpanEventRequest) -> SpanEvent:
|
|
365
|
+
if request.event.span_id is None:
|
|
366
|
+
raise ValueError("To create a span event, spanId is required.")
|
|
367
|
+
url = self._client.pipeline_urls.span_events(request.event.span_id)
|
|
368
|
+
payload = _sanitize_for_json(request.to_dict())
|
|
369
|
+
self.logger.info(f"create span event payload: {payload}")
|
|
370
|
+
if not isinstance(payload, dict):
|
|
371
|
+
raise TypeError("Span event payload must serialize to a JSON object")
|
|
372
|
+
response = self._client._post(url, payload=payload)
|
|
373
|
+
if not isinstance(response, dict):
|
|
374
|
+
raise TypeError(f"Expected dict from create span event, got {type(response).__name__}")
|
|
375
|
+
ev = response.get("event")
|
|
376
|
+
if not isinstance(ev, dict):
|
|
377
|
+
raise TypeError("Create span event response must include an 'event' object")
|
|
378
|
+
out = SpanEvent.from_dict(ev)
|
|
379
|
+
if out is None:
|
|
380
|
+
raise TypeError("Could not parse span event from response")
|
|
381
|
+
ack_success(
|
|
382
|
+
self.logger,
|
|
383
|
+
"create_span_event",
|
|
384
|
+
span_id=request.event.span_id,
|
|
385
|
+
event_uid=request.event.event_uid,
|
|
386
|
+
)
|
|
387
|
+
return out
|
|
388
|
+
|
|
389
|
+
# get pipeline by uid or id
|
|
390
|
+
def get_pipeline(self, pipeline_identity: str) -> PipelineResponse:
|
|
391
|
+
"""
|
|
392
|
+
Description:
|
|
393
|
+
To get an existing pipeline from the catalog
|
|
394
|
+
:param pipeline_identity: uid or id of the pipeline
|
|
395
|
+
:return:(Pipeline) pipeline class instance
|
|
396
|
+
"""
|
|
397
|
+
url = self._client.pipeline_urls.pipeline_by_identity(pipeline_identity)
|
|
398
|
+
response = self._client._get(url)
|
|
399
|
+
if not isinstance(response, dict):
|
|
400
|
+
raise TypeError(f"Expected dict from get pipeline, got {type(response).__name__}")
|
|
401
|
+
out = pipeline_response_from_api_dict(response)
|
|
402
|
+
pid = out.pipeline.id if out.pipeline is not None else None
|
|
403
|
+
ack_success(self.logger, "get_pipeline", pipeline_identity=pipeline_identity, pipeline_id=pid)
|
|
404
|
+
return out
|
|
405
|
+
|
|
406
|
+
def get_root_span(self, pipeline_run_id: int) -> Optional[SpanResource]:
|
|
407
|
+
from acceldata.models.sdk.pipeline.span_resource import wrap_fetched_span
|
|
408
|
+
|
|
409
|
+
url = self._client.pipeline_urls.pipeline_run_spans(pipeline_run_id)
|
|
410
|
+
response = self._client._get(url, params={"onlyRootSpan": "true"})
|
|
411
|
+
if not isinstance(response, dict):
|
|
412
|
+
raise TypeError(f"Expected dict from root span, got {type(response).__name__}")
|
|
413
|
+
spans = response.get("spans") or []
|
|
414
|
+
if not spans:
|
|
415
|
+
# Some deployments omit root when ``onlyRootSpan`` is set; fall back to full listing.
|
|
416
|
+
full = self._client._get(url)
|
|
417
|
+
if not isinstance(full, dict):
|
|
418
|
+
raise TypeError(f"Expected dict from spans listing, got {type(full).__name__}")
|
|
419
|
+
for item in full.get("spans") or []:
|
|
420
|
+
if not isinstance(item, dict):
|
|
421
|
+
raise TypeError("Each span must be an object")
|
|
422
|
+
if item.get("parentSpanId") is not None:
|
|
423
|
+
continue
|
|
424
|
+
span = span_from_api_dict(item)
|
|
425
|
+
if span is not None:
|
|
426
|
+
return wrap_fetched_span(self, span)
|
|
427
|
+
return None
|
|
428
|
+
first = spans[0]
|
|
429
|
+
if not isinstance(first, dict):
|
|
430
|
+
raise TypeError("spans[0] must be an object")
|
|
431
|
+
span = span_from_api_dict(first)
|
|
432
|
+
if span is None:
|
|
433
|
+
raise TypeError("Could not parse root span from response")
|
|
434
|
+
return wrap_fetched_span(self, span)
|
|
435
|
+
|
|
436
|
+
def get_pipelines(self) -> PipelinesListingResponse:
|
|
437
|
+
"""
|
|
438
|
+
Description:
|
|
439
|
+
To get all pipelines from ADOC
|
|
440
|
+
:return:(List[PipelineListingInfo]) PipelineListingInfo class instance
|
|
441
|
+
"""
|
|
442
|
+
url = self._client.pipeline_urls.pipelines_summary()
|
|
443
|
+
response = self._client._get(url)
|
|
444
|
+
if not isinstance(response, dict):
|
|
445
|
+
raise TypeError(f"Expected dict from list pipelines, got {type(response).__name__}")
|
|
446
|
+
listing = PipelinesListingResponse.from_dict(response)
|
|
447
|
+
ack_success(self.logger, "get_pipelines")
|
|
448
|
+
return listing
|
|
449
|
+
|
|
450
|
+
def get_run_details(self, pipeline_id: int, version_id: int) -> PipelineDetailsResponse:
|
|
451
|
+
url = self._client.pipeline_urls.pipeline_graph_by_version_id(pipeline_id, version_id)
|
|
452
|
+
response = self._client._get(url)
|
|
453
|
+
if not isinstance(response, dict):
|
|
454
|
+
raise TypeError(f"Expected dict from get_run_details, got {type(response).__name__}")
|
|
455
|
+
details = PipelineDetailsResponse.from_dict(response)
|
|
456
|
+
ack_success(self.logger, "get_run_details", pipeline_id=pipeline_id, version_id=version_id)
|
|
457
|
+
return details
|
|
458
|
+
|
|
459
|
+
def get_spans(self, pipeline_run_id: int) -> SpansResponse:
|
|
460
|
+
"""
|
|
461
|
+
Description:
|
|
462
|
+
List spans for the pipeline run.
|
|
463
|
+
:return: :class:`~acceldata.models.api.pipeline.spans_response.SpansResponse`
|
|
464
|
+
"""
|
|
465
|
+
url = self._client.pipeline_urls.pipeline_run_spans(pipeline_run_id=pipeline_run_id)
|
|
466
|
+
response = self._client._get(url=url)
|
|
467
|
+
if not isinstance(response, dict):
|
|
468
|
+
raise TypeError(f"Expected dict from get_spans, got {type(response).__name__}")
|
|
469
|
+
spans = spans_response_from_api_dict(response)
|
|
470
|
+
ack_success(self.logger, "get_spans", pipeline_run_id=pipeline_run_id)
|
|
471
|
+
return spans
|
|
472
|
+
|
|
473
|
+
def get_span(self, pipeline_run_id: int, span_identity: str) -> Span:
|
|
474
|
+
url = self._client.pipeline_urls.pipeline_run_span_by_uid(pipeline_run_id=pipeline_run_id,
|
|
475
|
+
span_identity=span_identity)
|
|
476
|
+
response = self._client._get(url=url)
|
|
477
|
+
if not isinstance(response, dict):
|
|
478
|
+
raise TypeError(f"Expected dict from get_span, got {type(response).__name__}")
|
|
479
|
+
# API returns SpanRequest: { "span": { ... }, "associatedJobUids": [...] }
|
|
480
|
+
if isinstance(response.get("span"), dict):
|
|
481
|
+
envelope = span_request_from_api_dict(response)
|
|
482
|
+
if envelope is None or envelope.span is None:
|
|
483
|
+
raise TypeError("get_span response missing span")
|
|
484
|
+
span = envelope.span
|
|
485
|
+
else:
|
|
486
|
+
span = span_from_api_dict(response)
|
|
487
|
+
ack_success(
|
|
488
|
+
self.logger,
|
|
489
|
+
"get_span",
|
|
490
|
+
pipeline_run_id=pipeline_run_id,
|
|
491
|
+
span_identity=span_identity,
|
|
492
|
+
span_id=span.id,
|
|
493
|
+
)
|
|
494
|
+
return span
|