airbyte-cdk 6.45.10__py3-none-any.whl → 6.46.0.post4.dev14712712756__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 (31) hide show
  1. airbyte_cdk/cli/__init__.py +9 -1
  2. airbyte_cdk/cli/airbyte_cdk/__init__.py +86 -0
  3. airbyte_cdk/cli/airbyte_cdk/_connector.py +179 -0
  4. airbyte_cdk/cli/airbyte_cdk/_image.py +95 -0
  5. airbyte_cdk/cli/airbyte_cdk/_manifest.py +24 -0
  6. airbyte_cdk/cli/airbyte_cdk/_secrets.py +150 -0
  7. airbyte_cdk/cli/airbyte_cdk/_util.py +43 -0
  8. airbyte_cdk/cli/airbyte_cdk/_version.py +13 -0
  9. airbyte_cdk/connector_builder/connector_builder_handler.py +10 -0
  10. airbyte_cdk/models/connector_metadata.py +97 -0
  11. airbyte_cdk/sources/declarative/declarative_component_schema.yaml +114 -81
  12. airbyte_cdk/sources/declarative/manifest_declarative_source.py +122 -45
  13. airbyte_cdk/sources/declarative/models/declarative_component_schema.py +90 -78
  14. airbyte_cdk/sources/declarative/parsers/custom_exceptions.py +9 -0
  15. airbyte_cdk/sources/declarative/parsers/manifest_component_transformer.py +2 -2
  16. airbyte_cdk/sources/declarative/parsers/manifest_normalizer.py +462 -0
  17. airbyte_cdk/sources/declarative/parsers/manifest_reference_resolver.py +2 -2
  18. airbyte_cdk/sources/declarative/parsers/model_to_component_factory.py +64 -33
  19. airbyte_cdk/sources/declarative/requesters/query_properties/query_properties.py +0 -10
  20. airbyte_cdk/test/standard_tests/connector_base.py +51 -25
  21. airbyte_cdk/test/standard_tests/declarative_sources.py +3 -1
  22. airbyte_cdk/test/standard_tests/test_resources.py +69 -0
  23. airbyte_cdk/test/standard_tests/util.py +79 -0
  24. airbyte_cdk/utils/docker.py +337 -0
  25. airbyte_cdk/utils/docker_image_templates.py +101 -0
  26. {airbyte_cdk-6.45.10.dist-info → airbyte_cdk-6.46.0.post4.dev14712712756.dist-info}/METADATA +6 -1
  27. {airbyte_cdk-6.45.10.dist-info → airbyte_cdk-6.46.0.post4.dev14712712756.dist-info}/RECORD +31 -18
  28. {airbyte_cdk-6.45.10.dist-info → airbyte_cdk-6.46.0.post4.dev14712712756.dist-info}/entry_points.txt +1 -0
  29. {airbyte_cdk-6.45.10.dist-info → airbyte_cdk-6.46.0.post4.dev14712712756.dist-info}/LICENSE.txt +0 -0
  30. {airbyte_cdk-6.45.10.dist-info → airbyte_cdk-6.46.0.post4.dev14712712756.dist-info}/LICENSE_SHORT +0 -0
  31. {airbyte_cdk-6.45.10.dist-info → airbyte_cdk-6.46.0.post4.dev14712712756.dist-info}/WHEEL +0 -0
@@ -417,15 +417,18 @@ class JwtAuthenticator(BaseModel):
417
417
  ...,
418
418
  description="Secret used to sign the JSON web token.",
419
419
  examples=["{{ config['secret_key'] }}"],
420
+ title="Secret Key",
420
421
  )
421
422
  base64_encode_secret_key: Optional[bool] = Field(
422
423
  False,
423
424
  description='When set to true, the secret key will be base64 encoded prior to being encoded as part of the JWT. Only set to "true" when required by the API.',
425
+ title="Base64-encode Secret Key",
424
426
  )
425
427
  algorithm: Algorithm = Field(
426
428
  ...,
427
429
  description="Algorithm used to sign the JSON web token.",
428
430
  examples=["ES256", "HS256", "RS256", "{{ config['algorithm'] }}"],
431
+ title="Algorithm",
429
432
  )
