airbyte-cdk 6.9.1.dev3__py3-none-any.whl → 6.9.1rc2__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 (20) hide show
  1. airbyte_cdk/sources/declarative/concurrent_declarative_source.py +25 -31
  2. airbyte_cdk/sources/declarative/datetime/datetime_parser.py +4 -4
  3. airbyte_cdk/sources/declarative/declarative_component_schema.yaml +100 -2
  4. airbyte_cdk/sources/declarative/incremental/datetime_based_cursor.py +1 -1
  5. airbyte_cdk/sources/declarative/manifest_declarative_source.py +53 -2
  6. airbyte_cdk/sources/declarative/models/declarative_component_schema.py +95 -2
  7. airbyte_cdk/sources/declarative/parsers/manifest_component_transformer.py +6 -0
  8. airbyte_cdk/sources/declarative/parsers/model_to_component_factory.py +95 -21
  9. airbyte_cdk/sources/declarative/partition_routers/__init__.py +2 -1
  10. airbyte_cdk/sources/declarative/resolvers/__init__.py +13 -0
  11. airbyte_cdk/sources/declarative/resolvers/components_resolver.py +55 -0
  12. airbyte_cdk/sources/declarative/resolvers/http_components_resolver.py +106 -0
  13. airbyte_cdk/sources/streams/concurrent/state_converters/datetime_stream_state_converter.py +2 -2
  14. airbyte_cdk-6.9.1rc2.dist-info/METADATA +108 -0
  15. {airbyte_cdk-6.9.1.dev3.dist-info → airbyte_cdk-6.9.1rc2.dist-info}/RECORD +18 -16
  16. airbyte_cdk/test/utils/manifest_only_fixtures.py +0 -81
  17. airbyte_cdk-6.9.1.dev3.dist-info/METADATA +0 -306
  18. {airbyte_cdk-6.9.1.dev3.dist-info → airbyte_cdk-6.9.1rc2.dist-info}/LICENSE.txt +0 -0
  19. {airbyte_cdk-6.9.1.dev3.dist-info → airbyte_cdk-6.9.1rc2.dist-info}/WHEEL +0 -0
  20. {airbyte_cdk-6.9.1.dev3.dist-info → airbyte_cdk-6.9.1rc2.dist-info}/entry_points.txt +0 -0
@@ -86,23 +86,10 @@ class ConcurrentDeclarativeSource(ManifestDeclarativeSource, Generic[TState]):
86
86
  component_factory=component_factory,
87
87
  )
88
88
 
89
+ # todo: We could remove state from initialization. Now that streams are grouped during the read(), a source
90
+ # no longer needs to store the original incoming state. But maybe there's an edge case?
89
91
  self._state = state
90
92
 
91
- self._concurrent_streams: Optional[List[AbstractStream]]
92
- self._synchronous_streams: Optional[List[Stream]]
93
-
94
- # If the connector command was SPEC, there is no incoming config, and we cannot instantiate streams because
95
- # they might depend on it. Ideally we want to have a static method on this class to get the spec without
96
- # any other arguments, but the existing entrypoint.py isn't designed to support this. Just noting this
97
- # for our future improvements to the CDK.
98
- if config:
99
- self._concurrent_streams, self._synchronous_streams = self._group_streams(
100
- config=config or {}
101
- )
102
- else:
103
- self._concurrent_streams = None
104
- self._synchronous_streams = None
105
-
106
93
  concurrency_level_from_manifest = self._source_config.get("concurrency_level")
107
94
  if concurrency_level_from_manifest:
108
95
  concurrency_level_component = self._constructor.create_component(
@@ -136,17 +123,20 @@ class ConcurrentDeclarativeSource(ManifestDeclarativeSource, Generic[TState]):
136
123
  logger: logging.Logger,
137
124
  config: Mapping[str, Any],
138
125
  catalog: ConfiguredAirbyteCatalog,
139
- state: Optional[Union[List[AirbyteStateMessage]]] = None,
126
+ state: Optional[List[AirbyteStateMessage]] = None,
140
127
  ) -> Iterator[AirbyteMessage]:
