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,120 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import logging
|
|
4
|
+
from typing import Any
|
|
5
|
+
|
|
6
|
+
from acceldata.client.http_client import BaseHttpClient
|
|
7
|
+
from acceldata.client.transient_retry import (
|
|
8
|
+
RetryConfig,
|
|
9
|
+
effective_transient_retry,
|
|
10
|
+
transient_retry_call,
|
|
11
|
+
)
|
|
12
|
+
from acceldata.models.api.catalog.assembly import Assembly
|
|
13
|
+
from acceldata.models.api.catalog.crawler_action_response import CrawlerActionResponse
|
|
14
|
+
from acceldata.models.api.catalog.crawler_status_response import CrawlerStatusResponse
|
|
15
|
+
from acceldata.models.sdk.catalog.asset_source_type import AssetSourceType
|
|
16
|
+
from acceldata.models.sdk.catalog.datasource_resource import DatasourceResource
|
|
17
|
+
|
|
18
|
+
logger = logging.getLogger("sdk")
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class DataSourceService:
|
|
22
|
+
def __init__(self, http_client: BaseHttpClient) -> None:
|
|
23
|
+
self._client = http_client
|
|
24
|
+
|
|
25
|
+
def start_crawler(
|
|
26
|
+
self,
|
|
27
|
+
datasource_name: str,
|
|
28
|
+
*,
|
|
29
|
+
transient_retry: RetryConfig | None = None,
|
|
30
|
+
) -> CrawlerActionResponse:
|
|
31
|
+
"""POST to start a crawler run (single request)."""
|
|
32
|
+
cfg = effective_transient_retry(transient_retry, None)
|
|
33
|
+
|
|
34
|
+
def _do() -> CrawlerActionResponse:
|
|
35
|
+
if datasource_name is None or datasource_name == "":
|
|
36
|
+
raise ValueError("datasource name is required")
|
|
37
|
+
url = self._client.catalog_urls.crawl_datasource(datasource_name=datasource_name)
|
|
38
|
+
response = self._client._post(url=url, payload={})
|
|
39
|
+
if isinstance(response, dict):
|
|
40
|
+
data = response.get("data")
|
|
41
|
+
if isinstance(data, dict):
|
|
42
|
+
started = CrawlerActionResponse.from_dict(data)
|
|
43
|
+
if started is None:
|
|
44
|
+
raise TypeError("crawler start returned empty data")
|
|
45
|
+
return started
|
|
46
|
+
raise TypeError(f"Expected dict from crawler start, got {type(response).__name__}")
|
|
47
|
+
|
|
48
|
+
return transient_retry_call(_do, cfg, logger=logger, operation_name="start_crawler")
|
|
49
|
+
|
|
50
|
+
def get_crawler_status(
|
|
51
|
+
self,
|
|
52
|
+
datasource_name: str,
|
|
53
|
+
*,
|
|
54
|
+
transient_retry: RetryConfig | None = None,
|
|
55
|
+
) -> CrawlerStatusResponse:
|
|
56
|
+
cfg = effective_transient_retry(transient_retry, None)
|
|
57
|
+
|
|
58
|
+
def _do() -> CrawlerStatusResponse:
|
|
59
|
+
if datasource_name is None or datasource_name == "":
|
|
60
|
+
raise ValueError("datasource name is required")
|
|
61
|
+
url = self._client.catalog_urls.crawl_datasource(datasource_name=datasource_name)
|
|
62
|
+
response = self._client._get(url=url)
|
|
63
|
+
logger.debug("Crawler response: %s", response)
|
|
64
|
+
if isinstance(response, dict):
|
|
65
|
+
data = response.get("data")
|
|
66
|
+
if isinstance(data, dict):
|
|
67
|
+
return CrawlerStatusResponse.from_dict(data)
|
|
68
|
+
raise TypeError(f"Expected dict from crawler status, got {type(response).__name__}")
|
|
69
|
+
|
|
70
|
+
return transient_retry_call(_do, cfg, logger=logger, operation_name="get_crawler_status")
|
|
71
|
+
|
|
72
|
+
def get_datasource(
|
|
73
|
+
self,
|
|
74
|
+
assembly_identifier: Any,
|
|
75
|
+
properties: bool = False,
|
|
76
|
+
) -> DatasourceResource:
|
|
77
|
+
"""
|
|
78
|
+
Find a datasource by name or numeric id in the catalog.
|
|
79
|
+
|
|
80
|
+
:param assembly_identifier: Datasource name or id in the catalog.
|
|
81
|
+
:param properties: When True, include assembly property templates in the response.
|
|
82
|
+
"""
|
|
83
|
+
url = self._client.catalog_urls.assembly(assembly_identifier, properties=properties)
|
|
84
|
+
response = self._client._get(url=url)
|
|
85
|
+
if not isinstance(response, dict):
|
|
86
|
+
raise TypeError(f"Expected dict from assemblies GET, got {type(response).__name__}")
|
|
87
|
+
raw = response.get("data")
|
|
88
|
+
logger.debug("assemblies response: %s", raw)
|
|
89
|
+
if raw is None:
|
|
90
|
+
raise ValueError("Datasource not found.")
|
|
91
|
+
model = Assembly.from_dict(raw)
|
|
92
|
+
return DatasourceResource(self, model)
|
|
93
|
+
|
|
94
|
+
def get_datasources(
|
|
95
|
+
self,
|
|
96
|
+
source_type: AssetSourceType | None = None,
|
|
97
|
+
) -> list[DatasourceResource]:
|
|
98
|
+
"""
|
|
99
|
+
Find datasources by type in the catalog.
|
|
100
|
+
|
|
101
|
+
:param source_type: Catalog source type filter (optional). Passed as ``sourceType`` query parameter.
|
|
102
|
+
:return: List of datasource resources.
|
|
103
|
+
"""
|
|
104
|
+
url = self._client.catalog_urls.datasources()
|
|
105
|
+
params: dict[str, str] | None = None
|
|
106
|
+
if source_type is not None:
|
|
107
|
+
params = {"sourceType": source_type.name}
|
|
108
|
+
response = self._client._get(url=url, params=params)
|
|
109
|
+
if not isinstance(response, dict):
|
|
110
|
+
raise TypeError(f"Expected dict from assemblies list, got {type(response).__name__}")
|
|
111
|
+
raw = response.get("data")
|
|
112
|
+
if raw is None:
|
|
113
|
+
raw = []
|
|
114
|
+
if not isinstance(raw, list):
|
|
115
|
+
raise TypeError(f"Expected list in data, got {type(raw).__name__}")
|
|
116
|
+
return [
|
|
117
|
+
DatasourceResource(self, Assembly.from_dict(item))
|
|
118
|
+
for item in raw
|
|
119
|
+
if isinstance(item, dict)
|
|
120
|
+
]
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import logging
|
|
4
|
+
from typing import Any
|
|
5
|
+
|
|
6
|
+
from acceldata.client.http_client import BaseHttpClient
|
|
7
|
+
from acceldata.models.api.catalog.analytics_pipeline import AnalyticsPipeline
|
|
8
|
+
from acceldata.models.api.catalog.asset_type import AssetType
|
|
9
|
+
from acceldata.models.api.catalog.connection_type import ConnectionType
|
|
10
|
+
from acceldata.models.api.catalog.source_type import SourceType
|
|
11
|
+
|
|
12
|
+
logger = logging.getLogger("generic_service")
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def _asset_types_list_from_response(response: dict[str, Any]) -> list[Any]:
|
|
16
|
+
for key in ("data", "assetTypes"):
|
|
17
|
+
raw = response.get(key)
|
|
18
|
+
if raw is None:
|
|
19
|
+
continue
|
|
20
|
+
if isinstance(raw, (list, tuple)):
|
|
21
|
+
return list(raw)
|
|
22
|
+
raise KeyError(
|
|
23
|
+
"asset-types response must include 'data' or 'assetTypes' with a list"
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def _connection_types_list_from_response(response: dict[str, Any]) -> list[Any]:
|
|
28
|
+
for key in ("data", "connectionTypes"):
|
|
29
|
+
raw = response.get(key)
|
|
30
|
+
if raw is None:
|
|
31
|
+
continue
|
|
32
|
+
if isinstance(raw, (list, tuple)):
|
|
33
|
+
return list(raw)
|
|
34
|
+
raise KeyError(
|
|
35
|
+
"connection-types response must include 'data' or 'connectionTypes' with a list"
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def _source_types_list_from_response(response: dict[str, Any]) -> list[Any]:
|
|
40
|
+
for key in ("data", "sourceTypes"):
|
|
41
|
+
raw = response.get(key)
|
|
42
|
+
if raw is None:
|
|
43
|
+
continue
|
|
44
|
+
if isinstance(raw, (list, tuple)):
|
|
45
|
+
return list(raw)
|
|
46
|
+
raise KeyError(
|
|
47
|
+
"source-types response must include 'data' or 'sourceTypes' with a list"
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
class GenericService:
|
|
52
|
+
def __init__(self, http_client: BaseHttpClient) -> None:
|
|
53
|
+
self._client = http_client
|
|
54
|
+
|
|
55
|
+
def get_asset_types(self) -> list[AssetType]:
|
|
56
|
+
url = self._client.catalog_urls.asset_types()
|
|
57
|
+
response = self._client._get(url=url)
|
|
58
|
+
logger.debug("get_asset_types response: %s", response)
|
|
59
|
+
if not isinstance(response, dict):
|
|
60
|
+
raise TypeError(
|
|
61
|
+
"asset-types response must be a JSON object, "
|
|
62
|
+
f"got {type(response).__name__}"
|
|
63
|
+
)
|
|
64
|
+
raw = _asset_types_list_from_response(response)
|
|
65
|
+
result: list[AssetType] = []
|
|
66
|
+
for item in raw:
|
|
67
|
+
if not isinstance(item, dict):
|
|
68
|
+
raise TypeError(
|
|
69
|
+
"each asset type must be a JSON object, "
|
|
70
|
+
f"got {type(item).__name__}"
|
|
71
|
+
)
|
|
72
|
+
result.append(AssetType.from_dict(item))
|
|
73
|
+
return result
|
|
74
|
+
|
|
75
|
+
def get_connection_types(self) -> list[ConnectionType]:
|
|
76
|
+
url = self._client.catalog_urls.connection_types()
|
|
77
|
+
response = self._client._get(url=url)
|
|
78
|
+
if not isinstance(response, dict):
|
|
79
|
+
raise TypeError(
|
|
80
|
+
"connection-types response must be a JSON object, "
|
|
81
|
+
f"got {type(response).__name__}"
|
|
82
|
+
)
|
|
83
|
+
raw = _connection_types_list_from_response(response)
|
|
84
|
+
result: list[ConnectionType] = []
|
|
85
|
+
for item in raw:
|
|
86
|
+
if not isinstance(item, dict):
|
|
87
|
+
raise TypeError(
|
|
88
|
+
"each connection type must be a JSON object, "
|
|
89
|
+
f"got {type(item).__name__}"
|
|
90
|
+
)
|
|
91
|
+
result.append(ConnectionType.from_dict(item))
|
|
92
|
+
return result
|
|
93
|
+
|
|
94
|
+
def get_source_types(self) -> list[SourceType]:
|
|
95
|
+
"""
|
|
96
|
+
Description:
|
|
97
|
+
list all sourcetypes in ADOC catalog
|
|
98
|
+
:return: (SourceType) list of sourcetype
|
|
99
|
+
"""
|
|
100
|
+
url = self._client.catalog_urls.source_types()
|
|
101
|
+
response = self._client._get(url=url)
|
|
102
|
+
raw = _source_types_list_from_response(response)
|
|
103
|
+
result: list[SourceType] = []
|
|
104
|
+
for item in raw:
|
|
105
|
+
if not isinstance(item, dict):
|
|
106
|
+
raise TypeError(
|
|
107
|
+
"each source type must be a JSON object, "
|
|
108
|
+
f"got {type(item).__name__}"
|
|
109
|
+
)
|
|
110
|
+
result.append(SourceType.from_dict(item))
|
|
111
|
+
return result
|
|
112
|
+
|
|
113
|
+
def get_analysis_pipeline(self, pipeline_identifier: str | int) -> AnalyticsPipeline:
|
|
114
|
+
"""GET catalog ``/analytics-pipelines/{id|name}`` and parse the ``pipeline`` object."""
|
|
115
|
+
url = self._client.catalog_urls.analytics_pipeline(pipeline_identifier)
|
|
116
|
+
response = self._client._get(url=url)
|
|
117
|
+
if not isinstance(response, dict):
|
|
118
|
+
raise TypeError(
|
|
119
|
+
"analytics-pipelines response must be a JSON object, "
|
|
120
|
+
f"got {type(response).__name__}"
|
|
121
|
+
)
|
|
122
|
+
inner = response.get("pipeline")
|
|
123
|
+
if inner is None:
|
|
124
|
+
raise KeyError(
|
|
125
|
+
"analytics-pipelines response must include a 'pipeline' object"
|
|
126
|
+
)
|
|
127
|
+
if not isinstance(inner, dict):
|
|
128
|
+
raise TypeError(
|
|
129
|
+
"pipeline must be a JSON object, "
|
|
130
|
+
f"got {type(inner).__name__}"
|
|
131
|
+
)
|
|
132
|
+
return AnalyticsPipeline.from_dict(inner)
|
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
"""Catalog ``markerConfig`` wire ``type`` values and helpers (service / SDK layer).
|
|
2
|
+
|
|
3
|
+
The OpenAPI ``MarkerConfig`` schema is a discriminated union. Each branch payload
|
|
4
|
+
must include a ``type`` string matching
|
|
5
|
+
``#/components/schemas/MarkerConfig`` discriminator mapping. Use the
|
|
6
|
+
``*_marker_config`` functions (names mirror the generated classes, e.g.
|
|
7
|
+
:func:`bounds_date_time_marker_config` for :class:`BoundsDateTimeMarkerConfig`) so
|
|
8
|
+
callers do not set that field by hand; for low-level access see
|
|
9
|
+
:func:`marker_type_for` and :data:`API_TYPE_BY_MARKER_CLASS`, and
|
|
10
|
+
:func:`as_marker_config` to normalize values before they are sent on API requests.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
from __future__ import annotations
|
|
14
|
+
|
|
15
|
+
from types import MappingProxyType
|
|
16
|
+
from typing import Any, Optional, Type, TypeVar, Union, cast
|
|
17
|
+
|
|
18
|
+
from acceldata.models.api.catalog.bounds_date_time_marker_config import (
|
|
19
|
+
BoundsDateTimeMarkerConfig,
|
|
20
|
+
)
|
|
21
|
+
from acceldata.models.api.catalog.bounds_file_event_marker_config import (
|
|
22
|
+
BoundsFileEventMarkerConfig,
|
|
23
|
+
)
|
|
24
|
+
from acceldata.models.api.catalog.bounds_id_marker_config import BoundsIdMarkerConfig
|
|
25
|
+
from acceldata.models.api.catalog.date_partitioning_marker_config import (
|
|
26
|
+
DatePartitioningMarkerConfig,
|
|
27
|
+
)
|
|
28
|
+
from acceldata.models.api.catalog.date_time_marker_config import DateTimeMarkerConfig
|
|
29
|
+
from acceldata.models.api.catalog.file_marker_config import FileMarkerConfig
|
|
30
|
+
from acceldata.models.api.catalog.id_marker_config import IdMarkerConfig
|
|
31
|
+
from acceldata.models.api.catalog.marker_config import MarkerConfig
|
|
32
|
+
from acceldata.models.api.catalog.marker_config_fallback import MarkerConfigFallback
|
|
33
|
+
from acceldata.models.api.catalog.offset_based_marker_config import (
|
|
34
|
+
OffsetBasedMarkerConfig,
|
|
35
|
+
)
|
|
36
|
+
from acceldata.models.api.catalog.pub_sub_lookback_marker_config import (
|
|
37
|
+
PubSubLookbackMarkerConfig,
|
|
38
|
+
)
|
|
39
|
+
from acceldata.models.api.catalog.pub_sub_timestamp_marker_config import (
|
|
40
|
+
PubSubTimestampMarkerConfig,
|
|
41
|
+
)
|
|
42
|
+
from acceldata.models.api.catalog.timestamp_based_marker_config import (
|
|
43
|
+
TimestampBasedMarkerConfig,
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
# Catalog MarkerConfig oneOf: discriminator propertyName "type" -> $ref
|
|
47
|
+
# (see components/schemas/MarkerConfig in the cleaned spec).
|
|
48
|
+
_WIRE: dict[Type[object], str] = {
|
|
49
|
+
BoundsDateTimeMarkerConfig: "boundDateTime",
|
|
50
|
+
BoundsFileEventMarkerConfig: "boundFileEvent",
|
|
51
|
+
BoundsIdMarkerConfig: "bound",
|
|
52
|
+
DatePartitioningMarkerConfig: "date_partitioned",
|
|
53
|
+
DateTimeMarkerConfig: "datetime",
|
|
54
|
+
FileMarkerConfig: "file",
|
|
55
|
+
IdMarkerConfig: "id",
|
|
56
|
+
OffsetBasedMarkerConfig: "offset",
|
|
57
|
+
PubSubLookbackMarkerConfig: "pubsub_lookback",
|
|
58
|
+
PubSubTimestampMarkerConfig: "pubsub_timestamp",
|
|
59
|
+
TimestampBasedMarkerConfig: "timestamp",
|
|
60
|
+
MarkerConfigFallback: "MarkerConfigFallback",
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
# Read-only: generated class -> wire ``type`` (discriminator) string
|
|
64
|
+
API_TYPE_BY_MARKER_CLASS: Any = MappingProxyType(_WIRE)
|
|
65
|
+
|
|
66
|
+
MMarker = TypeVar("MMarker", bound=object)
|
|
67
|
+
|
|
68
|
+
# Union of all branch models + wrapper for inputs (profiling, and other call sites).
|
|
69
|
+
MarkerConfigInput = Union[
|
|
70
|
+
MarkerConfig,
|
|
71
|
+
BoundsDateTimeMarkerConfig,
|
|
72
|
+
BoundsFileEventMarkerConfig,
|
|
73
|
+
BoundsIdMarkerConfig,
|
|
74
|
+
DatePartitioningMarkerConfig,
|
|
75
|
+
DateTimeMarkerConfig,
|
|
76
|
+
FileMarkerConfig,
|
|
77
|
+
IdMarkerConfig,
|
|
78
|
+
OffsetBasedMarkerConfig,
|
|
79
|
+
PubSubLookbackMarkerConfig,
|
|
80
|
+
PubSubTimestampMarkerConfig,
|
|
81
|
+
TimestampBasedMarkerConfig,
|
|
82
|
+
MarkerConfigFallback,
|
|
83
|
+
]
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def marker_type_for(model_type: type) -> str:
|
|
87
|
+
"""Return the API ``type`` string for a given generated *MarkerConfig* class."""
|
|
88
|
+
try:
|
|
89
|
+
return _WIRE[model_type]
|
|
90
|
+
except KeyError as e: # pragma: no cover - guard for SDK misuse
|
|
91
|
+
raise TypeError(
|
|
92
|
+
f"Not a known MarkerConfig branch class: {model_type!r}"
|
|
93
|
+
) from e
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def _build_marker(model_cls: type[MMarker], /, **kwargs: Any) -> MMarker:
|
|
97
|
+
if model_cls not in _WIRE:
|
|
98
|
+
raise TypeError(
|
|
99
|
+
f"Unknown marker model class: {model_cls!r}. "
|
|
100
|
+
"Use a known *MarkerConfig* branch (see API_TYPE_BY_MARKER_CLASS keys)."
|
|
101
|
+
)
|
|
102
|
+
if model_cls is MarkerConfigFallback:
|
|
103
|
+
if "type" not in kwargs:
|
|
104
|
+
raise TypeError(
|
|
105
|
+
"MarkerConfigFallback requires an explicit 'type' "
|
|
106
|
+
"(unknown backend name or the mapping key \"MarkerConfigFallback\")."
|
|
107
|
+
)
|
|
108
|
+
return model_cls(**kwargs) # type: ignore[call-arg, no-any-return]
|
|
109
|
+
wire = _WIRE[cast(Type[object], model_cls)]
|
|
110
|
+
return model_cls(**{**kwargs, "type": wire}) # type: ignore[call-arg, no-any-return]
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
def date_time_marker_config(**kwargs: Any) -> DateTimeMarkerConfig:
|
|
114
|
+
"""Build a :class:`DateTimeMarkerConfig` with the correct API ``type``."""
|
|
115
|
+
return _build_marker(DateTimeMarkerConfig, **kwargs)
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
def bounds_date_time_marker_config(**kwargs: Any) -> BoundsDateTimeMarkerConfig:
|
|
119
|
+
"""Build a :class:`BoundsDateTimeMarkerConfig` with the correct API ``type``."""
|
|
120
|
+
return _build_marker(BoundsDateTimeMarkerConfig, **kwargs)
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
def bounds_file_event_marker_config(**kwargs: Any) -> BoundsFileEventMarkerConfig:
|
|
124
|
+
"""Build a :class:`BoundsFileEventMarkerConfig` with the correct API ``type``."""
|
|
125
|
+
return _build_marker(BoundsFileEventMarkerConfig, **kwargs)
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
def date_partitioning_marker_config(**kwargs: Any) -> DatePartitioningMarkerConfig:
|
|
129
|
+
"""Build a :class:`DatePartitioningMarkerConfig` with the correct API ``type``."""
|
|
130
|
+
return _build_marker(DatePartitioningMarkerConfig, **kwargs)
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
def file_marker_config(**kwargs: Any) -> FileMarkerConfig:
|
|
134
|
+
"""Build a :class:`FileMarkerConfig` with the correct API ``type``."""
|
|
135
|
+
return _build_marker(FileMarkerConfig, **kwargs)
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
def offset_based_marker_config(**kwargs: Any) -> OffsetBasedMarkerConfig:
|
|
139
|
+
"""Build an :class:`OffsetBasedMarkerConfig` with the correct API ``type``."""
|
|
140
|
+
return _build_marker(OffsetBasedMarkerConfig, **kwargs)
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
def pub_sub_lookback_marker_config(**kwargs: Any) -> PubSubLookbackMarkerConfig:
|
|
144
|
+
"""Build a :class:`PubSubLookbackMarkerConfig` with the correct API ``type``."""
|
|
145
|
+
return _build_marker(PubSubLookbackMarkerConfig, **kwargs)
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
def pub_sub_timestamp_marker_config(**kwargs: Any) -> PubSubTimestampMarkerConfig:
|
|
149
|
+
"""Build a :class:`PubSubTimestampMarkerConfig` with the correct API ``type``."""
|
|
150
|
+
return _build_marker(PubSubTimestampMarkerConfig, **kwargs)
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
def timestamp_based_marker_config(**kwargs: Any) -> TimestampBasedMarkerConfig:
|
|
154
|
+
"""Build a :class:`TimestampBasedMarkerConfig` with the correct API ``type``."""
|
|
155
|
+
return _build_marker(TimestampBasedMarkerConfig, **kwargs)
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
def marker_config_fallback(**kwargs: Any) -> MarkerConfigFallback:
|
|
159
|
+
"""Build a :class:`MarkerConfigFallback`; you must pass ``type=`` in ``kwargs``."""
|
|
160
|
+
return _build_marker(MarkerConfigFallback, **kwargs)
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
def id_marker_config(
|
|
164
|
+
*,
|
|
165
|
+
id_column_name: str,
|
|
166
|
+
base_asset_id: int | None = None,
|
|
167
|
+
initial_offset: int | None = None,
|
|
168
|
+
) -> IdMarkerConfig:
|
|
169
|
+
"""Build an :class:`IdMarkerConfig` with the correct API ``type`` (``"id"``)."""
|
|
170
|
+
mk: dict[str, Any] = {"id_column_name": id_column_name}
|
|
171
|
+
if base_asset_id is not None:
|
|
172
|
+
mk["base_asset_id"] = base_asset_id
|
|
173
|
+
if initial_offset is not None:
|
|
174
|
+
mk["initial_offset"] = initial_offset
|
|
175
|
+
return _build_marker(IdMarkerConfig, **mk)
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
def bounds_id_marker_config(
|
|
179
|
+
*,
|
|
180
|
+
id_column_name: str,
|
|
181
|
+
from_id: int | None = None,
|
|
182
|
+
to_id: int | None = None,
|
|
183
|
+
base_asset_id: int | None = None,
|
|
184
|
+
) -> BoundsIdMarkerConfig:
|
|
185
|
+
"""Build a :class:`BoundsIdMarkerConfig` with the correct API ``type`` (``"bound"``).
|
|
186
|
+
|
|
187
|
+
For **incremental** profiling on an id column, use :func:`id_marker_config` instead.
|
|
188
|
+
"""
|
|
189
|
+
mk: dict[str, Any] = {"id_column_name": id_column_name}
|
|
190
|
+
if base_asset_id is not None:
|
|
191
|
+
mk["base_asset_id"] = base_asset_id
|
|
192
|
+
if from_id is not None:
|
|
193
|
+
mk["from_id"] = from_id
|
|
194
|
+
if to_id is not None:
|
|
195
|
+
mk["to_id"] = to_id
|
|
196
|
+
return _build_marker(BoundsIdMarkerConfig, **mk)
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
def _apply_canonical_type_if_known(instance: object) -> object:
|
|
200
|
+
t = type(instance)
|
|
201
|
+
if t is MarkerConfigFallback:
|
|
202
|
+
return instance
|
|
203
|
+
wire = _WIRE.get(t)
|
|
204
|
+
if wire is None or getattr(instance, "type", None) == wire:
|
|
205
|
+
return instance
|
|
206
|
+
m = instance
|
|
207
|
+
return m.model_copy(update={"type": wire})
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
def as_marker_config(value: MarkerConfigInput, /) -> MarkerConfig:
|
|
211
|
+
"""Normalize a payload and wrap in :class:`MarkerConfig` (public catalog union type)."""
|
|
212
|
+
if isinstance(value, MarkerConfig):
|
|
213
|
+
inner = value.actual_instance
|
|
214
|
+
if inner is None:
|
|
215
|
+
return value
|
|
216
|
+
updated = _apply_canonical_type_if_known(inner)
|
|
217
|
+
if updated is inner:
|
|
218
|
+
return value
|
|
219
|
+
return MarkerConfig(actual_instance=updated)
|
|
220
|
+
if type(value) in _WIRE and value is not None:
|
|
221
|
+
updated = _apply_canonical_type_if_known(value)
|
|
222
|
+
return MarkerConfig(actual_instance=updated) # type: ignore[arg-type]
|
|
223
|
+
raise TypeError(f"Unsupported marker config value type: {type(value)!r}")
|
|
224
|
+
|
|
225
|
+
|
|
226
|
+
def prepare_marker_config_for_request(
|
|
227
|
+
value: Optional[MarkerConfigInput],
|
|
228
|
+
) -> Optional[MarkerConfig]:
|
|
229
|
+
"""Apply discriminator defaults and return the catalog :class:`MarkerConfig` for HTTP bodies."""
|
|
230
|
+
if value is None:
|
|
231
|
+
return None
|
|
232
|
+
return as_marker_config(value)
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
"""Parse pipeline API BigDecimal payloads: structured dicts or plain JSON numbers (non-generated helper)."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from decimal import Decimal, InvalidOperation
|
|
6
|
+
from typing import TYPE_CHECKING, Any, Optional
|
|
7
|
+
|
|
8
|
+
from acceldata.models.api.pipeline.big_integer import BigInteger
|
|
9
|
+
|
|
10
|
+
if TYPE_CHECKING:
|
|
11
|
+
from acceldata.models.api.pipeline.big_decimal import BigDecimal
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def _decimal_to_unscaled_scale_unsigned(abs_d: Decimal) -> tuple[int, int]:
|
|
15
|
+
if abs_d == 0:
|
|
16
|
+
return 0, 0
|
|
17
|
+
t = abs_d.as_tuple()
|
|
18
|
+
digits_int = int("".join(str(x) for x in t.digits) or "0")
|
|
19
|
+
exp = t.exponent
|
|
20
|
+
if exp >= 0:
|
|
21
|
+
return digits_int * (10**exp), 0
|
|
22
|
+
return digits_int, -exp
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def big_decimal_from_json_scalar(val: Any) -> BigDecimal:
|
|
26
|
+
"""Build pipeline BigDecimal when the API returns a JSON number or decimal string."""
|
|
27
|
+
from acceldata.models.api.pipeline.big_decimal import BigDecimal
|
|
28
|
+
|
|
29
|
+
if isinstance(val, str):
|
|
30
|
+
try:
|
|
31
|
+
d = Decimal(val.strip())
|
|
32
|
+
except InvalidOperation as exc:
|
|
33
|
+
raise TypeError(f"BigDecimal value is not a valid decimal string: {val!r}") from exc
|
|
34
|
+
elif isinstance(val, bool):
|
|
35
|
+
raise TypeError("BigDecimal value must be a number, not bool")
|
|
36
|
+
elif isinstance(val, int):
|
|
37
|
+
d = Decimal(val)
|
|
38
|
+
elif isinstance(val, float):
|
|
39
|
+
d = Decimal(str(val))
|
|
40
|
+
else:
|
|
41
|
+
raise TypeError(f"BigDecimal value has unsupported type {type(val).__name__}")
|
|
42
|
+
|
|
43
|
+
if not d.is_finite():
|
|
44
|
+
raise TypeError("BigDecimal value must be a finite decimal")
|
|
45
|
+
|
|
46
|
+
sign = -1 if d < 0 else (0 if d == 0 else 1)
|
|
47
|
+
d_abs = abs(d)
|
|
48
|
+
unscaled_mag, scale = _decimal_to_unscaled_scale_unsigned(d_abs)
|
|
49
|
+
int_compact = sign * unscaled_mag
|
|
50
|
+
|
|
51
|
+
if sign == 0:
|
|
52
|
+
bi = BigInteger.model_validate(
|
|
53
|
+
{
|
|
54
|
+
"signum": 0,
|
|
55
|
+
"mag": [],
|
|
56
|
+
"bitCountPlusOne": 1,
|
|
57
|
+
"bitLengthPlusOne": 1,
|
|
58
|
+
"lowestSetBitPlusTwo": 2,
|
|
59
|
+
"firstNonzeroIntNumPlusTwo": 2,
|
|
60
|
+
}
|
|
61
|
+
)
|
|
62
|
+
prec = 1
|
|
63
|
+
s_cache = "0"
|
|
64
|
+
else:
|
|
65
|
+
bl = max(abs(unscaled_mag).bit_length(), 1)
|
|
66
|
+
bi = BigInteger.model_validate(
|
|
67
|
+
{
|
|
68
|
+
"signum": sign,
|
|
69
|
+
"mag": [{"value": unscaled_mag}],
|
|
70
|
+
"bitCountPlusOne": bl + 1,
|
|
71
|
+
"bitLengthPlusOne": bl + 1,
|
|
72
|
+
"lowestSetBitPlusTwo": 2,
|
|
73
|
+
"firstNonzeroIntNumPlusTwo": 2,
|
|
74
|
+
}
|
|
75
|
+
)
|
|
76
|
+
prec = max(len(str(abs(int_compact))), scale + 1 if scale else 1)
|
|
77
|
+
s_cache = format(d, "f")
|
|
78
|
+
|
|
79
|
+
return BigDecimal.model_validate(
|
|
80
|
+
{
|
|
81
|
+
"intVal": bi,
|
|
82
|
+
"scale": scale,
|
|
83
|
+
"precision": prec,
|
|
84
|
+
"stringCache": s_cache,
|
|
85
|
+
"intCompact": int_compact,
|
|
86
|
+
}
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def parse_optional_big_decimal_from_api(raw: Any) -> Optional[BigDecimal]:
|
|
91
|
+
"""Accept structured BigDecimal JSON, or a plain number/string from the API."""
|
|
92
|
+
from acceldata.models.api.pipeline.big_decimal import BigDecimal
|
|
93
|
+
|
|
94
|
+
if raw is None:
|
|
95
|
+
return None
|
|
96
|
+
if isinstance(raw, BigDecimal):
|
|
97
|
+
return raw
|
|
98
|
+
if isinstance(raw, dict):
|
|
99
|
+
return BigDecimal.from_dict(raw)
|
|
100
|
+
if isinstance(raw, (int, float, str)):
|
|
101
|
+
return big_decimal_from_json_scalar(raw)
|
|
102
|
+
return BigDecimal.from_dict(raw)
|