Skip to content

Commit

Permalink
Ads API v8 (#269)
Browse files Browse the repository at this point in the history
* update version to v8

* updated objective names

* update examples for new product names

* added description field for TA

* added tests for targeted audiences

* add owner_account_id to test and resource
  • Loading branch information
tushdante authored Oct 29, 2020
1 parent fbbb5ea commit 7241015
Show file tree
Hide file tree
Showing 9 changed files with 136 additions and 13 deletions.
4 changes: 2 additions & 2 deletions examples/batch_request.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@
line_item_1.name = 'my first ad'
line_item_1.product_type = PRODUCT.PROMOTED_TWEETS
line_item_1.placements = [PLACEMENT.ALL_ON_TWITTER]
line_item_1.objective = OBJECTIVE.TWEET_ENGAGEMENTS
line_item_1.objective = OBJECTIVE.ENGAGEMENTS
line_item_1.bid_amount_local_micro = 10000
line_item_1.entity_status = ENTITY_STATUS.PAUSED

Expand All @@ -55,7 +55,7 @@
line_item_2.name = 'my second ad'
line_item_2.product_type = PRODUCT.PROMOTED_TWEETS
line_item_2.placements = [PLACEMENT.ALL_ON_TWITTER]
line_item_2.objective = OBJECTIVE.TWEET_ENGAGEMENTS
line_item_2.objective = OBJECTIVE.ENGAGEMENTS
line_item_2.bid_amount_local_micro = 20000
line_item_2.entity_status = ENTITY_STATUS.PAUSED

Expand Down
2 changes: 1 addition & 1 deletion examples/quick_start.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
line_item.name = 'my first ad'
line_item.product_type = PRODUCT.PROMOTED_TWEETS
line_item.placements = [PLACEMENT.ALL_ON_TWITTER]
line_item.objective = OBJECTIVE.TWEET_ENGAGEMENTS
line_item.objective = OBJECTIVE.ENGAGEMENTS
line_item.bid_amount_local_micro = 10000
line_item.entity_status = ENTITY_STATUS.PAUSED
line_item.save()
Expand Down
4 changes: 2 additions & 2 deletions examples/video_tutorial.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,10 @@
campaign.start_time = datetime.utcnow()
campaign.save()

# create a line item with the VIDEO_VIEWS_PREROLL
# create a line item with the PREROLL_VIEWS
# objective and product_type MEDIA
line_item = LineItem(account)
line_item.objective = OBJECTIVE.VIDEO_VIEWS_PREROLL
line_item.objective = OBJECTIVE.PREROLL_VIEWS

line_item.campaign_id = campaign.id
line_item.name = 'Video tutorial example'
Expand Down
4 changes: 3 additions & 1 deletion tests/fixtures/tailored_audiences_all.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
],
"audience_type": "WEB",
"id": "abc2",
"owner_account_id": "2iqph",
"reasons_not_targetable": [
"TOO_SMALL"
],
Expand All @@ -27,6 +28,7 @@
{
"targetable": true,
"name": "TA #1",
"owner_account_id": "2iqph",
"targetable_types": [
"CRM",
"EXCLUDED_CRM"
Expand All @@ -44,6 +46,7 @@
{
"targetable": false,
"name": "TA #3",
"owner_account_id": "2iqph",
"targetable_types": [
"CRM",
"EXCLUDED_CRM"
Expand All @@ -61,7 +64,6 @@
"audience_size": null
}
],
"data_type": "tailored_audience",
"total_count": 3,
"next_cursor": null
}
33 changes: 33 additions & 0 deletions tests/fixtures/targeted_audiences.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
{
"request": {
"params": {
"account_id": "2iqph",
"tailored_audience_id": "abc2"
}
},
"next_cursor": null,
"data": [
{
"campaign_id": "59hod",
"campaign_name": "test-campaign",
"line_items": [
{
"id": "5gzog",
"name": "test-line-item",
"servable": true
}
]
},
{
"campaign_id": "arja7",
"campaign_name": "Untitled campaign",
"line_items": [
{
"id": "bjw1q",
"name": null,
"servable": true
}
]
}
]
}
47 changes: 47 additions & 0 deletions tests/test_targeted_audiences.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import responses
import unittest

from tests.support import with_resource, with_fixture, characters

from twitter_ads.account import Account
from twitter_ads.client import Client
from twitter_ads.audience import TailoredAudience
from twitter_ads.cursor import Cursor
from twitter_ads import API_VERSION


@responses.activate
def test_targeted_audiences():
responses.add(responses.GET,
with_resource('/' + API_VERSION + '/accounts/2iqph'),
body=with_fixture('accounts_load'))

responses.add(responses.GET,
with_resource('/' + API_VERSION + '/accounts/2iqph/tailored_audiences/2906h'),
body=with_fixture('tailored_audiences_load'))

responses.add(responses.GET,
with_resource('/' + API_VERSION + '/accounts/2iqph/tailored_audiences/abc2/targeted?with_active=True'),
body=with_fixture('targeted_audiences'))

client = Client(
characters(40),
characters(40),
characters(40),
characters(40)
)

account = Account.load(client, '2iqph')

audience = TailoredAudience.load(account, '2906h')
targeted_audiences = audience.targeted(
with_active=True
)

assert isinstance(targeted_audiences, Cursor)
assert isinstance(targeted_audiences.first.line_items, list)
assert targeted_audiences.first.campaign_id == '59hod'
assert targeted_audiences.first.line_items[0]['id'] == '5gzog'
assert targeted_audiences.first.line_items[0]['name'] == 'test-line-item'
assert targeted_audiences.first.line_items[0]['servable'] == True
assert len(responses.calls) == 3
4 changes: 2 additions & 2 deletions twitter_ads/__init__.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Copyright (C) 2015 Twitter, Inc.

VERSION = (7, 0, 2)
API_VERSION = '7'
VERSION = (8, 0, 0)
API_VERSION = '8'

from twitter_ads.utils import get_version

Expand Down
45 changes: 43 additions & 2 deletions twitter_ads/audience.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,13 @@ def permissions(self, **kwargs):
self._validate_loaded()
return TailoredAudiencePermission.all(self.account, self.id, **kwargs)

def targeted(self, **kwargs):
"""
Returns a collection of campaigns and line items targeting the curent tailored audience.
"""
self._validate_loaded()
return TailoredAudienceTargeted.all(self.account, self.id, **kwargs)

def __create_audience__(self, name):
params = {'name': name}
resource = self.RESOURCE_COLLECTION.format(account_id=self.account.id)
Expand All @@ -83,14 +90,15 @@ def __create_audience__(self, name):
resource_property(TailoredAudience, 'deleted', readonly=True, transform=TRANSFORM.BOOL)
resource_property(TailoredAudience, 'audience_size', readonly=True)
resource_property(TailoredAudience, 'audience_type', readonly=True)
resource_property(TailoredAudience, 'metadata', readonly=True)
resource_property(TailoredAudience, 'partner_source', readonly=True)
resource_property(TailoredAudience, 'reasons_not_targetable', readonly=True)
resource_property(TailoredAudience, 'targetable', readonly=True)
resource_property(TailoredAudience, 'targetable_types', readonly=True)
resource_property(TailoredAudience, 'owner_account_id', readonly=True)

# writable
resource_property(TailoredAudience, 'name')
resource_property(TailoredAudience, 'list_type')
resource_property(TailoredAudience, 'description')


class TailoredAudiencePermission(Resource):
Expand Down Expand Up @@ -149,3 +157,36 @@ def delete(self):
resource_property(TailoredAudiencePermission, 'tailored_audience_id')
resource_property(TailoredAudiencePermission, 'granted_account_id')
resource_property(TailoredAudiencePermission, 'permission_level')


class TailoredAudienceTargeted(Resource):

PROPERTIES = {}

RESOURCE = '/' + API_VERSION + '/accounts/{account_id}/tailored_audiences/\
{tailored_audience_id}/targeted'

@classmethod
def all(klass, account, tailored_audience_id, **kwargs):
"""Returns a Cursor instance for the given targeted tailored audience resource."""

resource = klass.RESOURCE.format(
account_id=account.id,
tailored_audience_id=tailored_audience_id)
request = Request(account.client, 'get', resource, params=kwargs)

return Cursor(klass, request, init_with=[account])


# tailored audience targeted properties
# read-only
resource_property(TailoredAudienceTargeted, 'campaign_id', readonly=True)
resource_property(TailoredAudienceTargeted, 'campaign_name', readonly=True)
resource_property(TailoredAudienceTargeted, 'line_items', readonly=True)
resource_property(TailoredAudienceTargeted, 'id', readonly=True)
resource_property(TailoredAudienceTargeted, 'name', readonly=True)
resource_property(TailoredAudienceTargeted, 'servable', readonly=True, transform=TRANSFORM.BOOL)

# writable
resource_property(TailoredAudienceTargeted, 'tailored_audience_id')
resource_property(TailoredAudienceTargeted, 'with_active', transform=TRANSFORM.BOOL)
6 changes: 3 additions & 3 deletions twitter_ads/enum.py
Original file line number Diff line number Diff line change
Expand Up @@ -128,11 +128,11 @@ def enum(**enums):
OBJECTIVE = enum(
APP_ENGAGEMENTS='APP_ENGAGEMENTS',
APP_INSTALLS='APP_INSTALLS',
AWARENESS='AWARENESS',
ENGAGEMENTS='ENGAGEMENTS',
FOLLOWERS='FOLLOWERS',
LEAD_GENERATION='LEAD_GENERATION',
TWEET_ENGAGEMENTS='TWEET_ENGAGEMENTS',
VIDEO_VIEWS_PREROLL='VIDEO_VIEWS_PREROLL',
PREROLL_VIEWS='PREROLL_VIEWS',
REACH='REACH',
VIDEO_VIEWS='VIDEO_VIEWS',
WEBSITE_CLICKS='WEBSITE_CLICKS',
WEBSITE_CONVERSIONS='WEBSITE_CONVERSIONS'
Expand Down

0 comments on commit 7241015

Please sign in to comment.