Skip to content

Commit

Permalink
version 13.0.7
Browse files Browse the repository at this point in the history
  • Loading branch information
qitia committed Dec 15, 2020
1 parent 33e437e commit 106657c
Show file tree
Hide file tree
Showing 14 changed files with 921 additions and 179 deletions.
8 changes: 8 additions & 0 deletions HISTORY.rst
@@ -1,6 +1,14 @@
.. :changelog:
Release History
13.0.7(2020-12-16)
+++++++++++++++++++++++++

* Update Bing Ads API Version 13 service proxies to reflect recent interface changes. For details please see the Bing Ads API Release Notes: https://docs.microsoft.com/en-us/bingads/guides/release-notes.
* Add bulk mappings for flyer ad extensions i.e., BulkFlyerAdExtension, BulkAccountFlyerAdExtension, BulkAdGroupFlyerAdExtension, and BulkCampaignFlyerAdExtension.
* Add ImpressionTrackingUrls mapping in the BulkResponsiveAd.
* Update the pattern matching to resolve EntityReadException with BulkCombinedList download.

13.0.6(2020-10-14)
+++++++++++++++++++++++++

Expand Down
3 changes: 3 additions & 0 deletions bingads/authorization.py
Expand Up @@ -689,6 +689,9 @@ def get_access_token(**kwargs):
if 'client_secret' in kwargs and kwargs['client_secret'] is None:
del kwargs['client_secret']

if 'requireliveconnect' in kwargs and kwargs['requireliveconnect'] == True:
del kwargs['tenant']

auth_token_url = _UriOAuthService.AUTH_TOKEN_URI[(kwargs['environment'], kwargs['requireliveconnect'])]

if 'tenant' in kwargs and kwargs['tenant'] is not None:
Expand Down
2 changes: 1 addition & 1 deletion bingads/manifest.py
@@ -1,5 +1,5 @@
import sys
VERSION = '13.0.6'
VERSION = '13.0.7'
BULK_FORMAT_VERSION_6 = '6.0'
WORKING_NAME = 'BingAdsSDKPython'
USER_AGENT = '{0} {1} {2}'.format(WORKING_NAME, VERSION, sys.version_info[0:3])
3 changes: 2 additions & 1 deletion bingads/v13/bulk/entities/ad_extensions/__init__.py
Expand Up @@ -11,4 +11,5 @@
from .bulk_price_ad_extensions import *
from .bulk_action_ad_extensions import *
from .bulk_promotion_ad_extensions import *
from .bulk_filterlink_ad_extensions import *
from .bulk_filterlink_ad_extensions import *
from .bulk_flyer_ad_extensions import *
171 changes: 171 additions & 0 deletions bingads/v13/bulk/entities/ad_extensions/bulk_flyer_ad_extensions.py
@@ -0,0 +1,171 @@
from bingads.v13.internal.bulk.mappings import _SimpleBulkMapping
from bingads.v13.internal.bulk.string_table import _StringTable
from bingads.service_client import _CAMPAIGN_OBJECT_FACTORY_V13

from bingads.v13.internal.extensions import *
from .common import _BulkAdExtensionBase
from .common import _BulkCampaignAdExtensionAssociation
from .common import _BulkAdGroupAdExtensionAssociation
from .common import _BulkAccountAdExtensionAssociation

_FlyerAdExtension = type(_CAMPAIGN_OBJECT_FACTORY_V13.create('FlyerAdExtension'))


class BulkFlyerAdExtension(_BulkAdExtensionBase):
""" Represents a flyer ad extension.
This class exposes the :attr:`flyer_ad_extension` property that can be read and written
as fields of the Flyer Ad Extension record in a bulk file.
For more information, see Flyer Ad Extension at https://go.microsoft.com/fwlink/?linkid=846127.
*See also:*
* :class:`.BulkServiceManager`
* :class:`.BulkOperation`
* :class:`.BulkFileReader`
* :class:`.BulkFileWriter`
"""

