airbyte-cdk 6.48.0__py3-none-any.whl → 6.48.2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (29) hide show
  1. airbyte_cdk/connector_builder/connector_builder_handler.py +11 -0
  2. airbyte_cdk/connector_builder/test_reader/reader.py +11 -0
  3. airbyte_cdk/manifest_migrations/README.md +73 -0
  4. airbyte_cdk/manifest_migrations/__init__.py +3 -0
  5. airbyte_cdk/manifest_migrations/exceptions.py +12 -0
  6. airbyte_cdk/manifest_migrations/manifest_migration.py +134 -0
  7. airbyte_cdk/manifest_migrations/migration_handler.py +163 -0
  8. airbyte_cdk/manifest_migrations/migrations/__init__.py +4 -0
  9. airbyte_cdk/manifest_migrations/migrations/http_requester_path_to_url.py +57 -0
  10. airbyte_cdk/manifest_migrations/migrations/http_requester_request_body_json_data_to_request_body.py +51 -0
  11. airbyte_cdk/manifest_migrations/migrations/http_requester_url_base_to_url.py +41 -0
  12. airbyte_cdk/manifest_migrations/migrations/registry.yaml +22 -0
  13. airbyte_cdk/manifest_migrations/migrations_registry.py +76 -0
  14. airbyte_cdk/sources/declarative/declarative_component_schema.yaml +80 -5
  15. airbyte_cdk/sources/declarative/declarative_source.py +10 -1
  16. airbyte_cdk/sources/declarative/interpolation/interpolated_nested_mapping.py +1 -1
  17. airbyte_cdk/sources/declarative/manifest_declarative_source.py +32 -7
  18. airbyte_cdk/sources/declarative/models/base_model_with_deprecations.py +144 -0
  19. airbyte_cdk/sources/declarative/models/declarative_component_schema.py +54 -5
  20. airbyte_cdk/sources/declarative/parsers/model_to_component_factory.py +66 -15
  21. airbyte_cdk/sources/declarative/requesters/http_requester.py +62 -17
  22. airbyte_cdk/sources/declarative/requesters/request_options/interpolated_request_options_provider.py +24 -2
  23. airbyte_cdk/sources/declarative/requesters/requester.py +12 -0
  24. {airbyte_cdk-6.48.0.dist-info → airbyte_cdk-6.48.2.dist-info}/METADATA +1 -1
  25. {airbyte_cdk-6.48.0.dist-info → airbyte_cdk-6.48.2.dist-info}/RECORD +29 -17
  26. {airbyte_cdk-6.48.0.dist-info → airbyte_cdk-6.48.2.dist-info}/LICENSE.txt +0 -0
  27. {airbyte_cdk-6.48.0.dist-info → airbyte_cdk-6.48.2.dist-info}/LICENSE_SHORT +0 -0
  28. {airbyte_cdk-6.48.0.dist-info → airbyte_cdk-6.48.2.dist-info}/WHEEL +0 -0
  29. {airbyte_cdk-6.48.0.dist-info → airbyte_cdk-6.48.2.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,76 @@
1
+ #
2
+ # Copyright (c) 2025 Airbyte, Inc., all rights reserved.
3
+ #
4
+
5
+
6
+ import importlib
7
+ import inspect
8
+ import os
9
+ from pathlib import Path
10
+ from types import ModuleType
11
+ from typing import Dict, List, Type
12
+
13
+ import yaml
14
+
15
+ from airbyte_cdk.manifest_migrations.manifest_migration import (
16
+ ManifestMigration,
17
+ )
18
+
19
+ DiscoveredMigrations = Dict[str, List[Type[ManifestMigration]]]
20
+
21
+ MIGRATIONS_PATH = Path(__file__).parent / "migrations"
22
+ REGISTRY_PATH = MIGRATIONS_PATH / "registry.yaml"
23
+
24
+
25
+ def _find_migration_module(name: str) -> str:
26
+ """
27
+ Finds the migration module by name in the migrations directory.
28
+ The name should match the file name of the migration module (without the .py extension).
29
+ Raises ImportError if the module is not found.
30
+ """
31
+
32
+ for migration_file in os.listdir(MIGRATIONS_PATH):
33
+ migration_name = name + ".py"
34
+ if migration_file == migration_name:
35
+ return migration_file.replace(".py", "")
36
+
37
+ raise ImportError(f"Migration module '{name}' not found in {MIGRATIONS_PATH}.")
38
+
39
+
40
+ def _get_migration_class(module: ModuleType) -> Type[ManifestMigration]:
41
+ """
42
+ Returns the ManifestMigration subclass defined in the module.
43
+ """
44
+ for _, obj in inspect.getmembers(module, inspect.isclass):
45
+ if issubclass(obj, ManifestMigration):
46
+ return obj
47
+
48
+ raise ImportError(f"No ManifestMigration subclass found in module {module.__name__}.")
49
+
50
+
51
+ def _discover_migrations() -> DiscoveredMigrations:
52
+ """
53
+ Discovers and returns a list of ManifestMigration subclasses in the order specified by registry.yaml.
54
+ """
55
+ with open(REGISTRY_PATH, "r") as f:
56
+ registry = yaml.safe_load(f)
57
+ migrations: DiscoveredMigrations = {}
58
+ # Iterate through the registry and import the migration classes
59
+ # based on the version and order specified in the registry.yaml
60
+ for version_entry in registry.get("manifest_migrations", []):
61
+ migration_version = version_entry.get("version", "0.0.0")
62
+ if not migration_version in migrations:
63
+ migrations[migration_version] = []
64
+
65
+ for migration in sorted(version_entry.get("migrations", []), key=lambda m: m["order"]):
66
+ module = importlib.import_module(
67
+ f"airbyte_cdk.manifest_migrations.migrations.{_find_migration_module(migration['name'])}"
68
+ )
69
+ migration_class = _get_migration_class(module)
70
+ migrations[migration_version].append(migration_class)
71
+
72
+ return migrations
73
+
74
+
75
+ # registered migrations
76
+ MANIFEST_MIGRATIONS: DiscoveredMigrations = _discover_migrations()
@@ -1911,15 +1911,16 @@ definitions:
1911
1911
  type: object
1912
1912
  required:
1913
1913
  - type
1914
- - url_base
1915
1914
  properties:
1916
1915
  type:
1917
1916
  type: string
1918
1917
  enum: [HttpRequester]
1919
1918
  url_base:
1920
- linkable: true
1919
+ deprecated: true
1920
+ deprecation_message: "Use `url` field instead."
1921
1921
  title: API Base URL
1922
- description: The Base URL of the API source. Do not put sensitive information (e.g. API tokens) into this field - Use the Authentication component for this.
1922
+ description: Deprecated, use the `url` instead. Base URL of the API source. Do not put sensitive information (e.g. API tokens) into this field - Use the Authentication component for this.
1923
+ linkable: true
1923
1924
  type: string
1924
1925
  interpolation_context:
1925
1926
  - config
@@ -1935,9 +1936,29 @@ definitions:
1935
1936
  - "{{ config['base_url'] or 'https://app.posthog.com'}}/api"
1936
1937
  - "https://connect.squareup.com/v2/quotes/{{ stream_partition['id'] }}/quote_line_groups"
1937
1938
  - "https://example.com/api/v1/resource/{{ next_page_token['id'] }}"
1939
+ url:
1940
+ title: The URL of an API endpoint
1941
+ description: The URL of the API source. Do not put sensitive information (e.g. API tokens) into this field - Use the Authentication component for this.
1942
+ type: string
1943
+ interpolation_context:
1944
+ - config
1945
+ - next_page_token
1946
+ - stream_interval
1947
+ - stream_partition
1948
+ - stream_slice
1949
+ - creation_response
1950
+ - polling_response
1951
+ - download_target
1952
+ examples:
1953
+ - "https://connect.squareup.com/v2"
1954
+ - "{{ config['url'] or 'https://app.posthog.com'}}/api"
1955
+ - "https://connect.squareup.com/v2/quotes/{{ stream_partition['id'] }}/quote_line_groups"
1956
+ - "https://example.com/api/v1/resource/{{ next_page_token['id'] }}"
1938
1957
  path:
1958
+ deprecated: true
1959
+ deprecation_message: "Use `url` field instead."
1939
1960
  title: URL Path
1940
- description: The Path the specific API endpoint that this stream represents. Do not put sensitive information (e.g. API tokens) into this field - Use the Authentication component for this.
1961
+ description: Deprecated, use the `url` instead. Path the specific API endpoint that this stream represents. Do not put sensitive information (e.g. API tokens) into this field - Use the Authentication component for this.
1941
1962
  type: string
1942
1963
  interpolation_context:
1943
1964
  - config
@@ -1983,6 +2004,8 @@ definitions:
1983
2004
  description: Allows for retrieving a dynamic set of properties from an API endpoint which can be injected into outbound request using the stream_partition.extra_fields.
1984
2005
  "$ref": "#/definitions/PropertiesFromEndpoint"
1985
2006
  request_body_data:
2007
+ deprecated: true
2008
+ deprecation_message: "Use `request_body` field instead."
1986
2009
  title: Request Body Payload (Non-JSON)
1987
2010
  description: Specifies how to populate the body of the request with a non-JSON payload. Plain text will be sent as is, whereas objects will be converted to a urlencoded form.
1988
2011
  anyOf:
@@ -2001,6 +2024,8 @@ definitions:
2001
2024
  [{"value": {{ stream_interval['start_time'] | int * 1000 }} }]
2002
2025
  }, "orderBy": 1, "columnName": "Timestamp"}]/
