airbyte-cdk 0.72.1__py3-none-any.whl → 6.17.1.dev0__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
Files changed (518) hide show
  1. airbyte_cdk/__init__.py +355 -6
  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 +230 -0
  5. airbyte_cdk/cli/source_declarative_manifest/spec.json +17 -0
  6. airbyte_cdk/config_observation.py +29 -10
  7. airbyte_cdk/connector.py +24 -24
  8. airbyte_cdk/connector_builder/README.md +53 -0
  9. airbyte_cdk/connector_builder/connector_builder_handler.py +37 -11
  10. airbyte_cdk/connector_builder/main.py +45 -13
  11. airbyte_cdk/connector_builder/message_grouper.py +189 -50
  12. airbyte_cdk/connector_builder/models.py +3 -2
  13. airbyte_cdk/destinations/__init__.py +4 -3
  14. airbyte_cdk/destinations/destination.py +54 -20
  15. airbyte_cdk/destinations/vector_db_based/README.md +37 -0
  16. airbyte_cdk/destinations/vector_db_based/config.py +40 -17
  17. airbyte_cdk/destinations/vector_db_based/document_processor.py +56 -17
  18. airbyte_cdk/destinations/vector_db_based/embedder.py +57 -15
  19. airbyte_cdk/destinations/vector_db_based/test_utils.py +14 -4
  20. airbyte_cdk/destinations/vector_db_based/utils.py +8 -2
  21. airbyte_cdk/destinations/vector_db_based/writer.py +24 -5
  22. airbyte_cdk/entrypoint.py +153 -44
  23. airbyte_cdk/exception_handler.py +21 -3
  24. airbyte_cdk/logger.py +30 -44
  25. airbyte_cdk/models/__init__.py +13 -2
  26. airbyte_cdk/models/airbyte_protocol.py +86 -1
  27. airbyte_cdk/models/airbyte_protocol_serializers.py +44 -0
  28. airbyte_cdk/models/file_transfer_record_message.py +13 -0
  29. airbyte_cdk/models/well_known_types.py +1 -1
  30. airbyte_cdk/sources/__init__.py +5 -1
  31. airbyte_cdk/sources/abstract_source.py +125 -79
  32. airbyte_cdk/sources/concurrent_source/__init__.py +7 -2
  33. airbyte_cdk/sources/concurrent_source/concurrent_read_processor.py +102 -36
  34. airbyte_cdk/sources/concurrent_source/concurrent_source.py +29 -36
  35. airbyte_cdk/sources/concurrent_source/concurrent_source_adapter.py +94 -10
  36. airbyte_cdk/sources/concurrent_source/stream_thread_exception.py +25 -0
  37. airbyte_cdk/sources/concurrent_source/thread_pool_manager.py +20 -14
  38. airbyte_cdk/sources/config.py +3 -2
  39. airbyte_cdk/sources/connector_state_manager.py +49 -83
  40. airbyte_cdk/sources/declarative/async_job/job.py +52 -0
  41. airbyte_cdk/sources/declarative/async_job/job_orchestrator.py +497 -0
  42. airbyte_cdk/sources/declarative/async_job/job_tracker.py +75 -0
  43. airbyte_cdk/sources/declarative/async_job/repository.py +35 -0
  44. airbyte_cdk/sources/declarative/async_job/status.py +24 -0
  45. airbyte_cdk/sources/declarative/async_job/timer.py +39 -0
  46. airbyte_cdk/sources/declarative/auth/__init__.py +2 -3
  47. airbyte_cdk/sources/declarative/auth/declarative_authenticator.py +3 -1
  48. airbyte_cdk/sources/declarative/auth/jwt.py +191 -0
  49. airbyte_cdk/sources/declarative/auth/oauth.py +60 -20
  50. airbyte_cdk/sources/declarative/auth/selective_authenticator.py +10 -2
  51. airbyte_cdk/sources/declarative/auth/token.py +28 -10
  52. airbyte_cdk/sources/declarative/auth/token_provider.py +9 -8
  53. airbyte_cdk/sources/declarative/checks/check_stream.py +16 -8
  54. airbyte_cdk/sources/declarative/checks/connection_checker.py +4 -2
  55. airbyte_cdk/sources/declarative/concurrency_level/__init__.py +7 -0
  56. airbyte_cdk/sources/declarative/concurrency_level/concurrency_level.py +50 -0
  57. airbyte_cdk/sources/declarative/concurrent_declarative_source.py +490 -0
  58. airbyte_cdk/sources/declarative/datetime/datetime_parser.py +4 -0
  59. airbyte_cdk/sources/declarative/datetime/min_max_datetime.py +26 -6
  60. airbyte_cdk/sources/declarative/declarative_component_schema.yaml +1185 -85
  61. airbyte_cdk/sources/declarative/declarative_source.py +5 -2
  62. airbyte_cdk/sources/declarative/declarative_stream.py +95 -9
  63. airbyte_cdk/sources/declarative/decoders/__init__.py +23 -2
  64. airbyte_cdk/sources/declarative/decoders/composite_raw_decoder.py +97 -0
  65. airbyte_cdk/sources/declarative/decoders/decoder.py +11 -4
  66. airbyte_cdk/sources/declarative/decoders/json_decoder.py +92 -5
  67. airbyte_cdk/sources/declarative/decoders/noop_decoder.py +21 -0
  68. airbyte_cdk/sources/declarative/decoders/pagination_decoder_decorator.py +39 -0
  69. airbyte_cdk/sources/declarative/decoders/xml_decoder.py +98 -0
  70. airbyte_cdk/sources/declarative/extractors/__init__.py +12 -1
  71. airbyte_cdk/sources/declarative/extractors/dpath_extractor.py +29 -24
  72. airbyte_cdk/sources/declarative/extractors/http_selector.py +4 -5
  73. airbyte_cdk/sources/declarative/extractors/record_extractor.py +2 -3
  74. airbyte_cdk/sources/declarative/extractors/record_filter.py +63 -8
  75. airbyte_cdk/sources/declarative/extractors/record_selector.py +85 -26
  76. airbyte_cdk/sources/declarative/extractors/response_to_file_extractor.py +177 -0
  77. airbyte_cdk/sources/declarative/extractors/type_transformer.py +55 -0
  78. airbyte_cdk/sources/declarative/incremental/__init__.py +31 -3
  79. airbyte_cdk/sources/declarative/incremental/concurrent_partition_cursor.py +346 -0
  80. airbyte_cdk/sources/declarative/incremental/datetime_based_cursor.py +156 -48
  81. airbyte_cdk/sources/declarative/incremental/declarative_cursor.py +13 -0
  82. airbyte_cdk/sources/declarative/incremental/global_substream_cursor.py +350 -0
  83. airbyte_cdk/sources/declarative/incremental/per_partition_cursor.py +173 -74
  84. airbyte_cdk/sources/declarative/incremental/per_partition_with_global.py +200 -0
  85. airbyte_cdk/sources/declarative/incremental/resumable_full_refresh_cursor.py +122 -0
  86. airbyte_cdk/sources/declarative/interpolation/filters.py +27 -1
  87. airbyte_cdk/sources/declarative/interpolation/interpolated_boolean.py +23 -5
  88. airbyte_cdk/sources/declarative/interpolation/interpolated_mapping.py +12 -8
  89. airbyte_cdk/sources/declarative/interpolation/interpolated_nested_mapping.py +13 -6
  90. airbyte_cdk/sources/declarative/interpolation/interpolated_string.py +21 -6
  91. airbyte_cdk/sources/declarative/interpolation/interpolation.py +9 -3
  92. airbyte_cdk/sources/declarative/interpolation/jinja.py +72 -37
  93. airbyte_cdk/sources/declarative/interpolation/macros.py +72 -17
  94. airbyte_cdk/sources/declarative/manifest_declarative_source.py +193 -52
  95. airbyte_cdk/sources/declarative/migrations/legacy_to_per_partition_state_migration.py +98 -0
  96. airbyte_cdk/sources/declarative/migrations/state_migration.py +24 -0
  97. airbyte_cdk/sources/declarative/models/__init__.py +1 -1
  98. airbyte_cdk/sources/declarative/models/declarative_component_schema.py +1319 -603
  99. airbyte_cdk/sources/declarative/parsers/custom_exceptions.py +2 -2
  100. airbyte_cdk/sources/declarative/parsers/manifest_component_transformer.py +26 -4
  101. airbyte_cdk/sources/declarative/parsers/manifest_reference_resolver.py +26 -15
  102. airbyte_cdk/sources/declarative/parsers/model_to_component_factory.py +1759 -225
  103. airbyte_cdk/sources/declarative/partition_routers/__init__.py +24 -4
  104. airbyte_cdk/sources/declarative/partition_routers/async_job_partition_router.py +65 -0
  105. airbyte_cdk/sources/declarative/partition_routers/cartesian_product_stream_slicer.py +176 -0
  106. airbyte_cdk/sources/declarative/partition_routers/list_partition_router.py +39 -9
  107. airbyte_cdk/sources/declarative/partition_routers/partition_router.py +62 -0
  108. airbyte_cdk/sources/declarative/partition_routers/single_partition_router.py +15 -3
  109. airbyte_cdk/sources/declarative/partition_routers/substream_partition_router.py +222 -39
  110. airbyte_cdk/sources/declarative/requesters/error_handlers/__init__.py +19 -5
  111. airbyte_cdk/sources/declarative/requesters/error_handlers/backoff_strategies/__init__.py +3 -1
  112. airbyte_cdk/sources/declarative/requesters/error_handlers/backoff_strategies/constant_backoff_strategy.py +19 -7
  113. airbyte_cdk/sources/declarative/requesters/error_handlers/backoff_strategies/exponential_backoff_strategy.py +19 -7
  114. airbyte_cdk/sources/declarative/requesters/error_handlers/backoff_strategies/header_helper.py +4 -2
  115. airbyte_cdk/sources/declarative/requesters/error_handlers/backoff_strategies/wait_time_from_header_backoff_strategy.py +41 -9
  116. airbyte_cdk/sources/declarative/requesters/error_handlers/backoff_strategies/wait_until_time_from_header_backoff_strategy.py +29 -14
  117. airbyte_cdk/sources/declarative/requesters/error_handlers/backoff_strategy.py +5 -13
  118. airbyte_cdk/sources/declarative/requesters/error_handlers/composite_error_handler.py +32 -16
  119. airbyte_cdk/sources/declarative/requesters/error_handlers/default_error_handler.py +46 -56
  120. airbyte_cdk/sources/declarative/requesters/error_handlers/default_http_response_filter.py +40 -0
  121. airbyte_cdk/sources/declarative/requesters/error_handlers/error_handler.py +6 -32
  122. airbyte_cdk/sources/declarative/requesters/error_handlers/http_response_filter.py +119 -41
  123. airbyte_cdk/sources/declarative/requesters/http_job_repository.py +228 -0
  124. airbyte_cdk/sources/declarative/requesters/http_requester.py +98 -344
  125. airbyte_cdk/sources/declarative/requesters/paginators/__init__.py +14 -3
  126. airbyte_cdk/sources/declarative/requesters/paginators/default_paginator.py +105 -46
  127. airbyte_cdk/sources/declarative/requesters/paginators/no_pagination.py +14 -8
  128. airbyte_cdk/sources/declarative/requesters/paginators/paginator.py +19 -8
  129. airbyte_cdk/sources/declarative/requesters/paginators/strategies/__init__.py +9 -3
  130. airbyte_cdk/sources/declarative/requesters/paginators/strategies/cursor_pagination_strategy.py +53 -21
  131. airbyte_cdk/sources/declarative/requesters/paginators/strategies/offset_increment.py +42 -19
  132. airbyte_cdk/sources/declarative/requesters/paginators/strategies/page_increment.py +25 -12
  133. airbyte_cdk/sources/declarative/requesters/paginators/strategies/pagination_strategy.py +13 -10
  134. airbyte_cdk/sources/declarative/requesters/paginators/strategies/stop_condition.py +26 -13
  135. airbyte_cdk/sources/declarative/requesters/request_options/__init__.py +15 -2
  136. airbyte_cdk/sources/declarative/requesters/request_options/datetime_based_request_options_provider.py +91 -0
  137. airbyte_cdk/sources/declarative/requesters/request_options/default_request_options_provider.py +60 -0
  138. airbyte_cdk/sources/declarative/requesters/request_options/interpolated_nested_request_input_provider.py +31 -14
  139. airbyte_cdk/sources/declarative/requesters/request_options/interpolated_request_input_provider.py +27 -15
  140. airbyte_cdk/sources/declarative/requesters/request_options/interpolated_request_options_provider.py +63 -10
  141. airbyte_cdk/sources/declarative/requesters/request_options/request_options_provider.py +1 -1
  142. airbyte_cdk/sources/declarative/requesters/requester.py +9 -17
  143. airbyte_cdk/sources/declarative/resolvers/__init__.py +41 -0
  144. airbyte_cdk/sources/declarative/resolvers/components_resolver.py +55 -0
  145. airbyte_cdk/sources/declarative/resolvers/config_components_resolver.py +136 -0
  146. airbyte_cdk/sources/declarative/resolvers/http_components_resolver.py +112 -0
  147. airbyte_cdk/sources/declarative/retrievers/__init__.py +6 -2
  148. airbyte_cdk/sources/declarative/retrievers/async_retriever.py +100 -0
  149. airbyte_cdk/sources/declarative/retrievers/retriever.py +1 -3
  150. airbyte_cdk/sources/declarative/retrievers/simple_retriever.py +229 -73
  151. airbyte_cdk/sources/declarative/schema/__init__.py +14 -1
  152. airbyte_cdk/sources/declarative/schema/default_schema_loader.py +5 -3
  153. airbyte_cdk/sources/declarative/schema/dynamic_schema_loader.py +236 -0
  154. airbyte_cdk/sources/declarative/schema/json_file_schema_loader.py +8 -8
  155. airbyte_cdk/sources/declarative/spec/spec.py +12 -5
  156. airbyte_cdk/sources/declarative/stream_slicers/__init__.py +1 -2
  157. airbyte_cdk/sources/declarative/stream_slicers/declarative_partition_generator.py +88 -0
  158. airbyte_cdk/sources/declarative/stream_slicers/stream_slicer.py +9 -14
  159. airbyte_cdk/sources/declarative/transformations/add_fields.py +19 -11
  160. airbyte_cdk/sources/declarative/transformations/flatten_fields.py +52 -0
  161. airbyte_cdk/sources/declarative/transformations/keys_replace_transformation.py +61 -0
  162. airbyte_cdk/sources/declarative/transformations/keys_to_lower_transformation.py +22 -0
  163. airbyte_cdk/sources/declarative/transformations/keys_to_snake_transformation.py +68 -0
  164. airbyte_cdk/sources/declarative/transformations/remove_fields.py +13 -10
  165. airbyte_cdk/sources/declarative/transformations/transformation.py +5 -5
  166. airbyte_cdk/sources/declarative/types.py +19 -110
  167. airbyte_cdk/sources/declarative/yaml_declarative_source.py +31 -10
  168. airbyte_cdk/sources/embedded/base_integration.py +16 -5
  169. airbyte_cdk/sources/embedded/catalog.py +16 -4
  170. airbyte_cdk/sources/embedded/runner.py +19 -3
  171. airbyte_cdk/sources/embedded/tools.py +5 -2
  172. airbyte_cdk/sources/file_based/README.md +152 -0
  173. airbyte_cdk/sources/file_based/__init__.py +24 -0
  174. airbyte_cdk/sources/file_based/availability_strategy/__init__.py +9 -2
  175. airbyte_cdk/sources/file_based/availability_strategy/abstract_file_based_availability_strategy.py +22 -6
  176. airbyte_cdk/sources/file_based/availability_strategy/default_file_based_availability_strategy.py +46 -10
  177. airbyte_cdk/sources/file_based/config/abstract_file_based_spec.py +47 -10
  178. airbyte_cdk/sources/file_based/config/avro_format.py +2 -1
  179. airbyte_cdk/sources/file_based/config/csv_format.py +29 -10
  180. airbyte_cdk/sources/file_based/config/excel_format.py +18 -0
  181. airbyte_cdk/sources/file_based/config/file_based_stream_config.py +16 -4
  182. airbyte_cdk/sources/file_based/config/jsonl_format.py +2 -1
  183. airbyte_cdk/sources/file_based/config/parquet_format.py +2 -1
  184. airbyte_cdk/sources/file_based/config/unstructured_format.py +13 -5
  185. airbyte_cdk/sources/file_based/discovery_policy/__init__.py +6 -2
  186. airbyte_cdk/sources/file_based/discovery_policy/abstract_discovery_policy.py +2 -4
  187. airbyte_cdk/sources/file_based/discovery_policy/default_discovery_policy.py +7 -2
  188. airbyte_cdk/sources/file_based/exceptions.py +18 -15
  189. airbyte_cdk/sources/file_based/file_based_source.py +140 -33
  190. airbyte_cdk/sources/file_based/file_based_stream_reader.py +69 -5
  191. airbyte_cdk/sources/file_based/file_types/__init__.py +14 -1
  192. airbyte_cdk/sources/file_based/file_types/avro_parser.py +75 -24
  193. airbyte_cdk/sources/file_based/file_types/csv_parser.py +116 -34
  194. airbyte_cdk/sources/file_based/file_types/excel_parser.py +196 -0
  195. airbyte_cdk/sources/file_based/file_types/file_transfer.py +37 -0
  196. airbyte_cdk/sources/file_based/file_types/file_type_parser.py +4 -1
  197. airbyte_cdk/sources/file_based/file_types/jsonl_parser.py +24 -8
  198. airbyte_cdk/sources/file_based/file_types/parquet_parser.py +60 -18
  199. airbyte_cdk/sources/file_based/file_types/unstructured_parser.py +141 -41
  200. airbyte_cdk/sources/file_based/remote_file.py +1 -1
  201. airbyte_cdk/sources/file_based/schema_helpers.py +38 -10
  202. airbyte_cdk/sources/file_based/schema_validation_policies/__init__.py +3 -1
  203. airbyte_cdk/sources/file_based/schema_validation_policies/abstract_schema_validation_policy.py +3 -1
  204. airbyte_cdk/sources/file_based/schema_validation_policies/default_schema_validation_policies.py +16 -5
  205. airbyte_cdk/sources/file_based/stream/abstract_file_based_stream.py +50 -13
  206. airbyte_cdk/sources/file_based/stream/concurrent/adapters.py +67 -27
  207. airbyte_cdk/sources/file_based/stream/concurrent/cursor/__init__.py +5 -1
  208. airbyte_cdk/sources/file_based/stream/concurrent/cursor/abstract_concurrent_file_based_cursor.py +14 -23
  209. airbyte_cdk/sources/file_based/stream/concurrent/cursor/file_based_concurrent_cursor.py +54 -18
  210. airbyte_cdk/sources/file_based/stream/concurrent/cursor/file_based_final_state_cursor.py +21 -9
  211. airbyte_cdk/sources/file_based/stream/cursor/abstract_file_based_cursor.py +3 -1
  212. airbyte_cdk/sources/file_based/stream/cursor/default_file_based_cursor.py +27 -10
  213. airbyte_cdk/sources/file_based/stream/default_file_based_stream.py +147 -45
  214. airbyte_cdk/sources/http_logger.py +8 -3
  215. airbyte_cdk/sources/message/__init__.py +7 -1
  216. airbyte_cdk/sources/message/repository.py +18 -4
  217. airbyte_cdk/sources/source.py +42 -38
  218. airbyte_cdk/sources/streams/__init__.py +2 -2
  219. airbyte_cdk/sources/streams/availability_strategy.py +54 -3
  220. airbyte_cdk/sources/streams/call_rate.py +64 -21
  221. airbyte_cdk/sources/streams/checkpoint/__init__.py +26 -0
  222. airbyte_cdk/sources/streams/checkpoint/checkpoint_reader.py +335 -0
  223. airbyte_cdk/sources/{declarative/incremental → streams/checkpoint}/cursor.py +17 -14
  224. airbyte_cdk/sources/streams/checkpoint/per_partition_key_serializer.py +22 -0
  225. airbyte_cdk/sources/streams/checkpoint/resumable_full_refresh_cursor.py +51 -0
  226. airbyte_cdk/sources/streams/checkpoint/substream_resumable_full_refresh_cursor.py +110 -0
  227. airbyte_cdk/sources/streams/concurrent/README.md +7 -0
  228. airbyte_cdk/sources/streams/concurrent/abstract_stream.py +7 -2
  229. airbyte_cdk/sources/streams/concurrent/adapters.py +84 -75
  230. airbyte_cdk/sources/streams/concurrent/availability_strategy.py +30 -2
  231. airbyte_cdk/sources/streams/concurrent/cursor.py +298 -42
  232. airbyte_cdk/sources/streams/concurrent/default_stream.py +12 -3
  233. airbyte_cdk/sources/streams/concurrent/exceptions.py +3 -0
  234. airbyte_cdk/sources/streams/concurrent/helpers.py +14 -3
  235. airbyte_cdk/sources/streams/concurrent/partition_enqueuer.py +12 -3
  236. airbyte_cdk/sources/streams/concurrent/partition_reader.py +10 -3
  237. airbyte_cdk/sources/streams/concurrent/partitions/partition.py +1 -16
  238. airbyte_cdk/sources/streams/concurrent/partitions/stream_slicer.py +21 -0
  239. airbyte_cdk/sources/streams/concurrent/partitions/types.py +15 -5
  240. airbyte_cdk/sources/streams/concurrent/state_converters/abstract_stream_state_converter.py +109 -17
  241. airbyte_cdk/sources/streams/concurrent/state_converters/datetime_stream_state_converter.py +90 -72
  242. airbyte_cdk/sources/streams/core.py +412 -87
  243. airbyte_cdk/sources/streams/http/__init__.py +2 -1
  244. airbyte_cdk/sources/streams/http/availability_strategy.py +12 -101
  245. airbyte_cdk/sources/streams/http/error_handlers/__init__.py +22 -0
  246. airbyte_cdk/sources/streams/http/error_handlers/backoff_strategy.py +28 -0
  247. airbyte_cdk/sources/streams/http/error_handlers/default_backoff_strategy.py +17 -0
  248. airbyte_cdk/sources/streams/http/error_handlers/default_error_mapping.py +86 -0
  249. airbyte_cdk/sources/streams/http/error_handlers/error_handler.py +42 -0
  250. airbyte_cdk/sources/streams/http/error_handlers/error_message_parser.py +19 -0
  251. airbyte_cdk/sources/streams/http/error_handlers/http_status_error_handler.py +110 -0
  252. airbyte_cdk/sources/streams/http/error_handlers/json_error_message_parser.py +52 -0
  253. airbyte_cdk/sources/streams/http/error_handlers/response_models.py +65 -0
  254. airbyte_cdk/sources/streams/http/exceptions.py +27 -7
  255. airbyte_cdk/sources/streams/http/http.py +369 -246
  256. airbyte_cdk/sources/streams/http/http_client.py +531 -0
  257. airbyte_cdk/sources/streams/http/rate_limiting.py +76 -12
  258. airbyte_cdk/sources/streams/http/requests_native_auth/abstract_oauth.py +28 -9
  259. airbyte_cdk/sources/streams/http/requests_native_auth/abstract_token.py +2 -1
  260. airbyte_cdk/sources/streams/http/requests_native_auth/oauth.py +90 -35
  261. airbyte_cdk/sources/streams/http/requests_native_auth/token.py +13 -3
  262. airbyte_cdk/sources/types.py +154 -0
  263. airbyte_cdk/sources/utils/record_helper.py +36 -21
  264. airbyte_cdk/sources/utils/schema_helpers.py +13 -6
  265. airbyte_cdk/sources/utils/slice_logger.py +4 -1
  266. airbyte_cdk/sources/utils/transform.py +54 -20
  267. airbyte_cdk/sql/_util/hashing.py +34 -0
  268. airbyte_cdk/sql/_util/name_normalizers.py +92 -0
  269. airbyte_cdk/sql/constants.py +32 -0
  270. airbyte_cdk/sql/exceptions.py +235 -0
  271. airbyte_cdk/sql/secrets.py +123 -0
  272. airbyte_cdk/sql/shared/__init__.py +15 -0
  273. airbyte_cdk/sql/shared/catalog_providers.py +145 -0
  274. airbyte_cdk/sql/shared/sql_processor.py +786 -0
  275. airbyte_cdk/sql/types.py +160 -0
  276. airbyte_cdk/test/catalog_builder.py +70 -18
  277. airbyte_cdk/test/entrypoint_wrapper.py +117 -42
  278. airbyte_cdk/test/mock_http/__init__.py +1 -1
  279. airbyte_cdk/test/mock_http/matcher.py +6 -0
  280. airbyte_cdk/test/mock_http/mocker.py +57 -10
  281. airbyte_cdk/test/mock_http/request.py +19 -3
  282. airbyte_cdk/test/mock_http/response.py +3 -1
  283. airbyte_cdk/test/mock_http/response_builder.py +32 -16
  284. airbyte_cdk/test/state_builder.py +18 -10
  285. airbyte_cdk/test/utils/__init__.py +1 -0
  286. airbyte_cdk/test/utils/data.py +24 -0
  287. airbyte_cdk/test/utils/http_mocking.py +16 -0
  288. airbyte_cdk/test/utils/manifest_only_fixtures.py +60 -0
  289. airbyte_cdk/test/utils/reading.py +26 -0
  290. airbyte_cdk/utils/__init__.py +2 -1
  291. airbyte_cdk/utils/airbyte_secrets_utils.py +5 -3
  292. airbyte_cdk/utils/analytics_message.py +10 -2
  293. airbyte_cdk/utils/datetime_format_inferrer.py +4 -1
  294. airbyte_cdk/utils/event_timing.py +10 -10
  295. airbyte_cdk/utils/mapping_helpers.py +3 -1
  296. airbyte_cdk/utils/message_utils.py +20 -11
  297. airbyte_cdk/utils/print_buffer.py +75 -0
  298. airbyte_cdk/utils/schema_inferrer.py +198 -28
  299. airbyte_cdk/utils/slice_hasher.py +30 -0
  300. airbyte_cdk/utils/spec_schema_transformations.py +6 -3
  301. airbyte_cdk/utils/stream_status_utils.py +8 -1
  302. airbyte_cdk/utils/traced_exception.py +61 -21
  303. airbyte_cdk-6.17.1.dev0.dist-info/METADATA +109 -0
  304. airbyte_cdk-6.17.1.dev0.dist-info/RECORD +350 -0
  305. {airbyte_cdk-0.72.1.dist-info → airbyte_cdk-6.17.1.dev0.dist-info}/WHEEL +1 -2
  306. airbyte_cdk-6.17.1.dev0.dist-info/entry_points.txt +3 -0
  307. airbyte_cdk/sources/declarative/create_partial.py +0 -92
  308. airbyte_cdk/sources/declarative/parsers/class_types_registry.py +0 -102
  309. airbyte_cdk/sources/declarative/parsers/default_implementation_registry.py +0 -64
  310. airbyte_cdk/sources/declarative/requesters/error_handlers/response_action.py +0 -16
  311. airbyte_cdk/sources/declarative/requesters/error_handlers/response_status.py +0 -68
  312. airbyte_cdk/sources/declarative/stream_slicers/cartesian_product_stream_slicer.py +0 -114
  313. airbyte_cdk/sources/deprecated/base_source.py +0 -94
  314. airbyte_cdk/sources/deprecated/client.py +0 -99
  315. airbyte_cdk/sources/singer/__init__.py +0 -8
  316. airbyte_cdk/sources/singer/singer_helpers.py +0 -304
  317. airbyte_cdk/sources/singer/source.py +0 -186
  318. airbyte_cdk/sources/streams/concurrent/partitions/record.py +0 -23
  319. airbyte_cdk/sources/streams/http/auth/__init__.py +0 -17
  320. airbyte_cdk/sources/streams/http/auth/core.py +0 -29
  321. airbyte_cdk/sources/streams/http/auth/oauth.py +0 -113
  322. airbyte_cdk/sources/streams/http/auth/token.py +0 -47
  323. airbyte_cdk/sources/streams/utils/stream_helper.py +0 -40
  324. airbyte_cdk/sources/utils/catalog_helpers.py +0 -22
  325. airbyte_cdk/sources/utils/schema_models.py +0 -84
  326. airbyte_cdk-0.72.1.dist-info/METADATA +0 -243
  327. airbyte_cdk-0.72.1.dist-info/RECORD +0 -466
  328. airbyte_cdk-0.72.1.dist-info/top_level.txt +0 -3
  329. source_declarative_manifest/main.py +0 -29
  330. unit_tests/connector_builder/__init__.py +0 -3
  331. unit_tests/connector_builder/test_connector_builder_handler.py +0 -871
  332. unit_tests/connector_builder/test_message_grouper.py +0 -713
  333. unit_tests/connector_builder/utils.py +0 -27
  334. unit_tests/destinations/test_destination.py +0 -243
  335. unit_tests/singer/test_singer_helpers.py +0 -56
  336. unit_tests/singer/test_singer_source.py +0 -112
  337. unit_tests/sources/__init__.py +0 -0
  338. unit_tests/sources/concurrent_source/__init__.py +0 -3
  339. unit_tests/sources/concurrent_source/test_concurrent_source_adapter.py +0 -106
  340. unit_tests/sources/declarative/__init__.py +0 -3
  341. unit_tests/sources/declarative/auth/__init__.py +0 -3
  342. unit_tests/sources/declarative/auth/test_oauth.py +0 -331
  343. unit_tests/sources/declarative/auth/test_selective_authenticator.py +0 -39
  344. unit_tests/sources/declarative/auth/test_session_token_auth.py +0 -182
  345. unit_tests/sources/declarative/auth/test_token_auth.py +0 -200
  346. unit_tests/sources/declarative/auth/test_token_provider.py +0 -73
  347. unit_tests/sources/declarative/checks/__init__.py +0 -3
  348. unit_tests/sources/declarative/checks/test_check_stream.py +0 -146
  349. unit_tests/sources/declarative/decoders/__init__.py +0 -0
  350. unit_tests/sources/declarative/decoders/test_json_decoder.py +0 -16
  351. unit_tests/sources/declarative/external_component.py +0 -13
  352. unit_tests/sources/declarative/extractors/__init__.py +0 -3
  353. unit_tests/sources/declarative/extractors/test_dpath_extractor.py +0 -55
  354. unit_tests/sources/declarative/extractors/test_record_filter.py +0 -55
  355. unit_tests/sources/declarative/extractors/test_record_selector.py +0 -179
  356. unit_tests/sources/declarative/incremental/__init__.py +0 -0
  357. unit_tests/sources/declarative/incremental/test_datetime_based_cursor.py +0 -860
  358. unit_tests/sources/declarative/incremental/test_per_partition_cursor.py +0 -406
  359. unit_tests/sources/declarative/incremental/test_per_partition_cursor_integration.py +0 -332
  360. unit_tests/sources/declarative/interpolation/__init__.py +0 -3
  361. unit_tests/sources/declarative/interpolation/test_filters.py +0 -80
  362. unit_tests/sources/declarative/interpolation/test_interpolated_boolean.py +0 -40
  363. unit_tests/sources/declarative/interpolation/test_interpolated_mapping.py +0 -35
  364. unit_tests/sources/declarative/interpolation/test_interpolated_nested_mapping.py +0 -45
  365. unit_tests/sources/declarative/interpolation/test_interpolated_string.py +0 -25
  366. unit_tests/sources/declarative/interpolation/test_jinja.py +0 -240
  367. unit_tests/sources/declarative/interpolation/test_macros.py +0 -73
  368. unit_tests/sources/declarative/parsers/__init__.py +0 -3
  369. unit_tests/sources/declarative/parsers/test_manifest_component_transformer.py +0 -406
  370. unit_tests/sources/declarative/parsers/test_manifest_reference_resolver.py +0 -139
  371. unit_tests/sources/declarative/parsers/test_model_to_component_factory.py +0 -1847
  372. unit_tests/sources/declarative/parsers/testing_components.py +0 -36
  373. unit_tests/sources/declarative/partition_routers/__init__.py +0 -3
  374. unit_tests/sources/declarative/partition_routers/test_list_partition_router.py +0 -155
  375. unit_tests/sources/declarative/partition_routers/test_single_partition_router.py +0 -14
  376. unit_tests/sources/declarative/partition_routers/test_substream_partition_router.py +0 -404
  377. unit_tests/sources/declarative/requesters/__init__.py +0 -3
  378. unit_tests/sources/declarative/requesters/error_handlers/__init__.py +0 -3
  379. unit_tests/sources/declarative/requesters/error_handlers/backoff_strategies/__init__.py +0 -3
  380. unit_tests/sources/declarative/requesters/error_handlers/backoff_strategies/test_constant_backoff.py +0 -34
  381. unit_tests/sources/declarative/requesters/error_handlers/backoff_strategies/test_exponential_backoff.py +0 -36
  382. unit_tests/sources/declarative/requesters/error_handlers/backoff_strategies/test_header_helper.py +0 -38
  383. unit_tests/sources/declarative/requesters/error_handlers/backoff_strategies/test_wait_time_from_header.py +0 -35
  384. unit_tests/sources/declarative/requesters/error_handlers/backoff_strategies/test_wait_until_time_from_header.py +0 -64
  385. unit_tests/sources/declarative/requesters/error_handlers/test_composite_error_handler.py +0 -213
  386. unit_tests/sources/declarative/requesters/error_handlers/test_default_error_handler.py +0 -178
  387. unit_tests/sources/declarative/requesters/error_handlers/test_http_response_filter.py +0 -121
  388. unit_tests/sources/declarative/requesters/error_handlers/test_response_status.py +0 -44
  389. unit_tests/sources/declarative/requesters/paginators/__init__.py +0 -3
  390. unit_tests/sources/declarative/requesters/paginators/test_cursor_pagination_strategy.py +0 -64
  391. unit_tests/sources/declarative/requesters/paginators/test_default_paginator.py +0 -313
  392. unit_tests/sources/declarative/requesters/paginators/test_no_paginator.py +0 -12
  393. unit_tests/sources/declarative/requesters/paginators/test_offset_increment.py +0 -58
  394. unit_tests/sources/declarative/requesters/paginators/test_page_increment.py +0 -70
  395. unit_tests/sources/declarative/requesters/paginators/test_request_option.py +0 -43
  396. unit_tests/sources/declarative/requesters/paginators/test_stop_condition.py +0 -105
  397. unit_tests/sources/declarative/requesters/request_options/__init__.py +0 -3
  398. unit_tests/sources/declarative/requesters/request_options/test_interpolated_request_options_provider.py +0 -101
  399. unit_tests/sources/declarative/requesters/test_http_requester.py +0 -974
  400. unit_tests/sources/declarative/requesters/test_interpolated_request_input_provider.py +0 -32
  401. unit_tests/sources/declarative/retrievers/__init__.py +0 -3
  402. unit_tests/sources/declarative/retrievers/test_simple_retriever.py +0 -542
  403. unit_tests/sources/declarative/schema/__init__.py +0 -6
  404. unit_tests/sources/declarative/schema/source_test/SourceTest.py +0 -8
  405. unit_tests/sources/declarative/schema/source_test/__init__.py +0 -3
  406. unit_tests/sources/declarative/schema/test_default_schema_loader.py +0 -32
  407. unit_tests/sources/declarative/schema/test_inline_schema_loader.py +0 -19
  408. unit_tests/sources/declarative/schema/test_json_file_schema_loader.py +0 -26
  409. unit_tests/sources/declarative/states/__init__.py +0 -3
  410. unit_tests/sources/declarative/stream_slicers/__init__.py +0 -3
  411. unit_tests/sources/declarative/stream_slicers/test_cartesian_product_stream_slicer.py +0 -225
  412. unit_tests/sources/declarative/test_create_partial.py +0 -83
  413. unit_tests/sources/declarative/test_declarative_stream.py +0 -103
  414. unit_tests/sources/declarative/test_manifest_declarative_source.py +0 -1260
  415. unit_tests/sources/declarative/test_types.py +0 -39
  416. unit_tests/sources/declarative/test_yaml_declarative_source.py +0 -148
  417. unit_tests/sources/file_based/__init__.py +0 -0
  418. unit_tests/sources/file_based/availability_strategy/__init__.py +0 -0
  419. unit_tests/sources/file_based/availability_strategy/test_default_file_based_availability_strategy.py +0 -100
  420. unit_tests/sources/file_based/config/__init__.py +0 -0
  421. unit_tests/sources/file_based/config/test_abstract_file_based_spec.py +0 -28
  422. unit_tests/sources/file_based/config/test_csv_format.py +0 -34
  423. unit_tests/sources/file_based/config/test_file_based_stream_config.py +0 -84
  424. unit_tests/sources/file_based/discovery_policy/__init__.py +0 -0
  425. unit_tests/sources/file_based/discovery_policy/test_default_discovery_policy.py +0 -31
  426. unit_tests/sources/file_based/file_types/__init__.py +0 -0
  427. unit_tests/sources/file_based/file_types/test_avro_parser.py +0 -243
  428. unit_tests/sources/file_based/file_types/test_csv_parser.py +0 -546
  429. unit_tests/sources/file_based/file_types/test_jsonl_parser.py +0 -158
  430. unit_tests/sources/file_based/file_types/test_parquet_parser.py +0 -274
  431. unit_tests/sources/file_based/file_types/test_unstructured_parser.py +0 -593
  432. unit_tests/sources/file_based/helpers.py +0 -70
  433. unit_tests/sources/file_based/in_memory_files_source.py +0 -211
  434. unit_tests/sources/file_based/scenarios/__init__.py +0 -0
  435. unit_tests/sources/file_based/scenarios/avro_scenarios.py +0 -744
  436. unit_tests/sources/file_based/scenarios/check_scenarios.py +0 -220
  437. unit_tests/sources/file_based/scenarios/concurrent_incremental_scenarios.py +0 -2844
  438. unit_tests/sources/file_based/scenarios/csv_scenarios.py +0 -3105
  439. unit_tests/sources/file_based/scenarios/file_based_source_builder.py +0 -91
  440. unit_tests/sources/file_based/scenarios/incremental_scenarios.py +0 -1926
  441. unit_tests/sources/file_based/scenarios/jsonl_scenarios.py +0 -930
  442. unit_tests/sources/file_based/scenarios/parquet_scenarios.py +0 -754
  443. unit_tests/sources/file_based/scenarios/scenario_builder.py +0 -234
  444. unit_tests/sources/file_based/scenarios/unstructured_scenarios.py +0 -608
  445. unit_tests/sources/file_based/scenarios/user_input_schema_scenarios.py +0 -746
  446. unit_tests/sources/file_based/scenarios/validation_policy_scenarios.py +0 -726
  447. unit_tests/sources/file_based/stream/__init__.py +0 -0
  448. unit_tests/sources/file_based/stream/concurrent/__init__.py +0 -0
  449. unit_tests/sources/file_based/stream/concurrent/test_adapters.py +0 -362
  450. unit_tests/sources/file_based/stream/concurrent/test_file_based_concurrent_cursor.py +0 -458
  451. unit_tests/sources/file_based/stream/test_default_file_based_cursor.py +0 -310
  452. unit_tests/sources/file_based/stream/test_default_file_based_stream.py +0 -244
  453. unit_tests/sources/file_based/test_file_based_scenarios.py +0 -320
  454. unit_tests/sources/file_based/test_file_based_stream_reader.py +0 -272
  455. unit_tests/sources/file_based/test_scenarios.py +0 -253
  456. unit_tests/sources/file_based/test_schema_helpers.py +0 -346
  457. unit_tests/sources/fixtures/__init__.py +0 -3
  458. unit_tests/sources/fixtures/source_test_fixture.py +0 -153
  459. unit_tests/sources/message/__init__.py +0 -0
  460. unit_tests/sources/message/test_repository.py +0 -153
  461. unit_tests/sources/streams/__init__.py +0 -0
  462. unit_tests/sources/streams/concurrent/__init__.py +0 -3
  463. unit_tests/sources/streams/concurrent/scenarios/__init__.py +0 -3
  464. unit_tests/sources/streams/concurrent/scenarios/incremental_scenarios.py +0 -250
  465. unit_tests/sources/streams/concurrent/scenarios/stream_facade_builder.py +0 -140
  466. unit_tests/sources/streams/concurrent/scenarios/stream_facade_scenarios.py +0 -452
  467. unit_tests/sources/streams/concurrent/scenarios/test_concurrent_scenarios.py +0 -76
  468. unit_tests/sources/streams/concurrent/scenarios/thread_based_concurrent_stream_scenarios.py +0 -418
  469. unit_tests/sources/streams/concurrent/scenarios/thread_based_concurrent_stream_source_builder.py +0 -142
  470. unit_tests/sources/streams/concurrent/scenarios/utils.py +0 -55
  471. unit_tests/sources/streams/concurrent/test_adapters.py +0 -380
  472. unit_tests/sources/streams/concurrent/test_concurrent_read_processor.py +0 -684
  473. unit_tests/sources/streams/concurrent/test_cursor.py +0 -139
  474. unit_tests/sources/streams/concurrent/test_datetime_state_converter.py +0 -369
  475. unit_tests/sources/streams/concurrent/test_default_stream.py +0 -197
  476. unit_tests/sources/streams/concurrent/test_partition_enqueuer.py +0 -90
  477. unit_tests/sources/streams/concurrent/test_partition_reader.py +0 -67
  478. unit_tests/sources/streams/concurrent/test_thread_pool_manager.py +0 -106
  479. unit_tests/sources/streams/http/__init__.py +0 -0
  480. unit_tests/sources/streams/http/auth/__init__.py +0 -0
  481. unit_tests/sources/streams/http/auth/test_auth.py +0 -173
  482. unit_tests/sources/streams/http/requests_native_auth/__init__.py +0 -0
  483. unit_tests/sources/streams/http/requests_native_auth/test_requests_native_auth.py +0 -423
  484. unit_tests/sources/streams/http/test_availability_strategy.py +0 -180
  485. unit_tests/sources/streams/http/test_http.py +0 -635
  486. unit_tests/sources/streams/test_availability_strategy.py +0 -70
  487. unit_tests/sources/streams/test_call_rate.py +0 -300
  488. unit_tests/sources/streams/test_stream_read.py +0 -405
  489. unit_tests/sources/streams/test_streams_core.py +0 -184
  490. unit_tests/sources/test_abstract_source.py +0 -1442
  491. unit_tests/sources/test_concurrent_source.py +0 -112
  492. unit_tests/sources/test_config.py +0 -92
  493. unit_tests/sources/test_connector_state_manager.py +0 -482
  494. unit_tests/sources/test_http_logger.py +0 -252
  495. unit_tests/sources/test_integration_source.py +0 -86
  496. unit_tests/sources/test_source.py +0 -684
  497. unit_tests/sources/test_source_read.py +0 -460
  498. unit_tests/test/__init__.py +0 -0
  499. unit_tests/test/mock_http/__init__.py +0 -0
  500. unit_tests/test/mock_http/test_matcher.py +0 -53
  501. unit_tests/test/mock_http/test_mocker.py +0 -214
  502. unit_tests/test/mock_http/test_request.py +0 -117
  503. unit_tests/test/mock_http/test_response_builder.py +0 -177
  504. unit_tests/test/test_entrypoint_wrapper.py +0 -240
  505. unit_tests/utils/__init__.py +0 -0
  506. unit_tests/utils/test_datetime_format_inferrer.py +0 -60
  507. unit_tests/utils/test_mapping_helpers.py +0 -54
  508. unit_tests/utils/test_message_utils.py +0 -91
  509. unit_tests/utils/test_rate_limiting.py +0 -26
  510. unit_tests/utils/test_schema_inferrer.py +0 -202
  511. unit_tests/utils/test_secret_utils.py +0 -135
  512. unit_tests/utils/test_stream_status_utils.py +0 -61
  513. unit_tests/utils/test_traced_exception.py +0 -107
  514. /airbyte_cdk/sources/{deprecated → declarative/async_job}/__init__.py +0 -0
  515. {source_declarative_manifest → airbyte_cdk/sources/declarative/migrations}/__init__.py +0 -0
  516. {unit_tests/destinations → airbyte_cdk/sql}/__init__.py +0 -0
  517. {unit_tests/singer → airbyte_cdk/sql/_util}/__init__.py +0 -0
  518. {airbyte_cdk-0.72.1.dist-info → airbyte_cdk-6.17.1.dev0.dist-info}/LICENSE.txt +0 -0
