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,10 @@
1
+ #
2
+ # Copyright (c) 2023 Airbyte, Inc., all rights reserved.
3
+ #
4
+
5
+ # Initialize Streams Package
6
+ from .exceptions import UserDefinedBackoffException
7
+ from .http import HttpStream, HttpSubStream
8
+ from .http_client import HttpClient
9
+
10
+ __all__ = ["HttpClient", "HttpStream", "HttpSubStream", "UserDefinedBackoffException"]
@@ -0,0 +1,54 @@
1
+ #
2
+ # Copyright (c) 2023 Airbyte, Inc., all rights reserved.
3
+ #
4
+
5
+ import logging
6
+ import typing
7
+ from typing import Optional, Tuple
8
+
9
+ from airbyte_cdk.sources.streams import Stream
10
+ from airbyte_cdk.sources.streams.availability_strategy import AvailabilityStrategy
11
+ from airbyte_cdk.utils.traced_exception import AirbyteTracedException
12
+
13
+ if typing.TYPE_CHECKING:
14
+ from airbyte_cdk.sources import Source
15
+
16
+
17
+ class HttpAvailabilityStrategy(AvailabilityStrategy):
18
+ def check_availability(
19
+ self, stream: Stream, logger: logging.Logger, source: Optional["Source"] = None
20
+ ) -> Tuple[bool, Optional[str]]:
21
+ """
22
+ Check stream availability by attempting to read the first record of the
23
+ stream.
24
+
25
+ :param stream: stream
26
+ :param logger: source logger
27
+ :param source: (optional) source
28
+ :return: A tuple of (boolean, str). If boolean is true, then the stream
29
+ is available, and no str is required. Otherwise, the stream is unavailable
30
+ for some reason and the str should describe what went wrong and how to
31
+ resolve the unavailability, if possible.
32
+ """
33
+ reason: Optional[str]
34
+ try:
35
+ # Some streams need a stream slice to read records (e.g. if they have a SubstreamPartitionRouter)
36
+ # Streams that don't need a stream slice will return `None` as their first stream slice.
37
+ stream_slice = self.get_first_stream_slice(stream)
38
+ except StopIteration:
39
+ # If stream_slices has no `next()` item (Note - this is different from stream_slices returning [None]!)
40
+ # This can happen when a substream's `stream_slices` method does a `for record in parent_records: yield <something>`
41
+ # without accounting for the case in which the parent stream is empty.
42
+ reason = f"Cannot attempt to connect to stream {stream.name} - no stream slices were found, likely because the parent stream is empty."
43
+ return False, reason
44
+ except AirbyteTracedException as error:
45
+ return False, error.message
46
+
47
+ try:
48
+ self.get_first_record_for_slice(stream, stream_slice)
49
+ return True, None
50
+ except StopIteration:
51
+ logger.info(f"Successfully connected to stream {stream.name}, but got 0 records.")
52
+ return True, None
53
+ except AirbyteTracedException as error:
54
+ return False, error.message
@@ -0,0 +1,22 @@
1
+ #
2
+ # Copyright (c) 2023 Airbyte, Inc., all rights reserved.
3
+ #
4
+
5
+ from .backoff_strategy import BackoffStrategy
6
+ from .default_backoff_strategy import DefaultBackoffStrategy
7
+ from .error_handler import ErrorHandler
8
+ from .error_message_parser import ErrorMessageParser
9
+ from .http_status_error_handler import HttpStatusErrorHandler
10
+ from .json_error_message_parser import JsonErrorMessageParser
11
+ from .response_models import ErrorResolution, ResponseAction
12
+
13
+ __all__ = [
14
+ "BackoffStrategy",
15
+ "DefaultBackoffStrategy",
16
+ "ErrorHandler",
17
+ "ErrorMessageParser",
18
+ "HttpStatusErrorHandler",
19
+ "JsonErrorMessageParser",
20
+ "ResponseAction",
21
+ "ErrorResolution",
22
+ ]
@@ -0,0 +1,28 @@
1
+ #
2
+ # Copyright (c) 2023 Airbyte, Inc., all rights reserved.
3
+ #
4
+
5
+ from abc import ABC, abstractmethod
6
+ from typing import Optional, Union
7
+
8
+ import requests
9
+
10
+
11
+ class BackoffStrategy(ABC):
12
+ @abstractmethod
13
+ def backoff_time(
14
+ self,
15
+ response_or_exception: Optional[Union[requests.Response, requests.RequestException]],
16
+ attempt_count: int,
17
+ ) -> Optional[float]:
18
+ """
19
+ Override this method to dynamically determine backoff time e.g: by reading the X-Retry-After header.
20
+
21
+ This method is called only if should_backoff() returns True for the input request.
22
+
23
+ :param response_or_exception: The response or exception that caused the backoff.
24
+ :param attempt_count: The number of attempts already performed for this request.
25
+ :return how long to backoff in seconds. The return value may be a floating point number for subsecond precision. Returning None defers backoff
26
+ to the default backoff behavior (e.g using an exponential algorithm).
27
+ """
28
+ pass
@@ -0,0 +1,17 @@
1
+ # Copyright (c) 2024 Airbyte, Inc., all rights reserved.
2
+
3
+
4
+ from typing import Optional, Union
5
+
6
+ import requests
7
+
8
+ from .backoff_strategy import BackoffStrategy
9
+
10
+
11
+ class DefaultBackoffStrategy(BackoffStrategy):
12
+ def backoff_time(
13
+ self,
14
+ response_or_exception: Optional[Union[requests.Response, requests.RequestException]],
15
+ attempt_count: int,
16
+ ) -> Optional[float]:
17
+ return None
@@ -0,0 +1,86 @@
1
+ #
2
+ # Copyright (c) 2024 Airbyte, Inc., all rights reserved.
3
+ #
4
+
5
+ from typing import Mapping, Type, Union
6
+
7
+ from requests.exceptions import InvalidSchema, InvalidURL, RequestException
8
+
9
+ from airbyte_cdk.models import FailureType
10
+ from airbyte_cdk.sources.streams.http.error_handlers.response_models import (
11
+ ErrorResolution,
12
+ ResponseAction,
13
+ )
14
+
15
+ DEFAULT_ERROR_MAPPING: Mapping[Union[int, str, Type[Exception]], ErrorResolution] = {
16
+ InvalidSchema: ErrorResolution(
17
+ response_action=ResponseAction.FAIL,
18
+ failure_type=FailureType.config_error,
19
+ error_message="Invalid Protocol Schema: The endpoint that data is being requested from is using an invalid or insecure. Exception: requests.exceptions.InvalidSchema",
20
+ ),
21
+ InvalidURL: ErrorResolution(
22
+ response_action=ResponseAction.RETRY,
23
+ failure_type=FailureType.transient_error,
24
+ error_message="Invalid URL specified or DNS error occurred: The endpoint that data is being requested from is not a valid URL. Exception: requests.exceptions.InvalidURL",
25
+ ),
26
+ RequestException: ErrorResolution(
27
+ response_action=ResponseAction.RETRY,
28
+ failure_type=FailureType.transient_error,
29
+ error_message="An exception occurred when making the request. Exception: requests.exceptions.RequestException",
30
+ ),
31
+ 400: ErrorResolution(
32
+ response_action=ResponseAction.FAIL,
33
+ failure_type=FailureType.system_error,
34
+ error_message="Bad request. Please check your request parameters.",
35
+ ),
36
+ 401: ErrorResolution(
37
+ response_action=ResponseAction.FAIL,
38
+ failure_type=FailureType.config_error,
39
+ error_message="Unauthorized. Please ensure you are authenticated correctly.",
40
+ ),
41
+ 403: ErrorResolution(
42
+ response_action=ResponseAction.FAIL,
43
+ failure_type=FailureType.config_error,
44
+ error_message="Forbidden. You don't have permission to access this resource.",
45
+ ),
46
+ 404: ErrorResolution(
47
+ response_action=ResponseAction.FAIL,
48
+ failure_type=FailureType.system_error,
49
+ error_message="Not found. The requested resource was not found on the server.",
50
+ ),
51
+ 405: ErrorResolution(
52
+ response_action=ResponseAction.FAIL,
53
+ failure_type=FailureType.system_error,
54
+ error_message="Method not allowed. Please check your request method.",
55
+ ),
56
+ 408: ErrorResolution(
57
+ response_action=ResponseAction.RETRY,
58
+ failure_type=FailureType.transient_error,
59
+ error_message="Request timeout.",
60
+ ),
61
+ 429: ErrorResolution(
62
+ response_action=ResponseAction.RATE_LIMITED,
63
+ failure_type=FailureType.transient_error,
64
+ error_message="Too many requests.",
65
+ ),
66
+ 500: ErrorResolution(
67
+ response_action=ResponseAction.RETRY,
68
+ failure_type=FailureType.transient_error,
69
+ error_message="Internal server error.",
70
+ ),
71
+ 502: ErrorResolution(
72
+ response_action=ResponseAction.RETRY,
73
+ failure_type=FailureType.transient_error,
74
+ error_message="Bad gateway.",
75
+ ),
76
+ 503: ErrorResolution(
77
+ response_action=ResponseAction.RETRY,
78
+ failure_type=FailureType.transient_error,
79
+ error_message="Service unavailable.",
80
+ ),
81
+ 504: ErrorResolution(
82
+ response_action=ResponseAction.RETRY,
83
+ failure_type=FailureType.transient_error,
84
+ error_message="Gateway timeout.",
85
+ ),
86
+ }
@@ -0,0 +1,42 @@
1
+ # Copyright (c) 2024 Airbyte, Inc., all rights reserved.
2
+
3
+ from abc import ABC, abstractmethod
4
+ from typing import Optional, Union
5
+
6
+ import requests
7
+
8
+ from .response_models import ErrorResolution
9
+
10
+
11
+ class ErrorHandler(ABC):
12
+ """
13
+ Abstract base class to determine how to handle a failed HTTP request.
14
+ """
15
+
16
+ @property
17
+ @abstractmethod
18
+ def max_retries(self) -> Optional[int]:
19
+ """
20
+ The maximum number of retries to attempt before giving up.
21
+ """
22
+ pass
23
+
24
+ @property
25
+ @abstractmethod
26
+ def max_time(self) -> Optional[int]:
27
+ """
28
+ The maximum amount of time in seconds to retry before giving up.
29
+ """
30
+ pass
31
+
32
+ @abstractmethod
33
+ def interpret_response(
34
+ self, response: Optional[Union[requests.Response, Exception]]
35
+ ) -> ErrorResolution:
36
+ """
37
+ Interpret the response or exception and return the corresponding response action, failure type, and error message.
38
+
39
+ :param response: The HTTP response object or exception raised during the request.
40
+ :return: A tuple containing the response action, failure type, and error message.
41
+ """
42
+ pass
@@ -0,0 +1,19 @@
1
+ #
2
+ # Copyright (c) 2023 Airbyte, Inc., all rights reserved.
3
+ #
4
+
5
+ from abc import ABC, abstractmethod
6
+ from typing import Optional
7
+
8
+ import requests
9
+
10
+
11
+ class ErrorMessageParser(ABC):
12
+ @abstractmethod
13
+ def parse_response_error_message(self, response: requests.Response) -> Optional[str]:
14
+ """
15
+ Parse error message from response.
16
+ :param response: response received for the request
17
+ :return: error message
18
+ """
19
+ pass
@@ -0,0 +1,110 @@
1
+ #
2
+ # Copyright (c) 2024 Airbyte, Inc., all rights reserved.
3
+ #
4
+
5
+ import logging
6
+ from datetime import timedelta
7
+ from typing import Mapping, Optional, Union
8
+
9
+ import requests
10
+
11
+ from airbyte_cdk.models import FailureType
12
+ from airbyte_cdk.sources.streams.http.error_handlers.default_error_mapping import (
13
+ DEFAULT_ERROR_MAPPING,
14
+ )
15
+ from airbyte_cdk.sources.streams.http.error_handlers.error_handler import ErrorHandler
16
+ from airbyte_cdk.sources.streams.http.error_handlers.response_models import (
17
+ ErrorResolution,
18
+ ResponseAction,
19
+ )
20
+
21
+
22
+ class HttpStatusErrorHandler(ErrorHandler):
23
+ def __init__(
24
+ self,
25
+ logger: logging.Logger,
26
+ error_mapping: Optional[Mapping[Union[int, str, type[Exception]], ErrorResolution]] = None,
27
+ max_retries: int = 5,
28
+ max_time: timedelta = timedelta(seconds=600),
29
+ ) -> None:
30
+ """
31
+ Initialize the HttpStatusErrorHandler.
32
+
33
+ :param error_mapping: Custom error mappings to extend or override the default mappings.
34
+ """
35
+ self._logger = logger
36
+ self._error_mapping = error_mapping or DEFAULT_ERROR_MAPPING
37
+ self._max_retries = max_retries
38
+ self._max_time = int(max_time.total_seconds())
39
+
40
+ @property
41
+ def max_retries(self) -> Optional[int]:
42
+ return self._max_retries
43
+
44
+ @property
45
+ def max_time(self) -> Optional[int]:
46
+ return self._max_time
47
+
48
+ def interpret_response(
49
+ self, response_or_exception: Optional[Union[requests.Response, Exception]] = None
50
+ ) -> ErrorResolution:
51
+ """
52
+ Interpret the response and return the corresponding response action, failure type, and error message.
53
+
54
+ :param response: The HTTP response object.
55
+ :return: A tuple containing the response action, failure type, and error message.
56
+ """
57
+
58
+ if isinstance(response_or_exception, Exception):
59
+ mapped_error: Optional[ErrorResolution] = self._error_mapping.get(
60
+ response_or_exception.__class__
61
+ )
62
+
63
+ if mapped_error is not None:
64
+ return mapped_error
65
+ else:
66
+ self._logger.error(
67
+ f"Unexpected exception in error handler: {response_or_exception}"
68
+ )
69
+ return ErrorResolution(
70
+ response_action=ResponseAction.RETRY,
71
+ failure_type=FailureType.system_error,
72
+ error_message=f"Unexpected exception in error handler: {response_or_exception}",
73
+ )
74
+
75
+ elif isinstance(response_or_exception, requests.Response):
76
+ if response_or_exception.status_code is None:
77
+ self._logger.error("Response does not include an HTTP status code.")
78
+ return ErrorResolution(
79
+ response_action=ResponseAction.RETRY,
80
+ failure_type=FailureType.transient_error,
81
+ error_message="Response does not include an HTTP status code.",
82
+ )
83
+
84
+ if response_or_exception.ok:
85
+ return ErrorResolution(
86
+ response_action=ResponseAction.SUCCESS,
87
+ failure_type=None,
88
+ error_message=None,
89
+ )
90
+
91
+ error_key = response_or_exception.status_code
92
+
93
+ mapped_error = self._error_mapping.get(error_key)
94
+
95
+ if mapped_error is not None:
96
+ return mapped_error
97
+ else:
98
+ self._logger.warning(f"Unexpected HTTP Status Code in error handler: '{error_key}'")
99
+ return ErrorResolution(
100
+ response_action=ResponseAction.RETRY,
101
+ failure_type=FailureType.system_error,
102
+ error_message=f"Unexpected HTTP Status Code in error handler: {error_key}",
103
+ )
104
+ else:
105
+ self._logger.error(f"Received unexpected response type: {type(response_or_exception)}")
106
+ return ErrorResolution(
107
+ response_action=ResponseAction.FAIL,
108
+ failure_type=FailureType.system_error,
109
+ error_message=f"Received unexpected response type: {type(response_or_exception)}",
110
+ )
@@ -0,0 +1,52 @@
1
+ #
2
+ # Copyright (c) 2023 Airbyte, Inc., all rights reserved.
3
+ #
4
+
5
+ from typing import Optional
6
+
7
+ import requests
8
+
9
+ from airbyte_cdk.sources.streams.http.error_handlers import ErrorMessageParser
10
+ from airbyte_cdk.sources.utils.types import JsonType
11
+
12
+
13
+ class JsonErrorMessageParser(ErrorMessageParser):
14
+ def _try_get_error(self, value: Optional[JsonType]) -> Optional[str]:
15
+ if isinstance(value, str):
16
+ return value
17
+ elif isinstance(value, list):
18
+ errors_in_value = [self._try_get_error(v) for v in value]
19
+ return ", ".join(v for v in errors_in_value if v is not None)
20
+ elif isinstance(value, dict):
21
+ new_value = (
22
+ value.get("message")
23
+ or value.get("messages")
24
+ or value.get("error")
25
+ or value.get("errors")
26
+ or value.get("failures")
27
+ or value.get("failure")
28
+ or value.get("detail")
29
+ or value.get("err")
30
+ or value.get("error_message")
31
+ or value.get("msg")
32
+ or value.get("reason")
33
+ or value.get("status_message")
34
+ )
35
+ return self._try_get_error(new_value)
36
+ return None
37
+
38
+ def parse_response_error_message(self, response: requests.Response) -> Optional[str]:
39
+ """
40
+ Parses the raw response object from a failed request into a user-friendly error message.
41
+
42
+ :param response:
43
+ :return: A user-friendly message that indicates the cause of the error
44
+ """
45
+ try:
46
+ body = response.json()
47
+ return self._try_get_error(body)
48
+ except requests.exceptions.JSONDecodeError:
49
+ try:
50
+ return response.content.decode("utf-8")
51
+ except Exception:
52
+ return None
@@ -0,0 +1,65 @@
1
+ # Copyright (c) 2024 Airbyte, Inc., all rights reserved.
2
+
3
+ from dataclasses import dataclass
4
+ from enum import Enum
5
+ from typing import Optional, Union
6
+
7
+ import requests
8
+ from requests import HTTPError
9
+
10
+ from airbyte_cdk.models import FailureType
11
+ from airbyte_cdk.utils.airbyte_secrets_utils import filter_secrets
12
+
13
+
14
+ class ResponseAction(Enum):
15
+ SUCCESS = "SUCCESS"
16
+ RETRY = "RETRY"
17
+ FAIL = "FAIL"
18
+ IGNORE = "IGNORE"
19
+ RATE_LIMITED = "RATE_LIMITED"
20
+
21
+
22
+ @dataclass
23
+ class ErrorResolution:
24
+ response_action: Optional[ResponseAction] = None
25
+ failure_type: Optional[FailureType] = None
26
+ error_message: Optional[str] = None
27
+
28
+
29
+ def _format_exception_error_message(exception: Exception) -> str:
30
+ return f"{type(exception).__name__}: {str(exception)}"
31
+
32
+
33
+ def _format_response_error_message(response: requests.Response) -> str:
34
+ try:
35
+ response.raise_for_status()
36
+ except HTTPError as exception:
37
+ return filter_secrets(
38
+ f"Response was not ok: `{str(exception)}`. Response content is: {response.text}"
39
+ )
40
+ # We purposefully do not add the response.content because the response is "ok" so there might be sensitive information in the payload.
41
+ # Feel free the
42
+ return f"Unexpected response with HTTP status {response.status_code}"
43
+
44
+
45
+ def create_fallback_error_resolution(
46
+ response_or_exception: Optional[Union[requests.Response, Exception]],
47
+ ) -> ErrorResolution:
48
+ if response_or_exception is None:
49
+ # We do not expect this case to happen but if it does, it would be good to understand the cause and improve the error message
50
+ error_message = "Error handler did not receive a valid response or exception. This is unexpected please contact Airbyte Support"
51
+ elif isinstance(response_or_exception, Exception):
52
+ error_message = _format_exception_error_message(response_or_exception)
53
+ else:
54
+ error_message = _format_response_error_message(response_or_exception)
55
+
56
+ return ErrorResolution(
57
+ response_action=ResponseAction.RETRY,
58
+ failure_type=FailureType.system_error,
59
+ error_message=error_message,
60
+ )
61
+
62
+
63
+ SUCCESS_RESOLUTION = ErrorResolution(
64
+ response_action=ResponseAction.SUCCESS, failure_type=None, error_message=None
65
+ )
@@ -0,0 +1,61 @@
1
+ #
2
+ # Copyright (c) 2023 Airbyte, Inc., all rights reserved.
3
+ #
4
+
5
+
6
+ from typing import Optional, Union
7
+
8
+ import requests
9
+
10
+
11
+ class BaseBackoffException(requests.exceptions.HTTPError):
12
+ def __init__(
13
+ self,
14
+ request: requests.PreparedRequest,
15
+ response: Optional[Union[requests.Response, Exception]],
16
+ error_message: str = "",
17
+ ):
18
+ if isinstance(response, requests.Response):
19
+ error_message = (
20
+ error_message
21
+ or f"Request URL: {request.url}, Response Code: {response.status_code}, Response Text: {response.text}"
22
+ )
23
+ super().__init__(error_message, request=request, response=response)
24
+ else:
25
+ error_message = error_message or f"Request URL: {request.url}, Exception: {response}"
26
+ super().__init__(error_message, request=request, response=None)
27
+
28
+
29
+ class RequestBodyException(Exception):
30
+ """
31
+ Raised when there are issues in configuring a request body
32
+ """
33
+
34
+
35
+ class UserDefinedBackoffException(BaseBackoffException):
36
+ """
37
+ An exception that exposes how long it attempted to backoff
38
+ """
39
+
40
+ def __init__(
41
+ self,
42
+ backoff: Union[int, float],
43
+ request: requests.PreparedRequest,
44
+ response: Optional[Union[requests.Response, Exception]],
45
+ error_message: str = "",
46
+ ):
47
+ """
48
+ :param backoff: how long to backoff in seconds
49
+ :param request: the request that triggered this backoff exception
50
+ :param response: the response that triggered the backoff exception
51
+ """
52
+ self.backoff = backoff
53
+ super().__init__(request=request, response=response, error_message=error_message)
54
+
55
+
56
+ class DefaultBackoffException(BaseBackoffException):
57
+ pass
58
+
59
+
60
+ class RateLimitBackoffException(BaseBackoffException):
61
+ pass