airbyte-cdk 6.7.3.dev1__py3-none-any.whl → 6.8.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.
airbyte_cdk/entrypoint.py CHANGED
@@ -15,8 +15,8 @@ from functools import wraps
15
15
  from typing import Any, DefaultDict, Iterable, List, Mapping, Optional
16
16
  from urllib.parse import urlparse
17
17
 
18
+ import orjson
18
19
  import requests
19
- from orjson import orjson
20
20
  from requests import PreparedRequest, Response, Session
21
21
 
22
22
  from airbyte_cdk.connector import TConfig
@@ -129,7 +129,11 @@ class AirbyteEntrypoint(object):
129
129
 
130
130
  source_spec: ConnectorSpecification = self.source.spec(self.logger)
131
131
  try:
132
- with tempfile.TemporaryDirectory() as temp_dir:
132
+ with tempfile.TemporaryDirectory(
133
+ # Cleanup can fail on Windows due to file locks. Ignore if so,
134
+ # rather than failing the whole process.
135
+ ignore_cleanup_errors=True,
136
+ ) as temp_dir:
133
137
  os.environ[ENV_REQUEST_CACHE_PATH] = (
134
138
  temp_dir # set this as default directory for request_cache to store *.sqlite files
135
139
  )
@@ -246,12 +250,18 @@ class AirbyteEntrypoint(object):
246
250
  ) -> AirbyteMessage:
247
251
  match message.type:
248
252
  case Type.RECORD:
253
+ if message.record is None:
254
+ raise ValueError("Record message must have a record attribute")
255
+
249
256
  stream_message_count[
250
257
  HashableStreamDescriptor(
251
258
  name=message.record.stream, namespace=message.record.namespace
252
259
  )
253
260
  ] += 1.0 # type: ignore[union-attr] # record has `stream` and `namespace`
254
261
  case Type.STATE:
262
+ if message.state is None:
263
+ raise ValueError("State message must have a state attribute")
264
+
255
265
  stream_descriptor = message_utils.get_stream_descriptor(message)
256
266
 
257
267
  # Set record count from the counter onto the state message
@@ -200,7 +200,11 @@ class ConcurrentDeclarativeSource(ManifestDeclarativeSource, Generic[TState]):
200
200
  # Some low-code sources use a combination of DeclarativeStream and regular Python streams. We can't inspect
201
201
  # these legacy Python streams the way we do low-code streams to determine if they are concurrent compatible,
202
202
  # so we need to treat them as synchronous
203
- if isinstance(declarative_stream, DeclarativeStream):
203
+ if (
204
+ isinstance(declarative_stream, DeclarativeStream)
205
+ and name_to_stream_mapping[declarative_stream.name].get("retriever")["type"]
206
+ == "SimpleRetriever"
207
+ ):
204
208
  incremental_sync_component_definition = name_to_stream_mapping[
205
209
  declarative_stream.name
206
210
  ].get("incremental_sync")
@@ -210,36 +214,30 @@ class ConcurrentDeclarativeSource(ManifestDeclarativeSource, Generic[TState]):
210
214
  .get("retriever")
211
215
  .get("partition_router")
212
216
  )
217
+ is_without_partition_router_or_cursor = not bool(
218
+ incremental_sync_component_definition
219
+ ) and not bool(partition_router_component_definition)
213
220
 
214
221
  is_substream_without_incremental = (
215
222
  partition_router_component_definition
216
223
  and not incremental_sync_component_definition
217
224
  )
218
225
 