2003
2026
  request_body_json:
2027
+ deprecated: true
2028
+ deprecation_message: "Use `request_body` field instead."
2004
2029
  title: Request Body JSON Payload
2005
2030
  description: Specifies how to populate the body of the request with a JSON payload. Can contain nested objects.
2006
2031
  anyOf:
@@ -2019,6 +2044,35 @@ definitions:
2019
2044
  - sort:
2020
2045
  field: "updated_at"
2021
2046
  order: "ascending"
2047
+ request_body:
2048
+ title: Request Body Payload to be send as a part of the API request.
2049
+ description: Specifies how to populate the body of the request with a payload. Can contain nested objects.
2050
+ anyOf:
2051
+ - "$ref": "#/definitions/RequestBody"
2052
+ interpolation_context:
2053
+ - next_page_token
2054
+ - stream_interval
2055
+ - stream_partition
2056
+ - stream_slice
2057
+ examples:
2058
+ - type: RequestBodyJson
2059
+ value:
2060
+ sort_order: "ASC"
2061
+ sort_field: "CREATED_AT"
2062
+ - type: RequestBodyJson
2063
+ value:
2064
+ key: "{{ config['value'] }}"
2065
+ - type: RequestBodyJson
2066
+ value:
2067
+ sort:
2068
+ field: "updated_at"
2069
+ order: "ascending"
2070
+ - type: RequestBodyData
2071
+ value: "plain_text_body"
2072
+ - type: RequestBodyData
2073
+ value:
2074
+ param1: "value1"
2075
+ param2: "{{ config['param2_value'] }}"
2022
2076
  request_headers:
