airbyte-cdk 6.13.0__py3-none-any.whl → 6.13.1.dev4100__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.
@@ -83,9 +83,7 @@ class OffsetIncrement(PaginationStrategy):
83
83
  return self._offset
84
84
 
85
85
  def reset(self, reset_value: Optional[Any] = 0) -> None:
86
- if reset_value is None:
87
- self._offset = 0
88
- elif not isinstance(reset_value, int):
86
+ if not isinstance(reset_value, int):
89
87
  raise ValueError(
90
88
  f"Reset value {reset_value} for OffsetIncrement pagination strategy was not an integer"
91
89
  )
@@ -53,10 +53,7 @@ class StopConditionPaginationStrategyDecorator(PaginationStrategy):
53
53
  return self._delegate.next_page_token(response, last_page_size, last_record)
54
54
 
55
55
  def reset(self, reset_value: Optional[Any] = None) -> None:
56
- if reset_value:
57
- self._delegate.reset(reset_value)
58
- else:
59
- self._delegate.reset()
56
+ self._delegate.reset(reset_value)
60
57
 
61
58
  def get_page_size(self) -> Optional[int]:
62
59
  return self._delegate.get_page_size()
@@ -14,6 +14,13 @@ from airbyte_cdk.sources.file_based.config.file_based_stream_config import FileB
14
14
  from airbyte_cdk.sources.utils import schema_helpers
15
15
 
16
16
 
17
+ class DeliveryOptions(BaseModel):
18
+ preserve_subdirectories_directories: bool = Field(
19
+ True,
20
+ description="Flag indicating we should preserve subdirectories directories",
21
+ )
22
+
23
+
17
24
  class DeliverRecords(BaseModel):
18
25
  class Config(OneOfOptionConfig):
19
26
  title = "Replicate Records"
@@ -30,6 +37,11 @@ class DeliverRawFiles(BaseModel):
30
37
  discriminator = "delivery_type"
31
38
 
32
39
  delivery_type: Literal["use_file_transfer"] = Field("use_file_transfer", const=True)
40
+ delivery_options: Optional[DeliveryOptions] = Field(
41
+ title="Delivery Options",
42
+ type="object",
43
+ order=2,
44
+ )
33
45
 
34
46
 
35
47
  class AbstractFileBasedSpec(BaseModel):
@@ -65,6 +77,12 @@ class AbstractFileBasedSpec(BaseModel):
65
77
  airbyte_hidden=True,
66
78
  )
67
79
 
80
+ delivery_options: Optional[DeliveryOptions] = Field(
81
+ title="Delivery Options",
82
+ type="object",
83
+ order=8,
84
+ )
85
+
68
86
  @classmethod
69
87
  @abstractmethod
70
88
  def documentation_url(cls) -> AnyUrl:
@@ -111,6 +111,10 @@ class ErrorListingFiles(BaseFileBasedSourceError):
111
111
  pass
112
112
 
113
113
 
114
+ class DuplicatedFilesError(BaseFileBasedSourceError):
115
+ pass
116
+
117
+
114
118
  class CustomFileBasedException(AirbyteTracedException):
