airbyte-cdk 6.29.0__py3-none-any.whl → 6.29.1__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.
@@ -22,6 +22,9 @@ from airbyte_cdk.sources.streams.checkpoint.per_partition_key_serializer import
22
22
  )
23
23
  from airbyte_cdk.sources.streams.concurrent.cursor import ConcurrentCursor, Cursor, CursorField
24
24
  from airbyte_cdk.sources.streams.concurrent.partitions.partition import Partition
25
+ from airbyte_cdk.sources.streams.concurrent.state_converters.abstract_stream_state_converter import (
26
+ AbstractStreamStateConverter,
27
+ )
25
28
  from airbyte_cdk.sources.types import Record, StreamSlice, StreamState
26
29
 
27
30
  logger = logging.getLogger("airbyte")
@@ -72,6 +75,7 @@ class ConcurrentPerPartitionCursor(Cursor):
72
75
  stream_state: Any,
73
76
  message_repository: MessageRepository,
74
77
  connector_state_manager: ConnectorStateManager,
78
+ connector_state_converter: AbstractStreamStateConverter,
75
79
  cursor_field: CursorField,
76
80
  ) -> None:
77
81
  self._global_cursor: Optional[StreamState] = {}
@@ -79,6 +83,7 @@ class ConcurrentPerPartitionCursor(Cursor):
79
83
  self._stream_namespace = stream_namespace
80
84
  self._message_repository = message_repository
81
85
  self._connector_state_manager = connector_state_manager
86
+ self._connector_state_converter = connector_state_converter
82
87
  self._cursor_field = cursor_field
83
88
 
84
89
  self._cursor_factory = cursor_factory
@@ -301,8 +306,7 @@ class ConcurrentPerPartitionCursor(Cursor):
301
306
  ):
302
307
  # We assume that `stream_state` is in a global format that can be applied to all partitions.
303
308
  # Example: {"global_state_format_key": "global_state_format_value"}
304
- self._global_cursor = deepcopy(stream_state)
305
- self._new_global_cursor = deepcopy(stream_state)
309
+ self._set_global_state(stream_state)
306
310
 
307
311
  else:
308
312
  self._use_global_cursor = stream_state.get("use_global_cursor", False)
@@ -319,8 +323,7 @@ class ConcurrentPerPartitionCursor(Cursor):
319
323
 
320
324
  # set default state for missing partitions if it is per partition with fallback to global
321
325
  if self._GLOBAL_STATE_KEY in stream_state:
322
- self._global_cursor = deepcopy(stream_state[self._GLOBAL_STATE_KEY])
323
- self._new_global_cursor = deepcopy(stream_state[self._GLOBAL_STATE_KEY])
326
+ self._set_global_state(stream_state[self._GLOBAL_STATE_KEY])
324
327
 
325
328
  # Set initial parent state
326
329
  if stream_state.get("parent_state"):
@@ -329,6 +332,27 @@ class ConcurrentPerPartitionCursor(Cursor):
329
332
  # Set parent state for partition routers based on parent streams
330
333
  self._partition_router.set_initial_state(stream_state)
331
334
 
335
+ def _set_global_state(self, stream_state: Mapping[str, Any]) -> None:
336
+ """
337
+ Initializes the global cursor state from the provided stream state.
338
+
339
+ If the cursor field key is present in the stream state, its value is parsed,
340
+ formatted, and stored as the global cursor. This ensures consistency in state
341
+ representation across partitions.
342
+ """
343
+ if self.cursor_field.cursor_field_key in stream_state:
344
+ global_state_value = stream_state[self.cursor_field.cursor_field_key]
345
+ final_format_global_state_value = self._connector_state_converter.output_format(
346
+ self._connector_state_converter.parse_value(global_state_value)
347
+ )
348
+
349
+ fixed_global_state = {
350
+ self.cursor_field.cursor_field_key: final_format_global_state_value
351
+ }
352
+
353
+ self._global_cursor = deepcopy(fixed_global_state)
354
+ self._new_global_cursor = deepcopy(fixed_global_state)
355
+
332
356
  def observe(self, record: Record) -> None:
