airbyte-cdk 6.52.0.dev0__py3-none-any.whl → 6.52.0.dev1__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.
@@ -4055,6 +4055,9 @@ definitions:
4055
4055
  title: Value Type
4056
4056
  description: The expected data type of the value. If omitted, the type will be inferred from the value provided.
4057
4057
  "$ref": "#/definitions/ValueType"
4058
+ create_or_update:
4059
+ type: boolean
4060
+ default: false
4058
4061
  $parameters:
4059
4062
  type: object
4060
4063
  additionalProperties: true
@@ -4106,6 +4109,12 @@ definitions:
4106
4109
  - ["data"]
4107
4110
  - ["data", "streams"]
4108
4111
  - ["data", "{{ parameters.name }}"]
4112
+ default_values:
4113
+ title: Default Values
4114
+ description: A list of default values, each matching the structure expected from the parsed component value.
4115
+ type: array
4116
+ items:
4117
+ type: object
4109
4118
  $parameters:
4110
4119
  type: object
4111
4120
  additionalProperties: true
@@ -4117,7 +4126,11 @@ definitions:
4117
4126
  type: string
4118
4127
  enum: [ConfigComponentsResolver]
4119
4128
  stream_config:
4120
- "$ref": "#/definitions/StreamConfig"
4129
+ anyOf:
4130
+ - type: array
4131
+ items:
4132
+ "$ref": "#/definitions/StreamConfig"
4133
+ - "$ref": "#/definitions/StreamConfig"
4121
4134
  components_mapping:
4122
4135
  type: array
4123
4136
  items:
@@ -300,9 +300,7 @@ class ManifestDeclarativeSource(DeclarativeSource):
300
300
  }
301
301
  )
302
302
 
303
- stream_configs = self._stream_configs(self._source_config) + self._dynamic_stream_configs(
304
- self._source_config, config
305
- )
303
+ stream_configs = self._stream_configs(self._source_config) + self.dynamic_streams
306
304
 
307
305
  api_budget_model = self._source_config.get("api_budget")
308
306
  if api_budget_model:
@@ -1478,6 +1478,7 @@ class ComponentMappingDefinition(BaseModel):
1478
1478
  description="The expected data type of the value. If omitted, the type will be inferred from the value provided.",
1479
1479
  title="Value Type",
1480
1480
  )
1481
+ create_or_update: Optional[bool] = False
1481
1482
  parameters: Optional[Dict[str, Any]] = Field(None, alias="$parameters")
1482
1483
 
1483
1484
 
@@ -1489,12 +1490,17 @@ class StreamConfig(BaseModel):
1489
1490
  examples=[["data"], ["data", "streams"], ["data", "{{ parameters.name }}"]],
1490
1491
  title="Configs Pointer",
1491
1492
  )
1493
+ default_values: Optional[List[Dict[str, Any]]] = Field(
1494
+ None,
1495
+ description="A list of default values, each matching the structure expected from the parsed component value.",
1496
+ title="Default Values",
1497
+ )
1492
1498
  parameters: Optional[Dict[str, Any]] = Field(None, alias="$parameters")
1493
1499
 
1494
1500
 
1495
1501
  class ConfigComponentsResolver(BaseModel):
1496
1502
  type: Literal["ConfigComponentsResolver"]
1497
- stream_config: StreamConfig
1503
+ stream_config: Union[List[StreamConfig], StreamConfig]
1498
1504
  components_mapping: List[ComponentMappingDefinition]
1499
1505
  parameters: Optional[Dict[str, Any]] = Field(None, alias="$parameters")
1500
1506
 
@@ -3754,6 +3754,7 @@ class ModelToComponentFactory:
3754
3754
  field_path=field_path, # type: ignore[arg-type] # field_path can be str and InterpolatedString
3755
3755
  value=interpolated_value,
3756
3756
  value_type=ModelToComponentFactory._json_schema_type_name_to_type(model.value_type),
3757
+ create_or_update=model.create_or_update,
3757
3758
  parameters=model.parameters or {},
