airbyte-cdk 6.45.10__py3-none-any.whl → 6.46.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.
Files changed (30) 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 +108 -79
  12. airbyte_cdk/sources/declarative/manifest_declarative_source.py +122 -45
  13. airbyte_cdk/sources/declarative/models/declarative_component_schema.py +87 -82
  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 +24 -24
  19. airbyte_cdk/test/standard_tests/connector_base.py +51 -25
  20. airbyte_cdk/test/standard_tests/declarative_sources.py +3 -1
  21. airbyte_cdk/test/standard_tests/test_resources.py +69 -0
  22. airbyte_cdk/test/standard_tests/util.py +79 -0
  23. airbyte_cdk/utils/docker.py +337 -0
  24. airbyte_cdk/utils/docker_image_templates.py +101 -0
  25. {airbyte_cdk-6.45.10.dist-info → airbyte_cdk-6.46.0.dist-info}/METADATA +6 -1
  26. {airbyte_cdk-6.45.10.dist-info → airbyte_cdk-6.46.0.dist-info}/RECORD +30 -17
  27. {airbyte_cdk-6.45.10.dist-info → airbyte_cdk-6.46.0.dist-info}/entry_points.txt +1 -0
  28. {airbyte_cdk-6.45.10.dist-info → airbyte_cdk-6.46.0.dist-info}/LICENSE.txt +0 -0
  29. {airbyte_cdk-6.45.10.dist-info → airbyte_cdk-6.46.0.dist-info}/LICENSE_SHORT +0 -0
  30. {airbyte_cdk-6.45.10.dist-info → airbyte_cdk-6.46.0.dist-info}/WHEEL +0 -0
@@ -29,7 +29,9 @@ from airbyte_cdk.sources.declarative.declarative_source import DeclarativeSource
29
29
  from airbyte_cdk.sources.declarative.models.declarative_component_schema import (
30
30
  DeclarativeStream as DeclarativeStreamModel,
31
31
  )
32
- from airbyte_cdk.sources.declarative.models.declarative_component_schema import Spec as SpecModel
32
+ from airbyte_cdk.sources.declarative.models.declarative_component_schema import (
33
+ Spec as SpecModel,
34
+ )
33
35
  from airbyte_cdk.sources.declarative.models.declarative_component_schema import (
34
36
  StateDelegatingStream as StateDelegatingStreamModel,
35
37
  )
@@ -39,6 +41,9 @@ from airbyte_cdk.sources.declarative.parsers.custom_code_compiler import (
39
41
  from airbyte_cdk.sources.declarative.parsers.manifest_component_transformer import (
40
42
  ManifestComponentTransformer,
41
43
  )
44
+ from airbyte_cdk.sources.declarative.parsers.manifest_normalizer import (
45
+ ManifestNormalizer,
46
+ )
42
47
  from airbyte_cdk.sources.declarative.parsers.manifest_reference_resolver import (
43
48
  ManifestReferenceResolver,
44
49
  )
@@ -57,6 +62,24 @@ from airbyte_cdk.sources.utils.slice_logger import (
57
62
  from airbyte_cdk.utils.traced_exception import AirbyteTracedException
58
63
 
59
64
 
65
+ def _get_declarative_component_schema() -> Dict[str, Any]:
66
+ try:
67
+ raw_component_schema = pkgutil.get_data(
68
+ "airbyte_cdk", "sources/declarative/declarative_component_schema.yaml"
69
+ )
70
+ if raw_component_schema is not None:
71
+ declarative_component_schema = yaml.load(raw_component_schema, Loader=yaml.SafeLoader)
72
+ return declarative_component_schema # type: ignore
73
+ else:
74
+ raise RuntimeError(
75
+ "Failed to read manifest component json schema required for deduplication"
76
+ )
77
+ except FileNotFoundError as e:
78
+ raise FileNotFoundError(
79
+ f"Failed to read manifest component json schema required for deduplication: {e}"
80
+ )
81
+
82
+
60
83
  class ManifestDeclarativeSource(DeclarativeSource):
61
84
  """Declarative source defined by a manifest of low-code components that define source connector behavior"""
62
85
 
@@ -68,7 +91,8 @@ class ManifestDeclarativeSource(DeclarativeSource):
68
91
  debug: bool = False,
69
92
  emit_connector_builder_messages: bool = False,
70
93
  component_factory: Optional[ModelToComponentFactory] = None,
71
- ):
94
+ normalize_manifest: Optional[bool] = False,
95
+ ) -> None:
72
96
  """
73
97
  Args:
74
98
  config: The provided config dict.
@@ -76,21 +100,16 @@ class ManifestDeclarativeSource(DeclarativeSource):
76
100
  debug: True if debug mode is enabled.
77
101
  emit_connector_builder_messages: True if messages should be emitted to the connector builder.
78
102
  component_factory: optional factory if ModelToComponentFactory's default behavior needs to be tweaked.
103
+ normalize_manifest: Optional flag to indicate if the manifest should be normalized.
79
104
  """