430
433
  token_duration: Optional[int] = Field(
431
434
  1200,
@@ -880,20 +883,17 @@ class FlattenFields(BaseModel):
880
883
 
881
884
 
882
885
  class KeyTransformation(BaseModel):
883
- prefix: Optional[Union[str, None]] = Field(
886
+ type: Literal["KeyTransformation"]
887
+ prefix: Optional[str] = Field(
884
888
  None,
885
889
  description="Prefix to add for object keys. If not provided original keys remain unchanged.",
886
- examples=[
887
- "flattened_",
888
- ],
890
+ examples=["flattened_"],
889
891
  title="Key Prefix",
890
892
  )
891
- suffix: Optional[Union[str, None]] = Field(
893
+ suffix: Optional[str] = Field(
892
894
  None,
893
895
  description="Suffix to add for object keys. If not provided original keys remain unchanged.",
894
- examples=[
895
- "_flattened",
896
- ],
896
+ examples=["_flattened"],
897
897
  title="Key Suffix",
898
898
  )
899
899
 
@@ -916,7 +916,7 @@ class DpathFlattenFields(BaseModel):
916
916
  description="Whether to replace the origin record or not. Default is False.",
917
917
  title="Replace Origin Record",
918
918
  )
919
- key_transformation: Optional[Union[KeyTransformation, None]] = Field(
919
+ key_transformation: Optional[KeyTransformation] = Field(
920
920
  None,
921
921
  description="Transformation for object keys. If not provided, original key will be used.",
922
922
  title="Key transformation",
@@ -1260,13 +1260,14 @@ class RecordFilter(BaseModel):
1260
1260
  "{{ record['created_at'] >= stream_interval['start_time'] }}",
1261
1261
  "{{ record.status in ['active', 'expired'] }}",
1262
1262
  ],
1263
+ title="Condition",
1263
1264
  )
1264
1265
  parameters: Optional[Dict[str, Any]] = Field(None, alias="$parameters")
1265
1266
 
1266
1267
 
1267
1268
  class SchemaNormalization(Enum):
1268
- None_ = "None"
1269
1269
  Default = "Default"
1270
+ None_ = "None"
1270
1271
 
1271
1272
 
1272
1273
  class RemoveFields(BaseModel):
@@ -1802,14 +1803,18 @@ class DefaultErrorHandler(BaseModel):
1802
1803
  class DefaultPaginator(BaseModel):
1803
1804
  type: Literal["DefaultPaginator"]
1804
1805
  pagination_strategy: Union[
1805
- CursorPagination, CustomPaginationStrategy, OffsetIncrement, PageIncrement
1806
+ PageIncrement, OffsetIncrement, CursorPagination, CustomPaginationStrategy
1806
1807
  ] = Field(
1807
1808
  ...,
1808
1809
  description="Strategy defining how records are paginated.",
1809
1810
  title="Pagination Strategy",
1810
1811
  )
1811
- page_size_option: Optional[RequestOption] = None
1812
- page_token_option: Optional[Union[RequestOption, RequestPath]] = None
1812
+ page_size_option: Optional[RequestOption] = Field(
1813
+ None, title="Inject Page Size Into Outgoing HTTP Request"
1814
+ )
1815
+ page_token_option: Optional[Union[RequestOption, RequestPath]] = Field(
1816
+ None, title="Inject Page Token Into Outgoing HTTP Request"
1817
+ )
1813
1818
  parameters: Optional[Dict[str, Any]] = Field(None, alias="$parameters")
1814
1819
 
1815
1820
 
@@ -1850,20 +1855,21 @@ class ListPartitionRouter(BaseModel):
1850
1855
 
1851
1856
  class RecordSelector(BaseModel):
1852
1857
  type: Literal["RecordSelector"]
1853
- extractor: Union[CustomRecordExtractor, DpathExtractor]
1854
- record_filter: Optional[Union[CustomRecordFilter, RecordFilter]] = Field(
1858
+ extractor: Union[DpathExtractor, CustomRecordExtractor]
1859
+ record_filter: Optional[Union[RecordFilter, CustomRecordFilter]] = Field(
1855
1860
  None,
1856
1861
  description="Responsible for filtering records to be emitted by the Source.",
1857
1862
  title="Record Filter",
1858
1863
  )
1859
1864
  schema_normalization: Optional[Union[SchemaNormalization, CustomSchemaNormalization]] = Field(
1860
- SchemaNormalization.None_,
1865
+ None,
1861
1866
  description="Responsible for normalization according to the schema.",
1862
1867
  title="Schema Normalization",
1863
1868
  )
1864
1869
  transform_before_filtering: Optional[bool] = Field(
1865
- False,
1870
+ None,
1866
1871
  description="If true, transformation will be applied before record filtering.",
1872
+ title="Transform Before Filtering",
1867
1873
  )
1868
1874
  parameters: Optional[Dict[str, Any]] = Field(None, alias="$parameters")
1869
1875
 
@@ -2096,26 +2102,26 @@ class DeclarativeStream(BaseModel):
2096
2102
  extra = Extra.allow
2097
2103
 
2098
2104
  type: Literal["DeclarativeStream"]
2099
- retriever: Union[AsyncRetriever, CustomRetriever, SimpleRetriever] = Field(
2105
+ name: Optional[str] = Field("", description="The stream name.", example=["Users"], title="Name")
2106
+ retriever: Union[SimpleRetriever, AsyncRetriever, CustomRetriever] = Field(
2100
2107
  ...,
2101
2108
  description="Component used to coordinate how records are extracted across stream slices and request pages.",
2102
2109
  title="Retriever",
2103
2110
  )
2104
2111
  incremental_sync: Optional[
2105
- Union[CustomIncrementalSync, DatetimeBasedCursor, IncrementingCountCursor]
2112
+ Union[DatetimeBasedCursor, IncrementingCountCursor, CustomIncrementalSync]
2106
2113
  ] = Field(
2107
2114
  None,
2108
2115
  description="Component used to fetch data incrementally based on a time field in the data.",
2109
2116
  title="Incremental Sync",
2110
2117
  )
2111
- name: Optional[str] = Field("", description="The stream name.", example=["Users"], title="Name")
2112
2118
  primary_key: Optional[PrimaryKey] = Field(
2113
2119
  "", description="The primary key of the stream.", title="Primary Key"
2114
2120
  )
2115
2121
  schema_loader: Optional[
2116
2122
  Union[
2117
- DynamicSchemaLoader,
2118
2123
  InlineSchemaLoader,
2124
+ DynamicSchemaLoader,
2119
2125
  JsonFileSchemaLoader,
2120
2126
  CustomSchemaLoader,
2121
2127
  ]
@@ -2205,7 +2211,7 @@ class HttpRequester(BaseModel):
2205
2211
  type: Literal["HttpRequester"]
2206
2212
  url_base: str = Field(
2207
2213
  ...,
2208
- description="Base URL of the API source. Do not put sensitive information (e.g. API tokens) into this field - Use the Authentication component for this.",
2214
+ description="The Base URL of the API source. Do not put sensitive information (e.g. API tokens) into this field - Use the Authentication component for this.",
2209
2215
  examples=[
2210
2216
  "https://connect.squareup.com/v2",
2211
2217
  "{{ config['base_url'] or 'https://app.posthog.com'}}/api",
@@ -2216,7 +2222,7 @@ class HttpRequester(BaseModel):
2216
2222
  )
2217
2223
  path: Optional[str] = Field(
2218
2224
  None,
2219
- description="Path the specific API endpoint that this stream represents. Do not put sensitive information (e.g. API tokens) into this field - Use the Authentication component for this.",
2225
+ description="The Path the specific API endpoint that this stream represents. Do not put sensitive information (e.g. API tokens) into this field - Use the Authentication component for this.",
2220
2226
  examples=[
2221
2227
  "/products",
2222
2228
  "/quotes/{{ stream_partition['id'] }}/quote_line_groups",
@@ -2224,38 +2230,36 @@ class HttpRequester(BaseModel):
2224
2230
  ],
2225
2231
  title="URL Path",
2226
2232
  )
2233
+ http_method: Optional[HttpMethod] = Field(
2234
+ HttpMethod.GET,
2235
+ description="The HTTP method used to fetch data from the source (can be GET or POST).",
2236
+ examples=["GET", "POST"],
2237
+ title="HTTP Method",
2238
+ )
2227
2239
  authenticator: Optional[
2228
2240
  Union[
2241
+ NoAuth,
2229
2242
  ApiKeyAuthenticator,
2230
2243
  BasicHttpAuthenticator,
2231
2244
  BearerAuthenticator,
2232
- CustomAuthenticator,
2233
2245
  OAuthAuthenticator,
2234
2246
  JwtAuthenticator,
2235
- NoAuth,
2236
2247
  SessionTokenAuthenticator,
2237
- LegacySessionTokenAuthenticator,
2238
2248
  SelectiveAuthenticator,
2249
+ CustomAuthenticator,
2250
+ LegacySessionTokenAuthenticator,
2239
2251
  ]
2240
2252
  ] = Field(
2241
2253
  None,
2242
2254
  description="Authentication method to use for requests sent to the API.",
2243
2255
  title="Authenticator",
2244
2256
  )
2245
- error_handler: Optional[
2246
- Union[DefaultErrorHandler, CustomErrorHandler, CompositeErrorHandler]
2247
- ] = Field(
2257
+ fetch_properties_from_endpoint: Optional[PropertiesFromEndpoint] = Field(
2248
2258
  None,
2249
- description="Error handler component that defines how to handle errors.",
2250
- title="Error Handler",
2251
- )
2252
- http_method: Optional[HttpMethod] = Field(
2253
- HttpMethod.GET,
2254
- description="The HTTP method used to fetch data from the source (can be GET or POST).",
2255
- examples=["GET", "POST"],
2256
- title="HTTP Method",
2259
+ description="Allows for retrieving a dynamic set of properties from an API endpoint which can be injected into outbound request using the stream_partition.extra_fields.",
2260
+ title="Fetch Properties from Endpoint",
2257
2261
  )
2258
- request_body_data: Optional[Union[str, Dict[str, str]]] = Field(
2262
+ request_body_data: Optional[Union[Dict[str, str], str]] = Field(
2259
2263
  None,
2260
2264
  description="Specifies how to populate the body of the request with a non-JSON payload. Plain text will be sent as is, whereas objects will be converted to a urlencoded form.",
2261
2265
  examples=[
@@ -2263,7 +2267,7 @@ class HttpRequester(BaseModel):
2263
2267
  ],
2264
2268
  title="Request Body Payload (Non-JSON)",
2265
2269
  )
2266
- request_body_json: Optional[Union[str, Dict[str, Any]]] = Field(
2270
+ request_body_json: Optional[Union[Dict[str, Any], str]] = Field(
2267
2271
  None,
2268
2272
  description="Specifies how to populate the body of the request with a JSON payload. Can contain nested objects.",
2269
2273
  examples=[
@@ -2273,13 +2277,13 @@ class HttpRequester(BaseModel):
2273
2277
  ],
2274
2278
  title="Request Body JSON Payload",
2275
2279
  )
2276
- request_headers: Optional[Union[str, Dict[str, str]]] = Field(
2280
+ request_headers: Optional[Union[Dict[str, str], str]] = Field(
2277
2281
  None,
2278
2282
  description="Return any non-auth headers. Authentication headers will overwrite any overlapping headers returned from this method.",
2279
2283
  examples=[{"Output-Format": "JSON"}, {"Version": "{{ config['version'] }}"}],
2280
2284
  title="Request Headers",
2281
2285
  )
2282
- request_parameters: Optional[Union[str, Dict[str, Union[str, Any]]]] = Field(
2286
+ request_parameters: Optional[Union[Dict[str, Union[str, QueryProperties]], str]] = Field(
2283
2287
  None,
2284
2288
  description="Specifies the query parameters that should be set on an outgoing HTTP request given the inputs.",
2285
2289
  examples=[
@@ -2292,6 +2296,13 @@ class HttpRequester(BaseModel):
2292
2296
  ],
2293
2297
  title="Query Parameters",
2294
2298
  )
2299
+ error_handler: Optional[
2300
+ Union[DefaultErrorHandler, CompositeErrorHandler, CustomErrorHandler]
2301
+ ] = Field(
2302
+ None,
2303
+ description="Error handler component that defines how to handle errors.",
2304
+ title="Error Handler",
2305
+ )
2295
2306
  use_cache: Optional[bool] = Field(
2296
2307
  False,
2297
2308
  description="Enables stream requests caching. This field is automatically set by the CDK.",
@@ -2409,25 +2420,41 @@ class StateDelegatingStream(BaseModel):
2409
2420
  full_refresh_stream: DeclarativeStream = Field(
2410
2421
  ...,
2411
2422
  description="Component used to coordinate how records are extracted across stream slices and request pages when the state is empty or not provided.",
2412
- title="Retriever",
2423
+ title="Full Refresh Stream",
2413
2424
  )
2414
2425
  incremental_stream: DeclarativeStream = Field(
2415
2426
  ...,
2416
2427
  description="Component used to coordinate how records are extracted across stream slices and request pages when the state provided.",
2417
- title="Retriever",
2428
+ title="Incremental Stream",
2418
2429
  )
2419
2430
  parameters: Optional[Dict[str, Any]] = Field(None, alias="$parameters")
2420
2431
 
2421
2432
 
2422
2433
  class SimpleRetriever(BaseModel):
2423
2434
  type: Literal["SimpleRetriever"]
2424
- record_selector: RecordSelector = Field(
2435
+ requester: Union[HttpRequester, CustomRequester] = Field(
2425
2436
  ...,
2426
- description="Component that describes how to extract records from a HTTP response.",
2437
+ description="Requester component that describes how to prepare HTTP requests to send to the source API.",
2427
2438
  )
2428
- requester: Union[CustomRequester, HttpRequester] = Field(
2439
+ decoder: Optional[
2440
+ Union[
2441
+ CsvDecoder,
2442
+ GzipDecoder,
2443
+ JsonDecoder,
2444
+ JsonlDecoder,
2445
+ IterableDecoder,
2446
+ XmlDecoder,
2447
+ ZipfileDecoder,
2448
+ CustomDecoder,
2449
+ ]
2450
+ ] = Field(
2451
+ None,
2452
+ description="Component decoding the response so records can be extracted.",
2453
+ title="Decoder",
2454
+ )
2455
+ record_selector: RecordSelector = Field(
2429
2456
  ...,
2430
- description="Requester component that describes how to prepare HTTP requests to send to the source API.",
2457
+ description="Component that describes how to extract records from a HTTP response.",
2431
2458
  )
2432
2459
  paginator: Optional[Union[DefaultPaginator, NoPagination]] = Field(
2433
2460
  None,
@@ -2439,16 +2466,16 @@ class SimpleRetriever(BaseModel):
2439
2466
  )
2440
2467
  partition_router: Optional[
2441
2468
  Union[
2442
- CustomPartitionRouter,
2443
2469
  ListPartitionRouter,
2444
2470
  SubstreamPartitionRouter,
2445
2471
  GroupingPartitionRouter,
2472
+ CustomPartitionRouter,
2446
2473
  List[
2447
2474
  Union[
2448
- CustomPartitionRouter,
2449
2475
  ListPartitionRouter,
2450
2476
  SubstreamPartitionRouter,
2451
2477
  GroupingPartitionRouter,
2478
+ CustomPartitionRouter,
2452
2479
  ]
2453
2480
  ],
2454
2481
  ]
@@ -2457,22 +2484,6 @@ class SimpleRetriever(BaseModel):
2457
2484
  description="PartitionRouter component that describes how to partition the stream, enabling incremental syncs and checkpointing.",
2458
2485
  title="Partition Router",
2459
2486
  )
2460
- decoder: Optional[
2461
- Union[
2462
- CustomDecoder,
2463
- CsvDecoder,
2464
- GzipDecoder,
2465
- JsonDecoder,
2466
- JsonlDecoder,
2467
- IterableDecoder,
2468
- XmlDecoder,
2469
- ZipfileDecoder,
2470
- ]
2471
- ] = Field(
2472
- None,
2473
- description="Component decoding the response so records can be extracted.",
2474
- title="Decoder",
2475
- )
2476
2487
  parameters: Optional[Dict[str, Any]] = Field(None, alias="$parameters")
2477
2488
 
2478
2489
 
@@ -2485,21 +2496,21 @@ class AsyncRetriever(BaseModel):
2485
2496
  status_mapping: AsyncJobStatusMap = Field(
2486
2497
  ..., description="Async Job Status to Airbyte CDK Async Job Status mapping."
2487
2498
  )
2488
- status_extractor: Union[CustomRecordExtractor, DpathExtractor] = Field(
2499
+ status_extractor: Union[DpathExtractor, CustomRecordExtractor] = Field(
2489
2500
  ..., description="Responsible for fetching the actual status of the async job."
2490
2501
  )
2491
- download_target_extractor: Union[CustomRecordExtractor, DpathExtractor] = Field(
2502
+ download_target_extractor: Union[DpathExtractor, CustomRecordExtractor] = Field(
2492
2503
  ...,
2493
2504
  description="Responsible for fetching the final result `urls` provided by the completed / finished / ready async job.",
2494
2505
  )
2495
2506
  download_extractor: Optional[
2496
- Union[CustomRecordExtractor, DpathExtractor, ResponseToFileExtractor]
2507
+ Union[DpathExtractor, CustomRecordExtractor, ResponseToFileExtractor]
2497
2508
  ] = Field(None, description="Responsible for fetching the records from provided urls.")
2498
- creation_requester: Union[CustomRequester, HttpRequester] = Field(
2509
+ creation_requester: Union[HttpRequester, CustomRequester] = Field(
2499
2510
  ...,
2500
2511
  description="Requester component that describes how to prepare HTTP requests to send to the source API to create the async server-side job.",
2501
2512
  )
2502
- polling_requester: Union[CustomRequester, HttpRequester] = Field(
2513
+ polling_requester: Union[HttpRequester, CustomRequester] = Field(
2503
2514
  ...,
2504
2515
  description="Requester component that describes how to prepare HTTP requests to send to the source API to fetch the status of the running async job.",
2505
2516
  )
@@ -2507,11 +2518,11 @@ class AsyncRetriever(BaseModel):
2507
2518
  None,
2508
2519
  description="The time in minutes after which the single Async Job should be considered as Timed Out.",
2509
2520
  )
2510
- download_target_requester: Optional[Union[CustomRequester, HttpRequester]] = Field(
2521
+ download_target_requester: Optional[Union[HttpRequester, CustomRequester]] = Field(
2511
2522
  None,
2512
2523
  description="Requester component that describes how to prepare HTTP requests to send to the source API to extract the url from polling response by the completed async job.",
2513
2524
  )
2514
- download_requester: Union[CustomRequester, HttpRequester] = Field(
2525
+ download_requester: Union[HttpRequester, CustomRequester] = Field(
2515
2526
  ...,
2516
2527
  description="Requester component that describes how to prepare HTTP requests to send to the source API to download the data provided by the completed async job.",
2517
2528
  )
@@ -2519,26 +2530,26 @@ class AsyncRetriever(BaseModel):
2519
2530
  None,
2520
2531
  description="Paginator component that describes how to navigate through the API's pages during download.",
2521
2532
  )
2522
- abort_requester: Optional[Union[CustomRequester, HttpRequester]] = Field(
2533
+ abort_requester: Optional[Union[HttpRequester, CustomRequester]] = Field(
2523
2534
  None,
2524
2535
  description="Requester component that describes how to prepare HTTP requests to send to the source API to abort a job once it is timed out from the source's perspective.",
2525
2536
  )
2526
- delete_requester: Optional[Union[CustomRequester, HttpRequester]] = Field(
2537
+ delete_requester: Optional[Union[HttpRequester, CustomRequester]] = Field(
2527
2538
  None,
2528
2539
  description="Requester component that describes how to prepare HTTP requests to send to the source API to delete a job once the records are extracted.",
2529
2540
  )
2530
2541
  partition_router: Optional[
2531
2542
  Union[
2532
- CustomPartitionRouter,
2533
2543
  ListPartitionRouter,
2534
2544
  SubstreamPartitionRouter,
2535
2545
  GroupingPartitionRouter,
2546
+ CustomPartitionRouter,
2536
2547
  List[
2537
2548
  Union[
2538
- CustomPartitionRouter,
2539
2549
  ListPartitionRouter,
2540
2550
  SubstreamPartitionRouter,
2541
2551
  GroupingPartitionRouter,
2552
+ CustomPartitionRouter,
2542
2553
  ]
2543
2554
  ],
2544
2555
  ]
@@ -2549,7 +2560,6 @@ class AsyncRetriever(BaseModel):
2549
2560
  )
2550
2561
  decoder: Optional[
2551
2562
  Union[
2552
- CustomDecoder,
2553
2563
  CsvDecoder,
2554
2564
  GzipDecoder,
2555
2565
  JsonDecoder,
@@ -2557,6 +2567,7 @@ class AsyncRetriever(BaseModel):
2557
2567
  IterableDecoder,
2558
2568
  XmlDecoder,
2559
2569
  ZipfileDecoder,
2570
+ CustomDecoder,
2560
2571
  ]
2561
2572
  ] = Field(
2562
2573
  None,
@@ -2565,7 +2576,6 @@ class AsyncRetriever(BaseModel):
2565
2576
  )
2566
2577
  download_decoder: Optional[
2567
2578
  Union[
2568
- CustomDecoder,
2569
2579
  CsvDecoder,
2570
2580
  GzipDecoder,
2571
2581
  JsonDecoder,
@@ -2573,6 +2583,7 @@ class AsyncRetriever(BaseModel):
2573
2583
  IterableDecoder,
2574
2584
  XmlDecoder,
2575
2585
  ZipfileDecoder,
2586
+ CustomDecoder,
2576
2587
  ]
2577
2588
  ] = Field(
2578
2589
  None,
@@ -2650,6 +2661,7 @@ SelectiveAuthenticator.update_forward_refs()
2650
2661
  FileUploader.update_forward_refs()
2651
2662
  DeclarativeStream.update_forward_refs()
2652
2663
  SessionTokenAuthenticator.update_forward_refs()
2664
+ HttpRequester.update_forward_refs()
2653
2665
  DynamicSchemaLoader.update_forward_refs()
2654
2666
  ParentStreamConfig.update_forward_refs()
2655
2667
  PropertiesFromEndpoint.update_forward_refs()
@@ -19,3 +19,12 @@ class UndefinedReferenceException(Exception):
19
19
 
20
20
  def __init__(self, path: str, reference: str) -> None:
21
21
  super().__init__(f"Undefined reference {reference} from {path}")
22
+
23
+
24
+ class ManifestNormalizationException(Exception):
25
+ """
26
+ Raised when a circular reference is detected in a manifest.
27
+ """
28
+
29
+ def __init__(self, message: str) -> None:
30
+ super().__init__(f"Failed to deduplicate manifest: {message}")
@@ -4,7 +4,7 @@
4
4
 
5
5
  import copy
6
6
  import typing
7
- from typing import Any, Mapping, Optional
7
+ from typing import Any, Dict, Mapping, Optional
8
8
 
9
9
  PARAMETERS_STR = "$parameters"
10
10
 
@@ -95,7 +95,7 @@ class ManifestComponentTransformer:
95
95
  declarative_component: Mapping[str, Any],
96
96
  parent_parameters: Mapping[str, Any],
97
97
  use_parent_parameters: Optional[bool] = None,
98
- ) -> Mapping[str, Any]:
98
+ ) -> Dict[str, Any]:
99
99
  """
100
100
  Recursively transforms the specified declarative component and subcomponents to propagate parameters and insert the
101
101
  default component type if it was not already present. The resulting transformed components are a deep copy of the input