diff --git a/examples/BingAdsPythonConsoleExamples/BingAdsPythonConsoleExamples/BingAdsPythonConsoleExamples.pyproj b/examples/BingAdsPythonConsoleExamples/BingAdsPythonConsoleExamples/BingAdsPythonConsoleExamples.pyproj
index e7fccf89..aa1db70a 100644
--- a/examples/BingAdsPythonConsoleExamples/BingAdsPythonConsoleExamples/BingAdsPythonConsoleExamples.pyproj
+++ b/examples/BingAdsPythonConsoleExamples/BingAdsPythonConsoleExamples/BingAdsPythonConsoleExamples.pyproj
@@ -34,6 +34,9 @@
+
+ Code
+
diff --git a/examples/BingAdsPythonConsoleExamples/BingAdsPythonConsoleExamples/v10/BulkKeywordBidUpdate.py b/examples/BingAdsPythonConsoleExamples/BingAdsPythonConsoleExamples/v10/BulkKeywordBidUpdate.py
new file mode 100644
index 00000000..cd914f8f
--- /dev/null
+++ b/examples/BingAdsPythonConsoleExamples/BingAdsPythonConsoleExamples/v10/BulkKeywordBidUpdate.py
@@ -0,0 +1,537 @@
+from bingads.service_client import ServiceClient
+from bingads.authorization import *
+from bingads.v10 import *
+from bingads.v10.bulk import *
+
+import sys
+import webbrowser
+from time import gmtime, strftime
+from suds import WebFault
+
+# Optionally you can include logging to output traffic, for example the SOAP request and response.
+
+#import logging
+#logging.basicConfig(level=logging.INFO)
+#logging.getLogger('suds.client').setLevel(logging.DEBUG)
+
+if __name__ == '__main__':
+ print("Python loads the web service proxies at runtime, so you will observe " \
+ "a performance delay between program launch and main execution...\n")
+
+ DEVELOPER_TOKEN='DeveloperTokenGoesHere'
+ ENVIRONMENT='production'
+
+ # If you are using OAuth in production, CLIENT_ID is required and CLIENT_STATE is recommended.
+ CLIENT_ID='ClientIdGoesHere'
+ CLIENT_STATE='ClientStateGoesHere'
+
+ # The directory for the bulk files.
+ FILE_DIRECTORY='c:/bulk/'
+
+ # The name of the bulk download file.
+ DOWNLOAD_FILE_NAME='download.csv'
+
+ #The name of the bulk upload file.
+ UPLOAD_FILE_NAME='upload.csv'
+
+ # The name of the bulk upload result file.
+ RESULT_FILE_NAME='result.csv'
+
+ # The bulk file extension type.
+ FILE_FORMAT = DownloadFileType.csv
+
+ # The bulk file extension type as a string.
+ FILE_TYPE = 'Csv'
+
+ authorization_data=AuthorizationData(
+ account_id=None,
+ customer_id=None,
+ developer_token=DEVELOPER_TOKEN,
+ authentication=None,
+ )
+
+ # Take advantage of the BulkServiceManager class to efficiently manage ads and keywords for all campaigns in an account.
+ # The client library provides classes to accelerate productivity for downloading and uploading entities.
+ # For example the upload_entities method of the BulkServiceManager class submits your upload request to the bulk service,
+ # polls the service until the upload completed, downloads the result file to a temporary directory, and exposes BulkEntity-derived objects
+ # that contain close representations of the corresponding Campaign Management data objects and value sets.
+
+ # Poll for downloads at reasonable intervals. You know your data better than anyone.
+ # If you download an account that is well less than one million keywords, consider polling
+ # at 15 to 20 second intervals. If the account contains about one million keywords, consider polling
+ # at one minute intervals after waiting five minutes. For accounts with about four million keywords,
+ # consider polling at one minute intervals after waiting 10 minutes.
+
+ bulk_service=BulkServiceManager(
+ authorization_data=authorization_data,
+ poll_interval_in_milliseconds=5000,
+ environment=ENVIRONMENT,
+ )
+
+ campaign_service=ServiceClient(
+ service='CampaignManagementService',
+ authorization_data=authorization_data,
+ environment=ENVIRONMENT,
+ version=10,
+ )
+
+ customer_service=ServiceClient(
+ 'CustomerManagementService',
+ authorization_data=authorization_data,
+ environment=ENVIRONMENT,
+ version=9,
+ )
+
+def authenticate_with_username():
+ '''
+ Sets the authentication property of the global AuthorizationData instance with PasswordAuthentication.
+ '''
+ global authorization_data
+ authentication=PasswordAuthentication(
+ user_name='UserNameGoesHere',
+ password='PasswordGoesHere'
+ )
+
+ # Assign this authentication instance to the global authorization_data.
+ authorization_data.authentication=authentication
+
+def authenticate_with_oauth():
+ '''
+ Sets the authentication property of the global AuthorizationData instance with OAuthDesktopMobileAuthCodeGrant.
+ '''
+ global authorization_data
+
+ authentication=OAuthDesktopMobileAuthCodeGrant(
+ client_id=CLIENT_ID
+ )
+
+ # It is recommended that you specify a non guessable 'state' request parameter to help prevent
+ # cross site request forgery (CSRF).
+ authentication.state=CLIENT_STATE
+
+ # Assign this authentication instance to the global authorization_data.
+ authorization_data.authentication=authentication
+
+ # Register the callback function to automatically save the refresh token anytime it is refreshed.
+ # Uncomment this line if you want to store your refresh token. Be sure to save your refresh token securely.
+ authorization_data.authentication.token_refreshed_callback=save_refresh_token
+
+ refresh_token=get_refresh_token()
+
+ try:
+ # If we have a refresh token let's refresh it
+ if refresh_token is not None:
+ authorization_data.authentication.request_oauth_tokens_by_refresh_token(refresh_token)
+ else:
+ request_user_consent()
+ except OAuthTokenRequestException:
+ # The user could not be authenticated or the grant is expired.
+ # The user must first sign in and if needed grant the client application access to the requested scope.
+ request_user_consent()
+
+def request_user_consent():
+ global authorization_data
+
+ webbrowser.open(authorization_data.authentication.get_authorization_endpoint(), new=1)
+ # For Python 3.x use 'input' instead of 'raw_input'
+ if(sys.version_info.major >= 3):
+ response_uri=input(
+ "You need to provide consent for the application to access your Bing Ads accounts. " \
+ "After you have granted consent in the web browser for the application to access your Bing Ads accounts, " \
+ "please enter the response URI that includes the authorization 'code' parameter: \n"
+ )
+ else:
+ response_uri=raw_input(
+ "You need to provide consent for the application to access your Bing Ads accounts. " \
+ "After you have granted consent in the web browser for the application to access your Bing Ads accounts, " \
+ "please enter the response URI that includes the authorization 'code' parameter: \n"
+ )
+
+ if authorization_data.authentication.state != CLIENT_STATE:
+ raise Exception("The OAuth response state does not match the client request state.")
+
+ # Request access and refresh tokens using the URI that you provided manually during program execution.
+ authorization_data.authentication.request_oauth_tokens_by_response_uri(response_uri=response_uri)
+
+def get_refresh_token():
+ '''
+ Returns a refresh token if stored locally.
+ '''
+ file=None
+ try:
+ file=open("refresh.txt")
+ line=file.readline()
+ file.close()
+ return line if line else None
+ except IOError:
+ if file:
+ file.close()
+ return None
+
+def save_refresh_token(oauth_tokens):
+ '''
+ Stores a refresh token locally. Be sure to save your refresh token securely.
+ '''
+ with open("refresh.txt","w+") as file:
+ file.write(oauth_tokens.refresh_token)
+ file.close()
+ return None
+
+def search_accounts_by_user_id(user_id):
+ '''
+ Search for account details by UserId.
+
+ :param user_id: The Bing Ads user identifier.
+ :type user_id: long
+ :return: List of accounts that the user can manage.
+ :rtype: ArrayOfAccount
+ '''
+ global customer_service
+
+ paging={
+ 'Index': 0,
+ 'Size': 10
+ }
+
+ predicates={
+ 'Predicate': [
+ {
+ 'Field': 'UserId',
+ 'Operator': 'Equals',
+ 'Value': user_id,
+ },
+ ]
+ }
+
+ search_accounts_request={
+ 'PageInfo': paging,
+ 'Predicates': predicates
+ }
+
+ return customer_service.SearchAccounts(
+ PageInfo = paging,
+ Predicates = predicates
+ )
+
+def print_percent_complete(progress):
+ output_status_message("Percent Complete: {0}\n".format(progress.percent_complete))
+
+def output_status_message(message):
+ print(message)
+
+def output_bulk_errors(errors):
+ for error in errors:
+ if error.error is not None:
+ output_status_message("Number: {0}".format(error.error))
+ output_status_message("Error: {0}".format(error.number))
+ if error.editorial_reason_code is not None:
+ output_status_message("EditorialTerm: {0}".format(error.editorial_term))
+ output_status_message("EditorialReasonCode: {0}".format(error.editorial_reason_code))
+ output_status_message("EditorialLocation: {0}".format(error.editorial_location))
+ output_status_message("PublisherCountries: {0}".format(error.publisher_countries))
+ output_status_message('')
+
+def output_bing_ads_webfault_error(error):
+ if hasattr(error, 'ErrorCode'):
+ output_status_message("ErrorCode: {0}".format(error.ErrorCode))
+ if hasattr(error, 'Code'):
+ output_status_message("Code: {0}".format(error.Code))
+ if hasattr(error, 'Message'):
+ output_status_message("Message: {0}".format(error.Message))
+ output_status_message('')
+
+def output_webfault_errors(ex):
+ if hasattr(ex.fault, 'detail') \
+ and hasattr(ex.fault.detail, 'ApiFault') \
+ and hasattr(ex.fault.detail.ApiFault, 'OperationErrors') \
+ and hasattr(ex.fault.detail.ApiFault.OperationErrors, 'OperationError'):
+ api_errors=ex.fault.detail.ApiFault.OperationErrors.OperationError
+ if type(api_errors) == list:
+ for api_error in api_errors:
+ output_bing_ads_webfault_error(api_error)
+ else:
+ output_bing_ads_webfault_error(api_errors)
+ elif hasattr(ex.fault, 'detail') \
+ and hasattr(ex.fault.detail, 'AdApiFaultDetail') \
+ and hasattr(ex.fault.detail.AdApiFaultDetail, 'Errors') \
+ and hasattr(ex.fault.detail.AdApiFaultDetail.Errors, 'AdApiError'):
+ api_errors=ex.fault.detail.AdApiFaultDetail.Errors.AdApiError
+ if type(api_errors) == list:
+ for api_error in api_errors:
+ output_bing_ads_webfault_error(api_error)
+ else:
+ output_bing_ads_webfault_error(api_errors)
+ elif hasattr(ex.fault, 'detail') \
+ and hasattr(ex.fault.detail, 'ApiFaultDetail') \
+ and hasattr(ex.fault.detail.ApiFaultDetail, 'BatchErrors') \
+ and hasattr(ex.fault.detail.ApiFaultDetail.BatchErrors, 'BatchError'):
+ api_errors=ex.fault.detail.ApiFaultDetail.BatchErrors.BatchError
+ if type(api_errors) == list:
+ for api_error in api_errors:
+ output_bing_ads_webfault_error(api_error)
+ else:
+ output_bing_ads_webfault_error(api_errors)
+ elif hasattr(ex.fault, 'detail') \
+ and hasattr(ex.fault.detail, 'ApiFaultDetail') \
+ and hasattr(ex.fault.detail.ApiFaultDetail, 'OperationErrors') \
+ and hasattr(ex.fault.detail.ApiFaultDetail.OperationErrors, 'OperationError'):
+ api_errors=ex.fault.detail.ApiFaultDetail.OperationErrors.OperationError
+ if type(api_errors) == list:
+ for api_error in api_errors:
+ output_bing_ads_webfault_error(api_error)
+ else:
+ output_bing_ads_webfault_error(api_errors)
+ elif hasattr(ex.fault, 'detail') \
+ and hasattr(ex.fault.detail, 'EditorialApiFaultDetail') \
+ and hasattr(ex.fault.detail.EditorialApiFaultDetail, 'BatchErrors') \
+ and hasattr(ex.fault.detail.EditorialApiFaultDetail.BatchErrors, 'BatchError'):
+ api_errors=ex.fault.detail.EditorialApiFaultDetail.BatchErrors.BatchError
+ if type(api_errors) == list:
+ for api_error in api_errors:
+ output_bing_ads_webfault_error(api_error)
+ else:
+ output_bing_ads_webfault_error(api_errors)
+ elif hasattr(ex.fault, 'detail') \
+ and hasattr(ex.fault.detail, 'EditorialApiFaultDetail') \
+ and hasattr(ex.fault.detail.EditorialApiFaultDetail, 'EditorialErrors') \
+ and hasattr(ex.fault.detail.EditorialApiFaultDetail.EditorialErrors, 'EditorialError'):
+ api_errors=ex.fault.detail.EditorialApiFaultDetail.EditorialErrors.EditorialError
+ if type(api_errors) == list:
+ for api_error in api_errors:
+ output_bing_ads_webfault_error(api_error)
+ else:
+ output_bing_ads_webfault_error(api_errors)
+ elif hasattr(ex.fault, 'detail') \
+ and hasattr(ex.fault.detail, 'EditorialApiFaultDetail') \
+ and hasattr(ex.fault.detail.EditorialApiFaultDetail, 'OperationErrors') \
+ and hasattr(ex.fault.detail.EditorialApiFaultDetail.OperationErrors, 'OperationError'):
+ api_errors=ex.fault.detail.EditorialApiFaultDetail.OperationErrors.OperationError
+ if type(api_errors) == list:
+ for api_error in api_errors:
+ output_bing_ads_webfault_error(api_error)
+ else:
+ output_bing_ads_webfault_error(api_errors)
+ # Handle serialization errors e.g. The formatter threw an exception while trying to deserialize the message:
+ # There was an error while trying to deserialize parameter https://bingads.microsoft.com/CampaignManagement/v10:Entities.
+ elif hasattr(ex.fault, 'detail') \
+ and hasattr(ex.fault.detail, 'ExceptionDetail'):
+ api_errors=ex.fault.detail.ExceptionDetail
+ if type(api_errors) == list:
+ for api_error in api_errors:
+ output_status_message(api_error.Message)
+ else:
+ output_status_message(api_errors.Message)
+ else:
+ raise Exception('Unknown WebFault')
+
+def output_bulk_keywords(bulk_entities):
+ for entity in bulk_entities:
+ output_status_message("BulkKeyword: \n")
+ output_status_message("AdGroup Id: {0}".format(entity.ad_group_id))
+ output_status_message("AdGroup Name: {0}".format(entity.ad_group_name))
+ output_status_message("Campaign Name: {0}".format(entity.campaign_name))
+ output_status_message("ClientId: {0}".format(entity.client_id))
+
+ if entity.last_modified_time is not None:
+ output_status_message("LastModifiedTime: {0}".format(entity.last_modified_time))
+
+ output_bulk_performance_data(entity.performance_data)
+ output_bulk_quality_score_data(entity.quality_score_data)
+ output_bulk_bid_suggestions(entity.bid_suggestions)
+
+ # Output the Campaign Management Keyword Object
+ output_keyword(entity.keyword)
+
+ if entity.has_errors:
+ output_bulk_errors(entity.errors)
+
+ output_status_message('')
+
+def output_keyword(keyword):
+ if keyword is not None:
+ output_status_message("Bid.Amount: {0}".format(
+ keyword.Bid.Amount if keyword.Bid is not None else None)
+ )
+ output_bidding_scheme(keyword.BiddingScheme)
+ output_status_message("DestinationUrl: {0}".format(keyword.DestinationUrl))
+ output_status_message("EditorialStatus: {0}".format(keyword.EditorialStatus))
+ output_status_message("FinalMobileUrls: ")
+ if keyword.FinalMobileUrls is not None:
+ for final_mobile_url in keyword.FinalMobileUrls['string']:
+ output_status_message("\t{0}".format(final_mobile_url))
+ output_status_message("FinalUrls: ")
+ if keyword.FinalUrls is not None:
+ for final_url in keyword.FinalUrls['string']:
+ output_status_message("\t{0}".format(final_url))
+ output_status_message("ForwardCompatibilityMap: ")
+ if keyword.ForwardCompatibilityMap is not None and len(keyword.ForwardCompatibilityMap.KeyValuePairOfstringstring) > 0:
+ for pair in text_ad.ForwardCompatibilityMap['KeyValuePairOfstringstring']:
+ output_status_message("Key: {0}".format(pair.key))
+ output_status_message("Value: {0}".format(pair.value))
+ output_status_message("Id: {0}".format(keyword.Id))
+ output_status_message("MatchType: {0}".format(keyword.MatchType))
+ output_status_message("Param1: {0}".format(keyword.Param1))
+ output_status_message("Param2: {0}".format(keyword.Param2))
+ output_status_message("Param3: {0}".format(keyword.Param3))
+ output_status_message("Status: {0}".format(keyword.Status))
+ output_status_message("Text: {0}".format(keyword.Text))
+ output_status_message("TrackingUrlTemplate: {0}".format(keyword.TrackingUrlTemplate))
+ output_status_message("UrlCustomParameters: ")
+ if keyword.UrlCustomParameters is not None and keyword.UrlCustomParameters.Parameters is not None:
+ for custom_parameter in keyword.UrlCustomParameters.Parameters['CustomParameter']:
+ output_status_message("\tKey: {0}".format(custom_parameter.Key))
+ output_status_message("\tValue: {0}".format(custom_parameter.Value))
+
+def output_bidding_scheme(bidding_scheme):
+ if bidding_scheme is None or type(bidding_scheme) == type(campaign_service.factory.create('ns0:BiddingScheme')):
+ return
+ elif type(bidding_scheme) == type(campaign_service.factory.create('ns0:EnhancedCpcBiddingScheme')):
+ output_status_message("BiddingScheme: EnhancedCpc")
+ elif type(bidding_scheme) == type(campaign_service.factory.create('ns0:InheritFromParentBiddingScheme')):
+ output_status_message("BiddingScheme: InheritFromParent")
+ elif type(bidding_scheme) == type(campaign_service.factory.create('ns0:MaxConversionsBiddingScheme')):
+ output_status_message("BiddingScheme: MaxConversions")
+ elif type(bidding_scheme) == type(campaign_service.factory.create('ns0:ManualCpcBiddingScheme')):
+ output_status_message("BiddingScheme: ManualCpc")
+ elif type(bidding_scheme) == type(campaign_service.factory.create('ns0:TargetCpaBiddingScheme')):
+ output_status_message("BiddingScheme: TargetCpa")
+ elif type(bidding_scheme) == type(campaign_service.factory.create('ns0:MaxClicksBiddingScheme')):
+ output_status_message("BiddingScheme: MaxClicks")
+
+def output_bulk_performance_data(performance_data):
+ if performance_data is not None:
+ output_status_message("AverageCostPerClick: {0}".format(performance_data.average_cost_per_click))
+ output_status_message("AverageCostPerThousandImpressions: {0}".format(performance_data.average_cost_per_thousand_impressions))
+ output_status_message("AveragePosition: {0}".format(performance_data.average_position))
+ output_status_message("Clicks: {0}".format(performance_data.clicks))
+ output_status_message("ClickThroughRate: {0}".format(performance_data.click_through_rate))
+ output_status_message("Conversions: {0}".format(performance_data.conversions))
+ output_status_message("CostPerConversion: {0}".format(performance_data.cost_per_conversion))
+ output_status_message("Impressions: {0}".format(performance_data.impressions))
+ output_status_message("Spend: {0}".format(performance_data.spend))
+
+def output_bulk_quality_score_data(quality_score_data):
+ if quality_score_data is not None:
+ output_status_message("KeywordRelevance: {0}".format(quality_score_data.keyword_relevance))
+ output_status_message("LandingPageRelevance: {0}".format(quality_score_data.landing_page_relevance))
+ output_status_message("LandingPageUserExperience: {0}".format(quality_score_data._landing_page_user_experience))
+ output_status_message("QualityScore: {0}".format(quality_score_data.quality_score))
+
+def output_bulk_bid_suggestions(bid_suggestions):
+ if bid_suggestions is not None:
+ output_status_message("BestPosition: {0}".format(bid_suggestions.best_position))
+ output_status_message("MainLine: {0}".format(bid_suggestions.main_line))
+ output_status_message("FirstPage: {0}".format(bid_suggestions.first_page))
+
+def write_entities_and_upload_file(upload_entities):
+ # Writes the specified entities to a local file and uploads the file. We could have uploaded directly
+ # without writing to file. This example writes to file as an exercise so that you can view the structure
+ # of the bulk records being uploaded as needed.
+ writer=BulkFileWriter(FILE_DIRECTORY+UPLOAD_FILE_NAME);
+ for entity in upload_entities:
+ writer.write_entity(entity)
+ writer.close()
+
+ file_upload_parameters=FileUploadParameters(
+ result_file_directory=FILE_DIRECTORY,
+ compress_upload_file=True,
+ result_file_name=RESULT_FILE_NAME,
+ overwrite_result_file=True,
+ upload_file_path=FILE_DIRECTORY+UPLOAD_FILE_NAME,
+ response_mode='ErrorsAndResults'
+ )
+
+ bulk_file_path=bulk_service.upload_file(file_upload_parameters, progress=print_percent_complete)
+
+ download_entities=[]
+ entities_generator=read_entities_from_bulk_file(file_path=bulk_file_path, result_file_type=ResultFileType.upload, file_format=FILE_FORMAT)
+ for entity in entities_generator:
+ download_entities.append(entity)
+
+ return download_entities
+
+def download_file(download_parameters):
+ bulk_file_path=bulk_service.download_file(download_parameters, progress=print_percent_complete)
+
+ download_entities=[]
+ entities_generator=read_entities_from_bulk_file(file_path=bulk_file_path, result_file_type=ResultFileType.full_download, file_format=FILE_FORMAT)
+ for entity in entities_generator:
+ download_entities.append(entity)
+
+ return download_entities
+
+def read_entities_from_bulk_file(file_path, result_file_type, file_format):
+ with BulkFileReader(file_path=file_path, result_file_type=result_file_type, file_format=file_format) as reader:
+ for entity in reader:
+ yield entity
+
+# Main execution
+if __name__ == '__main__':
+
+ errors=[]
+
+ try:
+ # You should authenticate for Bing Ads production services with a Microsoft Account,
+ # instead of providing the Bing Ads username and password set.
+ # Authentication with a Microsoft Account is currently not supported in Sandbox.
+ authenticate_with_oauth()
+
+ # Uncomment to run with Bing Ads legacy UserName and Password credentials.
+ # For example you would use this method to authenticate in sandbox.
+ #authenticate_with_username()
+
+ # Set to an empty user identifier to get the current authenticated Bing Ads user,
+ # and then search for all accounts the user may access.
+ user=customer_service.GetUser(None).User
+ accounts=search_accounts_by_user_id(user.Id)
+
+ # For this example we'll use the first account.
+ authorization_data.account_id=accounts['Account'][0].Id
+ authorization_data.customer_id=accounts['Account'][0].ParentCustomerId
+
+ download_parameters=DownloadParameters(
+ entities=['Keywords'],
+ result_file_directory=FILE_DIRECTORY,
+ result_file_name=DOWNLOAD_FILE_NAME,
+ overwrite_result_file=True,
+ last_sync_time_in_utc=None,
+ #campaign_ids=[OptionalCampaignId1GoesHere, OptionalCampaignId2GoesHere]
+ )
+
+ # Download all keywords across all ad groups.
+ download_entities=download_file(download_parameters)
+ output_status_message("Downloaded all keywords across all ad groups.\n");
+ for entity in download_entities:
+ if isinstance(entity, BulkKeyword):
+ output_bulk_keywords([entity])
+
+
+ upload_entities=[]
+
+ # Within the downloaded records, find all keywords that have bids.
+ for entity in download_entities:
+ if isinstance(entity, BulkKeyword) \
+ and entity.keyword is not None \
+ and entity.keyword.Bid is not None:
+ # Increase all bids by some predetermined amount or percentage.
+ # Implement your own logic to update bids by varying amounts.
+ entity.keyword.Bid.Amount += 0.01
+ upload_entities.append(entity)
+
+ if len(upload_entities) > 0:
+ output_status_message("Changed local bid of keywords. Starting upload.\n")
+
+ download_entities=write_entities_and_upload_file(upload_entities)
+ for entity in download_entities:
+ if isinstance(entity, BulkKeyword):
+ output_bulk_keywords([entity])
+ else:
+ output_status_message("No keywords in account.\n")
+
+ output_status_message("Program execution completed")
+
+ except WebFault as ex:
+ output_webfault_errors(ex)
+ except Exception as ex:
+ output_status_message(ex)
+
diff --git a/examples/BingAdsPythonConsoleExamples/BingAdsPythonConsoleExamples/v10/KeywordsAds.py b/examples/BingAdsPythonConsoleExamples/BingAdsPythonConsoleExamples/v10/KeywordsAds.py
index f56e6ddd..7ec498e2 100644
--- a/examples/BingAdsPythonConsoleExamples/BingAdsPythonConsoleExamples/v10/KeywordsAds.py
+++ b/examples/BingAdsPythonConsoleExamples/BingAdsPythonConsoleExamples/v10/KeywordsAds.py
@@ -24,7 +24,7 @@
# If you are using OAuth in production, CLIENT_ID is required and CLIENT_STATE is recommended.
CLIENT_ID='ClientIdGoesHere'
CLIENT_STATE='ClientStateGoesHere'
-
+
authorization_data=AuthorizationData(
account_id=None,
customer_id=None,
@@ -686,8 +686,7 @@ def output_keyword_results(keywords, keyword_ids, keyword_errors):
}
output_keyword_results(keywords, keyword_ids, keyword_errors)
-
-
+
# Here is a simple example that updates the campaign budget.
# If the campaign has a shared budget you cannot update the Campaign budget amount,
# and you must instead update the amount in the Budget object. If you try to update