Skip to content

Commit 3f91354

Browse files
authored
Update Python SDK to v4 (#174)
* v4 Updates * removed/updated in v4 * minor typo * fix flake8 errors * more flake8 fixes * finally fixed flake8 * fix under-indented lines
1 parent 322fc8b commit 3f91354

File tree

6 files changed

+92
-93
lines changed

6 files changed

+92
-93
lines changed

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 = (3, 0, 0)
4-
API_VERSION = '3'
3+
VERSION = (4, 0, 0)
4+
API_VERSION = '4'
55

66
from twitter_ads.utils import get_version
77

twitter_ads/account.py

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
from twitter_ads.resource import resource_property, Resource
1212
from twitter_ads.creative import (AccountMedia, MediaCreative, ScheduledTweet,
13-
Video, VideoWebsiteCard, PromotedTweet)
13+
VideoWebsiteCard, PromotedTweet)
1414
from twitter_ads.audience import TailoredAudience
1515
from twitter_ads.campaign import (AppList, Campaign, FundingInstrument, LineItem,
1616
PromotableUser, ScheduledPromotedTweet)
@@ -119,12 +119,6 @@ def tailored_audiences(self, id=None, **kwargs):
119119
"""
120120
return self._load_resource(TailoredAudience, id, **kwargs)
121121

122-
def videos(self, id=None, **kwargs):
123-
"""
124-
Returns a collection of videos available to the current account.
125-
"""
126-
return self._load_resource(Video, id, **kwargs)
127-
128122
def account_media(self, id=None, **kwargs):
129123
"""
130124
Returns a collection of account media available to the current account.
@@ -186,3 +180,6 @@ def scoped_timeline(self, *id, **kwargs):
186180
resource_property(Account, 'timezone_switch_at', readonly=True, transform=TRANSFORM.TIME)
187181
resource_property(Account, 'created_at', readonly=True, transform=TRANSFORM.TIME)
188182
resource_property(Account, 'updated_at', readonly=True, transform=TRANSFORM.TIME)
183+
# writable
184+
resource_property(Account, 'account_name')
185+
resource_property(Account, 'industry_type')

twitter_ads/audience.py

Lines changed: 24 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@
22

33
"""Container for all audience management logic used by the Ads API SDK."""
44

5-
from twitter_ads.enum import TA_OPERATIONS, TRANSFORM
5+
from twitter_ads.enum import TRANSFORM
66
from twitter_ads.resource import resource_property, Resource
7-
from twitter_ads.http import TONUpload, Request
7+
from twitter_ads.http import Request
88
from twitter_ads.error import BadRequest
99
from twitter_ads.cursor import Cursor
1010
from twitter_ads import API_VERSION
@@ -15,47 +15,43 @@
1515
class TailoredAudience(Resource):
1616

1717
PROPERTIES = {}
18-
1918
RESOURCE_COLLECTION = '/' + API_VERSION + '/accounts/{account_id}/tailored_audiences'
2019
RESOURCE = '/' + API_VERSION + '/accounts/{account_id}/tailored_audiences/{id}'
21-
RESOURCE_UPDATE = '/' + API_VERSION + '/accounts/{account_id}/tailored_audience_changes'
20+
RESOURCE_USERS = '/' + API_VERSION + '/accounts/{account_id}/tailored_audiences/\
21+
{id}/users'
2222
RESOURCE_PERMISSIONS = '/' + API_VERSION + '/accounts/{account_id}/tailored_audiences/\
2323
{id}/permissions'
24-
OPT_OUT = '/' + API_VERSION + '/accounts/{account_id}/tailored_audiences/global_opt_out'
2524

2625
@classmethod
27-
def create(klass, account, file_path, name, list_type):
26+
def create(klass, account, name):
2827
"""
29-
Uploads and creates a new tailored audience.
28+
Creates a new tailored audience.
3029
"""
31-
upload = TONUpload(account.client, file_path)
3230
audience = klass(account)
33-
getattr(audience, '__create_audience__')(name, list_type)
31+
getattr(audience, '__create_audience__')(name)
3432
try:
35-
getattr(audience, '__update_audience__')(upload.perform(), list_type, TA_OPERATIONS.ADD)
3633
return audience.reload()
3734
except BadRequest as e:
3835
audience.delete()
3936
raise e
4037

