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,14 @@
1
+ #
2
+ # Copyright (c) 2023 Airbyte, Inc., all rights reserved.
3
+ #
4
+
5
+ from .oauth import Oauth2Authenticator, SingleUseRefreshTokenOauth2Authenticator
6
+ from .token import BasicHttpAuthenticator, MultipleTokenAuthenticator, TokenAuthenticator
7
+
8
+ __all__ = [
9
+ "Oauth2Authenticator",
10
+ "SingleUseRefreshTokenOauth2Authenticator",
11
+ "TokenAuthenticator",
12
+ "MultipleTokenAuthenticator",
13
+ "BasicHttpAuthenticator",
14
+ ]
@@ -0,0 +1,479 @@
1
+ #
2
+ # Copyright (c) 2023 Airbyte, Inc., all rights reserved.
3
+ #
4
+
5
+ import logging
6
+ from abc import abstractmethod
7
+ from datetime import timedelta
8
+ from json import JSONDecodeError
9
+ from typing import Any, List, Mapping, MutableMapping, Optional, Tuple, Union
10
+
11
+ import backoff
12
+ import requests
13
+ from requests.auth import AuthBase
14
+
15
+ from airbyte_cdk.models import FailureType, Level
16
+ from airbyte_cdk.sources.http_logger import format_http_message
17
+ from airbyte_cdk.sources.message import MessageRepository, NoopMessageRepository
18
+ from airbyte_cdk.utils import AirbyteTracedException
19
+ from airbyte_cdk.utils.airbyte_secrets_utils import add_to_secrets
20
+ from airbyte_cdk.utils.datetime_helpers import AirbyteDateTime, ab_datetime_now, ab_datetime_parse
21
+
22
+ from ..exceptions import DefaultBackoffException
23
+
24
+ logger = logging.getLogger("airbyte")
25
+ _NOOP_MESSAGE_REPOSITORY = NoopMessageRepository()
26
+
27
+
28
+ class ResponseKeysMaxRecurtionReached(AirbyteTracedException):
29
+ """
30
+ Raised when the max level of recursion is reached, when trying to
31
+ find-and-get the target key, during the `_make_handled_request`
32
+ """
33
+
34
+
35
+ class AbstractOauth2Authenticator(AuthBase):
36
+ """
37
+ Abstract class for an OAuth authenticators that implements the OAuth token refresh flow. The authenticator
38
+ is designed to generically perform the refresh flow without regard to how config fields are get/set by
39
+ delegating that behavior to the classes implementing the interface.
40
+ """
41
+
42
+ _NO_STREAM_NAME = None
43
+
44
+ def __init__(
45
+ self,
46
+ refresh_token_error_status_codes: Tuple[int, ...] = (),
47
+ refresh_token_error_key: str = "",
48
+ refresh_token_error_values: Tuple[str, ...] = (),
49
+ ) -> None:
50
+ """
51
+ If all of refresh_token_error_status_codes, refresh_token_error_key, and refresh_token_error_values are set,
52
+ then http errors with such params will be wrapped in AirbyteTracedException.
53
+ """
54
+ self._refresh_token_error_status_codes = refresh_token_error_status_codes
55
+ self._refresh_token_error_key = refresh_token_error_key
56
+ self._refresh_token_error_values = refresh_token_error_values
57
+
58
+ def __call__(self, request: requests.PreparedRequest) -> requests.PreparedRequest:
59
+ """Attach the HTTP headers required to authenticate on the HTTP request"""
60
+ request.headers.update(self.get_auth_header())
61
+ return request
62
+
63
+ @property
64
+ def _is_access_token_flow(self) -> bool:
65
+ return self.get_token_refresh_endpoint() is None and self.access_token is not None
66
+
67
+ @property
68
+ def token_expiry_is_time_of_expiration(self) -> bool:
69
+ """
70
+ Indicates that the Token Expiry returns the date until which the token will be valid, not the amount of time it will be valid.
71
+ """
72
+
73
+ return False
74
+
75
+ @property
76
+ def token_expiry_date_format(self) -> Optional[str]:
77
+ """
78
+ Format of the datetime; exists it if expires_in is returned as the expiration datetime instead of seconds until it expires
79
+ """
80
+
81
+ return None
82
+
83
+ def get_auth_header(self) -> Mapping[str, Any]:
84
+ """HTTP header to set on the requests"""
85
+ token = self.access_token if self._is_access_token_flow else self.get_access_token()
86
+ return {"Authorization": f"Bearer {token}"}
87
+
88
+ def get_access_token(self) -> str:
89
+ """Returns the access token"""
90
+ if self.token_has_expired():
91
+ token, expires_in = self.refresh_access_token()
92
+ self.access_token = token
93
+ self.set_token_expiry_date(expires_in)
94
+
95
+ return self.access_token
96
+
97
+ def token_has_expired(self) -> bool:
98
+ """Returns True if the token is expired"""
99
+ return ab_datetime_now() > self.get_token_expiry_date()
100
+
101
+ def build_refresh_request_body(self) -> Mapping[str, Any]:
102
+ """
103
+ Returns the request body to set on the refresh request
104
+
105
+ Override to define additional parameters
106
+ """
107
+ payload: MutableMapping[str, Any] = {
108
+ self.get_grant_type_name(): self.get_grant_type(),
109
+ self.get_client_id_name(): self.get_client_id(),
110
+ self.get_client_secret_name(): self.get_client_secret(),
111
+ self.get_refresh_token_name(): self.get_refresh_token(),
112
+ }
113
+
114
+ if self.get_scopes():
115
+ payload["scopes"] = self.get_scopes()
116
+
117
+ if self.get_refresh_request_body():
118
+ for key, val in self.get_refresh_request_body().items():
119
+ # We defer to existing oauth constructs over custom configured fields
120
+ if key not in payload:
121
+ payload[key] = val
122
+
123
+ return payload
124
+
125
+ def build_refresh_request_headers(self) -> Mapping[str, Any] | None:
126
+ """
127
+ Returns the request headers to set on the refresh request
128
+
129
+ """
130
+ headers = self.get_refresh_request_headers()
131
+ return headers if headers else None
132
+
133
+ def refresh_access_token(self) -> Tuple[str, Union[str, int]]:
134
+ """
135
+ Returns the refresh token and its expiration datetime
136
+
137
+ :return: a tuple of (access_token, token_lifespan)
138
+ """
139
+ response_json = self._make_handled_request()
140
+ self._ensure_access_token_in_response(response_json)
141
+
142
+ return (
143
+ self._extract_access_token(response_json),
144
+ self._extract_token_expiry_date(response_json),
145
+ )
146
+
147
+ # ----------------
148
+ # PRIVATE METHODS
149
+ # ----------------
150
+
151
+ def _wrap_refresh_token_exception(
152
+ self, exception: requests.exceptions.RequestException
153
+ ) -> bool:
154
+ """
155
+ Wraps and handles exceptions that occur during the refresh token process.
156
+
157
+ This method checks if the provided exception is related to a refresh token error
158
+ by examining the response status code and specific error content.
159
+
160
+ Args:
161
+ exception (requests.exceptions.RequestException): The exception raised during the request.
162
+
163
+ Returns:
164
+ bool: True if the exception is related to a refresh token error, False otherwise.
165
+ """
166
+ try:
167
+ if exception.response is not None:
168
+ exception_content = exception.response.json()
169
+ else:
170
+ return False
171
+ except JSONDecodeError:
172
+ return False
173
+ return (
174
+ exception.response.status_code in self._refresh_token_error_status_codes
175
+ and exception_content.get(self._refresh_token_error_key)
176
+ in self._refresh_token_error_values
177
+ )
178
+
179
+ @backoff.on_exception(
180
+ backoff.expo,
181
+ DefaultBackoffException,
182
+ on_backoff=lambda details: logger.info(
183
+ f"Caught retryable error after {details['tries']} tries. Waiting {details['wait']} seconds then retrying..."
184
+ ),
185
+ max_time=300,
186
+ )
187
+ def _make_handled_request(self) -> Any:
188
+ """
189
+ Makes a handled HTTP request to refresh an OAuth token.
190
+
191
+ This method sends a POST request to the token refresh endpoint with the necessary
192
+ headers and body to obtain a new access token. It handles various exceptions that
193
+ may occur during the request and logs the response for troubleshooting purposes.
194
+
195
+ Returns:
196
+ Mapping[str, Any]: The JSON response from the token refresh endpoint.
197
+
198
+ Raises:
199
+ DefaultBackoffException: If the response status code is 429 (Too Many Requests)
200
+ or any 5xx server error.
201
+ AirbyteTracedException: If the refresh token is invalid or expired, prompting
202
+ re-authentication.
203
+ Exception: For any other exceptions that occur during the request.
204
+ """
205
+ try:
206
+ response = requests.request(
207
+ method="POST",
208
+ url=self.get_token_refresh_endpoint(), # type: ignore # returns None, if not provided, but str | bytes is expected.
209
+ data=self.build_refresh_request_body(),
210
+ headers=self.build_refresh_request_headers(),
211
+ )
212
+ # log the response even if the request failed for troubleshooting purposes
213
+ self._log_response(response)
214
+ response.raise_for_status()
215
+ return response.json()
216
+ except requests.exceptions.RequestException as e:
217
+ if e.response is not None:
218
+ if e.response.status_code == 429 or e.response.status_code >= 500:
219
+ raise DefaultBackoffException(request=e.response.request, response=e.response)
220
+ if self._wrap_refresh_token_exception(e):
221
+ message = "Refresh token is invalid or expired. Please re-authenticate from Sources/<your source>/Settings."
222
+ raise AirbyteTracedException(
223
+ internal_message=message, message=message, failure_type=FailureType.config_error
224
+ )
225
+ raise
226
+ except Exception as e:
227
+ raise Exception(f"Error while refreshing access token: {e}") from e
228
+
229
+ def _ensure_access_token_in_response(self, response_data: Mapping[str, Any]) -> None:
230
+ """
231
+ Ensures that the access token is present in the response data.
232
+
233
+ This method attempts to extract the access token from the provided response data.
234
+ If the access token is not found, it raises an exception indicating that the token
235
+ refresh API response was missing the access token. If the access token is found,
236
+ it adds the token to the list of secrets to ensure it is replaced before logging
237
+ the response.
238
+
239
+ Args:
240
+ response_data (Mapping[str, Any]): The response data from which to extract the access token.
241
+
242
+ Raises:
243
+ Exception: If the access token is not found in the response data.
244
+ ResponseKeysMaxRecurtionReached: If the maximum recursion depth is reached while extracting the access token.
245
+ """
246
+ try:
247
+ access_key = self._extract_access_token(response_data)
248
+ if not access_key:
249
+ raise Exception(
250
+ f"Token refresh API response was missing access token {self.get_access_token_name()}"
251
+ )
252
+ # Add the access token to the list of secrets so it is replaced before logging the response
253
+ # An argument could be made to remove the prevous access key from the list of secrets, but unmasking values seems like a security incident waiting to happen...
254
+ add_to_secrets(access_key)
255
+ except ResponseKeysMaxRecurtionReached as e:
256
+ raise e
257
+
258
+ def _parse_token_expiration_date(self, value: Union[str, int]) -> AirbyteDateTime:
259
+ """
260
+ Return the expiration datetime of the refresh token
261
+
262
+ :return: expiration datetime
263
+ """
264
+ if not value and not self.token_has_expired():
265
+ # No expiry token was provided but the previous one is not expired so it's fine
266
+ return self.get_token_expiry_date()
267
+
268
+ if self.token_expiry_is_time_of_expiration:
269
+ if not self.token_expiry_date_format:
270
+ raise ValueError(
271
+ f"Invalid token expiry date format {self.token_expiry_date_format}; a string representing the format is required."
272
+ )
273
+ try:
274
+ return ab_datetime_parse(str(value))
275
+ except ValueError as e:
276
+ raise ValueError(f"Invalid token expiry date format: {e}")
277
+ else:
278
+ try:
279
+ # Only accept numeric values (as int/float/string) when no format specified
280
+ seconds = int(float(str(value)))
281
+ return ab_datetime_now() + timedelta(seconds=seconds)
282
+ except (ValueError, TypeError):
283
+ raise ValueError(
284
+ f"Invalid expires_in value: {value}. Expected number of seconds when no format specified."
285
+ )
286
+
287
+ def _extract_access_token(self, response_data: Mapping[str, Any]) -> Any:
288
+ """
289
+ Extracts the access token from the given response data.
290
+
291
+ Args:
292
+ response_data (Mapping[str, Any]): The response data from which to extract the access token.
293
+
294
+ Returns:
295
+ str: The extracted access token.
296
+ """
297
+ return self._find_and_get_value_from_response(response_data, self.get_access_token_name())
298
+
299
+ def _extract_refresh_token(self, response_data: Mapping[str, Any]) -> Any:
300
+ """
301
+ Extracts the refresh token from the given response data.
302
+
303
+ Args:
304
+ response_data (Mapping[str, Any]): The response data from which to extract the refresh token.
305
+
306
+ Returns:
307
+ str: The extracted refresh token.
308
+ """
309
+ return self._find_and_get_value_from_response(response_data, self.get_refresh_token_name())
310
+
311
+ def _extract_token_expiry_date(self, response_data: Mapping[str, Any]) -> Any:
312
+ """
313
+ Extracts the token_expiry_date, like `expires_in` or `expires_at`, etc from the given response data.
314
+
315
+ Args:
316
+ response_data (Mapping[str, Any]): The response data from which to extract the token_expiry_date.
317
+
318
+ Returns:
319
+ str: The extracted token_expiry_date.
320
+ """
321
+ return self._find_and_get_value_from_response(response_data, self.get_expires_in_name())
322
+
323
+ def _find_and_get_value_from_response(
324
+ self,
325
+ response_data: Mapping[str, Any],
326
+ key_name: str,
327
+ max_depth: int = 5,
328
+ current_depth: int = 0,
329
+ ) -> Any:
330
+ """
331
+ Recursively searches for a specified key in a nested dictionary or list and returns its value if found.
332
+
333
+ Args:
334
+ response_data (Mapping[str, Any]): The response data to search through, which can be a dictionary or a list.
335
+ key_name (str): The key to search for in the response data.
336
+ max_depth (int, optional): The maximum depth to search for the key to avoid infinite recursion. Defaults to 5.
337
+ current_depth (int, optional): The current depth of the recursion. Defaults to 0.
338
+
339
+ Returns:
340
+ Any: The value associated with the specified key if found, otherwise None.
341
+
342
+ Raises:
343
+ AirbyteTracedException: If the maximum recursion depth is reached without finding the key.
344
+ """
345
+ if current_depth > max_depth:
346
+ # this is needed to avoid an inf loop, possible with a very deep nesting observed.
347
+ message = f"The maximum level of recursion is reached. Couldn't find the speficied `{key_name}` in the response."
348
+ raise ResponseKeysMaxRecurtionReached(
349
+ internal_message=message, message=message, failure_type=FailureType.config_error
350
+ )
351
+
352
+ if isinstance(response_data, dict):
353
+ # get from the root level
354
+ if key_name in response_data:
355
+ return response_data[key_name]
356
+
357
+ # get from the nested object
358
+ for _, value in response_data.items():
359
+ result = self._find_and_get_value_from_response(
360
+ value, key_name, max_depth, current_depth + 1
361
+ )
362
+ if result is not None:
363
+ return result
364
+
365
+ # get from the nested array object
366
+ elif isinstance(response_data, list):
367
+ for item in response_data:
368
+ result = self._find_and_get_value_from_response(
369
+ item, key_name, max_depth, current_depth + 1
370
+ )
371
+ if result is not None:
372
+ return result
373
+
374
+ return None
375
+
376
+ @property
377
+ def _message_repository(self) -> Optional[MessageRepository]:
378
+ """
379
+ The implementation can define a message_repository if it wants debugging logs for HTTP requests
380
+ """
381
+ return _NOOP_MESSAGE_REPOSITORY
382
+
383
+ def _log_response(self, response: requests.Response) -> None:
384
+ """
385
+ Logs the HTTP response using the message repository if it is available.
386
+
387
+ Args:
388
+ response (requests.Response): The HTTP response to log.
389
+ """
390
+ if self._message_repository:
391
+ self._message_repository.log_message(
392
+ Level.DEBUG,
393
+ lambda: format_http_message(
394
+ response,
395
+ "Refresh token",
396
+ "Obtains access token",
397
+ self._NO_STREAM_NAME,
398
+ is_auxiliary=True,
399
+ type="AUTH",
400
+ ),
401
+ )
402
+
403
+ # ----------------
404
+ # ABSTR METHODS
405
+ # ----------------
406
+
407
+ @abstractmethod
408
+ def get_token_refresh_endpoint(self) -> Optional[str]:
409
+ """Returns the endpoint to refresh the access token"""
410
+
411
+ @abstractmethod
412
+ def get_client_id_name(self) -> str:
413
+ """The client id name to authenticate"""
414
+
415
+ @abstractmethod
416
+ def get_client_id(self) -> str:
417
+ """The client id to authenticate"""
418
+
419
+ @abstractmethod
420
+ def get_client_secret_name(self) -> str:
421
+ """The client secret name to authenticate"""
422
+
423
+ @abstractmethod
424
+ def get_client_secret(self) -> str:
425
+ """The client secret to authenticate"""
426
+
427
+ @abstractmethod
428
+ def get_refresh_token_name(self) -> str:
429
+ """The refresh token name to authenticate"""
430
+
431
+ @abstractmethod
432
+ def get_refresh_token(self) -> Optional[str]:
433
+ """The token used to refresh the access token when it expires"""
434
+
435
+ @abstractmethod
436
+ def get_scopes(self) -> List[str]:
437
+ """List of requested scopes"""
438
+
439
+ @abstractmethod
440
+ def get_token_expiry_date(self) -> AirbyteDateTime:
441
+ """Expiration date of the access token"""
442
+
443
+ @abstractmethod
444
+ def set_token_expiry_date(self, value: Union[str, int]) -> None:
445
+ """Setter for access token expiration date"""
446
+
447
+ @abstractmethod
448
+ def get_access_token_name(self) -> str:
449
+ """Field to extract access token from in the response"""
450
+
451
+ @abstractmethod
452
+ def get_expires_in_name(self) -> str:
453
+ """Returns the expires_in field name"""
454
+
455
+ @abstractmethod
456
+ def get_refresh_request_body(self) -> Mapping[str, Any]:
457
+ """Returns the request body to set on the refresh request"""
458
+
459
+ @abstractmethod
460
+ def get_refresh_request_headers(self) -> Mapping[str, Any]:
461
+ """Returns the request headers to set on the refresh request"""
462
+
463
+ @abstractmethod
464
+ def get_grant_type(self) -> str:
465
+ """Returns grant_type specified for requesting access_token"""
466
+
467
+ @abstractmethod
468
+ def get_grant_type_name(self) -> str:
469
+ """Returns grant_type specified name for requesting access_token"""
470
+
471
+ @property
472
+ @abstractmethod
473
+ def access_token(self) -> str:
474
+ """Returns the access token"""
475
+
476
+ @access_token.setter
477
+ @abstractmethod
478
+ def access_token(self, value: str) -> str:
479
+ """Setter for the access token"""
@@ -0,0 +1,34 @@
1
+ #
2
+ # Copyright (c) 2023 Airbyte, Inc., all rights reserved.
3
+ #
4
+
5
+ from abc import abstractmethod
6
+ from typing import Any, Mapping
7
+
8
+ import requests
9
+ from requests.auth import AuthBase
10
+
11
+
12
+ class AbstractHeaderAuthenticator(AuthBase):
13
+ """Abstract class for an header-based authenticators that add a header to outgoing HTTP requests."""
14
+
15
+ def __call__(self, request: requests.PreparedRequest) -> Any:
16
+ """Attach the HTTP headers required to authenticate on the HTTP request"""
17
+ request.headers.update(self.get_auth_header())
18
+ return request
19
+
20
+ def get_auth_header(self) -> Mapping[str, Any]:
21
+ """The header to set on outgoing HTTP requests"""
22
+ if self.auth_header:
23
+ return {self.auth_header: self.token}
24
+ return {}
25
+
26
+ @property
27
+ @abstractmethod
28
+ def auth_header(self) -> str:
29
+ """HTTP header to set on the requests"""
30
+
31
+ @property
32
+ @abstractmethod
33
+ def token(self) -> str:
34
+ """The header value to set on outgoing HTTP requests"""