80
105
  self.logger = logging.getLogger(f"airbyte.{self.name}")
81
- # For ease of use we don't require the type to be specified at the top level manifest, but it should be included during processing
82
- manifest = dict(source_config)
83
- if "type" not in manifest:
84
- manifest["type"] = "DeclarativeSource"
85
-
106
+ self._should_normalize = normalize_manifest
107
+ self._declarative_component_schema = _get_declarative_component_schema()
86
108
  # If custom components are needed, locate and/or register them.
87
109
  self.components_module: ModuleType | None = get_registered_components_module(config=config)
110
+ # resolve all components in the manifest
111
+ self._source_config = self._preprocess_manifest(dict(source_config))
88
112
 
89
- resolved_source_config = ManifestReferenceResolver().preprocess_manifest(manifest)
90
- propagated_source_config = ManifestComponentTransformer().propagate_types_and_parameters(
91
- "", resolved_source_config, {}
92
- )
93
- self._source_config = propagated_source_config
94
113
  self._debug = debug
95
114
  self._emit_connector_builder_messages = emit_connector_builder_messages
96
115
  self._constructor = (
@@ -105,14 +124,81 @@ class ManifestDeclarativeSource(DeclarativeSource):
105
124
  self._slice_logger: SliceLogger = (
106
125
  AlwaysLogSliceLogger() if emit_connector_builder_messages else DebugSliceLogger()
107
126
  )
108
-
109
127
  self._config = config or {}
128
+
129
+ # validate resolved manifest against the declarative component schema
110
130
  self._validate_source()
111
131
 
132
+ # apply additional post-processing to the manifest
133
+ self._postprocess_manifest()
134
+
112
135
  @property
113
136
  def resolved_manifest(self) -> Mapping[str, Any]:
137
+ """
138
+ Returns the resolved manifest configuration for the source.
139
+
140
+ This property provides access to the internal source configuration as a mapping,
141
+ which contains all settings and parameters required to define the source's behavior.
142
+
143
+ Returns:
144
+ Mapping[str, Any]: The resolved source configuration manifest.
145
+ """
114
146
  return self._source_config
115
147
 
148
+ def _preprocess_manifest(self, manifest: Dict[str, Any]) -> Dict[str, Any]:
149
+ """
150
+ Preprocesses the provided manifest dictionary by resolving any manifest references.
151
+
152
+ This method modifies the input manifest in place, resolving references using the
153
+ ManifestReferenceResolver to ensure all references within the manifest are properly handled.
154
+
155
+ Args:
156
+ manifest (Dict[str, Any]): The manifest dictionary to preprocess and resolve references in.
157
+
158
+ Returns:
159
+ None
160
+ """
161
+ # For ease of use we don't require the type to be specified at the top level manifest, but it should be included during processing
162
+ manifest = self._fix_source_type(manifest)
163
+ # Resolve references in the manifest
164
+ resolved_manifest = ManifestReferenceResolver().preprocess_manifest(manifest)
165
+ # Propagate types and parameters throughout the manifest
166
+ propagated_manifest = ManifestComponentTransformer().propagate_types_and_parameters(
167
+ "", resolved_manifest, {}
168
+ )
169
+
170
+ return propagated_manifest
171
+
172
+ def _postprocess_manifest(self) -> None:
173
+ """
174
+ Post-processes the manifest after validation.
175
+ This method is responsible for any additional modifications or transformations needed
176
+ after the manifest has been validated and before it is used in the source.
177
+ """
178
+ # apply manifest normalization, if required
179
+ self._normalize_manifest()
180
+
181
+ def _normalize_manifest(self) -> None:
182
+ """
183
+ This method is used to normalize the manifest. It should be called after the manifest has been validated.
184
+
185
+ Connector Builder UI rendering requires the manifest to be in a specific format.
186
+ - references have been resolved
187
+ - the commonly used definitions are extracted to the `definitions.linked.*`
188
+ """
189
+ if self._should_normalize:
190
+ normalizer = ManifestNormalizer(self._source_config, self._declarative_component_schema)
191
+ self._source_config = normalizer.normalize()
192
+
193
+ def _fix_source_type(self, manifest: Dict[str, Any]) -> Dict[str, Any]:
194
+ """
195
+ Fix the source type in the manifest. This is necessary because the source type is not always set in the manifest.
196
+ """
197
+ if "type" not in manifest:
198
+ manifest["type"] = "DeclarativeSource"
199
+
200
+ return manifest
201
+
116
202
  @property
117
203
  def message_repository(self) -> MessageRepository:
118
204
  return self._message_repository
@@ -120,7 +206,9 @@ class ManifestDeclarativeSource(DeclarativeSource):
120
206
  @property
121
207
  def dynamic_streams(self) -> List[Dict[str, Any]]:
122
208
  return self._dynamic_stream_configs(
123
- manifest=self._source_config, config=self._config, with_dynamic_stream_name=True
209
+ manifest=self._source_config,
210
+ config=self._config,
211
+ with_dynamic_stream_name=True,
124
212
  )
125
213
 
126
214
  @property
@@ -143,7 +231,10 @@ class ManifestDeclarativeSource(DeclarativeSource):
143
231
 
144
232
  def streams(self, config: Mapping[str, Any]) -> List[Stream]:
145
233
  self._emit_manifest_debug_message(
146
- extra_args={"source_name": self.name, "parsed_config": json.dumps(self._source_config)}
234
+ extra_args={
235
+ "source_name": self.name,
236
+ "parsed_config": json.dumps(self._source_config),
237
+ }
147
238
  )
148
239
 
149
240
  stream_configs = self._stream_configs(self._source_config) + self._dynamic_stream_configs(
@@ -156,9 +247,11 @@ class ManifestDeclarativeSource(DeclarativeSource):
156
247
 
157
248
  source_streams = [
158
249
  self._constructor.create_component(
159
- StateDelegatingStreamModel
160
- if stream_config.get("type") == StateDelegatingStreamModel.__name__
161
- else DeclarativeStreamModel,
250
+ (
251
+ StateDelegatingStreamModel
252
+ if stream_config.get("type") == StateDelegatingStreamModel.__name__
253
+ else DeclarativeStreamModel
254
+ ),
162
255
  stream_config,
163
256
  config,
164
257
  emit_connector_builder_messages=self._emit_connector_builder_messages,
@@ -174,7 +267,9 @@ class ManifestDeclarativeSource(DeclarativeSource):
174
267
  ) -> List[Dict[str, Any]]:
175
268
  parent_streams = set()
176
269
 
177
- def update_with_cache_parent_configs(parent_configs: list[dict[str, Any]]) -> None:
270
+ def update_with_cache_parent_configs(
271
+ parent_configs: list[dict[str, Any]],
272
+ ) -> None:
178
273
  for parent_config in parent_configs:
179
274
  parent_streams.add(parent_config["stream"]["name"])
180
275
  if parent_config["stream"]["type"] == "StateDelegatingStream":
@@ -229,7 +324,10 @@ class ManifestDeclarativeSource(DeclarativeSource):
229
324
  """
230
325
  self._configure_logger_level(logger)
231
326
  self._emit_manifest_debug_message(
232
- extra_args={"source_name": self.name, "parsed_config": json.dumps(self._source_config)}
327
+ extra_args={
328
+ "source_name": self.name,
329
+ "parsed_config": json.dumps(self._source_config),
330
+ }
233
331
  )
234
332
 
235
333
  spec = self._source_config.get("spec")
@@ -266,32 +364,9 @@ class ManifestDeclarativeSource(DeclarativeSource):
266
364
  """
267
365
  Validates the connector manifest against the declarative component schema
268
366
  """
269
- try:
270
- raw_component_schema = pkgutil.get_data(
271
- "airbyte_cdk", "sources/declarative/declarative_component_schema.yaml"
272
- )
273
- if raw_component_schema is not None:
274
- declarative_component_schema = yaml.load(
275
- raw_component_schema, Loader=yaml.SafeLoader
276
- )
277
- else:
278
- raise RuntimeError(
279
- "Failed to read manifest component json schema required for validation"
280
- )
281
- except FileNotFoundError as e:
282
- raise FileNotFoundError(
283
- f"Failed to read manifest component json schema required for validation: {e}"
284
- )
285
-
286
- streams = self._source_config.get("streams")
287
- dynamic_streams = self._source_config.get("dynamic_streams")
288
- if not (streams or dynamic_streams):
289
- raise ValidationError(
290
- f"A valid manifest should have at least one stream defined. Got {streams}"
291
- )
292
367
 
293
368
  try:
294
- validate(self._source_config, declarative_component_schema)
369
+ validate(self._source_config, self._declarative_component_schema)
295
370
  except ValidationError as e:
296
371
  raise ValidationError(
297
372
  "Validation against json schema defined in declarative_component_schema.yaml schema failed"
@@ -389,7 +464,9 @@ class ManifestDeclarativeSource(DeclarativeSource):
389
464
 
390
465
  # Create a resolver for dynamic components based on type
391
466
  components_resolver = self._constructor.create_component(
392
- COMPONENTS_RESOLVER_TYPE_MAPPING[resolver_type], components_resolver_config, config
467
+ COMPONENTS_RESOLVER_TYPE_MAPPING[resolver_type],
468
+ components_resolver_config,
469
+ config,
393
470
  )
394
471
 
395
472
  stream_template_config = dynamic_definition["stream_template"]