115
119
  """
116
120
  A specialized exception for file-based connectors.
@@ -123,3 +127,25 @@ class CustomFileBasedException(AirbyteTracedException):
123
127
 
124
128
  class FileSizeLimitError(CustomFileBasedException):
125
129
  pass
130
+
131
+
132
+ def format_duplicate_files_error_message(
133
+ stream_name: str, duplicated_files_names: List[dict[str, List[str]]]
134
+ ) -> str:
135
+ duplicated_files_messages = []
136
+ for duplicated_file in duplicated_files_names:
137
+ for duplicated_file_name, file_paths in duplicated_file.items():
138
+ file_duplicated_message = (
139
+ f"{len(file_paths)} duplicates found for file name {duplicated_file_name}:\n\n"
140
+ + "".join(f"\n - {file_paths}")
141
+ )
142
+ duplicated_files_messages.append(file_duplicated_message)
143
+
144
+ error_message = (
145
+ f"ERROR: Duplicate filenames found for stream {stream_name}. "
146
+ "Duplicate file names are not allowed if the Preserve Subdirectories in File Paths option is disabled. "
147
+ "Please remove or rename the duplicate files before attempting to re-run the sync.\n\n"
148
+ + "\n".join(duplicated_files_messages)
149
+ )
150
+
151
+ return error_message
@@ -242,7 +242,7 @@ class FileBasedSource(ConcurrentSourceAdapter, ABC):
242
242
  stream=self._make_default_stream(
243
243
  stream_config=stream_config,
244
244
  cursor=cursor,
245
- use_file_transfer=self._use_file_transfer(parsed_config),
245
+ parsed_config=parsed_config,
246
246
  ),
247
247
  source=self,
248
248
  logger=self.logger,
@@ -273,7 +273,7 @@ class FileBasedSource(ConcurrentSourceAdapter, ABC):
273
273
  stream=self._make_default_stream(
274
274
  stream_config=stream_config,
275
275
  cursor=cursor,
276
- use_file_transfer=self._use_file_transfer(parsed_config),
276
+ parsed_config=parsed_config,
277
277
  ),
278
278
  source=self,
279
279
  logger=self.logger,
@@ -285,7 +285,7 @@ class FileBasedSource(ConcurrentSourceAdapter, ABC):
285
285
  stream = self._make_default_stream(
286
286
  stream_config=stream_config,
287
287
  cursor=cursor,
288
- use_file_transfer=self._use_file_transfer(parsed_config),
288
+ parsed_config=parsed_config,
289
289
  )
290
290
 
291
291
  streams.append(stream)
@@ -298,7 +298,7 @@ class FileBasedSource(ConcurrentSourceAdapter, ABC):
298
298
  self,
299
299
  stream_config: FileBasedStreamConfig,
300
300
  cursor: Optional[AbstractFileBasedCursor],
301
- use_file_transfer: bool = False,
301
+ parsed_config: AbstractFileBasedSpec,
302
302
  ) -> AbstractFileBasedStream:
303
303
  return DefaultFileBasedStream(
304
304
  config=stream_config,
@@ -310,7 +310,10 @@ class FileBasedSource(ConcurrentSourceAdapter, ABC):
310
310
  validation_policy=self._validate_and_get_validation_policy(stream_config),
311
311
  errors_collector=self.errors_collector,
312
312
  cursor=cursor,
313
- use_file_transfer=use_file_transfer,
313
+ use_file_transfer=self._use_file_transfer(parsed_config),
314
+ preserve_subdirectories_directories=self._preserve_subdirectories_directories(
315
+ parsed_config
316
+ ),
314
317
  )
315
318
 
316
319
  def _get_stream_from_catalog(
@@ -385,3 +388,14 @@ class FileBasedSource(ConcurrentSourceAdapter, ABC):
385
388
  and parsed_config.delivery_method.delivery_type == "use_file_transfer"
386
389
  )
387
390
  return use_file_transfer
391
+
392
+ @staticmethod
393
+ def _preserve_subdirectories_directories(parsed_config: AbstractFileBasedSpec) -> bool:
394
+ # fall back to preserve subdirectories if config is not present or incomplete
395
+ if (
396
+ hasattr(parsed_config, "delivery_options")
397
+ and parsed_config.delivery_options is not None
398
+ and hasattr(parsed_config.delivery_options, "preserve_subdirectories_directories")
399
+ ):
400
+ return parsed_config.delivery_options.preserve_subdirectories_directories
401
+ return True
@@ -135,6 +135,17 @@ class AbstractFileBasedStreamReader(ABC):
135
135
  return use_file_transfer
136
136
  return False
137
137
 
138
+ def preserve_subdirectories_directories(self) -> bool:
139
+ # fall back to preserve subdirectories if config is not present or incomplete
140
+ if (
141
+ self.config
142
+ and hasattr(self.config, "delivery_options")
143
+ and self.config.delivery_options is not None
144
+ and hasattr(self.config.delivery_options, "preserve_subdirectories_directories")
145
+ ):
146
+ return self.config.delivery_options.preserve_subdirectories_directories
147
+ return True
148
+
138
149
  @abstractmethod
139
150
  def get_file(
140
151
  self, file: RemoteFile, local_directory: str, logger: logging.Logger
@@ -159,10 +170,13 @@ class AbstractFileBasedStreamReader(ABC):
159
170
  """
160
171
  ...
161
172
 