141
- # ConcurrentReadProcessor pops streams that are finished being read so before syncing, the names of the concurrent
142
- # streams must be saved so that they can be removed from the catalog before starting synchronous streams
143
- if self._concurrent_streams:
128
+ concurrent_streams, _ = self._group_streams(config=config)
129
+
130
+ # ConcurrentReadProcessor pops streams that are finished being read so before syncing, the names of
131
+ # the concurrent streams must be saved so that they can be removed from the catalog before starting
132
+ # synchronous streams
133
+ if len(concurrent_streams) > 0:
144
134
  concurrent_stream_names = set(
145
- [concurrent_stream.name for concurrent_stream in self._concurrent_streams]
135
+ [concurrent_stream.name for concurrent_stream in concurrent_streams]
146
136
  )
147
137
 
148
138
  selected_concurrent_streams = self._select_streams(
149
- streams=self._concurrent_streams, configured_catalog=catalog
139
+ streams=concurrent_streams, configured_catalog=catalog
150
140
  )
151
141
  # It would appear that passing in an empty set of streams causes an infinite loop in ConcurrentReadProcessor.
152
142
  # This is also evident in concurrent_source_adapter.py so I'll leave this out of scope to fix for now
@@ -165,8 +155,7 @@ class ConcurrentDeclarativeSource(ManifestDeclarativeSource, Generic[TState]):
165
155
  yield from super().read(logger, config, filtered_catalog, state)
166
156
 
167
157
  def discover(self, logger: logging.Logger, config: Mapping[str, Any]) -> AirbyteCatalog:
