airbyte-cdk 6.45.1.post47.dev14456468218__py3-none-any.whl → 6.45.2.post3.dev14463482961__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 (32) hide show
  1. airbyte_cdk/connector_builder/connector_builder_handler.py +3 -1
  2. airbyte_cdk/connector_builder/test_reader/reader.py +3 -1
  3. airbyte_cdk/models/__init__.py +0 -1
  4. airbyte_cdk/models/airbyte_protocol.py +3 -1
  5. airbyte_cdk/models/file_transfer_record_message.py +13 -0
  6. airbyte_cdk/sources/concurrent_source/concurrent_read_processor.py +1 -1
  7. airbyte_cdk/sources/declarative/concurrent_declarative_source.py +0 -8
  8. airbyte_cdk/sources/declarative/declarative_component_schema.yaml +0 -36
  9. airbyte_cdk/sources/declarative/extractors/record_selector.py +1 -6
  10. airbyte_cdk/sources/declarative/models/declarative_component_schema.py +0 -31
  11. airbyte_cdk/sources/declarative/parsers/model_to_component_factory.py +1 -39
  12. airbyte_cdk/sources/declarative/retrievers/simple_retriever.py +1 -1
  13. airbyte_cdk/sources/declarative/stream_slicers/declarative_partition_generator.py +4 -9
  14. airbyte_cdk/sources/file_based/file_based_stream_reader.py +16 -38
  15. airbyte_cdk/sources/file_based/file_types/file_transfer.py +15 -8
  16. airbyte_cdk/sources/file_based/schema_helpers.py +1 -10
  17. airbyte_cdk/sources/file_based/stream/concurrent/adapters.py +12 -3
  18. airbyte_cdk/sources/file_based/stream/default_file_based_stream.py +38 -15
  19. airbyte_cdk/sources/file_based/stream/permissions_file_based_stream.py +3 -1
  20. airbyte_cdk/sources/streams/concurrent/default_stream.py +0 -3
  21. airbyte_cdk/sources/types.py +2 -11
  22. airbyte_cdk/sources/utils/record_helper.py +8 -8
  23. airbyte_cdk/test/mock_http/response_builder.py +0 -8
  24. {airbyte_cdk-6.45.1.post47.dev14456468218.dist-info → airbyte_cdk-6.45.2.post3.dev14463482961.dist-info}/METADATA +2 -2
  25. {airbyte_cdk-6.45.1.post47.dev14456468218.dist-info → airbyte_cdk-6.45.2.post3.dev14463482961.dist-info}/RECORD +29 -31
  26. airbyte_cdk/sources/declarative/retrievers/file_uploader.py +0 -89
  27. airbyte_cdk/sources/file_based/file_record_data.py +0 -22
  28. airbyte_cdk/sources/utils/files_directory.py +0 -15
  29. {airbyte_cdk-6.45.1.post47.dev14456468218.dist-info → airbyte_cdk-6.45.2.post3.dev14463482961.dist-info}/LICENSE.txt +0 -0
  30. {airbyte_cdk-6.45.1.post47.dev14456468218.dist-info → airbyte_cdk-6.45.2.post3.dev14463482961.dist-info}/LICENSE_SHORT +0 -0
  31. {airbyte_cdk-6.45.1.post47.dev14456468218.dist-info → airbyte_cdk-6.45.2.post3.dev14463482961.dist-info}/WHEEL +0 -0
  32. {airbyte_cdk-6.45.1.post47.dev14456468218.dist-info → airbyte_cdk-6.45.2.post3.dev14463482961.dist-info}/entry_points.txt +0 -0
@@ -4,7 +4,7 @@
4
4
 
5
5
 
6
6
  from dataclasses import asdict, dataclass, field
7
- from typing import Any, Dict, List, Mapping
7
+ from typing import Any, ClassVar, Dict, List, Mapping
8
8
 
9
9
  from airbyte_cdk.connector_builder.test_reader import TestReader