@@ -3,13 +3,16 @@
3
3
  #
4
4
 
5
5
  from dataclasses import InitVar, dataclass
6
- from typing import Any, List, Mapping, Union
6
+ from typing import Any, List, Mapping, Optional, Union
7
7
 
8
- import airbyte_cdk.sources.declarative.requesters.error_handlers.response_status as response_status
9
8
  import requests
10
- from airbyte_cdk.sources.declarative.requesters.error_handlers.error_handler import ErrorHandler
11
- from airbyte_cdk.sources.declarative.requesters.error_handlers.response_action import ResponseAction
12
- from airbyte_cdk.sources.declarative.requesters.error_handlers.response_status import ResponseStatus
9
+
10
+ from airbyte_cdk.sources.streams.http.error_handlers import ErrorHandler
11
+ from airbyte_cdk.sources.streams.http.error_handlers.response_models import (
12
+ ErrorResolution,
13
+ ResponseAction,
14
+ create_fallback_error_resolution,
15
+ )
13
16
 
14
17
 
15
18
  @dataclass
@@ -45,19 +48,32 @@ class CompositeErrorHandler(ErrorHandler):
45
48
  raise ValueError("CompositeErrorHandler expects at least 1 underlying error handler")
46
49
 
47
50
  @property
48
- def max_retries(self) -> Union[int, None]:
51
+ def max_retries(self) -> Optional[int]:
49
52
  return self.error_handlers[0].max_retries
