Skip to content

Commit 81e918b

Browse files
committed
error handling for multiple properties and updates from the latest schema changes
1 parent 32d6b7a commit 81e918b

File tree

3 files changed

+110
-9
lines changed

3 files changed

+110
-9
lines changed

airbyte_cdk/sources/declarative/models/declarative_component_schema.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
# Copyright (c) 2025 Airbyte, Inc., all rights reserved.
2+
13
# generated by datamodel-codegen:
24
# filename: declarative_component_schema.yaml
35

airbyte_cdk/sources/declarative/parsers/model_to_component_factory.py

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2945,16 +2945,19 @@ def create_simple_retriever(
29452945

29462946
query_properties: Optional[QueryProperties] = None
29472947
query_properties_key: Optional[str] = None
2948-
if (
2949-
hasattr(model.requester, "request_parameters")
2950-
and model.requester.request_parameters
2951-
and isinstance(model.requester.request_parameters, Mapping)
2952-
):
2948+
if self._query_properties_in_request_parameters(model.requester):
2949+
# It is better to be explicit about an error if PropertiesFromEndpoint is defined in multiple
2950+
# places instead of default to request_parameters which isn't clearly documented
2951+
if (
2952+
hasattr(model.requester, "fetch_properties_from_endpoint")
2953+
and model.requester.fetch_properties_from_endpoint
2954+
):
2955+
raise ValueError(
2956+
f"PropertiesFromEndpoint should only be specified once per stream, but found in {model.requester.type}.fetch_properties_from_endpoint and {model.requester.type}.request_parameters"
2957+
)
2958+
29532959
query_properties_definitions = []
2954-
for key, request_parameter in model.requester.request_parameters.items():
2955-
# When translating JSON schema into Pydantic models, enforcing types for arrays containing both
2956-
# concrete string complex object definitions like QueryProperties would get resolved to Union[str, Any].
2957-
# This adds the extra validation that we couldn't get for free in Pydantic model generation
2960+
for key, request_parameter in model.requester.request_parameters.items(): # type: ignore # request_parameters is already validated to be a Mapping using _query_properties_in_request_parameters()
29582961
if isinstance(request_parameter, QueryPropertiesModel):
29592962
query_properties_key = key
29602963
query_properties_definitions.append(request_parameter)
@@ -3102,6 +3105,19 @@ def create_simple_retriever(
31023105
parameters=model.parameters or {},
31033106
)
31043107

3108+
@staticmethod
3109+
def _query_properties_in_request_parameters(
3110+
requester: Union[HttpRequesterModel, CustomRequesterModel],
3111+
) -> bool:
3112+
if not hasattr(requester, "request_parameters"):
3113+
return False
3114+
request_parameters = requester.request_parameters
3115+
if request_parameters and isinstance(request_parameters, Mapping):
3116+
for request_parameter in request_parameters.values():
3117+
if isinstance(request_parameter, QueryPropertiesModel):
3118+
return True
3119+
return False
3120+
31053121
@staticmethod
31063122
def _remove_query_properties(
31073123
request_parameters: Mapping[str, Union[str, QueryPropertiesModel]],

unit_tests/sources/declarative/parsers/test_model_to_component_factory.py

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4442,6 +4442,89 @@ def test_create_simple_retriever_raise_error_if_multiple_request_properties():
44424442
)
44434443

44444444

4445+
def test_create_simple_retriever_raise_error_properties_from_endpoint_defined_multiple_times():
4446+
content = """
4447+
selector:
4448+
type: RecordSelector
4449+
extractor:
4450+
type: DpathExtractor
4451+
field_path: ["extractor_path"]
4452+
record_filter:
4453+
type: RecordFilter
4454+
condition: "{{ record['id'] > stream_state['id'] }}"
4455+
requester:
4456+
type: HttpRequester
4457+
name: "{{ parameters['name'] }}"
4458+
url_base: "https://api.linkedin.com/rest/"
4459+
http_method: "GET"
4460+
path: "adAnalytics"
4461+
fetch_properties_from_endpoint:
4462+
type: PropertiesFromEndpoint
4463+
property_field_path: [ "name" ]
4464+
retriever:
4465+
type: SimpleRetriever
4466+
requester:
4467+
type: HttpRequester
4468+
url_base: https://api.hubapi.com
4469+
path: "/properties/v2/dynamics/properties"
4470+
http_method: GET
4471+
record_selector:
4472+
type: RecordSelector
4473+
extractor:
4474+
type: DpathExtractor
4475+
field_path: []
4476+
request_parameters:
4477+
properties:
4478+
type: QueryProperties
4479+
property_list:
4480+
- first_name
4481+
- last_name
4482+
- status
4483+
- organization
4484+
- created_at
4485+
always_include_properties:
4486+
- id
4487+
property_chunking:
4488+
type: PropertyChunking
4489+
property_limit_type: property_count
4490+
property_limit: 3
4491+
record_merge_strategy:
4492+
type: GroupByKeyMergeStrategy
4493+
key: ["id"]
4494+
nonary: "{{config['nonary'] }}"
4495+
analytics_stream:
4496+
type: DeclarativeStream
4497+
incremental_sync:
4498+
type: DatetimeBasedCursor
4499+
$parameters:
4500+
datetime_format: "%Y-%m-%dT%H:%M:%S.%f%z"
4501+
start_datetime: "{{ config['start_time'] }}"
4502+
cursor_field: "created"
4503+
retriever:
4504+
type: SimpleRetriever
4505+
name: "{{ parameters['name'] }}"
4506+
requester:
4507+
$ref: "#/requester"
4508+
record_selector:
4509+
$ref: "#/selector"
4510+
$parameters:
4511+
name: "analytics"
4512+
"""
4513+
4514+
parsed_manifest = YamlDeclarativeSource._parse(content)
4515+
resolved_manifest = resolver.preprocess_manifest(parsed_manifest)
4516+
stream_manifest = transformer.propagate_types_and_parameters(
4517+
"", resolved_manifest["analytics_stream"], {}
4518+
)
4519+
4520+
with pytest.raises(ValueError):
4521+
factory.create_component(
4522+
model_type=DeclarativeStreamModel,
4523+
component_definition=stream_manifest,
4524+
config=input_config,
4525+
)
4526+
4527+
44454528
def test_create_property_chunking_characters():
44464529
property_chunking_model = {
44474530
"type": "PropertyChunking",

0 commit comments

Comments
 (0)