10
10
  from airbyte_cdk.models import (
@@ -37,6 +37,8 @@ MAX_STREAMS_KEY = "max_streams"
37
37
 
38
38
  @dataclass
39
39
  class TestLimits:
40
+ __test__: ClassVar[bool] = False # Tell Pytest this is not a Pytest class, despite its name
41
+
40
42
  max_records: int = field(default=DEFAULT_MAXIMUM_RECORDS)
41
43
  max_pages_per_slice: int = field(default=DEFAULT_MAXIMUM_NUMBER_OF_PAGES_PER_SLICE)
42
44
  max_slices: int = field(default=DEFAULT_MAXIMUM_NUMBER_OF_SLICES)
@@ -4,7 +4,7 @@
4
4
 
5
5
 
6
6
  import logging
7
- from typing import Any, Dict, Iterator, List, Mapping, Optional, Union
7
+ from typing import Any, ClassVar, Dict, Iterator, List, Mapping, Optional, Union
8
8
 
9
9
  from airbyte_cdk.connector_builder.models import (
10
10
  AuxiliaryRequest,
@@ -66,6 +66,8 @@ class TestReader:
66
66
 
67
67
  """
68
68
 
69
+ __test__: ClassVar[bool] = False # Tell Pytest this is not a Pytest class, despite its name
70
+
69
71
  logger = logging.getLogger("airbyte.connector-builder")
70
72
 
71
73
  def __init__(
@@ -19,7 +19,6 @@ from .airbyte_protocol import (
19
19
  AirbyteMessage,
20
20
  AirbyteProtocol,
21
21
  AirbyteRecordMessage,
22
- AirbyteRecordMessageFileReference,
23
22
  AirbyteStateBlob,
24
23
  AirbyteStateMessage,
25
24
  AirbyteStateStats,
@@ -8,6 +8,8 @@ from typing import Annotated, Any, Dict, List, Mapping, Optional, Union
8
8
  from airbyte_protocol_dataclasses.models import * # noqa: F403 # Allow '*'
9
9
  from serpyco_rs.metadata import Alias
10
10
 
11
+ from airbyte_cdk.models.file_transfer_record_message import AirbyteFileTransferRecordMessage
12
+
11
13
  # ruff: noqa: F405 # ignore fuzzy import issues with 'import *'
12
14
 
13
15
 
@@ -82,7 +84,7 @@ class AirbyteMessage:
82
84
  spec: Optional[ConnectorSpecification] = None # type: ignore [name-defined]
83
85
  connectionStatus: Optional[AirbyteConnectionStatus] = None # type: ignore [name-defined]
84
86
  catalog: Optional[AirbyteCatalog] = None # type: ignore [name-defined]
85
- record: Optional[AirbyteRecordMessage] = None # type: ignore [name-defined]
87
+ record: Optional[Union[AirbyteFileTransferRecordMessage, AirbyteRecordMessage]] = None # type: ignore [name-defined]
86
88
  state: Optional[AirbyteStateMessage] = None
87
89
  trace: Optional[AirbyteTraceMessage] = None # type: ignore [name-defined]
88
90
  control: Optional[AirbyteControlMessage] = None # type: ignore [name-defined]
@@ -0,0 +1,13 @@
1
+ # Copyright (c) 2024 Airbyte, Inc., all rights reserved.
2
+
3
+ from dataclasses import dataclass
4
+ from typing import Any, Dict, Optional
5
+
6
+
7
+ @dataclass
8
+ class AirbyteFileTransferRecordMessage:
9
+ stream: str
10
+ file: Dict[str, Any]
11
+ emitted_at: int
12
+ namespace: Optional[str] = None
13
+ data: Optional[Dict[str, Any]] = None
@@ -149,7 +149,7 @@ class ConcurrentReadProcessor:
149
149
  message = stream_data_to_airbyte_message(
150
150
  stream_name=record.stream_name,
151
151
  data_or_message=record.data,
152
- file_reference=record.file_reference,
152
+ is_file_transfer_message=record.is_file_transfer_message,
153
153
  )
154
154
  stream = self._stream_name_to_instance[record.stream_name]
155
155
 
@@ -25,7 +25,6 @@ from airbyte_cdk.sources.declarative.incremental.per_partition_with_global impor
25
25
  PerPartitionWithGlobalCursor,
26
26
  )
27
27
  from airbyte_cdk.sources.declarative.manifest_declarative_source import ManifestDeclarativeSource
28
- from airbyte_cdk.sources.declarative.models import FileUploader
29
28
  from airbyte_cdk.sources.declarative.models.declarative_component_schema import (
30
29
  ConcurrencyLevel as ConcurrencyLevelModel,
31
30
  )
@@ -207,10 +206,6 @@ class ConcurrentDeclarativeSource(ManifestDeclarativeSource, Generic[TState]):
207
206
  # these legacy Python streams the way we do low-code streams to determine if they are concurrent compatible,
208
207
  # so we need to treat them as synchronous
209
208
 
210
- supports_file_transfer = (
211
- "file_uploader" in name_to_stream_mapping[declarative_stream.name]
212
- )
213
-
214
209
  if (
215
210
  isinstance(declarative_stream, DeclarativeStream)
216
211
  and name_to_stream_mapping[declarative_stream.name]["type"]
@@ -327,7 +322,6 @@ class ConcurrentDeclarativeSource(ManifestDeclarativeSource, Generic[TState]):
327
322
  else None,
328
323
  logger=self.logger,
329
324
  cursor=cursor,
330
- supports_file_transfer=supports_file_transfer,
331
325
  )
332
326
  )
333
327
  elif (
@@ -359,7 +353,6 @@ class ConcurrentDeclarativeSource(ManifestDeclarativeSource, Generic[TState]):
359
353
  cursor_field=None,
360
354
  logger=self.logger,
361
355
  cursor=final_state_cursor,
362
- supports_file_transfer=supports_file_transfer,
363
356
  )
364
357
  )
365
358
  elif (
@@ -413,7 +406,6 @@ class ConcurrentDeclarativeSource(ManifestDeclarativeSource, Generic[TState]):
413
406
  cursor_field=perpartition_cursor.cursor_field.cursor_field_key,
414
407
  logger=self.logger,
415
408
  cursor=perpartition_cursor,
416
- supports_file_transfer=supports_file_transfer,
417
409
  )
418
410
  )
419
411
  else:
@@ -1448,42 +1448,6 @@ definitions:
1448
1448
  - "$ref": "#/definitions/LegacyToPerPartitionStateMigration"
1449
1449
  - "$ref": "#/definitions/CustomStateMigration"
1450
1450
  default: []
1451
- file_uploader:
1452
- title: File Uploader
1453
- description: (experimental) Describes how to fetch a file
1454
- type: object
1455
- required:
1456
- - type
1457
- - requester
1458
- - download_target_extractor
1459
- properties:
1460
- type:
1461
- type: string
1462
- enum: [ FileUploader ]
1463
- requester:
1464
- description: Requester component that describes how to prepare HTTP requests to send to the source API.
1465
- anyOf:
1466
- - "$ref": "#/definitions/CustomRequester"
1467
- - "$ref": "#/definitions/HttpRequester"
1468
- download_target_extractor:
1469
- description: Responsible for fetching the url where the file is located. This is applied on each records and not on the HTTP response
1470
- anyOf:
1471
- - "$ref": "#/definitions/CustomRecordExtractor"
1472
- - "$ref": "#/definitions/DpathExtractor"
1473
- file_extractor:
1474
- description: Responsible for fetching the content of the file. If not defined, the assumption is that the whole response body is the file content
1475
- anyOf:
1476
- - "$ref": "#/definitions/CustomRecordExtractor"
1477
- - "$ref": "#/definitions/DpathExtractor"
1478
- filename_extractor:
1479
- description: Defines the name to store the file. Stream name is automatically added to the file path. File unique ID can be used to avoid overwriting files. Random UUID will be used if the extractor is not provided.
1480
- type: string
1481
- interpolation_context:
1482
- - config
1483
- - record
1484
- examples:
1485
- - "{{ record.id }}/{{ record.file_name }}/"
1486
- - "{{ record.id }}_{{ record.file_name }}/"
1487
1451
  $parameters:
1488
1452
  type: object
1489
1453
  additional_properties: true
@@ -15,7 +15,6 @@ from airbyte_cdk.sources.declarative.extractors.type_transformer import (
15
15
  )
16
16
  from airbyte_cdk.sources.declarative.interpolation import InterpolatedString
17
17
  from airbyte_cdk.sources.declarative.models import SchemaNormalization
18
- from airbyte_cdk.sources.declarative.retrievers.file_uploader import FileUploader
19
18
  from airbyte_cdk.sources.declarative.transformations import RecordTransformation
20
19
  from airbyte_cdk.sources.types import Config, Record, StreamSlice, StreamState
21
20
  from airbyte_cdk.sources.utils.transform import TypeTransformer
@@ -43,7 +42,6 @@ class RecordSelector(HttpSelector):
43
42
  record_filter: Optional[RecordFilter] = None
44
43
  transformations: List[RecordTransformation] = field(default_factory=lambda: [])
45
44
  transform_before_filtering: bool = False
46
- file_uploader: Optional[FileUploader] = None
47
45
 
48
46
  def __post_init__(self, parameters: Mapping[str, Any]) -> None:
49
47
  self._parameters = parameters
@@ -119,10 +117,7 @@ class RecordSelector(HttpSelector):
119
117
  transformed_filtered_data, schema=records_schema
120
118
  )
121
119
  for data in normalized_data:
122
- record = Record(data=data, stream_name=self.name, associated_slice=stream_slice)
123
- if self.file_uploader:
124
- self.file_uploader.upload(record)
125
- yield record
120
+ yield Record(data=data, stream_name=self.name, associated_slice=stream_slice)
126
121
 
127
122
  def _normalize_by_schema(
128
123
  self, records: Iterable[Mapping[str, Any]], schema: Optional[Mapping[str, Any]]
@@ -2042,31 +2042,6 @@ class SelectiveAuthenticator(BaseModel):
2042
2042
  parameters: Optional[Dict[str, Any]] = Field(None, alias="$parameters")
2043
2043
 
2044
2044
 
2045
- class FileUploader(BaseModel):
2046
- type: Literal["FileUploader"]
2047
- requester: Union[CustomRequester, HttpRequester] = Field(
2048
- ...,
2049
- description="Requester component that describes how to prepare HTTP requests to send to the source API.",
2050
- )
2051
- download_target_extractor: Union[CustomRecordExtractor, DpathExtractor] = Field(
2052
- ...,
2053
- description="Responsible for fetching the url where the file is located. This is applied on each records and not on the HTTP response",
2054
- )
2055
- file_extractor: Optional[Union[CustomRecordExtractor, DpathExtractor]] = Field(
2056
- None,
2057
- description="Responsible for fetching the content of the file. If not defined, the assumption is that the whole response body is the file content",
2058
- )
2059
- filename_extractor: Optional[str] = Field(
2060
- None,
2061
- description="Defines the name to store the file. Stream name is automatically added to the file path. File unique ID can be used to avoid overwriting files. Random UUID will be used if the extractor is not provided.",
2062
- examples=[
2063
- "{{ record.id }}/{{ record.file_name }}/",
2064
- "{{ record.id }}_{{ record.file_name }}/",
2065
- ],
2066
- )
2067
- parameters: Optional[Dict[str, Any]] = Field(None, alias="$parameters")
2068
-
2069
-
2070
2045
  class DeclarativeStream(BaseModel):
2071
2046
  class Config:
2072
2047
  extra = Extra.allow
@@ -2125,11 +2100,6 @@ class DeclarativeStream(BaseModel):
2125
2100
  description="Array of state migrations to be applied on the input state",
2126
2101
  title="State Migrations",
2127
2102
  )
2128
- file_uploader: Optional[FileUploader] = Field(
2129
- None,
2130
- description="(experimental) Describes how to fetch a file",
2131
- title="File Uploader",
2132
- )
2133
2103
  parameters: Optional[Dict[str, Any]] = Field(None, alias="$parameters")
2134
2104
 
2135
2105
 
@@ -2623,7 +2593,6 @@ CompositeErrorHandler.update_forward_refs()
2623
2593
  DeclarativeSource1.update_forward_refs()
2624
2594
  DeclarativeSource2.update_forward_refs()
2625
2595
  SelectiveAuthenticator.update_forward_refs()
2626
- FileUploader.update_forward_refs()
2627
2596
  DeclarativeStream.update_forward_refs()
2628
2597
  SessionTokenAuthenticator.update_forward_refs()
2629
2598
  DynamicSchemaLoader.update_forward_refs()
@@ -106,6 +106,7 @@ from airbyte_cdk.sources.declarative.migrations.legacy_to_per_partition_state_mi
106
106
  )
107
107
  from airbyte_cdk.sources.declarative.models import (
108
108
  CustomStateMigration,
109
+ GzipDecoder,
109
110
  )
110
111
  from airbyte_cdk.sources.declarative.models.declarative_component_schema import (
111
112
  AddedFieldDefinition as AddedFieldDefinitionModel,
@@ -227,9 +228,6 @@ from airbyte_cdk.sources.declarative.models.declarative_component_schema import
227
228
  from airbyte_cdk.sources.declarative.models.declarative_component_schema import (
228
229
  ExponentialBackoffStrategy as ExponentialBackoffStrategyModel,
229
230
  )
230
- from airbyte_cdk.sources.declarative.models.declarative_component_schema import (
231
- FileUploader as FileUploaderModel,
232
- )
233
231
  from airbyte_cdk.sources.declarative.models.declarative_component_schema import (
234
232
  FixedWindowCallRatePolicy as FixedWindowCallRatePolicyModel,
235
233
  )
@@ -481,7 +479,6 @@ from airbyte_cdk.sources.declarative.retrievers import (
481
479
  SimpleRetriever,
482
480
  SimpleRetrieverTestReadDecorator,
483
481
  )
484
- from airbyte_cdk.sources.declarative.retrievers.file_uploader import FileUploader
485
482
  from airbyte_cdk.sources.declarative.schema import (
486
483
  ComplexFieldType,
487
484
  DefaultSchemaLoader,
@@ -678,7 +675,6 @@ class ModelToComponentFactory:
678
675
  ComponentMappingDefinitionModel: self.create_components_mapping_definition,
679
676
  ZipfileDecoderModel: self.create_zipfile_decoder,
680
677
  HTTPAPIBudgetModel: self.create_http_api_budget,
681
- FileUploaderModel: self.create_file_uploader,
682
678
  FixedWindowCallRatePolicyModel: self.create_fixed_window_call_rate_policy,
683
679
  MovingWindowCallRatePolicyModel: self.create_moving_window_call_rate_policy,
684
680
  UnlimitedCallRatePolicyModel: self.create_unlimited_call_rate_policy,
@@ -1830,11 +1826,6 @@ class ModelToComponentFactory:
1830
1826
  transformations.append(
1831
1827
  self._create_component_from_model(model=transformation_model, config=config)
1832
1828
  )
1833
- file_uploader = None
1834
- if model.file_uploader:
1835
- file_uploader = self._create_component_from_model(
1836
- model=model.file_uploader, config=config
1837
- )
1838
1829
 
1839
1830
  retriever = self._create_component_from_model(
1840
1831
  model=model.retriever,
@@ -1846,7 +1837,6 @@ class ModelToComponentFactory:
1846
1837
  stop_condition_on_cursor=stop_condition_on_cursor,
1847
1838
  client_side_incremental_sync=client_side_incremental_sync,
1848
1839
  transformations=transformations,
1849
- file_uploader=file_uploader,
1850
1840
  incremental_sync=model.incremental_sync,
1851
1841
  )
1852
1842
  cursor_field = model.incremental_sync.cursor_field if model.incremental_sync else None
@@ -2769,7 +2759,6 @@ class ModelToComponentFactory:
2769
2759
  transformations: List[RecordTransformation] | None = None,
2770
2760
  decoder: Decoder | None = None,
2771
2761
  client_side_incremental_sync: Dict[str, Any] | None = None,
2772
- file_uploader: Optional[FileUploader] = None,
2773
2762
  **kwargs: Any,
2774
2763
  ) -> RecordSelector:
2775
2764
  extractor = self._create_component_from_model(
@@ -2807,7 +2796,6 @@ class ModelToComponentFactory:
2807
2796
  config=config,
2808
2797
  record_filter=record_filter,
2809
2798
  transformations=transformations or [],
2810
- file_uploader=file_uploader,
2811
2799
  schema_normalization=schema_normalization,
2812
2800
  parameters=model.parameters or {},
2813
2801
  transform_before_filtering=transform_before_filtering,
@@ -2865,7 +2853,6 @@ class ModelToComponentFactory:
2865
2853
  stop_condition_on_cursor: bool = False,
2866
2854
  client_side_incremental_sync: Optional[Dict[str, Any]] = None,
2867
2855
  transformations: List[RecordTransformation],
2868
- file_uploader: Optional[FileUploader] = None,
2869
2856
  incremental_sync: Optional[
2870
2857
  Union[
2871
2858
  IncrementingCountCursorModel, DatetimeBasedCursorModel, CustomIncrementalSyncModel
@@ -2886,7 +2873,6 @@ class ModelToComponentFactory:
2886
2873
  decoder=decoder,
2887
2874
  transformations=transformations,
2888
2875
  client_side_incremental_sync=client_side_incremental_sync,
2889
- file_uploader=file_uploader,
2890
2876
  )
2891
2877
 
2892
2878
  query_properties: Optional[QueryProperties] = None
@@ -3552,30 +3538,6 @@ class ModelToComponentFactory:
3552
3538
  matchers=matchers,
3553
3539
  )
3554
3540
 
3555
- def create_file_uploader(
3556
- self, model: FileUploaderModel, config: Config, **kwargs: Any
3557
- ) -> FileUploader:
3558
- name = "File Uploader"
3559
- requester = self._create_component_from_model(
3560
- model=model.requester,
3561
- config=config,
3562
- name=name,
3563
- **kwargs,
3564
- )
3565
- download_target_extractor = self._create_component_from_model(
3566
- model=model.download_target_extractor,
3567
- config=config,
3568
- name=name,
3569
- **kwargs,
3570
- )
3571
- return FileUploader(
3572
- requester=requester,
3573
- download_target_extractor=download_target_extractor,
3574
- config=config,
3575
- parameters=model.parameters or {},
3576
- filename_extractor=model.filename_extractor if model.filename_extractor else None,
3577
- )
3578
-
3579
3541
  def create_moving_window_call_rate_policy(
3580
3542
  self, model: MovingWindowCallRatePolicyModel, config: Config, **kwargs: Any
3581
3543
  ) -> MovingWindowCallRatePolicy:
@@ -364,7 +364,7 @@ class SimpleRetriever(Retriever):
364
364
  pagination_complete = False
365
365
  initial_token = self._paginator.get_initial_token()
366
366
  next_page_token: Optional[Mapping[str, Any]] = (
367
- {"next_page_token": initial_token} if initial_token else None
367
+ {"next_page_token": initial_token} if initial_token is not None else None
368
368
  )
369
369
  while not pagination_complete:
370
370
  response = self._fetch_next_page(stream_state, stream_slice, next_page_token)
@@ -58,16 +58,11 @@ class DeclarativePartition(Partition):
58
58
  def read(self) -> Iterable[Record]:
59
59
  for stream_data in self._retriever.read_records(self._json_schema, self._stream_slice):
60
60
  if isinstance(stream_data, Mapping):
61
- record = (
62
- stream_data
63
- if isinstance(stream_data, Record)
64
- else Record(
65
- data=stream_data,
66
- stream_name=self.stream_name(),
67
- associated_slice=self._stream_slice,
68
- )
61
+ yield Record(
62
+ data=stream_data,
63
+ stream_name=self.stream_name(),
64
+ associated_slice=self._stream_slice,
69
65
  )
70
- yield record
71
66
  else:
72
67
  self._message_repository.emit_message(stream_data)
73
68
 
@@ -8,18 +8,16 @@ from datetime import datetime
8
8
  from enum import Enum
9
9
  from io import IOBase
10
10
  from os import makedirs, path
11
- from typing import Any, Callable, Iterable, List, MutableMapping, Optional, Set, Tuple
11
+ from typing import Any, Dict, Iterable, List, Optional, Set
12
12
 
13
13
  from wcmatch.glob import GLOBSTAR, globmatch
14
14
 
15
- from airbyte_cdk.models import AirbyteRecordMessageFileReference
16
15
  from airbyte_cdk.sources.file_based.config.abstract_file_based_spec import AbstractFileBasedSpec
17
16
  from airbyte_cdk.sources.file_based.config.validate_config_transfer_modes import (
18
17
  include_identities_stream,
19
18
  preserve_directory_structure,
20
19
  use_file_transfer,
21
20
  )
22
- from airbyte_cdk.sources.file_based.file_record_data import FileRecordData
23
21
  from airbyte_cdk.sources.file_based.remote_file import RemoteFile
24
22
 
25
23
 
@@ -30,10 +28,6 @@ class FileReadMode(Enum):
30
28
 
31
29
  class AbstractFileBasedStreamReader(ABC):
32
30
  DATE_TIME_FORMAT = "%Y-%m-%dT%H:%M:%S.%fZ"
33
- FILE_RELATIVE_PATH = "file_relative_path"
34
- FILE_NAME = "file_name"
35
- LOCAL_FILE_PATH = "local_file_path"
36
- FILE_FOLDER = "file_folder"
37
31
 
38
32
  def __init__(self) -> None:
39
33
  self._config = None
@@ -154,9 +148,9 @@ class AbstractFileBasedStreamReader(ABC):
154
148
  return False
155
149
 
156
150
  @abstractmethod
157
- def upload(
151
+ def get_file(
158
152
  self, file: RemoteFile, local_directory: str, logger: logging.Logger
159
- ) -> Tuple[FileRecordData, AirbyteRecordMessageFileReference]:
153
+ ) -> Dict[str, Any]:
160
154
  """
161
155
  This is required for connectors that will support writing to
162
156
  files. It will handle the logic to download,get,read,acquire or
@@ -168,41 +162,25 @@ class AbstractFileBasedStreamReader(ABC):
168
162
  logger (logging.Logger): Logger for logging information and errors.
169
163
 
170
164
  Returns:
171
- AirbyteRecordMessageFileReference: A file reference object containing:
172
- - staging_file_url (str): The absolute path to the referenced file in the staging area.
173
- - file_size_bytes (int): The size of the referenced file in bytes.
174
- - source_file_relative_path (str): The relative path to the referenced file in source.
165
+ dict: A dictionary containing the following:
166
+ - "file_url" (str): The absolute path of the downloaded file.
167
+ - "bytes" (int): The file size in bytes.
168
+ - "file_relative_path" (str): The relative path of the file for local storage. Is relative to local_directory as
169
+ this a mounted volume in the pod container.
170
+
175
171
  """
176
172
  ...
177
173
 
178
- def _get_file_transfer_paths(
179
- self, source_file_relative_path: str, staging_directory: str
180
- ) -> MutableMapping[str, Any]:
181
- """
182
- This method is used to get the file transfer paths for a given source file relative path and local directory.
183
- It returns a dictionary with the following keys:
184
- - FILE_RELATIVE_PATH: The relative path to file in reference to the staging directory.
185
- - LOCAL_FILE_PATH: The absolute path to the file.
186
- - FILE_NAME: The name of the referenced file.
187
- - FILE_FOLDER: The folder of the referenced file.
188
- """
174
+ def _get_file_transfer_paths(self, file: RemoteFile, local_directory: str) -> List[str]:
189
175
  preserve_directory_structure = self.preserve_directory_structure()
190
-
191
- file_name = path.basename(source_file_relative_path)
192
- file_folder = path.dirname(source_file_relative_path)
193
176
  if preserve_directory_structure:
194
177
  # Remove left slashes from source path format to make relative path for writing locally
195
- file_relative_path = source_file_relative_path.lstrip("/")
178
+ file_relative_path = file.uri.lstrip("/")
196
179
  else:
197
- file_relative_path = file_name
198
- local_file_path = path.join(staging_directory, file_relative_path)
180
+ file_relative_path = path.basename(file.uri)
181
+ local_file_path = path.join(local_directory, file_relative_path)
182
+
199
183
  # Ensure the local directory exists
200
184
  makedirs(path.dirname(local_file_path), exist_ok=True)
201
-
202
- file_paths = {
203
- self.FILE_RELATIVE_PATH: file_relative_path,
204
- self.LOCAL_FILE_PATH: local_file_path,
205
- self.FILE_NAME: file_name,
206
- self.FILE_FOLDER: file_folder,
207
- }
208
- return file_paths
185
+ absolute_file_path = path.abspath(local_file_path)
186
+ return [file_relative_path, local_file_path, absolute_file_path]
@@ -2,27 +2,34 @@
2
2
  # Copyright (c) 2024 Airbyte, Inc., all rights reserved.
3
3
  #
4
4
  import logging
5
- from typing import Iterable, Tuple
5
+ import os
6
+ from typing import Any, Dict, Iterable
6
7
 
7
- from airbyte_cdk.models import AirbyteRecordMessageFileReference
8
+ from airbyte_cdk.sources.file_based.config.file_based_stream_config import FileBasedStreamConfig
8
9
  from airbyte_cdk.sources.file_based.file_based_stream_reader import AbstractFileBasedStreamReader
9
- from airbyte_cdk.sources.file_based.file_record_data import FileRecordData
10
10
  from airbyte_cdk.sources.file_based.remote_file import RemoteFile
11
- from airbyte_cdk.sources.utils.files_directory import get_files_directory
11
+
12
+ AIRBYTE_STAGING_DIRECTORY = os.getenv("AIRBYTE_STAGING_DIRECTORY", "/staging/files")
13
+ DEFAULT_LOCAL_DIRECTORY = "/tmp/airbyte-file-transfer"
12
14
 
13
15
 
14
16
  class FileTransfer:
15
17
  def __init__(self) -> None:
16
- self._local_directory = get_files_directory()
18
+ self._local_directory = (
19
+ AIRBYTE_STAGING_DIRECTORY
20
+ if os.path.exists(AIRBYTE_STAGING_DIRECTORY)
21
+ else DEFAULT_LOCAL_DIRECTORY
22
+ )
17
23
 
18
- def upload(
24
+ def get_file(
19
25
  self,
26
+ config: FileBasedStreamConfig,
20
27
  file: RemoteFile,
21
28
  stream_reader: AbstractFileBasedStreamReader,
22
29
  logger: logging.Logger,
23
- ) -> Iterable[Tuple[FileRecordData, AirbyteRecordMessageFileReference]]:
30
+ ) -> Iterable[Dict[str, Any]]:
24
31
  try:
25
- yield stream_reader.upload(
32
+ yield stream_reader.get_file(
26
33
  file=file, local_directory=self._local_directory, logger=logger
27
34
  )
28
35
  except Exception as ex:
@@ -18,18 +18,9 @@ JsonSchemaSupportedType = Union[List[str], Literal["string"], str]
18
18
  SchemaType = Mapping[str, Mapping[str, JsonSchemaSupportedType]]
19
19
 
20
20
  schemaless_schema = {"type": "object", "properties": {"data": {"type": "object"}}}
21
-
22
21
  file_transfer_schema = {
23
22
  "type": "object",
24
- "properties": {
25
- "folder": {"type": "string"},
26
- "file_name": {"type": "string"},
27
- "source_uri": {"type": "string"},
28
- "bytes": {"type": "integer"},
29
- "id": {"type": ["null", "string"]},
30
- "updated_at": {"type": ["null", "string"]},
31
- "mime_type": {"type": ["null", "string"]},
32
- },
23
+ "properties": {"data": {"type": "object"}, "file": {"type": "object"}},
33
24
  }
34
25
 
35
26
 
@@ -4,7 +4,7 @@
4
4
 
5
5
  import copy
6
6
  import logging
7
- from functools import lru_cache
7
+ from functools import cache, lru_cache
8
8
  from typing import TYPE_CHECKING, Any, Iterable, List, Mapping, MutableMapping, Optional, Union
9
9
 
10
10
  from typing_extensions import deprecated
@@ -258,14 +258,19 @@ class FileBasedStreamPartition(Partition):
258
258
  and record_data.record is not None
259
259
  ):
260
260
  # `AirbyteMessage`s of type `Record` should also be yielded so they are enqueued
261
- record_message_data = record_data.record.data
261
+ # If stream is flagged for file_transfer the record should data in file key
262
+ record_message_data = (
263
+ record_data.record.file
264
+ if self._use_file_transfer()
265
+ else record_data.record.data
266
+ )
262
267
  if not record_message_data:
263
268
  raise ExceptionWithDisplayMessage("A record without data was found")
264
269
  else:
265
270
  yield Record(
266
271
  data=record_message_data,
267
272
  stream_name=self.stream_name(),
268
- file_reference=record_data.record.file_reference,
273
+ is_file_transfer_message=self._use_file_transfer(),
269
274
  )
270
275
  else:
271
276
  self._message_repository.emit_message(record_data)
@@ -301,6 +306,10 @@ class FileBasedStreamPartition(Partition):
301
306
  def stream_name(self) -> str:
302
307
  return self._stream.name
303
308
 
309
+ @cache
310
+ def _use_file_transfer(self) -> bool:
311
+ return hasattr(self._stream, "use_file_transfer") and self._stream.use_file_transfer
312
+
304
313
  def __repr__(self) -> str:
305
314
  return f"FileBasedStreamPartition({self._stream.name}, {self._slice})"
306
315
 
@@ -11,7 +11,7 @@ from functools import cache
11
11
  from os import path
12
12
  from typing import Any, Dict, Iterable, List, Mapping, MutableMapping, Optional, Set, Tuple, Union
13
13
 
14
- from airbyte_cdk.models import AirbyteLogMessage, AirbyteMessage, AirbyteStream, FailureType, Level
14
+ from airbyte_cdk.models import AirbyteLogMessage, AirbyteMessage, FailureType, Level
15
15
  from airbyte_cdk.models import Type as MessageType
16
16
  from airbyte_cdk.sources.file_based.config.file_based_stream_config import PrimaryKeyType
17
17
  from airbyte_cdk.sources.file_based.exceptions import (
@@ -56,7 +56,6 @@ class DefaultFileBasedStream(AbstractFileBasedStream, IncrementalMixin):
56
56
  airbyte_columns = [ab_last_mod_col, ab_file_name_col]
57
57
  use_file_transfer = False
58
58
  preserve_directory_structure = True
59
- _file_transfer = FileTransfer()
60
59
 
61
60
  def __init__(self, **kwargs: Any):
62
61
  if self.FILE_TRANSFER_KW in kwargs:
@@ -94,6 +93,21 @@ class DefaultFileBasedStream(AbstractFileBasedStream, IncrementalMixin):
94
93
  self.config
95
94
  )
96
95
 
96
+ def _filter_schema_invalid_properties(
97
+ self, configured_catalog_json_schema: Dict[str, Any]
98
+ ) -> Dict[str, Any]:
99
+ if self.use_file_transfer:
100
+ return {
101
+ "type": "object",
102
+ "properties": {
103
+ "file_path": {"type": "string"},
104
+ "file_size": {"type": "string"},
105
+ self.ab_file_name_col: {"type": "string"},
106
+ },
107
+ }
108
+ else:
109
+ return super()._filter_schema_invalid_properties(configured_catalog_json_schema)
110
+
97
111
  def _duplicated_files_names(
98
112
  self, slices: List[dict[str, List[RemoteFile]]]
99
113
  ) -> List[dict[str, List[str]]]:
@@ -131,6 +145,14 @@ class DefaultFileBasedStream(AbstractFileBasedStream, IncrementalMixin):
131
145
  record[self.ab_file_name_col] = file.uri
132
146
  return record
133
147
 
148
+ def transform_record_for_file_transfer(
149
+ self, record: dict[str, Any], file: RemoteFile
150
+ ) -> dict[str, Any]:
151
+ # timstamp() returns a float representing the number of seconds since the unix epoch
152
+ record[self.modified] = int(file.last_modified.timestamp()) * 1000
153
+ record[self.source_file_url] = file.uri
154
+ return record
155
+
134
156
  def read_records_from_slice(self, stream_slice: StreamSlice) -> Iterable[AirbyteMessage]:
135
157
  """
136
158
  Yield all records from all remote files in `list_files_for_this_sync`.
@@ -151,13 +173,19 @@ class DefaultFileBasedStream(AbstractFileBasedStream, IncrementalMixin):
151
173
 
152
174
  try:
153
175
  if self.use_file_transfer:
154
- for file_record_data, file_reference in self._file_transfer.upload(
155
- file=file, stream_reader=self.stream_reader, logger=self.logger
176
+ self.logger.info(f"{self.name}: {file} file-based syncing")
177
+ # todo: complete here the code to not rely on local parser
178
+ file_transfer = FileTransfer()
179
+ for record in file_transfer.get_file(
180
+ self.config, file, self.stream_reader, self.logger
156
181
  ):
182
+ line_no += 1
183
+ if not self.record_passes_validation_policy(record):
184
+ n_skipped += 1
185
+ continue
186
+ record = self.transform_record_for_file_transfer(record, file)
157
187
  yield stream_data_to_airbyte_message(
158
- self.name,
159
- file_record_data.dict(exclude_none=True),
160
- file_reference=file_reference,
188
+ self.name, record, is_file_transfer_message=True
161
189
  )
162
190
  else:
163
191
  for record in parser.parse_records(
@@ -231,8 +259,6 @@ class DefaultFileBasedStream(AbstractFileBasedStream, IncrementalMixin):
231
259
 
232
260
  @cache
233
261
  def get_json_schema(self) -> JsonSchema:
234
- if self.use_file_transfer:
235
- return file_transfer_schema
236
262
  extra_fields = {
237
263
  self.ab_last_mod_col: {"type": "string"},
238
264
  self.ab_file_name_col: {"type": "string"},
@@ -256,7 +282,9 @@ class DefaultFileBasedStream(AbstractFileBasedStream, IncrementalMixin):
256
282
  return {"type": "object", "properties": {**extra_fields, **schema["properties"]}}
257
283
 
258
284
  def _get_raw_json_schema(self) -> JsonSchema:
259
- if self.config.input_schema:
285
+ if self.use_file_transfer:
286
+ return file_transfer_schema
287
+ elif self.config.input_schema:
260
288
  return self.config.get_input_schema() # type: ignore
261
289
  elif self.config.schemaless:
262
290
  return schemaless_schema
@@ -313,11 +341,6 @@ class DefaultFileBasedStream(AbstractFileBasedStream, IncrementalMixin):
313
341
  self.config.globs or [], self.config.legacy_prefix, self.logger
314
342
  )
315
343
 
316
- def as_airbyte_stream(self) -> AirbyteStream:
317
- file_stream = super().as_airbyte_stream()
318
- file_stream.is_file_based = self.use_file_transfer
319
- return file_stream
320
-
321
344
  def infer_schema(self, files: List[RemoteFile]) -> Mapping[str, Any]:
322
345
  loop = asyncio.get_event_loop()
323
346
  schema = loop.run_until_complete(self._infer_schema(files))
@@ -61,7 +61,9 @@ class PermissionsFileBasedStream(DefaultFileBasedStream):
61
61
  permissions_record = self.transform_record(
62
62
  permissions_record, file, file_datetime_string
63
63
  )
64
- yield stream_data_to_airbyte_message(self.name, permissions_record)
64
+ yield stream_data_to_airbyte_message(
65
+ self.name, permissions_record, is_file_transfer_message=False
66
+ )
65
67
  except Exception as e:
66
68
  self.logger.error(f"Failed to retrieve permissions for file {file.uri}: {str(e)}")
67
69
  yield AirbyteMessage(
@@ -29,7 +29,6 @@ class DefaultStream(AbstractStream):
29
29
  logger: Logger,
30
30
  cursor: Cursor,
31
31
  namespace: Optional[str] = None,
32
- supports_file_transfer: bool = False,
33
32
  ) -> None:
34
33
  self._stream_partition_generator = partition_generator
35
34
  self._name = name
@@ -40,7 +39,6 @@ class DefaultStream(AbstractStream):
40
39
  self._logger = logger
41
40
  self._cursor = cursor
42
41
  self._namespace = namespace
43
- self._supports_file_transfer = supports_file_transfer
44
42
 
45
43
  def generate_partitions(self) -> Iterable[Partition]:
46
44
  yield from self._stream_partition_generator.generate()
@@ -70,7 +68,6 @@ class DefaultStream(AbstractStream):
70
68
  json_schema=dict(self._json_schema),
71
69
  supported_sync_modes=[SyncMode.full_refresh],
72
70
  is_resumable=False,
73
- is_file_based=self._supports_file_transfer,
74
71
  )
75
72
 
76
73
  if self._namespace:
@@ -6,7 +6,6 @@ from __future__ import annotations
6
6
 
7
7
  from typing import Any, ItemsView, Iterator, KeysView, List, Mapping, Optional, ValuesView
8
8
 
9
- from airbyte_cdk.models import AirbyteRecordMessageFileReference
10
9
  from airbyte_cdk.utils.slice_hasher import SliceHasher
11
10
 
12
11
  # A FieldPointer designates a path to a field inside a mapping. For example, retrieving ["k1", "k1.2"] in the object {"k1" :{"k1.2":
@@ -24,12 +23,12 @@ class Record(Mapping[str, Any]):
24
23
  data: Mapping[str, Any],
25
24
  stream_name: str,
26
25
  associated_slice: Optional[StreamSlice] = None,
27
- file_reference: Optional[AirbyteRecordMessageFileReference] = None,
26
+ is_file_transfer_message: bool = False,
28
27
  ):
29
28
  self._data = data
30
29
  self._associated_slice = associated_slice
31
30
  self.stream_name = stream_name
32
- self._file_reference = file_reference
31
+ self.is_file_transfer_message = is_file_transfer_message
33
32
 
34
33
  @property
35
34
  def data(self) -> Mapping[str, Any]:
@@ -39,14 +38,6 @@ class Record(Mapping[str, Any]):
39
38
  def associated_slice(self) -> Optional[StreamSlice]:
40
39
  return self._associated_slice
41
40
 
42
- @property
43
- def file_reference(self) -> AirbyteRecordMessageFileReference:
44
- return self._file_reference
45
-
46
- @file_reference.setter
47
- def file_reference(self, value: AirbyteRecordMessageFileReference) -> None:
48
- self._file_reference = value
49
-
50
41
  def __repr__(self) -> str:
51
42
  return repr(self._data)
52
43
 
@@ -9,10 +9,10 @@ from airbyte_cdk.models import (
9
9
  AirbyteLogMessage,
10
10
  AirbyteMessage,
11
11
  AirbyteRecordMessage,
12
- AirbyteRecordMessageFileReference,
13
12
  AirbyteTraceMessage,
14
13
  )
15
14
  from airbyte_cdk.models import Type as MessageType
15
+ from airbyte_cdk.models.file_transfer_record_message import AirbyteFileTransferRecordMessage
16
16
  from airbyte_cdk.sources.streams.core import StreamData
17
17
  from airbyte_cdk.sources.utils.transform import TransformConfig, TypeTransformer
18
18
 
@@ -22,7 +22,7 @@ def stream_data_to_airbyte_message(
22
22
  data_or_message: StreamData,
23
23
  transformer: TypeTransformer = TypeTransformer(TransformConfig.NoTransform),
24
24
  schema: Optional[Mapping[str, Any]] = None,
25
- file_reference: Optional[AirbyteRecordMessageFileReference] = None,
25
+ is_file_transfer_message: bool = False,
26
26
  ) -> AirbyteMessage:
27
27
  if schema is None:
28
28
  schema = {}
@@ -36,12 +36,12 @@ def stream_data_to_airbyte_message(
36
36
  # taken unless configured. See
37
37
  # docs/connector-development/cdk-python/schemas.md for details.
38
38
  transformer.transform(data, schema)
39
- message = AirbyteRecordMessage(
40
- stream=stream_name,
41
- data=data,
42
- emitted_at=now_millis,
43
- file_reference=file_reference,
44
- )
39
+ if is_file_transfer_message:
40
+ message = AirbyteFileTransferRecordMessage(
41
+ stream=stream_name, file=data, emitted_at=now_millis, data={}
42
+ )
43
+ else:
44
+ message = AirbyteRecordMessage(stream=stream_name, data=data, emitted_at=now_millis)
45
45
  return AirbyteMessage(type=MessageType.RECORD, record=message)
46
46
  case AirbyteTraceMessage():
47
47
  return AirbyteMessage(type=MessageType.TRACE, trace=data_or_message)
@@ -198,14 +198,6 @@ def find_template(resource: str, execution_folder: str) -> Dict[str, Any]:
198
198
  return json.load(template_file) # type: ignore # we assume the dev correctly set up the resource file
199
199
 
200
200
 
201
- def find_binary_response(resource: str, execution_folder: str) -> bytes:
202
- response_filepath = str(
203
- get_unit_test_folder(execution_folder) / "resource" / "http" / "response" / f"{resource}"
204
- )
205
- with open(response_filepath, "rb") as response_file:
206
- return response_file.read() # type: ignore # we assume the dev correctly set up the resource file
207
-
208
-
209
201
  def create_record_builder(
210
202
  response_template: Dict[str, Any],
211
203
  records_path: Union[FieldPath, NestedPath],
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: airbyte-cdk
3
- Version: 6.45.1.post47.dev14456468218
3
+ Version: 6.45.2.post3.dev14463482961
4
4
  Summary: A framework for writing Airbyte Connectors.
5
5
  Home-page: https://airbyte.com
6
6
  License: MIT
@@ -22,7 +22,7 @@ Provides-Extra: sql
22
22
  Provides-Extra: vector-db-based
23
23
  Requires-Dist: Jinja2 (>=3.1.2,<3.2.0)
24
24
  Requires-Dist: PyYAML (>=6.0.1,<7.0.0)
25
- Requires-Dist: airbyte-protocol-models-dataclasses (>=0.15,<0.16)
25
+ Requires-Dist: airbyte-protocol-models-dataclasses (>=0.14,<0.15)
26
26
  Requires-Dist: anyascii (>=0.3.2,<0.4.0)
27
27
  Requires-Dist: avro (>=1.11.2,<1.13.0) ; extra == "file-based"
28
28
  Requires-Dist: backoff
@@ -7,13 +7,13 @@ airbyte_cdk/config_observation.py,sha256=7SSPxtN0nXPkm4euGNcTTr1iLbwUL01jy-24V1H
7
7
  airbyte_cdk/connector.py,sha256=bO23kdGRkl8XKFytOgrrWFc_VagteTHVEF6IsbizVkM,4224
8
8
  airbyte_cdk/connector_builder/README.md,sha256=Hw3wvVewuHG9-QgsAq1jDiKuLlStDxKBz52ftyNRnBw,1665
9
9
  airbyte_cdk/connector_builder/__init__.py,sha256=4Hw-PX1-VgESLF16cDdvuYCzGJtHntThLF4qIiULWeo,61
10
- airbyte_cdk/connector_builder/connector_builder_handler.py,sha256=gwFpZHmvFrMB9NMlRuRfq0KEkbPaFucCB8k1DL20Wmw,5769
10
+ airbyte_cdk/connector_builder/connector_builder_handler.py,sha256=5ML_9Qw3TdD0NgHYhEOFNMvkmYCFLILbAX7kZFZx3gQ,5877
11
11
  airbyte_cdk/connector_builder/main.py,sha256=j1pP5N8RsnvQZ4iYxhLdLEHsJ5Ui7IVFBUi6wYMGBkM,3839
12
12
  airbyte_cdk/connector_builder/models.py,sha256=9pIZ98LW_d6fRS39VdnUOf3cxGt4TkC5MJ0_OrzcCRk,1578
13
13
  airbyte_cdk/connector_builder/test_reader/__init__.py,sha256=iTwBMoI9vaJotEgpqZbFjlxRcbxXYypSVJ9YxeHk7wc,120
14
14
  airbyte_cdk/connector_builder/test_reader/helpers.py,sha256=Iczn-_iczS2CaIAunWwyFcX0uLTra8Wh9JVfzm1Gfxo,26765
15
15
  airbyte_cdk/connector_builder/test_reader/message_grouper.py,sha256=84BAEPIBHMq3WCfO14WNvh_q7OsjGgDt0q1FTu8eW-w,6918
16
- airbyte_cdk/connector_builder/test_reader/reader.py,sha256=GurMB4ITO_PntvhIHSJkXbhynLilI4DObY5A2axavXo,20667
16
+ airbyte_cdk/connector_builder/test_reader/reader.py,sha256=wJtuYTZuc24-JlGF4UBFTJ2PChLjcQrvldqAWJM9Y9Y,20775
17
17
  airbyte_cdk/connector_builder/test_reader/types.py,sha256=hPZG3jO03kBaPyW94NI3JHRS1jxXGSNBcN1HFzOxo5Y,2528
18
18
  airbyte_cdk/destinations/__init__.py,sha256=FyDp28PT_YceJD5HDFhA-mrGfX9AONIyMQ4d68CHNxQ,213
19
19
  airbyte_cdk/destinations/destination.py,sha256=CIq-yb8C_0QvcKCtmStaHfiqn53GEfRAIGGCkJhKP1Q,5880
@@ -29,15 +29,16 @@ airbyte_cdk/destinations/vector_db_based/writer.py,sha256=nZ00xPiohElJmYktEZZIhr
29
29
  airbyte_cdk/entrypoint.py,sha256=NRJv5BNZRSUEVTmNBa9N7ih6fW5sg4DwL0nkB9kI99Y,18570
30
30
  airbyte_cdk/exception_handler.py,sha256=D_doVl3Dt60ASXlJsfviOCswxGyKF2q0RL6rif3fNks,2013
31
31
  airbyte_cdk/logger.py,sha256=1cURbvawbunCAV178q-XhTHcbAQZTSf07WhU7U9AXWU,3744
32
- airbyte_cdk/models/__init__.py,sha256=Et9wJWs5VOWynGbb-3aJRhsdAHAiLkNNLxdwqJAuqkw,2114
33
- airbyte_cdk/models/airbyte_protocol.py,sha256=oZdKsZ7yPjUt9hvxdWNpxCtgjSV2RWhf4R9Np03sqyY,3613
32
+ airbyte_cdk/models/__init__.py,sha256=MOTiuML2wShBaMSIwikdjyye2uUWBjo4J1QFSbnoiM4,2075
33
+ airbyte_cdk/models/airbyte_protocol.py,sha256=MCmLir67-hF12YM5OKzeGbWrlxr7ChG_OQSE1xG8EIU,3748
34
34
  airbyte_cdk/models/airbyte_protocol_serializers.py,sha256=s6SaFB2CMrG_7jTQGn_fhFbQ1FUxhCxf5kq2RWGHMVI,1749
35
+ airbyte_cdk/models/file_transfer_record_message.py,sha256=J-E-43KOmUFdpsjeKlEfNnnZRSB-Gb5AGZjonR25Drc,323
35
36
  airbyte_cdk/models/well_known_types.py,sha256=EquepbisGPuCSrs_D7YVVnMR9-ShhUr21wnFz3COiJs,156
36
37
  airbyte_cdk/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
37
38
  airbyte_cdk/sources/__init__.py,sha256=45J83QsFH3Wky3sVapZWg4C58R_i1thm61M06t2c1AQ,1156
38
39
  airbyte_cdk/sources/abstract_source.py,sha256=50vxEBRByiNhT4WJkiFvgM-C6PWqKSJgvuNC_aeg2cw,15547
39
40
  airbyte_cdk/sources/concurrent_source/__init__.py,sha256=3D_RJsxQfiLboSCDdNei1Iv-msRp3DXsas6E9kl7dXc,386
40
- airbyte_cdk/sources/concurrent_source/concurrent_read_processor.py,sha256=P_GA5QayzehCf0ksUbEbGoNixBnauzsepv-0ICzhH4w,12691
41
+ airbyte_cdk/sources/concurrent_source/concurrent_read_processor.py,sha256=dbDBNcNNg2IZU5pZb3HfZeILU7X5_EhYGSbNqq3JD4I,12711
41
42
  airbyte_cdk/sources/concurrent_source/concurrent_source.py,sha256=P8B6EcLKaSstfAD9kDZsTJ0q8vRmdFrxLt-zOA5_By0,7737
42
43
  airbyte_cdk/sources/concurrent_source/concurrent_source_adapter.py,sha256=f9PIRPWn2tXu0-bxVeYHL2vYdqCzZ_kgpHg5_Ep-cfQ,6103
43
44
  airbyte_cdk/sources/concurrent_source/partition_generation_completed_sentinel.py,sha256=z1t-rAZBsqVidv2fpUlPHE9JgyXsITuGk4AMu96mXSQ,696
@@ -66,11 +67,11 @@ airbyte_cdk/sources/declarative/checks/check_stream.py,sha256=QeExVmpSYjr_CnghHu
66
67
  airbyte_cdk/sources/declarative/checks/connection_checker.py,sha256=MBRJo6WJlZQHpIfOGaNOkkHUmgUl_4wDM6VPo41z5Ss,1383
67
68
  airbyte_cdk/sources/declarative/concurrency_level/__init__.py,sha256=5XUqrmlstYlMM0j6crktlKQwALek0uiz2D3WdM46MyA,191
68
69
  airbyte_cdk/sources/declarative/concurrency_level/concurrency_level.py,sha256=YIwCTCpOr_QSNW4ltQK0yUGWInI8PKNY216HOOegYLk,2101
69
- airbyte_cdk/sources/declarative/concurrent_declarative_source.py,sha256=nqqcSe2FeycTpYz3KsFomeOzRWxGYc2G5YfFNQrMKlI,28113
70
+ airbyte_cdk/sources/declarative/concurrent_declarative_source.py,sha256=uhy0dRkA2jq89JdHZMTH5LdP200-Pm_LTaaWnCoUiaM,27687
70
71
  airbyte_cdk/sources/declarative/datetime/__init__.py,sha256=4Hw-PX1-VgESLF16cDdvuYCzGJtHntThLF4qIiULWeo,61
71
72
  airbyte_cdk/sources/declarative/datetime/datetime_parser.py,sha256=_zGNGq31RNy_0QBLt_EcTvgPyhj7urPdx6oA3M5-r3o,3150
72
73
  airbyte_cdk/sources/declarative/datetime/min_max_datetime.py,sha256=0BHBtDNQZfvwM45-tY5pNlTcKAFSGGNxemoi0Jic-0E,5785
73
- airbyte_cdk/sources/declarative/declarative_component_schema.yaml,sha256=OCZDuyHSoubti45_LHfFHyPyZDjeFBhY1CymG9_buBk,159887
74
+ airbyte_cdk/sources/declarative/declarative_component_schema.yaml,sha256=pGFwleIC0sXFY-a6QphWyjY9QjUfHasgChPAMZFWjU8,158152
74
75
  airbyte_cdk/sources/declarative/declarative_source.py,sha256=nF7wBqFd3AQmEKAm4CnIo29CJoQL562cJGSCeL8U8bA,1531
75
76
  airbyte_cdk/sources/declarative/declarative_stream.py,sha256=dCRlddBUSaJmBNBz1pSO1r2rTw8AP5d2_vlmIeGs2gg,10767
76
77
  airbyte_cdk/sources/declarative/decoders/__init__.py,sha256=JHb_0d3SE6kNY10mxA5YBEKPeSbsWYjByq1gUQxepoE,953
@@ -88,7 +89,7 @@ airbyte_cdk/sources/declarative/extractors/dpath_extractor.py,sha256=wR4Ol4MG2lt
88
89
  airbyte_cdk/sources/declarative/extractors/http_selector.py,sha256=2zWZ4ewTqQC8VwkjS0xD_u350Km3SiYP7hpOOgiLg5o,1169
89
90
  airbyte_cdk/sources/declarative/extractors/record_extractor.py,sha256=XJELMjahAsaomlvQgN2zrNO0DJX0G0fr9r682gUz7Pg,691
90
91
  airbyte_cdk/sources/declarative/extractors/record_filter.py,sha256=yTdEkyDUSW2KbFkEwJJMlS963C955LgCCOVfTmmScpQ,3367
91
- airbyte_cdk/sources/declarative/extractors/record_selector.py,sha256=Xg4e0exJ5Tq8I346uD2-HjpCsAUFLgPPcNKa0UoHjV8,7178
92
+ airbyte_cdk/sources/declarative/extractors/record_selector.py,sha256=HCqx7IyENM_aRF4it2zJN26_vDu6WeP8XgCxQWHUvcY,6934
92
93
  airbyte_cdk/sources/declarative/extractors/response_to_file_extractor.py,sha256=WJyA2OYIEgFpVP5Y3o0tIj69AV6IKkn9B16MeXaEItI,6513
93
94
  airbyte_cdk/sources/declarative/extractors/type_transformer.py,sha256=d6Y2Rfg8pMVEEnHllfVksWZdNVOU55yk34O03dP9muY,1626
94
95
  airbyte_cdk/sources/declarative/incremental/__init__.py,sha256=U1oZKtBaEC6IACmvziY9Wzg7Z8EgF4ZuR7NwvjlB_Sk,1255
@@ -113,13 +114,13 @@ airbyte_cdk/sources/declarative/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW
113
114
  airbyte_cdk/sources/declarative/migrations/legacy_to_per_partition_state_migration.py,sha256=iemy3fKLczcU0-Aor7tx5jcT6DRedKMqyK7kCOp01hg,3924
114
115
  airbyte_cdk/sources/declarative/migrations/state_migration.py,sha256=KWPjealMLKSMtajXgkdGgKg7EmTLR-CqqD7UIh0-eDU,794
115
116
  airbyte_cdk/sources/declarative/models/__init__.py,sha256=nUFxNCiKeYRVXuZEKA7GD-lTHxsiKcQ8FitZjKhPIvE,100
116
- airbyte_cdk/sources/declarative/models/declarative_component_schema.py,sha256=EYPTtYTxNm_u-8OacYF6d4ce0PdV6jzYnxTmpjZOu_g,113491
117
+ airbyte_cdk/sources/declarative/models/declarative_component_schema.py,sha256=EfhCFVz_UHl7_cbRlf5hvFO1J5osxAZjISeqgbXE2t8,112007
117
118
  airbyte_cdk/sources/declarative/parsers/__init__.py,sha256=ZnqYNxHsKCgO38IwB34RQyRMXTs4GTvlRi3ImKnIioo,61
118
119
  airbyte_cdk/sources/declarative/parsers/custom_code_compiler.py,sha256=nlVvHC511NUyDEEIRBkoeDTAvLqKNp-hRy8D19z8tdk,5941
119
120
  airbyte_cdk/sources/declarative/parsers/custom_exceptions.py,sha256=Rir9_z3Kcd5Es0-LChrzk-0qubAsiK_RSEnLmK2OXm8,553
120
121
  airbyte_cdk/sources/declarative/parsers/manifest_component_transformer.py,sha256=4C15MKV-zOrMVQAm4FyohDsrJUBCSpMv5tZw0SK3aeI,9685
121
122
  airbyte_cdk/sources/declarative/parsers/manifest_reference_resolver.py,sha256=IWUOdF03o-aQn0Occo1BJCxU0Pz-QILk5L67nzw2thw,6803
122
- airbyte_cdk/sources/declarative/parsers/model_to_component_factory.py,sha256=2mB379Yg7oD11j6HkuGq2OyOgmE2Sc4itPWo9XhI_hs,160128
123
+ airbyte_cdk/sources/declarative/parsers/model_to_component_factory.py,sha256=Qim2qR64SKWbxD-Au0KAB3fLf6G2YfppUv3Q0w4QYtE,158619
123
124
  airbyte_cdk/sources/declarative/partition_routers/__init__.py,sha256=TBC9AkGaUqHm2IKHMPN6punBIcY5tWGULowcLoAVkfw,1109
124
125
  airbyte_cdk/sources/declarative/partition_routers/async_job_partition_router.py,sha256=VelO7zKqKtzMJ35jyFeg0ypJLQC0plqqIBNXoBW1G2E,3001
125
126
  airbyte_cdk/sources/declarative/partition_routers/cartesian_product_stream_slicer.py,sha256=c5cuVFM6NFkuQqG8Z5IwkBuwDrvXZN1CunUOM_L0ezg,6892
@@ -178,9 +179,8 @@ airbyte_cdk/sources/declarative/resolvers/config_components_resolver.py,sha256=d
178
179
  airbyte_cdk/sources/declarative/resolvers/http_components_resolver.py,sha256=AiojNs8wItJFrENZBFUaDvau3sgwudO6Wkra36upSPo,4639
179
180
  airbyte_cdk/sources/declarative/retrievers/__init__.py,sha256=nQepwG_RfW53sgwvK5dLPqfCx0VjsQ83nYoPjBMAaLM,527
180
181
  airbyte_cdk/sources/declarative/retrievers/async_retriever.py,sha256=6oZtnCHm9NdDvjTSrVwPQOXGSdETSIR7eWH2vFjM7jI,4855
181
- airbyte_cdk/sources/declarative/retrievers/file_uploader.py,sha256=Om8vaDHix_1EXxEDVpRP57R94KmBmzJJLWtgxDJ5P8E,3363
182
182
  airbyte_cdk/sources/declarative/retrievers/retriever.py,sha256=XPLs593Xv8c5cKMc37XzUAYmzlXd1a7eSsspM-CMuWA,1696
183
- airbyte_cdk/sources/declarative/retrievers/simple_retriever.py,sha256=Ixs_byM-DMfYiYB-iOa97yH4WGAvxgTdTYeAsskHdYM,31134
183
+ airbyte_cdk/sources/declarative/retrievers/simple_retriever.py,sha256=cI3UEWSIuGNzzIlf8I_7Vf_3fX_tQwIwPrnmrY7MEh4,31146
184
184
  airbyte_cdk/sources/declarative/schema/__init__.py,sha256=xU45UvM5O4c1PSM13UHpCdh5hpW3HXy9vRRGEiAC1rg,795
185
185
  airbyte_cdk/sources/declarative/schema/default_schema_loader.py,sha256=UnbzlExmwoQiVV8zDg4lhAEaqA_0pRfwbMRe8yqOuWk,1834
186
186
  airbyte_cdk/sources/declarative/schema/dynamic_schema_loader.py,sha256=J8Q_iJYhcSQLWyt0bTZCbDAGpxt9G8FCc6Q9jtGsNzw,10703
@@ -190,7 +190,7 @@ airbyte_cdk/sources/declarative/schema/schema_loader.py,sha256=kjt8v0N5wWKA5zyLn
190
190
  airbyte_cdk/sources/declarative/spec/__init__.py,sha256=H0UwoRhgucbKBIzg85AXrifybVmfpwWpPdy22vZKVuo,141
191
191
  airbyte_cdk/sources/declarative/spec/spec.py,sha256=ODSNUgkDOhnLQnwLjgSaME6R3kNeywjROvbNrWEnsgU,1876
192
192
  airbyte_cdk/sources/declarative/stream_slicers/__init__.py,sha256=sI9vhc95RwJYOnA0VKjcbtKgFcmAbWjhdWBXFbAijOs,176
193
- airbyte_cdk/sources/declarative/stream_slicers/declarative_partition_generator.py,sha256=cjKGm4r438dd1GxrFHJ4aYrdzG2bkncnwaWxAwlXR3M,3585
193
+ airbyte_cdk/sources/declarative/stream_slicers/declarative_partition_generator.py,sha256=RW1Q44ml-VWeMl4lNcV6EfyzrzCZkjj-hd0Omx_n_n4,3405
194
194
  airbyte_cdk/sources/declarative/stream_slicers/stream_slicer.py,sha256=SOkIPBi2Wu7yxIvA15yFzUAB95a3IzA8LPq5DEqHQQc,725
195
195
  airbyte_cdk/sources/declarative/transformations/__init__.py,sha256=CPJ8TlMpiUmvG3624VYu_NfTzxwKcfBjM2Q2wJ7fkSA,919
196
196
  airbyte_cdk/sources/declarative/transformations/add_fields.py,sha256=Eg1jQtRObgzxbtySTQs5uEZIjEklsoHFxYSPf78x6Ng,5420
@@ -224,26 +224,25 @@ airbyte_cdk/sources/file_based/discovery_policy/default_discovery_policy.py,sha2
224
224
  airbyte_cdk/sources/file_based/exceptions.py,sha256=WP0qkG6fpWoBpOyyicgp5YNE393VWyegq5qSy0v4QtM,7362
225
225
  airbyte_cdk/sources/file_based/file_based_source.py,sha256=Xg8OYWnGc-OcVBglvS08uwAWGWHBhEqsBnyODIkOK-4,20051
226
226
  airbyte_cdk/sources/file_based/file_based_stream_permissions_reader.py,sha256=4e7FXqQ9hueacexC0SyrZyjF8oREYHza8pKF9CgKbD8,5050
227
- airbyte_cdk/sources/file_based/file_based_stream_reader.py,sha256=rwz8AhEIqYB9gBF7uW9eR--eUiHOntzuwLH8jFHNacE,7854
228
- airbyte_cdk/sources/file_based/file_record_data.py,sha256=aIbUHHjZOF_OIS22ePr0Vu0MQ6rmLmSC1D4kDdGmVKw,415
227
+ airbyte_cdk/sources/file_based/file_based_stream_reader.py,sha256=0cmppYO3pZlFiJrs5oorF4JXv4ErhOeEMrdLG7P-Gdk,6742
229
228
  airbyte_cdk/sources/file_based/file_types/__init__.py,sha256=blCLn0-2LC-ZdgcNyDEhqM2RiUvEjEBh-G4-t32ZtuM,1268
230
229
  airbyte_cdk/sources/file_based/file_types/avro_parser.py,sha256=USEYqiICXBWpDV443VtNOCmUA-GINzY_Zah74_5w3qQ,10860
231
230
  airbyte_cdk/sources/file_based/file_types/csv_parser.py,sha256=QlCXB-ry3np67Q_VerQEPoWDOTcPTB6Go4ydZxY9ae4,20445
232
231
  airbyte_cdk/sources/file_based/file_types/excel_parser.py,sha256=BeplCq0hmojELU6bZCvvpRLpQ9us81TqbGYwrhd3INo,7188
233
- airbyte_cdk/sources/file_based/file_types/file_transfer.py,sha256=5l2Jo6bp6neDmgM427PrZMZeqU0hCIZVWnzUZ_7BT10,1100
232
+ airbyte_cdk/sources/file_based/file_types/file_transfer.py,sha256=HyGRihJxcb_lEsffKhfF3eylLBDy51_PXSwGUFEJ5bA,1265
234
233
  airbyte_cdk/sources/file_based/file_types/file_type_parser.py,sha256=JgpH21PrbRqwK92BJklZWvh2TndA6xZ-eP1LPMo44oQ,2832
235
234
  airbyte_cdk/sources/file_based/file_types/jsonl_parser.py,sha256=GwyNyxmST4RX-XpXy7xVH0D-znYWWBmGv_pVAu95oHQ,5886
236
235
  airbyte_cdk/sources/file_based/file_types/parquet_parser.py,sha256=XenFg5sJ-UBnIkSmsiNJRou11NO0zZXx-RXgPHMT2NA,10487
237
236
  airbyte_cdk/sources/file_based/file_types/unstructured_parser.py,sha256=2TYOQl62FQPCa8otLbkDIk_j01EP3oWaKSfXGhCjCHg,19492
238
237
  airbyte_cdk/sources/file_based/remote_file.py,sha256=yqRz93vPe8PBXLIMJ5W5u2JRlZRhg6sBrAjn3pPjJ8A,315
239
- airbyte_cdk/sources/file_based/schema_helpers.py,sha256=1zRxdyirn-1kx2Zvh1TOZ_AzFkwrNxqwIZFmQ5V-2s4,9859
238
+ airbyte_cdk/sources/file_based/schema_helpers.py,sha256=Cf8FH1bDFP0qCDDfEYir_WjP4exXUnikz8hZ40y1Ek0,9601
240
239
  airbyte_cdk/sources/file_based/schema_validation_policies/__init__.py,sha256=FkByIyEy56x2_awYnxGPqGaOp7zAzpAoRkPZHKySI9M,536
241
240
  airbyte_cdk/sources/file_based/schema_validation_policies/abstract_schema_validation_policy.py,sha256=kjvX7nOmUALYd7HuZHilUzgJPZ-MnZ08mtvuBnt2tQ0,618
242
241
  airbyte_cdk/sources/file_based/schema_validation_policies/default_schema_validation_policies.py,sha256=vjTlmYT_nqzY3DbT5xem7X-bwgA9RyXHoKFqiMO2URk,1728
243
242
  airbyte_cdk/sources/file_based/stream/__init__.py,sha256=q_zmeOHHg0JK5j1YNSOIsyXGz-wlTl_0E8z5GKVAcVM,543
244
243
  airbyte_cdk/sources/file_based/stream/abstract_file_based_stream.py,sha256=9pQh3BHYcxm8CRC8XawfmBxL8O9HggpWwCCbX_ncINE,7509
245
244
  airbyte_cdk/sources/file_based/stream/concurrent/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
246
- airbyte_cdk/sources/file_based/stream/concurrent/adapters.py,sha256=1AIuAOHa_M6zN9l0eAWBHwhKl4fdP4-KlUMOMzTv11U,13525
245
+ airbyte_cdk/sources/file_based/stream/concurrent/adapters.py,sha256=EwWuoCsQRNaoizxbb2-BYVwRYOxr57exw3q3M6zVv1E,13931
247
246
  airbyte_cdk/sources/file_based/stream/concurrent/cursor/__init__.py,sha256=Rx7TwjH8B7e0eee83Tlqxv1bWn-BVXOmlUAH7auM1uM,344
248
247
  airbyte_cdk/sources/file_based/stream/concurrent/cursor/abstract_concurrent_file_based_cursor.py,sha256=5dYZMLBEbvCyrCT89lCYdm2FdrLPLuxjdpQSVGP5o0w,1856
249
248
  airbyte_cdk/sources/file_based/stream/concurrent/cursor/file_based_concurrent_cursor.py,sha256=gRTL-9I3ejjQOpLKd6ixe9rB3kGlubCdhUt9ri6AdAI,14880
@@ -251,9 +250,9 @@ airbyte_cdk/sources/file_based/stream/concurrent/cursor/file_based_final_state_c
251
250
  airbyte_cdk/sources/file_based/stream/cursor/__init__.py,sha256=MhFB5hOo8sjwvCh8gangaymdg3EJWYt_72brFOZt068,191
252
251
  airbyte_cdk/sources/file_based/stream/cursor/abstract_file_based_cursor.py,sha256=om-x3gZFPgWDpi15S9RxZmR36VHnk8sytgN6LlBQhAw,1934
253
252
  airbyte_cdk/sources/file_based/stream/cursor/default_file_based_cursor.py,sha256=VGV7xLyBribuBMVrXtO1xqkWJD86bl7yhXtjnwLMohM,7051
254
- airbyte_cdk/sources/file_based/stream/default_file_based_stream.py,sha256=gzSN4cLywwzo_U1OdFS3Of_-4DRkUcX_j7Mv30MrxQs,17154
253
+ airbyte_cdk/sources/file_based/stream/default_file_based_stream.py,sha256=jyJLu2BUCYWKqrqD0ZUFxnrD0qybny7KbzKznxjIIpM,18199
255
254
  airbyte_cdk/sources/file_based/stream/identities_stream.py,sha256=FZH83Geoy3K3nwUk2VVNJERFcXUTnl-4XljjucUM23s,1893
256
- airbyte_cdk/sources/file_based/stream/permissions_file_based_stream.py,sha256=6KxqdD3-VvwxDTk7TtZ0M32fga4CI3qZ9IKdAkySpx0,3844
255
+ airbyte_cdk/sources/file_based/stream/permissions_file_based_stream.py,sha256=ke82qgm7snOlQTDx94Lqsc0cDkHWi3OJDTrPxffpFqc,3914
257
256
  airbyte_cdk/sources/file_based/types.py,sha256=INxG7OPnkdUP69oYNKMAbwhvV1AGvLRHs1J6pIia2FI,218
258
257
  airbyte_cdk/sources/http_config.py,sha256=OBZeuyFilm6NlDlBhFQvHhTWabEvZww6OHDIlZujIS0,730
259
258
  airbyte_cdk/sources/http_logger.py,sha256=H93kPAujHhPmXNX0JSFG3D-SL6yEFA5PtKot9Hu3TYA,1690
@@ -279,7 +278,7 @@ airbyte_cdk/sources/streams/concurrent/availability_strategy.py,sha256=4La5v2Uff
279
278
  airbyte_cdk/sources/streams/concurrent/clamping.py,sha256=i26GVyui2ScEXSP-IP_61K2HaTp1-6lTlYHsZVYpuZA,3240
280
279
  airbyte_cdk/sources/streams/concurrent/cursor.py,sha256=LFXbKBEMtNSVz_kZs9qydS9fPvzTU5wdgXRagRRJeHo,21388
281
280
  airbyte_cdk/sources/streams/concurrent/cursor_types.py,sha256=ZyWLPpeLX1qXcP5MwS-wxK11IBMsnVPCw9zx8gA2_Ro,843
282
- airbyte_cdk/sources/streams/concurrent/default_stream.py,sha256=3SBjFa1z955pSE_2qt1C7mAky-RKjOZeQDePbZkWYYs,3371
281
+ airbyte_cdk/sources/streams/concurrent/default_stream.py,sha256=K3rLMpYhS7nnmvwQ52lqBy7DQdFMJpvvT7sgBg_ckA8,3207
283
282
  airbyte_cdk/sources/streams/concurrent/exceptions.py,sha256=JOZ446MCLpmF26r9KfS6OO_6rGjcjgJNZdcw6jccjEI,468
284
283
  airbyte_cdk/sources/streams/concurrent/helpers.py,sha256=S6AW8TgIASCZ2UuUcQLE8OzgYUHWt2-KPOvNPwnQf-Q,1596
285
284
  airbyte_cdk/sources/streams/concurrent/partition_enqueuer.py,sha256=2t64b_z9cEPmlHZnjSiMTO8PEtEdiAJDG0JcYOtUqAE,3363
@@ -316,11 +315,10 @@ airbyte_cdk/sources/streams/http/requests_native_auth/oauth.py,sha256=C2j2uVfi9d
316
315
  airbyte_cdk/sources/streams/http/requests_native_auth/token.py,sha256=h5PTzcdH-RQLeCg7xZ45w_484OPUDSwNWl_iMJQmZoI,2526
317
316
  airbyte_cdk/sources/streams/permissions/identities_stream.py,sha256=9O9k6k18Xm3Zsiw_vnI_jsHXfMCQiek6V-jMkJJLxn8,2621
318
317
  airbyte_cdk/sources/streams/utils/__init__.py,sha256=4Hw-PX1-VgESLF16cDdvuYCzGJtHntThLF4qIiULWeo,61
319
- airbyte_cdk/sources/types.py,sha256=1oerHQpidFrIluUhWsM3-4Xst4wwUDqzkgtgZY0jjZU,5485
318
+ airbyte_cdk/sources/types.py,sha256=x5Rkfpottg46qgr1-g_O4kN6v0Fd0sWHttdYsftyo7w,5148
320
319
  airbyte_cdk/sources/utils/__init__.py,sha256=TTN6VUxVy6Is8BhYQZR5pxJGQh8yH4duXh4O1TiMiEY,118
321
320
  airbyte_cdk/sources/utils/casing.py,sha256=QC-gV1O4e8DR4-bhdXieUPKm_JamzslVyfABLYYRSXA,256
322
- airbyte_cdk/sources/utils/files_directory.py,sha256=z8Dmr-wkL1sAqdwCST4MBUFAyMHPD2cJIzVdAuCynp8,391
323
- airbyte_cdk/sources/utils/record_helper.py,sha256=7wL-pDYrBpcmZHa8ORtiSOqBZJEZI5hdl2dA1RYiatk,2029
321
+ airbyte_cdk/sources/utils/record_helper.py,sha256=jeB0mucudzna7Zvj-pCBbwFrbLJ36SlAWZTh5O4Fb9Y,2168
324
322
  airbyte_cdk/sources/utils/schema_helpers.py,sha256=bR3I70-e11S6B8r6VK-pthQXtcYrXojgXFvuK7lRrpg,8545
325
323
  airbyte_cdk/sources/utils/slice_logger.py,sha256=qWWeFLAvigFz0b4O1_O3QDM1cy8PqZAMMgVPR2hEeb8,1778
326
324
  airbyte_cdk/sources/utils/transform.py,sha256=0LOvIJg1vmg_70AiAVe-YHMr-LHrqEuxg9cm1BnYPDM,11725
@@ -344,7 +342,7 @@ airbyte_cdk/test/mock_http/matcher.py,sha256=4Qj8UnJKZIs-eodshryce3SN1Ayc8GZpBET
344
342
  airbyte_cdk/test/mock_http/mocker.py,sha256=XgsjMtVoeMpRELPyALgrkHFauH9H5irxrz1Kcxh2yFY,8013
345
343
  airbyte_cdk/test/mock_http/request.py,sha256=tdB8cqk2vLgCDTOKffBKsM06llYs4ZecgtH6DKyx6yY,4112
346
344
  airbyte_cdk/test/mock_http/response.py,sha256=s4-cQQqTtmeej0pQDWqmG0vUWpHS-93lIWMpW3zSVyU,662
347
- airbyte_cdk/test/mock_http/response_builder.py,sha256=F-v7ebftqGj7YVIMLKdodmU9U8Dq8aIyllWGo2NGwHc,8331
345
+ airbyte_cdk/test/mock_http/response_builder.py,sha256=debPx_lRYBaQVSwCoKLa0F8KFk3h0qG7bWxFBATa0cc,7958
348
346
  airbyte_cdk/test/state_builder.py,sha256=kLPql9lNzUJaBg5YYRLJlY_Hy5JLHJDVyKPMZMoYM44,946
349
347
  airbyte_cdk/test/utils/__init__.py,sha256=Hu-1XT2KDoYjDF7-_ziDwv5bY3PueGjANOCbzeOegDg,57
350
348
  airbyte_cdk/test/utils/data.py,sha256=CkCR1_-rujWNmPXFR1IXTMwx1rAl06wAyIKWpDcN02w,820
@@ -368,9 +366,9 @@ airbyte_cdk/utils/slice_hasher.py,sha256=EDxgROHDbfG-QKQb59m7h_7crN1tRiawdf5uU7G
368
366
  airbyte_cdk/utils/spec_schema_transformations.py,sha256=-5HTuNsnDBAhj-oLeQXwpTGA0HdcjFOf2zTEMUTTg_Y,816
369
367
  airbyte_cdk/utils/stream_status_utils.py,sha256=ZmBoiy5HVbUEHAMrUONxZvxnvfV9CesmQJLDTAIWnWw,1171
370
368
  airbyte_cdk/utils/traced_exception.py,sha256=C8uIBuCL_E4WnBAOPSxBicD06JAldoN9fGsQDp463OY,6292
371
- airbyte_cdk-6.45.1.post47.dev14456468218.dist-info/LICENSE.txt,sha256=Wfe61S4BaGPj404v8lrAbvhjYR68SHlkzeYrg3_bbuM,1051
372
- airbyte_cdk-6.45.1.post47.dev14456468218.dist-info/LICENSE_SHORT,sha256=aqF6D1NcESmpn-cqsxBtszTEnHKnlsp8L4x9wAh3Nxg,55
373
- airbyte_cdk-6.45.1.post47.dev14456468218.dist-info/METADATA,sha256=E2z0nkONKG5sYIjIZdGW6ahxFjfLAUH2YYx66TWzlGA,6093
374
- airbyte_cdk-6.45.1.post47.dev14456468218.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
375
- airbyte_cdk-6.45.1.post47.dev14456468218.dist-info/entry_points.txt,sha256=fj-e3PAQvsxsQzyyq8UkG1k8spunWnD4BAH2AwlR6NM,95
376
- airbyte_cdk-6.45.1.post47.dev14456468218.dist-info/RECORD,,
369
+ airbyte_cdk-6.45.2.post3.dev14463482961.dist-info/LICENSE.txt,sha256=Wfe61S4BaGPj404v8lrAbvhjYR68SHlkzeYrg3_bbuM,1051
370
+ airbyte_cdk-6.45.2.post3.dev14463482961.dist-info/LICENSE_SHORT,sha256=aqF6D1NcESmpn-cqsxBtszTEnHKnlsp8L4x9wAh3Nxg,55
371
+ airbyte_cdk-6.45.2.post3.dev14463482961.dist-info/METADATA,sha256=1zWGqhfb96Ud4180ayG4dERFE_OGwnWsUQqs8eUO38k,6092
372
+ airbyte_cdk-6.45.2.post3.dev14463482961.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
373
+ airbyte_cdk-6.45.2.post3.dev14463482961.dist-info/entry_points.txt,sha256=fj-e3PAQvsxsQzyyq8UkG1k8spunWnD4BAH2AwlR6NM,95
374
+ airbyte_cdk-6.45.2.post3.dev14463482961.dist-info/RECORD,,
@@ -1,89 +0,0 @@
1
- #
2
- # Copyright (c) 2025 Airbyte, Inc., all rights reserved.
3
- #
4
-
5
- import json
6
- import logging
7
- import uuid
8
- from dataclasses import InitVar, dataclass, field
9
- from pathlib import Path
10
- from typing import Any, Mapping, Optional, Union
11
-
12
- from airbyte_cdk.models import AirbyteRecordMessageFileReference
13
- from airbyte_cdk.sources.declarative.extractors.record_extractor import RecordExtractor
14
- from airbyte_cdk.sources.declarative.interpolation.interpolated_string import (
15
- InterpolatedString,
16
- )
17
- from airbyte_cdk.sources.declarative.partition_routers.substream_partition_router import (
18
- SafeResponse,
19
- )
20
- from airbyte_cdk.sources.declarative.requesters import Requester
21
- from airbyte_cdk.sources.declarative.types import Record, StreamSlice
22
- from airbyte_cdk.sources.types import Config
23
- from airbyte_cdk.sources.utils.files_directory import get_files_directory
24
-
25
- logger = logging.getLogger("airbyte")
26
-
27
-
28
- @dataclass
29
- class FileUploader:
30
- requester: Requester
31
- download_target_extractor: RecordExtractor
32
- config: Config
33
- parameters: InitVar[Mapping[str, Any]]
34
-
35
- filename_extractor: Optional[Union[InterpolatedString, str]] = None
36
- content_extractor: Optional[RecordExtractor] = None
37
-
38
- def __post_init__(self, parameters: Mapping[str, Any]) -> None:
39
- if self.filename_extractor:
40
- self.filename_extractor = InterpolatedString.create(
41
- self.filename_extractor,
42
- parameters=parameters,
43
- )
44
-
45
- def upload(self, record: Record) -> None:
46
- mocked_response = SafeResponse()
47
- mocked_response.content = json.dumps(record.data).encode()
48
- download_target = list(self.download_target_extractor.extract_records(mocked_response))[0]
49
- if not isinstance(download_target, str):
50
- raise ValueError(
51
- f"download_target is expected to be a str but was {type(download_target)}: {download_target}"
52
- )
53
-
54
- response = self.requester.send_request(
55
- stream_slice=StreamSlice(
56
- partition={}, cursor_slice={}, extra_fields={"download_target": download_target}
57
- ),
58
- )
59
-
60
- if self.content_extractor:
61
- raise NotImplementedError("TODO")
62
- else:
63
- files_directory = Path(get_files_directory())
64
-
65
- file_name = (
66
- self.filename_extractor.eval(self.config, record=record)
67
- if self.filename_extractor
68
- else str(uuid.uuid4())
69
- )
70
- file_name = file_name.lstrip("/")
71
- file_relative_path = Path(record.stream_name) / Path(file_name)
72
-
73
- full_path = files_directory / file_relative_path
74
- full_path.parent.mkdir(parents=True, exist_ok=True)
75
-
76
- with open(str(full_path), "wb") as f:
77
- f.write(response.content)
78
- file_size_bytes = full_path.stat().st_size
79
-
80
- logger.info("File uploaded successfully")
81
- logger.info(f"File url: {str(full_path)}")
82
- logger.info(f"File size: {file_size_bytes / 1024} KB")
83
- logger.info(f"File relative path: {str(file_relative_path)}")
84
-
85
- record.file_reference = AirbyteRecordMessageFileReference(
86
- staging_file_url=str(full_path),
87
- source_file_relative_path=str(file_relative_path),
88
- file_size_bytes=file_size_bytes,
89
- )
@@ -1,22 +0,0 @@
1
- #
2
- # Copyright (c) 2025 Airbyte, Inc., all rights reserved.
3
- #
4
-
5
- from datetime import datetime
6
- from typing import Optional
7
-
8
- from pydantic.v1 import BaseModel
9
-
10
-
11
- class FileRecordData(BaseModel):
12
- """
13
- A record in a file-based stream.
14
- """
15
-
16
- folder: str
17
- filename: str
18
- bytes: int
19
- source_uri: str
20
- id: Optional[str] = None
21
- updated_at: Optional[str] = None
22
- mime_type: Optional[str] = None
@@ -1,15 +0,0 @@
1
- #
2
- # Copyright (c) 2025 Airbyte, Inc., all rights reserved.
3
- #
4
- import os
5
-
6
- AIRBYTE_STAGING_DIRECTORY = os.getenv("AIRBYTE_STAGING_DIRECTORY", "/staging/files")
7
- DEFAULT_LOCAL_DIRECTORY = "/tmp/airbyte-file-transfer"
8
-
9
-
10
- def get_files_directory() -> str:
11
- return (
12
- AIRBYTE_STAGING_DIRECTORY
13
- if os.path.exists(AIRBYTE_STAGING_DIRECTORY)
14
- else DEFAULT_LOCAL_DIRECTORY
15
- )