50
53
 
51
54
  @property
52
- def max_time(self) -> Union[int, None]:
55
+ def max_time(self) -> Optional[int]:
53
56
  return max([error_handler.max_time or 0 for error_handler in self.error_handlers])
54
57
 
55
- def interpret_response(self, response: requests.Response) -> ResponseStatus:
56
- should_retry = ResponseStatus(ResponseAction.FAIL)
57
- for retrier in self.error_handlers:
58
- should_retry = retrier.interpret_response(response)
59
- if should_retry.action == ResponseAction.SUCCESS:
60
- return response_status.SUCCESS
61
- if should_retry == response_status.IGNORE or should_retry.action == ResponseAction.RETRY:
62
- return should_retry
63
- return should_retry
58
+ def interpret_response(
59
+ self, response_or_exception: Optional[Union[requests.Response, Exception]]
60
+ ) -> ErrorResolution:
61
+ matched_error_resolution = None
62
+ for error_handler in self.error_handlers:
63
+ matched_error_resolution = error_handler.interpret_response(response_or_exception)
64
+
65
+ if not isinstance(matched_error_resolution, ErrorResolution):
66
+ continue
67
+
68
+ if matched_error_resolution.response_action == ResponseAction.SUCCESS:
69
+ return matched_error_resolution
70
+
71
+ if (
72
+ matched_error_resolution.response_action == ResponseAction.RETRY
73
+ or matched_error_resolution.response_action == ResponseAction.IGNORE
74
+ ):
75
+ return matched_error_resolution
76
+ if matched_error_resolution:
77
+ return matched_error_resolution
78
+
79
+ return create_fallback_error_resolution(response_or_exception)
@@ -5,17 +5,21 @@
5
5
  from dataclasses import InitVar, dataclass, field
