airbyte-cdk 0.0.0.dev0__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 (368) hide show
  1. airbyte_cdk/__init__.py +358 -0
  2. airbyte_cdk/cli/__init__.py +1 -0
  3. airbyte_cdk/cli/source_declarative_manifest/__init__.py +5 -0
  4. airbyte_cdk/cli/source_declarative_manifest/_run.py +236 -0
  5. airbyte_cdk/cli/source_declarative_manifest/spec.json +17 -0
  6. airbyte_cdk/config_observation.py +104 -0
  7. airbyte_cdk/connector.py +123 -0
  8. airbyte_cdk/connector_builder/README.md +53 -0
  9. airbyte_cdk/connector_builder/__init__.py +3 -0
  10. airbyte_cdk/connector_builder/connector_builder_handler.py +121 -0
  11. airbyte_cdk/connector_builder/main.py +107 -0
  12. airbyte_cdk/connector_builder/models.py +73 -0
  13. airbyte_cdk/connector_builder/test_reader/__init__.py +7 -0
  14. airbyte_cdk/connector_builder/test_reader/helpers.py +689 -0
  15. airbyte_cdk/connector_builder/test_reader/message_grouper.py +173 -0
  16. airbyte_cdk/connector_builder/test_reader/reader.py +441 -0
  17. airbyte_cdk/connector_builder/test_reader/types.py +83 -0
  18. airbyte_cdk/destinations/__init__.py +8 -0
  19. airbyte_cdk/destinations/destination.py +154 -0
  20. airbyte_cdk/destinations/vector_db_based/README.md +37 -0
  21. airbyte_cdk/destinations/vector_db_based/__init__.py +38 -0
  22. airbyte_cdk/destinations/vector_db_based/config.py +298 -0
  23. airbyte_cdk/destinations/vector_db_based/document_processor.py +223 -0
  24. airbyte_cdk/destinations/vector_db_based/embedder.py +303 -0
  25. airbyte_cdk/destinations/vector_db_based/indexer.py +78 -0
  26. airbyte_cdk/destinations/vector_db_based/test_utils.py +63 -0
  27. airbyte_cdk/destinations/vector_db_based/utils.py +35 -0
  28. airbyte_cdk/destinations/vector_db_based/writer.py +104 -0
  29. airbyte_cdk/entrypoint.py +414 -0
  30. airbyte_cdk/exception_handler.py +56 -0
  31. airbyte_cdk/logger.py +109 -0
  32. airbyte_cdk/models/__init__.py +72 -0
  33. airbyte_cdk/models/airbyte_protocol.py +88 -0
  34. airbyte_cdk/models/airbyte_protocol_serializers.py +44 -0
  35. airbyte_cdk/models/well_known_types.py +5 -0
  36. airbyte_cdk/py.typed +0 -0
  37. airbyte_cdk/sources/__init__.py +26 -0
  38. airbyte_cdk/sources/abstract_source.py +326 -0
  39. airbyte_cdk/sources/concurrent_source/__init__.py +8 -0
  40. airbyte_cdk/sources/concurrent_source/concurrent_read_processor.py +255 -0
  41. airbyte_cdk/sources/concurrent_source/concurrent_source.py +165 -0
  42. airbyte_cdk/sources/concurrent_source/concurrent_source_adapter.py +147 -0
  43. airbyte_cdk/sources/concurrent_source/partition_generation_completed_sentinel.py +24 -0
  44. airbyte_cdk/sources/concurrent_source/stream_thread_exception.py +25 -0
  45. airbyte_cdk/sources/concurrent_source/thread_pool_manager.py +115 -0
  46. airbyte_cdk/sources/config.py +27 -0
  47. airbyte_cdk/sources/connector_state_manager.py +161 -0
  48. airbyte_cdk/sources/declarative/__init__.py +3 -0
  49. airbyte_cdk/sources/declarative/async_job/__init__.py +0 -0
  50. airbyte_cdk/sources/declarative/async_job/job.py +52 -0
  51. airbyte_cdk/sources/declarative/async_job/job_orchestrator.py +525 -0
  52. airbyte_cdk/sources/declarative/async_job/job_tracker.py +79 -0
  53. airbyte_cdk/sources/declarative/async_job/repository.py +35 -0
  54. airbyte_cdk/sources/declarative/async_job/status.py +24 -0
  55. airbyte_cdk/sources/declarative/async_job/timer.py +39 -0
  56. airbyte_cdk/sources/declarative/auth/__init__.py +8 -0
  57. airbyte_cdk/sources/declarative/auth/declarative_authenticator.py +42 -0
  58. airbyte_cdk/sources/declarative/auth/jwt.py +197 -0
  59. airbyte_cdk/sources/declarative/auth/oauth.py +293 -0
  60. airbyte_cdk/sources/declarative/auth/selective_authenticator.py +45 -0
  61. airbyte_cdk/sources/declarative/auth/token.py +267 -0
  62. airbyte_cdk/sources/declarative/auth/token_provider.py +82 -0
  63. airbyte_cdk/sources/declarative/checks/__init__.py +24 -0
  64. airbyte_cdk/sources/declarative/checks/check_dynamic_stream.py +61 -0
  65. airbyte_cdk/sources/declarative/checks/check_stream.py +56 -0
  66. airbyte_cdk/sources/declarative/checks/connection_checker.py +35 -0
  67. airbyte_cdk/sources/declarative/concurrency_level/__init__.py +7 -0
  68. airbyte_cdk/sources/declarative/concurrency_level/concurrency_level.py +50 -0
  69. airbyte_cdk/sources/declarative/concurrent_declarative_source.py +526 -0
  70. airbyte_cdk/sources/declarative/datetime/__init__.py +3 -0
  71. airbyte_cdk/sources/declarative/datetime/datetime_parser.py +65 -0
  72. airbyte_cdk/sources/declarative/datetime/min_max_datetime.py +118 -0
  73. airbyte_cdk/sources/declarative/declarative_component_schema.yaml +3975 -0
  74. airbyte_cdk/sources/declarative/declarative_source.py +36 -0
  75. airbyte_cdk/sources/declarative/declarative_stream.py +241 -0
  76. airbyte_cdk/sources/declarative/decoders/__init__.py +33 -0
  77. airbyte_cdk/sources/declarative/decoders/composite_raw_decoder.py +218 -0
  78. airbyte_cdk/sources/declarative/decoders/decoder.py +32 -0
  79. airbyte_cdk/sources/declarative/decoders/decoder_parser.py +30 -0
  80. airbyte_cdk/sources/declarative/decoders/json_decoder.py +65 -0
  81. airbyte_cdk/sources/declarative/decoders/noop_decoder.py +21 -0
  82. airbyte_cdk/sources/declarative/decoders/pagination_decoder_decorator.py +39 -0
  83. airbyte_cdk/sources/declarative/decoders/xml_decoder.py +98 -0
  84. airbyte_cdk/sources/declarative/decoders/zipfile_decoder.py +56 -0
  85. airbyte_cdk/sources/declarative/exceptions.py +9 -0
  86. airbyte_cdk/sources/declarative/extractors/__init__.py +21 -0
  87. airbyte_cdk/sources/declarative/extractors/dpath_extractor.py +86 -0
  88. airbyte_cdk/sources/declarative/extractors/http_selector.py +37 -0
  89. airbyte_cdk/sources/declarative/extractors/record_extractor.py +27 -0
  90. airbyte_cdk/sources/declarative/extractors/record_filter.py +91 -0
  91. airbyte_cdk/sources/declarative/extractors/record_selector.py +170 -0
  92. airbyte_cdk/sources/declarative/extractors/response_to_file_extractor.py +176 -0
  93. airbyte_cdk/sources/declarative/extractors/type_transformer.py +55 -0
  94. airbyte_cdk/sources/declarative/incremental/__init__.py +37 -0
  95. airbyte_cdk/sources/declarative/incremental/concurrent_partition_cursor.py +497 -0
  96. airbyte_cdk/sources/declarative/incremental/datetime_based_cursor.py +459 -0
  97. airbyte_cdk/sources/declarative/incremental/declarative_cursor.py +13 -0
  98. airbyte_cdk/sources/declarative/incremental/global_substream_cursor.py +357 -0
  99. airbyte_cdk/sources/declarative/incremental/per_partition_cursor.py +380 -0
  100. airbyte_cdk/sources/declarative/incremental/per_partition_with_global.py +200 -0
  101. airbyte_cdk/sources/declarative/incremental/resumable_full_refresh_cursor.py +122 -0
  102. airbyte_cdk/sources/declarative/interpolation/__init__.py +9 -0
  103. airbyte_cdk/sources/declarative/interpolation/filters.py +139 -0
  104. airbyte_cdk/sources/declarative/interpolation/interpolated_boolean.py +66 -0
  105. airbyte_cdk/sources/declarative/interpolation/interpolated_mapping.py +56 -0
  106. airbyte_cdk/sources/declarative/interpolation/interpolated_nested_mapping.py +52 -0
  107. airbyte_cdk/sources/declarative/interpolation/interpolated_string.py +79 -0
  108. airbyte_cdk/sources/declarative/interpolation/interpolation.py +34 -0
  109. airbyte_cdk/sources/declarative/interpolation/jinja.py +161 -0
  110. airbyte_cdk/sources/declarative/interpolation/macros.py +191 -0
  111. airbyte_cdk/sources/declarative/manifest_declarative_source.py +421 -0
  112. airbyte_cdk/sources/declarative/migrations/__init__.py +0 -0
  113. airbyte_cdk/sources/declarative/migrations/legacy_to_per_partition_state_migration.py +98 -0
  114. airbyte_cdk/sources/declarative/migrations/state_migration.py +24 -0
  115. airbyte_cdk/sources/declarative/models/__init__.py +2 -0
  116. airbyte_cdk/sources/declarative/models/declarative_component_schema.py +2503 -0
  117. airbyte_cdk/sources/declarative/parsers/__init__.py +3 -0
  118. airbyte_cdk/sources/declarative/parsers/custom_code_compiler.py +157 -0
  119. airbyte_cdk/sources/declarative/parsers/custom_exceptions.py +21 -0
  120. airbyte_cdk/sources/declarative/parsers/manifest_component_transformer.py +172 -0
  121. airbyte_cdk/sources/declarative/parsers/manifest_reference_resolver.py +213 -0
  122. airbyte_cdk/sources/declarative/parsers/model_to_component_factory.py +3407 -0
  123. airbyte_cdk/sources/declarative/partition_routers/__init__.py +29 -0
  124. airbyte_cdk/sources/declarative/partition_routers/async_job_partition_router.py +65 -0
  125. airbyte_cdk/sources/declarative/partition_routers/cartesian_product_stream_slicer.py +176 -0
  126. airbyte_cdk/sources/declarative/partition_routers/list_partition_router.py +121 -0
  127. airbyte_cdk/sources/declarative/partition_routers/partition_router.py +62 -0
  128. airbyte_cdk/sources/declarative/partition_routers/single_partition_router.py +63 -0
  129. airbyte_cdk/sources/declarative/partition_routers/substream_partition_router.py +437 -0
  130. airbyte_cdk/sources/declarative/requesters/README.md +56 -0
  131. airbyte_cdk/sources/declarative/requesters/__init__.py +9 -0
  132. airbyte_cdk/sources/declarative/requesters/error_handlers/__init__.py +25 -0
  133. airbyte_cdk/sources/declarative/requesters/error_handlers/backoff_strategies/__init__.py +23 -0
  134. airbyte_cdk/sources/declarative/requesters/error_handlers/backoff_strategies/constant_backoff_strategy.py +45 -0
  135. airbyte_cdk/sources/declarative/requesters/error_handlers/backoff_strategies/exponential_backoff_strategy.py +45 -0
  136. airbyte_cdk/sources/declarative/requesters/error_handlers/backoff_strategies/header_helper.py +41 -0
  137. airbyte_cdk/sources/declarative/requesters/error_handlers/backoff_strategies/wait_time_from_header_backoff_strategy.py +70 -0
  138. airbyte_cdk/sources/declarative/requesters/error_handlers/backoff_strategies/wait_until_time_from_header_backoff_strategy.py +77 -0
  139. airbyte_cdk/sources/declarative/requesters/error_handlers/backoff_strategy.py +17 -0
  140. airbyte_cdk/sources/declarative/requesters/error_handlers/composite_error_handler.py +101 -0
  141. airbyte_cdk/sources/declarative/requesters/error_handlers/default_error_handler.py +147 -0
  142. airbyte_cdk/sources/declarative/requesters/error_handlers/default_http_response_filter.py +40 -0
  143. airbyte_cdk/sources/declarative/requesters/error_handlers/error_handler.py +17 -0
  144. airbyte_cdk/sources/declarative/requesters/error_handlers/http_response_filter.py +179 -0
  145. airbyte_cdk/sources/declarative/requesters/http_job_repository.py +350 -0
  146. airbyte_cdk/sources/declarative/requesters/http_requester.py +433 -0
  147. airbyte_cdk/sources/declarative/requesters/paginators/__init__.py +21 -0
  148. airbyte_cdk/sources/declarative/requesters/paginators/default_paginator.py +327 -0
  149. airbyte_cdk/sources/declarative/requesters/paginators/no_pagination.py +76 -0
  150. airbyte_cdk/sources/declarative/requesters/paginators/paginator.py +65 -0
  151. airbyte_cdk/sources/declarative/requesters/paginators/strategies/__init__.py +25 -0
  152. airbyte_cdk/sources/declarative/requesters/paginators/strategies/cursor_pagination_strategy.py +98 -0
  153. airbyte_cdk/sources/declarative/requesters/paginators/strategies/offset_increment.py +102 -0
  154. airbyte_cdk/sources/declarative/requesters/paginators/strategies/page_increment.py +71 -0
  155. airbyte_cdk/sources/declarative/requesters/paginators/strategies/pagination_strategy.py +48 -0
  156. airbyte_cdk/sources/declarative/requesters/paginators/strategies/stop_condition.py +66 -0
  157. airbyte_cdk/sources/declarative/requesters/request_option.py +117 -0
  158. airbyte_cdk/sources/declarative/requesters/request_options/__init__.py +23 -0
  159. airbyte_cdk/sources/declarative/requesters/request_options/datetime_based_request_options_provider.py +92 -0
  160. airbyte_cdk/sources/declarative/requesters/request_options/default_request_options_provider.py +60 -0
  161. airbyte_cdk/sources/declarative/requesters/request_options/interpolated_nested_request_input_provider.py +59 -0
  162. airbyte_cdk/sources/declarative/requesters/request_options/interpolated_request_input_provider.py +68 -0
  163. airbyte_cdk/sources/declarative/requesters/request_options/interpolated_request_options_provider.py +119 -0
  164. airbyte_cdk/sources/declarative/requesters/request_options/request_options_provider.py +79 -0
  165. airbyte_cdk/sources/declarative/requesters/request_path.py +15 -0
  166. airbyte_cdk/sources/declarative/requesters/requester.py +144 -0
  167. airbyte_cdk/sources/declarative/resolvers/__init__.py +41 -0
  168. airbyte_cdk/sources/declarative/resolvers/components_resolver.py +55 -0
  169. airbyte_cdk/sources/declarative/resolvers/config_components_resolver.py +136 -0
  170. airbyte_cdk/sources/declarative/resolvers/http_components_resolver.py +112 -0
  171. airbyte_cdk/sources/declarative/retrievers/__init__.py +19 -0
  172. airbyte_cdk/sources/declarative/retrievers/async_retriever.py +124 -0
  173. airbyte_cdk/sources/declarative/retrievers/file_uploader.py +89 -0
  174. airbyte_cdk/sources/declarative/retrievers/retriever.py +54 -0
  175. airbyte_cdk/sources/declarative/retrievers/simple_retriever.py +702 -0
  176. airbyte_cdk/sources/declarative/schema/__init__.py +25 -0
  177. airbyte_cdk/sources/declarative/schema/default_schema_loader.py +47 -0
  178. airbyte_cdk/sources/declarative/schema/dynamic_schema_loader.py +285 -0
  179. airbyte_cdk/sources/declarative/schema/inline_schema_loader.py +19 -0
  180. airbyte_cdk/sources/declarative/schema/json_file_schema_loader.py +92 -0
  181. airbyte_cdk/sources/declarative/schema/schema_loader.py +17 -0
  182. airbyte_cdk/sources/declarative/spec/__init__.py +7 -0
  183. airbyte_cdk/sources/declarative/spec/spec.py +48 -0
  184. airbyte_cdk/sources/declarative/stream_slicers/__init__.py +7 -0
  185. airbyte_cdk/sources/declarative/stream_slicers/declarative_partition_generator.py +93 -0
  186. airbyte_cdk/sources/declarative/stream_slicers/stream_slicer.py +25 -0
  187. airbyte_cdk/sources/declarative/transformations/__init__.py +17 -0
  188. airbyte_cdk/sources/declarative/transformations/add_fields.py +146 -0
  189. airbyte_cdk/sources/declarative/transformations/dpath_flatten_fields.py +61 -0
  190. airbyte_cdk/sources/declarative/transformations/flatten_fields.py +52 -0
  191. airbyte_cdk/sources/declarative/transformations/keys_replace_transformation.py +61 -0
  192. airbyte_cdk/sources/declarative/transformations/keys_to_lower_transformation.py +22 -0
  193. airbyte_cdk/sources/declarative/transformations/keys_to_snake_transformation.py +68 -0
  194. airbyte_cdk/sources/declarative/transformations/remove_fields.py +75 -0
  195. airbyte_cdk/sources/declarative/transformations/transformation.py +37 -0
  196. airbyte_cdk/sources/declarative/types.py +25 -0
  197. airbyte_cdk/sources/declarative/yaml_declarative_source.py +67 -0
  198. airbyte_cdk/sources/file_based/README.md +152 -0
  199. airbyte_cdk/sources/file_based/__init__.py +24 -0
  200. airbyte_cdk/sources/file_based/availability_strategy/__init__.py +11 -0
  201. airbyte_cdk/sources/file_based/availability_strategy/abstract_file_based_availability_strategy.py +73 -0
  202. airbyte_cdk/sources/file_based/availability_strategy/default_file_based_availability_strategy.py +149 -0
  203. airbyte_cdk/sources/file_based/config/__init__.py +0 -0
  204. airbyte_cdk/sources/file_based/config/abstract_file_based_spec.py +153 -0
  205. airbyte_cdk/sources/file_based/config/avro_format.py +25 -0
  206. airbyte_cdk/sources/file_based/config/csv_format.py +210 -0
  207. airbyte_cdk/sources/file_based/config/excel_format.py +18 -0
  208. airbyte_cdk/sources/file_based/config/file_based_stream_config.py +99 -0
  209. airbyte_cdk/sources/file_based/config/jsonl_format.py +18 -0
  210. airbyte_cdk/sources/file_based/config/parquet_format.py +25 -0
  211. airbyte_cdk/sources/file_based/config/unstructured_format.py +102 -0
  212. airbyte_cdk/sources/file_based/config/validate_config_transfer_modes.py +81 -0
  213. airbyte_cdk/sources/file_based/discovery_policy/__init__.py +8 -0
  214. airbyte_cdk/sources/file_based/discovery_policy/abstract_discovery_policy.py +21 -0
  215. airbyte_cdk/sources/file_based/discovery_policy/default_discovery_policy.py +33 -0
  216. airbyte_cdk/sources/file_based/exceptions.py +159 -0
  217. airbyte_cdk/sources/file_based/file_based_source.py +466 -0
  218. airbyte_cdk/sources/file_based/file_based_stream_permissions_reader.py +123 -0
  219. airbyte_cdk/sources/file_based/file_based_stream_reader.py +209 -0
  220. airbyte_cdk/sources/file_based/file_record_data.py +22 -0
  221. airbyte_cdk/sources/file_based/file_types/__init__.py +37 -0
  222. airbyte_cdk/sources/file_based/file_types/avro_parser.py +233 -0
  223. airbyte_cdk/sources/file_based/file_types/csv_parser.py +527 -0
  224. airbyte_cdk/sources/file_based/file_types/excel_parser.py +196 -0
  225. airbyte_cdk/sources/file_based/file_types/file_transfer.py +30 -0
  226. airbyte_cdk/sources/file_based/file_types/file_type_parser.py +86 -0
  227. airbyte_cdk/sources/file_based/file_types/jsonl_parser.py +145 -0
  228. airbyte_cdk/sources/file_based/file_types/parquet_parser.py +275 -0
  229. airbyte_cdk/sources/file_based/file_types/unstructured_parser.py +480 -0
  230. airbyte_cdk/sources/file_based/remote_file.py +18 -0
  231. airbyte_cdk/sources/file_based/schema_helpers.py +281 -0
  232. airbyte_cdk/sources/file_based/schema_validation_policies/__init__.py +17 -0
  233. airbyte_cdk/sources/file_based/schema_validation_policies/abstract_schema_validation_policy.py +20 -0
  234. airbyte_cdk/sources/file_based/schema_validation_policies/default_schema_validation_policies.py +52 -0
  235. airbyte_cdk/sources/file_based/stream/__init__.py +13 -0
  236. airbyte_cdk/sources/file_based/stream/abstract_file_based_stream.py +197 -0
  237. airbyte_cdk/sources/file_based/stream/concurrent/__init__.py +0 -0
  238. airbyte_cdk/sources/file_based/stream/concurrent/adapters.py +343 -0
  239. airbyte_cdk/sources/file_based/stream/concurrent/cursor/__init__.py +9 -0
  240. airbyte_cdk/sources/file_based/stream/concurrent/cursor/abstract_concurrent_file_based_cursor.py +59 -0
  241. airbyte_cdk/sources/file_based/stream/concurrent/cursor/file_based_concurrent_cursor.py +313 -0
  242. airbyte_cdk/sources/file_based/stream/concurrent/cursor/file_based_final_state_cursor.py +83 -0
  243. airbyte_cdk/sources/file_based/stream/cursor/__init__.py +4 -0
  244. airbyte_cdk/sources/file_based/stream/cursor/abstract_file_based_cursor.py +66 -0
  245. airbyte_cdk/sources/file_based/stream/cursor/default_file_based_cursor.py +149 -0
  246. airbyte_cdk/sources/file_based/stream/default_file_based_stream.py +396 -0
  247. airbyte_cdk/sources/file_based/stream/identities_stream.py +49 -0
  248. airbyte_cdk/sources/file_based/stream/permissions_file_based_stream.py +92 -0
  249. airbyte_cdk/sources/file_based/types.py +10 -0
  250. airbyte_cdk/sources/http_config.py +10 -0
  251. airbyte_cdk/sources/http_logger.py +55 -0
  252. airbyte_cdk/sources/message/__init__.py +19 -0
  253. airbyte_cdk/sources/message/repository.py +137 -0
  254. airbyte_cdk/sources/source.py +95 -0
  255. airbyte_cdk/sources/specs/transfer_modes.py +26 -0
  256. airbyte_cdk/sources/streams/__init__.py +8 -0
  257. airbyte_cdk/sources/streams/availability_strategy.py +84 -0
  258. airbyte_cdk/sources/streams/call_rate.py +704 -0
  259. airbyte_cdk/sources/streams/checkpoint/__init__.py +26 -0
  260. airbyte_cdk/sources/streams/checkpoint/checkpoint_reader.py +335 -0
  261. airbyte_cdk/sources/streams/checkpoint/cursor.py +77 -0
  262. airbyte_cdk/sources/streams/checkpoint/per_partition_key_serializer.py +22 -0
  263. airbyte_cdk/sources/streams/checkpoint/resumable_full_refresh_cursor.py +51 -0
  264. airbyte_cdk/sources/streams/checkpoint/substream_resumable_full_refresh_cursor.py +110 -0
  265. airbyte_cdk/sources/streams/concurrent/README.md +7 -0
  266. airbyte_cdk/sources/streams/concurrent/__init__.py +3 -0
  267. airbyte_cdk/sources/streams/concurrent/abstract_stream.py +96 -0
  268. airbyte_cdk/sources/streams/concurrent/abstract_stream_facade.py +37 -0
  269. airbyte_cdk/sources/streams/concurrent/adapters.py +397 -0
  270. airbyte_cdk/sources/streams/concurrent/availability_strategy.py +94 -0
  271. airbyte_cdk/sources/streams/concurrent/clamping.py +99 -0
  272. airbyte_cdk/sources/streams/concurrent/cursor.py +481 -0
  273. airbyte_cdk/sources/streams/concurrent/cursor_types.py +32 -0
  274. airbyte_cdk/sources/streams/concurrent/default_stream.py +102 -0
  275. airbyte_cdk/sources/streams/concurrent/exceptions.py +18 -0
  276. airbyte_cdk/sources/streams/concurrent/helpers.py +42 -0
  277. airbyte_cdk/sources/streams/concurrent/partition_enqueuer.py +64 -0
  278. airbyte_cdk/sources/streams/concurrent/partition_reader.py +45 -0
  279. airbyte_cdk/sources/streams/concurrent/partitions/__init__.py +3 -0
  280. airbyte_cdk/sources/streams/concurrent/partitions/partition.py +48 -0
  281. airbyte_cdk/sources/streams/concurrent/partitions/partition_generator.py +18 -0
  282. airbyte_cdk/sources/streams/concurrent/partitions/stream_slicer.py +21 -0
  283. airbyte_cdk/sources/streams/concurrent/partitions/types.py +38 -0
  284. airbyte_cdk/sources/streams/concurrent/state_converters/__init__.py +0 -0
  285. airbyte_cdk/sources/streams/concurrent/state_converters/abstract_stream_state_converter.py +182 -0
  286. airbyte_cdk/sources/streams/concurrent/state_converters/datetime_stream_state_converter.py +223 -0
  287. airbyte_cdk/sources/streams/concurrent/state_converters/incrementing_count_stream_state_converter.py +92 -0
  288. airbyte_cdk/sources/streams/core.py +703 -0
  289. airbyte_cdk/sources/streams/http/__init__.py +10 -0
  290. airbyte_cdk/sources/streams/http/availability_strategy.py +54 -0
  291. airbyte_cdk/sources/streams/http/error_handlers/__init__.py +22 -0
  292. airbyte_cdk/sources/streams/http/error_handlers/backoff_strategy.py +28 -0
  293. airbyte_cdk/sources/streams/http/error_handlers/default_backoff_strategy.py +17 -0
  294. airbyte_cdk/sources/streams/http/error_handlers/default_error_mapping.py +86 -0
  295. airbyte_cdk/sources/streams/http/error_handlers/error_handler.py +42 -0
  296. airbyte_cdk/sources/streams/http/error_handlers/error_message_parser.py +19 -0
  297. airbyte_cdk/sources/streams/http/error_handlers/http_status_error_handler.py +110 -0
  298. airbyte_cdk/sources/streams/http/error_handlers/json_error_message_parser.py +52 -0
  299. airbyte_cdk/sources/streams/http/error_handlers/response_models.py +65 -0
  300. airbyte_cdk/sources/streams/http/exceptions.py +61 -0
  301. airbyte_cdk/sources/streams/http/http.py +673 -0
  302. airbyte_cdk/sources/streams/http/http_client.py +531 -0
  303. airbyte_cdk/sources/streams/http/rate_limiting.py +158 -0
  304. airbyte_cdk/sources/streams/http/requests_native_auth/__init__.py +14 -0
  305. airbyte_cdk/sources/streams/http/requests_native_auth/abstract_oauth.py +479 -0
  306. airbyte_cdk/sources/streams/http/requests_native_auth/abstract_token.py +34 -0
  307. airbyte_cdk/sources/streams/http/requests_native_auth/oauth.py +436 -0
  308. airbyte_cdk/sources/streams/http/requests_native_auth/token.py +83 -0
  309. airbyte_cdk/sources/streams/permissions/identities_stream.py +75 -0
  310. airbyte_cdk/sources/streams/utils/__init__.py +3 -0
  311. airbyte_cdk/sources/types.py +169 -0
  312. airbyte_cdk/sources/utils/__init__.py +7 -0
  313. airbyte_cdk/sources/utils/casing.py +12 -0
  314. airbyte_cdk/sources/utils/files_directory.py +15 -0
  315. airbyte_cdk/sources/utils/record_helper.py +53 -0
  316. airbyte_cdk/sources/utils/schema_helpers.py +230 -0
  317. airbyte_cdk/sources/utils/slice_logger.py +57 -0
  318. airbyte_cdk/sources/utils/transform.py +277 -0
  319. airbyte_cdk/sources/utils/types.py +7 -0
  320. airbyte_cdk/sql/__init__.py +0 -0
  321. airbyte_cdk/sql/_util/__init__.py +0 -0
  322. airbyte_cdk/sql/_util/hashing.py +34 -0
  323. airbyte_cdk/sql/_util/name_normalizers.py +92 -0
  324. airbyte_cdk/sql/constants.py +32 -0
  325. airbyte_cdk/sql/exceptions.py +235 -0
  326. airbyte_cdk/sql/secrets.py +123 -0
  327. airbyte_cdk/sql/shared/__init__.py +15 -0
  328. airbyte_cdk/sql/shared/catalog_providers.py +145 -0
  329. airbyte_cdk/sql/shared/sql_processor.py +786 -0
  330. airbyte_cdk/sql/types.py +160 -0
  331. airbyte_cdk/test/__init__.py +7 -0
  332. airbyte_cdk/test/catalog_builder.py +81 -0
  333. airbyte_cdk/test/entrypoint_wrapper.py +250 -0
  334. airbyte_cdk/test/mock_http/__init__.py +6 -0
  335. airbyte_cdk/test/mock_http/matcher.py +41 -0
  336. airbyte_cdk/test/mock_http/mocker.py +185 -0
  337. airbyte_cdk/test/mock_http/request.py +103 -0
  338. airbyte_cdk/test/mock_http/response.py +28 -0
  339. airbyte_cdk/test/mock_http/response_builder.py +237 -0
  340. airbyte_cdk/test/state_builder.py +33 -0
  341. airbyte_cdk/test/utils/__init__.py +1 -0
  342. airbyte_cdk/test/utils/data.py +24 -0
  343. airbyte_cdk/test/utils/http_mocking.py +16 -0
  344. airbyte_cdk/test/utils/manifest_only_fixtures.py +59 -0
  345. airbyte_cdk/test/utils/reading.py +26 -0
  346. airbyte_cdk/utils/__init__.py +10 -0
  347. airbyte_cdk/utils/airbyte_secrets_utils.py +80 -0
  348. airbyte_cdk/utils/analytics_message.py +25 -0
  349. airbyte_cdk/utils/constants.py +5 -0
  350. airbyte_cdk/utils/datetime_format_inferrer.py +94 -0
  351. airbyte_cdk/utils/datetime_helpers.py +499 -0
  352. airbyte_cdk/utils/event_timing.py +85 -0
  353. airbyte_cdk/utils/is_cloud_environment.py +18 -0
  354. airbyte_cdk/utils/mapping_helpers.py +162 -0
  355. airbyte_cdk/utils/message_utils.py +26 -0
  356. airbyte_cdk/utils/oneof_option_config.py +33 -0
  357. airbyte_cdk/utils/print_buffer.py +75 -0
  358. airbyte_cdk/utils/schema_inferrer.py +270 -0
  359. airbyte_cdk/utils/slice_hasher.py +37 -0
  360. airbyte_cdk/utils/spec_schema_transformations.py +26 -0
  361. airbyte_cdk/utils/stream_status_utils.py +43 -0
  362. airbyte_cdk/utils/traced_exception.py +145 -0
  363. airbyte_cdk-0.0.0.dev0.dist-info/LICENSE.txt +19 -0
  364. airbyte_cdk-0.0.0.dev0.dist-info/LICENSE_SHORT +1 -0
  365. airbyte_cdk-0.0.0.dev0.dist-info/METADATA +111 -0
  366. airbyte_cdk-0.0.0.dev0.dist-info/RECORD +368 -0
  367. airbyte_cdk-0.0.0.dev0.dist-info/WHEEL +4 -0
  368. airbyte_cdk-0.0.0.dev0.dist-info/entry_points.txt +3 -0
