From 1714c5bb27ba2d6b92aaf652ab8502fd335996b5 Mon Sep 17 00:00:00 2001 From: smaeda-ks Date: Tue, 30 Jul 2019 19:42:23 +0900 Subject: [PATCH 1/3] introduce PromotedTweet.attach() method - and deprecate .save() method --- tests/fixtures/promoted_tweets_attach.json | 25 +++++++++++++++++ tests/test_promoted_tweets.py | 31 ++++++++++++++++++++++ twitter_ads/creative.py | 29 ++++++++------------ 3 files changed, 67 insertions(+), 18 deletions(-) create mode 100644 tests/fixtures/promoted_tweets_attach.json diff --git a/tests/fixtures/promoted_tweets_attach.json b/tests/fixtures/promoted_tweets_attach.json new file mode 100644 index 0000000..29f7101 --- /dev/null +++ b/tests/fixtures/promoted_tweets_attach.json @@ -0,0 +1,25 @@ +{ + "data_type": "promoted_tweet", + "data": [ + { + "line_item_id": "2b7xw", + "id": "6thl4", + "entity_status": "ACTIVE", + "created_at": "2015-04-11T20:50:25Z", + "updated_at": "2015-04-11T20:50:25Z", + "approval_status": "ACCEPTED", + "tweet_id": "585127452231467008", + "deleted": false + } + ], + "request": { + "params": { + "line_item_id": "2b7xw", + "tweet_ids": [ + 585127452231467008 + ], + "account_id": "2iqph" + } + }, + "total_count": 1 +} diff --git a/tests/test_promoted_tweets.py b/tests/test_promoted_tweets.py index 929d429..04e2ee6 100644 --- a/tests/test_promoted_tweets.py +++ b/tests/test_promoted_tweets.py @@ -65,3 +65,34 @@ def test_promoted_tweets_load(): promoted_tweet = PromotedTweet.load(account, '6thl4') assert promoted_tweet.id == '6thl4' assert promoted_tweet.entity_status == 'ACTIVE' + + +@responses.activate +def test_promoted_tweets_attach(): + responses.add(responses.GET, + with_resource('/' + API_VERSION + '/accounts/2iqph'), + body=with_fixture('accounts_load'), + content_type='application/json') + + responses.add(responses.POST, + with_resource('/' + API_VERSION + '/accounts/2iqph/promoted_tweets'), + body=with_fixture('promoted_tweets_attach'), + content_type='application/json') + + client = Client( + characters(40), + characters(40), + characters(40), + characters(40) + ) + + account = Account.load(client, '2iqph') + response = PromotedTweet.attach( + account, + line_item_id='2b7xw', + tweet_ids=['585127452231467008'] + ) + + assert isinstance(response, Cursor) + assert response.count == 1 + assert response.first.id == '6thl4' diff --git a/twitter_ads/creative.py b/twitter_ads/creative.py index 3027974..4283ecb 100644 --- a/twitter_ads/creative.py +++ b/twitter_ads/creative.py @@ -2,8 +2,6 @@ """Container for all creative management logic used by the Ads API SDK.""" -from requests.exceptions import HTTPError - from twitter_ads import API_VERSION from twitter_ads.cursor import Cursor from twitter_ads.enum import TRANSFORM @@ -39,22 +37,18 @@ class PromotedTweet(Resource, Persistence, Analytics): RESOURCE_COLLECTION = '/' + API_VERSION + '/accounts/{account_id}/promoted_tweets' RESOURCE = '/' + API_VERSION + '/accounts/{account_id}/promoted_tweets/{id}' - def save(self): + @classmethod + def attach(klass, account, line_item_id=None, tweet_ids=None): """ - Saves or updates the current object instance depending on the - presence of `object.id`. + Associate one or more Tweets with the specified line item. """ - params = self.to_params() - if 'tweet_id' in params: - params['tweet_ids'] = [params['tweet_id']] - del params['tweet_id'] - - if self.id: - raise HTTPError("Method PUT not allowed.") + params = {} + params['line_item_id'] = line_item_id + params['tweet_ids'] = ",".join(map(str, tweet_ids)) - resource = self.RESOURCE_COLLECTION.format(account_id=self.account.id) - response = Request(self.account.client, 'post', resource, params=params).perform() - return self.from_response(response.body['data'][0]) + resource = klass.RESOURCE_COLLECTION.format(account_id=account.id) + request = Request(account.client, 'post', resource, params=params) + return Cursor(klass, request, init_with=[account]) # promoted tweet properties @@ -65,9 +59,8 @@ def save(self): resource_property(PromotedTweet, 'entity_status', readonly=True) resource_property(PromotedTweet, 'id', readonly=True) resource_property(PromotedTweet, 'updated_at', readonly=True, transform=TRANSFORM.TIME) -# writable -resource_property(PromotedTweet, 'line_item_id') -resource_property(PromotedTweet, 'tweet_id') # SDK limitation +resource_property(PromotedTweet, 'tweet_id', readonly=True) +resource_property(PromotedTweet, 'line_item_id', readonly=True) class AccountMedia(Resource, Persistence): From d16e663d2833ba7babc0db11d9f71cac5e1a823e Mon Sep 17 00:00:00 2001 From: smaeda-ks Date: Tue, 30 Jul 2019 20:11:13 +0900 Subject: [PATCH 2/3] Update example --- examples/promoted_tweet.py | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/examples/promoted_tweet.py b/examples/promoted_tweet.py index ec29806..b40d103 100644 --- a/examples/promoted_tweet.py +++ b/examples/promoted_tweet.py @@ -8,32 +8,32 @@ CONSUMER_SECRET = 'your consumer secret' ACCESS_TOKEN = 'user access token' ACCESS_TOKEN_SECRET = 'user access token secret' -ADS_ACCOUNT = 'ads account id' +ACCOUNT_ID = 'ads account id' # initialize the twitter ads api client client = Client(CONSUMER_KEY, CONSUMER_SECRET, ACCESS_TOKEN, ACCESS_TOKEN_SECRET) # load up the account instance, campaign and line item -account = client.accounts(ADS_ACCOUNT) +account = client.accounts(ACCOUNT_ID) campaign = account.campaigns().next() line_item = account.line_items(None, campaign_ids=campaign.id).next() # create request for a simple nullcasted tweet tweet1 = Tweet.create(account, text='There can be only one...') -# promote the tweet using our line item -promoted_tweet = PromotedTweet(account) -promoted_tweet.line_item_id = line_item.id -promoted_tweet.tweet_id = tweet1['id'] -promoted_tweet.save() - # create request for a nullcasted tweet with a website card website_card = WebsiteCard.all(account).next() -text = "Fine. There can be two. {card_url}".format(card_url=website_card.preview_url) -tweet2 = Tweet.create(account, text) +tweet2 = Tweet.create(account, text='Fine. There can be two.', card_uri=website_card.card_uri) # promote the tweet using our line item -promoted_tweet = PromotedTweet(account) -promoted_tweet.line_item_id = line_item.id -promoted_tweet.tweet_id = tweet2['id'] -promoted_tweet.save() +tweet_ids = [tweet1['id'], tweet2['id']] + +response = PromotedTweet.attach( + account, + line_item_id=line_item.id, + tweet_ids=tweet_ids +) + +for i in response: + print(i.id) + print(i.tweet_id) From fbd44ed41b93d6e086ff793dbb4fb290b8a845b3 Mon Sep 17 00:00:00 2001 From: smaeda-ks Date: Tue, 6 Aug 2019 21:45:30 +0900 Subject: [PATCH 3/3] leave PromotedTweet.save() but mark as deprecated --- twitter_ads/creative.py | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/twitter_ads/creative.py b/twitter_ads/creative.py index 9177988..70d0354 100644 --- a/twitter_ads/creative.py +++ b/twitter_ads/creative.py @@ -2,6 +2,7 @@ """Container for all creative management logic used by the Ads API SDK.""" +from requests.exceptions import HTTPError from twitter_ads import API_VERSION from twitter_ads.cursor import Cursor from twitter_ads.enum import TRANSFORM @@ -38,6 +39,26 @@ class PromotedTweet(Analytics, Resource, Persistence): RESOURCE_COLLECTION = '/' + API_VERSION + '/accounts/{account_id}/promoted_tweets' RESOURCE = '/' + API_VERSION + '/accounts/{account_id}/promoted_tweets/{id}' + @Deprecated('This method has been deprecated and will no longer be available ' + 'in the next major version update. Please use PromotedTweet.attach() ' + 'method instead.') + def save(self): + """ + Saves or updates the current object instance depending on the + presence of `object.id`. + """ + params = self.to_params() + if 'tweet_id' in params: + params['tweet_ids'] = [params['tweet_id']] + del params['tweet_id'] + + if self.id: + raise HTTPError("Method PUT not allowed.") + + resource = self.RESOURCE_COLLECTION.format(account_id=self.account.id) + response = Request(self.account.client, 'post', resource, params=params).perform() + return self.from_response(response.body['data'][0]) + @classmethod def attach(klass, account, line_item_id=None, tweet_ids=None): """ @@ -60,8 +81,8 @@ def attach(klass, account, line_item_id=None, tweet_ids=None): resource_property(PromotedTweet, 'entity_status', readonly=True) resource_property(PromotedTweet, 'id', readonly=True) resource_property(PromotedTweet, 'updated_at', readonly=True, transform=TRANSFORM.TIME) -resource_property(PromotedTweet, 'tweet_id', readonly=True) -resource_property(PromotedTweet, 'line_item_id', readonly=True) +resource_property(PromotedTweet, 'tweet_id') +resource_property(PromotedTweet, 'line_item_id') class AccountMedia(Resource, Persistence):