2023
2077
  title: Request Headers
2024
2078
  description: Return any non-auth headers. Authentication headers will overwrite any overlapping headers returned from this method.
@@ -4019,6 +4073,27 @@ definitions:
4019
4073
  - type
4020
4074
  - stream_template
4021
4075
  - components_resolver
4076
+ RequestBody:
4077
+ type: object
4078
+ description: The request body payload. Can be either URL encoded data or JSON.
4079
+ properties:
4080
+ type:
4081
+ anyOf:
4082
+ - type: string
4083
+ enum: [RequestBodyData]
4084
+ - type: string
4085
+ enum: [RequestBodyJson]
4086
+ value:
4087
+ anyOf:
4088
+ - type: string
4089
+ description: The request body payload as a string.
4090
+ - type: object
4091
+ description: The request body payload as a Non-JSON object (url-encoded data).
4092
+ additionalProperties:
4093
+ type: string
4094
+ - type: object
4095
+ description: The request body payload as a JSON object (json-encoded data).
4096
+ additionalProperties: true
4022
4097
  interpolation:
4023
4098
  variables:
4024
4099
  - title: config
@@ -4227,4 +4302,4 @@ interpolation:
4227
4302
  regex: The regular expression to search for. It must include a capture group.
4228
4303
  return_type: str