41-
@classmethod
42-
def opt_out(klass, account, file_path, list_type):
38+
def users(self, params):
4339
"""
44-
Updates the global opt-out list for the specified advertiser account.
40+
This is a private API and requires whitelisting from Twitter.
41+
This endpoint will allow partners to add, update and remove users from a given
42+
tailored_audience_id.
43+
The endpoint will also accept multiple user identifier types per user as well.
4544
"""
46-
upload = TONUpload(account.client, file_path)
47-
params = {'input_file_path': upload.perform(), 'list_type': list_type}
48-
resource = klass.OPT_OUT.format(account_id=account.id)
49-
Request(account.client, 'put', resource, params=params).perform()
50-
return True
51-
52-
def update(self, file_path, list_type, operation=TA_OPERATIONS.ADD):
53-
"""
54-
Updates the current tailored audience instance.
55-
"""
56-
upload = TONUpload(self.account.client, file_path)
57-
getattr(self, '__update_audience__')(upload.perform(), list_type, operation)
58-
return self.reload()
45+
resource = self.RESOURCE_USERS.format(account_id=self.account.id, id=self.id)
46+
headers = {'Content-Type': 'application/json'}
47+
response = Request(self.account.client,
48+
'post',
49+
resource,
50+
headers=headers,
51+
body=json.dumps(params)).perform()
52+
success_count = response.body['data']['success_count']
53+
total_count = response.body['data']['total_count']
54+
return (success_count, total_count)
5955

