Skip to content

Commit

Permalink
Add new decorator (#226)
Browse files Browse the repository at this point in the history
  • Loading branch information
smaeda-ks committed Sep 9, 2019
1 parent 43074bd commit b5e11cc
Show file tree
Hide file tree
Showing 5 changed files with 52 additions and 66 deletions.
4 changes: 2 additions & 2 deletions tests/test_analytics_async.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ def test_analytics_async():
job_id = stats.id_str
job_result = Campaign.async_stats_job_result(
account,
[job_id]).first
job_ids=[job_id]).first

assert job_result is not None
assert isinstance(job_result, Analytics)
Expand All @@ -84,7 +84,7 @@ def test_analytics_async():
# call async_stats_job_result() from Analytics class directly
job_result = Analytics.async_stats_job_result(
account,
[job_id]).first
job_ids=[job_id]).first

assert job_result is not None
assert isinstance(job_result, Analytics)
Expand Down
35 changes: 12 additions & 23 deletions twitter_ads/campaign.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from twitter_ads.resource import resource_property, Resource, Persistence, Batch, Analytics
from twitter_ads.http import Request
from twitter_ads.cursor import Cursor
from twitter_ads.utils import FlattenParams
from twitter_ads import API_VERSION


Expand All @@ -20,14 +21,11 @@ class TargetingCriteria(Resource, Persistence, Batch):
RESOURCE_OPTIONS = '/' + API_VERSION + '/targeting_criteria/'

@classmethod
def all(klass, account, line_item_ids, **kwargs):
@FlattenParams
def all(klass, account, **kwargs):
"""Returns a Cursor instance for a given resource."""
params = {'line_item_ids': ','.join(map(str, line_item_ids))}
params.update(kwargs)

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

request = Request(account.client, 'get', resource, params=kwargs)
return Cursor(klass, request, init_with=[account])

@classmethod
Expand Down Expand Up @@ -202,15 +200,12 @@ class AppList(Resource, Persistence):
RESOURCE_COLLECTION = '/' + API_VERSION + '/accounts/{account_id}/app_lists'
RESOURCE = '/' + API_VERSION + '/accounts/{account_id}/app_lists/{id}'

def create(self, name, *ids):
if isinstance(ids, list):
ids = ','.join(map(str, ids))

resource = self.RESOURCE_COLLECTION.format(account_id=self.account.id)
params = self.to_params.update({'app_store_identifiers': ids, 'name': name})
response = Request(self.account.client, 'post', resource, params=params).perform()

return self.from_response(response.body['data'])
@classmethod
@FlattenParams
def create(klass, account, **kwargs):
resource = klass.RESOURCE_COLLECTION.format(account_id=account.id)
response = Request(account.client, 'post', resource, params=kwargs).perform()
return klass(account).from_response(response.body['data'])

def apps(self):
if self.id and not hasattr(self, '_apps'):
Expand Down Expand Up @@ -340,19 +335,13 @@ def __init__(self):
'Error! {name} cannot be instantiated.'.format(name=self.__class__.__name__))

@classmethod
@FlattenParams
def create(klass, account, **kwargs):
"""
Creates a "Promoted-Only" Tweet using the specialized Ads API end point.
"""
params = {}
params.update(kwargs)

# handles array to string conversion for media keys
if 'media_keys' in params and isinstance(params['media_keys'], list):
params['media_keys'] = ','.join(map(str, params['media_keys']))

resource = klass.TWEET_CREATE.format(account_id=account.id)
response = Request(account.client, 'post', resource, params=params).perform()
response = Request(account.client, 'post', resource, params=kwargs).perform()
return response.body['data']


Expand Down
39 changes: 15 additions & 24 deletions twitter_ads/creative.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from twitter_ads.enum import TRANSFORM
from twitter_ads.http import Request
from twitter_ads.resource import resource_property, Resource, Persistence, Analytics
from twitter_ads.utils import Deprecated
from twitter_ads.utils import Deprecated, FlattenParams


class PromotedAccount(Analytics, Resource, Persistence):
Expand Down Expand Up @@ -60,16 +60,13 @@ def save(self):
return self.from_response(response.body['data'][0])

@classmethod
def attach(klass, account, line_item_id=None, tweet_ids=None):
@FlattenParams
def attach(klass, account, **kwargs):
"""
Associate one or more Tweets with the specified line item.
"""
params = {}
params['line_item_id'] = line_item_id
params['tweet_ids'] = ",".join(map(str, tweet_ids))

resource = klass.RESOURCE_COLLECTION.format(account_id=account.id)
request = Request(account.client, 'post', resource, params=params)
request = Request(account.client, 'post', resource, params=kwargs)
return Cursor(klass, request, init_with=[account])


Expand Down Expand Up @@ -482,24 +479,21 @@ def all(klass):
raise AttributeError("'CardsFetch' object has no attribute 'all'")