4229
4304
  examples:
4230
- - '{{ "goodbye, cruel world" | regex_search("goodbye,\s(.*)$") }} -> "cruel world"'
4305
+ - '{{ "goodbye, cruel world" | regex_search("goodbye,\s(.*)$") }} -> "cruel world"'
@@ -4,8 +4,11 @@
4
4
 
5
5
  import logging
6
6
  from abc import abstractmethod
7
- from typing import Any, Mapping, Tuple
7
+ from typing import Any, List, Mapping, Tuple
8
8
 
9
+ from airbyte_cdk.connector_builder.models import (
10
+ LogMessage as ConnectorBuilderLogMessage,
11
+ )
9
12
  from airbyte_cdk.sources.abstract_source import AbstractSource
10
13
  from airbyte_cdk.sources.declarative.checks.connection_checker import ConnectionChecker
11
14
 
@@ -34,3 +37,9 @@ class DeclarativeSource(AbstractSource):
34
37
  The error object will be cast to string to display the problem to the user.
35
38
  """
36
39
  return self.connection_checker.check_connection(self, logger, config)
40
+
41
+ def deprecation_warnings(self) -> List[ConnectorBuilderLogMessage]:
42
+ """
43
+ Returns a list of deprecation warnings for the source.
44
+ """
45
+ return []
@@ -12,7 +12,7 @@ from airbyte_cdk.sources.types import Config
12
12
  NestedMappingEntry = Union[
13
13
  dict[str, "NestedMapping"], list["NestedMapping"], str, int, float, bool, None
14
14
  ]
15
- NestedMapping = Union[dict[str, NestedMappingEntry], str]
15
+ NestedMapping = Union[dict[str, NestedMappingEntry], str, dict[str, Any]]
16
16
 
17
17
 
18
18
  @dataclass
@@ -15,6 +15,12 @@ from jsonschema.exceptions import ValidationError
15
15
  from jsonschema.validators import validate
16
16
  from packaging.version import InvalidVersion, Version
17
17
 
18
+ from airbyte_cdk.connector_builder.models import (
19
+ LogMessage as ConnectorBuilderLogMessage,
20
+ )
21
+ from airbyte_cdk.manifest_migrations.migration_handler import (
22
+ ManifestMigrationHandler,
23
+ )
18
24
  from airbyte_cdk.models import (
19
25
  AirbyteConnectionStatus,
20
26
  AirbyteMessage,
@@ -91,6 +97,7 @@ class ManifestDeclarativeSource(DeclarativeSource):
91
97
  debug: bool = False,
92
98
  emit_connector_builder_messages: bool = False,
93
99
  component_factory: Optional[ModelToComponentFactory] = None,
100
+ migrate_manifest: Optional[bool] = False,
94
101
  normalize_manifest: Optional[bool] = False,
95
102
  ) -> None:
96
103
  """