3758
3759
  )
3759
3760
 
@@ -3800,16 +3801,24 @@ class ModelToComponentFactory:
3800
3801
 
3801
3802
  return StreamConfig(
3802
3803
  configs_pointer=model_configs_pointer,
3804
+ default_values=model.default_values,
3803
3805
  parameters=model.parameters or {},
3804
3806
  )
3805
3807
 
3806
3808
  def create_config_components_resolver(
3807
3809
  self, model: ConfigComponentsResolverModel, config: Config
3808
3810
  ) -> Any:
3809
- stream_config = self._create_component_from_model(
3810
- model.stream_config, config=config, parameters=model.parameters or {}
3811
+ model_stream_configs = (
3812
+ model.stream_config if isinstance(model.stream_config, list) else [model.stream_config]
3811
3813
  )
3812
3814
 
3815
+ stream_configs = [
3816
+ self._create_component_from_model(
3817
+ stream_config, config=config, parameters=model.parameters or {}
3818
+ )
3819
+ for stream_config in model_stream_configs
3820
+ ]
3821
+
3813
3822
  components_mapping = [
3814
3823
  self._create_component_from_model(
3815
3824
  model=components_mapping_definition_model,
@@ -3822,7 +3831,7 @@ class ModelToComponentFactory:
3822
3831
  ]
3823
3832
 
3824
3833
  return ConfigComponentsResolver(
3825
- stream_config=stream_config,
3834
+ stream_configs=stream_configs,
3826
3835
  config=config,
3827
3836
  components_mapping=components_mapping,
3828
3837
  parameters=model.parameters or {},
@@ -22,6 +22,7 @@ class ComponentMappingDefinition:
22
22
  value: Union["InterpolatedString", str]
23
23
  value_type: Optional[Type[Any]]
24
24
  parameters: InitVar[Mapping[str, Any]]
25
+ create_or_update: Optional[bool] = False
25
26
 
26
27
 
27
28
  @dataclass(frozen=True)
@@ -34,6 +35,7 @@ class ResolvedComponentMappingDefinition:
34
35
  value: "InterpolatedString"
35
36
  value_type: Optional[Type[Any]]
36
37
  parameters: InitVar[Mapping[str, Any]]
38
+ create_or_update: Optional[bool] = False
37
39
 
38
40
 
39
41
  @deprecated("This class is experimental. Use at your own risk.", category=ExperimentalClassWarning)
@@ -4,10 +4,13 @@
4
4
 
5
5
  from copy import deepcopy
6
6
  from dataclasses import InitVar, dataclass, field
7
- from typing import Any, Dict, Iterable, List, Mapping, Union
7
+ from itertools import product
8
+ from typing import Any, Dict, Iterable, List, Mapping, Optional, Tuple, Union
8
9
 
9
10
  import dpath
11
+ import yaml
10
12
  from typing_extensions import deprecated
13
+ from yaml.parser import ParserError
11
14
 
12
15
  from airbyte_cdk.sources.declarative.interpolation import InterpolatedString
13
16
  from airbyte_cdk.sources.declarative.resolvers.components_resolver import (
@@ -28,6 +31,7 @@ class StreamConfig:
28
31
 
29
32
  configs_pointer: List[Union[InterpolatedString, str]]
30
33
  parameters: InitVar[Mapping[str, Any]]
34
+ default_values: Optional[List[Any]] = None
31
35
 
32
36
  def __post_init__(self, parameters: Mapping[str, Any]) -> None:
33
37
  self.configs_pointer = [
@@ -48,7 +52,7 @@ class ConfigComponentsResolver(ComponentsResolver):
48
52
  parameters (InitVar[Mapping[str, Any]]): Additional parameters for interpolation.
49
53
  """
50
54
 
51
- stream_config: StreamConfig
55
+ stream_configs: List[StreamConfig]
52
56
  config: Config
53
57
  components_mapping: List[ComponentMappingDefinition]
54
58
  parameters: InitVar[Mapping[str, Any]]
@@ -82,6 +86,7 @@ class ConfigComponentsResolver(ComponentsResolver):
82
86
  field_path=field_path,
83
87
  value=interpolated_value,
84
88
  value_type=component_mapping.value_type,
89
+ create_or_update=component_mapping.create_or_update,
85
90
  parameters=parameters,
86
91
  )
87
92
  )
@@ -90,18 +95,45 @@ class ConfigComponentsResolver(ComponentsResolver):
90
95
  f"Expected a string or InterpolatedString for value in mapping: {component_mapping}"
91
96
  )
92
97
 
98
+ @staticmethod
99
+ def _merge_combination(combo: Iterable[Tuple[int, Any]]) -> Dict[str, Any]:
100
+ """Collapse a combination of ``(idx, elem)`` into one config dict."""
101
+ result: Dict[str, Any] = {}
102
+ for config_index, (elem_index, elem) in enumerate(combo):
103
+ if isinstance(elem, dict):
104
+ result.update(elem)
105
+ else:
106
+ # keep non-dict values under an artificial name
107
+ result.setdefault(f"source_config_{config_index}", (elem_index, elem))
108
+ return result
109
+
93
110
  @property
94
- def _stream_config(self) -> Iterable[Mapping[str, Any]]:
95
- path = [
96
- node.eval(self.config) if not isinstance(node, str) else node
97
- for node in self.stream_config.configs_pointer
111
+ def _stream_config(self) -> List[Dict[str, Any]]:
112
+ """
113
+ Build every unique stream-configuration combination defined by
114
+ each ``StreamConfig`` and any ``default_values``.
115
+ """
116
+ all_indexed_streams = []
117
+ for stream_config in self.stream_configs:
118
+ path = [
119
+ node.eval(self.config) if not isinstance(node, str) else node
120
+ for node in stream_config.configs_pointer
121
+ ]
122
+ stream_configs_raw = dpath.get(dict(self.config), path, default=[])
123
+ stream_configs = (
124
+ list(stream_configs_raw)
125
+ if isinstance(stream_configs_raw, list)
126
+ else [stream_configs_raw]
127
+ )
128
+
129
+ if stream_config.default_values:
130
+ stream_configs.extend(stream_config.default_values)
131
+
132
+ all_indexed_streams.append([(i, item) for i, item in enumerate(stream_configs)])
133
+ return [
134
+ self._merge_combination(combo) # type: ignore[arg-type]
135
+ for combo in product(*all_indexed_streams)
98
136
  ]
99
- stream_config = dpath.get(dict(self.config), path, default=[])
100
-
101
- if not isinstance(stream_config, list):
102
- stream_config = [stream_config]
103
-
104
- return stream_config
105
137
 
106
138
  def resolve_components(
107
139
  self, stream_template_config: Dict[str, Any]
@@ -130,7 +162,27 @@ class ConfigComponentsResolver(ComponentsResolver):
130
162
  )
131
163
 
132
164
  path = [path.eval(self.config, **kwargs) for path in resolved_component.field_path]
165
+ parsed_value = self._parse_yaml_if_possible(value)
166
+ updated = dpath.set(updated_config, path, parsed_value)
133
167
 
134
- dpath.set(updated_config, path, value)
168
+ if parsed_value and not updated and resolved_component.create_or_update:
169
+ dpath.new(updated_config, path, parsed_value)
135
170
 
136
171
  yield updated_config
172
+
173
+ @staticmethod
174
+ def _parse_yaml_if_possible(value: Any) -> Any:
175
+ """
176
+ Try to turn value into a Python object by YAML-parsing it.
177
+
178
+ * If value is a `str` and can be parsed by `yaml.safe_load`,
179
+ return the parsed result.
180
+ * If parsing fails (`yaml.parser.ParserError`) – or value is not
181
+ a string at all – return the original value unchanged.
182
+ """
183
+ if isinstance(value, str):
184
+ try:
185
+ return yaml.safe_load(value)
186
+ except ParserError: # "{{ record[0] in ['cohortActiveUsers'] }}" # not valid YAML
187
+ return value
188
+ return value
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: airbyte-cdk
3
- Version: 6.52.0.dev0
3
+ Version: 6.52.0.dev1
4
4
  Summary: A framework for writing Airbyte Connectors.
5
5
  Home-page: https://airbyte.com
6
6
  License: MIT
@@ -89,7 +89,7 @@ airbyte_cdk/sources/declarative/concurrent_declarative_source.py,sha256=OKor1mDD
89
89
  airbyte_cdk/sources/declarative/datetime/__init__.py,sha256=4Hw-PX1-VgESLF16cDdvuYCzGJtHntThLF4qIiULWeo,61
90
90
  airbyte_cdk/sources/declarative/datetime/datetime_parser.py,sha256=_zGNGq31RNy_0QBLt_EcTvgPyhj7urPdx6oA3M5-r3o,3150
91
91
  airbyte_cdk/sources/declarative/datetime/min_max_datetime.py,sha256=0BHBtDNQZfvwM45-tY5pNlTcKAFSGGNxemoi0Jic-0E,5785
92
- airbyte_cdk/sources/declarative/declarative_component_schema.yaml,sha256=ttq2s4aivIbvIj2OWy0-CNb2cVXYVTzOgXS9PLbMNWU,176666
92
+ airbyte_cdk/sources/declarative/declarative_component_schema.yaml,sha256=LklBDA_hfKidQKWp4y8NCYBx4HkBVFAxhoTexBB2AU4,177075
93
93
  airbyte_cdk/sources/declarative/declarative_source.py,sha256=qmyMnnet92eGc3C22yBtpvD5UZjqdhsAafP_zxI5wp8,1814
94
94
  airbyte_cdk/sources/declarative/declarative_stream.py,sha256=dCRlddBUSaJmBNBz1pSO1r2rTw8AP5d2_vlmIeGs2gg,10767
95
95
  airbyte_cdk/sources/declarative/decoders/__init__.py,sha256=JHb_0d3SE6kNY10mxA5YBEKPeSbsWYjByq1gUQxepoE,953
@@ -127,20 +127,20 @@ airbyte_cdk/sources/declarative/interpolation/interpolated_string.py,sha256=CQkH
127
127
  airbyte_cdk/sources/declarative/interpolation/interpolation.py,sha256=9IoeuWam3L6GyN10L6U8xNWXmkt9cnahSDNkez1OmFY,982
128
128
  airbyte_cdk/sources/declarative/interpolation/jinja.py,sha256=UQeuS4Vpyp4hlOn-R3tRyeBX0e9IoV6jQ6gH-Jz8lY0,7182
129
129
  airbyte_cdk/sources/declarative/interpolation/macros.py,sha256=UYSJ5gW7TkHALYnNvUnRP3RlyGwGuRMObF3BHuNzjJM,5320
130
- airbyte_cdk/sources/declarative/manifest_declarative_source.py,sha256=AVb86oWIAxAOrE3KAyNr81bF5Dd2QjKdQ6E4Jl4yrQw,24719
130
+ airbyte_cdk/sources/declarative/manifest_declarative_source.py,sha256=aS_YxqUWgxyfyzwAZpV736RFg-m5a0sn-V7PPMBGVr4,24660
131
131
  airbyte_cdk/sources/declarative/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
132
132
  airbyte_cdk/sources/declarative/migrations/legacy_to_per_partition_state_migration.py,sha256=V2lpYE9LJKvz6BUViHk4vaRGndxNABmPbDCtyYdkqaE,4013
133
133
  airbyte_cdk/sources/declarative/migrations/state_migration.py,sha256=KWPjealMLKSMtajXgkdGgKg7EmTLR-CqqD7UIh0-eDU,794
134
134
  airbyte_cdk/sources/declarative/models/__init__.py,sha256=nUFxNCiKeYRVXuZEKA7GD-lTHxsiKcQ8FitZjKhPIvE,100
135
135
  airbyte_cdk/sources/declarative/models/base_model_with_deprecations.py,sha256=Imnj3yef0aqRdLfaUxkIYISUb8YkiPrRH_wBd-x8HjM,5999
136
- airbyte_cdk/sources/declarative/models/declarative_component_schema.py,sha256=YhQl_vjQyWl1GJTuPyhg1aKWQazbqHROZ5v0dIg7auE,125123
136
+ airbyte_cdk/sources/declarative/models/declarative_component_schema.py,sha256=ooVQMvPd4Dd-0XHjOXUFHdbSMe4PaP9-UjQ23ulRxz4,125426
137
137
  airbyte_cdk/sources/declarative/parsers/__init__.py,sha256=ZnqYNxHsKCgO38IwB34RQyRMXTs4GTvlRi3ImKnIioo,61
138
138
  airbyte_cdk/sources/declarative/parsers/custom_code_compiler.py,sha256=nlVvHC511NUyDEEIRBkoeDTAvLqKNp-hRy8D19z8tdk,5941
139
139
  airbyte_cdk/sources/declarative/parsers/custom_exceptions.py,sha256=wnRUP0Xeru9Rbu5OexXSDN9QWDo8YU4tT9M2LDVOgGA,802
140
140
  airbyte_cdk/sources/declarative/parsers/manifest_component_transformer.py,sha256=2UdpCz3yi7ISZTyqkQXSSy3dMxeyOWqV7OlAS5b9GVg,11568
141
141
  airbyte_cdk/sources/declarative/parsers/manifest_normalizer.py,sha256=laBy7ebjA-PiNwc-50U4FHvMqS_mmHvnabxgFs4CjGw,17069
142
142
  airbyte_cdk/sources/declarative/parsers/manifest_reference_resolver.py,sha256=pJmg78vqE5VfUrF_KJnWjucQ4k9IWFULeAxHCowrHXE,6806
143
- airbyte_cdk/sources/declarative/parsers/model_to_component_factory.py,sha256=j7MUNaWDpsxe5yDzE3-id_wivjNrSjsJa1VgE4oSRlo,174401
143
+ airbyte_cdk/sources/declarative/parsers/model_to_component_factory.py,sha256=7-q8icBPnEHbPa0vonz5KjsalYrrqJasIcLXK1TITlc,174730
144
144
  airbyte_cdk/sources/declarative/partition_routers/__init__.py,sha256=TBC9AkGaUqHm2IKHMPN6punBIcY5tWGULowcLoAVkfw,1109
145
145
  airbyte_cdk/sources/declarative/partition_routers/async_job_partition_router.py,sha256=VelO7zKqKtzMJ35jyFeg0ypJLQC0plqqIBNXoBW1G2E,3001
146
146
  airbyte_cdk/sources/declarative/partition_routers/cartesian_product_stream_slicer.py,sha256=c5cuVFM6NFkuQqG8Z5IwkBuwDrvXZN1CunUOM_L0ezg,6892
@@ -194,8 +194,8 @@ airbyte_cdk/sources/declarative/requesters/request_options/request_options_provi
194
194
  airbyte_cdk/sources/declarative/requesters/request_path.py,sha256=S3MeFvcaQrMbOkSY2W2VbXLNomqt_3eXqVd9ZhgNwUs,299
195
195
  airbyte_cdk/sources/declarative/requesters/requester.py,sha256=T6tMx_Bx4iT-0YVjY7IzgRil-gaIu9n01b1iwpTh3Ek,5516
196
196
  airbyte_cdk/sources/declarative/resolvers/__init__.py,sha256=NiDcz5qi8HPsfX94MUmnX0Rgs_kQXGvucOmJjNWlxKQ,1207
197
- airbyte_cdk/sources/declarative/resolvers/components_resolver.py,sha256=KPjKc0yb9artL4ZkeqN8RmEykHH6FJgqXD7fCEnh1X0,1936
198
- airbyte_cdk/sources/declarative/resolvers/config_components_resolver.py,sha256=dz4iJV9liD_LzY_Mn4XmAStoUll60R3MIGWV4aN3pgg,5223
197
+ airbyte_cdk/sources/declarative/resolvers/components_resolver.py,sha256=oJIpy66ep8n-QOc8GwpllApTRcl4QtQhkTw5fWWra2w,2026
198
+ airbyte_cdk/sources/declarative/resolvers/config_components_resolver.py,sha256=sD3N7nmqDjLsau8P2DE7DYOHdFTYjC_2nIB6454BNYk,7556
199
199
  airbyte_cdk/sources/declarative/resolvers/http_components_resolver.py,sha256=AiojNs8wItJFrENZBFUaDvau3sgwudO6Wkra36upSPo,4639
200
200
  airbyte_cdk/sources/declarative/retrievers/__init__.py,sha256=nQepwG_RfW53sgwvK5dLPqfCx0VjsQ83nYoPjBMAaLM,527
201
201
  airbyte_cdk/sources/declarative/retrievers/async_retriever.py,sha256=6oZtnCHm9NdDvjTSrVwPQOXGSdETSIR7eWH2vFjM7jI,4855
@@ -419,9 +419,9 @@ airbyte_cdk/utils/slice_hasher.py,sha256=EDxgROHDbfG-QKQb59m7h_7crN1tRiawdf5uU7G
419
419
  airbyte_cdk/utils/spec_schema_transformations.py,sha256=-5HTuNsnDBAhj-oLeQXwpTGA0HdcjFOf2zTEMUTTg_Y,816
420
420
  airbyte_cdk/utils/stream_status_utils.py,sha256=ZmBoiy5HVbUEHAMrUONxZvxnvfV9CesmQJLDTAIWnWw,1171
421
421
  airbyte_cdk/utils/traced_exception.py,sha256=C8uIBuCL_E4WnBAOPSxBicD06JAldoN9fGsQDp463OY,6292
422
- airbyte_cdk-6.52.0.dev0.dist-info/LICENSE.txt,sha256=Wfe61S4BaGPj404v8lrAbvhjYR68SHlkzeYrg3_bbuM,1051
423
- airbyte_cdk-6.52.0.dev0.dist-info/LICENSE_SHORT,sha256=aqF6D1NcESmpn-cqsxBtszTEnHKnlsp8L4x9wAh3Nxg,55
424
- airbyte_cdk-6.52.0.dev0.dist-info/METADATA,sha256=EWPjAFT5JFlV51VuHFHIciFphjfoYNyJ9prFTbWkbyM,6348
425
- airbyte_cdk-6.52.0.dev0.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
426
- airbyte_cdk-6.52.0.dev0.dist-info/entry_points.txt,sha256=AKWbEkHfpzzk9nF9tqBUaw1MbvTM4mGtEzmZQm0ZWvM,139
427
- airbyte_cdk-6.52.0.dev0.dist-info/RECORD,,
422
+ airbyte_cdk-6.52.0.dev1.dist-info/LICENSE.txt,sha256=Wfe61S4BaGPj404v8lrAbvhjYR68SHlkzeYrg3_bbuM,1051
423
+ airbyte_cdk-6.52.0.dev1.dist-info/LICENSE_SHORT,sha256=aqF6D1NcESmpn-cqsxBtszTEnHKnlsp8L4x9wAh3Nxg,55
424
+ airbyte_cdk-6.52.0.dev1.dist-info/METADATA,sha256=Atlb-SeF8vrGZIBbNcskhXmEpQBqFgfrFjM41G23cps,6348
425
+ airbyte_cdk-6.52.0.dev1.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
426
+ airbyte_cdk-6.52.0.dev1.dist-info/entry_points.txt,sha256=AKWbEkHfpzzk9nF9tqBUaw1MbvTM4mGtEzmZQm0ZWvM,139
427
+ airbyte_cdk-6.52.0.dev1.dist-info/RECORD,,