333
357
  if not self._use_global_cursor and self.limit_reached():
334
358
  self._use_global_cursor = True
@@ -1210,6 +1210,22 @@ class ModelToComponentFactory:
1210
1210
  )
1211
1211
  cursor_field = CursorField(interpolated_cursor_field.eval(config=config))
1212
1212
 
1213
+ datetime_format = datetime_based_cursor_model.datetime_format
1214
+
1215
+ cursor_granularity = (
1216
+ parse_duration(datetime_based_cursor_model.cursor_granularity)
1217
+ if datetime_based_cursor_model.cursor_granularity
1218
+ else None
1219
+ )
1220
+
1221
+ connector_state_converter: DateTimeStreamStateConverter
1222
+ connector_state_converter = CustomFormatConcurrentStreamStateConverter(
1223
+ datetime_format=datetime_format,
1224
+ input_datetime_formats=datetime_based_cursor_model.cursor_datetime_formats,
1225
+ is_sequential_state=True, # ConcurrentPerPartitionCursor only works with sequential state
1226
+ cursor_granularity=cursor_granularity,
1227
+ )
1228
+
1213
1229
  # Create the cursor factory
1214
1230
  cursor_factory = ConcurrentCursorFactory(
1215
1231
  partial(
@@ -1233,6 +1249,7 @@ class ModelToComponentFactory:
1233
1249
  stream_state=stream_state,
1234
1250
  message_repository=self._message_repository, # type: ignore
1235
1251
  connector_state_manager=state_manager,
1252
+ connector_state_converter=connector_state_converter,
1236
1253
  cursor_field=cursor_field,
1237
1254
  )
1238
1255
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: airbyte-cdk
3
- Version: 6.29.0
3
+ Version: 6.29.1
4
4
  Summary: A framework for writing Airbyte Connectors.
5
5
  Home-page: https://airbyte.com
6
6
  License: MIT
@@ -88,7 +88,7 @@ airbyte_cdk/sources/declarative/extractors/record_selector.py,sha256=tjNwcURmlyD
88
88
  airbyte_cdk/sources/declarative/extractors/response_to_file_extractor.py,sha256=LhqGDfX06_dDYLKsIVnwQ_nAWCln-v8PV7Wgt_QVeTI,6533
89
89
  airbyte_cdk/sources/declarative/extractors/type_transformer.py,sha256=d6Y2Rfg8pMVEEnHllfVksWZdNVOU55yk34O03dP9muY,1626
90
90
  airbyte_cdk/sources/declarative/incremental/__init__.py,sha256=U1oZKtBaEC6IACmvziY9Wzg7Z8EgF4ZuR7NwvjlB_Sk,1255
91
- airbyte_cdk/sources/declarative/incremental/concurrent_partition_cursor.py,sha256=ndUZaPW0MsN4_3cGpB-0Uu0otSPnmPmHgbixoJeDmjA,16660
91
+ airbyte_cdk/sources/declarative/incremental/concurrent_partition_cursor.py,sha256=5dbO47TFmC5Oz8TZ8DKXwXeZElz70xy2v2HJlZr5qVs,17751
92
92
  airbyte_cdk/sources/declarative/incremental/datetime_based_cursor.py,sha256=_UzUnSIUsDbRgbFTXgSyZEFb4ws-KdhdQPWO8mFbV7U,22028
93
93
  airbyte_cdk/sources/declarative/incremental/declarative_cursor.py,sha256=5Bhw9VRPyIuCaD0wmmq_L3DZsa-rJgtKSEUzSd8YYD0,536
94
94
  airbyte_cdk/sources/declarative/incremental/global_substream_cursor.py,sha256=9HO-QbL9akvjq2NP7l498RwLA4iQZlBMQW1tZbt34I8,15943
@@ -115,7 +115,7 @@ airbyte_cdk/sources/declarative/parsers/custom_code_compiler.py,sha256=958MMX6_Z
115
115
  airbyte_cdk/sources/declarative/parsers/custom_exceptions.py,sha256=Rir9_z3Kcd5Es0-LChrzk-0qubAsiK_RSEnLmK2OXm8,553
116
116
  airbyte_cdk/sources/declarative/parsers/manifest_component_transformer.py,sha256=CXwTfD3wSQq3okcqwigpprbHhSURUokh4GK2OmOyKC8,9132
117
117
  airbyte_cdk/sources/declarative/parsers/manifest_reference_resolver.py,sha256=IWUOdF03o-aQn0Occo1BJCxU0Pz-QILk5L67nzw2thw,6803
118
- airbyte_cdk/sources/declarative/parsers/model_to_component_factory.py,sha256=y4Yd9ik37vUkN3Jw54BkcCYv4UAT0QtBLfwtqPxDPYc,125491
118
+ airbyte_cdk/sources/declarative/parsers/model_to_component_factory.py,sha256=RzJ4rA4Gb8IhfkSHki19JyDzy0ICf31mCnM0YAy7c8g,126270
119
119
  airbyte_cdk/sources/declarative/partition_routers/__init__.py,sha256=HJ-Syp3p7RpyR_OK0X_a2kSyISfu3W-PKrRI16iY0a8,957
120
120
  airbyte_cdk/sources/declarative/partition_routers/async_job_partition_router.py,sha256=n82J15S8bjeMZ5uROu--P3hnbQoxkY5v7RPHYx7g7ro,2929
121
121
  airbyte_cdk/sources/declarative/partition_routers/cartesian_product_stream_slicer.py,sha256=c5cuVFM6NFkuQqG8Z5IwkBuwDrvXZN1CunUOM_L0ezg,6892
@@ -351,9 +351,9 @@ airbyte_cdk/utils/slice_hasher.py,sha256=EDxgROHDbfG-QKQb59m7h_7crN1tRiawdf5uU7G
351
351
  airbyte_cdk/utils/spec_schema_transformations.py,sha256=-5HTuNsnDBAhj-oLeQXwpTGA0HdcjFOf2zTEMUTTg_Y,816
352
352
  airbyte_cdk/utils/stream_status_utils.py,sha256=ZmBoiy5HVbUEHAMrUONxZvxnvfV9CesmQJLDTAIWnWw,1171
353
353
  airbyte_cdk/utils/traced_exception.py,sha256=C8uIBuCL_E4WnBAOPSxBicD06JAldoN9fGsQDp463OY,6292
354
- airbyte_cdk-6.29.0.dist-info/LICENSE.txt,sha256=Wfe61S4BaGPj404v8lrAbvhjYR68SHlkzeYrg3_bbuM,1051
355
- airbyte_cdk-6.29.0.dist-info/LICENSE_SHORT,sha256=aqF6D1NcESmpn-cqsxBtszTEnHKnlsp8L4x9wAh3Nxg,55
356
- airbyte_cdk-6.29.0.dist-info/METADATA,sha256=tBDu8ziyLjbzMqhfeqrkGFrLUjglWxY_Ga7NuDQBkBE,6010
357
- airbyte_cdk-6.29.0.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
358
- airbyte_cdk-6.29.0.dist-info/entry_points.txt,sha256=fj-e3PAQvsxsQzyyq8UkG1k8spunWnD4BAH2AwlR6NM,95
359
- airbyte_cdk-6.29.0.dist-info/RECORD,,
354
+ airbyte_cdk-6.29.1.dist-info/LICENSE.txt,sha256=Wfe61S4BaGPj404v8lrAbvhjYR68SHlkzeYrg3_bbuM,1051
355
+ airbyte_cdk-6.29.1.dist-info/LICENSE_SHORT,sha256=aqF6D1NcESmpn-cqsxBtszTEnHKnlsp8L4x9wAh3Nxg,55
356
+ airbyte_cdk-6.29.1.dist-info/METADATA,sha256=EXtPEYGpJtpVTZV9Q5pg_Ur4VDFNc2c_KxuVt4d0A80,6010
357
+ airbyte_cdk-6.29.1.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
358
+ airbyte_cdk-6.29.1.dist-info/entry_points.txt,sha256=fj-e3PAQvsxsQzyyq8UkG1k8spunWnD4BAH2AwlR6NM,95
359
+ airbyte_cdk-6.29.1.dist-info/RECORD,,