219
- if (
220
- incremental_sync_component_definition
221
- and incremental_sync_component_definition.get("type", "")
222
- == DatetimeBasedCursorModel.__name__
223
- and self._stream_supports_concurrent_partition_processing(
224
- declarative_stream=declarative_stream
225
- )
226
- and hasattr(declarative_stream.retriever, "stream_slicer")
227
- and isinstance(declarative_stream.retriever.stream_slicer, DatetimeBasedCursor)
226
+ if self._is_datetime_incremental_without_partition_routing(
227
+ declarative_stream, incremental_sync_component_definition
228
228
  ):
229
229
  stream_state = state_manager.get_stream_state(
230
230
  stream_name=declarative_stream.name, namespace=declarative_stream.namespace
231
231
  )
232
232
 
233
- cursor, connector_state_converter = (
234
- self._constructor.create_concurrent_cursor_from_datetime_based_cursor(
235
- state_manager=state_manager,
236
- model_type=DatetimeBasedCursorModel,
237
- component_definition=incremental_sync_component_definition,
238
- stream_name=declarative_stream.name,
239
- stream_namespace=declarative_stream.namespace,
240
- config=config or {},
241
- stream_state=stream_state,
242
- )
233
+ cursor = self._constructor.create_concurrent_cursor_from_datetime_based_cursor(
234
+ state_manager=state_manager,
235
+ model_type=DatetimeBasedCursorModel,
236
+ component_definition=incremental_sync_component_definition,
237
+ stream_name=declarative_stream.name,
238
+ stream_namespace=declarative_stream.namespace,
239
+ config=config or {},
240
+ stream_state=stream_state,
243
241
  )
244
242
 
245
243
  partition_generator = StreamSlicerPartitionGenerator(
@@ -263,14 +261,19 @@ class ConcurrentDeclarativeSource(ManifestDeclarativeSource, Generic[TState]):
263
261
  json_schema=declarative_stream.get_json_schema(),
264
262
  availability_strategy=AlwaysAvailableAvailabilityStrategy(),
265
263
  primary_key=get_primary_key_from_stream(declarative_stream.primary_key),
266
- cursor_field=cursor.cursor_field.cursor_field_key,
264
+ cursor_field=cursor.cursor_field.cursor_field_key
265
+ if hasattr(cursor, "cursor_field")
266
+ and hasattr(
267
+ cursor.cursor_field, "cursor_field_key"
268
+ ) # FIXME this will need to be updated once we do the per partition
269
+ else None,
267
270
  logger=self.logger,
268
271
  cursor=cursor,
269
272
  )
270
273
  )
271
- elif is_substream_without_incremental and hasattr(
272
- declarative_stream.retriever, "stream_slicer"
273
- ):
274
+ elif (
275
+ is_substream_without_incremental or is_without_partition_router_or_cursor
276
+ ) and hasattr(declarative_stream.retriever, "stream_slicer"):
274
277
  partition_generator = StreamSlicerPartitionGenerator(
275
278
  DeclarativePartitionFactory(
276
279
  declarative_stream.name,
@@ -310,6 +313,22 @@ class ConcurrentDeclarativeSource(ManifestDeclarativeSource, Generic[TState]):
310
313
 
311
314
  return concurrent_streams, synchronous_streams
312
315
 
316
+ def _is_datetime_incremental_without_partition_routing(
317
+ self,
318
+ declarative_stream: DeclarativeStream,
319
+ incremental_sync_component_definition: Mapping[str, Any],
320
+ ) -> bool:
321
+ return (
322
+ bool(incremental_sync_component_definition)
323
+ and incremental_sync_component_definition.get("type", "")
324
+ == DatetimeBasedCursorModel.__name__
325
+ and self._stream_supports_concurrent_partition_processing(
326
+ declarative_stream=declarative_stream
327
+ )
328
+ and hasattr(declarative_stream.retriever, "stream_slicer")
329
+ and isinstance(declarative_stream.retriever.stream_slicer, DatetimeBasedCursor)
330
+ )
331
+
313
332
  def _stream_supports_concurrent_partition_processing(
314
333
  self, declarative_stream: DeclarativeStream
315
334
  ) -> bool:
@@ -17,7 +17,6 @@ from typing import (
17
17
  Mapping,
18
18
  MutableMapping,
19
19
  Optional,
20
- Tuple,
21
20
  Type,
22
21
  Union,
23
22
  get_args,
@@ -760,7 +759,7 @@ class ModelToComponentFactory:
760
759
  config: Config,
761
760
  stream_state: MutableMapping[str, Any],
762
761
  **kwargs: Any,
763
- ) -> Tuple[ConcurrentCursor, DateTimeStreamStateConverter]:
762
+ ) -> ConcurrentCursor:
764
763
  component_type = component_definition.get("type")
765
764
  if component_definition.get("type") != model_type.__name__:
766
765
  raise ValueError(
@@ -891,23 +890,20 @@ class ModelToComponentFactory:
891
890
  if evaluated_step:
892
891
  step_length = parse_duration(evaluated_step)
893
892
 
894
- return (
895
- ConcurrentCursor(
896
- stream_name=stream_name,
897
- stream_namespace=stream_namespace,
898
- stream_state=stream_state,
899
- message_repository=self._message_repository, # type: ignore # message_repository is always instantiated with a value by factory
900
- connector_state_manager=state_manager,
901
- connector_state_converter=connector_state_converter,
902
- cursor_field=cursor_field,
903
- slice_boundary_fields=slice_boundary_fields,
904
- start=start_date, # type: ignore # Having issues w/ inspection for GapType and CursorValueType as shown in existing tests. Confirmed functionality is working in practice
905
- end_provider=end_date_provider, # type: ignore # Having issues w/ inspection for GapType and CursorValueType as shown in existing tests. Confirmed functionality is working in practice
906
- lookback_window=lookback_window,
907
- slice_range=step_length,
908
- cursor_granularity=cursor_granularity,
909
- ),
910
- connector_state_converter,
893
+ return ConcurrentCursor(
894
+ stream_name=stream_name,
895
+ stream_namespace=stream_namespace,
896
+ stream_state=stream_state,
897
+ message_repository=self._message_repository, # type: ignore # message_repository is always instantiated with a value by factory
898
+ connector_state_manager=state_manager,
899
+ connector_state_converter=connector_state_converter,
900
+ cursor_field=cursor_field,
901
+ slice_boundary_fields=slice_boundary_fields,
902
+ start=start_date, # type: ignore # Having issues w/ inspection for GapType and CursorValueType as shown in existing tests. Confirmed functionality is working in practice
903
+ end_provider=end_date_provider, # type: ignore # Having issues w/ inspection for GapType and CursorValueType as shown in existing tests. Confirmed functionality is working in practice
904
+ lookback_window=lookback_window,
905
+ slice_range=step_length,
906
+ cursor_granularity=cursor_granularity,
911
907
  )
912
908
 
913
909
  @staticmethod
@@ -13,8 +13,15 @@ def get_primary_key_from_stream(
13
13
  elif isinstance(stream_primary_key, str):
14
14
  return [stream_primary_key]
15
15
  elif isinstance(stream_primary_key, list):
16
- if len(stream_primary_key) > 0 and all(isinstance(k, str) for k in stream_primary_key):
16
+ are_all_elements_str = all(isinstance(k, str) for k in stream_primary_key)
17
+ are_all_elements_list_of_size_one = all(
18
+ isinstance(k, list) and len(k) == 1 for k in stream_primary_key
19
+ )
20
+
21
+ if are_all_elements_str:
17
22
  return stream_primary_key # type: ignore # We verified all items in the list are strings
23
+ elif are_all_elements_list_of_size_one:
24
+ return list(map(lambda x: x[0], stream_primary_key))
18
25
  else:
19
26
  raise ValueError(f"Nested primary keys are not supported. Found {stream_primary_key}")
20
27
  else:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: airbyte-cdk
3
- Version: 6.7.3.dev1
3
+ Version: 6.8.0
4
4
  Summary: A framework for writing Airbyte Connectors.
5
5
  Home-page: https://airbyte.com
6
6
  License: MIT
@@ -22,7 +22,7 @@ airbyte_cdk/destinations/vector_db_based/indexer.py,sha256=beiSi2Uu67EoTr7yQSaCJ
22
22
  airbyte_cdk/destinations/vector_db_based/test_utils.py,sha256=MkqLiOJ5QyKbV4rNiJhe-BHM7FD-ADHQ4bQGf4c5lRY,1932
23
23
  airbyte_cdk/destinations/vector_db_based/utils.py,sha256=FOyEo8Lc-fY8UyhpCivhZtIqBRyxf3cUt6anmK03fUY,1127
24
24
  airbyte_cdk/destinations/vector_db_based/writer.py,sha256=nPj1DtZ1-tkEBAz7Ape1FZz_YDQNXPceUyCoviVq3Fk,4525
25
- airbyte_cdk/entrypoint.py,sha256=B0kd8NWYs6pFDC75OoPxiGNcIh9jZDnU9qIVvtOQsNE,17605
25
+ airbyte_cdk/entrypoint.py,sha256=eG-SfN4PfvkbVLfZMCPI21QAJwox6e2RMr_xN__p-gA,18039
26
26
  airbyte_cdk/exception_handler.py,sha256=D_doVl3Dt60ASXlJsfviOCswxGyKF2q0RL6rif3fNks,2013
27
27
  airbyte_cdk/logger.py,sha256=ckavMoaV-p0rxQANyrRynVw8eysO7ZNoCGfKzHNYNB8,3758
28
28
  airbyte_cdk/models/__init__.py,sha256=5n8LEEQviDBmdZQPG4vnccWgsKpS4Q4L8MI7LUfIEsY,2051
@@ -62,7 +62,7 @@ airbyte_cdk/sources/declarative/checks/check_stream.py,sha256=dAA-UhmMj0WLXCkRQr
62
62
  airbyte_cdk/sources/declarative/checks/connection_checker.py,sha256=MBRJo6WJlZQHpIfOGaNOkkHUmgUl_4wDM6VPo41z5Ss,1383
63
63
  airbyte_cdk/sources/declarative/concurrency_level/__init__.py,sha256=5XUqrmlstYlMM0j6crktlKQwALek0uiz2D3WdM46MyA,191
64
64
  airbyte_cdk/sources/declarative/concurrency_level/concurrency_level.py,sha256=YIwCTCpOr_QSNW4ltQK0yUGWInI8PKNY216HOOegYLk,2101
65
- airbyte_cdk/sources/declarative/concurrent_declarative_source.py,sha256=k2rHM3FIyoRUCZ7egwO36gd9fyX_J1ZokfAtpVzNvac,22641
65
+ airbyte_cdk/sources/declarative/concurrent_declarative_source.py,sha256=4bpS63fz2K4mLPF33eG1xXgGRzzjjBAvpgDbiDrIs_Q,23549
66
66
  airbyte_cdk/sources/declarative/datetime/__init__.py,sha256=l9LG7Qm6e5r_qgqfVKnx3mXYtg1I9MmMjomVIPfU4XA,177
67
67
  airbyte_cdk/sources/declarative/datetime/datetime_parser.py,sha256=SX9JjdesN1edN2WVUVMzU_ptqp2QB1OnsnjZ4mwcX7w,2579
68
68
  airbyte_cdk/sources/declarative/datetime/min_max_datetime.py,sha256=8VZJP18eJLabSPP1XBSPDaagUBG6q1ynIiPJy3rE2mc,5344
@@ -109,7 +109,7 @@ airbyte_cdk/sources/declarative/parsers/__init__.py,sha256=ZnqYNxHsKCgO38IwB34RQ
109
109
  airbyte_cdk/sources/declarative/parsers/custom_exceptions.py,sha256=Rir9_z3Kcd5Es0-LChrzk-0qubAsiK_RSEnLmK2OXm8,553
110
110
  airbyte_cdk/sources/declarative/parsers/manifest_component_transformer.py,sha256=jVZ3ZV5YZrmDNIX5cM2mugXmnbH27zHRcD22_3oatpo,8454
111
111
  airbyte_cdk/sources/declarative/parsers/manifest_reference_resolver.py,sha256=IWUOdF03o-aQn0Occo1BJCxU0Pz-QILk5L67nzw2thw,6803
112
- airbyte_cdk/sources/declarative/parsers/model_to_component_factory.py,sha256=-1J_fjk3XQB42ApcpJEZmu5EqHiGmw5e1i42iGVmCWI,96909
112
+ airbyte_cdk/sources/declarative/parsers/model_to_component_factory.py,sha256=dvTPT7v_BlLZTLTPV6Uf9B5A5PnJ4mUgUeaxLzoMJBg,96741
113
113
  airbyte_cdk/sources/declarative/partition_routers/__init__.py,sha256=8uGos2u7TFTx_EJBdcjdUGn3Eyx6jUuEa1_VB8UP_dI,631
114
114
  airbyte_cdk/sources/declarative/partition_routers/cartesian_product_stream_slicer.py,sha256=c5cuVFM6NFkuQqG8Z5IwkBuwDrvXZN1CunUOM_L0ezg,6892
115
115
  airbyte_cdk/sources/declarative/partition_routers/list_partition_router.py,sha256=t7pRdFWfFWJtQQG19c9PVeMODyO2BknRTakpM5U9N-8,4844
@@ -248,7 +248,7 @@ airbyte_cdk/sources/streams/concurrent/availability_strategy.py,sha256=xqErZU9v9
248
248
  airbyte_cdk/sources/streams/concurrent/cursor.py,sha256=JX1MEtQZzRhYlr8wghBd5uC5geO7_Xh2aA4wIFDLE8s,20897
249
249
  airbyte_cdk/sources/streams/concurrent/default_stream.py,sha256=K3rLMpYhS7nnmvwQ52lqBy7DQdFMJpvvT7sgBg_ckA8,3207
250
250
  airbyte_cdk/sources/streams/concurrent/exceptions.py,sha256=JOZ446MCLpmF26r9KfS6OO_6rGjcjgJNZdcw6jccjEI,468
251
- airbyte_cdk/sources/streams/concurrent/helpers.py,sha256=gtj9p0clZwgnClrIRH6V2Wl0Jwu11Plq-9FP4FU2VQA,1327
251
+ airbyte_cdk/sources/streams/concurrent/helpers.py,sha256=S6AW8TgIASCZ2UuUcQLE8OzgYUHWt2-KPOvNPwnQf-Q,1596
252
252
  airbyte_cdk/sources/streams/concurrent/partition_enqueuer.py,sha256=2t64b_z9cEPmlHZnjSiMTO8PEtEdiAJDG0JcYOtUqAE,3363
253
253
  airbyte_cdk/sources/streams/concurrent/partition_reader.py,sha256=0TIrjbTzYJGdA0AZUzbeIKr0iHbawnoEKVl7bWxOFZY,1760
254
254
  airbyte_cdk/sources/streams/concurrent/partitions/__init__.py,sha256=4Hw-PX1-VgESLF16cDdvuYCzGJtHntThLF4qIiULWeo,61
@@ -330,8 +330,8 @@ airbyte_cdk/utils/slice_hasher.py,sha256=-pHexlNYoWYPnXNH-M7HEbjmeJe9Zk7SJijdQ7d
330
330
  airbyte_cdk/utils/spec_schema_transformations.py,sha256=LVc9KbtMeV_z99jWo0Ou8u4l6eBJ0BWNhxj4zrrGKRs,763
331
331
  airbyte_cdk/utils/stream_status_utils.py,sha256=ZmBoiy5HVbUEHAMrUONxZvxnvfV9CesmQJLDTAIWnWw,1171
332
332
  airbyte_cdk/utils/traced_exception.py,sha256=a6q51tBS3IdtefuOiL1eBwSmnNAXfjFMlMjSIQ_Tl-o,6165
333
- airbyte_cdk-6.7.3.dev1.dist-info/LICENSE.txt,sha256=Wfe61S4BaGPj404v8lrAbvhjYR68SHlkzeYrg3_bbuM,1051
334
- airbyte_cdk-6.7.3.dev1.dist-info/METADATA,sha256=_EJlHPoz3B-1HtLZTtlz3taug65WtZF6gKmI-VVU2FM,13524
335
- airbyte_cdk-6.7.3.dev1.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
336
- airbyte_cdk-6.7.3.dev1.dist-info/entry_points.txt,sha256=fj-e3PAQvsxsQzyyq8UkG1k8spunWnD4BAH2AwlR6NM,95
337
- airbyte_cdk-6.7.3.dev1.dist-info/RECORD,,
333
+ airbyte_cdk-6.8.0.dist-info/LICENSE.txt,sha256=Wfe61S4BaGPj404v8lrAbvhjYR68SHlkzeYrg3_bbuM,1051
334
+ airbyte_cdk-6.8.0.dist-info/METADATA,sha256=ITCA7CjjzLnu4ioCSKaa6O7DUBKEGRBh_FkvkAI-PMs,13519
335
+ airbyte_cdk-6.8.0.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
336
+ airbyte_cdk-6.8.0.dist-info/entry_points.txt,sha256=fj-e3PAQvsxsQzyyq8UkG1k8spunWnD4BAH2AwlR6NM,95
337
+ airbyte_cdk-6.8.0.dist-info/RECORD,,