Posts tagged with python-3.x

I am working on a project to let a client authorize their google ads account, and then use those authorized credentials to download data on their behalf. I have a webapp that successfully Authorizes the app to do things on the clients behalf. This generates an access code that I then trade for two credentials, an access token and a refresh token. This refresh token then gets passed to a database, where a separate app attempts to query the googleAds API. It is my understanding that the Google Oauth engine only needs the refresh token.

I am trying to authorize by use of load_from_dict() or load_from_env() methods of the GoogleAdsClient class. Both yield the same error: google.auth.exceptions.RefreshError: ('invalid_client: Unauthorized', {'error': 'invalid_client', 'error_description': 'Unauthorized'})

I have verified the developer_token, client_id, and client_secret are all accurate to what is in the API console. I have also verified the refresh_token is being passed correctly to the credential dict.

I am really at a loss on where to go from here. I have read many stack overflow threads with similar titles, and yet I am still stuck at the same place.

Here are some relevant links.

Google Ads API configuration

Google Identity and Server side web apps

Google's example of an API call

Relevant code

class GoogleAds: def __init__(self):     self.scope = ['https://www.googleapis.com/auth/adwords']     self.client_id = os.getenv('GOOGLE_ADS_CLIENT_ID')     self.client_secret = os.getenv('GOOGLE_ADS_CLIENT_SECRET')     self.developer_token = os.getenv('GOOGLE_ADS_DEVELOPER_TOKEN')     self.refresh_token = os.getenv('GOOGLE_ADS_REFRESH_TOKEN') def authorize(self):     credentials = {         "developer_token": self.developer_token,         "refresh_token": self.refresh_token,         "client_id": self.client_id,         "client_secret": self.client_secret,         "use_proto_plus":"True",         "grant_type": "refresh_token",     }     print(credentials)     googleads_client = GoogleAdsClient.load_from_dict(credentials)     service = googleads_client.get_service("GoogleAdsService")     request = googleads_client.get_type("SearchGoogleAdsRequest")     return service, request 

I am building something to sort and add values from an API response. I ended up going with an interesting structure, and I just want to make sure there's nothing inherently wrong with it.

from collections import defaultdict # Helps create a unique nested default dict object # for code readability def dict_counter():     return defaultdict(lambda: 0) # Creates the nested defaultdict object ad_data = defaultdict(dict_counter) # Sorts each instance into its channel, and # adds the dict values incrimentally for ad in example:        # Collects channel and metrics     channel = ad['ad_group']['type_']     metrics = dict(         impressions= int(ad['metrics']['impressions']),         clicks     = int(ad['metrics']['clicks']),         cost       = int(ad['metrics']['cost_micros'])     )          # Adds the variables     ad_data[channel]['impressions'] += metrics['impressions']     ad_data[channel]['clicks'] += metrics['clicks']     ad_data[channel]['cost'] += metrics['cost'] 

The output is as desired. Again, I just want to make sure I'm not reinventing the wheel or doing something really inefficient here.

defaultdict(<function __main__.dict_counter()>,             {'DISPLAY_STANDARD': defaultdict(<function __main__.dict_counter.<locals>.<lambda>()>,                          {'impressions': 14, 'clicks': 4, 'cost': 9}),              'SEARCH_STANDARD': defaultdict(<function __main__.dict_counter.<locals>.<lambda>()>,                          {'impressions': 6, 'clicks': 2, 'cost': 4})}) 

Here's what my input data would look like:

example = [     {         'campaign':          {             'resource_name': 'customers/12345/campaigns/12345',             'status': 'ENABLED',             'name': 'test_campaign_2'         },         'ad_group': {             'resource_name': 'customers/12345/adGroups/12345',             'type_': 'DISPLAY_STANDARD'},         'metrics': {             'clicks': '1', 'cost_micros': '3', 'impressions': '5'         },         'ad_group_ad': {             'resource_name': 'customers/12345/adGroupAds/12345~12345',             'ad': {                 'resource_name': 'customers/12345/ads/12345'             }         }     },     {         'campaign':          {             'resource_name': 'customers/12345/campaigns/12345',             'status': 'ENABLED',             'name': 'test_campaign_2'         },         'ad_group': {             'resource_name': 'customers/12345/adGroups/12345',             'type_': 'SEARCH_STANDARD'},         'metrics': {             'clicks': '2', 'cost_micros': '4', 'impressions': '6'         },         'ad_group_ad': {             'resource_name': 'customers/12345/adGroupAds/12345~12345',             'ad': {                 'resource_name': 'customers/12345/ads/12345'             }         }     },     {         'campaign':          {             'resource_name': 'customers/12345/campaigns/12345',             'status': 'ENABLED',             'name': 'test_campaign_2'         },         'ad_group': {             'resource_name': 'customers/12345/adGroups/12345',             'type_': 'DISPLAY_STANDARD'},         'metrics': {             'clicks': '3', 'cost_micros': '6', 'impressions': '9'         },         'ad_group_ad': {             'resource_name': 'customers/12345/adGroupAds/12345~12345',             'ad': {                 'resource_name': 'customers/12345/ads/12345'             }         }     } ] 

