diff --git a/HISTORY.rst b/HISTORY.rst
index 04a046b6..cdb1873f 100644
--- a/HISTORY.rst
+++ b/HISTORY.rst
@@ -2,6 +2,34 @@
Release History
+13.0.26(2026-12-09)
++++++++++++++++++++++++++
+API Updates:
+* Update Bing Ads API Version 13 service proxies to reflect recent interface changes. For details please see the [Bing Ads API Release Notes](https://learn.microsoft.com/en-us/advertising/guides/release-notes?view=bingads-13).
+* New report: BidStrategyReport.
+* New column ConversionDelay in AccountPerformanceReport, CampaignPerformanceReport and GoalsAndFunnelsReport.
+* New column CostPerConversion in AssetGroupPerformanceReport.
+* New API in AdInsight Service: GetAudienceBreakdown.
+* New criterion type: TopicCriterion.
+* Support multiple campaignIds/adGroupIds in ImpressionBasedRemarketingList.
+* New field Industry in UetTag.
+* New fields TrackingUrlTemplate, FinalUrlSuffix and UrlCustomParameters in AssetGroup.
+* New field IsPolitical in Campaign.
+* New field CurrencyCode, ReportingTimeZone and Scope in BidStrategy.
+* New field BidStrategyScope in Campaign.
+* Add enum value DataDriven in AttributionModelType.
+* New option NewTopicTargets and UpdateTopicTargets in GoogleImportOption.
+
+Bulk Mapping Updates:
+* Add bulk mappings: BulkAdGroupTopicCriterion, BulkContentPlacement and BulkTopic.
+* Add TrackingTemplate, FinalUrlSuffix and CustomParameter in BulkAssetGroup mapping.
+* Add BidStrategyScope, CurrencyCode and TimeZone in BulkBidStrategy mapping.
+* Add BidStrategyScope in BulkCampaign mapping.
+
+Other:
+* Support for Google login is now available. You can use GoogleOAuthDesktopMobileAuthCodeGrant or GoogleOAuthWebAuthCodeGrant to sign in with a Google account and access the Bing Ads API.
+* Remove pkg_resources and switch to importlib_resources.
+
13.0.25.3(2025-09-12)
+++++++++++++++++++++++++
* Update Bing Ads API Version 13 service proxies to reflect recent interface changes. For details please see the [Bing Ads API Release Notes](https://learn.microsoft.com/en-us/advertising/guides/release-notes?view=bingads-13).
diff --git a/bingads/authorization.py b/bingads/authorization.py
index 97589659..dd85e285 100644
--- a/bingads/authorization.py
+++ b/bingads/authorization.py
@@ -9,12 +9,13 @@
from .exceptions import OAuthTokenRequestException
-PRODUCTION='production'
-SANDBOX='sandbox'
-MSADS_MANAGE='msads.manage'
-ADS_MANAGE='ads.manage'
-BINGADS_MANAGE='bingads.manage'
-MSA_PROD='msa.prod'
+PRODUCTION = 'production'
+SANDBOX = 'sandbox'
+MSADS_MANAGE = 'msads.manage'
+ADS_MANAGE = 'ads.manage'
+BINGADS_MANAGE = 'bingads.manage'
+MSA_PROD = 'msa.prod'
+GOOGLE_PROD = 'google.prod'
class AuthorizationData:
""" Represents a user who intends to access the corresponding customer and account.
@@ -568,6 +569,62 @@ def __init__(self, client_id, oauth_tokens=None, env=PRODUCTION, oauth_scope=MSA
use_msa_prod=use_msa_prod
)
+class GoogleOAuthDesktopMobileAuthCodeGrant(OAuthWithAuthorizationCode):
+ """ Represents a Google OAuth authorization object implementing the authorization code grant flow for use in a desktop or mobile application.
+
+ You can use an instance of this class as the AuthorizationData.Authentication property
+ of an :class:`.AuthorizationData` object to authenticate with Bing Ads services.
+ In this case the AuthenticationToken request header will be set to the corresponding OAuthTokens.AccessToken value.
+
+ This class implements the authorization code grant flow for Google OAuth 2.0, which follows the standard OAuth 2.0 flow
+ as defined in detail in the Authorization Code Grant section of the OAuth 2.0 spec.
+ The Google access token obtained through this flow can be passed to the Bing Ads API backend in the same manner as Microsoft tokens.
+ """
+
+ def __init__(self, client_id, client_secret=None, oauth_tokens=None, env=PRODUCTION, oauth_scope=GOOGLE_PROD, tenant='common'):
+ """ Initializes a new instance of the this class with the specified client id.
+
+ :param client_id: The client identifier corresponding to your registered application.
+ :type client_id: str
+ :param oauth_tokens: Contains information about OAuth access tokens received from the Microsoft Account authorization service
+ :type oauth_tokens: OAuthTokens
+ """
+
+ super(GoogleOAuthDesktopMobileAuthCodeGrant, self).__init__(
+ client_id,
+ client_secret,
+ _UriOAuthService.REDIRECTION_URI[(env, oauth_scope)],
+ oauth_tokens=oauth_tokens,
+ env=env,
+ oauth_scope=oauth_scope,
+ tenant=tenant
+ )
+
+class GoogleOAuthWebAuthCodeGrant(OAuthWithAuthorizationCode):
+ """ Represents a Google OAuth authorization object implementing the authorization code grant flow for use in a web application.
+
+ You can use an instance of this class as the AuthorizationData.Authentication property
+ to authenticate with Bing Ads REST API services.
+ """
+
+ def __init__(self, client_id, client_secret, redirect_url, oauth_tokens=None, env=PRODUCTION, oauth_scope=GOOGLE_PROD, tenant='common'):
+ """ Initializes a new instance of this class with the specified client id.
+
+ :param client_id: The client identifier corresponding to your registered application.
+ :type client_id: str
+ :param oauth_tokens: OAuth token information
+ :type oauth_tokens: OAuthTokens
+ """
+ super(GoogleOAuthWebAuthCodeGrant, self).__init__(
+ client_id,
+ client_secret,
+ redirect_url,
+ oauth_tokens=oauth_tokens,
+ env=env,
+ oauth_scope=oauth_scope,
+ tenant=tenant
+ )
+
class OAuthWebAuthCodeGrant(OAuthWithAuthorizationCode):
""" Represents an OAuth authorization object implementing the authorization code grant flow for use in a web application.
@@ -666,33 +723,41 @@ class _UriOAuthService:
def __init__(self):
pass
- REDIRECTION_URI={
+ REDIRECTION_URI = {
(PRODUCTION, MSADS_MANAGE): 'https://login.microsoftonline.com/common/oauth2/nativeclient',
(PRODUCTION, ADS_MANAGE): 'https://login.microsoftonline.com/common/oauth2/nativeclient',
(PRODUCTION, BINGADS_MANAGE): 'https://login.live.com/oauth20_desktop.srf',
(SANDBOX, MSADS_MANAGE): 'https://login.windows-ppe.net/common/oauth2/nativeclient',
- (SANDBOX, MSA_PROD): 'https://login.microsoftonline.com/common/oauth2/nativeclient'
+ (SANDBOX, MSA_PROD): 'https://login.microsoftonline.com/common/oauth2/nativeclient',
+ (PRODUCTION, GOOGLE_PROD): 'http://localhost',
+ (SANDBOX, GOOGLE_PROD): 'http://localhost'
}
- AUTH_TOKEN_URI={
+ AUTH_TOKEN_URI = {
(PRODUCTION, MSADS_MANAGE): 'https://login.microsoftonline.com/common/oauth2/v2.0/token',
(PRODUCTION, ADS_MANAGE): 'https://login.microsoftonline.com/common/oauth2/v2.0/token',
(PRODUCTION, BINGADS_MANAGE): 'https://login.live.com/oauth20_token.srf',
(SANDBOX, MSADS_MANAGE): 'https://login.windows-ppe.net/consumers/oauth2/v2.0/token',
- (SANDBOX, MSA_PROD): 'https://login.microsoftonline.com/common/oauth2/v2.0/token'
+ (SANDBOX, MSA_PROD): 'https://login.microsoftonline.com/common/oauth2/v2.0/token',
+ (PRODUCTION, GOOGLE_PROD): 'https://oauth2.googleapis.com/token',
+ (SANDBOX, GOOGLE_PROD): 'https://oauth2.googleapis.com/token'
}
- AUTHORIZE_URI={
+ AUTHORIZE_URI = {
(PRODUCTION, MSADS_MANAGE): 'https://login.microsoftonline.com/common/oauth2/v2.0/authorize?client_id={0}&scope=https%3A%2F%2Fads.microsoft.com%2Fmsads.manage%20offline_access&response_type={1}&redirect_uri={2}',
(PRODUCTION, ADS_MANAGE): 'https://login.microsoftonline.com/common/oauth2/v2.0/authorize?client_id={0}&scope=https%3A%2F%2Fads.microsoft.com%2Fads.manage%20offline_access&response_type={1}&redirect_uri={2}',
(PRODUCTION, BINGADS_MANAGE): 'https://login.live.com/oauth20_authorize.srf?client_id={0}&scope=bingads.manage&response_type={1}&redirect_uri={2}',
(SANDBOX, MSADS_MANAGE): 'https://login.windows-ppe.net/consumers/oauth2/v2.0/authorize?client_id={0}&scope=https://api.ads.microsoft.com/msads.manage%20offline_access&response_type={1}&redirect_uri={2}&prompt=login',
- (SANDBOX, MSA_PROD): 'https://login.microsoftonline.com/common/oauth2/v2.0/authorize?client_id={0}&scope=https%3A%2F%2Fsi.ads.microsoft.com%2Fmsads.manage%20offline_access&response_type={1}&redirect_uri={2}'
+ (SANDBOX, MSA_PROD): 'https://login.microsoftonline.com/common/oauth2/v2.0/authorize?client_id={0}&scope=https%3A%2F%2Fsi.ads.microsoft.com%2Fmsads.manage%20offline_access&response_type={1}&redirect_uri={2}',
+ (PRODUCTION, GOOGLE_PROD): 'https://accounts.google.com/o/oauth2/v2/auth?client_id={0}&scope=openid%20email%20profile&response_type={1}&redirect_uri={2}&access_type=offline&prompt=consent',
+ (SANDBOX, GOOGLE_PROD): 'https://accounts.google.com/o/oauth2/v2/auth?client_id={0}&scope=openid%20email%20profile&response_type={1}&redirect_uri={2}&access_type=offline&prompt=consent'
}
- SCOPE={
+ SCOPE = {
(PRODUCTION, MSADS_MANAGE): 'https://ads.microsoft.com/msads.manage offline_access',
(PRODUCTION, ADS_MANAGE): 'https://ads.microsoft.com/ads.manage offline_access',
(PRODUCTION, BINGADS_MANAGE): 'bingads.manage',
(SANDBOX, MSADS_MANAGE): 'https://api.ads.microsoft.com/msads.manage offline_access',
- (SANDBOX, MSA_PROD): 'https://si.ads.microsoft.com/msads.manage offline_access'
+ (SANDBOX, MSA_PROD): 'https://si.ads.microsoft.com/msads.manage offline_access',
+ (PRODUCTION, GOOGLE_PROD): 'openid email profile',
+ (SANDBOX, GOOGLE_PROD): 'openid email profile'
}
@staticmethod
@@ -725,4 +790,4 @@ def get_access_token(**kwargs):
raise OAuthTokenRequestException(error_json.get('error'), error_json.get('error_description'))
r_json = json.loads(r.text)
- return OAuthTokens(r_json['access_token'], int(r_json['expires_in']), r_json['refresh_token'], r_json)
+ return OAuthTokens(r_json['access_token'], int(r_json['expires_in']), r_json.get('refresh_token', None), r_json)
diff --git a/bingads/manifest.py b/bingads/manifest.py
index 8388f538..4b09e886 100644
--- a/bingads/manifest.py
+++ b/bingads/manifest.py
@@ -1,5 +1,5 @@
import sys
-VERSION = '13.0.25.3'
+VERSION = '13.0.26'
BULK_FORMAT_VERSION_6 = '6.0'
WORKING_NAME = 'BingAdsSDKPython'
USER_AGENT = '{0} {1} {2}'.format(WORKING_NAME, VERSION, sys.version_info[0:3])
diff --git a/bingads/service_client.py b/bingads/service_client.py
index 1fe91dc8..827be933 100644
--- a/bingads/service_client.py
+++ b/bingads/service_client.py
@@ -18,7 +18,7 @@ def __init__(self, resolver):
@type resolver: L{resolver.Resolver}
"""
self.resolver = resolver
-
+
def skip_value(self, type):
""" whether or not to skip setting the value """
return False
@@ -45,7 +45,7 @@ def __init__(self, service, version, authorization_data=None, environment='produ
self._authorization_data = authorization_data
self._refresh_oauth_tokens_automatically = True
self._version = ServiceClient._format_version(version)
-
+
# Use in-memory cache by default.
if 'cache' not in suds_options:
@@ -68,7 +68,7 @@ def __getattr__(self, name):
self.set_options(**self._options)
return _ServiceCall(self, name)
-
+
def get_response_header(self):
return self.hp.get_response_header()
@@ -109,7 +109,7 @@ def factory(self):
"""
return self.soap_client.factory
-
+
@property
def service_url(self):
""" The wsdl url of service based on the specific service and environment.
@@ -304,14 +304,18 @@ def name(self):
return self._name
-import pkg_resources
+import sys
+if sys.version_info >= (3, 9):
+ import importlib.resources as importlib_resources
+else:
+ import importlib_resources
import types
from suds.sudsobject import Property
from suds.sax.text import Text
# this is used to create entity only. Given the sandbox should have the same contract, we are good to use sandbox wsdl.
_CAMPAIGN_MANAGEMENT_SERVICE_V13 = Client(
- 'file:///' + pkg_resources.resource_filename('bingads', 'v13/proxies/sandbox/campaignmanagement_service.xml'), cache=DictCache())
+ 'file:///' + str(importlib_resources.files('bingads').joinpath('v13/proxies/sandbox/campaignmanagement_service.xml')), cache=DictCache())
_CAMPAIGN_OBJECT_FACTORY_V13 = _CAMPAIGN_MANAGEMENT_SERVICE_V13.factory
_CAMPAIGN_OBJECT_FACTORY_V13.builder = BingAdsBuilder(_CAMPAIGN_OBJECT_FACTORY_V13.builder.resolver)
diff --git a/bingads/service_info.py b/bingads/service_info.py
index 07fdde25..cde29cef 100644
--- a/bingads/service_info.py
+++ b/bingads/service_info.py
@@ -1,11 +1,15 @@
-import pkg_resources
+import sys
+if sys.version_info >= (3, 9):
+ import importlib.resources as importlib_resources
+else:
+ import importlib_resources
_SERVICE_LIST = ['adinsight', 'bulk', 'campaignmanagement', 'customerbilling', 'customermanagement', 'reporting']
SERVICE_INFO_DICT_V13 = {}
for service in _SERVICE_LIST:
- SERVICE_INFO_DICT_V13[(service, 'production')] = 'file:///' + pkg_resources.resource_filename('bingads', 'v13/proxies/production/%s_service.xml' % (service))
- SERVICE_INFO_DICT_V13[(service, 'sandbox')] = 'file:///' + pkg_resources.resource_filename('bingads', 'v13/proxies/sandbox/%s_service.xml' % (service))
+ SERVICE_INFO_DICT_V13[(service, 'production')] = 'file:///' + str(importlib_resources.files('bingads').joinpath('v13/proxies/production/%s_service.xml' % (service)))
+ SERVICE_INFO_DICT_V13[(service, 'sandbox')] = 'file:///' + str(importlib_resources.files('bingads').joinpath('v13/proxies/sandbox/%s_service.xml' % (service)))
SERVICE_INFO_DICT = {13: SERVICE_INFO_DICT_V13}
diff --git a/bingads/v13/bulk/entities/__init__.py b/bingads/v13/bulk/entities/__init__.py
index f019fad5..8c626452 100644
--- a/bingads/v13/bulk/entities/__init__.py
+++ b/bingads/v13/bulk/entities/__init__.py
@@ -58,3 +58,5 @@
from .bulk_new_customer_acquisition_goal import *
from .goals import *
from .account_placement_exclusion_list import *
+from .bulk_topic import *
+from .bulk_content_placement import *
diff --git a/bingads/v13/bulk/entities/bulk_asset_group.py b/bingads/v13/bulk/entities/bulk_asset_group.py
index ba3831f9..da79b18f 100644
--- a/bingads/v13/bulk/entities/bulk_asset_group.py
+++ b/bingads/v13/bulk/entities/bulk_asset_group.py
@@ -163,6 +163,21 @@ def asset_group(self, asset_group):
field_to_csv=lambda c: bulk_optional_str(c.asset_group.Path2, c.asset_group.Id),
csv_to_field=lambda c, v: setattr(c.asset_group, 'Path2', v)
),
+ _SimpleBulkMapping(
+ header=_StringTable.TrackingTemplate,
+ field_to_csv=lambda c: bulk_optional_str(c.asset_group.TrackingUrlTemplate, c.asset_group.Id),
+ csv_to_field=lambda c, v: setattr(c.asset_group, 'TrackingUrlTemplate', v if v else None)
+ ),
+ _SimpleBulkMapping(
+ header=_StringTable.FinalUrlSuffix,
+ field_to_csv=lambda c: bulk_optional_str(c.asset_group.FinalUrlSuffix, c.asset_group.Id),
+ csv_to_field=lambda c, v: setattr(c.asset_group, 'FinalUrlSuffix', v if v else None)
+ ),
+ _SimpleBulkMapping(
+ header=_StringTable.CustomParameter,
+ field_to_csv=lambda c: field_to_csv_UrlCustomParameters(c.asset_group),
+ csv_to_field=lambda c, v: csv_to_field_UrlCustomParameters(c.asset_group, v)
+ ),
]
diff --git a/bingads/v13/bulk/entities/bulk_bid_strategy.py b/bingads/v13/bulk/entities/bulk_bid_strategy.py
index 8dc37a84..68760b4e 100644
--- a/bingads/v13/bulk/entities/bulk_bid_strategy.py
+++ b/bingads/v13/bulk/entities/bulk_bid_strategy.py
@@ -90,6 +90,21 @@ def account_id(self, value):
field_to_csv=lambda c: bulk_str(c.bid_strategy.AssociatedCampaignType),
csv_to_field=lambda c, v: setattr(c.bid_strategy, 'AssociatedCampaignType', v if v else None)
),
+ _SimpleBulkMapping(
+ header=_StringTable.BidStrategyScope,
+ field_to_csv=lambda c: bulk_str(c.bid_strategy.Scope),
+ csv_to_field=lambda c, v: csv_to_field_enum(c.bid_strategy, v, 'Scope', EntityScope)
+ ),
+ _SimpleBulkMapping(
+ header=_StringTable.CurrencyCode,
+ field_to_csv=lambda c: bulk_str(c.bid_strategy.CurrencyCode),
+ csv_to_field=lambda c, v: setattr(c.bid_strategy, 'CurrencyCode', v)
+ ),
+ _SimpleBulkMapping(
+ header=_StringTable.TimeZone,
+ field_to_csv=lambda c: bulk_str(c.bid_strategy.ReportingTimeZone),
+ csv_to_field=lambda c, v: setattr(c.bid_strategy, 'ReportingTimeZone', v)
+ ),
_ComplexBulkMapping(bid_strategy_biddingscheme_to_csv, csv_to_bid_strategy_biddingscheme),
]
diff --git a/bingads/v13/bulk/entities/bulk_campaign.py b/bingads/v13/bulk/entities/bulk_campaign.py
index 0cd6f0c4..64e2d4b2 100644
--- a/bingads/v13/bulk/entities/bulk_campaign.py
+++ b/bingads/v13/bulk/entities/bulk_campaign.py
@@ -44,6 +44,7 @@ def __init__(self, account_id=None, campaign=None):
self._destination_channel = None
self._is_multi_channel_campaign = None
self._should_serve_on_msan = None
+ self._scope = None
@property
def account_id(self):
@@ -148,6 +149,14 @@ def should_serve_on_msan(self):
def should_serve_on_msan(self, value):
self._should_serve_on_msan = value
+ @property
+ def scope(self):
+ return self._scope
+
+ @scope.setter
+ def scope(self, value):
+ self._scope = value
+
def _get_dynamic_feed_setting(self):
return self._get_setting(_DynamicFeedSetting, 'DynamicFeedSetting')
@@ -844,6 +853,11 @@ def _write_website(c):
field_to_csv=lambda c: field_to_csv_bool(c.campaign.IsPolitical),
csv_to_field=lambda c, v: setattr(c.campaign, 'IsPolitical', parse_bool(v))
),
+ _SimpleBulkMapping(
+ header=_StringTable.BidStrategyScope,
+ field_to_csv=lambda c: bulk_str(c.scope),
+ csv_to_field=lambda c, v: csv_to_field_enum(c, v, 'scope', EntityScope)
+ ),
]
def read_additional_data(self, stream_reader):
diff --git a/bingads/v13/bulk/entities/bulk_content_placement.py b/bingads/v13/bulk/entities/bulk_content_placement.py
new file mode 100644
index 00000000..8e6f59bb
--- /dev/null
+++ b/bingads/v13/bulk/entities/bulk_content_placement.py
@@ -0,0 +1,126 @@
+from bingads.v13.internal.bulk.string_table import _StringTable
+from bingads.v13.internal.bulk.entities.single_record_bulk_entity import _SingleRecordBulkEntity
+from bingads.v13.internal.bulk.mappings import _SimpleBulkMapping
+from bingads.v13.internal.extensions import *
+
+class BulkContentPlacement(_SingleRecordBulkEntity):
+ """ Represents a ContentPlacement.
+
+ This class exposes the property :attr:`brand_item` that can be read and written as fields of the ContentPlacement record
+ in a bulk file.
+
+ For more information, see ContentPlacement at https://go.microsoft.com/fwlink/?linkid=846127.
+
+ *See also:*
+
+ * :class:`.BulkServiceManager`
+ * :class:`.BulkOperation`
+ * :class:`.BulkFileReader`
+ * :class:`.BulkFileWriter`
+ """
+
+ def __init__(self, id=None, parent_id=None, name=None, status=None):
+ super(BulkContentPlacement, self).__init__()
+
+ self._id = id
+ self._parent_id = parent_id
+ self._name = name
+ self._status = status
+
+ @property
+ def id(self):
+ """ The identifier of the ContentPlacement.
+
+ Corresponds to the 'Id' field in the bulk file.
+
+ :rtype: int
+ """
+
+ return self._id
+
+ @id.setter
+ def id(self, id):
+ self._id = id
+
+ @property
+ def parent_id(self):
+ """ The parent identifier of the ContentPlacement that contains the ContentPlacement.
+
+ Corresponds to the 'Parent Id' field in the bulk file.
+
+ :rtype: int
+ """
+
+ return self._parent_id
+
+ @parent_id.setter
+ def parent_id(self, parent_id):
+ self._parent_id = parent_id
+
+ @property
+ def name(self):
+ """ The name of the ContentPlacement.
+
+ Corresponds to the 'Name' field in the bulk file.
+
+ :rtype: str
+ """
+
+ return self._name
+
+ @name.setter
+ def name(self, name):
+ self._name = name
+
+ @property
+ def status(self):
+ """ The status
+
+ Corresponds to the 'Status' field in the bulk file.
+
+ :rtype: str
+ """
+
+ return self._status
+
+ @status.setter
+ def status(self, status):
+ self._status = status
+
+ _MAPPINGS = [
+ _SimpleBulkMapping(
+ header=_StringTable.Id,
+ field_to_csv=lambda c: bulk_str(c.id),
+ csv_to_field=lambda c, v: setattr(c, 'id', int(v) if v else None)
+ ),
+ _SimpleBulkMapping(
+ header=_StringTable.Name,
+ field_to_csv=lambda c: bulk_str(c.name),
+ csv_to_field=lambda c, v: setattr(c, 'name', v)
+ ),
+ _SimpleBulkMapping(
+ header=_StringTable.ParentId,
+ field_to_csv=lambda c: bulk_str(c.parent_id),
+ csv_to_field=lambda c, v: setattr(c, 'parent_id', int(v) if v else None)
+ ),
+ _SimpleBulkMapping(
+ header=_StringTable.Name,
+ field_to_csv=lambda c: bulk_str(c.name),
+ csv_to_field=lambda c, v: setattr(c, 'name', v)
+ ),
+ _SimpleBulkMapping(
+ header=_StringTable.Status,
+ field_to_csv=lambda c: bulk_str(c.status),
+ csv_to_field=lambda c, v: setattr(c, 'status', v)
+ ),
+ ]
+
+ def process_mappings_from_row_values(self, row_values):
+
+ row_values.convert_to_entity(self, BulkContentPlacement._MAPPINGS)
+
+ def process_mappings_to_row_values(self, row_values, exclude_readonly_data):
+ self.convert_to_values(row_values, BulkContentPlacement._MAPPINGS)
+
+ def read_additional_data(self, stream_reader):
+ super(BulkContentPlacement, self).read_additional_data(stream_reader)
diff --git a/bingads/v13/bulk/entities/bulk_topic.py b/bingads/v13/bulk/entities/bulk_topic.py
new file mode 100644
index 00000000..5897dd96
--- /dev/null
+++ b/bingads/v13/bulk/entities/bulk_topic.py
@@ -0,0 +1,147 @@
+from bingads.v13.internal.bulk.string_table import _StringTable
+from bingads.v13.internal.bulk.entities.single_record_bulk_entity import _SingleRecordBulkEntity
+from bingads.v13.internal.bulk.mappings import _SimpleBulkMapping
+from bingads.v13.internal.extensions import *
+
+class BulkTopic(_SingleRecordBulkEntity):
+ """ Represents a topic.
+
+ This class exposes the property :attr:`brand_item` that can be read and written as fields of the topic record
+ in a bulk file.
+
+ For more information, see topic at https://go.microsoft.com/fwlink/?linkid=846127.
+
+ *See also:*
+
+ * :class:`.BulkServiceManager`
+ * :class:`.BulkOperation`
+ * :class:`.BulkFileReader`
+ * :class:`.BulkFileWriter`
+ """
+
+ def __init__(self, id=None, parent_id=None, topic_parent_id=None, name=None, status=None):
+ super(BulkTopic, self).__init__()
+
+ self._id = id
+ self._parent_id = parent_id
+ self._topic_parent_id = topic_parent_id
+ self._name = name
+ self._status = status
+
+ @property
+ def id(self):
+ """ The identifier of the topic.
+
+ Corresponds to the 'Id' field in the bulk file.
+
+ :rtype: int
+ """
+
+ return self._id
+
+ @id.setter
+ def id(self, id):
+ self._id = id
+
+ @property
+ def parent_id(self):
+ """ The parent identifier of the topic that contains the topic.
+
+ Corresponds to the 'Parent Id' field in the bulk file.
+
+ :rtype: int
+ """
+
+ return self._parent_id
+
+ @parent_id.setter
+ def parent_id(self, parent_id):
+ self._parent_id = parent_id
+
+ @property
+ def topic_parent_id(self):
+ """ The parent identifier of the topic that contains the topic.
+
+ Corresponds to the 'Topic Parent Id' field in the bulk file.
+
+ :rtype: int
+ """
+
+ return self._topic_parent_id
+
+ @topic_parent_id.setter
+ def topic_parent_id(self, topic_parent_id):
+ self._topic_parent_id = topic_parent_id
+
+ @property
+ def name(self):
+ """ The name of the topic.
+
+ Corresponds to the 'Name' field in the bulk file.
+
+ :rtype: str
+ """
+
+ return self._name
+
+ @name.setter
+ def name(self, name):
+ self._name = name
+
+ @property
+ def status(self):
+ """ The status
+
+ Corresponds to the 'Status' field in the bulk file.
+
+ :rtype: str
+ """
+
+ return self._status
+
+ @status.setter
+ def status(self, status):
+ self._status = status
+
+ _MAPPINGS = [
+ _SimpleBulkMapping(
+ header=_StringTable.Id,
+ field_to_csv=lambda c: bulk_str(c.id),
+ csv_to_field=lambda c, v: setattr(c, 'id', int(v) if v else None)
+ ),
+ _SimpleBulkMapping(
+ header=_StringTable.Name,
+ field_to_csv=lambda c: bulk_str(c.name),
+ csv_to_field=lambda c, v: setattr(c, 'name', v)
+ ),
+ _SimpleBulkMapping(
+ header=_StringTable.ParentId,
+ field_to_csv=lambda c: bulk_str(c.parent_id),
+ csv_to_field=lambda c, v: setattr(c, 'parent_id', int(v) if v else None)
+ ),
+ _SimpleBulkMapping(
+ header=_StringTable.TopicParentId,
+ field_to_csv=lambda c: bulk_str(c.topic_parent_id),
+ csv_to_field=lambda c, v: setattr(c, 'topic_parent_id', int(v) if v else None)
+ ),
+ _SimpleBulkMapping(
+ header=_StringTable.Name,
+ field_to_csv=lambda c: bulk_str(c.name),
+ csv_to_field=lambda c, v: setattr(c, 'name', v)
+ ),
+ _SimpleBulkMapping(
+ header=_StringTable.Status,
+ field_to_csv=lambda c: bulk_str(c.status),
+ csv_to_field=lambda c, v: setattr(c, 'status', v)
+ ),
+ ]
+
+ def process_mappings_from_row_values(self, row_values):
+
+ row_values.convert_to_entity(self, BulkTopic._MAPPINGS)
+
+ def process_mappings_to_row_values(self, row_values, exclude_readonly_data):
+ self.convert_to_values(row_values, BulkTopic._MAPPINGS)
+
+ def read_additional_data(self, stream_reader):
+ super(BulkTopic, self).read_additional_data(stream_reader)
diff --git a/bingads/v13/bulk/entities/target_criterions/__init__.py b/bingads/v13/bulk/entities/target_criterions/__init__.py
index dafefb08..7c4f91e4 100644
--- a/bingads/v13/bulk/entities/target_criterions/__init__.py
+++ b/bingads/v13/bulk/entities/target_criterions/__init__.py
@@ -33,3 +33,4 @@
from .bulk_ad_group_hotel_date_selection_type_criterion import *
from .bulk_ad_group_hotel_length_of_stay_criterion import *
from .bulk_ad_group_genre_criterion import *
+from .bulk_ad_group_topic_criterion import *
diff --git a/bingads/v13/bulk/entities/target_criterions/bulk_ad_group_topic_criterion.py b/bingads/v13/bulk/entities/target_criterions/bulk_ad_group_topic_criterion.py
new file mode 100644
index 00000000..ee48ee62
--- /dev/null
+++ b/bingads/v13/bulk/entities/target_criterions/bulk_ad_group_topic_criterion.py
@@ -0,0 +1,51 @@
+from bingads.service_client import _CAMPAIGN_OBJECT_FACTORY_V13
+from bingads.v13.bulk.entities.target_criterions.bulk_ad_group_biddable_criterion import BulkAdGroupBiddableCriterion
+from bingads.v13.internal.bulk.mappings import _SimpleBulkMapping
+from bingads.v13.internal.bulk.string_table import _StringTable
+from bingads.v13.internal.extensions import *
+
+
+class BulkAdGroupTopicCriterion(BulkAdGroupBiddableCriterion):
+ """ Represents an Ad Group Topic Criterion that can be read or written in a bulk file.
+
+ This class exposes the :attr:`biddable_ad_group_criterion` property that can be read and written as fields of the
+ Ad Group Topic Criterion record in a bulk file.
+
+ For more information, see Ad Group Topic Criterion at https://go.microsoft.com/fwlink/?linkid=846127.
+
+ *See also:*
+
+ * :class:`.BulkServiceManager`
+ * :class:`.BulkOperation`
+ * :class:`.BulkFileReader`
+ * :class:`.BulkFileWriter`
+ """
+
+ def __init__(self,
+ biddable_ad_group_criterion=None,
+ campaign_name=None,
+ ad_group_name=None, ):
+ super(BulkAdGroupTopicCriterion, self).__init__(biddable_ad_group_criterion, campaign_name, ad_group_name)
+
+ _MAPPINGS = [
+ _SimpleBulkMapping(
+ _StringTable.Target,
+ field_to_csv=lambda c: field_to_csv_TopicId(c.biddable_ad_group_criterion),
+ csv_to_field=lambda c, v: csv_to_field_TopicId(c.biddable_ad_group_criterion, v)
+ )
+ ]
+
+ def create_criterion(self):
+ self._biddable_ad_group_criterion.Criterion = _CAMPAIGN_OBJECT_FACTORY_V13.create('TopicCriterion')
+ self._biddable_ad_group_criterion.Criterion.Type = 'TopicCriterion'
+
+ def process_mappings_to_row_values(self, row_values, exclude_readonly_data):
+ super(BulkAdGroupTopicCriterion, self).process_mappings_to_row_values(row_values, exclude_readonly_data)
+ self.convert_to_values(row_values, BulkAdGroupTopicCriterion._MAPPINGS)
+
+ def process_mappings_from_row_values(self, row_values):
+ super(BulkAdGroupTopicCriterion, self).process_mappings_from_row_values(row_values)
+ row_values.convert_to_entity(self, BulkAdGroupTopicCriterion._MAPPINGS)
+
+ def read_additional_data(self, stream_reader):
+ super(BulkAdGroupTopicCriterion, self).read_additional_data(stream_reader)
diff --git a/bingads/v13/internal/bulk/bulk_object_factory.py b/bingads/v13/internal/bulk/bulk_object_factory.py
index 77f116eb..a495ebe4 100644
--- a/bingads/v13/internal/bulk/bulk_object_factory.py
+++ b/bingads/v13/internal/bulk/bulk_object_factory.py
@@ -180,6 +180,7 @@ class _BulkObjectFactory():
_StringTable.AdGroupNegativeIndustryCriterion: _EntityInfo(lambda: BulkAdGroupNegativeIndustryCriterion()),
_StringTable.AdGroupNegativeJobFunctionCriterion: _EntityInfo(lambda: BulkAdGroupNegativeJobFunctionCriterion()),
_StringTable.AdGroupGenreCriterion: _EntityInfo(lambda: BulkAdGroupGenreCriterion()),
+ _StringTable.AdGroupTopicCriterion: _EntityInfo(lambda: BulkAdGroupTopicCriterion()),
_StringTable.Label: _EntityInfo(lambda: BulkLabel()),
_StringTable.CampaignLabel: _EntityInfo(lambda: BulkCampaignLabel()),
_StringTable.AdGroupLabel: _EntityInfo(lambda: BulkAdGroupLabel()),
@@ -240,6 +241,8 @@ class _BulkObjectFactory():
_StringTable.AccountPlacementInclusionList: _EntityInfo(lambda: BulkAccountPlacementInclusionList()),
_StringTable.AccountPlacementInclusionListItem: _EntityInfo(lambda: BulkSharedSite()),
_StringTable.CampaignAccountPlacementInclusionListAssociation: _EntityInfo(lambda: BulkAccountPlacementInclusionListAssociation()),
+ _StringTable.Topic: _EntityInfo(lambda: BulkTopic()),
+ _StringTable.ContentPlacement: _EntityInfo(lambda: BulkContentPlacement()),
}
ADDITIONAL_OBJECT_MAP = {
diff --git a/bingads/v13/internal/bulk/csv_headers.py b/bingads/v13/internal/bulk/csv_headers.py
index 47924ea4..af2735d7 100644
--- a/bingads/v13/internal/bulk/csv_headers.py
+++ b/bingads/v13/internal/bulk/csv_headers.py
@@ -331,6 +331,7 @@ class _CsvHeaders:
_StringTable.BidStrategyCommissionRate,
_StringTable.BidStrategyPercentMaxCpc,
_StringTable.BidStrategyTargetCostPerSale,
+ _StringTable.BidStrategyScope,
# Ad Format Preference
_StringTable.AdFormatPreference,
@@ -537,7 +538,7 @@ class _CsvHeaders:
_StringTable.NewCustomerAcquisitionBidOnlyMode,
_StringTable.AccountPlacementListItemUrl,
-
+ _StringTable.TopicParentId,
]
@staticmethod
diff --git a/bingads/v13/internal/bulk/string_table.py b/bingads/v13/internal/bulk/string_table.py
index 683406e9..a6f7eaaf 100644
--- a/bingads/v13/internal/bulk/string_table.py
+++ b/bingads/v13/internal/bulk/string_table.py
@@ -438,6 +438,7 @@ class _StringTable:
BidStrategyPercentMaxCpc = "Bid Strategy PercentMaxCpc"
BidStrategyCommissionRate = "Bid Strategy CommissionRate"
BidStrategyTargetCostPerSale = "Bid Strategy TargetCostPerSale"
+ BidStrategyScope = "Bid Strategy Scope"
# Remarketing
Audience = "Audience"
@@ -543,6 +544,7 @@ class _StringTable:
AdGroupNegativeIndustryCriterion = "Ad Group Negative Industry Criterion"
AdGroupNegativeJobFunctionCriterion = "Ad Group Negative Job Function Criterion"
AdGroupGenreCriterion = "Ad Group Genre Criterion"
+ AdGroupTopicCriterion = "Ad Group Topic Criterion"
# Responsive Ad
ResponsiveAd = "Responsive Ad"
@@ -751,3 +753,7 @@ class _StringTable:
CampaignAccountPlacementInclusionListAssociation = "Campaign Account Placement Inclusion List Association"
AccountPlacementInclusionListId = "Account Placement Inclusion List Id"
AccountPlacementInclusionListItemId = "Account Placement Inclusion List Item Id"
+
+ Topic = "Topic"
+ ContentPlacement = "Content Placement"
+ TopicParentId = "Topic Parent Id"
diff --git a/bingads/v13/internal/extensions.py b/bingads/v13/internal/extensions.py
index 7838891f..6a391b6b 100644
--- a/bingads/v13/internal/extensions.py
+++ b/bingads/v13/internal/extensions.py
@@ -59,6 +59,7 @@
HotelAdvanceBookingWindowCriterion = _CAMPAIGN_OBJECT_FACTORY_V13.create('HotelAdvanceBookingWindowCriterion')
HotelCheckInDateCriterion = _CAMPAIGN_OBJECT_FACTORY_V13.create('HotelCheckInDateCriterion')
GenreCriterion = _CAMPAIGN_OBJECT_FACTORY_V13.create('GenreCriterion')
+TopicCriterion = _CAMPAIGN_OBJECT_FACTORY_V13.create('TopicCriterion')
HotelCheckInDayCriterion = _CAMPAIGN_OBJECT_FACTORY_V13.create('HotelCheckInDayCriterion')
HotelDateSelectionTypeCriterion = _CAMPAIGN_OBJECT_FACTORY_V13.create('HotelDateSelectionTypeCriterion')
HotelLengthOfStayCriterion = _CAMPAIGN_OBJECT_FACTORY_V13.create('HotelLengthOfStayCriterion')
@@ -302,7 +303,7 @@ def csv_to_status(c, v):
c.ad_group.Status = AdGroupStatus.Deleted
else:
c.ad_group.Status = None
-
+
def parse_bid_option(str):
if str == "BidValue":
return BidOption.BidValue
@@ -1097,7 +1098,7 @@ def field_to_csv_UseSearcherTimeZone(bool_value, id):
return DELETE_VALUE if id and id > 0 else None
else:
return str(bool_value)
-
+
def csv_to_field_enum(entity, value, attr_name, enum_class):
"""
Generic method to convert CSV string values to enum fields on an entity.
@@ -1118,7 +1119,7 @@ def csv_to_field_enum(entity, value, attr_name, enum_class):
except (AttributeError, ValueError):
# If the value doesn't match any enum value, set to None
setattr(entity, attr_name, None)
-
+
def csv_to_field_CampaignStatus(entity, value):
if value is None or value == '':
entity.Status = None
@@ -1135,7 +1136,7 @@ def csv_to_field_CampaignStatus(entity, value):
elif value == 'Suspended':
entity.Status = CampaignStatus.Suspended
else:
- entity.Status = None
+ entity.Status = None
def field_to_csv_bool(bool_value):
if bool_value is None:
@@ -1606,6 +1607,17 @@ def csv_to_field_GenreId(entity, value):
if entity is not None and entity.Criterion is not None and isinstance(entity.Criterion,type(GenreCriterion)):
setattr(entity.Criterion, "GenreId", int(value) if value else None)
+def field_to_csv_TopicId(entity):
+ if entity is None or entity.Criterion is None or entity.Criterion.TopicId is None:
+ return None
+ return bulk_str(entity.Criterion.TopicId)
+
+def csv_to_field_TopicId(entity, value):
+ if value is None or value == '':
+ return
+ if entity is not None and entity.Criterion is not None and isinstance(entity.Criterion,type(TopicCriterion)):
+ setattr(entity.Criterion, "TopicId", int(value) if value else None)
+
def field_to_csv_EndDate(entity):
if entity is None or entity.Criterion is None or entity.Criterion.EndDate is None:
return None
diff --git a/bingads/v13/proxies/production/adinsight_service.xml b/bingads/v13/proxies/production/adinsight_service.xml
index 8a659060..484cf4d9 100644
--- a/bingads/v13/proxies/production/adinsight_service.xml
+++ b/bingads/v13/proxies/production/adinsight_service.xml
@@ -466,6 +466,7 @@
+
@@ -685,10 +686,71 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
@@ -718,13 +780,13 @@
-
+
-
-
+
+
@@ -800,13 +862,13 @@
-
+
-
+
-
+
@@ -859,7 +921,7 @@
-
+
@@ -902,10 +964,10 @@
-
+
-
+
@@ -953,10 +1015,10 @@
-
+
-
+
@@ -1031,9 +1093,9 @@
-
+
-
+
@@ -1067,7 +1129,7 @@
-
+
@@ -1120,7 +1182,7 @@
-
+
@@ -1488,7 +1550,7 @@
-
+
@@ -1640,7 +1702,7 @@
-
+
@@ -1788,7 +1850,7 @@
-
+
@@ -1815,7 +1877,7 @@
-
+
@@ -3012,9 +3074,9 @@
-
+
-
+
@@ -3062,7 +3124,7 @@
-
+
@@ -3083,7 +3145,7 @@
-
+
@@ -3144,7 +3206,7 @@
-
+
@@ -3322,6 +3384,9 @@
+
+
+
@@ -3407,11 +3472,57 @@
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 1
+
+
+
+
+
+
+ 2
+
+
+
+
+
+
+ 4
+
+
+
+
+
+
@@ -3872,6 +3983,9 @@
+
+
+
@@ -3925,9 +4039,9 @@
-
-
-
+
+
+
@@ -4241,6 +4355,30 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -4260,7 +4398,7 @@
-
+
@@ -4284,7 +4422,7 @@
-
+
@@ -4308,7 +4446,7 @@
-
+
@@ -4332,7 +4470,7 @@
-
+
@@ -4356,7 +4494,7 @@
-
+
@@ -4380,7 +4518,7 @@
-
+
@@ -4404,7 +4542,7 @@
-
+
@@ -4428,7 +4566,7 @@
-
+
@@ -4452,7 +4590,7 @@
-
+
@@ -4476,7 +4614,7 @@
-
+
@@ -4500,7 +4638,7 @@
-
+
@@ -4524,7 +4662,7 @@
-
+
@@ -4548,7 +4686,7 @@
-
+
@@ -4572,7 +4710,7 @@
-
+
@@ -4596,7 +4734,7 @@
-
+
@@ -4620,7 +4758,7 @@
-
+
@@ -4644,7 +4782,7 @@
-
+
@@ -4668,7 +4806,7 @@
-
+
@@ -4692,7 +4830,7 @@
-
+
@@ -4716,7 +4854,7 @@
-
+
@@ -4740,7 +4878,7 @@
-
+
@@ -4764,7 +4902,7 @@
-
+
@@ -4788,7 +4926,7 @@
-
+
@@ -4812,7 +4950,7 @@
-
+
@@ -4836,7 +4974,7 @@
-
+
@@ -4890,6 +5028,12 @@
+
+
+
+
+
+
@@ -5228,6 +5372,29 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/bingads/v13/proxies/production/campaignmanagement_service.xml b/bingads/v13/proxies/production/campaignmanagement_service.xml
index 43423f23..0499696f 100644
--- a/bingads/v13/proxies/production/campaignmanagement_service.xml
+++ b/bingads/v13/proxies/production/campaignmanagement_service.xml
@@ -1192,6 +1192,13 @@
+
+
+
+
+
+
+
@@ -1282,6 +1289,13 @@
+
+
+
+
+
+
+
@@ -1668,6 +1682,8 @@
+
+
@@ -5389,13 +5405,6 @@
-
-
-
-
-
-
-
@@ -6007,8 +6016,29 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -6038,6 +6068,7 @@
+
@@ -6053,6 +6084,7 @@
+
@@ -6105,6 +6137,7 @@
+
@@ -7268,6 +7301,7 @@
+
@@ -7285,6 +7319,7 @@
+
@@ -7525,6 +7560,17 @@
+
+
+
+
+
+
+
+
+
+
+
@@ -8175,6 +8221,13 @@
+
+
+
+
+
+
+
@@ -8318,6 +8371,13 @@
+
+
+
+
+
+
+
@@ -8587,6 +8647,20 @@
+
+
+
+ 33554432
+
+
+
+
+
+
+ 67108864
+
+
+
@@ -10399,9 +10473,7 @@
-
-
@@ -10416,9 +10488,6 @@
-
-
-
@@ -10430,88 +10499,13 @@
-
-
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/bingads/v13/proxies/production/customerbilling_service.xml b/bingads/v13/proxies/production/customerbilling_service.xml
index e4ad96a2..629fa63d 100644
--- a/bingads/v13/proxies/production/customerbilling_service.xml
+++ b/bingads/v13/proxies/production/customerbilling_service.xml
@@ -224,6 +224,24 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -279,6 +297,12 @@
+
+
+
+
+
+
@@ -1100,6 +1124,28 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -1175,6 +1221,12 @@
+
+
+
+
+
+
@@ -1437,6 +1489,27 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/bingads/v13/proxies/production/reporting_service.xml b/bingads/v13/proxies/production/reporting_service.xml
index d6d4fa4e..709a1552 100644
--- a/bingads/v13/proxies/production/reporting_service.xml
+++ b/bingads/v13/proxies/production/reporting_service.xml
@@ -2056,6 +2056,10 @@
+
+
+
+
@@ -2064,11 +2068,24 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -2290,18 +2307,6 @@
-
-
-
-
-
-
-
-
-
-
-
-
@@ -4595,6 +4600,8 @@
+
+
@@ -4938,16 +4945,19 @@
-
+
-
+
+
+
+
diff --git a/bingads/v13/proxies/sandbox/adinsight_service.xml b/bingads/v13/proxies/sandbox/adinsight_service.xml
index 5c4ce362..0716ac42 100644
--- a/bingads/v13/proxies/sandbox/adinsight_service.xml
+++ b/bingads/v13/proxies/sandbox/adinsight_service.xml
@@ -466,6 +466,7 @@
+
@@ -685,10 +686,71 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
@@ -718,13 +780,13 @@
-
+
-
-
+
+
@@ -800,13 +862,13 @@
-
+
-
+
-
+
@@ -859,7 +921,7 @@
-
+
@@ -902,10 +964,10 @@
-
+
-
+
@@ -953,10 +1015,10 @@
-
+
-
+
@@ -1031,9 +1093,9 @@
-
+
-
+
@@ -1067,7 +1129,7 @@
-
+
@@ -1120,7 +1182,7 @@
-
+
@@ -1488,7 +1550,7 @@
-
+
@@ -1640,7 +1702,7 @@
-
+
@@ -1788,7 +1850,7 @@
-
+
@@ -1815,7 +1877,7 @@
-
+
@@ -3012,9 +3074,9 @@
-
+
-
+
@@ -3062,7 +3124,7 @@
-
+
@@ -3083,7 +3145,7 @@
-
+
@@ -3144,7 +3206,7 @@
-
+
@@ -3322,6 +3384,9 @@
+
+
+
@@ -3334,6 +3399,7 @@
+
@@ -3407,11 +3473,57 @@
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 1
+
+
+
+
+
+
+ 2
+
+
+
+
+
+
+ 4
+
+
+
+
+
+
@@ -3762,6 +3874,7 @@
+
@@ -3872,6 +3985,9 @@
+
+
+
@@ -3925,9 +4041,9 @@
-
-
-
+
+
+
@@ -4241,6 +4357,30 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -4260,7 +4400,7 @@
-
+
@@ -4284,7 +4424,7 @@
-
+
@@ -4308,7 +4448,7 @@
-
+
@@ -4332,7 +4472,7 @@
-
+
@@ -4356,7 +4496,7 @@
-
+
@@ -4380,7 +4520,7 @@
-
+
@@ -4404,7 +4544,7 @@
-
+
@@ -4428,7 +4568,7 @@
-
+
@@ -4452,7 +4592,7 @@
-
+
@@ -4476,7 +4616,7 @@
-
+
@@ -4500,7 +4640,7 @@
-
+
@@ -4524,7 +4664,7 @@
-
+
@@ -4548,7 +4688,7 @@
-
+
@@ -4572,7 +4712,7 @@
-
+
@@ -4596,7 +4736,7 @@
-
+
@@ -4620,7 +4760,7 @@
-
+
@@ -4644,7 +4784,7 @@
-
+
@@ -4668,7 +4808,7 @@
-
+
@@ -4692,7 +4832,7 @@
-
+
@@ -4716,7 +4856,7 @@
-
+
@@ -4740,7 +4880,7 @@
-
+
@@ -4764,7 +4904,7 @@
-
+
@@ -4788,7 +4928,7 @@
-
+
@@ -4812,7 +4952,7 @@
-
+
@@ -4836,7 +4976,7 @@
-
+
@@ -4890,6 +5030,12 @@
+
+
+
+
+
+
@@ -5228,6 +5374,29 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/bingads/v13/proxies/sandbox/campaignmanagement_service.xml b/bingads/v13/proxies/sandbox/campaignmanagement_service.xml
index 60bb0ee0..eb86b049 100644
--- a/bingads/v13/proxies/sandbox/campaignmanagement_service.xml
+++ b/bingads/v13/proxies/sandbox/campaignmanagement_service.xml
@@ -1192,6 +1192,13 @@
+
+
+
+
+
+
+
@@ -1282,6 +1289,13 @@
+
+
+
+
+
+
+
@@ -1668,6 +1682,8 @@
+
+
@@ -4705,6 +4721,7 @@
+
@@ -5389,13 +5406,6 @@
-
-
-
-
-
-
-
@@ -6007,8 +6017,29 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -6038,6 +6069,7 @@
+
@@ -6053,6 +6085,7 @@
+
@@ -6105,6 +6138,7 @@
+
@@ -7016,6 +7050,62 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 3
+
+
+
+
+
+
+ 4
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -7268,6 +7358,7 @@
+
@@ -7285,6 +7376,7 @@
+
@@ -7525,6 +7617,17 @@
+
+
+
+
+
+
+
+
+
+
+
@@ -8169,12 +8272,26 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -8318,6 +8435,13 @@
+
+
+
+
+
+
+
@@ -8587,6 +8711,27 @@
+
+
+
+ 33554432
+
+
+
+
+
+
+ 67108864
+
+
+
+
+
+
+ 134217728
+
+
+
@@ -10399,9 +10544,7 @@
-
-
@@ -10416,9 +10559,6 @@
-
-
-
@@ -10430,88 +10570,13 @@
-
-
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
@@ -10557,6 +10622,117 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -15155,6 +15331,78 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -16272,6 +16520,24 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -20554,6 +20820,75 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/bingads/v13/proxies/sandbox/customerbilling_service.xml b/bingads/v13/proxies/sandbox/customerbilling_service.xml
index 6594f522..159e5da1 100644
--- a/bingads/v13/proxies/sandbox/customerbilling_service.xml
+++ b/bingads/v13/proxies/sandbox/customerbilling_service.xml
@@ -224,6 +224,24 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -279,6 +297,12 @@
+
+
+
+
+
+
@@ -1100,6 +1124,28 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -1175,6 +1221,12 @@
+
+
+
+
+
+
@@ -1437,6 +1489,27 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/bingads/v13/proxies/sandbox/reporting_service.xml b/bingads/v13/proxies/sandbox/reporting_service.xml
index 3f73b4a5..05fb8c73 100644
--- a/bingads/v13/proxies/sandbox/reporting_service.xml
+++ b/bingads/v13/proxies/sandbox/reporting_service.xml
@@ -2056,6 +2056,10 @@
+
+
+
+
@@ -2064,11 +2068,24 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -2290,18 +2307,6 @@
-
-
-
-
-
-
-
-
-
-
-
-
@@ -4595,6 +4600,8 @@
+
+
@@ -4938,16 +4945,19 @@
-
+
-
+
+
+
+
diff --git a/requirements.txt b/requirements.txt
index 56cfaf5e..67124777 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -7,3 +7,4 @@ coverage
flake8
setuptools
Sphinx
+importlib_resources>=5; python_version < "3.9"
\ No newline at end of file
diff --git a/setup.py b/setup.py
index 3aaa4fa4..3d597113 100644
--- a/setup.py
+++ b/setup.py
@@ -3,7 +3,7 @@
except ImportError:
from distutils.core import setup
-VERSION = '13.0.25.3'
+VERSION = '13.0.26'
with open('README.rst', 'r') as f:
readme = f.read()
@@ -14,6 +14,7 @@
'suds-community>=1.1.0',
'requests',
'enum34;python_version<"3.9"',
+ 'importlib_resources>=5; python_version<"3.9"',
]
setup(