airbyte-source-google-ads 4.2.2__tar.gz → 4.2.4__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {airbyte_source_google_ads-4.2.2 → airbyte_source_google_ads-4.2.4}/PKG-INFO +1 -1
- {airbyte_source_google_ads-4.2.2 → airbyte_source_google_ads-4.2.4}/pyproject.toml +1 -1
- {airbyte_source_google_ads-4.2.2 → airbyte_source_google_ads-4.2.4}/source_google_ads/components.py +55 -1
- {airbyte_source_google_ads-4.2.2 → airbyte_source_google_ads-4.2.4}/source_google_ads/manifest.yaml +2 -0
- {airbyte_source_google_ads-4.2.2 → airbyte_source_google_ads-4.2.4}/source_google_ads/utils.py +3 -2
- {airbyte_source_google_ads-4.2.2 → airbyte_source_google_ads-4.2.4}/README.md +0 -0
- {airbyte_source_google_ads-4.2.2 → airbyte_source_google_ads-4.2.4}/source_google_ads/__init__.py +0 -0
- {airbyte_source_google_ads-4.2.2 → airbyte_source_google_ads-4.2.4}/source_google_ads/config_migrations.py +0 -0
- {airbyte_source_google_ads-4.2.2 → airbyte_source_google_ads-4.2.4}/source_google_ads/google_ads.py +0 -0
- {airbyte_source_google_ads-4.2.2 → airbyte_source_google_ads-4.2.4}/source_google_ads/models.py +0 -0
- {airbyte_source_google_ads-4.2.2 → airbyte_source_google_ads-4.2.4}/source_google_ads/run.py +0 -0
- {airbyte_source_google_ads-4.2.2 → airbyte_source_google_ads-4.2.4}/source_google_ads/schemas/customer_client.json +0 -0
- {airbyte_source_google_ads-4.2.2 → airbyte_source_google_ads-4.2.4}/source_google_ads/schemas/service_accounts.json +0 -0
- {airbyte_source_google_ads-4.2.2 → airbyte_source_google_ads-4.2.4}/source_google_ads/source.py +0 -0
- {airbyte_source_google_ads-4.2.2 → airbyte_source_google_ads-4.2.4}/source_google_ads/spec.json +0 -0
- {airbyte_source_google_ads-4.2.2 → airbyte_source_google_ads-4.2.4}/source_google_ads/streams.py +0 -0
|
@@ -3,7 +3,7 @@ requires = [ "poetry-core>=1.0.0",]
|
|
|
3
3
|
build-backend = "poetry.core.masonry.api"
|
|
4
4
|
|
|
5
5
|
[tool.poetry]
|
|
6
|
-
version = "4.2.
|
|
6
|
+
version = "4.2.4"
|
|
7
7
|
name = "airbyte-source-google-ads"
|
|
8
8
|
description = "Source implementation for Google Ads."
|
|
9
9
|
authors = [ "Airbyte <contact@airbyte.io>",]
|
{airbyte_source_google_ads-4.2.2 → airbyte_source_google_ads-4.2.4}/source_google_ads/components.py
RENAMED
|
@@ -10,7 +10,7 @@ import threading
|
|
|
10
10
|
from dataclasses import dataclass, field
|
|
11
11
|
from datetime import datetime, timedelta
|
|
12
12
|
from itertools import groupby
|
|
13
|
-
from typing import Any, Callable, Dict, Generator, Iterable, List, Mapping, MutableMapping, Optional, Tuple, Union
|
|
13
|
+
from typing import Any, Callable, ClassVar, Dict, Generator, Iterable, List, Mapping, MutableMapping, Optional, Set, Tuple, Union
|
|
14
14
|
|
|
15
15
|
import anyascii
|
|
16
16
|
import requests
|
|
@@ -147,6 +147,55 @@ class FlattenNestedDictsTransformation(RecordTransformation):
|
|
|
147
147
|
_flatten(top_key, nested)
|
|
148
148
|
|
|
149
149
|
|
|
150
|
+
@dataclass
|
|
151
|
+
class SerializeMessageFieldsTransformation(RecordTransformation):
|
|
152
|
+
"""
|
|
153
|
+
Serializes MESSAGE-type fields (nested dict values) to JSON strings before
|
|
154
|
+
flattening occurs. This prevents FlattenNestedDictsTransformation from
|
|
155
|
+
recursively flattening MESSAGE fields like change_event.old_resource and
|
|
156
|
+
change_event.new_resource, which would create sub-keys not present in
|
|
157
|
+
the schema and cause the original field values to be lost (returned as NULL).
|
|
158
|
+
|
|
159
|
+
This transformation must run AFTER KeysToSnakeCaseGoogleAdsTransformation
|
|
160
|
+
and BEFORE FlattenNestedDictsTransformation in the custom query stream
|
|
161
|
+
transformation chain.
|
|
162
|
+
|
|
163
|
+
The set of MESSAGE-type field names is populated by
|
|
164
|
+
CustomGAQuerySchemaLoader.get_json_schema() during stream initialization
|
|
165
|
+
and stored on the CustomGAQuerySchemaLoader class.
|
|
166
|
+
"""
|
|
167
|
+
|
|
168
|
+
def transform(
|
|
169
|
+
self,
|
|
170
|
+
record: Dict[str, Any],
|
|
171
|
+
config: Optional[Config] = None,
|
|
172
|
+
stream_state: Optional[StreamState] = None,
|
|
173
|
+
stream_slice: Optional[StreamSlice] = None,
|
|
174
|
+
) -> None:
|
|
175
|
+
message_fields: set = CustomGAQuerySchemaLoader._all_message_fields
|
|
176
|
+
if not message_fields:
|
|
177
|
+
return
|
|
178
|
+
|
|
179
|
+
for field_name in message_fields:
|
|
180
|
+
parts = field_name.split(".")
|
|
181
|
+
current = record
|
|
182
|
+
for part in parts[:-1]:
|
|
183
|
+
if isinstance(current, dict) and part in current:
|
|
184
|
+
current = current[part]
|
|
185
|
+
else:
|
|
186
|
+
current = None
|
|
187
|
+
break
|
|
188
|
+
|
|
189
|
+
if current is not None and isinstance(current, dict):
|
|
190
|
+
last_part = parts[-1]
|
|
191
|
+
if last_part in current:
|
|
192
|
+
value = current[last_part]
|
|
193
|
+
if isinstance(value, dict):
|
|
194
|
+
current[last_part] = json.dumps(value)
|
|
195
|
+
elif isinstance(value, list):
|
|
196
|
+
current[last_part] = [json.dumps(item) if isinstance(item, dict) else item for item in value]
|
|
197
|
+
|
|
198
|
+
|
|
150
199
|
class DoubleQuotedDictTypeTransformer(TypeTransformer):
|
|
151
200
|
"""
|
|
152
201
|
Convert arrays of dicts into JSON-formatted string arrays using double quotes only
|
|
@@ -928,6 +977,7 @@ class CustomGAQuerySchemaLoader(SchemaLoader):
|
|
|
928
977
|
|
|
929
978
|
_google_ads_client: Optional[GoogleAds] = None
|
|
930
979
|
_client_lock = threading.Lock()
|
|
980
|
+
_all_message_fields: ClassVar[Set[str]] = set()
|
|
931
981
|
|
|
932
982
|
def __post_init__(self):
|
|
933
983
|
self._cursor_field = InterpolatedString.create(self.cursor_field, parameters={}) if self.cursor_field else None
|
|
@@ -964,10 +1014,14 @@ class CustomGAQuerySchemaLoader(SchemaLoader):
|
|
|
964
1014
|
fields = self._get_list_of_fields()
|
|
965
1015
|
fields_metadata = self.google_ads_client(self.config).get_fields_metadata(fields)
|
|
966
1016
|
|
|
1017
|
+
message_fields: set = set()
|
|
967
1018
|
for field, field_metadata in fields_metadata.items():
|
|
1019
|
+
if field_metadata.data_type.name == "MESSAGE":
|
|
1020
|
+
message_fields.add(field)
|
|
968
1021
|
field_value = self._build_field_value(field, field_metadata)
|
|
969
1022
|
local_json_schema["properties"][field] = field_value
|
|
970
1023
|
|
|
1024
|
+
CustomGAQuerySchemaLoader._all_message_fields = CustomGAQuerySchemaLoader._all_message_fields | message_fields
|
|
971
1025
|
return local_json_schema
|
|
972
1026
|
|
|
973
1027
|
def _build_field_value(self, field: str, field_metadata) -> Any:
|
{airbyte_source_google_ads-4.2.2 → airbyte_source_google_ads-4.2.4}/source_google_ads/manifest.yaml
RENAMED
|
@@ -425,6 +425,8 @@ definitions:
|
|
|
425
425
|
transformations:
|
|
426
426
|
- type: CustomTransformation
|
|
427
427
|
class_name: "source_google_ads.components.KeysToSnakeCaseGoogleAdsTransformation"
|
|
428
|
+
- type: CustomTransformation
|
|
429
|
+
class_name: "source_google_ads.components.SerializeMessageFieldsTransformation"
|
|
428
430
|
- type: CustomTransformation
|
|
429
431
|
class_name: "source_google_ads.components.FlattenNestedDictsTransformation"
|
|
430
432
|
- type: AddFields
|
{airbyte_source_google_ads-4.2.2 → airbyte_source_google_ads-4.2.4}/source_google_ads/utils.py
RENAMED
|
@@ -109,10 +109,11 @@ def traced_exception(
|
|
|
109
109
|
)
|
|
110
110
|
|
|
111
111
|
elif is_error_type(query_error, QueryErrorEnum.QueryError.UNRECOGNIZED_FIELD):
|
|
112
|
+
query_label = f'"{query_name}" ' if query_name else ""
|
|
112
113
|
message = (
|
|
113
|
-
f"
|
|
114
|
+
f"Custom query {query_label}references an unrecognized field for the queried resource."
|
|
115
|
+
" Verify all selected fields are valid for the resource."
|
|
114
116
|
)
|
|
115
|
-
# additionally log the error for visability during `check_connection` in UI.
|
|
116
117
|
logger.error(message)
|
|
117
118
|
|
|
118
119
|
elif query_error:
|
|
File without changes
|
{airbyte_source_google_ads-4.2.2 → airbyte_source_google_ads-4.2.4}/source_google_ads/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{airbyte_source_google_ads-4.2.2 → airbyte_source_google_ads-4.2.4}/source_google_ads/google_ads.py
RENAMED
|
File without changes
|
{airbyte_source_google_ads-4.2.2 → airbyte_source_google_ads-4.2.4}/source_google_ads/models.py
RENAMED
|
File without changes
|
{airbyte_source_google_ads-4.2.2 → airbyte_source_google_ads-4.2.4}/source_google_ads/run.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{airbyte_source_google_ads-4.2.2 → airbyte_source_google_ads-4.2.4}/source_google_ads/source.py
RENAMED
|
File without changes
|
{airbyte_source_google_ads-4.2.2 → airbyte_source_google_ads-4.2.4}/source_google_ads/spec.json
RENAMED
|
File without changes
|
{airbyte_source_google_ads-4.2.2 → airbyte_source_google_ads-4.2.4}/source_google_ads/streams.py
RENAMED
|
File without changes
|