def __init__(self, account_id=None, ad_extension=None):
if ad_extension and not isinstance(ad_extension, _FlyerAdExtension):
raise ValueError('The type of ad_extension is: {0}, should be: {1}'.format(
type(ad_extension),
'FlyerAdExtension'
))
super(BulkFlyerAdExtension, self).__init__(
account_id=account_id,
ad_extension=ad_extension
)

@property
def flyer_ad_extension(self):
""" The flyer ad extension.
see Flyer Ad Extension at https://go.microsoft.com/fwlink/?linkid=846127.
"""

return self._ad_extension

@flyer_ad_extension.setter
def flyer_ad_extension(self, value):
self._ad_extension = value

_MAPPINGS = [
_SimpleBulkMapping(
header=_StringTable.FlyerName,
field_to_csv=lambda c: bulk_str(c.flyer_ad_extension.FlyerName),
csv_to_field=lambda c, v: setattr(c.flyer_ad_extension, 'FlyerName', v)
),
_SimpleBulkMapping(
header=_StringTable.MerchantCenterId,
field_to_csv=lambda c: bulk_str(c.flyer_ad_extension.StoreId),
csv_to_field=lambda c, v: setattr(c.flyer_ad_extension, 'StoreId', int(v) if v else None)
),
_SimpleBulkMapping(
header=_StringTable.Description,
field_to_csv=lambda c: bulk_str(c.flyer_ad_extension.Description),
csv_to_field=lambda c, v: setattr(c.flyer_ad_extension, 'Description', v)
),
_SimpleBulkMapping(
header=_StringTable.MediaIds,
field_to_csv=lambda c: field_to_csv_MediaIds(c.flyer_ad_extension),
csv_to_field=lambda c, v: csv_to_field_MediaIds(c.flyer_ad_extension, v)
),
_SimpleBulkMapping(
header=_StringTable.FinalUrlSuffix,
field_to_csv=lambda c: bulk_optional_str(c.flyer_ad_extension.FinalUrlSuffix, c.flyer_ad_extension.Id),
csv_to_field=lambda c, v: setattr(c.flyer_ad_extension, 'FinalUrlSuffix', v)
),
_SimpleBulkMapping(
header=_StringTable.TrackingTemplate,
field_to_csv=lambda c: bulk_str(c.flyer_ad_extension.TrackingUrlTemplate),
csv_to_field=lambda c, v: setattr(c.flyer_ad_extension, 'TrackingUrlTemplate', v if v else None)
),
_SimpleBulkMapping(
header=_StringTable.CustomParameter,
field_to_csv=lambda c: field_to_csv_UrlCustomParameters(c.flyer_ad_extension),
csv_to_field=lambda c, v: csv_to_field_UrlCustomParameters(c.flyer_ad_extension, v)
),
_SimpleBulkMapping(
header=_StringTable.FinalUrl,
field_to_csv=lambda c: field_to_csv_Urls(c.flyer_ad_extension.FinalUrls, c.flyer_ad_extension.Id),
csv_to_field=lambda c, v: csv_to_field_Urls(c.flyer_ad_extension.FinalUrls, v)
),
_SimpleBulkMapping(
header=_StringTable.FinalMobileUrl,
field_to_csv=lambda c: field_to_csv_Urls(c.flyer_ad_extension.FinalMobileUrls, c.flyer_ad_extension.Id),
csv_to_field=lambda c, v: csv_to_field_Urls(c.flyer_ad_extension.FinalMobileUrls, v)
),
_SimpleBulkMapping(
header=_StringTable.MediaUrls,
field_to_csv=lambda c: field_to_csv_Urls(c.flyer_ad_extension.ImageMediaUrls, c.flyer_ad_extension.Id),
csv_to_field=lambda c, v: csv_to_field_Urls(c.flyer_ad_extension.ImageMediaUrls, v)
),
]

