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.
- airbyte_cdk/__init__.py +358 -0
- airbyte_cdk/cli/__init__.py +1 -0
- airbyte_cdk/cli/source_declarative_manifest/__init__.py +5 -0
- airbyte_cdk/cli/source_declarative_manifest/_run.py +236 -0
- airbyte_cdk/cli/source_declarative_manifest/spec.json +17 -0
- airbyte_cdk/config_observation.py +104 -0
- airbyte_cdk/connector.py +123 -0
- airbyte_cdk/connector_builder/README.md +53 -0
- airbyte_cdk/connector_builder/__init__.py +3 -0
- airbyte_cdk/connector_builder/connector_builder_handler.py +121 -0
- airbyte_cdk/connector_builder/main.py +107 -0
- airbyte_cdk/connector_builder/models.py +73 -0
- airbyte_cdk/connector_builder/test_reader/__init__.py +7 -0
- airbyte_cdk/connector_builder/test_reader/helpers.py +689 -0
- airbyte_cdk/connector_builder/test_reader/message_grouper.py +173 -0
- airbyte_cdk/connector_builder/test_reader/reader.py +441 -0
- airbyte_cdk/connector_builder/test_reader/types.py +83 -0
- airbyte_cdk/destinations/__init__.py +8 -0
- airbyte_cdk/destinations/destination.py +154 -0
- airbyte_cdk/destinations/vector_db_based/README.md +37 -0
- airbyte_cdk/destinations/vector_db_based/__init__.py +38 -0
- airbyte_cdk/destinations/vector_db_based/config.py +298 -0
- airbyte_cdk/destinations/vector_db_based/document_processor.py +223 -0
- airbyte_cdk/destinations/vector_db_based/embedder.py +303 -0
- airbyte_cdk/destinations/vector_db_based/indexer.py +78 -0
- airbyte_cdk/destinations/vector_db_based/test_utils.py +63 -0
- airbyte_cdk/destinations/vector_db_based/utils.py +35 -0
- airbyte_cdk/destinations/vector_db_based/writer.py +104 -0
- airbyte_cdk/entrypoint.py +414 -0
- airbyte_cdk/exception_handler.py +56 -0
- airbyte_cdk/logger.py +109 -0
- airbyte_cdk/models/__init__.py +72 -0
- airbyte_cdk/models/airbyte_protocol.py +88 -0
- airbyte_cdk/models/airbyte_protocol_serializers.py +44 -0
- airbyte_cdk/models/well_known_types.py +5 -0
- airbyte_cdk/py.typed +0 -0
- airbyte_cdk/sources/__init__.py +26 -0
- airbyte_cdk/sources/abstract_source.py +326 -0
- airbyte_cdk/sources/concurrent_source/__init__.py +8 -0
- airbyte_cdk/sources/concurrent_source/concurrent_read_processor.py +255 -0
- airbyte_cdk/sources/concurrent_source/concurrent_source.py +165 -0
- airbyte_cdk/sources/concurrent_source/concurrent_source_adapter.py +147 -0
- airbyte_cdk/sources/concurrent_source/partition_generation_completed_sentinel.py +24 -0
- airbyte_cdk/sources/concurrent_source/stream_thread_exception.py +25 -0
- airbyte_cdk/sources/concurrent_source/thread_pool_manager.py +115 -0
- airbyte_cdk/sources/config.py +27 -0
- airbyte_cdk/sources/connector_state_manager.py +161 -0
- airbyte_cdk/sources/declarative/__init__.py +3 -0
- airbyte_cdk/sources/declarative/async_job/__init__.py +0 -0
- airbyte_cdk/sources/declarative/async_job/job.py +52 -0
- airbyte_cdk/sources/declarative/async_job/job_orchestrator.py +525 -0
- airbyte_cdk/sources/declarative/async_job/job_tracker.py +79 -0
- airbyte_cdk/sources/declarative/async_job/repository.py +35 -0
- airbyte_cdk/sources/declarative/async_job/status.py +24 -0
- airbyte_cdk/sources/declarative/async_job/timer.py +39 -0
- airbyte_cdk/sources/declarative/auth/__init__.py +8 -0
- airbyte_cdk/sources/declarative/auth/declarative_authenticator.py +42 -0
- airbyte_cdk/sources/declarative/auth/jwt.py +197 -0
- airbyte_cdk/sources/declarative/auth/oauth.py +293 -0
- airbyte_cdk/sources/declarative/auth/selective_authenticator.py +45 -0
- airbyte_cdk/sources/declarative/auth/token.py +267 -0
- airbyte_cdk/sources/declarative/auth/token_provider.py +82 -0
- airbyte_cdk/sources/declarative/checks/__init__.py +24 -0
- airbyte_cdk/sources/declarative/checks/check_dynamic_stream.py +61 -0
- airbyte_cdk/sources/declarative/checks/check_stream.py +56 -0
- airbyte_cdk/sources/declarative/checks/connection_checker.py +35 -0
- airbyte_cdk/sources/declarative/concurrency_level/__init__.py +7 -0
- airbyte_cdk/sources/declarative/concurrency_level/concurrency_level.py +50 -0
- airbyte_cdk/sources/declarative/concurrent_declarative_source.py +526 -0
- airbyte_cdk/sources/declarative/datetime/__init__.py +3 -0
- airbyte_cdk/sources/declarative/datetime/datetime_parser.py +65 -0
- airbyte_cdk/sources/declarative/datetime/min_max_datetime.py +118 -0
- airbyte_cdk/sources/declarative/declarative_component_schema.yaml +3975 -0
- airbyte_cdk/sources/declarative/declarative_source.py +36 -0
- airbyte_cdk/sources/declarative/declarative_stream.py +241 -0
- airbyte_cdk/sources/declarative/decoders/__init__.py +33 -0
- airbyte_cdk/sources/declarative/decoders/composite_raw_decoder.py +218 -0
- airbyte_cdk/sources/declarative/decoders/decoder.py +32 -0
- airbyte_cdk/sources/declarative/decoders/decoder_parser.py +30 -0
- airbyte_cdk/sources/declarative/decoders/json_decoder.py +65 -0
- airbyte_cdk/sources/declarative/decoders/noop_decoder.py +21 -0
- airbyte_cdk/sources/declarative/decoders/pagination_decoder_decorator.py +39 -0
- airbyte_cdk/sources/declarative/decoders/xml_decoder.py +98 -0
- airbyte_cdk/sources/declarative/decoders/zipfile_decoder.py +56 -0
- airbyte_cdk/sources/declarative/exceptions.py +9 -0
- airbyte_cdk/sources/declarative/extractors/__init__.py +21 -0
- airbyte_cdk/sources/declarative/extractors/dpath_extractor.py +86 -0
- airbyte_cdk/sources/declarative/extractors/http_selector.py +37 -0
- airbyte_cdk/sources/declarative/extractors/record_extractor.py +27 -0
- airbyte_cdk/sources/declarative/extractors/record_filter.py +91 -0
- airbyte_cdk/sources/declarative/extractors/record_selector.py +170 -0
- airbyte_cdk/sources/declarative/extractors/response_to_file_extractor.py +176 -0
- airbyte_cdk/sources/declarative/extractors/type_transformer.py +55 -0
- airbyte_cdk/sources/declarative/incremental/__init__.py +37 -0
- airbyte_cdk/sources/declarative/incremental/concurrent_partition_cursor.py +497 -0
- airbyte_cdk/sources/declarative/incremental/datetime_based_cursor.py +459 -0
- airbyte_cdk/sources/declarative/incremental/declarative_cursor.py +13 -0
- airbyte_cdk/sources/declarative/incremental/global_substream_cursor.py +357 -0
- airbyte_cdk/sources/declarative/incremental/per_partition_cursor.py +380 -0
- airbyte_cdk/sources/declarative/incremental/per_partition_with_global.py +200 -0
- airbyte_cdk/sources/declarative/incremental/resumable_full_refresh_cursor.py +122 -0
- airbyte_cdk/sources/declarative/interpolation/__init__.py +9 -0
- airbyte_cdk/sources/declarative/interpolation/filters.py +139 -0
- airbyte_cdk/sources/declarative/interpolation/interpolated_boolean.py +66 -0
- airbyte_cdk/sources/declarative/interpolation/interpolated_mapping.py +56 -0
- airbyte_cdk/sources/declarative/interpolation/interpolated_nested_mapping.py +52 -0
- airbyte_cdk/sources/declarative/interpolation/interpolated_string.py +79 -0
- airbyte_cdk/sources/declarative/interpolation/interpolation.py +34 -0
- airbyte_cdk/sources/declarative/interpolation/jinja.py +161 -0
- airbyte_cdk/sources/declarative/interpolation/macros.py +191 -0
- airbyte_cdk/sources/declarative/manifest_declarative_source.py +421 -0
- airbyte_cdk/sources/declarative/migrations/__init__.py +0 -0
- airbyte_cdk/sources/declarative/migrations/legacy_to_per_partition_state_migration.py +98 -0
- airbyte_cdk/sources/declarative/migrations/state_migration.py +24 -0
- airbyte_cdk/sources/declarative/models/__init__.py +2 -0
- airbyte_cdk/sources/declarative/models/declarative_component_schema.py +2503 -0
- airbyte_cdk/sources/declarative/parsers/__init__.py +3 -0
- airbyte_cdk/sources/declarative/parsers/custom_code_compiler.py +157 -0
- airbyte_cdk/sources/declarative/parsers/custom_exceptions.py +21 -0
- airbyte_cdk/sources/declarative/parsers/manifest_component_transformer.py +172 -0
- airbyte_cdk/sources/declarative/parsers/manifest_reference_resolver.py +213 -0
- airbyte_cdk/sources/declarative/parsers/model_to_component_factory.py +3407 -0
- airbyte_cdk/sources/declarative/partition_routers/__init__.py +29 -0
- airbyte_cdk/sources/declarative/partition_routers/async_job_partition_router.py +65 -0
- airbyte_cdk/sources/declarative/partition_routers/cartesian_product_stream_slicer.py +176 -0
- airbyte_cdk/sources/declarative/partition_routers/list_partition_router.py +121 -0
- airbyte_cdk/sources/declarative/partition_routers/partition_router.py +62 -0
- airbyte_cdk/sources/declarative/partition_routers/single_partition_router.py +63 -0
- airbyte_cdk/sources/declarative/partition_routers/substream_partition_router.py +437 -0
- airbyte_cdk/sources/declarative/requesters/README.md +56 -0
- airbyte_cdk/sources/declarative/requesters/__init__.py +9 -0
- airbyte_cdk/sources/declarative/requesters/error_handlers/__init__.py +25 -0
- airbyte_cdk/sources/declarative/requesters/error_handlers/backoff_strategies/__init__.py +23 -0
- airbyte_cdk/sources/declarative/requesters/error_handlers/backoff_strategies/constant_backoff_strategy.py +45 -0
- airbyte_cdk/sources/declarative/requesters/error_handlers/backoff_strategies/exponential_backoff_strategy.py +45 -0
- airbyte_cdk/sources/declarative/requesters/error_handlers/backoff_strategies/header_helper.py +41 -0
- airbyte_cdk/sources/declarative/requesters/error_handlers/backoff_strategies/wait_time_from_header_backoff_strategy.py +70 -0
- airbyte_cdk/sources/declarative/requesters/error_handlers/backoff_strategies/wait_until_time_from_header_backoff_strategy.py +77 -0
- airbyte_cdk/sources/declarative/requesters/error_handlers/backoff_strategy.py +17 -0
- airbyte_cdk/sources/declarative/requesters/error_handlers/composite_error_handler.py +101 -0
- airbyte_cdk/sources/declarative/requesters/error_handlers/default_error_handler.py +147 -0
- airbyte_cdk/sources/declarative/requesters/error_handlers/default_http_response_filter.py +40 -0
- airbyte_cdk/sources/declarative/requesters/error_handlers/error_handler.py +17 -0
- airbyte_cdk/sources/declarative/requesters/error_handlers/http_response_filter.py +179 -0
- airbyte_cdk/sources/declarative/requesters/http_job_repository.py +350 -0
- airbyte_cdk/sources/declarative/requesters/http_requester.py +433 -0
- airbyte_cdk/sources/declarative/requesters/paginators/__init__.py +21 -0
- airbyte_cdk/sources/declarative/requesters/paginators/default_paginator.py +327 -0
- airbyte_cdk/sources/declarative/requesters/paginators/no_pagination.py +76 -0
- airbyte_cdk/sources/declarative/requesters/paginators/paginator.py +65 -0
- airbyte_cdk/sources/declarative/requesters/paginators/strategies/__init__.py +25 -0
- airbyte_cdk/sources/declarative/requesters/paginators/strategies/cursor_pagination_strategy.py +98 -0
- airbyte_cdk/sources/declarative/requesters/paginators/strategies/offset_increment.py +102 -0
- airbyte_cdk/sources/declarative/requesters/paginators/strategies/page_increment.py +71 -0
- airbyte_cdk/sources/declarative/requesters/paginators/strategies/pagination_strategy.py +48 -0
- airbyte_cdk/sources/declarative/requesters/paginators/strategies/stop_condition.py +66 -0
- airbyte_cdk/sources/declarative/requesters/request_option.py +117 -0
- airbyte_cdk/sources/declarative/requesters/request_options/__init__.py +23 -0
- airbyte_cdk/sources/declarative/requesters/request_options/datetime_based_request_options_provider.py +92 -0
- airbyte_cdk/sources/declarative/requesters/request_options/default_request_options_provider.py +60 -0
- airbyte_cdk/sources/declarative/requesters/request_options/interpolated_nested_request_input_provider.py +59 -0
- airbyte_cdk/sources/declarative/requesters/request_options/interpolated_request_input_provider.py +68 -0
- airbyte_cdk/sources/declarative/requesters/request_options/interpolated_request_options_provider.py +119 -0
- airbyte_cdk/sources/declarative/requesters/request_options/request_options_provider.py +79 -0
- airbyte_cdk/sources/declarative/requesters/request_path.py +15 -0
- airbyte_cdk/sources/declarative/requesters/requester.py +144 -0
- airbyte_cdk/sources/declarative/resolvers/__init__.py +41 -0
- airbyte_cdk/sources/declarative/resolvers/components_resolver.py +55 -0
- airbyte_cdk/sources/declarative/resolvers/config_components_resolver.py +136 -0
- airbyte_cdk/sources/declarative/resolvers/http_components_resolver.py +112 -0
- airbyte_cdk/sources/declarative/retrievers/__init__.py +19 -0
- airbyte_cdk/sources/declarative/retrievers/async_retriever.py +124 -0
- airbyte_cdk/sources/declarative/retrievers/file_uploader.py +89 -0
- airbyte_cdk/sources/declarative/retrievers/retriever.py +54 -0
- airbyte_cdk/sources/declarative/retrievers/simple_retriever.py +702 -0
- airbyte_cdk/sources/declarative/schema/__init__.py +25 -0
- airbyte_cdk/sources/declarative/schema/default_schema_loader.py +47 -0
- airbyte_cdk/sources/declarative/schema/dynamic_schema_loader.py +285 -0
- airbyte_cdk/sources/declarative/schema/inline_schema_loader.py +19 -0
- airbyte_cdk/sources/declarative/schema/json_file_schema_loader.py +92 -0
- airbyte_cdk/sources/declarative/schema/schema_loader.py +17 -0
- airbyte_cdk/sources/declarative/spec/__init__.py +7 -0
- airbyte_cdk/sources/declarative/spec/spec.py +48 -0
- airbyte_cdk/sources/declarative/stream_slicers/__init__.py +7 -0
- airbyte_cdk/sources/declarative/stream_slicers/declarative_partition_generator.py +93 -0
- airbyte_cdk/sources/declarative/stream_slicers/stream_slicer.py +25 -0
- airbyte_cdk/sources/declarative/transformations/__init__.py +17 -0
- airbyte_cdk/sources/declarative/transformations/add_fields.py +146 -0
- airbyte_cdk/sources/declarative/transformations/dpath_flatten_fields.py +61 -0
- airbyte_cdk/sources/declarative/transformations/flatten_fields.py +52 -0
- airbyte_cdk/sources/declarative/transformations/keys_replace_transformation.py +61 -0
- airbyte_cdk/sources/declarative/transformations/keys_to_lower_transformation.py +22 -0
- airbyte_cdk/sources/declarative/transformations/keys_to_snake_transformation.py +68 -0
- airbyte_cdk/sources/declarative/transformations/remove_fields.py +75 -0
- airbyte_cdk/sources/declarative/transformations/transformation.py +37 -0
- airbyte_cdk/sources/declarative/types.py +25 -0
- airbyte_cdk/sources/declarative/yaml_declarative_source.py +67 -0
- airbyte_cdk/sources/file_based/README.md +152 -0
- airbyte_cdk/sources/file_based/__init__.py +24 -0
- airbyte_cdk/sources/file_based/availability_strategy/__init__.py +11 -0
- airbyte_cdk/sources/file_based/availability_strategy/abstract_file_based_availability_strategy.py +73 -0
- airbyte_cdk/sources/file_based/availability_strategy/default_file_based_availability_strategy.py +149 -0
- airbyte_cdk/sources/file_based/config/__init__.py +0 -0
- airbyte_cdk/sources/file_based/config/abstract_file_based_spec.py +153 -0
- airbyte_cdk/sources/file_based/config/avro_format.py +25 -0
- airbyte_cdk/sources/file_based/config/csv_format.py +210 -0
- airbyte_cdk/sources/file_based/config/excel_format.py +18 -0
- airbyte_cdk/sources/file_based/config/file_based_stream_config.py +99 -0
- airbyte_cdk/sources/file_based/config/jsonl_format.py +18 -0
- airbyte_cdk/sources/file_based/config/parquet_format.py +25 -0
- airbyte_cdk/sources/file_based/config/unstructured_format.py +102 -0
- airbyte_cdk/sources/file_based/config/validate_config_transfer_modes.py +81 -0
- airbyte_cdk/sources/file_based/discovery_policy/__init__.py +8 -0
- airbyte_cdk/sources/file_based/discovery_policy/abstract_discovery_policy.py +21 -0
- airbyte_cdk/sources/file_based/discovery_policy/default_discovery_policy.py +33 -0
- airbyte_cdk/sources/file_based/exceptions.py +159 -0
- airbyte_cdk/sources/file_based/file_based_source.py +466 -0
- airbyte_cdk/sources/file_based/file_based_stream_permissions_reader.py +123 -0
- airbyte_cdk/sources/file_based/file_based_stream_reader.py +209 -0
- airbyte_cdk/sources/file_based/file_record_data.py +22 -0
- airbyte_cdk/sources/file_based/file_types/__init__.py +37 -0
- airbyte_cdk/sources/file_based/file_types/avro_parser.py +233 -0
- airbyte_cdk/sources/file_based/file_types/csv_parser.py +527 -0
- airbyte_cdk/sources/file_based/file_types/excel_parser.py +196 -0
- airbyte_cdk/sources/file_based/file_types/file_transfer.py +30 -0
- airbyte_cdk/sources/file_based/file_types/file_type_parser.py +86 -0
- airbyte_cdk/sources/file_based/file_types/jsonl_parser.py +145 -0
- airbyte_cdk/sources/file_based/file_types/parquet_parser.py +275 -0
- airbyte_cdk/sources/file_based/file_types/unstructured_parser.py +480 -0
- airbyte_cdk/sources/file_based/remote_file.py +18 -0
- airbyte_cdk/sources/file_based/schema_helpers.py +281 -0
- airbyte_cdk/sources/file_based/schema_validation_policies/__init__.py +17 -0
- airbyte_cdk/sources/file_based/schema_validation_policies/abstract_schema_validation_policy.py +20 -0
- airbyte_cdk/sources/file_based/schema_validation_policies/default_schema_validation_policies.py +52 -0
- airbyte_cdk/sources/file_based/stream/__init__.py +13 -0
- airbyte_cdk/sources/file_based/stream/abstract_file_based_stream.py +197 -0
- airbyte_cdk/sources/file_based/stream/concurrent/__init__.py +0 -0
- airbyte_cdk/sources/file_based/stream/concurrent/adapters.py +343 -0
- airbyte_cdk/sources/file_based/stream/concurrent/cursor/__init__.py +9 -0
- airbyte_cdk/sources/file_based/stream/concurrent/cursor/abstract_concurrent_file_based_cursor.py +59 -0
- airbyte_cdk/sources/file_based/stream/concurrent/cursor/file_based_concurrent_cursor.py +313 -0
- airbyte_cdk/sources/file_based/stream/concurrent/cursor/file_based_final_state_cursor.py +83 -0
- airbyte_cdk/sources/file_based/stream/cursor/__init__.py +4 -0
- airbyte_cdk/sources/file_based/stream/cursor/abstract_file_based_cursor.py +66 -0
- airbyte_cdk/sources/file_based/stream/cursor/default_file_based_cursor.py +149 -0
- airbyte_cdk/sources/file_based/stream/default_file_based_stream.py +396 -0
- airbyte_cdk/sources/file_based/stream/identities_stream.py +49 -0
- airbyte_cdk/sources/file_based/stream/permissions_file_based_stream.py +92 -0
- airbyte_cdk/sources/file_based/types.py +10 -0
- airbyte_cdk/sources/http_config.py +10 -0
- airbyte_cdk/sources/http_logger.py +55 -0
- airbyte_cdk/sources/message/__init__.py +19 -0
- airbyte_cdk/sources/message/repository.py +137 -0
- airbyte_cdk/sources/source.py +95 -0
- airbyte_cdk/sources/specs/transfer_modes.py +26 -0
- airbyte_cdk/sources/streams/__init__.py +8 -0
- airbyte_cdk/sources/streams/availability_strategy.py +84 -0
- airbyte_cdk/sources/streams/call_rate.py +704 -0
- airbyte_cdk/sources/streams/checkpoint/__init__.py +26 -0
- airbyte_cdk/sources/streams/checkpoint/checkpoint_reader.py +335 -0
- airbyte_cdk/sources/streams/checkpoint/cursor.py +77 -0
- airbyte_cdk/sources/streams/checkpoint/per_partition_key_serializer.py +22 -0
- airbyte_cdk/sources/streams/checkpoint/resumable_full_refresh_cursor.py +51 -0
- airbyte_cdk/sources/streams/checkpoint/substream_resumable_full_refresh_cursor.py +110 -0
- airbyte_cdk/sources/streams/concurrent/README.md +7 -0
- airbyte_cdk/sources/streams/concurrent/__init__.py +3 -0
- airbyte_cdk/sources/streams/concurrent/abstract_stream.py +96 -0
- airbyte_cdk/sources/streams/concurrent/abstract_stream_facade.py +37 -0
- airbyte_cdk/sources/streams/concurrent/adapters.py +397 -0
- airbyte_cdk/sources/streams/concurrent/availability_strategy.py +94 -0
- airbyte_cdk/sources/streams/concurrent/clamping.py +99 -0
- airbyte_cdk/sources/streams/concurrent/cursor.py +481 -0
- airbyte_cdk/sources/streams/concurrent/cursor_types.py +32 -0
- airbyte_cdk/sources/streams/concurrent/default_stream.py +102 -0
- airbyte_cdk/sources/streams/concurrent/exceptions.py +18 -0
- airbyte_cdk/sources/streams/concurrent/helpers.py +42 -0
- airbyte_cdk/sources/streams/concurrent/partition_enqueuer.py +64 -0
- airbyte_cdk/sources/streams/concurrent/partition_reader.py +45 -0
- airbyte_cdk/sources/streams/concurrent/partitions/__init__.py +3 -0
- airbyte_cdk/sources/streams/concurrent/partitions/partition.py +48 -0
- airbyte_cdk/sources/streams/concurrent/partitions/partition_generator.py +18 -0
- airbyte_cdk/sources/streams/concurrent/partitions/stream_slicer.py +21 -0
- airbyte_cdk/sources/streams/concurrent/partitions/types.py +38 -0
- airbyte_cdk/sources/streams/concurrent/state_converters/__init__.py +0 -0
- airbyte_cdk/sources/streams/concurrent/state_converters/abstract_stream_state_converter.py +182 -0
- airbyte_cdk/sources/streams/concurrent/state_converters/datetime_stream_state_converter.py +223 -0
- airbyte_cdk/sources/streams/concurrent/state_converters/incrementing_count_stream_state_converter.py +92 -0
- airbyte_cdk/sources/streams/core.py +703 -0
- airbyte_cdk/sources/streams/http/__init__.py +10 -0
- airbyte_cdk/sources/streams/http/availability_strategy.py +54 -0
- airbyte_cdk/sources/streams/http/error_handlers/__init__.py +22 -0
- airbyte_cdk/sources/streams/http/error_handlers/backoff_strategy.py +28 -0
- airbyte_cdk/sources/streams/http/error_handlers/default_backoff_strategy.py +17 -0
- airbyte_cdk/sources/streams/http/error_handlers/default_error_mapping.py +86 -0
- airbyte_cdk/sources/streams/http/error_handlers/error_handler.py +42 -0
- airbyte_cdk/sources/streams/http/error_handlers/error_message_parser.py +19 -0
- airbyte_cdk/sources/streams/http/error_handlers/http_status_error_handler.py +110 -0
- airbyte_cdk/sources/streams/http/error_handlers/json_error_message_parser.py +52 -0
- airbyte_cdk/sources/streams/http/error_handlers/response_models.py +65 -0
- airbyte_cdk/sources/streams/http/exceptions.py +61 -0
- airbyte_cdk/sources/streams/http/http.py +673 -0
- airbyte_cdk/sources/streams/http/http_client.py +531 -0
- airbyte_cdk/sources/streams/http/rate_limiting.py +158 -0
- airbyte_cdk/sources/streams/http/requests_native_auth/__init__.py +14 -0
- airbyte_cdk/sources/streams/http/requests_native_auth/abstract_oauth.py +479 -0
- airbyte_cdk/sources/streams/http/requests_native_auth/abstract_token.py +34 -0
- airbyte_cdk/sources/streams/http/requests_native_auth/oauth.py +436 -0
- airbyte_cdk/sources/streams/http/requests_native_auth/token.py +83 -0
- airbyte_cdk/sources/streams/permissions/identities_stream.py +75 -0
- airbyte_cdk/sources/streams/utils/__init__.py +3 -0
- airbyte_cdk/sources/types.py +169 -0
- airbyte_cdk/sources/utils/__init__.py +7 -0
- airbyte_cdk/sources/utils/casing.py +12 -0
- airbyte_cdk/sources/utils/files_directory.py +15 -0
- airbyte_cdk/sources/utils/record_helper.py +53 -0
- airbyte_cdk/sources/utils/schema_helpers.py +230 -0
- airbyte_cdk/sources/utils/slice_logger.py +57 -0
- airbyte_cdk/sources/utils/transform.py +277 -0
- airbyte_cdk/sources/utils/types.py +7 -0
- airbyte_cdk/sql/__init__.py +0 -0
- airbyte_cdk/sql/_util/__init__.py +0 -0
- airbyte_cdk/sql/_util/hashing.py +34 -0
- airbyte_cdk/sql/_util/name_normalizers.py +92 -0
- airbyte_cdk/sql/constants.py +32 -0
- airbyte_cdk/sql/exceptions.py +235 -0
- airbyte_cdk/sql/secrets.py +123 -0
- airbyte_cdk/sql/shared/__init__.py +15 -0
- airbyte_cdk/sql/shared/catalog_providers.py +145 -0
- airbyte_cdk/sql/shared/sql_processor.py +786 -0
- airbyte_cdk/sql/types.py +160 -0
- airbyte_cdk/test/__init__.py +7 -0
- airbyte_cdk/test/catalog_builder.py +81 -0
- airbyte_cdk/test/entrypoint_wrapper.py +250 -0
- airbyte_cdk/test/mock_http/__init__.py +6 -0
- airbyte_cdk/test/mock_http/matcher.py +41 -0
- airbyte_cdk/test/mock_http/mocker.py +185 -0
- airbyte_cdk/test/mock_http/request.py +103 -0
- airbyte_cdk/test/mock_http/response.py +28 -0
- airbyte_cdk/test/mock_http/response_builder.py +237 -0
- airbyte_cdk/test/state_builder.py +33 -0
- airbyte_cdk/test/utils/__init__.py +1 -0
- airbyte_cdk/test/utils/data.py +24 -0
- airbyte_cdk/test/utils/http_mocking.py +16 -0
- airbyte_cdk/test/utils/manifest_only_fixtures.py +59 -0
- airbyte_cdk/test/utils/reading.py +26 -0
- airbyte_cdk/utils/__init__.py +10 -0
- airbyte_cdk/utils/airbyte_secrets_utils.py +80 -0
- airbyte_cdk/utils/analytics_message.py +25 -0
- airbyte_cdk/utils/constants.py +5 -0
- airbyte_cdk/utils/datetime_format_inferrer.py +94 -0
- airbyte_cdk/utils/datetime_helpers.py +499 -0
- airbyte_cdk/utils/event_timing.py +85 -0
- airbyte_cdk/utils/is_cloud_environment.py +18 -0
- airbyte_cdk/utils/mapping_helpers.py +162 -0
- airbyte_cdk/utils/message_utils.py +26 -0
- airbyte_cdk/utils/oneof_option_config.py +33 -0
- airbyte_cdk/utils/print_buffer.py +75 -0
- airbyte_cdk/utils/schema_inferrer.py +270 -0
- airbyte_cdk/utils/slice_hasher.py +37 -0
- airbyte_cdk/utils/spec_schema_transformations.py +26 -0
- airbyte_cdk/utils/stream_status_utils.py +43 -0
- airbyte_cdk/utils/traced_exception.py +145 -0
- airbyte_cdk-0.0.0.dev0.dist-info/LICENSE.txt +19 -0
- airbyte_cdk-0.0.0.dev0.dist-info/LICENSE_SHORT +1 -0
- airbyte_cdk-0.0.0.dev0.dist-info/METADATA +111 -0
- airbyte_cdk-0.0.0.dev0.dist-info/RECORD +368 -0
- airbyte_cdk-0.0.0.dev0.dist-info/WHEEL +4 -0
- airbyte_cdk-0.0.0.dev0.dist-info/entry_points.txt +3 -0
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Copyright (c) 2023 Airbyte, Inc., all rights reserved.
|
|
3
|
+
#
|
|
4
|
+
|
|
5
|
+
import numbers
|
|
6
|
+
from re import Pattern
|
|
7
|
+
from typing import Optional
|
|
8
|
+
|
|
9
|
+
import requests
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def get_numeric_value_from_header(
|
|
13
|
+
response: requests.Response, header: str, regex: Optional[Pattern[str]]
|
|
14
|
+
) -> Optional[float]:
|
|
15
|
+
"""
|
|
16
|
+
Extract a header value from the response as a float
|
|
17
|
+
:param response: response the extract header value from
|
|
18
|
+
:param header: Header to extract
|
|
19
|
+
:param regex: optional regex to apply on the header to obtain the value
|
|
20
|
+
:return: header value as float if it's a number. None otherwise
|
|
21
|
+
"""
|
|
22
|
+
header_value = response.headers.get(header, None)
|
|
23
|
+
if not header_value:
|
|
24
|
+
return None
|
|
25
|
+
if isinstance(header_value, str):
|
|
26
|
+
if regex:
|
|
27
|
+
match = regex.match(header_value)
|
|
28
|
+
if match:
|
|
29
|
+
header_value = match.group()
|
|
30
|
+
return _as_float(header_value)
|
|
31
|
+
elif isinstance(header_value, numbers.Number):
|
|
32
|
+
return float(header_value) # type: ignore[arg-type]
|
|
33
|
+
else:
|
|
34
|
+
return None
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def _as_float(s: str) -> Optional[float]:
|
|
38
|
+
try:
|
|
39
|
+
return float(s)
|
|
40
|
+
except ValueError:
|
|
41
|
+
return None
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Copyright (c) 2023 Airbyte, Inc., all rights reserved.
|
|
3
|
+
#
|
|
4
|
+
|
|
5
|
+
import re
|
|
6
|
+
from dataclasses import InitVar, dataclass
|
|
7
|
+
from typing import Any, Mapping, Optional, Union
|
|
8
|
+
|
|
9
|
+
import requests
|
|
10
|
+
|
|
11
|
+
from airbyte_cdk.models import FailureType
|
|
12
|
+
from airbyte_cdk.sources.declarative.interpolation.interpolated_string import InterpolatedString
|
|
13
|
+
from airbyte_cdk.sources.declarative.requesters.error_handlers.backoff_strategies.header_helper import (
|
|
14
|
+
get_numeric_value_from_header,
|
|
15
|
+
)
|
|
16
|
+
from airbyte_cdk.sources.declarative.requesters.error_handlers.backoff_strategy import (
|
|
17
|
+
BackoffStrategy,
|
|
18
|
+
)
|
|
19
|
+
from airbyte_cdk.sources.types import Config
|
|
20
|
+
from airbyte_cdk.utils import AirbyteTracedException
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
@dataclass
|
|
24
|
+
class WaitTimeFromHeaderBackoffStrategy(BackoffStrategy):
|
|
25
|
+
"""
|
|
26
|
+
Extract wait time from http header
|
|
27
|
+
|
|
28
|
+
Attributes:
|
|
29
|
+
header (str): header to read wait time from
|
|
30
|
+
regex (Optional[str]): optional regex to apply on the header to extract its value
|
|
31
|
+
max_waiting_time_in_seconds: (Optional[float]): given the value extracted from the header is greater than this value, stop the stream
|
|
32
|
+
"""
|
|
33
|
+
|
|
34
|
+
header: Union[InterpolatedString, str]
|
|
35
|
+
parameters: InitVar[Mapping[str, Any]]
|
|
36
|
+
config: Config
|
|
37
|
+
regex: Optional[Union[InterpolatedString, str]] = None
|
|
38
|
+
max_waiting_time_in_seconds: Optional[float] = None
|
|
39
|
+
|
|
40
|
+
def __post_init__(self, parameters: Mapping[str, Any]) -> None:
|
|
41
|
+
self.regex = (
|
|
42
|
+
InterpolatedString.create(self.regex, parameters=parameters) if self.regex else None
|
|
43
|
+
)
|
|
44
|
+
self.header = InterpolatedString.create(self.header, parameters=parameters)
|
|
45
|
+
|
|
46
|
+
def backoff_time(
|
|
47
|
+
self,
|
|
48
|
+
response_or_exception: Optional[Union[requests.Response, requests.RequestException]],
|
|
49
|
+
attempt_count: int,
|
|
50
|
+
) -> Optional[float]:
|
|
51
|
+
header = self.header.eval(config=self.config) # type: ignore # header is always cast to an interpolated stream
|
|
52
|
+
if self.regex:
|
|
53
|
+
evaled_regex = self.regex.eval(self.config) # type: ignore # header is always cast to an interpolated string
|
|
54
|
+
regex = re.compile(evaled_regex)
|
|
55
|
+
else:
|
|
56
|
+
regex = None
|
|
57
|
+
header_value = None
|
|
58
|
+
if isinstance(response_or_exception, requests.Response):
|
|
59
|
+
header_value = get_numeric_value_from_header(response_or_exception, header, regex)
|
|
60
|
+
if (
|
|
61
|
+
self.max_waiting_time_in_seconds
|
|
62
|
+
and header_value
|
|
63
|
+
and header_value >= self.max_waiting_time_in_seconds
|
|
64
|
+
):
|
|
65
|
+
raise AirbyteTracedException(
|
|
66
|
+
internal_message=f"Rate limit wait time {header_value} is greater than max waiting time of {self.max_waiting_time_in_seconds} seconds. Stopping the stream...",
|
|
67
|
+
message="The rate limit is greater than max waiting time has been reached.",
|
|
68
|
+
failure_type=FailureType.transient_error,
|
|
69
|
+
)
|
|
70
|
+
return header_value
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Copyright (c) 2023 Airbyte, Inc., all rights reserved.
|
|
3
|
+
#
|
|
4
|
+
|
|
5
|
+
import numbers
|
|
6
|
+
import re
|
|
7
|
+
import time
|
|
8
|
+
from dataclasses import InitVar, dataclass
|
|
9
|
+
from typing import Any, Mapping, Optional, Union
|
|
10
|
+
|
|
11
|
+
import requests
|
|
12
|
+
|
|
13
|
+
from airbyte_cdk.sources.declarative.interpolation.interpolated_string import InterpolatedString
|
|
14
|
+
from airbyte_cdk.sources.declarative.requesters.error_handlers.backoff_strategies.header_helper import (
|
|
15
|
+
get_numeric_value_from_header,
|
|
16
|
+
)
|
|
17
|
+
from airbyte_cdk.sources.declarative.requesters.error_handlers.backoff_strategy import (
|
|
18
|
+
BackoffStrategy,
|
|
19
|
+
)
|
|
20
|
+
from airbyte_cdk.sources.types import Config
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
@dataclass
|
|
24
|
+
class WaitUntilTimeFromHeaderBackoffStrategy(BackoffStrategy):
|
|
25
|
+
"""
|
|
26
|
+
Extract time at which we can retry the request from response header
|
|
27
|
+
and wait for the difference between now and that time
|
|
28
|
+
|
|
29
|
+
Attributes:
|
|
30
|
+
header (str): header to read wait time from
|
|
31
|
+
min_wait (Optional[float]): minimum time to wait for safety
|
|
32
|
+
regex (Optional[str]): optional regex to apply on the header to extract its value
|
|
33
|
+
"""
|
|
34
|
+
|
|
35
|
+
header: Union[InterpolatedString, str]
|
|
36
|
+
parameters: InitVar[Mapping[str, Any]]
|
|
37
|
+
config: Config
|
|
38
|
+
min_wait: Optional[Union[float, InterpolatedString, str]] = None
|
|
39
|
+
regex: Optional[Union[InterpolatedString, str]] = None
|
|
40
|
+
|
|
41
|
+
def __post_init__(self, parameters: Mapping[str, Any]) -> None:
|
|
42
|
+
self.header = InterpolatedString.create(self.header, parameters=parameters)
|
|
43
|
+
self.regex = (
|
|
44
|
+
InterpolatedString.create(self.regex, parameters=parameters) if self.regex else None
|
|
45
|
+
)
|
|
46
|
+
if not isinstance(self.min_wait, InterpolatedString):
|
|
47
|
+
self.min_wait = InterpolatedString.create(str(self.min_wait), parameters=parameters)
|
|
48
|
+
|
|
49
|
+
def backoff_time(
|
|
50
|
+
self,
|
|
51
|
+
response_or_exception: Optional[Union[requests.Response, requests.RequestException]],
|
|
52
|
+
attempt_count: int,
|
|
53
|
+
) -> Optional[float]:
|
|
54
|
+
now = time.time()
|
|
55
|
+
header = self.header.eval(self.config) # type: ignore # header is always cast to an interpolated string
|
|
56
|
+
if self.regex:
|
|
57
|
+
evaled_regex = self.regex.eval(self.config) # type: ignore # header is always cast to an interpolated string
|
|
58
|
+
regex = re.compile(evaled_regex)
|
|
59
|
+
else:
|
|
60
|
+
regex = None
|
|
61
|
+
wait_until = None
|
|
62
|
+
if isinstance(response_or_exception, requests.Response):
|
|
63
|
+
wait_until = get_numeric_value_from_header(response_or_exception, header, regex)
|
|
64
|
+
min_wait = self.min_wait.eval(self.config) # type: ignore # header is always cast to an interpolated string
|
|
65
|
+
if wait_until is None or not wait_until:
|
|
66
|
+
return float(min_wait) if min_wait else None
|
|
67
|
+
if (isinstance(wait_until, str) and wait_until.isnumeric()) or isinstance(
|
|
68
|
+
wait_until, numbers.Number
|
|
69
|
+
):
|
|
70
|
+
wait_time = float(wait_until) - now
|
|
71
|
+
else:
|
|
72
|
+
return float(min_wait)
|
|
73
|
+
if min_wait:
|
|
74
|
+
return float(max(wait_time, min_wait))
|
|
75
|
+
elif wait_time < 0:
|
|
76
|
+
return None
|
|
77
|
+
return wait_time
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Copyright (c) 2023 Airbyte, Inc., all rights reserved.
|
|
3
|
+
#
|
|
4
|
+
|
|
5
|
+
from abc import ABC
|
|
6
|
+
from dataclasses import dataclass
|
|
7
|
+
|
|
8
|
+
from airbyte_cdk.sources.streams.http.error_handlers import BackoffStrategy
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@dataclass
|
|
12
|
+
class DecalarativeBackoffStrategy(BackoffStrategy, ABC):
|
|
13
|
+
"""
|
|
14
|
+
This interface exists to retain backwards compatability with connectors that reference the declarative BackoffStrategy. As part of the effort to promote common interfaces to the Python CDK, this now extends the Python CDK backoff strategy interface.
|
|
15
|
+
|
|
16
|
+
Backoff strategy defining how long to wait before retrying a request that resulted in an error.
|
|
17
|
+
"""
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Copyright (c) 2023 Airbyte, Inc., all rights reserved.
|
|
3
|
+
#
|
|
4
|
+
|
|
5
|
+
from dataclasses import InitVar, dataclass
|
|
6
|
+
from typing import Any, List, Mapping, Optional, Union
|
|
7
|
+
|
|
8
|
+
import requests
|
|
9
|
+
|
|
10
|
+
from airbyte_cdk.sources.streams.http.error_handlers import ErrorHandler
|
|
11
|
+
from airbyte_cdk.sources.streams.http.error_handlers.backoff_strategy import BackoffStrategy
|
|
12
|
+
from airbyte_cdk.sources.streams.http.error_handlers.response_models import (
|
|
13
|
+
ErrorResolution,
|
|
14
|
+
ResponseAction,
|
|
15
|
+
create_fallback_error_resolution,
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@dataclass
|
|
20
|
+
class CompositeErrorHandler(ErrorHandler):
|
|
21
|
+
"""
|
|
22
|
+
Error handler that sequentially iterates over a list of `ErrorHandler`s
|
|
23
|
+
|
|
24
|
+
Sample config chaining 2 different retriers:
|
|
25
|
+
error_handler:
|
|
26
|
+
type: "CompositeErrorHandler"
|
|
27
|
+
error_handlers:
|
|
28
|
+
- response_filters:
|
|
29
|
+
- predicate: "{{ 'codase' in response }}"
|
|
30
|
+
action: RETRY
|
|
31
|
+
backoff_strategies:
|
|
32
|
+
- type: "ConstantBackoff"
|
|
33
|
+
backoff_time_in_seconds: 5
|
|
34
|
+
- response_filters:
|
|
35
|
+
- http_codes: [ 403 ]
|
|
36
|
+
action: RETRY
|
|
37
|
+
backoff_strategies:
|
|
38
|
+
- type: "ConstantBackoff"
|
|
39
|
+
backoff_time_in_seconds: 10
|
|
40
|
+
Attributes:
|
|
41
|
+
error_handlers (List[ErrorHandler]): list of error handlers
|
|
42
|
+
"""
|
|
43
|
+
|
|
44
|
+
error_handlers: List[ErrorHandler]
|
|
45
|
+
parameters: InitVar[Mapping[str, Any]]
|
|
46
|
+
|
|
47
|
+
def __post_init__(self, parameters: Mapping[str, Any]) -> None:
|
|
48
|
+
if not self.error_handlers:
|
|
49
|
+
raise ValueError("CompositeErrorHandler expects at least 1 underlying error handler")
|
|
50
|
+
|
|
51
|
+
@property
|
|
52
|
+
def max_retries(self) -> Optional[int]:
|
|
53
|
+
return self.error_handlers[0].max_retries
|
|
54
|
+
|
|
55
|
+
@property
|
|
56
|
+
def max_time(self) -> Optional[int]:
|
|
57
|
+
return max([error_handler.max_time or 0 for error_handler in self.error_handlers])
|
|
58
|
+
|
|
59
|
+
def interpret_response(
|
|
60
|
+
self, response_or_exception: Optional[Union[requests.Response, Exception]]
|
|
61
|
+
) -> ErrorResolution:
|
|
62
|
+
matched_error_resolution = None
|
|
63
|
+
for error_handler in self.error_handlers:
|
|
64
|
+
matched_error_resolution = error_handler.interpret_response(response_or_exception)
|
|
65
|
+
|
|
66
|
+
if not isinstance(matched_error_resolution, ErrorResolution):
|
|
67
|
+
continue
|
|
68
|
+
|
|
69
|
+
if matched_error_resolution.response_action == ResponseAction.SUCCESS:
|
|
70
|
+
return matched_error_resolution
|
|
71
|
+
|
|
72
|
+
if (
|
|
73
|
+
matched_error_resolution.response_action == ResponseAction.RETRY
|
|
74
|
+
or matched_error_resolution.response_action == ResponseAction.IGNORE
|
|
75
|
+
):
|
|
76
|
+
return matched_error_resolution
|
|
77
|
+
if matched_error_resolution:
|
|
78
|
+
return matched_error_resolution
|
|
79
|
+
|
|
80
|
+
return create_fallback_error_resolution(response_or_exception)
|
|
81
|
+
|
|
82
|
+
@property
|
|
83
|
+
def backoff_strategies(self) -> Optional[List[BackoffStrategy]]:
|
|
84
|
+
"""
|
|
85
|
+
Combines backoff strategies from all child error handlers into a single flattened list.
|
|
86
|
+
|
|
87
|
+
When used with HttpRequester, note the following behavior:
|
|
88
|
+
- In HttpRequester.__post_init__, the entire list of backoff strategies is assigned to the error handler
|
|
89
|
+
- However, the error handler's backoff_time() method only ever uses the first non-None strategy in the list
|
|
90
|
+
- This means that if any backoff strategies are present, the first non-None strategy becomes the default
|
|
91
|
+
- This applies to both user-defined response filters and errors from DEFAULT_ERROR_MAPPING
|
|
92
|
+
- The list structure is not used to map different strategies to different error conditions
|
|
93
|
+
- Therefore, subsequent strategies in the list will not be used
|
|
94
|
+
|
|
95
|
+
Returns None if no handlers have strategies defined, which will result in HttpRequester using its default backoff strategy.
|
|
96
|
+
"""
|
|
97
|
+
all_strategies = []
|
|
98
|
+
for handler in self.error_handlers:
|
|
99
|
+
if hasattr(handler, "backoff_strategies") and handler.backoff_strategies:
|
|
100
|
+
all_strategies.extend(handler.backoff_strategies)
|
|
101
|
+
return all_strategies if all_strategies else None
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Copyright (c) 2023 Airbyte, Inc., all rights reserved.
|
|
3
|
+
#
|
|
4
|
+
|
|
5
|
+
from dataclasses import InitVar, dataclass, field
|
|
6
|
+
from typing import Any, List, Mapping, MutableMapping, Optional, Union
|
|
7
|
+
|
|
8
|
+
import requests
|
|
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,
|
|
15
|
+
)
|
|
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
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
@dataclass
|
|
26
|
+
class DefaultErrorHandler(ErrorHandler):
|
|
27
|
+
"""
|
|
28
|
+
Default error handler.
|
|
29
|
+
|
|
30
|
+
By default, the handler will only use the `DEFAULT_ERROR_MAPPING` that is part of the Python CDK's `HttpStatusErrorHandler`.
|
|
31
|
+
|
|
32
|
+
If the response is successful, then a SUCCESS_RESOLUTION is returned.
|
|
33
|
+
Otherwise, iterate over the response_filters.
|
|
34
|
+
If any of the filter match the response, then return the appropriate status.
|
|
35
|
+
When `DefaultErrorHandler.backoff_time()` is invoked, iterate sequentially over the backoff_strategies and return the first non-None backoff time, else return None.
|
|
36
|
+
|
|
37
|
+
Sample configs:
|
|
38
|
+
|
|
39
|
+
1. retry 10 times
|
|
40
|
+
`
|
|
41
|
+
error_handler:
|
|
42
|
+
max_retries: 10
|
|
43
|
+
`
|
|
44
|
+
2. backoff for 5 seconds
|
|
45
|
+
`
|
|
46
|
+
error_handler:
|
|
47
|
+
backoff_strategies:
|
|
48
|
+
- type: "ConstantBackoff"
|
|
49
|
+
backoff_time_in_seconds: 5
|
|
50
|
+
`
|
|
51
|
+
3. retry on HTTP 404
|
|
52
|
+
`
|
|
53
|
+
error_handler:
|
|
54
|
+
response_filters:
|
|
55
|
+
- http_codes: [ 404 ]
|
|
56
|
+
action: RETRY
|
|
57
|
+
`
|
|
58
|
+
4. ignore HTTP 404
|
|
59
|
+
`
|
|
60
|
+
error_handler:
|
|
61
|
+
response_filters:
|
|
62
|
+
- http_codes: [ 404 ]
|
|
63
|
+
action: IGNORE
|
|
64
|
+
`
|
|
65
|
+
5. retry if error message contains `retrythisrequest!` substring
|
|
66
|
+
`
|
|
67
|
+
error_handler:
|
|
68
|
+
response_filters:
|
|
69
|
+
- error_message_contain: "retrythisrequest!"
|
|
70
|
+
action: IGNORE
|
|
71
|
+
`
|
|
72
|
+
6. retry if 'code' is a field present in the response body
|
|
73
|
+
`
|
|
74
|
+
error_handler:
|
|
75
|
+
response_filters:
|
|
76
|
+
- predicate: "{{ 'code' in response }}"
|
|
77
|
+
action: IGNORE
|
|
78
|
+
`
|
|
79
|
+
|
|
80
|
+
7. ignore 429 and retry on 404
|
|
81
|
+
`
|
|
82
|
+
error_handler:
|
|
83
|
+
- http_codes: [ 429 ]
|
|
84
|
+
action: IGNORE
|
|
85
|
+
- http_codes: [ 404 ]
|
|
86
|
+
action: RETRY
|
|
87
|
+
`
|
|
88
|
+
|
|
89
|
+
Attributes:
|
|
90
|
+
response_filters (Optional[List[HttpResponseFilter]]): response filters to iterate on
|
|
91
|
+
max_retries (Optional[int]): maximum retry attempts
|
|
92
|
+
backoff_strategies (Optional[List[BackoffStrategy]]): list of backoff strategies to use to determine how long
|
|
93
|
+
to wait before retrying
|
|
94
|
+
"""
|
|
95
|
+
|
|
96
|
+
parameters: InitVar[Mapping[str, Any]]
|
|
97
|
+
config: Config
|
|
98
|
+
response_filters: Optional[List[HttpResponseFilter]] = None
|
|
99
|
+
max_retries: Optional[int] = 5
|
|
100
|
+
max_time: int = 60 * 10
|
|
101
|
+
_max_retries: int = field(init=False, repr=False, default=5)
|
|
102
|
+
_max_time: int = field(init=False, repr=False, default=60 * 10)
|
|
103
|
+
backoff_strategies: Optional[List[BackoffStrategy]] = None
|
|
104
|
+
|
|
105
|
+
def __post_init__(self, parameters: Mapping[str, Any]) -> None:
|
|
106
|
+
if not self.response_filters:
|
|
107
|
+
self.response_filters = [HttpResponseFilter(config=self.config, parameters={})]
|
|
108
|
+
|
|
109
|
+
self._last_request_to_attempt_count: MutableMapping[requests.PreparedRequest, int] = {}
|
|
110
|
+
|
|
111
|
+
def interpret_response(
|
|
112
|
+
self, response_or_exception: Optional[Union[requests.Response, Exception]]
|
|
113
|
+
) -> ErrorResolution:
|
|
114
|
+
if self.response_filters:
|
|
115
|
+
for response_filter in self.response_filters:
|
|
116
|
+
matched_error_resolution = response_filter.matches(
|
|
117
|
+
response_or_exception=response_or_exception
|
|
118
|
+
)
|
|
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]:
|
|
139
|
+
backoff = None
|
|
140
|
+
if self.backoff_strategies:
|
|
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
|
+
)
|
|
145
|
+
if backoff:
|
|
146
|
+
return backoff
|
|
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
|
+
)
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Copyright (c) 2023 Airbyte, Inc., all rights reserved.
|
|
3
|
+
#
|
|
4
|
+
|
|
5
|
+
from abc import ABC
|
|
6
|
+
from dataclasses import dataclass
|
|
7
|
+
|
|
8
|
+
from airbyte_cdk.sources.streams.http.error_handlers import ErrorHandler
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@dataclass
|
|
12
|
+
class DeclarativeErrorHandler(ErrorHandler, ABC):
|
|
13
|
+
"""
|
|
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.
|
|
15
|
+
|
|
16
|
+
`ErrorHandler` defines how to handle errors that occur during the request process, returning an ErrorResolution object that defines how to proceed.
|
|
17
|
+
"""
|