162
- @staticmethod
163
- def _get_file_transfer_paths(file: RemoteFile, local_directory: str) -> List[str]:
164
- # Remove left slashes from source path format to make relative path for writing locally
165
- file_relative_path = file.uri.lstrip("/")
173
+ def _get_file_transfer_paths(self, file: RemoteFile, local_directory: str) -> List[str]:
174
+ preserve_subdirectories_directories = self.preserve_subdirectories_directories()
175
+ if preserve_subdirectories_directories:
176
+ # Remove left slashes from source path format to make relative path for writing locally
177
+ file_relative_path = file.uri.lstrip("/")
178
+ else:
179
+ file_relative_path = path.basename(file.uri)
166
180
  local_file_path = path.join(local_directory, file_relative_path)
167
181
 
168
182
  # Ensure the local directory exists
@@ -5,20 +5,24 @@
5
5
  import asyncio
6
6
  import itertools
7
7
  import traceback
8
+ from collections import defaultdict
8
9
  from copy import deepcopy
9
10
  from functools import cache
10
- from typing import Any, Dict, Iterable, List, Mapping, MutableMapping, Optional, Set, Union
11
+ from os import path
12
+ from typing import Any, Dict, Iterable, List, Mapping, MutableMapping, Optional, Set, Tuple, Union
11
13
 
12
14
  from airbyte_cdk.models import AirbyteLogMessage, AirbyteMessage, FailureType, Level
13
15
  from airbyte_cdk.models import Type as MessageType
14
16
  from airbyte_cdk.sources.file_based.config.file_based_stream_config import PrimaryKeyType
15
17
  from airbyte_cdk.sources.file_based.exceptions import (
18
+ DuplicatedFilesError,
16
19
  FileBasedSourceError,
17
20
  InvalidSchemaError,
18
21
  MissingSchemaError,
19
22
  RecordParseError,
20
23
  SchemaInferenceError,
21
24
  StopSyncPerValidationPolicy,
25
+ format_duplicate_files_error_message,
22
26
  )
23
27
  from airbyte_cdk.sources.file_based.file_types import FileTransfer
24
28
  from airbyte_cdk.sources.file_based.remote_file import RemoteFile
