-
Notifications
You must be signed in to change notification settings - Fork 75
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 RON support and Bidder Code Params #52
base: master
Are you sure you want to change the base?
Changes from all commits
e9c3f4a
d89af9d
dabc750
590a8bb
346b834
6ebd50d
eb8e763
be9cc2e
24a71d0
70a277d
3dcfa0a
7fe03f9
2efc445
3aac015
b5f0be8
132e32e
3840021
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -80,11 +80,14 @@ Setting | Description | Default | |
`DFP_USE_EXISTING_ORDER_IF_EXISTS` | Whether we should modify an existing order if one already exists with name `DFP_ORDER_NAME` | `False` | ||
`DFP_NUM_CREATIVES_PER_LINE_ITEM` | The number of duplicate creatives to attach to each line item. Due to [DFP limitations](https://support.google.com/dfp_sb/answer/82245?hl=en), this should be equal to or greater than the number of ad units you serve on a given page. | the length of setting `DFP_TARGETED_PLACEMENT_NAMES` | ||
`DFP_CURRENCY_CODE` | The currency to use in line items. | `'USD'` | ||
`DFP_ALLOW_NO_INVENTORY_TARGETING` | If no placement should be used, for example for a run of network. If True, DFP_TARGETED_PLACEMENT_NAMES still need to be set to an empty array. | `False` | ||
`DFP_ASSOCIATIONS_BATCH` | Determine number of line item/creative associations to be created in one batch. | the number of line items to be created multiplied by `DFP_NUM_CREATIVES_PER_LINE_ITEM` | ||
`PREBID_BIDDER_PARAMS` | Whether DFP targeting keys should be created following Bidders' Params structure. This is used when it's required to send all bids to the ad server. | `False` | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What do you think about renaming this setting to |
||
|
||
## Limitations | ||
|
||
* Currently, the names of the bidder code targeting key (`hb_bidder`) and price bucket targeting key (`hb_pb`) are not customizable. The `hb_bidder` targeting key is currently required (see [#18](../../issues/18)) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We should keep the "and price bucket targeting key ( |
||
* This tool does not support additional line item targeting beyond placement, `hb_bidder`, and `hb_pb` values. Placement targeting is currently required (see [#16](../../issues/16)), and targeting by ad unit isn't supported (see [#17](../../issues/17)) | ||
* Currently, the names of the bidder code targeting key (`hb_bidder`) is not customizable. The `hb_bidder` targeting key is currently required (see [#18](../../issues/18)) | ||
* This tool does not support additional line item targeting beyond placement, `hb_bidder`, and `hb_pb` values. Targeting by ad unit isn't supported (see [#17](../../issues/17)) | ||
* The price bucketing setting `PREBID_PRICE_BUCKETS` only allows for uniform bucketing. For example, you can create $0.01 buckets from $0 - $20, but you cannot specify $0.01 buckets from $0 - $5 and $0.50 buckets from $5 - $20. Using entirely $0.01 buckets will still work for the custom buckets—you'll just have more line items than you need. | ||
* This tool does not modify existing orders or line items, it only creates them. If you need to make a change to an order, it's easiest to archive the existing order and recreate it. | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,6 +4,10 @@ | |
|
||
from dfp.client import get_client | ||
|
||
import settings | ||
import time | ||
import suds | ||
from pprint import pprint | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Remove unused |
||
|
||
logger = logging.getLogger(__name__) | ||
|
||
|
@@ -41,10 +45,40 @@ def make_licas(line_item_ids, creative_ids, size_overrides=[]): | |
# settings, as recommended: http://prebid.org/adops/step-by-step.html | ||
'sizes': sizes | ||
}) | ||
licas = lica_service.createLineItemCreativeAssociations(licas) | ||
|
||
if licas: | ||
logger.info( | ||
u'Created {0} line item <> creative associations.'.format(len(licas))) | ||
associations_batch = getattr(settings, 'DFP_ASSOCIATIONS_BATCH', None) | ||
|
||
if not associations_batch is None: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As noted above, let's just always use batch uploads here. Do you know if DFP has any batch size limits? I didn't see any. Hardcoding something like 20 or 50 items seems reasonable (whatever you found works for you). |
||
while licas: | ||
batch = [] | ||
|
||
for b in range(0, associations_batch): | ||
if licas: | ||
batch.append(licas.pop(0)) | ||
|
||
try: | ||
time.sleep(1) | ||
batch = lica_service.createLineItemCreativeAssociations(batch) | ||
except suds.WebFault as err: | ||
logger.info(u'A common error was raised (it can happen). Waiting 30 seconds and retrying...') | ||
time.sleep(30) | ||
try: | ||
batch = lica_service.createLineItemCreativeAssociations(batch) | ||
except suds.WebFault as err: | ||
logger.info(u'A common error was raised (it can happen). Waiting 30 seconds and retrying...') | ||
time.sleep(30) | ||
batch = lica_service.createLineItemCreativeAssociations(batch) | ||
|
||
if batch: | ||
logger.info( | ||
u'Created {0} line item <> creative associations.'.format(len(batch))) | ||
else: | ||
logger.info(u'No line item <> creative associations created.') | ||
else: | ||
logger.info(u'No line item <> creative associations created.') | ||
licas = lica_service.createLineItemCreativeAssociations(licas) | ||
|
||
if licas: | ||
logger.info( | ||
u'Created {0} line item <> creative associations.'.format(len(licas))) | ||
else: | ||
logger.info(u'No line item <> creative associations created.') |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,6 +7,8 @@ | |
|
||
from dfp.client import get_client | ||
|
||
import settings | ||
|
||
|
||
logger = logging.getLogger(__name__) | ||
|
||
|
@@ -48,6 +50,19 @@ def create_creative_config(name, advertiser_id): | |
with open(snippet_file_path, 'r') as snippet_file: | ||
snippet = snippet_file.read() | ||
|
||
# Determine what bidder params should be | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please move this logic into a standalone module (e.g. |
||
bidder_code = getattr(settings, 'PREBID_BIDDER_CODE', None) | ||
bidder_params = getattr(settings, 'PREBID_BIDDER_PARAMS', None) | ||
hb_adid_key = 'hb_adid' | ||
|
||
if bidder_params is True: | ||
hb_adid_key += '_' + bidder_code | ||
|
||
if len(hb_adid_key) > 20: | ||
hb_adid_key = hb_adid_key[:20] | ||
|
||
snippet = snippet.replace('{hb_adid_key}', hb_adid_key) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could you please add a test for this, if possible? |
||
|
||
# https://developers.google.com/doubleclick-publishers/docs/reference/v201802/CreativeService.Creative | ||
config = { | ||
'xsi_type': 'ThirdPartyCreative', | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
#!/usr/bin/env python | ||
# -*- coding: utf-8 -*- | ||
|
||
import logging | ||
|
||
from googleads import dfp | ||
|
||
from dfp.client import get_client | ||
|
||
|
||
logger = logging.getLogger(__name__) | ||
|
||
def get_all_ad_units(print_ad_units=False): | ||
""" | ||
Gets ad units from DFP. | ||
|
||
Returns: | ||
array of ad units | ||
""" | ||
|
||
# Initialize units array | ||
ad_units = [] | ||
|
||
dfp_client = get_client() | ||
|
||
# Initialize appropriate service. | ||
ad_unit_service = dfp_client.GetService('InventoryService', version='v201802') | ||
|
||
# Create a statement to select ad units. | ||
statement = dfp.StatementBuilder() | ||
|
||
# Retrieve a small amount of ad units at a time, paging | ||
# through until all ad units have been retrieved. | ||
while True: | ||
response = ad_unit_service.getAdUnitsByStatement(statement.ToStatement()) | ||
if 'results' in response: | ||
for ad_unit in response['results']: | ||
ad_units.append(ad_unit) | ||
if print_ad_units: | ||
print('Ad unit with ID "%s" and name "%s" was found.' % (ad_unit['id'], ad_unit['name'])) | ||
statement.offset += dfp.SUGGESTED_PAGE_LIMIT | ||
else: | ||
break | ||
|
||
return ad_units | ||
|
||
def get_root_ad_unit_id(): | ||
""" | ||
Gets root ad unit ID from DFP. | ||
|
||
Returns: | ||
an ad unit ID, or None | ||
""" | ||
|
||
dfp_client = get_client() | ||
network_service = dfp_client.GetService('NetworkService', version='v201802') | ||
current_network = network_service.getCurrentNetwork() | ||
|
||
if hasattr(current_network, 'effectiveRootAdUnitId'): | ||
return current_network.effectiveRootAdUnitId | ||
|
||
return None | ||
|
||
def main(): | ||
get_all_ad_units(print_ad_units=True) | ||
|
||
if __name__ == '__main__': | ||
main() |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -18,7 +18,7 @@ | |
# The exact name of the DFP advertiser for the created order | ||
DFP_ADVERTISER_NAME = None | ||
|
||
# Names of placements the line items should target. | ||
# Names of placements the line items should target. Has priority over ad units. | ||
DFP_TARGETED_PLACEMENT_NAMES = [] | ||
|
||
# Sizes of placements. These are used to set line item and creative sizes. | ||
|
@@ -33,6 +33,10 @@ | |
}, | ||
] | ||
|
||
# If no placement should be used, for example for a run of network. If True, | ||
# DFP_TARGETED_PLACEMENT_NAMES still need to be set to an empty array. | ||
DFP_ALLOW_NO_INVENTORY_TARGETING = False | ||
|
||
# Whether we should create the advertiser in DFP if it does not exist. | ||
# If False, the program will exit rather than create an advertiser. | ||
DFP_CREATE_ADVERTISER_IF_DOES_NOT_EXIST = False | ||
|
@@ -58,12 +62,23 @@ | |
# The currency to use in DFP when setting line item CPMs. Defaults to 'USD'. | ||
# DFP_CURRENCY_CODE = 'USD' | ||
|
||
# Optional | ||
# Determine if line items and creative should be associated in batch. | ||
# Useful to avoid timeouts if many of them have to be created. | ||
# DFP_ASSOCIATIONS_BATCH = 50 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As noted above, let's not add this setting. |
||
|
||
######################################################################### | ||
# PREBID SETTINGS | ||
######################################################################### | ||
|
||
PREBID_BIDDER_CODE = None | ||
|
||
# Whether DFP targeting keys should be created following Bidders' Params structure. | ||
# This is used when it's required to send all bids to the ad server. | ||
# See: http://prebid.org/dev-docs/bidders.html | ||
# And: http://prebid.org/adops/send-all-bids-adops.html | ||
PREBID_BIDDER_PARAMS = False | ||
|
||
# Price buckets. This should match your Prebid settings for the partner. See: | ||
# http://prebid.org/dev-docs/publisher-api-reference.html#module_pbjs.setPriceGranularity | ||
# FIXME: this should be an array of buckets. See: | ||
|
@@ -81,4 +96,4 @@ | |
try: | ||
from local_settings import * | ||
except ImportError: | ||
pass | ||
pass |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This doesn't need to be a setting. We can simply always use batch updates.