@classmethod
def load(klass, account, card_uris=None, card_id=None, with_deleted=None):
@FlattenParams
def load(klass, account, **kwargs):
# check whether both are specified or neither are specified
if all([card_uris, card_id]) or not any([card_uris, card_id]):
if all([kwargs.get('card_uris'), kwargs.get('card_id')]) or \
not any([kwargs.get('card_uris'), kwargs.get('card_id')]):
raise ValueError('card_uris and card_id are exclusive parameters. ' +
'Please supply one or the other, but not both.')
params = {}
if with_deleted:
params['with_deleted'] = 'true'

if card_uris:
params['card_uris'] = ','.join(map(str, card_uris))
if kwargs.get('card_uris'):
resource = klass.FETCH_URI.format(account_id=account.id)
request = Request(account.client, 'get', resource, params=params)
request = Request(account.client, 'get', resource, params=kwargs)
return Cursor(klass, request, init_with=[account])
else:
params['card_id'] = card_id
resource = klass.FETCH_ID.format(account_id=account.id, id=card_id)
response = Request(account.client, 'get', resource, params=params).perform()
resource = klass.FETCH_ID.format(account_id=account.id, id=kwargs.get('card_id'))
response = Request(account.client, 'get', resource, params=kwargs).perform()
return klass(account).from_response(response.body['data'])

def reload(self):
Expand Down Expand Up @@ -575,13 +569,10 @@ class TweetPreview(Resource):
RESOURCE_COLLECTION = '/' + API_VERSION + '/accounts/{account_id}/tweet_previews'

@classmethod
def load(klass, account, tweet_ids=None, tweet_type=None):
params = {}

params['tweet_ids'] = ','.join(map(str, tweet_ids))
params['tweet_type'] = tweet_type
@FlattenParams
def load(klass, account, **kwargs):
resource = klass.RESOURCE_COLLECTION.format(account_id=account.id)
request = Request(account.client, 'get', resource, params=params)
request = Request(account.client, 'get', resource, params=kwargs)
return Cursor(klass, request, init_with=[account])


Expand Down
26 changes: 9 additions & 17 deletions twitter_ads/resource.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
from twitter_ads.http import Request
from twitter_ads.cursor import Cursor
from twitter_ads import API_VERSION
from twitter_ads.utils import extract_response_headers
from twitter_ads.utils import extract_response_headers, FlattenParams


def resource_property(klass, name, **kwargs):
Expand Down Expand Up @@ -295,17 +295,13 @@ def queue_async_stats_job(klass, account, ids, metric_groups, **kwargs):
return Analytics(account).from_response(response.body['data'], headers=response.headers)

@classmethod
def async_stats_job_result(klass, account, job_ids=None, **kwargs):
@FlattenParams
def async_stats_job_result(klass, account, **kwargs):
"""
Returns the results of the specified async job IDs
"""
params = {}
params.update(kwargs)
if isinstance(job_ids, list):
params['job_ids'] = ','.join(map(str, job_ids))

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

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

Expand All @@ -323,30 +319,26 @@ def async_stats_job_data(klass, account, url, **kwargs):
return response.body

@classmethod
@FlattenParams
def active_entities(klass, account, start_time, end_time, **kwargs):
"""
Returns the details about which entities' analytics metrics
have changed in a given time period.
"""
entity_type = klass.__name__
if entity_type == 'OrganicTweet':
entity = kwargs.get('entity') or klass.ANALYTICS_MAP[klass.__name__]
if entity == klass.ANALYTICS_MAP['OrganicTweet']:
raise ValueError("'OrganicTweet' not support with 'active_entities'")

# The start and end times must be expressed in whole hours
validate_whole_hours(start_time)
validate_whole_hours(end_time)

params = {
'entity': klass.ANALYTICS_MAP[entity_type],
'entity': entity,
'start_time': to_time(start_time, None),
'end_time': to_time(end_time, None)
}

for k in kwargs:
if isinstance(kwargs[k], list):
params[k] = ','.join(map(str, kwargs[k]))
else:
params[k] = kwargs[k]
params.update(kwargs)

resource = klass.RESOURCE_ACTIVE_ENTITIES.format(account_id=account.id)
response = Request(account.client, 'get', resource, params=params).perform()
Expand Down
14 changes: 14 additions & 0 deletions twitter_ads/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,3 +102,17 @@ def wrapper(*args, **kwargs):
)
return decorated(*args, **kwargs)
return wrapper


class FlattenParams(object):
def __init__(self, function):
self._func = function

def __call__(self, *args, **kwargs):
params = kwargs
for i in params:
if isinstance(params[i], list):
params[i] = ','.join(map(str, params[i]))
elif isinstance(params[i], bool):
params[i] = str(params[i]).lower()
return self._func(*args, **params)

0 comments on commit b5e11cc

Please sign in to comment.