@@ -43,6 +47,8 @@ class DefaultFileBasedStream(AbstractFileBasedStream, IncrementalMixin):
43
47
  """
44
48
 
45
49
  FILE_TRANSFER_KW = "use_file_transfer"
50
+ PRESERVE_SUBDIRECTORIES_KW = "preserve_subdirectories_directories"
51
+ FILES_KEY = "files"
46
52
  DATE_TIME_FORMAT = "%Y-%m-%dT%H:%M:%S.%fZ"
47
53
  ab_last_mod_col = "_ab_source_file_last_modified"
48
54
  ab_file_name_col = "_ab_source_file_url"
@@ -50,10 +56,14 @@ class DefaultFileBasedStream(AbstractFileBasedStream, IncrementalMixin):
50
56
  source_file_url = "source_file_url"
51
57
  airbyte_columns = [ab_last_mod_col, ab_file_name_col]
52
58
  use_file_transfer = False
59
+ preserve_subdirectories_directories = True
53
60
 
54
61
  def __init__(self, **kwargs: Any):
55
62
  if self.FILE_TRANSFER_KW in kwargs:
56
63
  self.use_file_transfer = kwargs.pop(self.FILE_TRANSFER_KW, False)
64
+ self.preserve_subdirectories_directories = kwargs.pop(
65
+ self.PRESERVE_SUBDIRECTORIES_KW, True
66
+ )
57
67
  super().__init__(**kwargs)
58
68
 
59
69
  @property
@@ -98,15 +108,43 @@ class DefaultFileBasedStream(AbstractFileBasedStream, IncrementalMixin):
98
108
  else:
99
109
  return super()._filter_schema_invalid_properties(configured_catalog_json_schema)
100
110
 
111
+ def _duplicated_files_names(
112
+ self, slices: List[dict[str, List[RemoteFile]]]
113
+ ) -> List[dict[str, List[str]]]:
114
+ seen_file_names = set()
115
+ duplicates_file_names = set()
116
+ file_paths = defaultdict(list)
117
+ for file_slice in slices:
118
+ for file_found in file_slice[self.FILES_KEY]:
119
+ file_name = path.basename(file_found.uri)
120
+ if file_name not in seen_file_names:
121
+ seen_file_names.add(file_name)
122
+ else:
123
+ duplicates_file_names.add(file_name)
124
+ file_paths[file_name].append(file_found.uri)
125
+ return [
126
+ {duplicated_file: file_paths[duplicated_file]}
127
+ for duplicated_file in duplicates_file_names
128
+ ]
129
+
101
130
  def compute_slices(self) -> Iterable[Optional[Mapping[str, Any]]]:
102
131
  # Sort files by last_modified, uri and return them grouped by last_modified
103
132
  all_files = self.list_files()
104
133
  files_to_read = self._cursor.get_files_to_sync(all_files, self.logger)
105
134
  sorted_files_to_read = sorted(files_to_read, key=lambda f: (f.last_modified, f.uri))
106
135
  slices = [
107
- {"files": list(group[1])}
136
+ {self.FILES_KEY: list(group[1])}
108
137
  for group in itertools.groupby(sorted_files_to_read, lambda f: f.last_modified)
109
138
  ]
139
+ if slices and not self.preserve_subdirectories_directories:
140
+ duplicated_files_names = self._duplicated_files_names(slices)
141
+ if duplicated_files_names:
142
+ raise DuplicatedFilesError(
143
+ format_duplicate_files_error_message(
144
+ stream_name=self.name, duplicated_files_names=duplicated_files_names
145
+ ),
146
+ stream=self.name,
147
+ )
110
148
  return slices
111
149
 
112
150
  def transform_record(
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: airbyte-cdk
3
- Version: 6.13.0
3
+ Version: 6.13.1.dev4100
4
4
  Summary: A framework for writing Airbyte Connectors.
5
5
  Home-page: https://airbyte.com
6
6
  License: MIT
@@ -140,10 +140,10 @@ airbyte_cdk/sources/declarative/requesters/paginators/no_pagination.py,sha256=-P
140
140
  airbyte_cdk/sources/declarative/requesters/paginators/paginator.py,sha256=ZgyvH7DOrASQ5K__J5SRAXH3REUW2n3yPHnFW9xq4NU,1972
141
141
  airbyte_cdk/sources/declarative/requesters/paginators/strategies/__init__.py,sha256=2gly8fuZpDNwtu1Qg6oE2jBLGqQRdzSLJdnpk_iDV6I,767
142
142
  airbyte_cdk/sources/declarative/requesters/paginators/strategies/cursor_pagination_strategy.py,sha256=vFzpNv8BdgXrYO5qhi2_Un4x4y-EAQWxinZtEPWz5KI,3654
143
- airbyte_cdk/sources/declarative/requesters/paginators/strategies/offset_increment.py,sha256=TKG4Mp1t8MfmFJDeHtXmxCp_ibRK03J5O04N5HVtBvE,3430
143
+ airbyte_cdk/sources/declarative/requesters/paginators/strategies/offset_increment.py,sha256=pMPi6iQrhtrI9VRPj218QNM_OqD8lX8P3Tr9yloKoE8,3367
144
144
  airbyte_cdk/sources/declarative/requesters/paginators/strategies/page_increment.py,sha256=kQGpfr-dOwarxTIf2S4sHVulBzm8zSwQXBM7rOhkafA,2491
145
145
  airbyte_cdk/sources/declarative/requesters/paginators/strategies/pagination_strategy.py,sha256=ABpO4t0UUziBZnyml8UT_NhlF6loekhQji57TpKnaiY,1290
146
- airbyte_cdk/sources/declarative/requesters/paginators/strategies/stop_condition.py,sha256=2b005ulACvHgIL8ktTWwposu4umowyu0iGV2mGOb_Tg,2290
146
+ airbyte_cdk/sources/declarative/requesters/paginators/strategies/stop_condition.py,sha256=-8NwokW-aKwv8DdeHh1ssODTobBYSOmIhH2-IjSjlNA,2213
147
147
  airbyte_cdk/sources/declarative/requesters/request_option.py,sha256=_qmv8CLQQ3fERt6BuMZeRu6tZXscPoeARx1VJdWMQ_M,1055
148
148
  airbyte_cdk/sources/declarative/requesters/request_options/__init__.py,sha256=WCwpKqM4wKqy-DHJaCHbKAlFqRVOqMi9K5qonxIfi_Y,809
149
149
  airbyte_cdk/sources/declarative/requesters/request_options/datetime_based_request_options_provider.py,sha256=FLkg0uzC9bc-zFnALWr0FLYpKsz8iK2xQsd4UOyeW08,3706
@@ -193,7 +193,7 @@ airbyte_cdk/sources/file_based/availability_strategy/__init__.py,sha256=ddKQfUmk
193
193
  airbyte_cdk/sources/file_based/availability_strategy/abstract_file_based_availability_strategy.py,sha256=01Nd4b7ERAbp-OZo_8rrAzFXWPTMwr02SnWiN17nx8Q,2363
194
194
  airbyte_cdk/sources/file_based/availability_strategy/default_file_based_availability_strategy.py,sha256=j9T5TimfWFUz7nqsaj-83G3xWmDpsmeSbDnaUNmz0UM,5849
195
195
  airbyte_cdk/sources/file_based/config/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
196
- airbyte_cdk/sources/file_based/config/abstract_file_based_spec.py,sha256=tj-M1L5BTa5yIQ3jHo09CtCTSq_eR-68zgyOPqwsurw,6455
196
+ airbyte_cdk/sources/file_based/config/abstract_file_based_spec.py,sha256=1V7NpVdcVA7QNF_mI0uH5X3WqBvrS6U-W1iHoTiEDtY,6926
197
197
  airbyte_cdk/sources/file_based/config/avro_format.py,sha256=NxTF96ewzn6HuhgodsY7Rpb-ybr1ZEWW5d4Vid64g5A,716
198
198
  airbyte_cdk/sources/file_based/config/csv_format.py,sha256=NWekkyT8dTwiVK0mwa_krQD4FJPHSDfILo8kPAg3-Vs,8006
199
199
  airbyte_cdk/sources/file_based/config/excel_format.py,sha256=9qAmTsT6SoVzNfNv0oBVkVCmiyqQuVAbfRKajjoa7Js,378
@@ -204,9 +204,9 @@ airbyte_cdk/sources/file_based/config/unstructured_format.py,sha256=tIbB9Pn1HqU6
204
204
  airbyte_cdk/sources/file_based/discovery_policy/__init__.py,sha256=gl3ey6mZbyfraB9P3pFhf9UJp2JeTZ1SUFAopy2iBvY,301
205
205
  airbyte_cdk/sources/file_based/discovery_policy/abstract_discovery_policy.py,sha256=dCfXX529Rd5rtopg4VeEgTPJjFtqjtjzPq6LCw18Wt0,605
206
206
  airbyte_cdk/sources/file_based/discovery_policy/default_discovery_policy.py,sha256=-xujTidtrq6HC00WKbjQh1CZdT5LMuzkp5BLjqDmfTY,1007
207
- airbyte_cdk/sources/file_based/exceptions.py,sha256=AEELNIRzKPX6eopKd_2jhE7WiNeR0Aw7nQWVOL8fvkc,5760
208
- airbyte_cdk/sources/file_based/file_based_source.py,sha256=RfpctRNLJ_EHKKEc2E1EZGYRfhG0Z9o6TgsKS4XrSNY,16652
209
- airbyte_cdk/sources/file_based/file_based_stream_reader.py,sha256=ohxKlqPuV7TGwjyRy_gaWUol8QN5lBSoCYoaqBtRh1c,6179
207
+ airbyte_cdk/sources/file_based/exceptions.py,sha256=KfOgQgssBKgsv3h5po2IG1DhZcH664Zf_fx96mBlPSg,6761
208
+ airbyte_cdk/sources/file_based/file_based_source.py,sha256=Z-1EQS8_gczgBgBHJV75LCwHOtXgonEqxNpXmNmqVTM,17263
209
+ airbyte_cdk/sources/file_based/file_based_stream_reader.py,sha256=Uwg_e9wHdJ2UaWxHcW2Ph6S4sHDhB0_MoyCEW7neVdA,6888
210
210
  airbyte_cdk/sources/file_based/file_types/__init__.py,sha256=blCLn0-2LC-ZdgcNyDEhqM2RiUvEjEBh-G4-t32ZtuM,1268
211
211
  airbyte_cdk/sources/file_based/file_types/avro_parser.py,sha256=XNx-JC-sgzH9u3nOJ2M59FxBXvtig8LN6BIkeDOavZA,10858
212
212
  airbyte_cdk/sources/file_based/file_types/csv_parser.py,sha256=QlCXB-ry3np67Q_VerQEPoWDOTcPTB6Go4ydZxY9ae4,20445
@@ -232,7 +232,7 @@ airbyte_cdk/sources/file_based/stream/concurrent/cursor/file_based_final_state_c
232
232
  airbyte_cdk/sources/file_based/stream/cursor/__init__.py,sha256=MhFB5hOo8sjwvCh8gangaymdg3EJWYt_72brFOZt068,191
233
233
  airbyte_cdk/sources/file_based/stream/cursor/abstract_file_based_cursor.py,sha256=om-x3gZFPgWDpi15S9RxZmR36VHnk8sytgN6LlBQhAw,1934
234
234
  airbyte_cdk/sources/file_based/stream/cursor/default_file_based_cursor.py,sha256=VGV7xLyBribuBMVrXtO1xqkWJD86bl7yhXtjnwLMohM,7051
235
- airbyte_cdk/sources/file_based/stream/default_file_based_stream.py,sha256=rpwU6AOyhFLuXtcFKkcOHFWbRQ4kLCOKzAjcID_M87k,16770
235
+ airbyte_cdk/sources/file_based/stream/default_file_based_stream.py,sha256=HRjR0rQGc8cYK2PxpLgAvZQ--jvtV8QgS1QIxkemnko,18413
236
236
  airbyte_cdk/sources/file_based/types.py,sha256=INxG7OPnkdUP69oYNKMAbwhvV1AGvLRHs1J6pIia2FI,218
237
237
  airbyte_cdk/sources/http_config.py,sha256=OBZeuyFilm6NlDlBhFQvHhTWabEvZww6OHDIlZujIS0,730
238
238
  airbyte_cdk/sources/http_logger.py,sha256=TyBmtRA6D9g0XDkKGvdM415b36RXDjgfkwRewDsH8-0,1576
@@ -340,8 +340,8 @@ airbyte_cdk/utils/slice_hasher.py,sha256=-pHexlNYoWYPnXNH-M7HEbjmeJe9Zk7SJijdQ7d
340
340
  airbyte_cdk/utils/spec_schema_transformations.py,sha256=-5HTuNsnDBAhj-oLeQXwpTGA0HdcjFOf2zTEMUTTg_Y,816
341
341
  airbyte_cdk/utils/stream_status_utils.py,sha256=ZmBoiy5HVbUEHAMrUONxZvxnvfV9CesmQJLDTAIWnWw,1171
342
342
  airbyte_cdk/utils/traced_exception.py,sha256=C8uIBuCL_E4WnBAOPSxBicD06JAldoN9fGsQDp463OY,6292
343
- airbyte_cdk-6.13.0.dist-info/LICENSE.txt,sha256=Wfe61S4BaGPj404v8lrAbvhjYR68SHlkzeYrg3_bbuM,1051
344
- airbyte_cdk-6.13.0.dist-info/METADATA,sha256=Iwa16bm84hAFYmkLc2CvpiktJh7jFymHCYFUfoPUZlI,5988
345
- airbyte_cdk-6.13.0.dist-info/WHEEL,sha256=RaoafKOydTQ7I_I3JTrPCg6kUmTgtm4BornzOqyEfJ8,88
346
- airbyte_cdk-6.13.0.dist-info/entry_points.txt,sha256=fj-e3PAQvsxsQzyyq8UkG1k8spunWnD4BAH2AwlR6NM,95
347
- airbyte_cdk-6.13.0.dist-info/RECORD,,
343
+ airbyte_cdk-6.13.1.dev4100.dist-info/LICENSE.txt,sha256=Wfe61S4BaGPj404v8lrAbvhjYR68SHlkzeYrg3_bbuM,1051
344
+ airbyte_cdk-6.13.1.dev4100.dist-info/METADATA,sha256=P_PnklFtJqLdDdAxsiOLX7Ydkee8d7jz9m_v2XNCRAI,5996
345
+ airbyte_cdk-6.13.1.dev4100.dist-info/WHEEL,sha256=RaoafKOydTQ7I_I3JTrPCg6kUmTgtm4BornzOqyEfJ8,88
346
+ airbyte_cdk-6.13.1.dev4100.dist-info/entry_points.txt,sha256=fj-e3PAQvsxsQzyyq8UkG1k8spunWnD4BAH2AwlR6NM,95
347
+ airbyte_cdk-6.13.1.dev4100.dist-info/RECORD,,