@@ -104,12 +111,11 @@ class ManifestDeclarativeSource(DeclarativeSource):
104
111
  """
105
112
  self.logger = logging.getLogger(f"airbyte.{self.name}")
106
113
  self._should_normalize = normalize_manifest
114
+ self._should_migrate = migrate_manifest
107
115
  self._declarative_component_schema = _get_declarative_component_schema()
108
116
  # If custom components are needed, locate and/or register them.
109
117
  self.components_module: ModuleType | None = get_registered_components_module(config=config)
110
- # resolve all components in the manifest
111
- self._source_config = self._preprocess_manifest(dict(source_config))
112
-
118
+ # set additional attributes
113
119
  self._debug = debug
114
120
  self._emit_connector_builder_messages = emit_connector_builder_messages
115
121
  self._constructor = (
@@ -126,11 +132,12 @@ class ManifestDeclarativeSource(DeclarativeSource):
126
132
  )
127
133
  self._config = config or {}
128
134
 
135
+ # resolve all components in the manifest
136
+ self._source_config = self._pre_process_manifest(dict(source_config))
129
137
  # validate resolved manifest against the declarative component schema
130
138
  self._validate_source()
131
-
132
139
  # apply additional post-processing to the manifest
133
- self._postprocess_manifest()
140
+ self._post_process_manifest()
134
141
 
135
142
  @property
136
143
  def resolved_manifest(self) -> Mapping[str, Any]:
@@ -145,7 +152,7 @@ class ManifestDeclarativeSource(DeclarativeSource):
145
152
  """
146
153
  return self._source_config
147
154
 
148
- def _preprocess_manifest(self, manifest: Dict[str, Any]) -> Dict[str, Any]:
155
+ def _pre_process_manifest(self, manifest: Dict[str, Any]) -> Dict[str, Any]:
149
156
  """
150
157
  Preprocesses the provided manifest dictionary by resolving any manifest references.
151
158
 
@@ -169,12 +176,14 @@ class ManifestDeclarativeSource(DeclarativeSource):
169
176
 
170
177
  return propagated_manifest
171
178
 
172
- def _postprocess_manifest(self) -> None:
179
+ def _post_process_manifest(self) -> None:
173
180
  """
174
181
  Post-processes the manifest after validation.
175
182
  This method is responsible for any additional modifications or transformations needed
176
183
  after the manifest has been validated and before it is used in the source.
177
184
  """
185
+ # apply manifest migration, if required
186
+ self._migrate_manifest()
178
187
  # apply manifest normalization, if required
179
188
  self._normalize_manifest()
180
189
 
@@ -190,6 +199,19 @@ class ManifestDeclarativeSource(DeclarativeSource):
190
199
  normalizer = ManifestNormalizer(self._source_config, self._declarative_component_schema)
191
200
  self._source_config = normalizer.normalize()
192
201
 
202
+ def _migrate_manifest(self) -> None:
203
+ """
204
+ This method is used to migrate the manifest. It should be called after the manifest has been validated.
205
+ The migration is done in place, so the original manifest is modified.
206
+
207
+ The original manifest is returned if any error occurs during migration.
208
+ """
209
+ if self._should_migrate:
210
+ manifest_migrator = ManifestMigrationHandler(self._source_config)
211
+ self._source_config = manifest_migrator.apply_migrations()
212
+ # validate migrated manifest against the declarative component schema
213
+ self._validate_source()
214
+
193
215
  def _fix_source_type(self, manifest: Dict[str, Any]) -> Dict[str, Any]:
194
216
  """
195
217
  Fix the source type in the manifest. This is necessary because the source type is not always set in the manifest.
@@ -211,6 +233,9 @@ class ManifestDeclarativeSource(DeclarativeSource):
211
233
  with_dynamic_stream_name=True,
212
234
  )
213
235
 
236
+ def deprecation_warnings(self) -> List[ConnectorBuilderLogMessage]:
237
+ return self._constructor.get_model_deprecations()
238
+
214
239
  @property
215
240
  def connection_checker(self) -> ConnectionChecker:
216
241
  check = self._source_config["check"]
