#!/usr/bin/python # # Copyright 2009 Google Inc. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # """Methods to access CampaignService service.""" __author__ = 'api.sgrinberg@gmail.com (Stan Grinberg)' from aw_api import SanityCheck as glob_sanity_check from aw_api import SOAPPY from aw_api import ZSI from aw_api.Errors import ValidationError from aw_api.WebService import WebService class CampaignService(object): """Wrapper for CampaignService. The Campaign Service lets you access, create, list, and modify campaigns and perform campaign-wide operations such as pausing a campaign. """ def __init__(self, headers, config, op_config, lock, logger): """Inits CampaignService. Args: headers: dict dictionary object with populated authentication credentials. config: dict dictionary object with populated configuration values. op_config: dict dictionary object with additional configuration values for this operation. lock: thread.lock the thread lock. logger: Logger the instance of Logger """ url = [op_config['server'], 'api/adwords', op_config['version'], self.__class__.__name__] if glob_sanity_check.IsNewApi(op_config['version']): url.insert(2, 'cm') if config['access']: url.insert(len(url) - 1, config['access']) self.__service = WebService(headers, config, op_config, '/'.join(url), lock, logger) self.__config = config self.__op_config = op_config if self.__config['soap_lib'] == SOAPPY: from aw_api.soappy_toolkit import MessageHandler from aw_api.soappy_toolkit import SanityCheck self.__web_services = None self.__message_handler = MessageHandler elif self.__config['soap_lib'] == ZSI: from aw_api import API_VERSIONS from aw_api.zsi_toolkit import SanityCheck if op_config['version'] in API_VERSIONS: module = '%s_services' % self.__class__.__name__ try: web_services = __import__('aw_api.zsi_toolkit.%s.%s' % (op_config['version'], module), globals(), locals(), ['']) except ImportError, e: # If one of library's required modules is missing, re raise exception. if str(e).find(module) < 0: raise ImportError(e) msg = ('The version \'%s\' is not compatible with \'%s\'.' % (op_config['version'], self.__class__.__name__)) raise ValidationError(msg) else: msg = 'Invalid API version, not one of %s.' % str(list(API_VERSIONS)) raise ValidationError(msg) self.__web_services = web_services self.__loc = eval('web_services.%sLocator()' % self.__class__.__name__) self.__sanity_check = SanityCheck def AddCampaign(self, campaign): """Create a new campaign. Args: campaign: dict information for the new campaign. Ex: campaign = { 'budgetAmount': '1000000', 'budgetOptimizerSettings': { 'bidCeiling': '1000000', 'enabled': 'False', 'takeOnOptimizedBids': 'False' }, 'budgetPeriod': 'Daily' or 'Monthly', 'contentTargeting': 'AllPlacements' or 'SelectedPlacements', 'conversionOptimizerSettings': { 'enabled': 'False', 'maxCpaBidForAllAdGroups': '1000000' }, 'endDay': '2010-01-01', 'geoTargeting': { 'cityTargets': { 'cities': ['New York, NY US'], 'excludedCities': ['New York, NY US'] }, 'countryTargets': { 'countries': ['US'], 'excludedCountries': ['US'] }, 'metroTargets': { 'excludedMetros': ['501'], 'metros': ['501'] }, 'regionTargets': { 'excludedRegions': ['US-NY'], 'regions': ['US-NY'] } 'proximityTargets': { 'circles': [ { 'latitudeMicroDegrees': '12345678', 'longitudeMicroDegrees': '-12345678', 'radiusMeters': '1000' } ] }, 'targetAll': 'False' }, 'languageTargeting': ['en'], 'name': 'Test Campaign', 'networkTargeting': ['GoogleSearch', 'ContentNetwork'], 'schedule': { 'intervals': [ { 'day': 'Monday', 'endHour': '17', 'endMinute': '0', 'multiplier': '1.0', 'startHour': '8', 'startMinute': '0' } ], 'status': 'Disabled' }, 'startDay': '2008-01-01', 'status': 'Active' } Returns: tuple The response from the API method. """ self.__sanity_check.ValidateCampaignV13(campaign) method_name = 'addCampaign' if self.__config['soap_lib'] == SOAPPY: return self.__service.CallMethod(method_name, (campaign)) elif self.__config['soap_lib'] == ZSI: web_services = self.__web_services request = eval('web_services.%sRequest()' % method_name) return self.__service.CallMethod(method_name, (({'campaign': campaign},)), 'Campaign', self.__loc, request) def AddCampaignList(self, campaigns): """Add a list of new Campaigns. Args: campaigns: list new campaign data. Ex: campaigns = [ { 'budgetAmount': '1000000', 'budgetOptimizerSettings': { 'bidCeiling': '1000000', 'enabled': 'False', 'takeOnOptimizedBids': 'False' }, 'budgetPeriod': 'Daily' or 'Monthly', 'contentTargeting': 'AllPlacements' or 'SelectedPlacements', 'conversionOptimizerSettings': { 'enabled': 'False', 'maxCpaBidForAllAdGroups': '1000000' }, 'endDay': '2010-01-01', 'geoTargeting': { 'cityTargets': { 'cities': ['New York, NY US'], 'excludedCities': ['New York, NY US'] }, 'countryTargets': { 'countries': ['US'], 'excludedCountries': ['US'] }, 'metroTargets': { 'excludedMetros': ['501'], 'metros': ['501'] }, 'regionTargets': { 'excludedRegions': ['US-NY'], 'regions': ['US-NY'] } 'proximityTargets': { 'circles': [ { 'latitudeMicroDegrees': '12345678', 'longitudeMicroDegrees': '-12345678', 'radiusMeters': '1000' } ] }, 'targetAll': 'False' }, 'languageTargeting': ['en'], 'name': 'Test Campaign', 'networkTargeting': ['GoogleSearch', 'ContentNetwork'], 'schedule': { 'intervals': [ { 'day': 'Monday', 'endHour': '17', 'endMinute': '0', 'multiplier': '1.0', 'startHour': '8', 'startMinute': '0' } ], 'status': 'Disabled' }, 'startDay': '2008-01-01', 'status': 'Active' } ] Returns: tuple The response from the API method. """ glob_sanity_check.ValidateTypes(((campaigns, list),)) for item in campaigns: self.__sanity_check.ValidateCampaignV13(item) method_name = 'addCampaignList' if self.__config['soap_lib'] == SOAPPY: return self.__service.CallMethod(method_name, (campaigns)) elif self.__config['soap_lib'] == ZSI: web_services = self.__web_services request = eval('web_services.%sRequest()' % method_name) return self.__service.CallMethod(method_name, (({'campaigns': campaigns},)), 'Campaign', self.__loc, request) def GetActiveAdWordsCampaigns(self): """Return all information about active campaigns. Active campaigns belonging to the customer issuing the request. Returns: tuple response from the API method. """ method_name = 'getActiveAdWordsCampaigns' if self.__config['soap_lib'] == SOAPPY: return self.__service.CallMethod(method_name, ()) elif self.__config['soap_lib'] == ZSI: web_services = self.__web_services request = eval('web_services.%sRequest()' % method_name) return self.__service.CallMethod(method_name, (), 'Campaign', self.__loc, request) def GetAllAdWordsCampaigns(self): """Return all information about all Campaigns. All campaigns belonging to the customer issuing the request. Returns: tuple response from the API method. """ method_name = 'getAllAdWordsCampaigns' if self.__config['soap_lib'] == SOAPPY: return self.__service.CallMethod(method_name, (0)) elif self.__config['soap_lib'] == ZSI: web_services = self.__web_services request = eval('web_services.%sRequest()' % method_name) return self.__service.CallMethod(method_name, (({'dummy': 0},)), 'Campaign', self.__loc, request) def GetCampaign(self, campaign_id): """Return all information about a specified Campaign. Args: campaign_id: str ID of the campaign, which must already exist. Ex: campaign_id = '1234567890' Returns: tuple response from the API method. """ glob_sanity_check.ValidateTypes(((campaign_id, (str, unicode)),)) method_name = 'getCampaign' if self.__config['soap_lib'] == SOAPPY: return self.__service.CallMethod(method_name, (campaign_id)) elif self.__config['soap_lib'] == ZSI: web_services = self.__web_services request = eval('web_services.%sRequest()' % method_name) return self.__service.CallMethod(method_name, (({'id': campaign_id},)), 'Campaign', self.__loc, request) def GetCampaignList(self, campaign_ids): """Return all information about a list of Campaigns. Args: campaign_ids: list IDs whose campaigns to retrieve. Ex: campaign_ids = ['1234567890'] Returns: tuple response from the API method. """ glob_sanity_check.ValidateTypes(((campaign_ids, list),)) for item in campaign_ids: glob_sanity_check.ValidateTypes(((item, (str, unicode)),)) method_name = 'getCampaignList' if self.__config['soap_lib'] == SOAPPY: return self.__service.CallMethod(method_name, (campaign_ids)) elif self.__config['soap_lib'] == ZSI: web_services = self.__web_services request = eval('web_services.%sRequest()' % method_name) return self.__service.CallMethod(method_name, (({'ids': campaign_ids},)), 'Campaign', self.__loc, request) def GetCampaignStats(self, campaign_ids, start_day, end_day): """Get statistics for a list of Campaigns. Args: campaign_ids: list campaign whose statistics are being queried. start_day: str starting day of the period for which statistics are to be collected. end_day: str ending day of the period for which statistics are to be collected, inclusive. Ex: campaign_ids = ['1234567890'] start_day = '2008-01-01' end_day = '2008-01-31' Returns: tuple response from the API method. """ glob_sanity_check.ValidateTypes(((campaign_ids, list), (start_day, (str, unicode)), (end_day, (str, unicode)))) for item in campaign_ids: glob_sanity_check.ValidateTypes(((item, (str, unicode)),)) method_name = 'getCampaignStats' if self.__config['soap_lib'] == SOAPPY: return self.__service.CallMethod( method_name, (campaign_ids, start_day, end_day)) elif self.__config['soap_lib'] == ZSI: web_services = self.__web_services request = eval('web_services.%sRequest()' % method_name) return self.__service.CallMethod(method_name, (({'campaignIds': campaign_ids}, {'startDay': start_day}, {'endDay': end_day},)), 'Campaign', self.__loc, request) def GetConversionOptimizerEligibility(self, campaign_ids): """Check if campaigns are eligible to use conversion optimzer. Args: campaign_ids: list campaigns to check. Ex: campaign_ids = ['1234567890'] Returns: tuple response from the API method. """ glob_sanity_check.ValidateTypes(((campaign_ids, list),)) for item in campaign_ids: glob_sanity_check.ValidateTypes(((item, (str, unicode)),)) method_name = 'getConversionOptimizerEligibility' if self.__config['soap_lib'] == SOAPPY: return self.__service.CallMethod(method_name, (campaign_ids)) elif self.__config['soap_lib'] == ZSI: web_services = self.__web_services request = eval('web_services.%sRequest()' % method_name) return self.__service.CallMethod(method_name, (({'campaignIds': campaign_ids},)), 'Campaign', self.__loc, request) def GetOptimizeAdServing(self, campaign_id): """Retrieve the 'optimized ad serving' setting for this campaign. Args: campaign_id: str ID of the campaign, which must already exist. Ex: campaign_id = '1234567890' Returns: tuple response from the API method. """ glob_sanity_check.ValidateTypes(((campaign_id, (str, unicode)),)) method_name = 'getOptimizeAdServing' if self.__config['soap_lib'] == SOAPPY: return self.__service.CallMethod(method_name, (campaign_id)) elif self.__config['soap_lib'] == ZSI: web_services = self.__web_services request = eval('web_services.%sRequest()' % method_name) return self.__service.CallMethod(method_name, (({'campaignId': campaign_id},)), 'Campaign', self.__loc, request) def GetRecommendedBudgetList(self, campaign_ids): """Returns the recommended budgets for the specified campaigns. Args: campaign_ids: list campaigns to get recommended budget for. Ex: campaign_ids = ['1234567890'] Returns: tuple response from the API method. """ glob_sanity_check.ValidateTypes(((campaign_ids, list),)) for item in campaign_ids: glob_sanity_check.ValidateTypes(((item, (str, unicode)),)) method_name = 'getRecommendedBudgetList' if self.__config['soap_lib'] == SOAPPY: return self.__service.CallMethod(method_name, (campaign_ids)) elif self.__config['soap_lib'] == ZSI: web_services = self.__web_services request = eval('web_services.%sRequest()' % method_name) return self.__service.CallMethod(method_name, (({'campaignIds': campaign_ids},)), 'Campaign', self.__loc, request) def SetOptimizeAdServing(self, campaign_id, enable): """Modify the 'optimized ad serving' setting for this campaign. Args: campaign_id: str ID of the campaign, which must already exist. enable: str if true, optimization will be turned on; if false, optimization will be turned off. Ex: campaign_id = '1234567890' enable = 'True' """ glob_sanity_check.ValidateTypes(((campaign_id, (str, unicode)), (enable, (str, unicode)))) method_name = 'setOptimizeAdServing' if self.__config['soap_lib'] == SOAPPY: enable = self.__sanity_check.UnType(enable) self.__service.CallMethod(method_name, (campaign_id, enable)) elif self.__config['soap_lib'] == ZSI: web_services = self.__web_services request = eval('web_services.%sRequest()' % method_name) self.__service.CallMethod(method_name, (({'campaignId': campaign_id}, {'enable': enable},)), 'Campaign', self.__loc, request) def UpdateCampaign(self, campaign): """Update the settings for an existing campaign. Args: campaign: dict new campaign settings. Ex: campaign = { 'budgetAmount': '1000000', 'budgetOptimizerSettings': { 'bidCeiling': '1000000', 'enabled': 'False', 'takeOnOptimizedBids': 'False' }, 'budgetPeriod': 'Daily' or 'Monthly', 'contentTargeting': 'AllPlacements' or 'SelectedPlacements', 'conversionOptimizerSettings': { 'enabled': 'False', 'maxCpaBidForAllAdGroups': '1000000' }, 'endDay': '2010-01-01', 'geoTargeting': { 'cityTargets': { 'cities': ['New York, NY US'], 'excludedCities': ['New York, NY US'] }, 'countryTargets': { 'countries': ['US'], 'excludedCountries': ['US'] }, 'metroTargets': { 'excludedMetros': ['501'], 'metros': ['501'] }, 'regionTargets': { 'excludedRegions': ['US-NY'], 'regions': ['US-NY'] } 'proximityTargets': { 'circles': [ { 'latitudeMicroDegrees': '12345678', 'longitudeMicroDegrees': '-12345678', 'radiusMeters': '1000' } ] }, 'targetAll': 'False' }, 'id': '1234567890', 'languageTargeting': ['en'], 'name': 'Test Campaign', 'networkTargeting': ['GoogleSearch', 'ContentNetwork'], 'schedule': { 'intervals': [ { 'day': 'Monday', 'endHour': '17', 'endMinute': '0', 'multiplier': '1.0', 'startHour': '8', 'startMinute': '0' } ], 'status': 'Disabled' }, 'startDay': '2008-01-01', 'status': 'Active' } """ self.__sanity_check.ValidateCampaignV13(campaign) method_name = 'updateCampaign' if self.__config['soap_lib'] == SOAPPY: self.__service.CallMethod(method_name, (campaign)) elif self.__config['soap_lib'] == ZSI: web_services = self.__web_services request = eval('web_services.%sRequest()' % method_name) self.__service.CallMethod(method_name, (({'campaign': campaign},)), 'Campaign', self.__loc, request) def UpdateCampaignList(self, campaigns): """Update the settings for a list of existing campaigns. Args: campaigns: list campaigns to to be updated. Ex: campaigns = [ { 'budgetAmount': '1000000', 'budgetOptimizerSettings': { 'bidCeiling': '1000000', 'enabled': 'False', 'takeOnOptimizedBids': 'False' }, 'budgetPeriod': 'Daily' or 'Monthly', 'contentTargeting': 'AllPlacements' or 'SelectedPlacements', 'conversionOptimizerSettings': { 'enabled': 'False', 'maxCpaBidForAllAdGroups': '1000000' }, 'endDay': '2010-01-01', 'geoTargeting': { 'cityTargets': { 'cities': ['New York, NY US'], 'excludedCities': ['New York, NY US'] }, 'countryTargets': { 'countries': ['US'], 'excludedCountries': ['US'] }, 'metroTargets': { 'excludedMetros': ['501'], 'metros': ['501'] }, 'regionTargets': { 'excludedRegions': ['US-NY'], 'regions': ['US-NY'] } 'proximityTargets': { 'circles': [ { 'latitudeMicroDegrees': '12345678', 'longitudeMicroDegrees': '-12345678', 'radiusMeters': '1000' } ] }, 'targetAll': 'False' }, 'id': '1234567890', 'languageTargeting': ['en'], 'name': 'Test Campaign', 'networkTargeting': ['GoogleSearch', 'ContentNetwork'], 'schedule': { 'intervals': [ { 'day': 'Monday', 'endHour': '17', 'endMinute': '0', 'multiplier': '1.0', 'startHour': '8', 'startMinute': '0' } ], 'status': 'Disabled' }, 'startDay': '2008-01-01', 'status': 'Active' } ] """ glob_sanity_check.ValidateTypes(((campaigns, list),)) for item in campaigns: self.__sanity_check.ValidateCampaignV13(item) method_name = 'updateCampaignList' if self.__config['soap_lib'] == SOAPPY: self.__service.CallMethod(method_name, (campaigns)) elif self.__config['soap_lib'] == ZSI: web_services = self.__web_services request = eval('web_services.%sRequest()' % method_name) self.__service.CallMethod(method_name, (({'campaigns': campaigns},)), 'Campaign', self.__loc, request) def Get(self, selector): """Return a list of campaigns. List of campaigns specified by the list of selectors from the customer's account. Args: selector: dict filter to run campaigns through. Returns: tuple list of campaigns meeting all the criteria of the selector. """ method_name = 'getCampaign' if self.__config['soap_lib'] == SOAPPY: self.__sanity_check.ValidateSelector(selector) selector = self.__message_handler.PackDictAsXml( selector, 'selector', ['ids', 'campaignStatuses', 'statsSelector', 'paging']) return self.__service.CallMethod( method_name.split(self.__class__.__name__.split('Service')[0])[0], (selector)) elif self.__config['soap_lib'] == ZSI: web_services = self.__web_services self.__sanity_check.ValidateSelector(selector, web_services) request = eval('web_services.%sRequest()' % method_name) return self.__service.CallMethod(method_name, (({'selector': selector},)), 'Campaign', self.__loc, request) def Mutate(self, ops): """Add, update, or remove campaigns. Args: ops: list unique operations. Returns: tuple mutated campaigns. """ method_name = 'mutateCampaign' if self.__config['soap_lib'] == SOAPPY: glob_sanity_check.ValidateTypes(((ops, list),)) new_ops = [] for op in ops: self.__sanity_check.ValidateOperation(op) new_ops.append(self.__message_handler.PackDictAsXml( op, 'operations', ['operator', 'biddingTransition', 'operand'])) ops = ''.join(new_ops) return self.__service.CallMethod( method_name.split(self.__class__.__name__.split('Service')[0])[0], (ops)) elif self.__config['soap_lib'] == ZSI: web_services = self.__web_services glob_sanity_check.ValidateTypes(((ops, list),)) for op in ops: op = self.__sanity_check.ValidateOperation(op, web_services) request = eval('web_services.%sRequest()' % method_name) return self.__service.CallMethod(method_name, (({'operations': ops},)), 'Campaign', self.__loc, request)