Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement size override for video (#111) #112

Merged
merged 1 commit into from
Jul 7, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion line_item_manager/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
__version__ = '0.2.8'

# For an official release, use dev_version = ''
dev_version = '1'
dev_version = '2'

version = __version__
if dev_version:
Expand Down
1 change: 1 addition & 0 deletions line_item_manager/conf.d/line_item_manager.yml
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ creative: # at least one of the following types is required {video, banner}
...
</script>
video:
# size_override: True with a 1x1 creative # optional: defaults to False
sizes: # list
- height: 480
width: 640
Expand Down
2 changes: 2 additions & 0 deletions line_item_manager/conf.d/schema.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ properties:
$ref: "#/definitions/positiveIntegerType"
max_duration:
$ref: "#/definitions/positiveIntegerType"
size_override:
type: "boolean"
required:
- "sizes"
- "vast_xml_url"
Expand Down
11 changes: 7 additions & 4 deletions line_item_manager/conf.d/settings.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@ mgr:
advertiser:
type: "ADVERTISER"
creative:
banner:
size_override: True
video:
size_override: False
size_override:
name_template: '{{ name }} Copy:{{ index }}'
date_fmt: "%m/%d/%y %H:%M"
Expand Down Expand Up @@ -39,10 +43,9 @@ prebid:
name: "Top Bid"
targeting_key: "hb_pb"
creative:
banner:
size:
height: 1
width: 1
size_override:
height: 1
width: 1
video:
max_duration: 30000 # milliseconds
price_granularity:
Expand Down
14 changes: 6 additions & 8 deletions line_item_manager/gam_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,6 @@

logger = config.getLogger(__name__)

BANNER_SIZE = config.app['prebid']['creative']['banner']['size']

def is_create_retryable_error(exc: Exception) -> bool:
is_error = isinstance(exc, GoogleAdsServerFault)
if is_error:
Expand Down Expand Up @@ -70,8 +68,8 @@ def __init__(self, gam: Any, media_type: str, bidder: PrebidBidder, cpms: List[s

@property
def is_size_override(self) -> bool:
return self.media_type == 'banner' and \
config.user['creative']['banner'].get('size_override', True)
default = config.app['mgr']['creative'][self.media_type]['size_override']
return config.user['creative'][self.media_type].get('size_override', default)

@property
def advertiser(self) -> dict:
Expand Down Expand Up @@ -132,17 +130,17 @@ def creative_banner(self, index: int, cfg: dict, size: dict) -> dict:
params = dict(
name=self.creative_name(cfg, index),
advertiserId=self.advertiser['id'],
size=BANNER_SIZE if self.is_size_override else size,
size=config.app['prebid']['creative']['size_override'] if self.is_size_override else size,
snippet=cfg['banner']['snippet'],
isSafeFrameCompatible=cfg['banner'].get('safe_frame', True),
)
return CreativeBanner(**params).fetchone(create=True)

def creative_video(self, _: int, cfg: dict, size: dict) -> dict:
def creative_video(self, index: int, cfg: dict, size: dict) -> dict:
params = dict(
name=cfg['name'],
name=self.creative_name(cfg, index),
advertiserId=self.advertiser['id'],
size=size,
size=config.app['prebid']['creative']['size_override'] if self.is_size_override else size,
vastXmlUrl=cfg['video']['vast_xml_url'],
duration=config.user['creative']['video']['duration'],
)
Expand Down
19 changes: 19 additions & 0 deletions tests/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,25 @@
},
)

BIDDER_VIDEO_SVC_IDS_SIZE_OVERRIDE = dict(
CreativeService={
dump(dict(
name="Prebid InteractiveOffers-video Copy:1",
advertiserId=1001,
size={'height': 1, 'width': 1},
vastXmlUrl= \
'https://prebid.adnxs.com/pbc/v1/cache?uuid=%%PATTERN:hb_cache_id_interact%%',
)): 4001,
dump(dict(
name="Prebid InteractiveOffers-video Copy:2",
advertiserId=1001,
size={'height': 1, 'width': 1},
vastXmlUrl= \
'https://prebid.adnxs.com/pbc/v1/cache?uuid=%%PATTERN:hb_cache_id_interact%%',
)): 4002,
},
)

BIDDER_TEST_RUN_VIDEO_SVC_IDS = dict(
OrderService={
dump(dict(
Expand Down
128 changes: 128 additions & 0 deletions tests/resources/cfg_video_size_override.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
# line_item_manager configuration
###############################################################################
# Templating uses jinja2 rendering (see https://palletsprojects.com/p/jinja/)
# The following key word types are supported:
# Bidder:
# bidder_code = bidder-code
# bidder_name = bidder-name
# hb_<keystr> = hb_<keystr>_<bidder-code> (20 char limit)
# CPM:
# cpm = line item rate as cost-per-thousand impressions
# Media:
# media_type = video or banner based on creative configuration below
# Misc:
# time = current UTC time represented as "%m/%d/%Y %H:%M:%S"
# Order:
# cpm_max = order maximum cpm
# cpm_min = order minimum cpm
#
# See https://docs.prebid.org/dev-docs/bidder-data.csv for referencing bidder
# names and codes.
###############################################################################
# Publisher (optional)
# This can be specified at run-time like this:
# --network-code <code>
# --network-name <name>
#
publisher:
network_code: 1234
network_name: "Video Publisher"
###############################################################################
# Advertiser (required)
# Allowed Templating Key Words: Bidder
###############################################################################
advertiser:
name: "Prebid-{{ bidder_name }}"
###############################################################################
# Creatives (required)
# Allowed Templating Key Words: Bidder, Media, Misc
###############################################################################
creative: # at least one of the following types is required {video, banner}
name: "Prebid {{ bidder_name }}-{{ media_type }}"
video:
size_override: True
sizes: # list
- height: 480
width: 640
- height: 240
width: 320
vast_xml_url: "https://prebid.adnxs.com/pbc/v1/cache?uuid=%%PATTERN:{{ hb_cache_id }}%%"
# banner:
# sizes: # list
# - height: 480
# width: 640
# snippet: |
# <script src = "https://..."></script>
# <script>
# ...
# </script>
# safe_frame: False (optional: defaults to True)
###############################################################################
# Orders (required)
# Allowed Templating Key Words: Bidder, Media, Order, Misc
###############################################################################
order:
name: "Prebid-{{ bidder_name }}-{{ media_type }}-{{ time }} {{ cpm_min }}-{{ cpm_max }}"
appliedTeamIds: # list (optional)
- 12345678
- 23456789
###############################################################################
# Line Items (required)
# Allowed Templating Key Words: Bidder, Media, CPM, Misc
#
# Supported Types: price_priority, standard
# datetimes use: "%m/%d/%y %H:%M" (ex. 11/17/20 21:28)
# - default timezone is UTC
# timezones: https://en.wikipedia.org/wiki/List_of_tz_database_time_zones
###############################################################################
line_item:
name: "Prebid-{{ bidder_name }}-{{ media_type }}-{{ time }} @ {{ cpm }}"
item_type: "price_priority"
# Optional
# start_datetime: "11/17/20 21:28"
# end_datetime: "12/17/20 21:28"
# timezone: "UTC"
###############################################################################
# Bidder Targeting Key Override Map (optional):
# If provided override the default bidder_targeting_key and use these
# targeting keys specified by bidder_code.
#
# bidder_key_map:
# <bidder_code_1>: <bidder_targeting_key_1>
# <bidder_code_2>: <bidder_targeting_key_2>
###############################################################################
# Targeting (required)
# Allowed Templating Key Words: None
#
# Note: A Key-Value of 'bidder_targeting_key' with all CPM values is created
# by default.
###############################################################################
targeting:
custom: # list (optional)
- name: "country"
values:
- "US"
- "CAN"
# One of the below either placemane_names or ad_unit_names is required
placement_names: # list of names
- "placement 1"
- "placement 2"
ad_unit_names: # list of names
- "ad unit 1"
- "ad unit 2"
###############################################################################
# Rate (required)
# NOTE: granularity in Prebid.js config must align with this granularity
# Allowed Templating Key Words: None
###############################################################################
rate:
currency: "USD" # required
granularity:
type: "custom"
custom:
- min: 1.25
max: 1.50
interval: 0.25
# optional properties
# vcpm: 100000 # viewable impressions will be enabled

33 changes: 32 additions & 1 deletion tests/test_create.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
from .client import MockAdClient, SINGLE_ORDER_SVC_IDS, SINGLE_ORDER_VIDEO_SVC_IDS, \
BIDDER_BANNER_SVC_IDS, BIDDER_VIDEO_SVC_IDS, BIDDER_TEST_RUN_VIDEO_SVC_IDS, \
MISSING_RESOURCE_SVC_IDS, BIDDER_BANNER_SVC_IDS_NO_SIZE_OVERRIDE, \
BIDDER_VIDEO_BIDDER_KEY_MAP_SVC_IDS
BIDDER_VIDEO_BIDDER_KEY_MAP_SVC_IDS, BIDDER_VIDEO_SVC_IDS_SIZE_OVERRIDE

CONFIG_FILE = 'tests/resources/cfg.yml'
KEY_FILE = 'tests/resources/gam_creds.json'
Expand Down Expand Up @@ -78,6 +78,24 @@ def mock_id(name: str, rec: object):
[[{'creativeId': 4001, 'id': 9001, 'lineItemId': 8001},
{'creativeId': 4001, 'id': 9001, 'lineItemId': 8002}]]

VIDEO_EXPECTED_LICA_SIZE_OVERRIDE = \
[[{'creativeId': 4001,
'id': 9001,
'lineItemId': 8001,
'sizes': [{'height': 480, 'width': 640}, {'height': 240, 'width': 320}]},
{'creativeId': 4002,
'id': 9002,
'lineItemId': 8001,
'sizes': [{'height': 480, 'width': 640}, {'height': 240, 'width': 320}]},
{'creativeId': 4001,
'id': 9001,
'lineItemId': 8002,
'sizes': [{'height': 480, 'width': 640}, {'height': 240, 'width': 320}]},
{'creativeId': 4002,
'id': 9002,
'lineItemId': 8002,
'sizes': [{'height': 480, 'width': 640}, {'height': 240, 'width': 320}]}]]

# init
config._start_time = pytest.start_time
with open(CONFIG_FILE) as fp:
Expand Down Expand Up @@ -429,6 +447,19 @@ def test_banner_safe_frame_vcpm(monkeypatch, cli_config):
assert load_file('tests/resources/banner_vcpm_expected.yml') == gam.li_objs[0].line_items
assert BANNER_EXPECTED_LICA_NO_SIZE_OVERRIDE == gam.lica_objs

@pytest.mark.command(f'create tests/resources/cfg_video_size_override.yml -k {KEY_FILE} -b {CONFIG_BIDDER}')
def test_video_size_override(monkeypatch, cli_config):
svc_ids = copy.deepcopy(BIDDER_VIDEO_SVC_IDS)
svc_ids.update(BIDDER_VIDEO_SVC_IDS_SIZE_OVERRIDE)
client = Client(CUSTOM_TARGETING, svc_ids)
monkeypatch.setattr(ad_manager.AdManagerClient, "LoadFromString", lambda x: client)
gam = GAMConfig()
gam.create_line_items()

assert len(gam.li_objs) == 1
assert load_file('tests/resources/video_expected.yml') == gam.li_objs[0].line_items
assert VIDEO_EXPECTED_LICA_SIZE_OVERRIDE == gam.lica_objs

@pytest.mark.command(f'create tests/resources/cfg_sponsorship.yml -k {KEY_FILE} -b {CONFIG_BIDDER}')
def test_sponsorship_priority(monkeypatch, cli_config):
client = Client(CUSTOM_TARGETING, BIDDER_BANNER_SVC_IDS)
Expand Down