From 729e3d30187dec3a5b90745c99d38b6c04b427a6 Mon Sep 17 00:00:00 2001 From: Dave Waldrum Date: Thu, 19 May 2016 20:16:15 +0000 Subject: [PATCH 1/6] Making imports relative to module --- vast/ad.py | 2 +- vast/companionAd.py | 2 +- vast/creative.py | 6 +++--- vast/vast.py | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/vast/ad.py b/vast/ad.py index e16c3ff..d158bce 100644 --- a/vast/ad.py +++ b/vast/ad.py @@ -15,7 +15,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -from creative import Creative +from .creative import Creative REQUIRED_INLINE = ['AdSystem', 'AdTitle'] diff --git a/vast/companionAd.py b/vast/companionAd.py index 5e26973..f3a0317 100644 --- a/vast/companionAd.py +++ b/vast/companionAd.py @@ -15,7 +15,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -from trackingEvent import TrackingEvent +from .trackingEvent import TrackingEvent class CompanionAd(object): diff --git a/vast/creative.py b/vast/creative.py index 10e15f2..bda1603 100644 --- a/vast/creative.py +++ b/vast/creative.py @@ -16,9 +16,9 @@ # limitations under the License. -from companionAd import CompanionAd -from icon import Icon -from trackingEvent import TrackingEvent +from .companionAd import CompanionAd +from .icon import Icon +from .trackingEvent import TrackingEvent VALID_VIDEO_CLICKS = ['ClickThrough', 'ClickTracking', 'CustomClick'] diff --git a/vast/vast.py b/vast/vast.py index 82f1a06..d046933 100644 --- a/vast/vast.py +++ b/vast/vast.py @@ -15,7 +15,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -from ad import Ad +from .ad import Ad from xmlbuilder import XMLBuilder From f8b0a92c8b58c0ca167b7360c97572bf66034d6c Mon Sep 17 00:00:00 2001 From: Dave Waldrum Date: Tue, 31 May 2016 21:24:14 +0000 Subject: [PATCH 2/6] Updating libray to use lxml --- setup.py | 5 +- vast/ad.py | 33 +++--- vast/creative.py | 69 ++++++----- vast/icon.py | 4 +- vast/vast.py | 297 +++++++++++++++++++++++++++++++---------------- 5 files changed, 268 insertions(+), 140 deletions(-) diff --git a/setup.py b/setup.py index cb57be1..fae11f1 100644 --- a/setup.py +++ b/setup.py @@ -26,5 +26,8 @@ license='Apache', author='Timu Eren', author_email='selamtux@gmail.com', - description="Easy way to generate vast (3.0) xml" + description="Easy way to generate vast (3.0) xml", + install_requires=[ + 'lxml' + ] ) diff --git a/vast/ad.py b/vast/ad.py index d158bce..9ef3ca5 100644 --- a/vast/ad.py +++ b/vast/ad.py @@ -18,8 +18,8 @@ from .creative import Creative -REQUIRED_INLINE = ['AdSystem', 'AdTitle'] -REQUIRED_WRAPPER = ['AdSystem', 'VASTAdTagURI'] +REQUIRED_INLINE = ['id', 'ad_system', 'ad_title'] +REQUIRED_WRAPPER = ['id', 'ad_system', 'vast_ad_tag_uri'] def validateSettings(settings, requireds): @@ -39,30 +39,33 @@ def validateWrapperSettings(settings): class Ad(object): def __init__(self, settings={}): + print ("Settings") + print (settings) self.errors = [] self.surveys = [] self.impressions = [] self.creatives = [] + self.extensions = [] if settings["structure"].lower() == 'wrapper': validateWrapperSettings(settings) - self.VASTAdTagURI = settings["VASTAdTagURI"] + self.vast_ad_tag_uri = settings["vast_ad_tag_uri"] + self.ad_title = settings.get("ad_title", None) else: validateInLineSettings(settings) + self.ad_title = settings["ad_title"] self.id = settings["id"] - self.sequence = settings.get("sequence", None) self.structure = settings["structure"] - self.AdSystem = settings["AdSystem"] - self.AdTitle = settings["AdTitle"] + self.ad_system = settings["ad_system"] # optional elements - self.Error = settings.get("Error", None) - self.Description = settings.get("Description", None) - self.Advertiser = settings.get("Advertiser", None) + self.sequence = settings.get("sequence", None) + self.error = settings.get("error", None) + self.description = settings.get("description", None) + self.avertiser = settings.get("advertiser", None) - self.Pricing = settings.get("Pricing", None) - self.Extensions = settings.get("Extensions", None) + self.pricing = settings.get("pricing", None) def attachSurvey(self, settings): survey={"url": settings.url} @@ -74,8 +77,12 @@ def attachImpression(self, settings): self.impressions.append(settings) return self - def attachCreative(self, _type, options): - creative = Creative(_type, options) + def attachCreative(self, creative_type, options): + creative = Creative(creative_type, options) self.creatives.append(creative) return creative + def attachExtension(self, extension_type, xml): + self.extensions.append({"type": extension_type, "xml": xml}) + return self + diff --git a/vast/creative.py b/vast/creative.py index bda1603..e5eefba 100644 --- a/vast/creative.py +++ b/vast/creative.py @@ -21,12 +21,17 @@ from .trackingEvent import TrackingEvent VALID_VIDEO_CLICKS = ['ClickThrough', 'ClickTracking', 'CustomClick'] +VALID_CREATIVE_TYPES = ['Linear', 'NonLinear', 'CompanionAds'] +REQUIRED_MEDIA_ATTRIBUTES = ['type', 'width', 'height', 'delivery'] class Creative(object): - def __init__(self, _type, settings=None): + def __init__(self, creative_type, settings=None): + if creative_type not in VALID_CREATIVE_TYPES: + raise Exception('The supplied creative type is not a valid VAST creative type.') + settings = {} if settings is None else settings - self.type = _type + self.type = creative_type self.mediaFiles = [] self.trackingEvents = [] self.videoClicks = [] @@ -34,19 +39,17 @@ def __init__(self, _type, settings=None): self.clicks = [] self.resources = [] self.icons = [] - self.AdParameters = settings.get("AdParameters", None) - self._adParameters = None + self.ad_parameters = settings.get("adParameters", None) self.attributes = {} - self.duration = settings.get("Duration", None) + self.duration = settings.get("duration", None) self.skipoffset = settings.get("skipoffset", None) self.nonLinearClickEvent = None - if _type == "Linear" and self.duration is None: + if creative_type == "Linear" and self.duration is None: raise Exception('A Duration is required for all creatives. Consider defaulting to "00:00:00"') if "id" in settings: self.attributes["id"] = settings["id"] - if "width" in settings: self.attributes["width"] = settings["width"] if "height" in settings: @@ -65,16 +68,21 @@ def __init__(self, _type, settings=None): self.attributes["apiFramework"] = settings["apiFramework"] def attachMediaFile(self, url, settings={}): + keys = settings.keys() + print (keys) + for required in REQUIRED_MEDIA_ATTRIBUTES: + if required not in keys: + raise Exception("MediaFile missing required settings: {required}".format(required=required)) + media_file = {"attributes": {}} media_file["url"] = url - media_file["attributes"]["type"] = settings.get("type", 'video/mp4') - media_file["attributes"]["width"] = settings.get("width",'640') - media_file["attributes"]["height"] = settings.get("height", '360') - media_file["attributes"]["delivery"]= settings.get("delivery", 'progressive') - if "id" not in settings: - raise Exception('an `id` is required for all media files') - - media_file["attributes"]["id"] = settings["id"] + media_file["attributes"]["type"] = settings.get("type") + media_file["attributes"]["width"] = settings.get("width") + media_file["attributes"]["height"] = settings.get("height") + media_file["attributes"]["delivery"]= settings.get("delivery") + + if "id" in settings: + media_file["attributes"]["id"] = settings["id"] if "bitrate" in settings: media_file["attributes"]["bitrate"] = settings["bitrate"] if "minBitrate" in settings: @@ -93,32 +101,39 @@ def attachMediaFile(self, url, settings={}): self.mediaFiles.append(media_file) return self - def attachTrackingEvent(self, _type, url, offset=None): - self.trackingEvents.append(TrackingEvent(_type, url, offset)) + def attachTrackingEvent(self, event_type, url, offset=None): + self.trackingEvents.append(TrackingEvent(event_type, url, offset)) return self - def attachVideoClick(self, _type, url, _id=''): - if _type not in VALID_VIDEO_CLICKS: + def attachVideoClick(self, click_type, url, click_id=''): + if click_type not in VALID_VIDEO_CLICKS: raise Exception('The supplied VideoClick `type` is not a valid VAST VideoClick type.') - self.videoClicks.append({"type": _type, "url": url, "id": _id}) + + self.videoClicks.append({"type": click_type, "url": url, "id": click_id}) + return self def attachClickThrough(self, url): self.clickThroughs.append(url) return self - def attachClick(self, uri, _type=None): + def attachClick(self, uri, click_type=None): if isinstance(uri, basestring): - _type = 'NonLinearClickThrough' - self.clicks = [{"type": _type, "uri": uri}] + click_type = 'NonLinearClickThrough' + + self.clicks = [{"type": click_type, "uri": uri}] + return self - def attachResource(self, _type, uri, creative_type=None): - resource = {"type": _type, "uri": uri} - if _type == 'HTMLResource': + def attachResource(self, resource_type, uri, creative_type=None): + resource = {"type": resource_type, "uri": uri} + + if resource_type == 'HTMLResource': resource["html"] = uri + if creative_type is not None: resource["creativeType"] = creative_type + self.resources.append(resource) return self @@ -128,7 +143,7 @@ def attachIcon(self, settings): return icon def adParameters(self, data, xml_encoded): - self._adParameters = {"data": data, "xmlEncoded": xml_encoded} + self.ad_parameters = {"data": data, "xmlEncoded": xml_encoded} return self def attachNonLinearClickTracking(self, url): diff --git a/vast/icon.py b/vast/icon.py index 49db50c..a17e2c7 100644 --- a/vast/icon.py +++ b/vast/icon.py @@ -16,13 +16,13 @@ # limitations under the License. -REQURED_ATTRIBUTES = ["program", "width", "height", "xPosition", "yPosition"] +REQUIRED_ATTRIBUTES = ["program", "width", "height", "xPosition", "yPosition"] class Icon(object): def __init__(self, settings=dict()): keys = settings.keys() - for required in keys: + for required in REQUIRED_ATTRIBUTES: if required not in keys: raise Exception("Missing required attribute '{attr}'".format(attr=required)) diff --git a/vast/vast.py b/vast/vast.py index d046933..8a2fc64 100644 --- a/vast/vast.py +++ b/vast/vast.py @@ -16,130 +16,232 @@ # limitations under the License. from .ad import Ad -from xmlbuilder import XMLBuilder +from xml.etree import ElementTree as et +from lxml import etree class VAST(object): def __init__(self, settings={}): self.ads = [] self.version = settings.get("version", "3.0") - self.VASTErrorURI = settings.get("VASTErrorURI", None) + self.vast_error_uri = settings.get("vast_error_uri", None) - def attachAd(self, settings): + def attachAd(self, ad): + self.ads.append(ad) + return ad + + def createAd(self, settings): ad = Ad(settings) self.ads.append(ad) return ad def cdata(self, param): - return param - #return """""".format(param=param) - # + return """""".format(param=param) - def add_creatives(self, response, ad, track): + def add_creatives(self, elem, ad): linearCreatives = [c for c in ad.creatives if c.type == "Linear"] nonLinearCreatives = [c for c in ad.creatives if c.type == "NonLinear"] companionAdCreatives = [c for c in ad.creatives if c.type == "CompanionAd"] - with response.Creatives: - for creative in linearCreatives: - creativeOpts = {} + + creativesElem = etree.SubElement(elem, "Creatives") + + for creative in linearCreatives: + creativeElem = etree.SubElement(creativesElem, "Creative") + + linearOptions = {} + if creative.skipoffset: + linearOptions['skipoffset'] = str(creative.skipoffset) + + linearElem = etree.SubElement(creativeElem, "Linear", linearOptions) + + durationElem = etree.SubElement(linearElem, "Duration") + durationElem.text = str(creative.duration) + + if creative.ad_parameters: + adParametersOptions = {} + if creative.ad_parameters.xmlEncoded: + adParametersOptions['xmlEncoded'] = str(creative.ad_parameters.xmlEncoded) + + adParametersElem = etree.SubElement(linearElem, "AdParameters", adParametersOptions) + adParametersElem.text = str(self.cdata(creative.AdParameters.data)) + + if creative.trackingEvents: + trackingEventsElem = etree.SubElement(linearElem, "TrackingEvents") + + for event in creative.trackingEvents: + trackingEventOptions = {"event": str(event.event)} + + if event.offset: + trackingEventOptions["offset"] = str(event.offset) + + trackingEventElem = etree.SubElement(trackingEventsElem, "Tracking", trackingEventOptions) + trackingEventElem.text = str(self.cdata(event.url)) + + if creative.videoClicks: + videoClicksElem = etree.SubElement(linearElem, "VideoClicks") + + for click in creative.videoClicks: + clickOptions = {}; + + print (click) + + if click['id']: + clickOptions['id'] = str(click['id']); + + clickElem = etree.SubElement(videoClicksElem, click['type'], clickOptions) + clickElem.text = str(self.cdata(click['url'])) + + if creative.mediaFiles: + mediaFilesElem = etree.SubElement(linearElem, "MediaFiles") + + for media in creative.mediaFiles: + mediaFileElem = etree.SubElement(mediaFilesElem, "MediaFile", media["attributes"]) + mediaFileElem.text = str(self.cdata(media["url"])) + + ''' + if len(creative.icons) > 0: + iconsElem = etree.SubElement(linearElem, "Icons") + for icon in creative.icons: + with response.Icon(**icon.attributes): + attributes = {} + if "creativeType" in icon.resource: + attributes["creativeType"] = icon.resource["creativeType"] + attr = getattr(response, icon.resource["type"]) + attr(icon.resource["uri"], **attributes) + if icon.click or icon.clickThrough: + with response.IconClicks: + if icon.clickThrough: + response.IconClickThrough(icon.clickThrough) + if icon.click: + response.IconClickTraking(icon.click) + if icon.view: + response.IconViewTracking(icon.view) + ''' + + ''' + if len(nonLinearCreatives) > 0: + for creative in nonLinearCreatives: with response.Creative: - if creative.skipoffset: - creativeOpts["skipoffset"] = creative.skipoffset - with response.Linear(**creativeOpts): - if len(creative.icons) > 0: - with response.Icons: - for icon in creative.icons: - with response.Icon(**icon.attributes): - attributes = {} - if "creativeType" in icon.resource: - attributes["creativeType"] = icon.resource["creativeType"] - attr = getattr(response, icon.resource["type"]) - attr(icon.resource["uri"], **attributes) - if icon.click or icon.clickThrough: - with response.IconClicks: - if icon.clickThrough: - response.IconClickThrough(icon.clickThrough) - if icon.click: - response.IconClickTraking(icon.click) - if icon.view: - response.IconViewTracking(icon.view) - response.Duration(creative.duration) - with response.TrackingEvents: - for event in creative.trackingEvents: - if track: - attrs = {"event": event.event} - if event.offset: - attrs["offset"] = event.offset - response.Tracking(event.url, **attrs) - if creative.AdParameters: - response.AddParameters(creative.AdParameters) - with response.VideoClicks: - for click in creative.videoClicks: - attr = getattr(response, click["type"]) - attr(click["url"], **{"id": click.get("id", "")}) - - with response.MediaFiles: - for media in creative.mediaFiles: - response.MediaFile(media["url"], **media["attributes"]) - - if len(nonLinearCreatives) > 0: - for creative in nonLinearCreatives: - with response.Creative: - with response.NonLinearAds: - with response.NonLinear(**creative.attributes): - for resource in creative.resources: - attrs = {} - if "creativeType" in resource: - attrs["creativeType"] = resource["creativeType"] - element = getattr(response, resource["type"]) - element(resource["uri"], **attrs) - - for click in creative.clicks: - element = getattr(response, click["type"]) - element(click["uri"]) - - if creative.AdParameters: - response.AdParameters(creative.AdParameters["data"], **{ - "xmlEncoded": creative.AdParameters["xmlEncoded"] - }) - if creative.nonLinearClickEvent: - response.NonLinearClickTracking(creative.nonLinearClickEvent) - - if len(companionAdCreatives) > 0: - with response.CompanionAds: - for creative in companionAdCreatives: - with response.Companion(**creative.attributes): + with response.NonLinearAds: + with response.NonLinear(**creative.attributes): for resource in creative.resources: attrs = {} - element = getattr(response, resource["type"]) if "creativeType" in resource: attrs["creativeType"] = resource["creativeType"] + element = getattr(response, resource["type"]) element(resource["uri"], **attrs) - if "adParameters" in resource: - response.AdParameters(resource["adParameters"]["data"], **{ - "xmlEncoded": resource["adParameters"]["xmlEncoded"] - }) - with response.TrakingEvents: - for event in creative.trackingEvents: - if track: - attrs = {"event": event.event} - if event.offset: - attrs["offset"] = event.offset - response.Tracking(event.url, **attrs) - - for click in creative.clickThroughs: - response.CompanionClickThrough(click) + for click in creative.clicks: + element = getattr(response, click["type"]) + element(click["uri"]) + + if creative.AdParameters: + response.AdParameters(creative.AdParameters["data"], **{ + "xmlEncoded": creative.AdParameters["xmlEncoded"] + }) if creative.nonLinearClickEvent: - response.CompanionClickTracking(creative.nonLinearClickEvent) + response.NonLinearClickTracking(creative.nonLinearClickEvent) + + if len(companionAdCreatives) > 0: + with response.CompanionAds: + for creative in companionAdCreatives: + with response.Companion(**creative.attributes): + for resource in creative.resources: + attrs = {} + element = getattr(response, resource["type"]) + if "creativeType" in resource: + attrs["creativeType"] = resource["creativeType"] + element(resource["uri"], **attrs) + if "adParameters" in resource: + response.AdParameters(resource["adParameters"]["data"], **{ + "xmlEncoded": resource["adParameters"]["xmlEncoded"] + }) + with response.TrakingEvents: + for event in creative.trackingEvents: + if track: + attrs = {"event": event.event} + if event.offset: + attrs["offset"] = event.offset + response.Tracking(event.url, **attrs) + + for click in creative.clickThroughs: + response.CompanionClickThrough(click) + + if creative.nonLinearClickEvent: + response.CompanionClickTracking(creative.nonLinearClickEvent) + ''' + + def formatXmlResponse(self, response): + response = etree.tostring(response, pretty_print=True, encoding="UTF-8") + return response.decode("utf-8") def xml(self, options={}): - track = True if options.get("track", True) else options.get("track") + root = etree.Element('VAST') + root.set("version", str(self.version)) + + if len(self.ads) == 0 and self.vast_error_uri: + etree.SubElement(root, "Error", self.cdata(self.vast_error_uri)) + return self.formatXmlResponse(root) + + for ad in self.ads: + adOptions = { 'id': str(ad.id) } + + if ad.sequence: + adOptions['sequence'] = str(ad.sequence) + + adElem = etree.SubElement(root, "Ad", adOptions) + + if ad.structure.lower() == 'wrapper': + wrapperElem = etree.SubElement(adElem, "Wrapper") + + + response.AdSystem(ad.AdSystem["name"], **{"version": ad.AdSystem["version"]}) + response.VASTAdTagURI(self.cdata(ad.VASTAdTagURI)) + if ad.Error: + response.Error(self.cdata(ad.Error)) + for impression in ad.impressions: + if track: + response.Impression(self.cdata(impression["url"])) + self.add_creatives(response, ad, track) + else: + inlineElem = etree.SubElement(adElem, "InLine") + + adSystemElem = etree.SubElement(inlineElem, "AdSystem") + adSystemElem.text = str(ad.ad_system) + + adTitleElem = etree.SubElement(inlineElem, "AdTitle") + adTitleElem.text = str(self.cdata(ad.ad_title)) + + if ad.description: + adDescriptionElem = etree.SubElement(inlineElem, "Description") + adDescriptionElem.text = str(self.cdata(ad.description)) + + if ad.error: + adErrorElem = etree.SubElement(inlineElem, "Error") + adErrorElem.text = str(self.cdata(ad.error)) + + for impression in ad.impressions: + impressionElem = etree.SubElement(inlineElem, "Impression") + impressionElem.text = str(self.cdata(impression["url"])) + + self.add_creatives(inlineElem, ad) + + if ad.extensions: + extensionsElem = etree.SubElement(inlineElem, "Extensions") + + for extension in ad.extensions: + extensionElem = etree.SubElement(inlineElem, "Extension") + + if (extension['type']): + extensionElem.set("type", extension['type']); + + extensionElem.append(etree.fromstring(extension['xml'])) + + return self.formatXmlResponse(root) +''' response = XMLBuilder('VAST', version=self.version) - if len(self.ads) == 0 and self.VASTErrorURI: - response.Error(self.cdata(self.VASTErrorURI)) + if len(self.ads) == 0 and self.vast_error_uri: + response.Error(self.cdata(self.vast_error_uri)) return response for ad in self.ads: adOptions = {"id": ad.id} @@ -183,3 +285,4 @@ def xml(self, options={}): for extension in ad.Extensions: response.Extension(extension) return response +''' From e6b0a155f32cf5b4ae786937bc581a5a3ab6dbbf Mon Sep 17 00:00:00 2001 From: Dave Waldrum Date: Fri, 3 Jun 2016 21:37:20 +0000 Subject: [PATCH 3/6] Working on vast --- vast/vast.py | 35 ++++++++++++++++++++--------------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/vast/vast.py b/vast/vast.py index 8a2fc64..bc94c7f 100644 --- a/vast/vast.py +++ b/vast/vast.py @@ -81,17 +81,16 @@ def add_creatives(self, elem, ad): videoClicksElem = etree.SubElement(linearElem, "VideoClicks") for click in creative.videoClicks: - clickOptions = {}; + if ad.structure.lower() != 'wrapper' or click['type'] != 'ClickThrough': + clickOptions = {}; - print (click) + if click['id']: + clickOptions['id'] = str(click['id']); - if click['id']: - clickOptions['id'] = str(click['id']); + clickElem = etree.SubElement(videoClicksElem, click['type'], clickOptions) + clickElem.text = str(self.cdata(click['url'])) - clickElem = etree.SubElement(videoClicksElem, click['type'], clickOptions) - clickElem.text = str(self.cdata(click['url'])) - - if creative.mediaFiles: + if creative.mediaFiles and ad.structure.lower() != 'wrapper': mediaFilesElem = etree.SubElement(linearElem, "MediaFiles") for media in creative.mediaFiles: @@ -194,15 +193,21 @@ def xml(self, options={}): if ad.structure.lower() == 'wrapper': wrapperElem = etree.SubElement(adElem, "Wrapper") + adSystemElem = etree.SubElement(wrapperElem, "AdSystem") + adSystemElem.text = str(ad.ad_system) + + vastAdTagElem = etree.SubElement(wrapperElem, "VASTAdTagURI") + vastAdTagElem.text = str(self.cdata(ad.vast_ad_tag_uri)) + + if ad.error: + adErrorElem = etree.SubElement(wrapperElem, "Error") + adErrorElem.text = str(self.cdata(ad.error)) - response.AdSystem(ad.AdSystem["name"], **{"version": ad.AdSystem["version"]}) - response.VASTAdTagURI(self.cdata(ad.VASTAdTagURI)) - if ad.Error: - response.Error(self.cdata(ad.Error)) for impression in ad.impressions: - if track: - response.Impression(self.cdata(impression["url"])) - self.add_creatives(response, ad, track) + impressionElem = etree.SubElement(wrapperElem, "Impression") + impressionElem.text = str(self.cdata(impression["url"])) + + self.add_creatives(wrapperElem, ad) else: inlineElem = etree.SubElement(adElem, "InLine") From 7510bfe5d1c5ce571d89a9ffff883487d1f4f1d3 Mon Sep 17 00:00:00 2001 From: Dave Waldrum Date: Thu, 9 Jun 2016 18:27:22 +0000 Subject: [PATCH 4/6] Removing debugging --- vast/ad.py | 2 -- vast/creative.py | 1 - vast/vast.py | 52 ++---------------------------------------------- 3 files changed, 2 insertions(+), 53 deletions(-) diff --git a/vast/ad.py b/vast/ad.py index 9ef3ca5..eac2d25 100644 --- a/vast/ad.py +++ b/vast/ad.py @@ -39,8 +39,6 @@ def validateWrapperSettings(settings): class Ad(object): def __init__(self, settings={}): - print ("Settings") - print (settings) self.errors = [] self.surveys = [] self.impressions = [] diff --git a/vast/creative.py b/vast/creative.py index e5eefba..37b1304 100644 --- a/vast/creative.py +++ b/vast/creative.py @@ -69,7 +69,6 @@ def __init__(self, creative_type, settings=None): def attachMediaFile(self, url, settings={}): keys = settings.keys() - print (keys) for required in REQUIRED_MEDIA_ATTRIBUTES: if required not in keys: raise Exception("MediaFile missing required settings: {required}".format(required=required)) diff --git a/vast/vast.py b/vast/vast.py index bc94c7f..10707cd 100644 --- a/vast/vast.py +++ b/vast/vast.py @@ -97,10 +97,11 @@ def add_creatives(self, elem, ad): mediaFileElem = etree.SubElement(mediaFilesElem, "MediaFile", media["attributes"]) mediaFileElem.text = str(self.cdata(media["url"])) - ''' if len(creative.icons) > 0: iconsElem = etree.SubElement(linearElem, "Icons") for icon in creative.icons: + iconElem = etree.SubElement(iconsElem, "Icon", icon.attributes) + with response.Icon(**icon.attributes): attributes = {} if "creativeType" in icon.resource: @@ -115,7 +116,6 @@ def add_creatives(self, elem, ad): response.IconClickTraking(icon.click) if icon.view: response.IconViewTracking(icon.view) - ''' ''' if len(nonLinearCreatives) > 0: @@ -243,51 +243,3 @@ def xml(self, options={}): extensionElem.append(etree.fromstring(extension['xml'])) return self.formatXmlResponse(root) -''' - response = XMLBuilder('VAST', version=self.version) - if len(self.ads) == 0 and self.vast_error_uri: - response.Error(self.cdata(self.vast_error_uri)) - return response - for ad in self.ads: - adOptions = {"id": ad.id} - if ad.sequence: - adOptions["sequence"] = str(ad.sequence) - - with response.Ad(**adOptions): - if ad.structure.lower() == 'wrapper': - with response.Wrapper: - response.AdSystem(ad.AdSystem["name"], **{"version": ad.AdSystem["version"]}) - response.VASTAdTagURI(self.cdata(ad.VASTAdTagURI)) - if ad.Error: - response.Error(self.cdata(ad.Error)) - for impression in ad.impressions: - if track: - response.Impression(self.cdata(impression["url"])) - self.add_creatives(response, ad, track) - else: - with response.InLine: - response.AdSystem(ad.AdSystem["name"], **{"version": ad.AdSystem["version"]}) - response.AdTitle(self.cdata(ad.AdTitle)) - response.Description(self.cdata(ad.Description or '')) - - with response.Survey: - for survey in ad.surveys: - attributes = {} - if survey.type: - attributes["type"] = survey.type - response.Survey(self.cdata(survey.url), **attributes) - - if ad.Error: - response.Error(self.cdata(ad.Error)) - - for impression in ad.impressions: - if track: - response.Impression(self.cdata(impression["url"])) - - self.add_creatives(response, ad, track) - - if ad.Extensions: - for extension in ad.Extensions: - response.Extension(extension) - return response -''' From 4a2e51f05dff989a5be774d22f1acab51982ae07 Mon Sep 17 00:00:00 2001 From: Dave Waldrum Date: Thu, 9 Jun 2016 18:29:54 +0000 Subject: [PATCH 5/6] Fixing icon file --- vast/icon.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/vast/icon.py b/vast/icon.py index a17e2c7..c391b1f 100644 --- a/vast/icon.py +++ b/vast/icon.py @@ -33,15 +33,18 @@ def __init__(self, settings=dict()): self.click = None self.view = None - def setResource(self, _type, uri, creativeType=None): - if _type not in ('StaticResource', "IFrameResource", "HTMLResource"): + def setResource(self, resource_type, uri, creativeType=None): + if resource_type not in ('StaticResource', "IFrameResource", "HTMLResource"): raise Exception("Invalid resource type") - resource = {"type": _type, "uri": uri} - if _type == 'HTMLResource': + resource = {"type": resource_type, "uri": uri} + + if resource_type == 'HTMLResource': resource["html"] = uri + if creativeType: resource["creativeType"] = creativeType + self.resource = resource def setClickThrough(self, uri): From 4162ad79b55d57cf13fbf286b806cd8ef63e214a Mon Sep 17 00:00:00 2001 From: Dave Waldrum Date: Fri, 7 Oct 2016 15:17:02 +0000 Subject: [PATCH 6/6] Use LXML CDATA function to fix encoding --- vast/vast.py | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) mode change 100644 => 100755 vast/vast.py diff --git a/vast/vast.py b/vast/vast.py old mode 100644 new mode 100755 index 10707cd..8bcbfa4 --- a/vast/vast.py +++ b/vast/vast.py @@ -63,7 +63,7 @@ def add_creatives(self, elem, ad): adParametersOptions['xmlEncoded'] = str(creative.ad_parameters.xmlEncoded) adParametersElem = etree.SubElement(linearElem, "AdParameters", adParametersOptions) - adParametersElem.text = str(self.cdata(creative.AdParameters.data)) + adParametersElem.text = etree.CDATA(creative.AdParameters.data) if creative.trackingEvents: trackingEventsElem = etree.SubElement(linearElem, "TrackingEvents") @@ -75,7 +75,7 @@ def add_creatives(self, elem, ad): trackingEventOptions["offset"] = str(event.offset) trackingEventElem = etree.SubElement(trackingEventsElem, "Tracking", trackingEventOptions) - trackingEventElem.text = str(self.cdata(event.url)) + trackingEventElem.text = etree.CDATA(event.url) if creative.videoClicks: videoClicksElem = etree.SubElement(linearElem, "VideoClicks") @@ -88,14 +88,14 @@ def add_creatives(self, elem, ad): clickOptions['id'] = str(click['id']); clickElem = etree.SubElement(videoClicksElem, click['type'], clickOptions) - clickElem.text = str(self.cdata(click['url'])) + clickElem.text = etree.CDATA(click['url']) if creative.mediaFiles and ad.structure.lower() != 'wrapper': mediaFilesElem = etree.SubElement(linearElem, "MediaFiles") for media in creative.mediaFiles: mediaFileElem = etree.SubElement(mediaFilesElem, "MediaFile", media["attributes"]) - mediaFileElem.text = str(self.cdata(media["url"])) + mediaFileElem.text = etree.CDATA(media["url"]) if len(creative.icons) > 0: iconsElem = etree.SubElement(linearElem, "Icons") @@ -179,7 +179,7 @@ def xml(self, options={}): root.set("version", str(self.version)) if len(self.ads) == 0 and self.vast_error_uri: - etree.SubElement(root, "Error", self.cdata(self.vast_error_uri)) + etree.SubElement(root, "Error", etree.CDATA(self.vast_error_uri)) return self.formatXmlResponse(root) for ad in self.ads: @@ -197,15 +197,15 @@ def xml(self, options={}): adSystemElem.text = str(ad.ad_system) vastAdTagElem = etree.SubElement(wrapperElem, "VASTAdTagURI") - vastAdTagElem.text = str(self.cdata(ad.vast_ad_tag_uri)) + vastAdTagElem.text = etree.CDATA(ad.vast_ad_tag_uri) if ad.error: adErrorElem = etree.SubElement(wrapperElem, "Error") - adErrorElem.text = str(self.cdata(ad.error)) + adErrorElem.text = etree.CDATA(ad.error) for impression in ad.impressions: impressionElem = etree.SubElement(wrapperElem, "Impression") - impressionElem.text = str(self.cdata(impression["url"])) + impressionElem.text = etree.CDATA(impression["url"]) self.add_creatives(wrapperElem, ad) else: @@ -215,19 +215,19 @@ def xml(self, options={}): adSystemElem.text = str(ad.ad_system) adTitleElem = etree.SubElement(inlineElem, "AdTitle") - adTitleElem.text = str(self.cdata(ad.ad_title)) + adTitleElem.text = etree.CDATA(ad.ad_title) if ad.description: adDescriptionElem = etree.SubElement(inlineElem, "Description") - adDescriptionElem.text = str(self.cdata(ad.description)) + adDescriptionElem.text = etree.CDATA(ad.description) if ad.error: adErrorElem = etree.SubElement(inlineElem, "Error") - adErrorElem.text = str(self.cdata(ad.error)) + adErrorElem.text = etree.CDATA(ad.error) for impression in ad.impressions: impressionElem = etree.SubElement(inlineElem, "Impression") - impressionElem.text = str(self.cdata(impression["url"])) + impressionElem.text = etree.CDATA(impression["url"]) self.add_creatives(inlineElem, ad)