Skip to content

Commit 7241015

Browse files
authored
Ads API v8 (#269)
* 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
1 parent fbbb5ea commit 7241015

9 files changed

+136
-13
lines changed

examples/batch_request.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@
4646
line_item_1.name = 'my first ad'
4747
line_item_1.product_type = PRODUCT.PROMOTED_TWEETS
4848
line_item_1.placements = [PLACEMENT.ALL_ON_TWITTER]
49-
line_item_1.objective = OBJECTIVE.TWEET_ENGAGEMENTS
49+
line_item_1.objective = OBJECTIVE.ENGAGEMENTS
5050
line_item_1.bid_amount_local_micro = 10000
5151
line_item_1.entity_status = ENTITY_STATUS.PAUSED
5252

@@ -55,7 +55,7 @@
5555
line_item_2.name = 'my second ad'
5656
line_item_2.product_type = PRODUCT.PROMOTED_TWEETS
5757
line_item_2.placements = [PLACEMENT.ALL_ON_TWITTER]
58-
line_item_2.objective = OBJECTIVE.TWEET_ENGAGEMENTS
58+
line_item_2.objective = OBJECTIVE.ENGAGEMENTS
5959
line_item_2.bid_amount_local_micro = 20000
6060
line_item_2.entity_status = ENTITY_STATUS.PAUSED
6161

examples/quick_start.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
line_item.name = 'my first ad'
3232
line_item.product_type = PRODUCT.PROMOTED_TWEETS
3333
line_item.placements = [PLACEMENT.ALL_ON_TWITTER]
34-
line_item.objective = OBJECTIVE.TWEET_ENGAGEMENTS
34+
line_item.objective = OBJECTIVE.ENGAGEMENTS
3535
line_item.bid_amount_local_micro = 10000
3636
line_item.entity_status = ENTITY_STATUS.PAUSED
3737
line_item.save()

examples/video_tutorial.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,10 +48,10 @@
4848
campaign.start_time = datetime.utcnow()
4949
campaign.save()
5050

51-
# create a line item with the VIDEO_VIEWS_PREROLL
51+
# create a line item with the PREROLL_VIEWS
5252
# objective and product_type MEDIA
5353
line_item = LineItem(account)
54-
line_item.objective = OBJECTIVE.VIDEO_VIEWS_PREROLL
54+
line_item.objective = OBJECTIVE.PREROLL_VIEWS
5555

5656
line_item.campaign_id = campaign.id
5757
line_item.name = 'Video tutorial example'

tests/fixtures/tailored_audiences_all.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
],
1515
"audience_type": "WEB",
1616
"id": "abc2",
17+
"owner_account_id": "2iqph",
1718
"reasons_not_targetable": [
1819
"TOO_SMALL"
1920
],
@@ -27,6 +28,7 @@
2728
{
2829
"targetable": true,
2930
"name": "TA #1",
31+
"owner_account_id": "2iqph",
3032
"targetable_types": [
3133
"CRM",
3234
"EXCLUDED_CRM"
@@ -44,6 +46,7 @@
4446
{
4547
"targetable": false,
4648
"name": "TA #3",
49+
"owner_account_id": "2iqph",
4750
"targetable_types": [
4851
"CRM",
4952
"EXCLUDED_CRM"
@@ -61,7 +64,6 @@
6164
"audience_size": null
6265
}
6366
],
64-
"data_type": "tailored_audience",
6567
"total_count": 3,
6668
"next_cursor": null
6769
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
{
2+
"request": {
3+
"params": {
4+
"account_id": "2iqph",
5+
"tailored_audience_id": "abc2"
6+
}
7+
},
8+
"next_cursor": null,
9+
"data": [
10+
{
11+
"campaign_id": "59hod",
12+
"campaign_name": "test-campaign",
13+
"line_items": [
14+
{
15+
"id": "5gzog",
16+
"name": "test-line-item",
17+
"servable": true
18+
}
19+
]
20+
},
21+
{
22+
"campaign_id": "arja7",
23+
"campaign_name": "Untitled campaign",
24+
"line_items": [
25+
{
26+
"id": "bjw1q",
27+
"name": null,
28+
"servable": true
29+
}
30+
]
31+
}
32+
]
33+
}

tests/test_targeted_audiences.py

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import responses
2+
import unittest
3+
4+
from tests.support import with_resource, with_fixture, characters
5+
6+
from twitter_ads.account import Account
7+
from twitter_ads.client import Client
8+
from twitter_ads.audience import TailoredAudience
9+
from twitter_ads.cursor import Cursor
10+
from twitter_ads import API_VERSION
11+
12+
13+
@responses.activate
14+
def test_targeted_audiences():
15+
responses.add(responses.GET,
16+
with_resource('/' + API_VERSION + '/accounts/2iqph'),
17+
body=with_fixture('accounts_load'))
18+
19+
responses.add(responses.GET,
20+
with_resource('/' + API_VERSION + '/accounts/2iqph/tailored_audiences/2906h'),
21+
body=with_fixture('tailored_audiences_load'))
22+
23+
responses.add(responses.GET,
24+
with_resource('/' + API_VERSION + '/accounts/2iqph/tailored_audiences/abc2/targeted?with_active=True'),
25+
body=with_fixture('targeted_audiences'))
26+
27+
client = Client(
28+
characters(40),
29+
characters(40),
30+
characters(40),
31+
characters(40)
32+
)
33+
34+
account = Account.load(client, '2iqph')
35+
36+
audience = TailoredAudience.load(account, '2906h')
37+
targeted_audiences = audience.targeted(
38+
with_active=True
39+
)
40+
41+
assert isinstance(targeted_audiences, Cursor)
42+
assert isinstance(targeted_audiences.first.line_items, list)
43+
assert targeted_audiences.first.campaign_id == '59hod'
44+
assert targeted_audiences.first.line_items[0]['id'] == '5gzog'
45+
assert targeted_audiences.first.line_items[0]['name'] == 'test-line-item'
46+
assert targeted_audiences.first.line_items[0]['servable'] == True
47+
assert len(responses.calls) == 3

twitter_ads/__init__.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# Copyright (C) 2015 Twitter, Inc.
22

3-
VERSION = (7, 0, 2)
4-
API_VERSION = '7'
3+
VERSION = (8, 0, 0)
4+
API_VERSION = '8'
55

66
from twitter_ads.utils import get_version
77

twitter_ads/audience.py

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,13 @@ def permissions(self, **kwargs):
6868
self._validate_loaded()
6969
return TailoredAudiencePermission.all(self.account, self.id, **kwargs)
7070

71+
def targeted(self, **kwargs):
72+
"""
73+
Returns a collection of campaigns and line items targeting the curent tailored audience.
74+
"""
75+
self._validate_loaded()
76+
return TailoredAudienceTargeted.all(self.account, self.id, **kwargs)
77+
7178
def __create_audience__(self, name):
7279
params = {'name': name}
7380
resource = self.RESOURCE_COLLECTION.format(account_id=self.account.id)
@@ -83,14 +90,15 @@ def __create_audience__(self, name):
8390
resource_property(TailoredAudience, 'deleted', readonly=True, transform=TRANSFORM.BOOL)
8491
resource_property(TailoredAudience, 'audience_size', readonly=True)
8592
resource_property(TailoredAudience, 'audience_type', readonly=True)
86-
resource_property(TailoredAudience, 'metadata', readonly=True)
8793
resource_property(TailoredAudience, 'partner_source', readonly=True)
8894
resource_property(TailoredAudience, 'reasons_not_targetable', readonly=True)
8995
resource_property(TailoredAudience, 'targetable', readonly=True)
9096
resource_property(TailoredAudience, 'targetable_types', readonly=True)
97+
resource_property(TailoredAudience, 'owner_account_id', readonly=True)
98+
9199
# writable
92100
resource_property(TailoredAudience, 'name')
93-
resource_property(TailoredAudience, 'list_type')
101+
resource_property(TailoredAudience, 'description')
94102

95103

96104
class TailoredAudiencePermission(Resource):
@@ -149,3 +157,36 @@ def delete(self):
149157
resource_property(TailoredAudiencePermission, 'tailored_audience_id')
150158
resource_property(TailoredAudiencePermission, 'granted_account_id')
151159
resource_property(TailoredAudiencePermission, 'permission_level')
160+
161+
162+
class TailoredAudienceTargeted(Resource):
163+
164+
PROPERTIES = {}
165+
166+
RESOURCE = '/' + API_VERSION + '/accounts/{account_id}/tailored_audiences/\
167+
{tailored_audience_id}/targeted'
168+
169+
@classmethod
170+
def all(klass, account, tailored_audience_id, **kwargs):
171+
"""Returns a Cursor instance for the given targeted tailored audience resource."""
172+
173+
resource = klass.RESOURCE.format(
174+
account_id=account.id,
175+
tailored_audience_id=tailored_audience_id)
176+
request = Request(account.client, 'get', resource, params=kwargs)
177+
178+
return Cursor(klass, request, init_with=[account])
179+
180+
181+
# tailored audience targeted properties
182+
# read-only
183+
resource_property(TailoredAudienceTargeted, 'campaign_id', readonly=True)
184+
resource_property(TailoredAudienceTargeted, 'campaign_name', readonly=True)
185+
resource_property(TailoredAudienceTargeted, 'line_items', readonly=True)
186+
resource_property(TailoredAudienceTargeted, 'id', readonly=True)
187+
resource_property(TailoredAudienceTargeted, 'name', readonly=True)
188+
resource_property(TailoredAudienceTargeted, 'servable', readonly=True, transform=TRANSFORM.BOOL)
189+
190+
# writable
191+
resource_property(TailoredAudienceTargeted, 'tailored_audience_id')
192+
resource_property(TailoredAudienceTargeted, 'with_active', transform=TRANSFORM.BOOL)

twitter_ads/enum.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -128,11 +128,11 @@ def enum(**enums):
128128
OBJECTIVE = enum(
129129
APP_ENGAGEMENTS='APP_ENGAGEMENTS',
130130
APP_INSTALLS='APP_INSTALLS',
131-
AWARENESS='AWARENESS',
131+
ENGAGEMENTS='ENGAGEMENTS',
132132
FOLLOWERS='FOLLOWERS',
133133
LEAD_GENERATION='LEAD_GENERATION',
134-
TWEET_ENGAGEMENTS='TWEET_ENGAGEMENTS',
135-
VIDEO_VIEWS_PREROLL='VIDEO_VIEWS_PREROLL',
134+
PREROLL_VIEWS='PREROLL_VIEWS',
135+
REACH='REACH',
136136
VIDEO_VIEWS='VIDEO_VIEWS',
137137
WEBSITE_CLICKS='WEBSITE_CLICKS',
138138
WEBSITE_CONVERSIONS='WEBSITE_CONVERSIONS'

0 commit comments

Comments
 (0)