6056
def delete(self):
6157
"""
@@ -65,43 +61,19 @@ def delete(self):
6561
response = Request(self.account.client, 'delete', resource).perform()
6662
return self.from_response(response.body['data'])
6763

68-
def status(self):
69-
"""
70-
Returns the status of all changes for the current tailored audience instance.
71-
"""
72-
if not self.id:
73-
return None
74-
75-
resource = self.RESOURCE_UPDATE.format(account_id=self.account.id)
76-
request = Request(self.account.client, 'get', resource, params=self.to_params())
77-
cursor = list(Cursor(None, request))
78-
79-
return filter(lambda change: change['tailored_audience_id'] == self.id, cursor)
80-
8164
def permissions(self, **kwargs):
8265
"""
8366
Returns a collection of permissions for the curent tailored audience.
8467
"""
8568
self._validate_loaded()
8669
return TailoredAudiencePermission.all(self.account, self.id, **kwargs)
8770

88-
def __create_audience__(self, name, list_type):
89-
params = {'name': name, 'list_type': list_type}
71+
def __create_audience__(self, name):
72+
params = {'name': name}
9073
resource = self.RESOURCE_COLLECTION.format(account_id=self.account.id)
9174
response = Request(self.account.client, 'post', resource, params=params).perform()
9275
return self.from_response(response.body['data'])
9376

94-
def __update_audience__(self, location, list_type, operation):
95-
params = {
96-
'tailored_audience_id': self.id,
97-
'input_file_path': location,
98-
'list_type': list_type,
99-
'operation': operation
100-
}
101-
102-
resource = self.RESOURCE_UPDATE.format(account_id=self.account.id)
103-
return Request(self.account.client, 'post', resource, params=params).perform()
104-
10577

10678
# tailored audience properties
10779
# read-only

twitter_ads/campaign.py

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -366,3 +366,56 @@ def create(klass, account, **kwargs):
366366
resource = klass.TWEET_CREATE.format(account_id=account.id)
367367
response = Request(account.client, 'post', resource, params=params).perform()
368368
return response.body['data']
369+
370+
371+
class UserSettings(Resource, Persistence):
372+
373+
PROPERTIES = {}
374+
375+
RESOURCE = '/' + API_VERSION + '/accounts/{account_id}/user_settings/{id}'
376+
377+
378+
# user settings properties
379+
# writable
380+
resource_property(UserSettings, 'notification_email')
381+
resource_property(UserSettings, 'contact_phone')
382+
resource_property(UserSettings, 'contact_phone_extension')
383+
resource_property(UserSettings, 'subscribed_email_types')
384+
resource_property(UserSettings, 'user_id')
385+
386+
387+
class TaxSettings(Resource, Persistence):
388+
389+
PROPERTIES = {}
390+
391+
RESOURCE = '/' + API_VERSION + '/accounts/{account_id}/tax_settings/{id}'
392+
393+
394+
# tax settings properties
395+
# writable
396+
resource_property(TaxSettings, 'address_city')
397+
resource_property(TaxSettings, 'address_country')
398+
resource_property(TaxSettings, 'address_email')
399+
resource_property(TaxSettings, 'address_first_name')
400+
resource_property(TaxSettings, 'address_last_name')
401+
resource_property(TaxSettings, 'address_name')
402+
resource_property(TaxSettings, 'address_postal_code')
403+
resource_property(TaxSettings, 'address_region')
404+
resource_property(TaxSettings, 'address_street1')
405+
resource_property(TaxSettings, 'address_street2')
406+
resource_property(TaxSettings, 'bill_to')
407+
resource_property(TaxSettings, 'business_relationship')
408+
resource_property(TaxSettings, 'client_address_city')
409+
resource_property(TaxSettings, 'client_address_country')
410+
resource_property(TaxSettings, 'client_address_email')
411+
resource_property(TaxSettings, 'client_address_first_name')
412+
resource_property(TaxSettings, 'client_address_last_name')
413+
resource_property(TaxSettings, 'client_address_name')
414+
resource_property(TaxSettings, 'client_address_postal_code')
415+
resource_property(TaxSettings, 'client_address_region')
416+
resource_property(TaxSettings, 'client_address_street1')
417+
resource_property(TaxSettings, 'client_address_street2')
418+
resource_property(TaxSettings, 'invoice_jurisdiction')
419+
resource_property(TaxSettings, 'tax_category')
420+
resource_property(TaxSettings, 'tax_exemption_id')
421+
resource_property(TaxSettings, 'tax_id')

twitter_ads/creative.py

Lines changed: 3 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -69,35 +69,6 @@ def save(self):
6969
resource_property(PromotedTweet, 'tweet_id') # SDK limitation
7070

7171

72-
class Video(Resource, Persistence):
73-
74-
PROPERTIES = {}
75-
76-
RESOURCE_COLLECTION = '/' + API_VERSION + '/accounts/{account_id}/videos'
77-
RESOURCE = '/' + API_VERSION + '/accounts/{account_id}/videos/{id}'
78-
79-
80-
# video properties
81-
# read-only
82-
resource_property(Video, 'aspect_ratio', readonly=True)
83-
resource_property(Video, 'created_at', readonly=True, transform=TRANSFORM.TIME)
84-
resource_property(Video, 'deleted', readonly=True, transform=TRANSFORM.BOOL)
85-
resource_property(Video, 'duration', readonly=True, transform=TRANSFORM.INT)
86-
resource_property(Video, 'id', readonly=True)
87-
resource_property(Video, 'media_key', readonly=True)
88-
resource_property(Video, 'poster_url', readonly=True)
89-
resource_property(Video, 'preview_url', readonly=True)
90-
resource_property(Video, 'ready_to_tweet', readonly=True, transform=TRANSFORM.BOOL)
91-
resource_property(Video, 'reasons_not_servable', readonly=True, transform=TRANSFORM.LIST)
92-
resource_property(Video, 'tweeted', readonly=True, transform=TRANSFORM.BOOL)
93-
resource_property(Video, 'updated_at', readonly=True, transform=TRANSFORM.TIME)
94-
# writable
95-
resource_property(Video, 'description')
96-
resource_property(Video, 'poster_image_media_id')
97-
resource_property(Video, 'title')
98-
resource_property(Video, 'video_media_id')
99-
100-
10172
class AccountMedia(Resource, Persistence):
10273

10374
PROPERTIES = {}
@@ -228,7 +199,7 @@ class ImageAppDownloadCard(Resource, Persistence):
228199
resource_property(ImageAppDownloadCard, 'updated_at', readonly=True, transform=TRANSFORM.TIME)
229200
resource_property(ImageAppDownloadCard, 'deleted', readonly=True, transform=TRANSFORM.BOOL)
230201
# writable
231-
resource_property(ImageAppDownloadCard, 'app_country_code')
202+
resource_property(ImageAppDownloadCard, 'country_code')
232203
resource_property(ImageAppDownloadCard, 'app_cta')
233204
resource_property(ImageAppDownloadCard, 'iphone_app_id')
234205
resource_property(ImageAppDownloadCard, 'iphone_deep_link')
@@ -263,7 +234,7 @@ class VideoAppDownloadCard(Resource, Persistence):
263234
resource_property(VideoAppDownloadCard, 'video_poster_url', readonly=True)
264235
resource_property(VideoAppDownloadCard, 'video_url', readonly=True)
265236
# writable
266-
resource_property(VideoAppDownloadCard, 'app_country_code')
237+
resource_property(VideoAppDownloadCard, 'country_code')
267238
resource_property(VideoAppDownloadCard, 'app_cta')
268239
resource_property(VideoAppDownloadCard, 'image_media_id')
269240
resource_property(VideoAppDownloadCard, 'ipad_app_id')
@@ -521,7 +492,7 @@ def reload(self):
521492

522493
# card properties
523494
# read-only
524-
resource_property(CardsFetch, 'app_country_code', readonly=True)
495+
resource_property(CardsFetch, 'country_code', readonly=True)
525496
resource_property(CardsFetch, 'app_cta', readonly=True)
526497
resource_property(CardsFetch, 'card_type', readonly=True)
527498
resource_property(CardsFetch, 'card_uri', readonly=True)

twitter_ads/enum.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,3 +182,9 @@ def enum(**enums):
182182
HANDLE='TARGETING_CRITERIA',
183183
EVENT='EVENT'
184184
)
185+
186+
LOOKALIKE_EXPANSION = enum(
187+
BROAD='BROAD',
188+
DEFINED='DEFINED',
189+
EXPANDED='EXPANDED'
190+
)

0 commit comments

Comments
 (0)