@@ -0,0 +1,144 @@
1
+ # Copyright (c) 2025 Airbyte, Inc., all rights reserved.
2
+
3
+ # THIS IS A STATIC CLASS MODEL USED TO DISPLAY DEPRECATION WARNINGS
4
+ # WHEN DEPRECATED FIELDS ARE ACCESSED
5
+
6
+ import warnings
7
+ from typing import Any, List
8
+
9
+ from pydantic.v1 import BaseModel
10
+
11
+ from airbyte_cdk.connector_builder.models import LogMessage as ConnectorBuilderLogMessage
12
+
13
+ # format the warning message
14
+ warnings.formatwarning = (
15
+ lambda message, category, *args, **kwargs: f"{category.__name__}: {message}"
16
+ )
17
+
18
+ FIELDS_TAG = "__fields__"
19
+ DEPRECATED = "deprecated"
20
+ DEPRECATION_MESSAGE = "deprecation_message"
21
+ DEPRECATION_LOGS_TAG = "_deprecation_logs"
22
+
23
+
24
+ class BaseModelWithDeprecations(BaseModel):
25
+ """
26
+ Pydantic BaseModel that warns when deprecated fields are accessed.
27
+ The deprecation message is stored in the field's extra attributes.
28
+ This class is used to create models that can have deprecated fields
29
+ and show warnings when those fields are accessed or initialized.
30
+
31
+ The `_deprecation_logs` attribute is stored in the model itself.
32
+ The collected deprecation warnings are further propagated to the Airbyte log messages,
33
+ during the component creation process, in `model_to_component._collect_model_deprecations()`.
34
+
35
+ The component implementation is not responsible for handling the deprecation warnings,
36
+ since the deprecation warnings are already handled in the model itself.
37
+ """
38
+
39
+ class Config:
40
+ """
41
+ Allow extra fields in the model. In case the model restricts extra fields.
42
+ """
43
+
44
+ extra = "allow"
45
+
46
+ def __init__(self, **model_fields: Any) -> None:
47
+ """
48
+ Show warnings for deprecated fields during component initialization.
49
+ """
50
+ # call the parent constructor first to initialize Pydantic internals
51
+ super().__init__(**model_fields)
52
+ # set the placeholder for the default deprecation messages
53
+ self._default_deprecation_messages: List[str] = []
54
+ # set the placeholder for the deprecation logs
55
+ self._deprecation_logs: List[ConnectorBuilderLogMessage] = []
56
+ # process deprecated fields, if present
57
+ self._process_fields(model_fields)
58
+ # emit default deprecation messages
59
+ self._emit_default_deprecation_messages()
60
+ # set the deprecation logs attribute to the model
61
+ self._set_deprecation_logs_attr_to_model()
62
+
63
+ def _is_deprecated_field(self, field_name: str) -> bool:
64
+ return (
65
+ self.__fields__[field_name].field_info.extra.get(DEPRECATED, False)
66
+ if field_name in self.__fields__.keys()
67
+ else False
68
+ )
69
+
70
+ def _get_deprecation_message(self, field_name: str) -> str:
71
+ return (
72
+ self.__fields__[field_name].field_info.extra.get(
73
+ DEPRECATION_MESSAGE, "<missing_deprecation_message>"
74
+ )
75
+ if field_name in self.__fields__.keys()
76
+ else "<missing_deprecation_message>"
77
+ )
78
+
79
+ def _process_fields(self, model_fields: Any) -> None:
80
+ """
81
+ Processes the fields in the provided model data, checking for deprecated fields.
82
+
83
+ For each field in the input `model_fields`, this method checks if the field exists in the model's defined fields.
84
+ If the field is marked as deprecated (using the `DEPRECATED` flag in its metadata), it triggers a deprecation warning
85
+ by calling the `_create_warning` method with the field name and an optional deprecation message.
86
+
87
+ Args:
88
+ model_fields (Any): The data containing fields to be processed.
89
+
90
+ Returns:
91
+ None
92
+ """
93
+
94
+ if hasattr(self, FIELDS_TAG):
95
+ for field_name in model_fields.keys():
96
+ if self._is_deprecated_field(field_name):
97
+ self._create_warning(
98
+ field_name,
99
+ self._get_deprecation_message(field_name),
100
+ )
101
+
102
+ def _set_deprecation_logs_attr_to_model(self) -> None:
103
+ """
104
+ Sets the deprecation logs attribute on the model instance.
105
+
106
+ This method attaches the current instance's deprecation logs to the model by setting
107
+ an attribute named by `DEPRECATION_LOGS_TAG` to the value of `self._deprecation_logs`.
108
+ This is typically used to track or log deprecated features or configurations within the model.
109
+
110
+ Returns:
111
+ None
112
+ """
113
+ setattr(self, DEPRECATION_LOGS_TAG, self._deprecation_logs)
114
+
115
+ def _create_warning(self, field_name: str, message: str) -> None:
116
+ """
117
+ Show a warning message for deprecated fields (to stdout).
118
+ Args:
119
+ field_name (str): Name of the deprecated field.
120
+ message (str): Warning message to be displayed.
121
+ """
122
+
123
+ deprecated_message = f"Component type: `{self.__class__.__name__}`. Field '{field_name}' is deprecated. {message}"
124
+
125
+ if deprecated_message not in self._default_deprecation_messages:
126
+ # Avoid duplicates in the default deprecation messages
127
+ self._default_deprecation_messages.append(deprecated_message)
128
+
129
+ # Create an Airbyte deprecation log message
130
+ deprecation_log_message = ConnectorBuilderLogMessage(
131
+ level="WARN", message=deprecated_message
132
+ )
133
+ # Add the deprecation message to the Airbyte log messages,
134
+ # this logs are displayed in the Connector Builder.
135
+ if deprecation_log_message not in self._deprecation_logs:
136
+ # Avoid duplicates in the deprecation logs
137
+ self._deprecation_logs.append(deprecation_log_message)
138
+
139
+ def _emit_default_deprecation_messages(self) -> None:
140
+ """
141
+ Emit default deprecation messages for deprecated fields to STDOUT.
142
+ """
143
+ for message in self._default_deprecation_messages:
144
+ warnings.warn(message, DeprecationWarning)
@@ -10,6 +10,10 @@ from typing import Any, Dict, List, Literal, Optional, Union
10
10
 