def process_mappings_from_row_values(self, row_values):
self.flyer_ad_extension = _CAMPAIGN_OBJECT_FACTORY_V13.create('FlyerAdExtension')
self.flyer_ad_extension.Type = 'FlyerAdExtension'
super(BulkFlyerAdExtension, self).process_mappings_from_row_values(row_values)
row_values.convert_to_entity(self, BulkFlyerAdExtension._MAPPINGS)

def process_mappings_to_row_values(self, row_values, exclude_readonly_data):
self._validate_property_not_null(self.flyer_ad_extension, 'flyer_ad_extension')
super(BulkFlyerAdExtension, self).process_mappings_to_row_values(row_values, exclude_readonly_data)
self.convert_to_values(row_values, BulkFlyerAdExtension._MAPPINGS)


class BulkAccountFlyerAdExtension(_BulkAccountAdExtensionAssociation):
""" Represents an account level flyer ad extension.
This class exposes properties that can be read and written
as fields of the Account Flyer Ad Extension record in a bulk file.
For more information, see Account Flyer Ad Extension at https://go.microsoft.com/fwlink/?linkid=846127.
*See also:*
* :class:`.BulkServiceManager`
* :class:`.BulkOperation`
* :class:`.BulkFileReader`
* :class:`.BulkFileWriter`
"""

pass


class BulkCampaignFlyerAdExtension(_BulkCampaignAdExtensionAssociation):
""" Represents a campaign level imflyerage ad extension.
This class exposes properties that can be read and written
as fields of the Campaign Flyer Ad Extension record in a bulk file.
For more information, see Campaign Flyer Ad Extension at https://go.microsoft.com/fwlink/?linkid=846127.
*See also:*
* :class:`.BulkServiceManager`
* :class:`.BulkOperation`
* :class:`.BulkFileReader`
"""

pass

class BulkAdGroupFlyerAdExtension(_BulkAdGroupAdExtensionAssociation):
""" Represents an ad group level flyer ad extension.
This class exposes properties that can be read and written
as fields of the Ad Group Flyer Ad Extension record in a bulk file.
For more information, see Ad Group Flyer Ad Extension at https://go.microsoft.com/fwlink/?linkid=846127.
*See also:*
* :class:`.BulkServiceManager`
* :class:`.BulkOperation`
* :class:`.BulkFileReader`
* :class:`.BulkFileWriter`
"""

pass
25 changes: 5 additions & 20 deletions bingads/v13/bulk/entities/bulk_ads.py
Expand Up @@ -636,26 +636,6 @@ def responsive_ad(self, responsive_ad):
field_to_csv=lambda c: c.responsive_ad.LongHeadlineString,
csv_to_field=lambda c, v: setattr(c.responsive_ad, 'LongHeadlineString', v)
),
_SimpleBulkMapping(
header=_StringTable.LandscapeImageMediaId,
field_to_csv=lambda c: c.responsive_ad.LandscapeImageMediaId,
csv_to_field=lambda c, v: setattr(c.responsive_ad, 'LandscapeImageMediaId', int(v) if v else None)
),
_SimpleBulkMapping(
header=_StringTable.LandscapeLogoMediaId,
field_to_csv=lambda c: c.responsive_ad.LandscapeLogoMediaId,
csv_to_field=lambda c, v: setattr(c.responsive_ad, 'LandscapeLogoMediaId', int(v) if v else None)
),
_SimpleBulkMapping(
header=_StringTable.SquareImageMediaId,
field_to_csv=lambda c: c.responsive_ad.SquareImageMediaId,
csv_to_field=lambda c, v: setattr(c.responsive_ad, 'SquareImageMediaId', int(v) if v else None)
),
_SimpleBulkMapping(
header=_StringTable.SquareLogoMediaId,
field_to_csv=lambda c: c.responsive_ad.SquareLogoMediaId,
csv_to_field=lambda c, v: setattr(c.responsive_ad, 'SquareLogoMediaId', int(v) if v else None)
),
_SimpleBulkMapping(
header=_StringTable.Text,
field_to_csv=lambda c: c.responsive_ad.Text,
Expand All @@ -666,6 +646,11 @@ def responsive_ad(self, responsive_ad):
field_to_csv=lambda c: field_to_csv_ImageAssetLinks(c.responsive_ad.Images),
csv_to_field=lambda c, v: csv_to_field_ImageAssetLinks(c.responsive_ad.Images, v)
),
_SimpleBulkMapping(
header=_StringTable.ImpressionTrackingUrls,
field_to_csv=lambda c: field_to_csv_Urls(c.responsive_ad.ImpressionTrackingUrls, c.ad.Id),
csv_to_field=lambda c, v: csv_to_field_Urls(c.responsive_ad.ImpressionTrackingUrls, v)
)
]

