Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

🐛 Source Google Ads: added handling for 401 error while parsing response. added metrics.cost_micros to ad_groups stream #33494

Merged
merged 20 commits into from Jan 9, 2024
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
d19987e
added handling for 401 error while parsing response
darynaishchenko Dec 14, 2023
59f276a
updated changelog
darynaishchenko Dec 14, 2023
8c2d8eb
Merge branch 'master' into daryna/source-google-ads/oc-auth-error
darynaishchenko Dec 15, 2023
c0c5c30
updated expected records
darynaishchenko Dec 18, 2023
38d6bf6
added metrics.cost_micros field to ad_group stream
darynaishchenko Dec 18, 2023
6484760
Merge branch 'master' into daryna/source-google-ads/oc-auth-error
darynaishchenko Dec 20, 2023
fd1af0c
updated expected records
darynaishchenko Dec 20, 2023
b1a493a
updated expected records
darynaishchenko Dec 20, 2023
9b52fc6
Merge branch 'master' into daryna/source-google-ads/oc-auth-error
darynaishchenko Dec 21, 2023
a2f3392
Merge branch 'master' into daryna/source-google-ads/oc-auth-error
darynaishchenko Jan 8, 2024
09a701f
updated expected records
darynaishchenko Jan 8, 2024
0edc4eb
added traced_exception func, updated connector version
darynaishchenko Jan 8, 2024
c01f6d1
Merge branch 'master' into daryna/source-google-ads/oc-auth-error
darynaishchenko Jan 8, 2024
f57d67f
format fix
darynaishchenko Jan 9, 2024
1ebb3b4
added ignored fields
darynaishchenko Jan 9, 2024
05ed28a
added 401 handling to request_records_job func
darynaishchenko Jan 9, 2024
d227cd1
Merge branch 'master' into daryna/source-google-ads/oc-auth-error
darynaishchenko Jan 9, 2024
d481a88
added 401 handling to read records
darynaishchenko Jan 9, 2024
f1bc200
Merge branch 'master' into daryna/source-google-ads/oc-auth-error
darynaishchenko Jan 9, 2024
531718d
format fix
darynaishchenko Jan 9, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Expand Up @@ -11,7 +11,7 @@ data:
connectorSubtype: api
connectorType: source
definitionId: 253487c0-2246-43ba-a21f-5116b20a2c50
dockerImageTag: 3.0.0
dockerImageTag: 3.0.1
dockerRepository: airbyte/source-google-ads
documentationUrl: https://docs.airbyte.com/integrations/sources/google-ads
githubIssueLabel: source-google-ads
Expand Down
Expand Up @@ -14,6 +14,9 @@
"ad_group.campaign": {
"type": ["null", "string"]
},
"metrics.cost_micros": {
"type": ["null", "integer"]
},
"ad_group.cpc_bid_micros": {
"type": ["null", "integer"]
},
Expand Down
Expand Up @@ -16,7 +16,7 @@
from google.ads.googleads.errors import GoogleAdsException
from google.ads.googleads.v15.services.services.google_ads_service.pagers import SearchPager
from google.ads.googleads.v15.services.types.google_ads_service import SearchGoogleAdsResponse
from google.api_core.exceptions import InternalServerError, ServerError, ServiceUnavailable, TooManyRequests
from google.api_core.exceptions import InternalServerError, ServerError, ServiceUnavailable, TooManyRequests, Unauthenticated

from .google_ads import GoogleAds, logger
from .models import CustomerModel
Expand All @@ -38,7 +38,15 @@ def get_query(self, stream_slice: Mapping[str, Any]) -> str:

def parse_response(self, response: SearchPager, stream_slice: Optional[Mapping[str, Any]] = None) -> Iterable[Mapping]:
for result in response:
yield self.google_ads_client.parse_single_result(self.get_json_schema(), result)
try:
yield self.google_ads_client.parse_single_result(self.get_json_schema(), result)
except Unauthenticated:
raise AirbyteTracedException(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it be possible to incorporate this error handling into the traced_exception function located in utils.py? This would centralize error handling, making it more manageable and consistent across the connector.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

updated with traced_exception

internal_message="authentication error",
failure_type=FailureType.config_error,
message="Authentication failed. Please try to Re-authenticate your credentials on set up Google Ads page."
)


def stream_slices(self, stream_state: Mapping[str, Any] = None, **kwargs) -> Iterable[Optional[Mapping[str, any]]]:
for customer in self.customers:
Expand Down
Expand Up @@ -11,10 +11,10 @@
from google.ads.googleads.errors import GoogleAdsException
from google.ads.googleads.v15.errors.types.errors import ErrorCode, GoogleAdsError, GoogleAdsFailure
from google.ads.googleads.v15.errors.types.request_error import RequestErrorEnum
from google.api_core.exceptions import DataLoss, InternalServerError, ResourceExhausted, TooManyRequests
from google.api_core.exceptions import DataLoss, InternalServerError, ResourceExhausted, TooManyRequests, Unauthenticated
from grpc import RpcError
from source_google_ads.google_ads import GoogleAds
from source_google_ads.streams import ClickView, Customer
from source_google_ads.streams import ClickView, Customer, CustomerLabel

# EXPIRED_PAGE_TOKEN exception will be raised when page token has expired.
exception = GoogleAdsException(
Expand Down Expand Up @@ -261,3 +261,23 @@ def test_parse_response(mocker, customers, config):
]

assert output == expected_output


def test_parse_response_unauthenticated(mocker, customers, config):
credentials = config["credentials"]
api = GoogleAds(credentials=credentials)

mocker.patch.object(api, "parse_single_result", side_effect=Unauthenticated(message="Unauthenticated"))

stream_config = dict(
api=api,
customers=customers,
)
stream = CustomerLabel(**stream_config)
response = [
{"customer.id": "1", "segments.date": "2023-09-19", "customer.optimization_score_weight": 80},
]
with pytest.raises(AirbyteTracedException) as exc_info:
list(stream.parse_response(response))

assert exc_info.value.message == "Authentication failed. Please try to Re-authenticate your credentials on set up Google Ads page."
1 change: 1 addition & 0 deletions docs/integrations/sources/google-ads.md
Expand Up @@ -278,6 +278,7 @@ Due to a limitation in the Google Ads API which does not allow getting performan

| Version | Date | Pull Request | Subject |
|:---------|:-----------|:---------------------------------------------------------|:-------------------------------------------------------------------------------------------------------------------------------------|
| `3.0.1` | 2023-12-20 | [33494](https://github.com/airbytehq/airbyte/pull/33494) | Add handling for 401 error while parsing response. Add `metrics.cost_micros` field to Ad Group stream. |
| `3.0.0` | 2023-12-07 | [33120](https://github.com/airbytehq/airbyte/pull/33120) | Upgrade API version to v15 |
| `2.0.4` | 2023-11-10 | [32414](https://github.com/airbytehq/airbyte/pull/32414) | Add backoff strategy for read_records method |
| `2.0.3` | 2023-11-02 | [32102](https://github.com/airbytehq/airbyte/pull/32102) | Fix incremental events streams |
Expand Down