Thanks!

Does Boto3 client support connectors for GoogleAds and FacebookAds? According to documentation we can use Custom Connector but when i try to use it in the code i get the below error saying it should be one of the built in types.

[ERROR] ParamValidationError: Parameter validation failed: Unknown parameter in connectorProfileConfig.connectorProfileProperties: "CustomConnector", must be one of: Amplitude, Datadog, Dynatrace, GoogleAnalytics, Honeycode, InforNexus, Marketo, Redshift, Salesforce, ServiceNow, Singular, Slack, Snowflake, Trendmicro, Veeva, Zendesk, SAPOData Unknown parameter in connectorProfileConfig.connectorProfileCredentials: "CustomConnector", must be one of: Amplitude, Datadog, Dynatrace, GoogleAnalytics, Honeycode, InforNexus, Marketo, Redshift, Salesforce, ServiceNow, Singular, Slack, Snowflake, Trendmicro, Veeva, Zendesk, SAPOData Traceback (most recent call last):   File "/var/task/lambda_function.py", line 34, in lambda_handler     response = client.create_connector_profile(   File "/var/runtime/botocore/client.py", line 391, in _api_call     return self._make_api_call(operation_name, kwargs)   File "/var/runtime/botocore/client.py", line 691, in _make_api_call     request_dict = self._convert_to_request_dict(   File "/var/runtime/botocore/client.py", line 739, in _convert_to_request_dict     request_dict = self._serializer.serialize_to_request(   File "/var/runtime/botocore/validate.py", line 360, in serialize_to_request     raise ParamValidationError(report=report.generate_report()) 

Code in Lambda :

import json import boto3 def lambda_handler(event, context):     client = boto3.client('appflow')        ### Google Ads     response = client.create_connector_profile(     connectorProfileName='GoogleAdsConn',     connectorType='CustomConnector',     # connectorLabel='GoogleAds',     connectionMode='Public',     connectorProfileConfig= {       "connectorProfileProperties": {           'CustomConnector': {                 # 'profileProperties': {                 #     'string': 'string'                 # },                 'oAuth2Properties': {                     'tokenUrl': 'https://oauth2.googleapis.com/token',                     'oAuth2GrantType': 'AUTHORIZATION_CODE'                     # ,'tokenUrlCustomProperties': {                     #     'string': 'string'                     # }                 }             }             },       "connectorProfileCredentials": {         "CustomConnector": {              "authenticationType": "OAUTH2",             "oauth2": {                 "accessToken": "myaccesstoken",                "clientId": "myclientid",                "clientSecret": "myclientsecret",               "oAuthRequest": {                   "authCode": "string",                  "redirectUri": "string"               },                "refreshToken": "myrefreshtoken"             }       }     }        }    )     return {         'response': response     } 

Any leads on this will be appreciated.
Thanks!

I am working on a project to convert Python code that's using the soon-to-be-discontinued Adwords API to the new version Google Ads API v10.

I have a query that needs a few metrics, but when I use the main customer ID that works to connect, I get REQUESTED_METRICS_FOR_MANAGER error saying I need to "issue separate requests against each client account under the manager account".

How do I generate a client account to do this? I haven't seen any examples of this step.

Thanks much!

I am using python to execute the query and retrieve the data from Google Ads I am trying to set start and end date as variable and use these in my query.

The query looks like this:

GAquery = """ SELECT     segments.date,     segments.device,     campaign.name,     metrics.clicks,     metrics.conversions,     metrics.conversions_value,     metrics.cost_micros,     metrics.impressions FROM    campaign WHERE segments.date >= '2021-12-01' AND segments.date <= '2022-02-27' ORDER BY     metrics.clicks DESC""" 

and it is executed by Google Function for Python

response = ga_service.search_stream(customer_id=customer_id, query=GAquery) 

This function does not have element params where i could use %s as placeholder in the query and then call it in params regular execute(sql,conn, params[Sdate,Edate] function in python.

So what i need to do is somehow break the query string, and add the dates in between. Something like this:

sdate = (dt.date.today() - dt.timedelta(days=60)) edate = dt.date.today() GAquery = """ SELECT     segments.date,     segments.device,     campaign.name,     metrics.clicks,     metrics.conversions,     metrics.conversions_value,     metrics.cost_micros,     metrics.impressions FROM    campaign WHERE segments.date """ + """>= """+ str(sdate) +""" AND segments.date""" +  """<=""" +str(edate) + """ ORDER BY     metrics.clicks DESC""" 

So basically i am trying to force variables into GAquery by breaking the query apart inserting it and stitching it together.

It is failing because i am not breaking it correctly and not adding it back together correctly.

Any idea how to handle this?