def process_mappings_from_row_values(self, row_values):
Expand Down
2 changes: 1 addition & 1 deletion bingads/v13/bulk/entities/bulk_campaign.py
Expand Up @@ -361,7 +361,7 @@ def _write_website(c):
)
),
_SimpleBulkMapping(
header=_StringTable.BingMerchantCenterId,
header=_StringTable.MerchantCenterId,
field_to_csv=lambda c: BulkCampaign._write_store_id(c),
csv_to_field=lambda c, v: BulkCampaign._read_store_id(c, v)
),
Expand Down
Expand Up @@ -54,7 +54,7 @@ def __init__(self,
csv_to_field=lambda c, v: setattr(c, 'campaign_name', v)
),
_SimpleBulkMapping(
header=_StringTable.BingMerchantCenterId,
header=_StringTable.MerchantCenterId,
field_to_csv=lambda c: bulk_str(c.negative_campaign_criterion.Criterion.StoreId),
csv_to_field=lambda c, v: setattr(c.negative_campaign_criterion.Criterion,'StoreId', int(v) if v else None)
),
Expand Down
4 changes: 4 additions & 0 deletions bingads/v13/internal/bulk/bulk_object_factory.py
Expand Up @@ -16,6 +16,10 @@ class _BulkObjectFactory():
_StringTable.Keyword: _EntityInfo(lambda: BulkKeyword()),
_StringTable.CallAdExtension: _EntityInfo(lambda: BulkCallAdExtension()),
_StringTable.CampaignCallAdExtension: _EntityInfo(lambda: BulkCampaignCallAdExtension()),
_StringTable.FlyerAdExtension: _EntityInfo(lambda: BulkFlyerAdExtension()),
_StringTable.AccountFlyerAdExtension: _EntityInfo(lambda: BulkAccountFlyerAdExtension()),
_StringTable.CampaignFlyerAdExtension: _EntityInfo(lambda: BulkCampaignFlyerAdExtension()),
_StringTable.AdGroupFlyerAdExtension: _EntityInfo(lambda: BulkAdGroupFlyerAdExtension()),
_StringTable.ImageAdExtension: _EntityInfo(lambda: BulkImageAdExtension()),
_StringTable.AccountImageAdExtension: _EntityInfo(lambda: BulkAccountImageAdExtension()),
_StringTable.CampaignImageAdExtension: _EntityInfo(lambda: BulkCampaignImageAdExtension()),
Expand Down
13 changes: 11 additions & 2 deletions bingads/v13/internal/bulk/csv_headers.py
Expand Up @@ -127,10 +127,18 @@ class _CsvHeaders:

# Callout Ad Extension
_StringTable.CalloutText,

#Flyer Ad Extension
_StringTable.FlyerAdExtension,
_StringTable.AccountFlyerAdExtension,
_StringTable.CampaignFlyerAdExtension,
_StringTable.AdGroupFlyerAdExtension,
_StringTable.FlyerName,
_StringTable.MediaUrls,