6
6
  from typing import Any, List, Mapping, MutableMapping, Optional, Union
7
7
 
8
- import airbyte_cdk.sources.declarative.requesters.error_handlers.response_status as response_status
9
8
  import requests
10
- from airbyte_cdk.sources.declarative.requesters.error_handlers.backoff_strategies.exponential_backoff_strategy import (
11
- ExponentialBackoffStrategy,
9
+
10
+ from airbyte_cdk.sources.declarative.requesters.error_handlers.default_http_response_filter import (
11
+ DefaultHttpResponseFilter,
12
+ )
13
+ from airbyte_cdk.sources.declarative.requesters.error_handlers.http_response_filter import (
14
+ HttpResponseFilter,
12
15
  )
13
- from airbyte_cdk.sources.declarative.requesters.error_handlers.backoff_strategy import BackoffStrategy
14
- from airbyte_cdk.sources.declarative.requesters.error_handlers.error_handler import ErrorHandler
15
- from airbyte_cdk.sources.declarative.requesters.error_handlers.http_response_filter import HttpResponseFilter
16
- from airbyte_cdk.sources.declarative.requesters.error_handlers.response_action import ResponseAction
17
- from airbyte_cdk.sources.declarative.requesters.error_handlers.response_status import ResponseStatus
18
- from airbyte_cdk.sources.declarative.types import Config
16
+ from airbyte_cdk.sources.streams.http.error_handlers import BackoffStrategy, ErrorHandler
17
+ from airbyte_cdk.sources.streams.http.error_handlers.response_models import (
18
+ SUCCESS_RESOLUTION,
19
+ ErrorResolution,
20
+ create_fallback_error_resolution,
21
+ )
22
+ from airbyte_cdk.sources.types import Config
19
23
 
20
24
 
21
25
  @dataclass
@@ -23,12 +27,12 @@ class DefaultErrorHandler(ErrorHandler):
23
27
  """
24
28
  Default error handler.
25
29
 
26
- By default, the handler will only retry server errors (HTTP 5XX) and too many requests (HTTP 429) with exponential backoff.
30
+ By default, the handler will only use the `DEFAULT_ERROR_MAPPING` that is part of the Python CDK's `HttpStatusErrorHandler`.
27
31
 
28
- If the response is successful, then return SUCCESS
32
+ If the response is successful, then a SUCCESS_RESOLUTION is returned.
29
33
  Otherwise, iterate over the response_filters.
30
34
  If any of the filter match the response, then return the appropriate status.
31
- If the match is RETRY, then iterate sequentially over the backoff_strategies and return the first non-None backoff time.
35
+ When `DefaultErrorHandler.backoff_time()` is invoked, iterate sequentially over the backoff_strategies and return the first non-None backoff time, else return None.
32
36
 
33
37
  Sample configs:
34
38
 
@@ -89,8 +93,6 @@ class DefaultErrorHandler(ErrorHandler):
89
93
  to wait before retrying
90
94
  """
91
95
 
92
- DEFAULT_BACKOFF_STRATEGY = ExponentialBackoffStrategy
93
-
94
96
  parameters: InitVar[Mapping[str, Any]]
95
97
  config: Config
96
98
  response_filters: Optional[List[HttpResponseFilter]] = None
@@ -101,57 +103,45 @@ class DefaultErrorHandler(ErrorHandler):
101
103
  backoff_strategies: Optional[List[BackoffStrategy]] = None
102
104
 
103
105
  def __post_init__(self, parameters: Mapping[str, Any]) -> None:
104
- self.response_filters = self.response_filters or []
105
-
106
106
  if not self.response_filters:
107
- self.response_filters.append(
108
- HttpResponseFilter(
109
- ResponseAction.RETRY, http_codes=HttpResponseFilter.DEFAULT_RETRIABLE_ERRORS, config=self.config, parameters={}
110
- )
111
- )
112
- self.response_filters.append(HttpResponseFilter(ResponseAction.IGNORE, config={}, parameters={}))
113
-
114
- if not self.backoff_strategies:
115
- self.backoff_strategies = [DefaultErrorHandler.DEFAULT_BACKOFF_STRATEGY(parameters=parameters, config=self.config)]
107
+ self.response_filters = [HttpResponseFilter(config=self.config, parameters={})]
116
108
 
117
109
  self._last_request_to_attempt_count: MutableMapping[requests.PreparedRequest, int] = {}
118
110
 
119
- @property # type: ignore # overwrite the property to handle the case where max_retries is not provided in the constructor
120
- def max_retries(self) -> Union[int, None]:
121
- return self._max_retries
122
-
123
- @max_retries.setter
124
- def max_retries(self, value: int) -> None:
125
- # Covers the case where max_retries is not provided in the constructor, which causes the property object
126
- # to be set which we need to avoid doing
127
- if not isinstance(value, property):
128
- self._max_retries = value
129
-
130
- def interpret_response(self, response: requests.Response) -> ResponseStatus:
131
- request = response.request
132
-
133
- if request not in self._last_request_to_attempt_count:
134
- self._last_request_to_attempt_count = {request: 1}
135
- else:
136
- self._last_request_to_attempt_count[request] += 1
111
+ def interpret_response(
112
+ self, response_or_exception: Optional[Union[requests.Response, Exception]]
113
+ ) -> ErrorResolution:
137
114
  if self.response_filters:
138
115
  for response_filter in self.response_filters:
139
- matched_status = response_filter.matches(
140
- response=response, backoff_time=self._backoff_time(response, self._last_request_to_attempt_count[request])
116
+ matched_error_resolution = response_filter.matches(
117
+ response_or_exception=response_or_exception
141
118
  )
142
- if matched_status is not None:
143
- return matched_status
144
-
145
- if response.ok:
146
- return response_status.SUCCESS
147
- # Fail if the response matches no filters
148
- return response_status.FAIL
149
-
150
- def _backoff_time(self, response: requests.Response, attempt_count: int) -> Optional[float]:
119
+ if matched_error_resolution:
120
+ return matched_error_resolution
121
+ if isinstance(response_or_exception, requests.Response):
122
+ if response_or_exception.ok:
123
+ return SUCCESS_RESOLUTION
124
+
125
+ default_reponse_filter = DefaultHttpResponseFilter(parameters={}, config=self.config)
126
+ default_response_filter_resolution = default_reponse_filter.matches(response_or_exception)
127
+
128
+ return (
129
+ default_response_filter_resolution
130
+ if default_response_filter_resolution
131
+ else create_fallback_error_resolution(response_or_exception)
132
+ )
133
+
134
+ def backoff_time(
135
+ self,
136
+ response_or_exception: Optional[Union[requests.Response, requests.RequestException]],
137
+ attempt_count: int = 0,
138
+ ) -> Optional[float]:
151
139
  backoff = None
152
140
  if self.backoff_strategies:
153
- for backoff_strategies in self.backoff_strategies:
154
- backoff = backoff_strategies.backoff(response, attempt_count)
141
+ for backoff_strategy in self.backoff_strategies:
142
+ backoff = backoff_strategy.backoff_time(
143
+ response_or_exception=response_or_exception, attempt_count=attempt_count
144
+ )
155
145
  if backoff:
156
146
  return backoff
157
147
  return backoff
@@ -0,0 +1,40 @@
1
+ #
2
+ # Copyright (c) 2024 Airbyte, Inc., all rights reserved.
3
+ #
4
+
5
+ from typing import Optional, Union
6
+
7
+ import requests
8
+
9
+ from airbyte_cdk.sources.declarative.requesters.error_handlers.http_response_filter import (
10
+ HttpResponseFilter,
11
+ )
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.response_models import (
16
+ ErrorResolution,
17
+ create_fallback_error_resolution,
18
+ )
19
+
20
+
21
+ class DefaultHttpResponseFilter(HttpResponseFilter):
22
+ def matches(
23
+ self, response_or_exception: Optional[Union[requests.Response, Exception]]
24
+ ) -> Optional[ErrorResolution]:
25
+ default_mapped_error_resolution = None
26
+
27
+ if isinstance(response_or_exception, (requests.Response, Exception)):
28
+ mapped_key: Union[int, type] = (
29
+ response_or_exception.status_code
30
+ if isinstance(response_or_exception, requests.Response)
31
+ else response_or_exception.__class__
32
+ )
33
+
34
+ default_mapped_error_resolution = DEFAULT_ERROR_MAPPING.get(mapped_key)
35
+
36
+ return (
37
+ default_mapped_error_resolution
38
+ if default_mapped_error_resolution
39
+ else create_fallback_error_resolution(response_or_exception)
40
+ )
@@ -2,42 +2,16 @@
2
2
  # Copyright (c) 2023 Airbyte, Inc., all rights reserved.
3
3
  #
4
4
 
5
- from abc import abstractmethod
5
+ from abc import ABC
6
6
  from dataclasses import dataclass
7
- from typing import Union
8
7
 
9
- import requests
10
- from airbyte_cdk.sources.declarative.requesters.error_handlers.response_status import ResponseStatus
8
+ from airbyte_cdk.sources.streams.http.error_handlers import ErrorHandler
11
9
 
12
10
 
13
11
  @dataclass
14
- class ErrorHandler:
12
+ class DeclarativeErrorHandler(ErrorHandler, ABC):
15
13
  """
16
- Defines whether a request was successful and how to handle a failure.
17
- """
18
-
19
- @property
20
- @abstractmethod
21
- def max_retries(self) -> Union[int, None]:
22
- """
23
- Specifies maximum amount of retries for backoff policy. Return None for no limit.
24
- """
25
- pass
26
-
27
- @property
28
- @abstractmethod
29
- def max_time(self) -> Union[int, None]:
30
- """
31
- Specifies maximum total waiting time (in seconds) for backoff policy. Return None for no limit.
32
- """
33
- pass
14
+ This interface exists to retain backwards compatability with connectors that reference the declarative ErrorHandler. As part of the effort to promote common interfaces to the Python CDK, this now extends the Python CDK ErrorHandler interface.
34
15
 
35
- @abstractmethod
36
- def interpret_response(self, response: requests.Response) -> ResponseStatus:
37
- """
38
- Evaluate response status describing whether a failing request should be retried or ignored.
39
-
40
- :param response: response to evaluate
41
- :return: response status
42
- """
43
- pass
16
+ `ErrorHandler` defines how to handle errors that occur during the request process, returning an ErrorResolution object that defines how to proceed.
17
+ """
@@ -6,96 +6,174 @@ from dataclasses import InitVar, dataclass
6
6
  from typing import Any, Mapping, Optional, Set, Union
7
7
 
8
8
  import requests
9
+
10
+ from airbyte_cdk.models import FailureType
9
11
  from airbyte_cdk.sources.declarative.interpolation import InterpolatedString
10
12
  from airbyte_cdk.sources.declarative.interpolation.interpolated_boolean import InterpolatedBoolean
11
- from airbyte_cdk.sources.declarative.requesters.error_handlers.response_action import ResponseAction
12
- from airbyte_cdk.sources.declarative.requesters.error_handlers.response_status import ResponseStatus
13
- from airbyte_cdk.sources.declarative.types import Config
14
- from airbyte_cdk.sources.streams.http.http import HttpStream
13
+ from airbyte_cdk.sources.streams.http.error_handlers import JsonErrorMessageParser
14
+ from airbyte_cdk.sources.streams.http.error_handlers.default_error_mapping import (
15
+ DEFAULT_ERROR_MAPPING,
16
+ )
17
+ from airbyte_cdk.sources.streams.http.error_handlers.response_models import (
18
+ ErrorResolution,
19
+ ResponseAction,
20
+ )
21
+ from airbyte_cdk.sources.types import Config
15
22
 
16
23
 
17
24
  @dataclass
18
25
  class HttpResponseFilter:
19
26
  """
20
- Filter to select HttpResponses
27
+ Filter to select a response based on its HTTP status code, error message or a predicate.
28
+ If a response matches the filter, the response action, failure_type, and error message are returned as an ErrorResolution object.
29
+ For http_codes declared in the filter, the failure_type will default to `system_error`.
30
+ To override default failure_type use configured failure_type with ResponseAction.FAIL.
21
31
 
22
32
  Attributes:
23
33
  action (Union[ResponseAction, str]): action to execute if a request matches
34
+ failure_type (Union[ResponseAction, str]): failure type of traced exception if a response matches the filter
24
35
  http_codes (Set[int]): http code of matching requests
25
36
  error_message_contains (str): error substring of matching requests
26
37
  predicate (str): predicate to apply to determine if a request is matching
27
38
  error_message (Union[InterpolatedString, str): error message to display if the response matches the filter
28
39
  """
29
40
 
30
- TOO_MANY_REQUESTS_ERRORS = {429}
31
- DEFAULT_RETRIABLE_ERRORS = set([x for x in range(500, 600)]).union(TOO_MANY_REQUESTS_ERRORS)
32
-
33
- action: Union[ResponseAction, str]
34
41
  config: Config
35
42
  parameters: InitVar[Mapping[str, Any]]
36
- http_codes: Set[int] = None
37
- error_message_contains: str = None
43
+ action: Optional[Union[ResponseAction, str]] = None
44
+ failure_type: Optional[Union[FailureType, str]] = None
45
+ http_codes: Optional[Set[int]] = None
46
+ error_message_contains: Optional[str] = None
38
47
  predicate: Union[InterpolatedBoolean, str] = ""
39
48
  error_message: Union[InterpolatedString, str] = ""
40
49
 
41
- def __post_init__(self, parameters: Mapping[str, Any]):
42
- if isinstance(self.action, str):
43
- self.action = ResponseAction[self.action]
50
+ def __post_init__(self, parameters: Mapping[str, Any]) -> None:
51
+ if self.action is not None:
52
+ if (
53
+ self.http_codes is None
54
+ and self.predicate is None
55
+ and self.error_message_contains is None
56
+ ):
57
+ raise ValueError(
58
+ "HttpResponseFilter requires a filter condition if an action is specified"
59
+ )
60
+ elif isinstance(self.action, str):
61
+ self.action = ResponseAction[self.action]
44
62
  self.http_codes = self.http_codes or set()
45
63
  if isinstance(self.predicate, str):
46
64
  self.predicate = InterpolatedBoolean(condition=self.predicate, parameters=parameters)
47
- self.error_message = InterpolatedString.create(string_or_interpolated=self.error_message, parameters=parameters)
65
+ self.error_message = InterpolatedString.create(
66
+ string_or_interpolated=self.error_message, parameters=parameters
67
+ )
68
+ self._error_message_parser = JsonErrorMessageParser()
69
+ if self.failure_type and isinstance(self.failure_type, str):
70
+ self.failure_type = FailureType[self.failure_type]
71
+
72
+ def matches(
73
+ self, response_or_exception: Optional[Union[requests.Response, Exception]]
74
+ ) -> Optional[ErrorResolution]:
75
+ filter_action = self._matches_filter(response_or_exception)
76
+ mapped_key = (
77
+ response_or_exception.status_code
78
+ if isinstance(response_or_exception, requests.Response)
79
+ else response_or_exception.__class__
80
+ )
81
+
82
+ if isinstance(mapped_key, (int, Exception)):
83
+ default_mapped_error_resolution = self._match_default_error_mapping(mapped_key)
84
+ else:
85
+ default_mapped_error_resolution = None
48
86
 
49
- def matches(self, response: requests.Response, backoff_time: Optional[float] = None) -> Optional[ResponseStatus]:
50
- filter_action = self._matches_filter(response)
51
87
  if filter_action is not None:
52
- error_message = self._create_error_message(response)
53
- if filter_action == ResponseAction.RETRY:
54
- return ResponseStatus(
55
- response_action=ResponseAction.RETRY,
56
- retry_in=backoff_time,
57
- error_message=error_message,
58
- )
88
+ default_error_message = (
89
+ default_mapped_error_resolution.error_message
90
+ if default_mapped_error_resolution
91
+ else ""
92
+ )
93
+ error_message = None
94
+ if isinstance(response_or_exception, requests.Response):
95
+ error_message = self._create_error_message(response_or_exception)
96
+ error_message = error_message or default_error_message
97
+
98
+ if self.failure_type and filter_action == ResponseAction.FAIL:
99
+ failure_type = self.failure_type
100
+ elif default_mapped_error_resolution:
101
+ failure_type = default_mapped_error_resolution.failure_type
59
102
  else:
60
- return ResponseStatus(filter_action, error_message=error_message)
103
+ failure_type = FailureType.system_error
104
+
105
+ return ErrorResolution(
106
+ response_action=filter_action,
107
+ failure_type=failure_type,
108
+ error_message=error_message,
109
+ )
110
+
111
+ if (
112
+ (isinstance(self.http_codes, list) and len(self.http_codes)) is None
113
+ and self.predicate is None
114
+ and self.error_message_contains is None
115
+ ) and default_mapped_error_resolution:
116
+ return default_mapped_error_resolution
117
+
61
118
  return None
62
119
 
63
- def _matches_filter(self, response: requests.Response) -> Optional[ResponseAction]:
120
+ def _match_default_error_mapping(
121
+ self, mapped_key: Union[int, type[Exception]]
122
+ ) -> Optional[ErrorResolution]:
123
+ return DEFAULT_ERROR_MAPPING.get(mapped_key)
124
+
125
+ def _matches_filter(
126
+ self, response_or_exception: Optional[Union[requests.Response, Exception]]
127
+ ) -> Optional[ResponseAction]:
64
128
  """
65
- Apply the filter on the response and return the action to execute if it matches
129
+ Apply the HTTP filter on the response and return the action to execute if it matches
66
130
  :param response: The HTTP response to evaluate
67
131
  :return: The action to execute. None if the response does not match the filter
68
132
  """
69
- if (
70
- response.status_code in self.http_codes
71
- or (self._response_matches_predicate(response))
72
- or (self._response_contains_error_message(response))
133
+ if isinstance(response_or_exception, requests.Response) and (
134
+ response_or_exception.status_code in self.http_codes # type: ignore # http_codes set is always initialized to a value in __post_init__
135
+ or self._response_matches_predicate(response_or_exception)
136
+ or self._response_contains_error_message(response_or_exception)
73
137
  ):
74
- return self.action
75
- else:
76
- return None
138
+ return self.action # type: ignore # action is always cast to a ResponseAction not a str
139
+ return None
77
140
 
78
141
  @staticmethod
79
- def _safe_response_json(response: requests.Response) -> dict:
142
+ def _safe_response_json(response: requests.Response) -> dict[str, Any]:
80
143
  try:
81
- return response.json()
144
+ return response.json() # type: ignore # Response.json() returns a dictionary even if the signature does not
82
145
  except requests.exceptions.JSONDecodeError:
83
146
  return {}
84
147
 
85
- def _create_error_message(self, response: requests.Response) -> str:
148
+ def _create_error_message(self, response: requests.Response) -> Optional[str]:
86
149
  """
87
150
  Construct an error message based on the specified message template of the filter.
88
151
  :param response: The HTTP response which can be used during interpolation
89
152
  :return: The evaluated error message string to be emitted
90
153
  """
91
- return self.error_message.eval(self.config, response=self._safe_response_json(response), headers=response.headers)
154
+ return self.error_message.eval( # type: ignore [no-any-return, union-attr]
155
+ self.config, response=self._safe_response_json(response), headers=response.headers
156
+ )
92
157
 
93
158
  def _response_matches_predicate(self, response: requests.Response) -> bool:
94
- return self.predicate and self.predicate.eval(None, response=self._safe_response_json(response), headers=response.headers)
159
+ return (
160
+ bool(
161
+ self.predicate.condition # type: ignore [union-attr]
162
+ and self.predicate.eval( # type: ignore [union-attr]
163
+ None, # type: ignore [arg-type]
164
+ response=self._safe_response_json(response),
165
+ headers=response.headers,
166
+ )
167
+ )
168
+ if self.predicate
169
+ else False
170
+ )
95
171
 
96
172
  def _response_contains_error_message(self, response: requests.Response) -> bool:
97
173
  if not self.error_message_contains:
98
174
  return False
99
175
  else:
100
- error_message = HttpStream.parse_response_error_message(response)
101
- return error_message and self.error_message_contains in error_message
176
+ error_message = self._error_message_parser.parse_response_error_message(
177
+ response=response
178
+ )
179
+ return bool(error_message and self.error_message_contains in error_message)