@@ -0,0 +1,267 @@
1
+ #
2
+ # Copyright (c) 2023 Airbyte, Inc., all rights reserved.
3
+ #
4
+
5
+ import base64
6
+ import logging
7
+ from dataclasses import InitVar, dataclass
8
+ from typing import Any, Mapping, MutableMapping, Union
9
+
10
+ import requests
11
+ from cachetools import TTLCache, cached
12
+
13
+ from airbyte_cdk.sources.declarative.auth.declarative_authenticator import DeclarativeAuthenticator
14
+ from airbyte_cdk.sources.declarative.auth.token_provider import TokenProvider
15
+ from airbyte_cdk.sources.declarative.interpolation.interpolated_string import InterpolatedString
16
+ from airbyte_cdk.sources.declarative.requesters.request_option import (
17
+ RequestOption,
18
+ RequestOptionType,
19
+ )
20
+ from airbyte_cdk.sources.types import Config
21
+
22
+
23
+ @dataclass
24
+ class ApiKeyAuthenticator(DeclarativeAuthenticator):
25
+ """
26
+ ApiKeyAuth sets a request header on the HTTP requests sent.
27
+
28
+ The header is of the form:
29
+ `"<header>": "<token>"`
30
+
31
+ For example,
32
+ `ApiKeyAuthenticator("Authorization", "Bearer hello")`
33
+ will result in the following header set on the HTTP request
34
+ `"Authorization": "Bearer hello"`
35
+
36
+ Attributes:
37
+ request_option (RequestOption): request option how to inject the token into the request
38
+ token_provider (TokenProvider): Provider of the token
39
+ config (Config): The user-provided configuration as specified by the source's spec
40
+ parameters (Mapping[str, Any]): Additional runtime parameters to be used for string interpolation
41
+ """
42
+
43
+ request_option: RequestOption
44
+ token_provider: TokenProvider
45
+ config: Config
46
+ parameters: InitVar[Mapping[str, Any]]
47
+
48
+ @property
49
+ def auth_header(self) -> str:
50
+ options = self._get_request_options(RequestOptionType.header)
51
+ return next(iter(options.keys()), "")
52
+
53
+ @property
54
+ def token(self) -> str:
55
+ return self.token_provider.get_token()
56
+
57
+ def _get_request_options(self, option_type: RequestOptionType) -> Mapping[str, Any]:
58
+ options: MutableMapping[str, Any] = {}
59
+ if self.request_option.inject_into == option_type:
60
+ self.request_option.inject_into_request(options, self.token, self.config)
61
+ return options
62
+
63
+ def get_request_params(self) -> Mapping[str, Any]:
64
+ return self._get_request_options(RequestOptionType.request_parameter)
65
+
66
+ def get_request_body_data(self) -> Union[Mapping[str, Any], str]:
67
+ return self._get_request_options(RequestOptionType.body_data)
68
+
69
+ def get_request_body_json(self) -> Mapping[str, Any]:
70
+ return self._get_request_options(RequestOptionType.body_json)
71
+
72
+
73
+ @dataclass
74
+ class BearerAuthenticator(DeclarativeAuthenticator):
75
+ """
76
+ Authenticator that sets the Authorization header on the HTTP requests sent.
77
+
78
+ The header is of the form:
79
+ `"Authorization": "Bearer <token>"`
80
+
81
+ Attributes:
82
+ token_provider (TokenProvider): Provider of the token
83
+ config (Config): The user-provided configuration as specified by the source's spec
84
+ parameters (Mapping[str, Any]): Additional runtime parameters to be used for string interpolation
85
+ """
86
+
87
+ token_provider: TokenProvider
88
+ config: Config
89
+ parameters: InitVar[Mapping[str, Any]]
90
+
91
+ @property
92
+ def auth_header(self) -> str:
93
+ return "Authorization"
94
+
95
+ @property
96
+ def token(self) -> str:
97
+ return f"Bearer {self.token_provider.get_token()}"
98
+
99
+
100
+ @dataclass
101
+ class BasicHttpAuthenticator(DeclarativeAuthenticator):
102
+ """
103
+ Builds auth based off the basic authentication scheme as defined by RFC 7617, which transmits credentials as USER ID/password pairs, encoded using base64
104
+ https://developer.mozilla.org/en-US/docs/Web/HTTP/Authentication#basic_authentication_scheme
105
+
106
+ The header is of the form
107
+ `"Authorization": "Basic <encoded_credentials>"`
108
+
109
+ Attributes:
110
+ username (Union[InterpolatedString, str]): The username
111
+ config (Config): The user-provided configuration as specified by the source's spec
112
+ password (Union[InterpolatedString, str]): The password
113
+ parameters (Mapping[str, Any]): Additional runtime parameters to be used for string interpolation
114
+ """
115
+
116
+ username: Union[InterpolatedString, str]
117
+ config: Config
118
+ parameters: InitVar[Mapping[str, Any]]
119
+ password: Union[InterpolatedString, str] = ""
120
+
121
+ def __post_init__(self, parameters: Mapping[str, Any]) -> None:
122
+ self._username = InterpolatedString.create(self.username, parameters=parameters)
123
+ self._password = InterpolatedString.create(self.password, parameters=parameters)
124
+
125
+ @property
126
+ def auth_header(self) -> str:
127
+ return "Authorization"
128
+
129
+ @property
130
+ def token(self) -> str:
131
+ auth_string = (
132
+ f"{self._username.eval(self.config)}:{self._password.eval(self.config)}".encode("utf8")
133
+ )
134
+ b64_encoded = base64.b64encode(auth_string).decode("utf8")
135
+ return f"Basic {b64_encoded}"
136
+
137
+
138
+ """
139
+ maxsize - The maximum size of the cache
140
+ ttl - time-to-live value in seconds
141
+ docs https://cachetools.readthedocs.io/en/latest/
142
+ maxsize=1000 - when the cache is full, in this case more than 1000,
143
+ i.e. by adding another item the cache would exceed its maximum size, the cache must choose which item(s) to discard
144
+ ttl=86400 means that cached token will live for 86400 seconds (one day)
145
+ """
146
+ cacheSessionTokenAuthenticator: TTLCache[str, str] = TTLCache(maxsize=1000, ttl=86400)
147
+
148
+
149
+ @cached(cacheSessionTokenAuthenticator)
150
+ def get_new_session_token(api_url: str, username: str, password: str, response_key: str) -> str:
151
+ """
152
+ This method retrieves session token from api by username and password for SessionTokenAuthenticator.
153
+ It's cashed to avoid a multiple calling by sync and updating session token every stream sync.
154
+ Args:
155
+ api_url: api url for getting new session token
156
+ username: username for auth
157
+ password: password for auth
158
+ response_key: field name in response to retrieve a session token
159
+
160
+ Returns:
161
+ session token
162
+ """
163
+ response = requests.post(
164
+ f"{api_url}",
165
+ headers={"Content-Type": "application/json"},
166
+ json={"username": username, "password": password},
167
+ )
168
+ response.raise_for_status()
169
+ if not response.ok:
170
+ raise ConnectionError(
171
+ f"Failed to retrieve new session token, response code {response.status_code} because {response.reason}"
172
+ )
173
+ return str(response.json()[response_key])
174
+
175
+
176
+ @dataclass
177
+ class LegacySessionTokenAuthenticator(DeclarativeAuthenticator):
178
+ """
179
+ Builds auth based on session tokens.
180
+ A session token is a random value generated by a server to identify
181
+ a specific user for the duration of one interaction session.
182
+
183
+ The header is of the form
184
+ `"Specific Header": "Session Token Value"`
185
+
186
+ Attributes:
187
+ api_url (Union[InterpolatedString, str]): Base api url of source
188
+ username (Union[InterpolatedString, str]): The username
189
+ config (Config): The user-provided configuration as specified by the source's spec
190
+ password (Union[InterpolatedString, str]): The password
191
+ header (Union[InterpolatedString, str]): Specific header of source for providing session token
192
+ parameters (Mapping[str, Any]): Additional runtime parameters to be used for string interpolation
193
+ session_token (Union[InterpolatedString, str]): Session token generated by user
194
+ session_token_response_key (Union[InterpolatedString, str]): Key for retrieving session token from api response
195
+ login_url (Union[InterpolatedString, str]): Url fot getting a specific session token
196
+ validate_session_url (Union[InterpolatedString, str]): Url to validate passed session token
197
+ """
198
+
199
+ api_url: Union[InterpolatedString, str]
200
+ header: Union[InterpolatedString, str]
201
+ session_token: Union[InterpolatedString, str]
202
+ session_token_response_key: Union[InterpolatedString, str]
203
+ username: Union[InterpolatedString, str]
204
+ config: Config
205
+ parameters: InitVar[Mapping[str, Any]]
206
+ login_url: Union[InterpolatedString, str]
207
+ validate_session_url: Union[InterpolatedString, str]
208
+ password: Union[InterpolatedString, str] = ""
209
+
210
+ def __post_init__(self, parameters: Mapping[str, Any]) -> None:
211
+ self._username = InterpolatedString.create(self.username, parameters=parameters)
212
+ self._password = InterpolatedString.create(self.password, parameters=parameters)
213
+ self._api_url = InterpolatedString.create(self.api_url, parameters=parameters)
214
+ self._header = InterpolatedString.create(self.header, parameters=parameters)
215
+ self._session_token = InterpolatedString.create(self.session_token, parameters=parameters)
216
+ self._session_token_response_key = InterpolatedString.create(
217
+ self.session_token_response_key, parameters=parameters
218
+ )
219
+ self._login_url = InterpolatedString.create(self.login_url, parameters=parameters)
220
+ self._validate_session_url = InterpolatedString.create(
221
+ self.validate_session_url, parameters=parameters
222
+ )
223
+
224
+ self.logger = logging.getLogger("airbyte")
225
+
226
+ @property
227
+ def auth_header(self) -> str:
228
+ return str(self._header.eval(self.config))
229
+
230
+ @property
231
+ def token(self) -> str:
232
+ if self._session_token.eval(self.config):
233
+ if self.is_valid_session_token():
234
+ return str(self._session_token.eval(self.config))
235
+ if self._password.eval(self.config) and self._username.eval(self.config):
236
+ username = self._username.eval(self.config)
237
+ password = self._password.eval(self.config)
238
+ session_token_response_key = self._session_token_response_key.eval(self.config)
239
+ api_url = f"{self._api_url.eval(self.config)}{self._login_url.eval(self.config)}"
240
+
241
+ self.logger.info("Using generated session token by username and password")
242
+ return get_new_session_token(api_url, username, password, session_token_response_key)
243
+
244
+ raise ConnectionError(
245
+ "Invalid credentials: session token is not valid or provide username and password"
246
+ )
247
+
248
+ def is_valid_session_token(self) -> bool:
249
+ try:
250
+ response = requests.get(
251
+ f"{self._api_url.eval(self.config)}{self._validate_session_url.eval(self.config)}",
252
+ headers={self.auth_header: self._session_token.eval(self.config)},
253
+ )
254
+ response.raise_for_status()
255
+ except requests.exceptions.HTTPError as e:
256
+ if e.response.status_code == requests.codes["unauthorized"]:
257
+ self.logger.info(f"Unable to connect by session token from config due to {str(e)}")
258
+ return False
259
+ else:
260
+ raise ConnectionError(f"Error while validating session token: {e}")
261
+ if response.ok:
262
+ self.logger.info("Connection check for source is successful.")
263
+ return True
264
+ else:
265
+ raise ConnectionError(
266
+ f"Failed to retrieve new session token, response code {response.status_code} because {response.reason}"
267
+ )
@@ -0,0 +1,82 @@
1
+ #
2
+ # Copyright (c) 2023 Airbyte, Inc., all rights reserved.
3
+ #
4
+
5
+
6
+ import datetime
7
+ from abc import abstractmethod
8
+ from dataclasses import InitVar, dataclass, field
9
+ from typing import Any, List, Mapping, Optional, Union
10
+
11
+ import dpath
12
+ from isodate import Duration
13
+
14
+ from airbyte_cdk.sources.declarative.decoders.decoder import Decoder
15
+ from airbyte_cdk.sources.declarative.decoders.json_decoder import JsonDecoder
16
+ from airbyte_cdk.sources.declarative.exceptions import ReadException
17
+ from airbyte_cdk.sources.declarative.interpolation.interpolated_string import InterpolatedString
18
+ from airbyte_cdk.sources.declarative.requesters.requester import Requester
19
+ from airbyte_cdk.sources.http_logger import format_http_message
20
+ from airbyte_cdk.sources.message import MessageRepository, NoopMessageRepository
21
+ from airbyte_cdk.sources.types import Config
22
+ from airbyte_cdk.utils.datetime_helpers import AirbyteDateTime, ab_datetime_now
23
+
24
+
25
+ class TokenProvider:
26
+ @abstractmethod
27
+ def get_token(self) -> str:
28
+ pass
29
+
30
+
31
+ @dataclass
32
+ class SessionTokenProvider(TokenProvider):
33
+ login_requester: Requester
34
+ session_token_path: List[str]
35
+ expiration_duration: Optional[Union[datetime.timedelta, Duration]]
36
+ parameters: InitVar[Mapping[str, Any]]
37
+ message_repository: MessageRepository = NoopMessageRepository()
38
+ decoder: Decoder = field(default_factory=lambda: JsonDecoder(parameters={}))
39
+
40
+ _next_expiration_time: Optional[AirbyteDateTime] = None
41
+ _token: Optional[str] = None
42
+
43
+ def get_token(self) -> str:
44
+ self._refresh_if_necessary()
45
+ if self._token is None:
46
+ raise ReadException("Failed to get session token, token is None")
47
+ return self._token
48
+
49
+ def _refresh_if_necessary(self) -> None:
50
+ if self._next_expiration_time is None or self._next_expiration_time < ab_datetime_now():
51
+ self._refresh()
52
+
53
+ def _refresh(self) -> None:
54
+ response = self.login_requester.send_request(
55
+ log_formatter=lambda response: format_http_message(
56
+ response,
57
+ "Login request",
58
+ "Obtains session token",
59
+ None,
60
+ is_auxiliary=True,
61
+ type="AUTH",
62
+ ),
63
+ )
64
+ if response is None:
65
+ raise ReadException("Failed to get session token, response got ignored by requester")
66
+ session_token = dpath.get(next(self.decoder.decode(response)), self.session_token_path)
67
+ if self.expiration_duration is not None:
68
+ self._next_expiration_time = ab_datetime_now() + self.expiration_duration
69
+ self._token = session_token # type: ignore # Returned decoded response will be Mapping and therefore session_token will be str or None
70
+
71
+
72
+ @dataclass
73
+ class InterpolatedStringTokenProvider(TokenProvider):
74
+ config: Config
75
+ api_token: Union[InterpolatedString, str]
76
+ parameters: Mapping[str, Any]
77
+
78
+ def __post_init__(self) -> None:
79
+ self._token = InterpolatedString.create(self.api_token, parameters=self.parameters)
80
+
81
+ def get_token(self) -> str:
82
+ return str(self._token.eval(self.config))
@@ -0,0 +1,24 @@
1
+ #
2
+ # Copyright (c) 2025 Airbyte, Inc., all rights reserved.
3
+ #
4
+
5
+ from typing import Mapping
6
+
7
+ from pydantic.v1 import BaseModel
8
+
9
+ from airbyte_cdk.sources.declarative.checks.check_dynamic_stream import CheckDynamicStream
10
+ from airbyte_cdk.sources.declarative.checks.check_stream import CheckStream
11
+ from airbyte_cdk.sources.declarative.checks.connection_checker import ConnectionChecker
12
+ from airbyte_cdk.sources.declarative.models import (
13
+ CheckDynamicStream as CheckDynamicStreamModel,
14
+ )
15
+ from airbyte_cdk.sources.declarative.models import (
16
+ CheckStream as CheckStreamModel,
17
+ )
18
+
19
+ COMPONENTS_CHECKER_TYPE_MAPPING: Mapping[str, type[BaseModel]] = {
20
+ "CheckStream": CheckStreamModel,
21
+ "CheckDynamicStream": CheckDynamicStreamModel,
22
+ }
23
+
24
+ __all__ = ["CheckStream", "CheckDynamicStream", "ConnectionChecker"]
@@ -0,0 +1,61 @@
1
+ #
2
+ # Copyright (c) 2025 Airbyte, Inc., all rights reserved.
3
+ #
4
+
5
+ import logging
6
+ import traceback
7
+ from dataclasses import InitVar, dataclass
8
+ from typing import Any, List, Mapping, Tuple
9
+
10
+ from airbyte_cdk import AbstractSource
11
+ from airbyte_cdk.sources.declarative.checks.connection_checker import ConnectionChecker
12
+ from airbyte_cdk.sources.streams.http.availability_strategy import HttpAvailabilityStrategy
13
+
14
+
15
+ @dataclass
16
+ class CheckDynamicStream(ConnectionChecker):
17
+ """
18
+ Checks the connections by checking availability of one or many dynamic streams
19
+
20
+ Attributes:
21
+ stream_count (int): numbers of streams to check
22
+ """
23
+
24
+ # TODO: Add field stream_names to check_connection for static streams
25
+ # https://github.com/airbytehq/airbyte-python-cdk/pull/293#discussion_r1934933483
26
+
27
+ stream_count: int
28
+ parameters: InitVar[Mapping[str, Any]]
29
+ use_check_availability: bool = True
30
+
31
+ def __post_init__(self, parameters: Mapping[str, Any]) -> None:
32
+ self._parameters = parameters
33
+
34
+ def check_connection(
35
+ self, source: AbstractSource, logger: logging.Logger, config: Mapping[str, Any]
36
+ ) -> Tuple[bool, Any]:
37
+ streams = source.streams(config=config)
38
+
39
+ if len(streams) == 0:
40
+ return False, f"No streams to connect to from source {source}"
41
+ if not self.use_check_availability:
42
+ return True, None
43
+
44
+ availability_strategy = HttpAvailabilityStrategy()
45
+
46
+ try:
47
+ for stream in streams[: min(self.stream_count, len(streams))]:
48
+ stream_is_available, reason = availability_strategy.check_availability(
49
+ stream, logger
50
+ )
51
+ if not stream_is_available:
52
+ logger.warning(f"Stream {stream.name} is not available: {reason}")
53
+ return False, reason
54
+ except Exception as error:
55
+ error_message = (
56
+ f"Encountered an error trying to connect to stream {stream.name}. Error: {error}"
57
+ )
58
+ logger.error(error_message, exc_info=True)
59
+ return False, error_message
60
+
61
+ return True, None
@@ -0,0 +1,56 @@
1
+ #
2
+ # Copyright (c) 2023 Airbyte, Inc., all rights reserved.
3
+ #
4
+
5
+ import logging
6
+ import traceback
7
+ from dataclasses import InitVar, dataclass
8
+ from typing import Any, List, Mapping, Tuple
9
+
10
+ from airbyte_cdk import AbstractSource
11
+ from airbyte_cdk.sources.declarative.checks.connection_checker import ConnectionChecker
12
+ from airbyte_cdk.sources.streams.http.availability_strategy import HttpAvailabilityStrategy
13
+
14
+
15
+ @dataclass
16
+ class CheckStream(ConnectionChecker):
17
+ """
18
+ Checks the connections by checking availability of one or many streams selected by the developer
19
+
20
+ Attributes:
21
+ stream_name (List[str]): names of streams to check
22
+ """
23
+
24
+ stream_names: List[str]
25
+ parameters: InitVar[Mapping[str, Any]]
26
+
27
+ def __post_init__(self, parameters: Mapping[str, Any]) -> None:
28
+ self._parameters = parameters
29
+
30
+ def check_connection(
31
+ self, source: AbstractSource, logger: logging.Logger, config: Mapping[str, Any]
32
+ ) -> Tuple[bool, Any]:
33
+ streams = source.streams(config=config)
34
+ stream_name_to_stream = {s.name: s for s in streams}
35
+ if len(streams) == 0:
36
+ return False, f"No streams to connect to from source {source}"
37
+ for stream_name in self.stream_names:
38
+ if stream_name not in stream_name_to_stream.keys():
39
+ raise ValueError(
40
+ f"{stream_name} is not part of the catalog. Expected one of {stream_name_to_stream.keys()}."
41
+ )
42
+
43
+ stream = stream_name_to_stream[stream_name]
44
+ availability_strategy = HttpAvailabilityStrategy()
45
+ try:
46
+ stream_is_available, reason = availability_strategy.check_availability(
47
+ stream, logger
48
+ )
49
+ if not stream_is_available:
50
+ return False, reason
51
+ except Exception as error:
52
+ logger.error(
53
+ f"Encountered an error trying to connect to stream {stream_name}. Error: \n {traceback.format_exc()}"
54
+ )
55
+ return False, f"Unable to connect to stream {stream_name} - {error}"
56
+ return True, None
@@ -0,0 +1,35 @@
1
+ #
2
+ # Copyright (c) 2023 Airbyte, Inc., all rights reserved.
3
+ #
4
+
5
+ import logging
6
+ from abc import ABC, abstractmethod
7
+ from typing import Any, Mapping, Tuple
8
+
9
+ from airbyte_cdk import AbstractSource
10
+
11
+
12
+ class ConnectionChecker(ABC):
13
+ """
14
+ Abstract base class for checking a connection
15
+ """
16
+
17
+ @abstractmethod
18
+ def check_connection(
19
+ self, source: AbstractSource, logger: logging.Logger, config: Mapping[str, Any]
20
+ ) -> Tuple[bool, Any]:
21
+ """
22
+ Tests if the input configuration can be used to successfully connect to the integration e.g: if a provided Stripe API token can be used to connect
23
+ to the Stripe API.
24
+
25
+ :param source: source
26
+ :param logger: source logger
27
+ :param config: The user-provided configuration as specified by the source's spec.
28
+ This usually contains information required to check connection e.g. tokens, secrets and keys etc.
29
+ :return: A tuple of (boolean, error). If boolean is true, then the connection check is successful
30
+ and we can connect to the underlying data source using the provided configuration.
31
+ Otherwise, the input config cannot be used to connect to the underlying data source,
32
+ and the "error" object should describe what went wrong.
33
+ The error object will be cast to string to display the problem to the user.
34
+ """
35
+ pass
@@ -0,0 +1,7 @@
1
+ #
2
+ # Copyright (c) 2024 Airbyte, Inc., all rights reserved.
3
+ #
4
+
5
+ from airbyte_cdk.sources.declarative.concurrency_level.concurrency_level import ConcurrencyLevel
6
+
7
+ __all__ = ["ConcurrencyLevel"]
@@ -0,0 +1,50 @@
1
+ #
2
+ # Copyright (c) 2024 Airbyte, Inc., all rights reserved.
3
+ #
4
+
5
+ from dataclasses import InitVar, dataclass
6
+ from typing import Any, Mapping, Optional, Union
7
+
8
+ from airbyte_cdk.sources.declarative.interpolation import InterpolatedString
9
+ from airbyte_cdk.sources.types import Config
10
+
11
+
12
+ @dataclass
13
+ class ConcurrencyLevel:
14
+ """
15
+ Returns the number of worker threads that should be used when syncing concurrent streams in parallel
16
+
17
+ Attributes:
18
+ default_concurrency (Union[int, str]): The hardcoded integer or interpolation of how many worker threads to use during a sync
19
+ max_concurrency (Optional[int]): The maximum number of worker threads to use when the default_concurrency is exceeded
20
+ """
21
+
22
+ default_concurrency: Union[int, str]
23
+ max_concurrency: Optional[int]
24
+ config: Config
25
+ parameters: InitVar[Mapping[str, Any]]
26
+
27
+ def __post_init__(self, parameters: Mapping[str, Any]) -> None:
28
+ if isinstance(self.default_concurrency, int):
29
+ self._default_concurrency: Union[int, InterpolatedString] = self.default_concurrency
30
+ elif "config" in self.default_concurrency and not self.max_concurrency:
31
+ raise ValueError(
32
+ "ConcurrencyLevel requires that max_concurrency be defined if the default_concurrency can be used-specified"
33
+ )
34
+ else:
35
+ self._default_concurrency = InterpolatedString.create(
36
+ self.default_concurrency, parameters=parameters
37
+ )
38
+
39
+ def get_concurrency_level(self) -> int:
40
+ if isinstance(self._default_concurrency, InterpolatedString):
41
+ evaluated_default_concurrency = self._default_concurrency.eval(config=self.config)
42
+ if not isinstance(evaluated_default_concurrency, int):
43
+ raise ValueError("default_concurrency did not evaluate to an integer")
44
+ return (
45
+ min(evaluated_default_concurrency, self.max_concurrency)
46
+ if self.max_concurrency
47
+ else evaluated_default_concurrency
48
+ )
49
+ else:
50
+ return self._default_concurrency