168
- concurrent_streams = self._concurrent_streams or []
169
- synchronous_streams = self._synchronous_streams or []
158
+ concurrent_streams, synchronous_streams = self._group_streams(config=config)
170
159
  return AirbyteCatalog(
171
160
  streams=[
172
161
  stream.as_airbyte_stream() for stream in concurrent_streams + synchronous_streams
@@ -192,9 +181,13 @@ class ConcurrentDeclarativeSource(ManifestDeclarativeSource, Generic[TState]):
192
181
 
193
182
  state_manager = ConnectorStateManager(state=self._state) # type: ignore # state is always in the form of List[AirbyteStateMessage]. The ConnectorStateManager should use generics, but this can be done later
194
183
 
195
- name_to_stream_mapping = {
196
- stream["name"]: stream for stream in self.resolved_manifest["streams"]
197
- }
184
+ # Combine streams and dynamic_streams. Note: both cannot be empty at the same time,
185
+ # and this is validated during the initialization of the source.
186
+ streams = self._stream_configs(self._source_config) + self._dynamic_stream_configs(
187
+ self._source_config, config
188
+ )
189
+
190
+ name_to_stream_mapping = {stream["name"]: stream for stream in streams}
198
191
 
199
192
  for declarative_stream in self.streams(config=config):
200
193
  # Some low-code sources use a combination of DeclarativeStream and regular Python streams. We can't inspect
@@ -202,7 +195,7 @@ class ConcurrentDeclarativeSource(ManifestDeclarativeSource, Generic[TState]):
202
195
  # so we need to treat them as synchronous
203
196
  if (
204
197
  isinstance(declarative_stream, DeclarativeStream)
205
- and name_to_stream_mapping[declarative_stream.name].get("retriever")["type"]
198
+ and name_to_stream_mapping[declarative_stream.name]["retriever"]["type"]
206
199
  == "SimpleRetriever"
207
200
  ):
208
201
  incremental_sync_component_definition = name_to_stream_mapping[
@@ -211,7 +204,7 @@ class ConcurrentDeclarativeSource(ManifestDeclarativeSource, Generic[TState]):
211
204
 
212
205
  partition_router_component_definition = (
213
206
  name_to_stream_mapping[declarative_stream.name]
214
- .get("retriever")
207
+ .get("retriever", {})
215
208
  .get("partition_router")
216
209
  )
217
210
  is_without_partition_router_or_cursor = not bool(
@@ -233,7 +226,7 @@ class ConcurrentDeclarativeSource(ManifestDeclarativeSource, Generic[TState]):
233
226
  cursor = self._constructor.create_concurrent_cursor_from_datetime_based_cursor(
234
227
  state_manager=state_manager,
235
228
  model_type=DatetimeBasedCursorModel,
236
- component_definition=incremental_sync_component_definition,
229
+ component_definition=incremental_sync_component_definition, # type: ignore # Not None because of the if condition above
237
230
  stream_name=declarative_stream.name,
238
231
  stream_namespace=declarative_stream.namespace,
239
232
  config=config or {},
@@ -316,10 +309,11 @@ class ConcurrentDeclarativeSource(ManifestDeclarativeSource, Generic[TState]):
316
309
  def _is_datetime_incremental_without_partition_routing(
317
310
  self,
318
311
  declarative_stream: DeclarativeStream,
319
- incremental_sync_component_definition: Mapping[str, Any],
312
+ incremental_sync_component_definition: Mapping[str, Any] | None,
320
313
  ) -> bool:
321
314
  return (
322
- bool(incremental_sync_component_definition)
315
+ incremental_sync_component_definition is not None
316
+ and bool(incremental_sync_component_definition)
323
317
  and incremental_sync_component_definition.get("type", "")
324
318
  == DatetimeBasedCursorModel.__name__
325
319
  and self._stream_supports_concurrent_partition_processing(
@@ -37,17 +37,17 @@ class DatetimeParser:
37
37
  return parsed_datetime.replace(tzinfo=datetime.timezone.utc)
38
38
  return parsed_datetime
39
39
 
40
- def format(self, dt: datetime.datetime, format: str) -> str:
40
+ def format(self, dt: datetime.datetime, format: str) -> Union[str, int]:
41
41
  # strftime("%s") is unreliable because it ignores the time zone information and assumes the time zone of the system it's running on
42
42
  # It's safer to use the timestamp() method than the %s directive
43
43
  # See https://stackoverflow.com/a/4974930
44
44
  if format == "%s":
45
- return str(int(dt.timestamp()))
45
+ return int(dt.timestamp())
46
46
  if format == "%s_as_float":
47
- return str(float(dt.timestamp()))
47
+ return float(dt.timestamp())
48
48
  if format == "%ms":
49
49
  # timstamp() returns a float representing the number of seconds since the unix epoch
50
- return str(int(dt.timestamp() * 1000))
50
+ return int(dt.timestamp() * 1000)
51
51
  else:
52
52
  return dt.strftime(format)
53
53
 
@@ -7,8 +7,12 @@ version: 1.0.0
7
7
  required:
8
8
  - type
9
9
  - check
10
- - streams
11
10
  - version
11
+ anyOf:
12
+ - required:
13
+ - streams
14
+ - required:
15
+ - dynamic_streams
12
16
  properties:
13
17
  type:
14
18
  type: string
@@ -19,6 +23,10 @@ properties:
19
23
  type: array
20
24
  items:
21
25
  "$ref": "#/definitions/DeclarativeStream"
26
+ dynamic_streams:
27
+ type: array
28
+ items:
29
+ "$ref": "#/definitions/DynamicDeclarativeStream"
22
30
  version:
23
31
  type: string
24
32
  description: The version of the Airbyte CDK used to build and test the source.
@@ -1321,7 +1329,7 @@ definitions:
1321
1329
  type: array
1322
1330
  items:
1323
1331
  - type: string
1324
- interpolation_content:
1332
+ interpolation_context:
1325
1333
  - config
1326
1334
  examples:
1327
1335
  - ["data"]
@@ -2895,6 +2903,96 @@ definitions:
2895
2903
  $parameters:
2896
2904
  type: object
2897
2905
  additionalProperties: true
2906
+ ComponentMappingDefinition:
2907
+ title: Component Mapping Definition
2908
+ description: (This component is experimental. Use at your own risk.) Specifies a mapping definition to update or add fields in a record or configuration. This allows dynamic mapping of data by interpolating values into the template based on provided contexts.
2909
+ type: object
2910
+ required:
2911
+ - type
2912
+ - field_path
2913
+ - value
2914
+ properties:
2915
+ type:
2916
+ type: string
2917
+ enum: [ComponentMappingDefinition]
2918
+ field_path:
2919
+ title: Field Path
2920
+ description: A list of potentially nested fields indicating the full path where value will be added or updated.
2921
+ type: array
2922
+ items:
2923
+ - type: string
2924
+ interpolation_context:
2925
+ - config
2926
+ - components_values
2927
+ - stream_template_config
2928
+ examples:
2929
+ - ["data"]
2930
+ - ["data", "records"]
2931
+ - ["data", "{{ parameters.name }}"]
2932
+ - ["data", "*", "record"]
2933
+ value:
2934
+ title: Value
2935
+ description: The dynamic or static value to assign to the key. Interpolated values can be used to dynamically determine the value during runtime.
2936
+ type: string
2937
+ interpolation_context:
2938
+ - config
2939
+ - stream_template_config
2940
+ - components_values
2941
+ examples:
2942
+ - "{{ components_values['updates'] }}"
2943
+ - "{{ components_values['MetaData']['LastUpdatedTime'] }}"
2944
+ - "{{ config['segment_id'] }}"
2945
+ value_type:
2946
+ title: Value Type
2947
+ description: The expected data type of the value. If omitted, the type will be inferred from the value provided.
2948
+ "$ref": "#/definitions/ValueType"
2949
+ $parameters:
2950
+ type: object
2951
+ additionalProperties: true
2952
+ HttpComponentsResolver:
2953
+ type: object
2954
+ description: (This component is experimental. Use at your own risk.) Component resolve and populates stream templates with components fetched via an HTTP retriever.
2955
+ properties:
2956
+ type:
2957
+ type: string
2958
+ enum: [HttpComponentsResolver]
2959
+ retriever:
2960
+ title: Retriever
2961
+ description: Component used to coordinate how records are extracted across stream slices and request pages.
2962
+ anyOf:
2963
+ - "$ref": "#/definitions/AsyncRetriever"
2964
+ - "$ref": "#/definitions/CustomRetriever"
2965
+ - "$ref": "#/definitions/SimpleRetriever"
2966
+ components_mapping:
2967
+ type: array
2968
+ items:
2969
+ "$ref": "#/definitions/ComponentMappingDefinition"
2970
+ $parameters:
2971
+ type: object
2972
+ additionalProperties: true
2973
+ required:
2974
+ - type
2975
+ - retriever
2976
+ - components_mapping
2977
+ DynamicDeclarativeStream:
2978
+ type: object
2979
+ description: (This component is experimental. Use at your own risk.) A component that described how will be created declarative streams based on stream template.
2980
+ properties:
2981
+ type:
2982
+ type: string
2983
+ enum: [DynamicDeclarativeStream]
2984
+ stream_template:
2985
+ title: Stream Template
2986
+ description: Reference to the stream template.
2987
+ "$ref": "#/definitions/DeclarativeStream"
2988
+ components_resolver:
2989
+ title: Components Resolver
2990
+ description: Component resolve and populates stream templates with components values.
2991
+ "$ref": "#/definitions/HttpComponentsResolver"
2992
+ required:
2993
+ - type
2994
+ - stream_template
2995
+ - components_resolver
2898
2996
  interpolation:
2899
2997
  variables:
2900
2998
  - title: config
@@ -248,7 +248,7 @@ class DatetimeBasedCursor(DeclarativeCursor):
248
248
  return datetime.datetime.min.replace(tzinfo=datetime.timezone.utc)
249
249
 
250
250
  def _format_datetime(self, dt: datetime.datetime) -> str:
251
- return self._parser.format(dt, self.datetime_format)
251
+ return str(self._parser.format(dt, self.datetime_format))
252
252
 
253
253
  def _partition_daterange(
254
254
  self,
@@ -39,6 +39,7 @@ from airbyte_cdk.sources.declarative.parsers.manifest_reference_resolver import
39
39
  from airbyte_cdk.sources.declarative.parsers.model_to_component_factory import (
40
40
  ModelToComponentFactory,
41
41
  )
42
+ from airbyte_cdk.sources.declarative.resolvers import COMPONENTS_RESOLVER_TYPE_MAPPING
42
43
  from airbyte_cdk.sources.message import MessageRepository
43
44
  from airbyte_cdk.sources.streams.core import Stream
44
45
  from airbyte_cdk.sources.types import ConnectionDefinition
@@ -120,7 +121,10 @@ class ManifestDeclarativeSource(DeclarativeSource):
120
121
  self._emit_manifest_debug_message(
121
122
  extra_args={"source_name": self.name, "parsed_config": json.dumps(self._source_config)}
122
123
  )
123
- stream_configs = self._stream_configs(self._source_config)
124
+
125
+ stream_configs = self._stream_configs(self._source_config) + self._dynamic_stream_configs(
126
+ self._source_config, config
127
+ )
124
128
 
125
129
  source_streams = [
126
130
  self._constructor.create_component(
@@ -234,7 +238,8 @@ class ManifestDeclarativeSource(DeclarativeSource):
234
238
  )
235
239
 
236
240
  streams = self._source_config.get("streams")
237
- if not streams:
241
+ dynamic_streams = self._source_config.get("dynamic_streams")
242
+ if not (streams or dynamic_streams):
238
243
  raise ValidationError(
239
244
  f"A valid manifest should have at least one stream defined. Got {streams}"
240
245
  )
@@ -303,5 +308,51 @@ class ManifestDeclarativeSource(DeclarativeSource):
303
308
  s["type"] = "DeclarativeStream"
304
309
  return stream_configs
305
310
 
311
+ def _dynamic_stream_configs(
312
+ self, manifest: Mapping[str, Any], config: Mapping[str, Any]
313
+ ) -> List[Dict[str, Any]]:
314
+ dynamic_stream_definitions: List[Dict[str, Any]] = manifest.get("dynamic_streams", [])
315
+ dynamic_stream_configs: List[Dict[str, Any]] = []
316
+
317
+ for dynamic_definition in dynamic_stream_definitions:
318
+ components_resolver_config = dynamic_definition["components_resolver"]
319
+
320
+ if not components_resolver_config:
321
+ raise ValueError(
322
+ f"Missing 'components_resolver' in dynamic definition: {dynamic_definition}"
323
+ )
324
+
325
+ resolver_type = components_resolver_config.get("type")
326
+ if not resolver_type:
327
+ raise ValueError(
328
+ f"Missing 'type' in components resolver configuration: {components_resolver_config}"
329
+ )
330
+
331
+ if resolver_type not in COMPONENTS_RESOLVER_TYPE_MAPPING:
332
+ raise ValueError(
333
+ f"Invalid components resolver type '{resolver_type}'. "
334
+ f"Expected one of {list(COMPONENTS_RESOLVER_TYPE_MAPPING.keys())}."
335
+ )
336
+
337
+ if "retriever" in components_resolver_config:
338
+ components_resolver_config["retriever"]["requester"]["use_cache"] = True
339
+
340
+ # Create a resolver for dynamic components based on type
341
+ components_resolver = self._constructor.create_component(
342
+ COMPONENTS_RESOLVER_TYPE_MAPPING[resolver_type], components_resolver_config, config
343
+ )
344
+
345
+ stream_template_config = dynamic_definition["stream_template"]
346
+
347
+ for dynamic_stream in components_resolver.resolve_components(
348
+ stream_template_config=stream_template_config
349
+ ):
350
+ if "type" not in dynamic_stream:
351
+ dynamic_stream["type"] = "DeclarativeStream"
352
+
353
+ dynamic_stream_configs.append(dynamic_stream)
354
+
355
+ return dynamic_stream_configs
356
+
306
357
  def _emit_manifest_debug_message(self, extra_args: dict[str, Any]) -> None:
307
358
  self.logger.debug("declarative source created from manifest", extra=extra_args)
@@ -1158,6 +1158,37 @@ class WaitUntilTimeFromHeader(BaseModel):
1158
1158
  parameters: Optional[Dict[str, Any]] = Field(None, alias="$parameters")
1159
1159
 
1160
1160
 
1161
+ class ComponentMappingDefinition(BaseModel):
1162
+ type: Literal["ComponentMappingDefinition"]
1163
+ field_path: List[str] = Field(
1164
+ ...,
1165
+ description="A list of potentially nested fields indicating the full path where value will be added or updated.",
1166
+ examples=[
1167
+ ["data"],
1168
+ ["data", "records"],
1169
+ ["data", "{{ parameters.name }}"],
1170
+ ["data", "*", "record"],
1171
+ ],
1172
+ title="Field Path",
1173
+ )
1174
+ value: str = Field(
1175
+ ...,
1176
+ description="The dynamic or static value to assign to the key. Interpolated values can be used to dynamically determine the value during runtime.",
1177
+ examples=[
1178
+ "{{ components_values['updates'] }}",
1179
+ "{{ components_values['MetaData']['LastUpdatedTime'] }}",
1180
+ "{{ config['segment_id'] }}",
1181
+ ],
1182
+ title="Value",
1183
+ )
1184
+ value_type: Optional[ValueType] = Field(
1185
+ None,
1186
+ description="The expected data type of the value. If omitted, the type will be inferred from the value provided.",
1187
+ title="Value Type",
1188
+ )
1189
+ parameters: Optional[Dict[str, Any]] = Field(None, alias="$parameters")
1190
+
1191
+
1161
1192
  class AddedFieldDefinition(BaseModel):
1162
1193
  type: Literal["AddedFieldDefinition"]
1163
1194
  path: List[str] = Field(
@@ -1455,13 +1486,40 @@ class CompositeErrorHandler(BaseModel):
1455
1486
  parameters: Optional[Dict[str, Any]] = Field(None, alias="$parameters")
1456
1487
 
1457
1488
 
1458
- class DeclarativeSource(BaseModel):
1489
+ class DeclarativeSource1(BaseModel):
1459
1490
  class Config:
1460
1491
  extra = Extra.forbid
1461
1492
 
1462
1493
  type: Literal["DeclarativeSource"]
1463
1494
  check: CheckStream
1464
1495
  streams: List[DeclarativeStream]
1496
+ dynamic_streams: Optional[List[DynamicDeclarativeStream]] = None
1497
+ version: str = Field(
1498
+ ...,
1499
+ description="The version of the Airbyte CDK used to build and test the source.",
1500
+ )
1501
+ schemas: Optional[Schemas] = None
1502
+ definitions: Optional[Dict[str, Any]] = None
1503
+ spec: Optional[Spec] = None
1504
+ concurrency_level: Optional[ConcurrencyLevel] = None
1505
+ metadata: Optional[Dict[str, Any]] = Field(
1506
+ None,
1507
+ description="For internal Airbyte use only - DO NOT modify manually. Used by consumers of declarative manifests for storing related metadata.",
1508
+ )
1509
+ description: Optional[str] = Field(
1510
+ None,
1511
+ description="A description of the connector. It will be presented on the Source documentation page.",
1512
+ )
1513
+
1514
+
1515
+ class DeclarativeSource2(BaseModel):
1516
+ class Config:
1517
+ extra = Extra.forbid
1518
+
1519
+ type: Literal["DeclarativeSource"]
1520
+ check: CheckStream
1521
+ streams: Optional[List[DeclarativeStream]] = None
1522
+ dynamic_streams: List[DynamicDeclarativeStream]
1465
1523
  version: str = Field(
1466
1524
  ...,
1467
1525
  description="The version of the Airbyte CDK used to build and test the source.",
@@ -1480,6 +1538,17 @@ class DeclarativeSource(BaseModel):
1480
1538
  )
1481
1539
 
1482
1540
 
1541
+ class DeclarativeSource(BaseModel):
1542
+ class Config:
1543
+ extra = Extra.forbid
1544
+
1545
+ __root__: Union[DeclarativeSource1, DeclarativeSource2] = Field(
1546
+ ...,
1547
+ description="An API source that extracts data according to its declarative components.",
1548
+ title="DeclarativeSource",
1549
+ )
1550
+
1551
+
1483
1552
  class SelectiveAuthenticator(BaseModel):
1484
1553
  class Config:
1485
1554
  extra = Extra.allow
@@ -1883,8 +1952,32 @@ class SubstreamPartitionRouter(BaseModel):
1883
1952
  parameters: Optional[Dict[str, Any]] = Field(None, alias="$parameters")
1884
1953
 
1885
1954
 
1955
+ class HttpComponentsResolver(BaseModel):
1956
+ type: Literal["HttpComponentsResolver"]
1957
+ retriever: Union[AsyncRetriever, CustomRetriever, SimpleRetriever] = Field(
1958
+ ...,
1959
+ description="Component used to coordinate how records are extracted across stream slices and request pages.",
1960
+ title="Retriever",
1961
+ )
1962
+ components_mapping: List[ComponentMappingDefinition]
1963
+ parameters: Optional[Dict[str, Any]] = Field(None, alias="$parameters")
1964
+
1965
+
1966
+ class DynamicDeclarativeStream(BaseModel):
1967
+ type: Literal["DynamicDeclarativeStream"]
1968
+ stream_template: DeclarativeStream = Field(
1969
+ ..., description="Reference to the stream template.", title="Stream Template"
1970
+ )
1971
+ components_resolver: HttpComponentsResolver = Field(
1972
+ ...,
1973
+ description="Component resolve and populates stream templates with components values.",
1974
+ title="Components Resolver",
1975
+ )
1976
+
1977
+
1886
1978
  CompositeErrorHandler.update_forward_refs()
1887
- DeclarativeSource.update_forward_refs()
1979
+ DeclarativeSource1.update_forward_refs()
1980
+ DeclarativeSource2.update_forward_refs()
1888
1981
  SelectiveAuthenticator.update_forward_refs()
1889
1982
  DeclarativeStream.update_forward_refs()
1890
1983
  SessionTokenAuthenticator.update_forward_refs()
@@ -31,6 +31,12 @@ DEFAULT_MODEL_TYPES: Mapping[str, str] = {
31
31
  # DeclarativeStream
32
32
  "DeclarativeStream.retriever": "SimpleRetriever",
33
33
  "DeclarativeStream.schema_loader": "JsonFileSchemaLoader",
34
+ # DynamicDeclarativeStream
35
+ "DynamicDeclarativeStream.stream_template": "DeclarativeStream",
36
+ "DynamicDeclarativeStream.components_resolver": "HttpComponentsResolver",
37
+ # HttpComponentsResolver
38
+ "HttpComponentsResolver.retriever": "SimpleRetriever",
39
+ "HttpComponentsResolver.components_mapping": "ComponentMappingDefinition",
34
40
  # DefaultErrorHandler
35
41
  "DefaultErrorHandler.response_filters": "HttpResponseFilter",
36
42
  # DefaultPaginator