# Product Target
_StringTable.BingMerchantCenterId,
_StringTable.BingMerchantCenterName,
_StringTable.MerchantCenterId,
_StringTable.MerchantCenterName,
_StringTable.ProductCondition1,
_StringTable.ProductValue1,
_StringTable.ProductCondition2,
Expand Down Expand Up @@ -317,6 +325,7 @@ class _CsvHeaders:
_StringTable.LongHeadline,
_StringTable.SquareImageMediaId,
_StringTable.SquareLogoMediaId,
_StringTable.ImpressionTrackingUrls,

# Ad Scheduling
_StringTable.AdSchedule,
Expand Down
17 changes: 14 additions & 3 deletions bingads/v13/internal/bulk/string_table.py
Expand Up @@ -182,6 +182,16 @@ class _StringTable:
AdGroupSitelinkAdExtension = "Ad Group Sitelink Ad Extension"
CampaignSitelinkAdExtension = "Campaign Sitelink Ad Extension"
AccountSitelinkAdExtension = "Account Sitelink Ad Extension"


# Flyer Ad Extension
FlyerAdExtension = "Flyer Ad Extension"
AccountFlyerAdExtension = "Account Flyer Ad Extension"
CampaignFlyerAdExtension = "Campaign Flyer Ad Extension"
AdGroupFlyerAdExtension = "Ad Group Flyer Ad Extension"
FlyerName = "Flyer Name"
MediaUrls = "Media Urls"


# Editorial Rejection Reasons
PublisherCountries = "Publisher Countries"
Expand All @@ -208,8 +218,8 @@ class _StringTable:
ProductValue7 = "Product Value 7"
ProductValue8 = "Product Value 8"

BingMerchantCenterId = "Store Id"
BingMerchantCenterName = "Store Name"
MerchantCenterId = "Store Id"
MerchantCenterName = "Store Name"

# App Ad Extension
AppAdExtension = "App Ad Extension"
Expand Down Expand Up @@ -486,6 +496,7 @@ class _StringTable:
LongHeadline = "Long Headline"
SquareImageMediaId = "Square Image Media Id"
SquareLogoMediaId = "Square Logo Media Id"
ImpressionTrackingUrls = "Impression Tracking Urls"

#Image
Image = "Image"
Expand Down Expand Up @@ -538,4 +549,4 @@ class _StringTable:
CampaignJobFunctionCriterion = 'Campaign Job Function Criterion'
CampaignIndustryCriterion = 'Campaign Industry Criterion'

FinalUrlSuffix = "Final Url Suffix"
FinalUrlSuffix = "Final Url Suffix"
12 changes: 8 additions & 4 deletions bingads/v13/internal/extensions.py
Expand Up @@ -518,7 +518,7 @@ def field_to_csv_Rsa_TextAssetLinks(entity):
contract['pinnedField'] = assetLink.PinnedField if hasattr(assetLink, 'PinnedField') else None
assetLinkContracts.append(contract)
if len(assetLinkContracts) > 0:
return json.dumps(assetLinkContracts)
return json.dumps(assetLinkContracts, sort_keys = True)
return None


Expand Down Expand Up @@ -1551,12 +1551,16 @@ def parse_combination_rules(combination_list, value):
return None

rules = value.split('&')
pattern = re.compile(combine_rule_pattern)
pattern = re.compile(combine_rule_pattern, re.IGNORECASE)
for rule in rules:
m = pattern.match(rule)
if m:
combination_rule = _CAMPAIGN_OBJECT_FACTORY_V13.create('CombinationRule')
combination_rule.Operator = m.group(1)
combination_rule.Operator = to_operation(m.group(1))
combination_rule.AudienceIds.long.extend([int(id) for id in m.group(2).split(',') if len(id) > 0])
combination_list.CombinationRules.CombinationRule.append(combination_rule)

def to_operation(op):
if op.lower() == 'and': return 'And'
if op.lower() == 'or': return 'Or'
if op.lower() == 'not': return 'Not'
return none

0 comments on commit 106657c

Please sign in to comment.