Skip to content

Commit 18154a1

Browse files
committed
Merge branch 'pnilan/feat/implement-validators' into pnilan/feat/extend-spec-class-for-config-migrations
2 parents 70785b8 + a2dc105 commit 18154a1

File tree

7 files changed

+47
-31
lines changed

7 files changed

+47
-31
lines changed

airbyte_cdk/sources/declarative/transformations/config_transformations/__init__.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22
# Copyright (c) 2025 Airbyte, Inc., all rights reserved.
33
#
44

5-
from .add_fields import AddFields
6-
from .remap_field import RemapField
7-
from .remove_fields import RemoveFields
5+
from .add_fields import ConfigAddFields
6+
from .remap_field import ConfigRemapField
7+
from .remove_fields import ConfigRemoveFields
88

9-
__all__ = ["RemapField", "AddFields", "RemoveFields"]
9+
__all__ = ["ConfigRemapField", "ConfigAddFields", "ConfigRemoveFields"]

airbyte_cdk/sources/declarative/transformations/config_transformations/add_fields.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,15 +34,15 @@ class ParsedAddFieldDefinition:
3434

3535

3636
@dataclass
37-
class AddFields(ConfigTransformation):
37+
class ConfigAddFields(ConfigTransformation):
3838
"""
3939
Transformation which adds fields to a config. The path of the added field can be nested. Adding nested fields will create all
4040
necessary parent objects (like mkdir -p).
4141
4242
This transformation has access to the config being transformed.
4343
4444
Examples of instantiating this transformation via YAML:
45-
- type: AddFields
45+
- type: ConfigAddFields
4646
fields:
4747
# hardcoded constant
4848
- path: ["path"]
@@ -113,8 +113,7 @@ def transform(
113113
for parsed_field in self._parsed_fields:
114114
valid_types = (parsed_field.value_type,) if parsed_field.value_type else None
115115
value = parsed_field.value.eval(config, valid_types=valid_types)
116-
is_empty_condition = not self.condition
117-
if is_empty_condition or self._filter_interpolator.eval(
116+
if not self.condition or self._filter_interpolator.eval(
118117
config, value=value, path=parsed_field.path
119118
):
120119
dpath.new(config, parsed_field.path, value)

airbyte_cdk/sources/declarative/transformations/config_transformations/remap_field.py

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,23 +2,26 @@
22
# Copyright (c) 2025 Airbyte, Inc., all rights reserved.
33
#
44

5-
from dataclasses import dataclass
5+
from dataclasses import dataclass, field
66
from typing import Any, List, Mapping, MutableMapping, Union
77

8+
from airbyte_cdk.sources.declarative.interpolation.interpolated_boolean import InterpolatedBoolean
9+
from airbyte_cdk.sources.declarative.interpolation.interpolated_mapping import InterpolatedMapping
810
from airbyte_cdk.sources.declarative.interpolation.interpolated_string import InterpolatedString
911
from airbyte_cdk.sources.declarative.transformations.config_transformations.config_transformation import (
1012
ConfigTransformation,
1113
)
1214

1315

1416
@dataclass
15-
class RemapField(ConfigTransformation):
17+
class ConfigRemapField(ConfigTransformation):
1618
"""
1719
Transformation that remaps a field's value to another value based on a static map.
1820
"""
1921

2022
map: Mapping[str, Any]
2123
field_path: List[Union[InterpolatedString, str]]
24+
config: Mapping[str, Any] = field(default_factory=dict)
2225

2326
def __post_init__(self) -> None:
2427
if not self.field_path:
@@ -31,6 +34,7 @@ def __post_init__(self) -> None:
3134
self._field_path[path_index] = InterpolatedString.create(
3235
self.field_path[path_index], parameters={}
3336
)
37+
self._map = InterpolatedMapping(self.map, parameters={}).eval(config=self.config)
3438

3539
def transform(
3640
self,
@@ -51,10 +55,10 @@ def transform(
5155
return
5256
current = current[component]
5357

54-
if not isinstance(current, Mapping):
58+
if not isinstance(current, MutableMapping):
5559
return
5660

5761
field_name = path_components[-1]
5862

59-
if field_name in current and current[field_name] in self.map:
60-
current[field_name] = self.map[current[field_name]]
63+
if field_name in current and current[field_name] in self._map:
64+
current[field_name] = self._map[current[field_name]]

airbyte_cdk/sources/declarative/transformations/config_transformations/remove_fields.py

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
#
22
# Copyright (c) 2025 Airbyte, Inc., all rights reserved.
33
#
4-
import logging
54
from dataclasses import dataclass
65
from typing import Any, List, MutableMapping
76

@@ -14,11 +13,9 @@
1413
)
1514
from airbyte_cdk.sources.types import FieldPointer
1615

17-
logger = logging.getLogger("airbyte")
18-
1916

2017
@dataclass
21-
class RemoveFields(ConfigTransformation):
18+
class ConfigRemoveFields(ConfigTransformation):
2219
"""
2320
A transformation which removes fields from a config. The fields removed are designated using FieldPointers.
2421
During transformation, if a field or any of its parents does not exist in the config, no error is thrown.
@@ -67,6 +64,3 @@ def transform(
6764
dpath.delete(config, pointer)
6865
except dpath.exceptions.PathNotFound:
6966
pass
70-
except Exception as e:
71-
logger.error(f"Error removing field {pointer}: {e}")
72-
raise e

unit_tests/sources/declarative/transformations/config_transformations/test_add_fields.py renamed to unit_tests/sources/declarative/transformations/config_transformations/test_config_add_fields.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@
66

77
from airbyte_cdk.sources.declarative.transformations.config_transformations.add_fields import (
88
AddedFieldDefinition,
9-
AddFields,
9+
)
10+
from airbyte_cdk.sources.declarative.transformations.config_transformations.add_fields import (
11+
ConfigAddFields as AddFields,
1012
)
1113

1214

unit_tests/sources/declarative/transformations/config_transformations/test_remap_field.py renamed to unit_tests/sources/declarative/transformations/config_transformations/test_config_remap_field.py

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,25 +3,26 @@
33

44
import pytest
55

6-
from airbyte_cdk.sources.declarative.transformations.config_transformations.remap_field import (
7-
RemapField,
6+
from airbyte_cdk.sources.declarative.transformations.config_transformations import (
7+
ConfigRemapField as RemapField,
88
)
99

1010

1111
class TestRemapField(TestCase):
1212
def test_given_valid_inputs_when_transform_then_field_is_remapped(self):
13-
remap_transform = RemapField(
14-
field_path=["authorization", "auth_type"],
15-
map={"client_credentials": "oauth2", "api_key": "key_auth"},
16-
)
17-
1813
config = {
1914
"authorization": {
2015
"auth_type": "client_credentials",
2116
"client_id": "12345",
2217
"client_secret": "secret",
2318
}
2419
}
20+
remap_transform = RemapField(
21+
field_path=["authorization", "auth_type"],
22+
map={"client_credentials": "oauth2", "api_key": "key_auth"},
23+
config=config,
24+
)
25+
2526
original_config = deepcopy(config)
2627

2728
remap_transform.transform(config)
@@ -110,3 +111,21 @@ def test_multiple_transformations_applied_in_sequence(self):
110111

111112
assert config["auth"]["type"] == "oauth2"
112113
assert config["environment"] == "development"
114+
115+
def test_amazon_seller_partner_marketplace_remap_with_interpolated_mapping(self):
116+
mapping = {
117+
"endpoint": {
118+
"ES": "{{ 'https://sellingpartnerapi' if config.environment == 'production' else 'https://sandbox.sellingpartnerapi' }}-eu.amazon.com",
119+
}
120+
}
121+
sandbox_config = {"environment": "sandbox", "marketplace": "ES"}
122+
production_config = {"environment": "production", "marketplace": "ES"}
123+
RemapField(
124+
field_path=["marketplace"], map=mapping["endpoint"], config=sandbox_config
125+
).transform(sandbox_config)
126+
RemapField(
127+
field_path=["marketplace"], map=mapping["endpoint"], config=production_config
128+
).transform(production_config)
129+
130+
assert sandbox_config["marketplace"] == "https://sandbox.sellingpartnerapi-eu.amazon.com"
131+
assert production_config["marketplace"] == "https://sellingpartnerapi-eu.amazon.com"

unit_tests/sources/declarative/transformations/config_transformations/test_remove_fields.py renamed to unit_tests/sources/declarative/transformations/config_transformations/test_config_remove_fields.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,8 @@
22
# Copyright (c) 2025 Airbyte, Inc., all rights reserved.
33
#
44

5-
import pytest
6-
75
from airbyte_cdk.sources.declarative.transformations.config_transformations.remove_fields import (
8-
RemoveFields,
6+
ConfigRemoveFields as RemoveFields,
97
)
108

119

0 commit comments

Comments
 (0)