11
11
  from pydantic.v1 import BaseModel, Extra, Field
12
12
 
13
+ from airbyte_cdk.sources.declarative.models.base_model_with_deprecations import (
14
+ BaseModelWithDeprecations,
15
+ )
16
+
13
17
 
14
18
  class AuthFlowType(Enum):
15
19
  oauth2_0 = "oauth2.0"
@@ -1497,6 +1501,11 @@ class ConfigComponentsResolver(BaseModel):
1497
1501
  parameters: Optional[Dict[str, Any]] = Field(None, alias="$parameters")
1498
1502
 
1499
1503
 
1504
+ class RequestBody(BaseModel):
1505
+ type: Optional[Union[Literal["RequestBodyData"], Literal["RequestBodyJson"]]] = None
1506
+ value: Optional[Union[str, Dict[str, str], Dict[str, Any]]] = None
1507
+
1508
+
1500
1509
  class AddedFieldDefinition(BaseModel):
1501
1510
  type: Literal["AddedFieldDefinition"]
1502
1511
  path: List[str] = Field(
@@ -2207,11 +2216,13 @@ class SessionTokenAuthenticator(BaseModel):
2207
2216
  parameters: Optional[Dict[str, Any]] = Field(None, alias="$parameters")
2208
2217
 
2209
2218
 
2210
- class HttpRequester(BaseModel):
2219
+ class HttpRequester(BaseModelWithDeprecations):
2211
2220
  type: Literal["HttpRequester"]
2212
- url_base: str = Field(
2213
- ...,
2214
- description="The Base URL of the API source. Do not put sensitive information (e.g. API tokens) into this field - Use the Authentication component for this.",
2221
+ url_base: Optional[str] = Field(
2222
+ None,
2223
+ deprecated=True,
2224
+ deprecation_message="Use `url` field instead.",
2225
+ description="Deprecated, use the `url` instead. Base URL of the API source. Do not put sensitive information (e.g. API tokens) into this field - Use the Authentication component for this.",
2215
2226
  examples=[
2216
2227
  "https://connect.squareup.com/v2",
2217
2228
  "{{ config['base_url'] or 'https://app.posthog.com'}}/api",
@@ -2220,9 +2231,22 @@ class HttpRequester(BaseModel):
2220
2231
  ],
2221
2232
  title="API Base URL",
2222
2233
  )
2234
+ url: Optional[str] = Field(
2235
+ None,
2236
+ description="The URL of the API source. Do not put sensitive information (e.g. API tokens) into this field - Use the Authentication component for this.",
2237
+ examples=[
2238
+ "https://connect.squareup.com/v2",
2239
+ "{{ config['url'] or 'https://app.posthog.com'}}/api",
2240
+ "https://connect.squareup.com/v2/quotes/{{ stream_partition['id'] }}/quote_line_groups",
2241
+ "https://example.com/api/v1/resource/{{ next_page_token['id'] }}",
2242
+ ],
2243
+ title="The URL of an API endpoint",
2244
+ )
2223
2245
  path: Optional[str] = Field(
2224
2246
  None,
2225
- description="The Path the specific API endpoint that this stream represents. Do not put sensitive information (e.g. API tokens) into this field - Use the Authentication component for this.",
2247
+ deprecated=True,
2248
+ deprecation_message="Use `url` field instead.",
2249
+ description="Deprecated, use the `url` instead. Path the specific API endpoint that this stream represents. Do not put sensitive information (e.g. API tokens) into this field - Use the Authentication component for this.",
2226
2250
  examples=[
2227
2251
  "/products",
2228
2252
  "/quotes/{{ stream_partition['id'] }}/quote_line_groups",
@@ -2261,6 +2285,8 @@ class HttpRequester(BaseModel):
2261
2285
  )
2262
2286
  request_body_data: Optional[Union[Dict[str, str], str]] = Field(
2263
2287
  None,
2288
+ deprecated=True,
2289
+ deprecation_message="Use `request_body` field instead.",
2264
2290
  description="Specifies how to populate the body of the request with a non-JSON payload. Plain text will be sent as is, whereas objects will be converted to a urlencoded form.",
2265
2291
  examples=[
2266
2292
  '[{"clause": {"type": "timestamp", "operator": 10, "parameters":\n [{"value": {{ stream_interval[\'start_time\'] | int * 1000 }} }]\n }, "orderBy": 1, "columnName": "Timestamp"}]/\n'
@@ -2269,6 +2295,8 @@ class HttpRequester(BaseModel):
2269
2295
  )
2270
2296
  request_body_json: Optional[Union[Dict[str, Any], str]] = Field(
2271
2297
  None,
2298
+ deprecated=True,
2299
+ deprecation_message="Use `request_body` field instead.",
2272
2300
  description="Specifies how to populate the body of the request with a JSON payload. Can contain nested objects.",
2273
2301
  examples=[
2274
2302
  {"sort_order": "ASC", "sort_field": "CREATED_AT"},
@@ -2277,6 +2305,27 @@ class HttpRequester(BaseModel):
2277
2305
  ],
2278
2306
  title="Request Body JSON Payload",
2279
2307
  )
2308
+ request_body: Optional[RequestBody] = Field(
2309
+ None,
2310
+ description="Specifies how to populate the body of the request with a payload. Can contain nested objects.",
2311
+ examples=[
2312
+ {
2313
+ "type": "RequestBodyJson",
2314
+ "value": {"sort_order": "ASC", "sort_field": "CREATED_AT"},
2315
+ },
2316
+ {"type": "RequestBodyJson", "value": {"key": "{{ config['value'] }}"}},
2317
+ {
2318
+ "type": "RequestBodyJson",
2319
+ "value": {"sort": {"field": "updated_at", "order": "ascending"}},
2320
+ },
2321
+ {"type": "RequestBodyData", "value": "plain_text_body"},
2322
+ {
2323
+ "type": "RequestBodyData",
2324
+ "value": {"param1": "value1", "param2": "{{ config['param2_value'] }}"},
2325
+ },
2326
+ ],
2327
+ title="Request Body Payload to be send as a part of the API request.",
2328
+ )
2280
2329
  request_headers: Optional[Union[Dict[str, str], str]] = Field(
2281
2330
  None,
2282
2331
  description="Return any non-auth headers. Authentication headers will overwrite any overlapping headers returned from this method.",