airbyte-cdk 6.18.0.dev1__py3-none-any.whl → 6.18.1__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.
@@ -56,8 +56,12 @@ class DeclarativeOauth2Authenticator(AbstractOauth2Authenticator, DeclarativeAut
56
56
  token_expiry_is_time_of_expiration: bool = False
57
57
  access_token_name: Union[InterpolatedString, str] = "access_token"
58
58
  access_token_value: Optional[Union[InterpolatedString, str]] = None
59
+ client_id_name: Union[InterpolatedString, str] = "client_id"
60
+ client_secret_name: Union[InterpolatedString, str] = "client_secret"
59
61
  expires_in_name: Union[InterpolatedString, str] = "expires_in"
62
+ refresh_token_name: Union[InterpolatedString, str] = "refresh_token"
60
63
  refresh_request_body: Optional[Mapping[str, Any]] = None
64
+ grant_type_name: Union[InterpolatedString, str] = "grant_type"
61
65
  grant_type: Union[InterpolatedString, str] = "refresh_token"
62
66
  message_repository: MessageRepository = NoopMessageRepository()
63
67
 
@@ -69,8 +73,15 @@ class DeclarativeOauth2Authenticator(AbstractOauth2Authenticator, DeclarativeAut
69
73
  )
70
74
  else:
71
75
  self._token_refresh_endpoint = None
76
+ self._client_id_name = InterpolatedString.create(self.client_id_name, parameters=parameters)
72
77
  self._client_id = InterpolatedString.create(self.client_id, parameters=parameters)
78
+ self._client_secret_name = InterpolatedString.create(
79
+ self.client_secret_name, parameters=parameters
80
+ )
73
81
  self._client_secret = InterpolatedString.create(self.client_secret, parameters=parameters)
82
+ self._refresh_token_name = InterpolatedString.create(
83
+ self.refresh_token_name, parameters=parameters
84
+ )
74
85
  if self.refresh_token is not None:
75
86
  self._refresh_token: Optional[InterpolatedString] = InterpolatedString.create(
76
87
  self.refresh_token, parameters=parameters
@@ -83,6 +94,9 @@ class DeclarativeOauth2Authenticator(AbstractOauth2Authenticator, DeclarativeAut
83
94
  self.expires_in_name = InterpolatedString.create(
84
95
  self.expires_in_name, parameters=parameters
85
96
  )
97
+ self.grant_type_name = InterpolatedString.create(
98
+ self.grant_type_name, parameters=parameters
99
+ )
86
100
  self.grant_type = InterpolatedString.create(self.grant_type, parameters=parameters)
87
101
  self._refresh_request_body = InterpolatedMapping(
88
102
  self.refresh_request_body or {}, parameters=parameters
@@ -122,18 +136,27 @@ class DeclarativeOauth2Authenticator(AbstractOauth2Authenticator, DeclarativeAut
122
136
  return refresh_token_endpoint
123
137
  return None
124
138
 
139
+ def get_client_id_name(self) -> str:
140
+ return self._client_id_name.eval(self.config) # type: ignore # eval returns a string in this context
141
+
125
142
  def get_client_id(self) -> str:
126
143
  client_id: str = self._client_id.eval(self.config)
127
144
  if not client_id:
128
145
  raise ValueError("OAuthAuthenticator was unable to evaluate client_id parameter")
129
146
  return client_id
130
147
 
148
+ def get_client_secret_name(self) -> str:
149
+ return self._client_secret_name.eval(self.config) # type: ignore # eval returns a string in this context
150
+
131
151
  def get_client_secret(self) -> str:
132
152
  client_secret: str = self._client_secret.eval(self.config)
133
153
  if not client_secret:
134
154
  raise ValueError("OAuthAuthenticator was unable to evaluate client_secret parameter")
135
155
  return client_secret
136
156
 
157
+ def get_refresh_token_name(self) -> str:
158
+ return self._refresh_token_name.eval(self.config) # type: ignore # eval returns a string in this context
159
+
137
160
  def get_refresh_token(self) -> Optional[str]:
138
161
  return None if self._refresh_token is None else str(self._refresh_token.eval(self.config))
139
162
 
@@ -146,6 +169,9 @@ class DeclarativeOauth2Authenticator(AbstractOauth2Authenticator, DeclarativeAut
146
169
  def get_expires_in_name(self) -> str:
147
170
  return self.expires_in_name.eval(self.config) # type: ignore # eval returns a string in this context
148
171
 
172
+ def get_grant_type_name(self) -> str:
173
+ return self.grant_type_name.eval(self.config) # type: ignore # eval returns a string in this context
174
+
149
175
  def get_grant_type(self) -> str:
150
176
  return self.grant_type.eval(self.config) # type: ignore # eval returns a string in this context
151
177
 
@@ -678,7 +678,7 @@ definitions:
678
678
  properties:
679
679
  type:
680
680
  type: string
681
- enum: [CustomSchemaNormalization]
681
+ enum: [ CustomSchemaNormalization ]
682
682
  class_name:
683
683
  title: Class Name
684
684
  description: Fully-qualified name of the class that will be implementing the custom normalization. The format is `source_<name>.<package>.<class_name>`.
@@ -1047,6 +1047,13 @@ definitions:
1047
1047
  type:
1048
1048
  type: string
1049
1049
  enum: [OAuthAuthenticator]
1050
+ client_id_name:
1051
+ title: Client ID Property Name
1052
+ description: The name of the property to use to refresh the `access_token`.
1053
+ type: string
1054
+ default: "client_id"
1055
+ examples:
1056
+ - custom_app_id
1050
1057
  client_id:
1051
1058
  title: Client ID
1052
1059
  description: The OAuth client ID. Fill it in the user inputs.
@@ -1054,6 +1061,13 @@ definitions:
1054
1061
  examples:
1055
1062
  - "{{ config['client_id }}"
1056
1063
  - "{{ config['credentials']['client_id }}"
1064
+ client_secret_name:
1065
+ title: Client Secret Property Name
1066
+ description: The name of the property to use to refresh the `access_token`.
1067
+ type: string
1068
+ default: "client_secret"
1069
+ examples:
1070
+ - custom_app_secret
1057
1071
  client_secret:
1058
1072
  title: Client Secret
1059
1073
  description: The OAuth client secret. Fill it in the user inputs.
@@ -1061,6 +1075,13 @@ definitions:
1061
1075
  examples:
1062
1076
  - "{{ config['client_secret }}"
1063
1077
  - "{{ config['credentials']['client_secret }}"
1078
+ refresh_token_name:
1079
+ title: Refresh Token Property Name
1080
+ description: The name of the property to use to refresh the `access_token`.
1081
+ type: string
1082
+ default: "refresh_token"
1083
+ examples:
1084
+ - custom_app_refresh_value
1064
1085
  refresh_token:
1065
1086
  title: Refresh Token
1066
1087
  description: Credential artifact used to get a new access token.
@@ -1094,6 +1115,13 @@ definitions:
1094
1115
  default: "expires_in"
1095
1116
  examples:
1096
1117
  - expires_in
1118
+ grant_type_name:
1119
+ title: Grant Type Property Name
1120
+ description: The name of the property to use to refresh the `access_token`.
1121
+ type: string
1122
+ default: "grant_type"
1123
+ examples:
1124
+ - custom_grant_type
1097
1125
  grant_type:
1098
1126
  title: Grant Type
1099
1127
  description: Specifies the OAuth2 grant type. If set to refresh_token, the refresh_token needs to be provided as well. For client_credentials, only client id and secret are required. Other grant types are not officially supported.
@@ -2014,20 +2042,6 @@ definitions:
2014
2042
  $parameters:
2015
2043
  type: object
2016
2044
  additionalProperties: true
2017
- JsonParser:
2018
- title: JsonParser
2019
- description: Parser used for parsing str, bytes, or bytearray data and returning data in a dictionary format.
2020
- type: object
2021
- additionalProperties: true
2022
- required:
2023
- - type
2024
- properties:
2025
- type:
2026
- type: string
2027
- enum: [JsonParser]
2028
- encoding:
2029
- type: string
2030
- default: utf-8
2031
2045
  ListPartitionRouter:
2032
2046
  title: List Partition Router
2033
2047
  description: A Partition router that specifies a list of attributes where each attribute describes a portion of the complete data set for a stream. During a sync, each value is iterated over and can be used as input to outbound API requests.
@@ -2218,15 +2232,15 @@ definitions:
2218
2232
  Pertains to the fields defined by the connector relating to the OAuth flow.
2219
2233
 
2220
2234
  Interpolation capabilities:
2221
- - The variables placeholders are declared as `{my_var}`.
2222
- - The nested resolution variables like `{{my_nested_var}}` is allowed as well.
2235
+ - The variables placeholders are declared as `{{my_var}}`.
2236
+ - The nested resolution variables like `{{ {{my_nested_var}} }}` is allowed as well.
2223
2237
 
2224
2238
  - The allowed interpolation context is:
2225
- + base64Encoder - encode to `base64`, {base64Encoder:{my_var_a}:{my_var_b}}
2226
- + base64Decorer - decode from `base64` encoded string, {base64Decoder:{my_string_variable_or_string_value}}
2227
- + urlEncoder - encode the input string to URL-like format, {urlEncoder:https://test.host.com/endpoint}
2228
- + urlDecorer - decode the input url-encoded string into text format, {urlDecoder:https%3A%2F%2Fairbyte.io}
2229
- + codeChallengeS256 - get the `codeChallenge` encoded value to provide additional data-provider specific authorisation values, {codeChallengeS256:{state_value}}
2239
+ + base64Encoder - encode to `base64`, {{ {{my_var_a}}:{{my_var_b}} | base64Encoder }}
2240
+ + base64Decorer - decode from `base64` encoded string, {{ {{my_string_variable_or_string_value}} | base64Decoder }}
2241
+ + urlEncoder - encode the input string to URL-like format, {{ https://test.host.com/endpoint | urlEncoder}}
2242
+ + urlDecorer - decode the input url-encoded string into text format, {{ urlDecoder:https%3A%2F%2Fairbyte.io | urlDecoder}}
2243
+ + codeChallengeS256 - get the `codeChallenge` encoded value to provide additional data-provider specific authorisation values, {{ {{state_value}} | codeChallengeS256 }}
2230
2244
 
2231
2245
  Examples:
2232
2246
  - The TikTok Marketing DeclarativeOAuth spec:
@@ -2235,12 +2249,12 @@ definitions:
2235
2249
  "type": "object",
2236
2250
  "additionalProperties": false,
2237
2251
  "properties": {
2238
- "consent_url": "https://ads.tiktok.com/marketing_api/auth?{client_id_key}={{client_id_key}}&{redirect_uri_key}={urlEncoder:{{redirect_uri_key}}}&{state_key}={{state_key}}",
2252
+ "consent_url": "https://ads.tiktok.com/marketing_api/auth?{{client_id_key}}={{client_id_value}}&{{redirect_uri_key}}={{ {{redirect_uri_value}} | urlEncoder}}&{{state_key}}={{state_value}}",
2239
2253
  "access_token_url": "https://business-api.tiktok.com/open_api/v1.3/oauth2/access_token/",
2240
2254
  "access_token_params": {
2241
- "{auth_code_key}": "{{auth_code_key}}",
2242
- "{client_id_key}": "{{client_id_key}}",
2243
- "{client_secret_key}": "{{client_secret_key}}"
2255
+ "{{ auth_code_key }}": "{{ auth_code_value }}",
2256
+ "{{ client_id_key }}": "{{ client_id_value }}",
2257
+ "{{ client_secret_key }}": "{{ client_secret_value }}"
2244
2258
  },
2245
2259
  "access_token_headers": {
2246
2260
  "Content-Type": "application/json",
@@ -2258,7 +2272,6 @@ definitions:
2258
2272
  required:
2259
2273
  - consent_url
2260
2274
  - access_token_url
2261
- - extract_output
2262
2275
  properties:
2263
2276
  consent_url:
2264
2277
  title: Consent URL
@@ -2267,8 +2280,8 @@ definitions:
2267
2280
  The DeclarativeOAuth Specific string URL string template to initiate the authentication.
2268
2281
  The placeholders are replaced during the processing to provide neccessary values.
2269
2282
  examples:
2270
- - https://domain.host.com/marketing_api/auth?{client_id_key}={{client_id_key}}&{redirect_uri_key}={urlEncoder:{{redirect_uri_key}}}&{state_key}={{state_key}}
2271
- - https://endpoint.host.com/oauth2/authorize?{client_id_key}={{client_id_key}}&{redirect_uri_key}={urlEncoder:{{redirect_uri_key}}}&{scope_key}={urlEncoder:{{scope_key}}}&{state_key}={{state_key}}&subdomain={subdomain}
2283
+ - https://domain.host.com/marketing_api/auth?{{client_id_key}}={{client_id_value}}&{{redirect_uri_key}}={{{{redirect_uri_value}} | urlEncoder}}&{{state_key}}={{state_value}}
2284
+ - https://endpoint.host.com/oauth2/authorize?{{client_id_key}}={{client_id_value}}&{{redirect_uri_key}}={{{{redirect_uri_value}} | urlEncoder}}&{{scope_key}}={{{{scope_value}} | urlEncoder}}&{{state_key}}={{state_value}}&subdomain={{subdomain}}
2272
2285
  scope:
2273
2286
  title: Scopes
2274
2287
  type: string
@@ -2283,7 +2296,7 @@ definitions:
2283
2296
  The DeclarativeOAuth Specific URL templated string to obtain the `access_token`, `refresh_token` etc.
2284
2297
  The placeholders are replaced during the processing to provide neccessary values.
2285
2298
  examples:
2286
- - https://auth.host.com/oauth2/token?{client_id_key}={{client_id_key}}&{client_secret_key}={{client_secret_key}}&{auth_code_key}={{auth_code_key}}&{redirect_uri_key}={urlEncoder:{{redirect_uri_key}}}
2299
+ - https://auth.host.com/oauth2/token?{{client_id_key}}={{client_id_value}}&{{client_secret_key}}={{client_secret_value}}&{{auth_code_key}}={{auth_code_value}}&{{redirect_uri_key}}={{{{redirect_uri_value}} | urlEncoder}}
2287
2300
  access_token_headers:
2288
2301
  title: Access Token Headers
2289
2302
  type: object
@@ -2292,7 +2305,7 @@ definitions:
2292
2305
  The DeclarativeOAuth Specific optional headers to inject while exchanging the `auth_code` to `access_token` during `completeOAuthFlow` step.
2293
2306
  examples:
2294
2307
  - {
2295
- "Authorization": "Basic {base64Encoder:{client_id}:{client_secret}}",
2308
+ "Authorization": "Basic {{ {{ client_id_value }}:{{ client_secret_value }} | base64Encoder }}",
2296
2309
  }
2297
2310
  access_token_params:
2298
2311
  title: Access Token Query Params (Json Encoded)
@@ -2303,9 +2316,9 @@ definitions:
2303
2316
  When this property is provided, the query params will be encoded as `Json` and included in the outgoing API request.
2304
2317
  examples:
2305
2318
  - {
2306
- "{auth_code_key}": "{{auth_code_key}}",
2307
- "{client_id_key}": "{{client_id_key}}",
2308
- "{client_secret_key}": "{{client_secret_key}}",
2319
+ "{{ auth_code_key }}": "{{ auth_code_value }}",
2320
+ "{{ client_id_key }}": "{{ client_id_value }}",
2321
+ "{{ client_secret_key }}": "{{ client_secret_value }}",
2309
2322
  }
2310
2323
  extract_output:
2311
2324
  title: Extract Output
@@ -2991,6 +3004,11 @@ definitions:
2991
3004
  anyOf:
2992
3005
  - "$ref": "#/definitions/CustomRequester"
2993
3006
  - "$ref": "#/definitions/HttpRequester"
3007
+ url_requester:
3008
+ description: Requester component that describes how to prepare HTTP requests to send to the source API to extract the url from polling response by the completed async job.
3009
+ anyOf:
3010
+ - "$ref": "#/definitions/CustomRequester"
3011
+ - "$ref": "#/definitions/HttpRequester"
2994
3012
  download_requester:
2995
3013
  description: Requester component that describes how to prepare HTTP requests to send to the source API to download the data provided by the completed async job.
2996
3014
  anyOf:
@@ -7,12 +7,9 @@ from dataclasses import dataclass
7
7
  from io import BufferedIOBase, TextIOWrapper
8
8
  from typing import Any, Generator, MutableMapping, Optional
9
9
 
10
- import orjson
11
10
  import requests
12
11
 
13
- from airbyte_cdk.models import FailureType
14
12
  from airbyte_cdk.sources.declarative.decoders.decoder import Decoder
15
- from airbyte_cdk.utils import AirbyteTracedException
16
13
 
17
14
  logger = logging.getLogger("airbyte")
18
15
 
@@ -45,31 +42,6 @@ class GzipParser(Parser):
45
42
  yield from self.inner_parser.parse(gzipobj)
46
43
 
47
44
 
48
- @dataclass
49
- class JsonParser(Parser):
50
- encoding: str = "utf-8"
51
-
52
- def parse(self, data: BufferedIOBase) -> Generator[MutableMapping[str, Any], None, None]:
53
- raw_data = data.read()
54
- try:
55
- body_json = orjson.loads(raw_data.decode(self.encoding))
56
- except Exception:
57
- try:
58
- body_json = json.loads(raw_data.decode(self.encoding))
59
- except Exception as exc:
60
- raise AirbyteTracedException(
61
- message="Response JSON data failed to be parsed. See logs for more inforation.",
62
- internal_message=f"Response JSON data faild to be parsed: {exc=}, {raw_data=}",
63
- failure_type=FailureType.system_error,
64
- exception=exc,
65
- )
66
-
67
- if isinstance(body_json, list):
68
- yield from body_json
69
- else:
70
- yield from [body_json]
71
-
72
-
73
45
  @dataclass
74
46
  class JsonLineParser(Parser):
75
47
  encoding: Optional[str] = "utf-8"
@@ -481,12 +481,24 @@ class RefreshTokenUpdater(BaseModel):
481
481
 
482
482
  class OAuthAuthenticator(BaseModel):
483
483
  type: Literal["OAuthAuthenticator"]
484
+ client_id_name: Optional[str] = Field(
485
+ "client_id",
486
+ description="The name of the property to use to refresh the `access_token`.",
487
+ examples=["custom_app_id"],
488
+ title="Client ID Property Name",
489
+ )
484
490
  client_id: str = Field(
485
491
  ...,
486
492
  description="The OAuth client ID. Fill it in the user inputs.",
487
493
  examples=["{{ config['client_id }}", "{{ config['credentials']['client_id }}"],
488
494
  title="Client ID",
489
495
  )
496
+ client_secret_name: Optional[str] = Field(
497
+ "client_secret",
498
+ description="The name of the property to use to refresh the `access_token`.",
499
+ examples=["custom_app_secret"],
500
+ title="Client Secret Property Name",
501
+ )
490
502
  client_secret: str = Field(
491
503
  ...,
492
504
  description="The OAuth client secret. Fill it in the user inputs.",
@@ -496,6 +508,12 @@ class OAuthAuthenticator(BaseModel):
496
508
  ],
497
509
  title="Client Secret",
498
510
  )
511
+ refresh_token_name: Optional[str] = Field(
512
+ "refresh_token",
513
+ description="The name of the property to use to refresh the `access_token`.",
514
+ examples=["custom_app_refresh_value"],
515
+ title="Refresh Token Property Name",
516
+ )
499
517
  refresh_token: Optional[str] = Field(
500
518
  None,
501
519
  description="Credential artifact used to get a new access token.",
@@ -529,6 +547,12 @@ class OAuthAuthenticator(BaseModel):
529
547
  examples=["expires_in"],
530
548
  title="Token Expiry Property Name",
531
549
  )
550
+ grant_type_name: Optional[str] = Field(
551
+ "grant_type",
552
+ description="The name of the property to use to refresh the `access_token`.",
553
+ examples=["custom_grant_type"],
554
+ title="Grant Type Property Name",
555
+ )
532
556
  grant_type: Optional[str] = Field(
533
557
  "refresh_token",
534
558
  description="Specifies the OAuth2 grant type. If set to refresh_token, the refresh_token needs to be provided as well. For client_credentials, only client id and secret are required. Other grant types are not officially supported.",
@@ -805,14 +829,6 @@ class GzipJsonDecoder(BaseModel):
805
829
  parameters: Optional[Dict[str, Any]] = Field(None, alias="$parameters")
806
830
 
807
831
 
808
- class JsonParser(BaseModel):
809
- class Config:
810
- extra = Extra.allow
811
-
812
- type: Literal["JsonParser"]
813
- encoding: Optional[str] = "utf-8"
814
-
815
-
816
832
  class MinMaxDatetime(BaseModel):
817
833
  type: Literal["MinMaxDatetime"]
818
834
  datetime: str = Field(
@@ -867,8 +883,8 @@ class OauthConnectorInputSpecification(BaseModel):
867
883
  ...,
868
884
  description="The DeclarativeOAuth Specific string URL string template to initiate the authentication.\nThe placeholders are replaced during the processing to provide neccessary values.",
869
885
  examples=[
870
- "https://domain.host.com/marketing_api/auth?{client_id_key}={{client_id_key}}&{redirect_uri_key}={urlEncoder:{{redirect_uri_key}}}&{state_key}={{state_key}}",
871
- "https://endpoint.host.com/oauth2/authorize?{client_id_key}={{client_id_key}}&{redirect_uri_key}={urlEncoder:{{redirect_uri_key}}}&{scope_key}={urlEncoder:{{scope_key}}}&{state_key}={{state_key}}&subdomain={subdomain}",
886
+ "https://domain.host.com/marketing_api/auth?{{client_id_key}}={{client_id_value}}&{{redirect_uri_key}}={{{{redirect_uri_value}} | urlEncoder}}&{{state_key}}={{state_value}}",
887
+ "https://endpoint.host.com/oauth2/authorize?{{client_id_key}}={{client_id_value}}&{{redirect_uri_key}}={{{{redirect_uri_value}} | urlEncoder}}&{{scope_key}}={{{{scope_value}} | urlEncoder}}&{{state_key}}={{state_value}}&subdomain={{subdomain}}",
872
888
  ],
873
889
  title="Consent URL",
874
890
  )
@@ -882,14 +898,18 @@ class OauthConnectorInputSpecification(BaseModel):
882
898
  ...,
883
899
  description="The DeclarativeOAuth Specific URL templated string to obtain the `access_token`, `refresh_token` etc.\nThe placeholders are replaced during the processing to provide neccessary values.",
884
900
  examples=[
885
- "https://auth.host.com/oauth2/token?{client_id_key}={{client_id_key}}&{client_secret_key}={{client_secret_key}}&{auth_code_key}={{auth_code_key}}&{redirect_uri_key}={urlEncoder:{{redirect_uri_key}}}"
901
+ "https://auth.host.com/oauth2/token?{{client_id_key}}={{client_id_value}}&{{client_secret_key}}={{client_secret_value}}&{{auth_code_key}}={{auth_code_value}}&{{redirect_uri_key}}={{{{redirect_uri_value}} | urlEncoder}}"
886
902
  ],
887
903
  title="Access Token URL",
888
904
  )
889
905
  access_token_headers: Optional[Dict[str, Any]] = Field(
890
906
  None,
891
907
  description="The DeclarativeOAuth Specific optional headers to inject while exchanging the `auth_code` to `access_token` during `completeOAuthFlow` step.",
892
- examples=[{"Authorization": "Basic {base64Encoder:{client_id}:{client_secret}}"}],
908
+ examples=[
909
+ {
910
+ "Authorization": "Basic {{ {{ client_id_value }}:{{ client_secret_value }} | base64Encoder }}"
911
+ }
912
+ ],
893
913
  title="Access Token Headers",
894
914
  )
895
915
  access_token_params: Optional[Dict[str, Any]] = Field(
@@ -897,15 +917,15 @@ class OauthConnectorInputSpecification(BaseModel):
897
917
  description="The DeclarativeOAuth Specific optional query parameters to inject while exchanging the `auth_code` to `access_token` during `completeOAuthFlow` step.\nWhen this property is provided, the query params will be encoded as `Json` and included in the outgoing API request.",
898
918
  examples=[
899
919
  {
900
- "{auth_code_key}": "{{auth_code_key}}",
901
- "{client_id_key}": "{{client_id_key}}",
902
- "{client_secret_key}": "{{client_secret_key}}",
920
+ "{{ auth_code_key }}": "{{ auth_code_value }}",
921
+ "{{ client_id_key }}": "{{ client_id_value }}",
922
+ "{{ client_secret_key }}": "{{ client_secret_value }}",
903
923
  }
904
924
  ],
905
925
  title="Access Token Query Params (Json Encoded)",
906
926
  )
907
- extract_output: List[str] = Field(
908
- ...,
927
+ extract_output: Optional[List[str]] = Field(
928
+ None,
909
929
  description="The DeclarativeOAuth Specific list of strings to indicate which keys should be extracted and returned back to the input config.",
910
930
  examples=[["access_token", "refresh_token", "other_field"]],
911
931
  title="Extract Output",
@@ -974,7 +994,7 @@ class OAuthConfigSpecification(BaseModel):
974
994
  )
975
995
  oauth_connector_input_specification: Optional[OauthConnectorInputSpecification] = Field(
976
996
  None,
977
- description='The DeclarativeOAuth specific blob.\nPertains to the fields defined by the connector relating to the OAuth flow.\n\nInterpolation capabilities:\n- The variables placeholders are declared as `{my_var}`.\n- The nested resolution variables like `{{my_nested_var}}` is allowed as well.\n\n- The allowed interpolation context is:\n + base64Encoder - encode to `base64`, {base64Encoder:{my_var_a}:{my_var_b}}\n + base64Decorer - decode from `base64` encoded string, {base64Decoder:{my_string_variable_or_string_value}}\n + urlEncoder - encode the input string to URL-like format, {urlEncoder:https://test.host.com/endpoint}\n + urlDecorer - decode the input url-encoded string into text format, {urlDecoder:https%3A%2F%2Fairbyte.io}\n + codeChallengeS256 - get the `codeChallenge` encoded value to provide additional data-provider specific authorisation values, {codeChallengeS256:{state_value}}\n\nExamples:\n - The TikTok Marketing DeclarativeOAuth spec:\n {\n "oauth_connector_input_specification": {\n "type": "object",\n "additionalProperties": false,\n "properties": {\n "consent_url": "https://ads.tiktok.com/marketing_api/auth?{client_id_key}={{client_id_key}}&{redirect_uri_key}={urlEncoder:{{redirect_uri_key}}}&{state_key}={{state_key}}",\n "access_token_url": "https://business-api.tiktok.com/open_api/v1.3/oauth2/access_token/",\n "access_token_params": {\n "{auth_code_key}": "{{auth_code_key}}",\n "{client_id_key}": "{{client_id_key}}",\n "{client_secret_key}": "{{client_secret_key}}"\n },\n "access_token_headers": {\n "Content-Type": "application/json",\n "Accept": "application/json"\n },\n "extract_output": ["data.access_token"],\n "client_id_key": "app_id",\n "client_secret_key": "secret",\n "auth_code_key": "auth_code"\n }\n }\n }',
997
+ description='The DeclarativeOAuth specific blob.\nPertains to the fields defined by the connector relating to the OAuth flow.\n\nInterpolation capabilities:\n- The variables placeholders are declared as `{{my_var}}`.\n- The nested resolution variables like `{{ {{my_nested_var}} }}` is allowed as well.\n\n- The allowed interpolation context is:\n + base64Encoder - encode to `base64`, {{ {{my_var_a}}:{{my_var_b}} | base64Encoder }}\n + base64Decorer - decode from `base64` encoded string, {{ {{my_string_variable_or_string_value}} | base64Decoder }}\n + urlEncoder - encode the input string to URL-like format, {{ https://test.host.com/endpoint | urlEncoder}}\n + urlDecorer - decode the input url-encoded string into text format, {{ urlDecoder:https%3A%2F%2Fairbyte.io | urlDecoder}}\n + codeChallengeS256 - get the `codeChallenge` encoded value to provide additional data-provider specific authorisation values, {{ {{state_value}} | codeChallengeS256 }}\n\nExamples:\n - The TikTok Marketing DeclarativeOAuth spec:\n {\n "oauth_connector_input_specification": {\n "type": "object",\n "additionalProperties": false,\n "properties": {\n "consent_url": "https://ads.tiktok.com/marketing_api/auth?{{client_id_key}}={{client_id_value}}&{{redirect_uri_key}}={{ {{redirect_uri_value}} | urlEncoder}}&{{state_key}}={{state_value}}",\n "access_token_url": "https://business-api.tiktok.com/open_api/v1.3/oauth2/access_token/",\n "access_token_params": {\n "{{ auth_code_key }}": "{{ auth_code_value }}",\n "{{ client_id_key }}": "{{ client_id_value }}",\n "{{ client_secret_key }}": "{{ client_secret_value }}"\n },\n "access_token_headers": {\n "Content-Type": "application/json",\n "Accept": "application/json"\n },\n "extract_output": ["data.access_token"],\n "client_id_key": "app_id",\n "client_secret_key": "secret",\n "auth_code_key": "auth_code"\n }\n }\n }',
978
998
  title="DeclarativeOAuth Connector Specification",
979
999
  )
980
1000
  complete_oauth_output_specification: Optional[Dict[str, Any]] = Field(
@@ -2058,6 +2078,10 @@ class AsyncRetriever(BaseModel):
2058
2078
  ...,
2059
2079
  description="Requester component that describes how to prepare HTTP requests to send to the source API to fetch the status of the running async job.",
2060
2080
  )
2081
+ url_requester: Optional[Union[CustomRequester, HttpRequester]] = Field(
2082
+ None,
2083
+ description="Requester component that describes how to prepare HTTP requests to send to the source API to extract the url from polling response by the completed async job.",
2084
+ )
2061
2085
  download_requester: Union[CustomRequester, HttpRequester] = Field(
2062
2086
  ...,
2063
2087
  description="Requester component that describes how to prepare HTTP requests to send to the source API to download the data provided by the completed async job.",
@@ -72,7 +72,6 @@ from airbyte_cdk.sources.declarative.decoders.composite_raw_decoder import (
72
72
  CsvParser,
73
73
  GzipParser,
74
74
  JsonLineParser,
75
- JsonParser,
76
75
  )
77
76
  from airbyte_cdk.sources.declarative.extractors import (
78
77
  DpathExtractor,
@@ -248,9 +247,6 @@ from airbyte_cdk.sources.declarative.models.declarative_component_schema import
248
247
  from airbyte_cdk.sources.declarative.models.declarative_component_schema import (
249
248
  JsonLineParser as JsonLineParserModel,
250
249
  )
251
- from airbyte_cdk.sources.declarative.models.declarative_component_schema import (
252
- JsonParser as JsonParserModel,
253
- )
254
250
  from airbyte_cdk.sources.declarative.models.declarative_component_schema import (
255
251
  JwtAuthenticator as JwtAuthenticatorModel,
256
252
  )
@@ -526,7 +522,6 @@ class ModelToComponentFactory:
526
522
  JsonDecoderModel: self.create_json_decoder,
527
523
  JsonlDecoderModel: self.create_jsonl_decoder,
528
524
  JsonLineParserModel: self.create_json_line_parser,
529
- JsonParserModel: self.create_json_parser,
530
525
  GzipJsonDecoderModel: self.create_gzipjson_decoder,
531
526
  GzipParserModel: self.create_gzip_parser,
532
527
  KeysToLowerModel: self.create_keys_to_lower_transformation,
@@ -1753,11 +1748,6 @@ class ModelToComponentFactory:
1753
1748
  def create_json_decoder(model: JsonDecoderModel, config: Config, **kwargs: Any) -> JsonDecoder:
1754
1749
  return JsonDecoder(parameters={})
1755
1750
 
1756
- @staticmethod
1757
- def create_json_parser(model: JsonParserModel, config: Config, **kwargs: Any) -> JsonParser:
1758
- encoding = model.encoding or "utf-8"
1759
- return JsonParser(encoding=encoding)
1760
-
1761
1751
  @staticmethod
1762
1752
  def create_jsonl_decoder(
1763
1753
  model: JsonlDecoderModel, config: Config, **kwargs: Any
@@ -1895,15 +1885,24 @@ class ModelToComponentFactory:
1895
1885
  expires_in_name=InterpolatedString.create(
1896
1886
  model.expires_in_name or "expires_in", parameters=model.parameters or {}
1897
1887
  ).eval(config),
1888
+ client_id_name=InterpolatedString.create(
1889
+ model.client_id_name or "client_id", parameters=model.parameters or {}
1890
+ ).eval(config),
1898
1891
  client_id=InterpolatedString.create(
1899
1892
  model.client_id, parameters=model.parameters or {}
1900
1893
  ).eval(config),
1894
+ client_secret_name=InterpolatedString.create(
1895
+ model.client_secret_name or "client_secret", parameters=model.parameters or {}
1896
+ ).eval(config),
1901
1897
  client_secret=InterpolatedString.create(
1902
1898
  model.client_secret, parameters=model.parameters or {}
1903
1899
  ).eval(config),
1904
1900
  access_token_config_path=model.refresh_token_updater.access_token_config_path,
1905
1901
  refresh_token_config_path=model.refresh_token_updater.refresh_token_config_path,
1906
1902
  token_expiry_date_config_path=model.refresh_token_updater.token_expiry_date_config_path,
1903
+ grant_type_name=InterpolatedString.create(
1904
+ model.grant_type_name or "grant_type", parameters=model.parameters or {}
1905
+ ).eval(config),
1907
1906
  grant_type=InterpolatedString.create(
1908
1907
  model.grant_type or "refresh_token", parameters=model.parameters or {}
1909
1908
  ).eval(config),
@@ -1921,11 +1920,15 @@ class ModelToComponentFactory:
1921
1920
  return DeclarativeOauth2Authenticator( # type: ignore
1922
1921
  access_token_name=model.access_token_name or "access_token",
1923
1922
  access_token_value=model.access_token_value,
1923
+ client_id_name=model.client_id_name or "client_id",
1924
1924
  client_id=model.client_id,
1925
+ client_secret_name=model.client_secret_name or "client_secret",
1925
1926
  client_secret=model.client_secret,
1926
1927
  expires_in_name=model.expires_in_name or "expires_in",
1928
+ grant_type_name=model.grant_type_name or "grant_type",
1927
1929
  grant_type=model.grant_type or "refresh_token",
1928
1930
  refresh_request_body=model.refresh_request_body,
1931
+ refresh_token_name=model.refresh_token_name or "refresh_token",
1929
1932
  refresh_token=model.refresh_token,
1930
1933
  scopes=model.scopes,
1931
1934
  token_expiry_date=model.token_expiry_date,
@@ -2297,7 +2300,7 @@ class ModelToComponentFactory:
2297
2300
  extractor=download_extractor,
2298
2301
  name=name,
2299
2302
  record_filter=None,
2300
- transformations=[],
2303
+ transformations=transformations,
2301
2304
  schema_normalization=TypeTransformer(TransformConfig.NoTransform),
2302
2305
  config=config,
2303
2306
  parameters={},
@@ -2334,6 +2337,16 @@ class ModelToComponentFactory:
2334
2337
  if model.delete_requester
2335
2338
  else None
2336
2339
  )
2340
+ url_requester = (
2341
+ self._create_component_from_model(
2342
+ model=model.url_requester,
2343
+ decoder=decoder,
2344
+ config=config,
2345
+ name=f"job extract_url - {name}",
2346
+ )
2347
+ if model.url_requester
2348
+ else None
2349
+ )
2337
2350
  status_extractor = self._create_component_from_model(
2338
2351
  model=model.status_extractor, decoder=decoder, config=config, name=name
2339
2352
  )
@@ -2344,6 +2357,7 @@ class ModelToComponentFactory:
2344
2357
  creation_requester=creation_requester,
2345
2358
  polling_requester=polling_requester,
2346
2359
  download_retriever=download_retriever,
2360
+ url_requester=url_requester,
2347
2361
  abort_requester=abort_requester,
2348
2362
  delete_requester=delete_requester,
2349
2363
  status_extractor=status_extractor,
@@ -0,0 +1,57 @@
1
+ # AsyncHttpJobRepository sequence diagram
2
+
3
+ - Components marked as optional are not required and can be ignored.
4
+ - if `url_requester` is not provided, `urls_extractor` will get urls from the `polling_job_response`
5
+ - interpolation_context, e.g. `create_job_response` or `polling_job_response` can be obtained from stream_slice
6
+
7
+
8
+ ```mermaid
9
+ ---
10
+ title: AsyncHttpJobRepository Sequence Diagram
11
+ ---
12
+ sequenceDiagram
13
+ participant AsyncHttpJobRepository as AsyncOrchestrator
14
+ participant CreationRequester as creation_requester
15
+ participant PollingRequester as polling_requester
16
+ participant UrlRequester as url_requester (Optional)
17
+ participant DownloadRetriever as download_retriever
18
+ participant AbortRequester as abort_requester (Optional)
19
+ participant DeleteRequester as delete_requester (Optional)
20
+ participant Reporting Server as Async Reporting Server
21
+
22
+ AsyncHttpJobRepository ->> CreationRequester: Initiate job creation
23
+ CreationRequester ->> Reporting Server: Create job request
24
+ Reporting Server -->> CreationRequester: Job ID response
25
+ CreationRequester -->> AsyncHttpJobRepository: Job ID
26
+
27
+ loop Poll for job status
28
+ AsyncHttpJobRepository ->> PollingRequester: Check job status
29
+ PollingRequester ->> Reporting Server: Status request (interpolation_context: `create_job_response`)
30
+ Reporting Server -->> PollingRequester: Status response
31
+ PollingRequester -->> AsyncHttpJobRepository: Job status
32
+ end
33
+
34
+ alt Status: Ready
35
+ AsyncHttpJobRepository ->> UrlRequester: Request download URLs (if applicable)
36
+ UrlRequester ->> Reporting Server: URL request (interpolation_context: `polling_job_response`)
37
+ Reporting Server -->> UrlRequester: Download URLs
38
+ UrlRequester -->> AsyncHttpJobRepository: Download URLs
39
+
40
+ AsyncHttpJobRepository ->> DownloadRetriever: Download reports
41
+ DownloadRetriever ->> Reporting Server: Retrieve report data (interpolation_context: `url`)
42
+ Reporting Server -->> DownloadRetriever: Report data
43
+ DownloadRetriever -->> AsyncHttpJobRepository: Report data
44
+ else Status: Failed
45
+ AsyncHttpJobRepository ->> AbortRequester: Send abort request
46
+ AbortRequester ->> Reporting Server: Abort job
47
+ Reporting Server -->> AbortRequester: Abort confirmation
48
+ AbortRequester -->> AsyncHttpJobRepository: Confirmation
49
+ end
50
+
51
+ AsyncHttpJobRepository ->> DeleteRequester: Send delete job request
52
+ DeleteRequester ->> Reporting Server: Delete job
53
+ Reporting Server -->> DeleteRequester: Deletion confirmation
54
+ DeleteRequester -->> AsyncHttpJobRepository: Confirmation
55
+
56
+
57
+ ```
@@ -31,6 +31,10 @@ LOGGER = logging.getLogger("airbyte")
31
31
 
32
32
  @dataclass
33
33
  class AsyncHttpJobRepository(AsyncJobRepository):
34
+ """
35
+ See Readme file for more details about flow.
36
+ """
37
+
34
38
  creation_requester: Requester
35
39
  polling_requester: Requester
36
40
  download_retriever: SimpleRetriever
@@ -44,6 +48,9 @@ class AsyncHttpJobRepository(AsyncJobRepository):
44
48
  record_extractor: RecordExtractor = field(
45
49
  init=False, repr=False, default_factory=lambda: ResponseToFileExtractor({})
46
50
  )
51
+ url_requester: Optional[Requester] = (
52
+ None # use it in case polling_requester provides some <id> and extra request is needed to obtain list of urls to download from
53
+ )
47
54
 
48
55
  def __post_init__(self) -> None:
49
56
  self._create_job_response_by_id: Dict[str, Response] = {}
@@ -186,10 +193,13 @@ class AsyncHttpJobRepository(AsyncJobRepository):
186
193
 
187
194
  """
188
195
 
189
- for url in self.urls_extractor.extract_records(
190
- self._polling_job_response_by_id[job.api_job_id()]
191
- ):
192
- stream_slice: StreamSlice = StreamSlice(partition={"url": url}, cursor_slice={})
196
+ for url in self._get_download_url(job):
197
+ job_slice = job.job_parameters()
198
+ stream_slice = StreamSlice(
199
+ partition=job_slice.partition,
200
+ cursor_slice=job_slice.cursor_slice,
201
+ extra_fields={**job_slice.extra_fields, "url": url},
202
+ )
193
203
  for message in self.download_retriever.read_records({}, stream_slice):
194
204
  if isinstance(message, Record):
195
205
  yield message.data
@@ -226,3 +236,22 @@ class AsyncHttpJobRepository(AsyncJobRepository):
226
236
  cursor_slice={},
227
237
  )
228
238
  return stream_slice
239
+
240
+ def _get_download_url(self, job: AsyncJob) -> Iterable[str]:
241
+ if not self.url_requester:
242
+ url_response = self._polling_job_response_by_id[job.api_job_id()]
243
+ else:
244
+ stream_slice: StreamSlice = StreamSlice(
245
+ partition={
246
+ "polling_job_response": self._polling_job_response_by_id[job.api_job_id()]
247
+ },
248
+ cursor_slice={},
249
+ )
250
+ url_response = self.url_requester.send_request(stream_slice=stream_slice) # type: ignore # we expect url_requester to always be presented, otherwise raise an exception as we cannot proceed with the report
251
+ if not url_response:
252
+ raise AirbyteTracedException(
253
+ internal_message="Always expect a response or an exception from url_requester",
254
+ failure_type=FailureType.system_error,
255
+ )
256
+
257
+ yield from self.urls_extractor.extract_records(url_response) # type: ignore # we expect urls_extractor to always return list of strings
@@ -81,10 +81,10 @@ class AbstractOauth2Authenticator(AuthBase):
81
81
  Override to define additional parameters
82
82
  """
83
83
  payload: MutableMapping[str, Any] = {
84
- "grant_type": self.get_grant_type(),
85
- "client_id": self.get_client_id(),
86
- "client_secret": self.get_client_secret(),
87
- "refresh_token": self.get_refresh_token(),
84
+ self.get_grant_type_name(): self.get_grant_type(),
85
+ self.get_client_id_name(): self.get_client_id(),
86
+ self.get_client_secret_name(): self.get_client_secret(),
87
+ self.get_refresh_token_name(): self.get_refresh_token(),
88
88
  }
89
89
 
90
90
  if self.get_scopes():
@@ -206,14 +206,26 @@ class AbstractOauth2Authenticator(AuthBase):
206
206
  def get_token_refresh_endpoint(self) -> Optional[str]:
207
207
  """Returns the endpoint to refresh the access token"""
208
208
 
209
+ @abstractmethod
210
+ def get_client_id_name(self) -> str:
211
+ """The client id name to authenticate"""
212
+
209
213
  @abstractmethod
210
214
  def get_client_id(self) -> str:
211
215
  """The client id to authenticate"""
212
216
 
217
+ @abstractmethod
218
+ def get_client_secret_name(self) -> str:
219
+ """The client secret name to authenticate"""
220
+
213
221
  @abstractmethod
214
222
  def get_client_secret(self) -> str:
215
223
  """The client secret to authenticate"""
216
224
 
225
+ @abstractmethod
226
+ def get_refresh_token_name(self) -> str:
227
+ """The refresh token name to authenticate"""
228
+
217
229
  @abstractmethod
218
230
  def get_refresh_token(self) -> Optional[str]:
219
231
  """The token used to refresh the access token when it expires"""
@@ -246,6 +258,10 @@ class AbstractOauth2Authenticator(AuthBase):
246
258
  def get_grant_type(self) -> str:
247
259
  """Returns grant_type specified for requesting access_token"""
248
260
 
261
+ @abstractmethod
262
+ def get_grant_type_name(self) -> str:
263
+ """Returns grant_type specified name for requesting access_token"""
264
+
249
265
  @property
250
266
  @abstractmethod
251
267
  def access_token(self) -> str:
@@ -30,12 +30,16 @@ class Oauth2Authenticator(AbstractOauth2Authenticator):
30
30
  client_id: str,
31
31
  client_secret: str,
32
32
  refresh_token: str,
33
+ client_id_name: str = "client_id",
34
+ client_secret_name: str = "client_secret",
35
+ refresh_token_name: str = "refresh_token",
33
36
  scopes: List[str] | None = None,
34
37
  token_expiry_date: pendulum.DateTime | None = None,
35
38
  token_expiry_date_format: str | None = None,
36
39
  access_token_name: str = "access_token",
37
40
  expires_in_name: str = "expires_in",
38
41
  refresh_request_body: Mapping[str, Any] | None = None,
42
+ grant_type_name: str = "grant_type",
39
43
  grant_type: str = "refresh_token",
40
44
  token_expiry_is_time_of_expiration: bool = False,
41
45
  refresh_token_error_status_codes: Tuple[int, ...] = (),
@@ -43,13 +47,17 @@ class Oauth2Authenticator(AbstractOauth2Authenticator):
43
47
  refresh_token_error_values: Tuple[str, ...] = (),
44
48
  ):
45
49
  self._token_refresh_endpoint = token_refresh_endpoint
50
+ self._client_secret_name = client_secret_name
46
51
  self._client_secret = client_secret
52
+ self._client_id_name = client_id_name
47
53
  self._client_id = client_id
54
+ self._refresh_token_name = refresh_token_name
48
55
  self._refresh_token = refresh_token
49
56
  self._scopes = scopes
50
57
  self._access_token_name = access_token_name
51
58
  self._expires_in_name = expires_in_name
52
59
  self._refresh_request_body = refresh_request_body
60
+ self._grant_type_name = grant_type_name
53
61
  self._grant_type = grant_type
54
62
 
55
63
  self._token_expiry_date = token_expiry_date or pendulum.now().subtract(days=1) # type: ignore [no-untyped-call]
@@ -63,12 +71,21 @@ class Oauth2Authenticator(AbstractOauth2Authenticator):
63
71
  def get_token_refresh_endpoint(self) -> str:
64
72
  return self._token_refresh_endpoint
65
73
 
74
+ def get_client_id_name(self) -> str:
75
+ return self._client_id_name
76
+
66
77
  def get_client_id(self) -> str:
67
78
  return self._client_id
68
79
 
80
+ def get_client_secret_name(self) -> str:
81
+ return self._client_secret_name
82
+
69
83
  def get_client_secret(self) -> str:
70
84
  return self._client_secret
71
85
 
86
+ def get_refresh_token_name(self) -> str:
87
+ return self._refresh_token_name
88
+
72
89
  def get_refresh_token(self) -> str:
73
90
  return self._refresh_token
74
91
 
@@ -84,6 +101,9 @@ class Oauth2Authenticator(AbstractOauth2Authenticator):
84
101
  def get_refresh_request_body(self) -> Mapping[str, Any]:
85
102
  return self._refresh_request_body # type: ignore [return-value]
86
103
 
104
+ def get_grant_type_name(self) -> str:
105
+ return self._grant_type_name
106
+
87
107
  def get_grant_type(self) -> str:
88
108
  return self._grant_type
89
109
 
@@ -129,8 +149,11 @@ class SingleUseRefreshTokenOauth2Authenticator(Oauth2Authenticator):
129
149
  expires_in_name: str = "expires_in",
130
150
  refresh_token_name: str = "refresh_token",
131
151
  refresh_request_body: Mapping[str, Any] | None = None,
152
+ grant_type_name: str = "grant_type",
132
153
  grant_type: str = "refresh_token",
154
+ client_id_name: str = "client_id",
133
155
  client_id: Optional[str] = None,
156
+ client_secret_name: str = "client_secret",
134
157
  client_secret: Optional[str] = None,
135
158
  access_token_config_path: Sequence[str] = ("credentials", "access_token"),
136
159
  refresh_token_config_path: Sequence[str] = ("credentials", "refresh_token"),
@@ -174,23 +197,30 @@ class SingleUseRefreshTokenOauth2Authenticator(Oauth2Authenticator):
174
197
  ("credentials", "client_secret"),
175
198
  )
176
199
  )
200
+ self._client_id_name = client_id_name
201
+ self._client_secret_name = client_secret_name
177
202
  self._access_token_config_path = access_token_config_path
178
203
  self._refresh_token_config_path = refresh_token_config_path
179
204
  self._token_expiry_date_config_path = token_expiry_date_config_path
180
205
  self._token_expiry_date_format = token_expiry_date_format
181
206
  self._refresh_token_name = refresh_token_name
207
+ self._grant_type_name = grant_type_name
182
208
  self._connector_config = connector_config
183
209
  self.__message_repository = message_repository
184
210
  super().__init__(
185
- token_refresh_endpoint,
186
- self.get_client_id(),
187
- self.get_client_secret(),
188
- self.get_refresh_token(),
211
+ token_refresh_endpoint=token_refresh_endpoint,
212
+ client_id_name=self._client_id_name,
213
+ client_id=self.get_client_id(),
214
+ client_secret_name=self._client_secret_name,
215
+ client_secret=self.get_client_secret(),
216
+ refresh_token=self.get_refresh_token(),
217
+ refresh_token_name=self._refresh_token_name,
189
218
  scopes=scopes,
190
219
  token_expiry_date=self.get_token_expiry_date(),
191
220
  access_token_name=access_token_name,
192
221
  expires_in_name=expires_in_name,
193
222
  refresh_request_body=refresh_request_body,
223
+ grant_type_name=self._grant_type_name,
194
224
  grant_type=grant_type,
195
225
  token_expiry_date_format=token_expiry_date_format,
196
226
  token_expiry_is_time_of_expiration=token_expiry_is_time_of_expiration,
@@ -152,3 +152,6 @@ class StreamSlice(Mapping[str, Any]):
152
152
 
153
153
  def __hash__(self) -> int:
154
154
  return hash(orjson.dumps(self._stream_slice, option=orjson.OPT_SORT_KEYS))
155
+
156
+ def __bool__(self) -> bool:
157
+ return bool(self._stream_slice) or bool(self._extra_fields)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: airbyte-cdk
3
- Version: 6.18.0.dev1
3
+ Version: 6.18.1
4
4
  Summary: A framework for writing Airbyte Connectors.
5
5
  License: MIT
6
6
  Keywords: airbyte,connector-development-kit,cdk
@@ -53,7 +53,7 @@ airbyte_cdk/sources/declarative/async_job/timer.py,sha256=Fb8P72CQ7jIzJyzMSSNuBf
53
53
  airbyte_cdk/sources/declarative/auth/__init__.py,sha256=e2CRrcBWGhz3sQu3Oh34d1riEIwXipGS8hrSB1pu0Oo,284
54
54
  airbyte_cdk/sources/declarative/auth/declarative_authenticator.py,sha256=nf-OmRUHYG4ORBwyb5CANzuHEssE-oNmL-Lccn41Td8,1099
55
55
  airbyte_cdk/sources/declarative/auth/jwt.py,sha256=7r5q1zOekjw8kEmEk1oUyovzVt3cbD6BuFnRILeLZi8,8250
56
- airbyte_cdk/sources/declarative/auth/oauth.py,sha256=Yr0ljFjln9FIWudQohXARyKEo6-4ACG840pZoi6JVrE,9165
56
+ airbyte_cdk/sources/declarative/auth/oauth.py,sha256=EDx-tY0ZhBXe6yVHkqjUAqMWJAl4rQXjQbr4rElt_Ds,10555
57
57
  airbyte_cdk/sources/declarative/auth/selective_authenticator.py,sha256=qGwC6YsCldr1bIeKG6Qo-A9a5cTdHw-vcOn3OtQrS4c,1540
58
58
  airbyte_cdk/sources/declarative/auth/token.py,sha256=r4u3WXyVa7WmiSZ9-eZXlrUI-pS0D4YWJnwjLzwV-Fk,11210
59
59
  airbyte_cdk/sources/declarative/auth/token_provider.py,sha256=9oq3dcBPAPwXSfkISjhA05dMhIzxaDQTmwOydBrnsMk,3028
@@ -66,11 +66,11 @@ airbyte_cdk/sources/declarative/concurrent_declarative_source.py,sha256=tSTCSmyM
66
66
  airbyte_cdk/sources/declarative/datetime/__init__.py,sha256=l9LG7Qm6e5r_qgqfVKnx3mXYtg1I9MmMjomVIPfU4XA,177
67
67
  airbyte_cdk/sources/declarative/datetime/datetime_parser.py,sha256=SX9JjdesN1edN2WVUVMzU_ptqp2QB1OnsnjZ4mwcX7w,2579
68
68
  airbyte_cdk/sources/declarative/datetime/min_max_datetime.py,sha256=0BHBtDNQZfvwM45-tY5pNlTcKAFSGGNxemoi0Jic-0E,5785
69
- airbyte_cdk/sources/declarative/declarative_component_schema.yaml,sha256=QDqDyKmkYDDW3fXA8ImE61p4v_sBNQnqnV-uX_qNHNM,133531
69
+ airbyte_cdk/sources/declarative/declarative_component_schema.yaml,sha256=00X3palFmBp9WqQugXgtzFVn7s17KYWKTrn83ObmBzc,134673
70
70
  airbyte_cdk/sources/declarative/declarative_source.py,sha256=nF7wBqFd3AQmEKAm4CnIo29CJoQL562cJGSCeL8U8bA,1531
71
71
  airbyte_cdk/sources/declarative/declarative_stream.py,sha256=JRyNeOIpsFu4ztVZsN6sncqUEIqIE-bUkD2TPgbMgk0,10375
72
72
  airbyte_cdk/sources/declarative/decoders/__init__.py,sha256=edGj4fGxznBk4xzRQyCA1rGfbpqe7z-RE0K3kQQWbgA,858
73
- airbyte_cdk/sources/declarative/decoders/composite_raw_decoder.py,sha256=rSvqdGsVgBT3ZfY_bthjZl_OmxY84iKz8g9GQIWyq8k,3766
73
+ airbyte_cdk/sources/declarative/decoders/composite_raw_decoder.py,sha256=-aO3ujXX9YTP2ZDvI2BP-x0VOKdAq2TlHo4zG8DCTlY,2748
74
74
  airbyte_cdk/sources/declarative/decoders/decoder.py,sha256=sl-Gt8lXi7yD2Q-sD8je5QS2PbgrgsYjxRLWsay7DMc,826
75
75
  airbyte_cdk/sources/declarative/decoders/json_decoder.py,sha256=qdbjeR6RffKaah_iWvMsOcDolYuxJY5DaI3b9AMTZXg,3327
76
76
  airbyte_cdk/sources/declarative/decoders/noop_decoder.py,sha256=iZh0yKY_JzgBnJWiubEusf5c0o6Khd-8EWFWT-8EgFo,542
@@ -106,12 +106,12 @@ airbyte_cdk/sources/declarative/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW
106
106
  airbyte_cdk/sources/declarative/migrations/legacy_to_per_partition_state_migration.py,sha256=iemy3fKLczcU0-Aor7tx5jcT6DRedKMqyK7kCOp01hg,3924
107
107
  airbyte_cdk/sources/declarative/migrations/state_migration.py,sha256=KWPjealMLKSMtajXgkdGgKg7EmTLR-CqqD7UIh0-eDU,794
108
108
  airbyte_cdk/sources/declarative/models/__init__.py,sha256=nUFxNCiKeYRVXuZEKA7GD-lTHxsiKcQ8FitZjKhPIvE,100
109
- airbyte_cdk/sources/declarative/models/declarative_component_schema.py,sha256=SpMwCe-6NZTxICSFIXzwlAnAwNLlC8xS12ncEC1NcbA,93536
109
+ airbyte_cdk/sources/declarative/models/declarative_component_schema.py,sha256=1wrAW9XeEq2xdUAAkmHcelka-LOwyYb-izRcACkNPKM,94915
110
110
  airbyte_cdk/sources/declarative/parsers/__init__.py,sha256=ZnqYNxHsKCgO38IwB34RQyRMXTs4GTvlRi3ImKnIioo,61
111
111
  airbyte_cdk/sources/declarative/parsers/custom_exceptions.py,sha256=Rir9_z3Kcd5Es0-LChrzk-0qubAsiK_RSEnLmK2OXm8,553
112
112
  airbyte_cdk/sources/declarative/parsers/manifest_component_transformer.py,sha256=CXwTfD3wSQq3okcqwigpprbHhSURUokh4GK2OmOyKC8,9132
113
113
  airbyte_cdk/sources/declarative/parsers/manifest_reference_resolver.py,sha256=IWUOdF03o-aQn0Occo1BJCxU0Pz-QILk5L67nzw2thw,6803
114
- airbyte_cdk/sources/declarative/parsers/model_to_component_factory.py,sha256=lmSh2Yp-lgRTbbSw3m6UH8L2nTRjt0w3aiISWHRG6IM,109739
114
+ airbyte_cdk/sources/declarative/parsers/model_to_component_factory.py,sha256=NElLb7eLDVmxDgtTX9fQ-ZPrpfH3d7RpMDaQiLtvuuQ,110550
115
115
  airbyte_cdk/sources/declarative/partition_routers/__init__.py,sha256=HJ-Syp3p7RpyR_OK0X_a2kSyISfu3W-PKrRI16iY0a8,957
116
116
  airbyte_cdk/sources/declarative/partition_routers/async_job_partition_router.py,sha256=n82J15S8bjeMZ5uROu--P3hnbQoxkY5v7RPHYx7g7ro,2929
117
117
  airbyte_cdk/sources/declarative/partition_routers/cartesian_product_stream_slicer.py,sha256=c5cuVFM6NFkuQqG8Z5IwkBuwDrvXZN1CunUOM_L0ezg,6892
@@ -119,6 +119,7 @@ airbyte_cdk/sources/declarative/partition_routers/list_partition_router.py,sha25
119
119
  airbyte_cdk/sources/declarative/partition_routers/partition_router.py,sha256=YyEIzdmLd1FjbVP3QbQ2VFCLW_P-OGbVh6VpZShp54k,2218
120
120
  airbyte_cdk/sources/declarative/partition_routers/single_partition_router.py,sha256=SKzKjSyfccq4dxGIh-J6ejrgkCHzaiTIazmbmeQiRD4,1942
121
121
  airbyte_cdk/sources/declarative/partition_routers/substream_partition_router.py,sha256=5bgXoJfBg_6i53krQMptAGb50XB5XoVfqQxKQhlLtBA,15383
122
+ airbyte_cdk/sources/declarative/requesters/README.md,sha256=WabtHlwHg_J34aL1Kwm8vboYqBaSgsFjq10qR-P2sx8,2658
122
123
  airbyte_cdk/sources/declarative/requesters/__init__.py,sha256=d7a3OoHbqaJDyyPli3nqqJ2yAW_SLX6XDaBAKOwvpxw,364
123
124
  airbyte_cdk/sources/declarative/requesters/error_handlers/__init__.py,sha256=SkEDcJxlT1683rNx93K9whoS0OyUukkuOfToGtgpF58,776
124
125
  airbyte_cdk/sources/declarative/requesters/error_handlers/backoff_strategies/__init__.py,sha256=1WZdpFmWL6W_Dko0qjflTaKIWeqt8jHT-D6HcujIp3s,884
@@ -133,7 +134,7 @@ airbyte_cdk/sources/declarative/requesters/error_handlers/default_error_handler.
133
134
  airbyte_cdk/sources/declarative/requesters/error_handlers/default_http_response_filter.py,sha256=q0YkeYUUWO6iErUy0vjqiOkhg8_9d5YcCmtlpXAJJ9E,1314
134
135
  airbyte_cdk/sources/declarative/requesters/error_handlers/error_handler.py,sha256=Tan66odx8VHzfdyyXMQkXz2pJYksllGqvxmpoajgcK4,669
135
136
  airbyte_cdk/sources/declarative/requesters/error_handlers/http_response_filter.py,sha256=vhWsEKNTYEzZ4gerhHqnDNKu4wGIP485NAzpSQ5DRZg,7941
136
- airbyte_cdk/sources/declarative/requesters/http_job_repository.py,sha256=o0520AmHMb7SAoeokVNwoOzuZzIAT6ryx9uFYGSOrs0,8664
137
+ airbyte_cdk/sources/declarative/requesters/http_job_repository.py,sha256=3GtOefPH08evlSUxaILkiKLTHbIspFY4qd5B3ZqNE60,10063
137
138
  airbyte_cdk/sources/declarative/requesters/http_requester.py,sha256=RqYPkgJFAWfcZBTc-JBcGHPm4JL1ZQOhs9GKU4MP2eE,14723
138
139
  airbyte_cdk/sources/declarative/requesters/paginators/__init__.py,sha256=uArbKs9JKNCt7t9tZoeWwjDpyI1HoPp29FNW0JzvaEM,644
139
140
  airbyte_cdk/sources/declarative/requesters/paginators/default_paginator.py,sha256=FnSl3qPvv5wD6ieAI2Ic5c4dqBk-3fRe4tCaWzq3YwM,11840
@@ -287,12 +288,12 @@ airbyte_cdk/sources/streams/http/http.py,sha256=JAMpiTdS9HFNOlwayWNvQdxoqs2rpW9w
287
288
  airbyte_cdk/sources/streams/http/http_client.py,sha256=tDE0ROtxjGMVphvsw8INvGMtZ97hIF-v47pZ3jIyiwc,23011
288
289
  airbyte_cdk/sources/streams/http/rate_limiting.py,sha256=IwdjrHKUnU97XO4qONgYRv4YYW51xQ8SJm4WLafXDB8,6351
289
290
  airbyte_cdk/sources/streams/http/requests_native_auth/__init__.py,sha256=RN0D3nOX1xLgwEwKWu6pkGy3XqBFzKSNZ8Lf6umU2eY,413
290
- airbyte_cdk/sources/streams/http/requests_native_auth/abstract_oauth.py,sha256=sxmrQKAvN8piamssL3xh8KXevTwdaXuLs2O0hNEA5aQ,10635
291
+ airbyte_cdk/sources/streams/http/requests_native_auth/abstract_oauth.py,sha256=xX-qKbMVN-OTwNda-B6cVQqnQrNDGBnvavAcSvXK2wU,11179
291
292
  airbyte_cdk/sources/streams/http/requests_native_auth/abstract_token.py,sha256=Y3n7J-sk5yGjv_OxtY6Z6k0PEsFZmtIRi-x0KCbaHdA,1010
292
- airbyte_cdk/sources/streams/http/requests_native_auth/oauth.py,sha256=ka-bBRWvIv09LmZNYl49p2lK9nd_Tvi2g0lIp3OkU40,14872
293
+ airbyte_cdk/sources/streams/http/requests_native_auth/oauth.py,sha256=wjsp4Xf8u3AnY7ZmTTGfLnfj6ztDBogR5biURkqcwCA,16156
293
294
  airbyte_cdk/sources/streams/http/requests_native_auth/token.py,sha256=h5PTzcdH-RQLeCg7xZ45w_484OPUDSwNWl_iMJQmZoI,2526
294
295
  airbyte_cdk/sources/streams/utils/__init__.py,sha256=4Hw-PX1-VgESLF16cDdvuYCzGJtHntThLF4qIiULWeo,61
295
- airbyte_cdk/sources/types.py,sha256=WWVigI7ZSoQU2TBCzDsHJtoX4Ima9v--lcLyYwUG_cE,4904
296
+ airbyte_cdk/sources/types.py,sha256=nLPkTpyfGV4E6e99qcBWX4r8C3fE4I8Fvgx2EjvT9ic,5005
296
297
  airbyte_cdk/sources/utils/__init__.py,sha256=TTN6VUxVy6Is8BhYQZR5pxJGQh8yH4duXh4O1TiMiEY,118
297
298
  airbyte_cdk/sources/utils/casing.py,sha256=QC-gV1O4e8DR4-bhdXieUPKm_JamzslVyfABLYYRSXA,256
298
299
  airbyte_cdk/sources/utils/record_helper.py,sha256=jeB0mucudzna7Zvj-pCBbwFrbLJ36SlAWZTh5O4Fb9Y,2168
@@ -342,8 +343,8 @@ airbyte_cdk/utils/slice_hasher.py,sha256=-pHexlNYoWYPnXNH-M7HEbjmeJe9Zk7SJijdQ7d
342
343
  airbyte_cdk/utils/spec_schema_transformations.py,sha256=-5HTuNsnDBAhj-oLeQXwpTGA0HdcjFOf2zTEMUTTg_Y,816
343
344
  airbyte_cdk/utils/stream_status_utils.py,sha256=ZmBoiy5HVbUEHAMrUONxZvxnvfV9CesmQJLDTAIWnWw,1171
344
345
  airbyte_cdk/utils/traced_exception.py,sha256=C8uIBuCL_E4WnBAOPSxBicD06JAldoN9fGsQDp463OY,6292
345
- airbyte_cdk-6.18.0.dev1.dist-info/LICENSE.txt,sha256=Wfe61S4BaGPj404v8lrAbvhjYR68SHlkzeYrg3_bbuM,1051
346
- airbyte_cdk-6.18.0.dev1.dist-info/METADATA,sha256=ALXOgvI3pTcF2tNmvbQ9S8fG424n229th_tx1u2uSCo,6005
347
- airbyte_cdk-6.18.0.dev1.dist-info/WHEEL,sha256=IYZQI976HJqqOpQU6PHkJ8fb3tMNBFjg-Cn-pwAbaFM,88
348
- airbyte_cdk-6.18.0.dev1.dist-info/entry_points.txt,sha256=fj-e3PAQvsxsQzyyq8UkG1k8spunWnD4BAH2AwlR6NM,95
349
- airbyte_cdk-6.18.0.dev1.dist-info/RECORD,,
346
+ airbyte_cdk-6.18.1.dist-info/LICENSE.txt,sha256=Wfe61S4BaGPj404v8lrAbvhjYR68SHlkzeYrg3_bbuM,1051
347
+ airbyte_cdk-6.18.1.dist-info/METADATA,sha256=OMpca59Gc1MJOlwEgvDJX0uwp7skSel83qkbtcan6hE,6000
348
+ airbyte_cdk-6.18.1.dist-info/WHEEL,sha256=IYZQI976HJqqOpQU6PHkJ8fb3tMNBFjg-Cn-pwAbaFM,88
349
+ airbyte_cdk-6.18.1.dist-info/entry_points.txt,sha256=fj-e3PAQvsxsQzyyq8UkG1k8spunWnD4BAH2AwlR6NM,95
350
+ airbyte_cdk-6.18.1.dist-info/RECORD,,